Add support to 'listen' for tags
This adds support to break the `read_passive_target` function up into two parts if desired. First tell the PN532 to listen for tags, and then explicitly ask to read the UID from the tag. This can be useful when trying to simultaneously scan tags and run timing sensitive code, like updating neopixels, and don't want to wait for the timeout delay of `read_passive_target`.
This commit is contained in:
parent
ccc822d38e
commit
02c063079a
2 changed files with 123 additions and 8 deletions
|
@ -295,6 +295,19 @@ class PN532:
|
|||
for a response and return a bytearray of response bytes, or None if no
|
||||
response is available within the timeout.
|
||||
"""
|
||||
if not self.send_command(command, params=params, timeout=timeout):
|
||||
return None
|
||||
return self.process_response(
|
||||
command, response_length=response_length, timeout=timeout
|
||||
)
|
||||
|
||||
def send_command(
|
||||
self, command, params=[], timeout=1
|
||||
): # pylint: disable=dangerous-default-value
|
||||
"""Send specified command to the PN532 and wait for an acknowledgment.
|
||||
Will wait up to timeout seconds for the acknowlegment and return True.
|
||||
If no acknowlegment is received, False is returned.
|
||||
"""
|
||||
# Build frame data with command and parameters.
|
||||
data = bytearray(2 + len(params))
|
||||
data[0] = _HOSTTOPN532
|
||||
|
@ -306,12 +319,21 @@ class PN532:
|
|||
self._write_frame(data)
|
||||
except OSError:
|
||||
self._wakeup()
|
||||
return None
|
||||
return False
|
||||
if not self._wait_ready(timeout):
|
||||
return None
|
||||
return False
|
||||
# Verify ACK response and wait to be ready for function response.
|
||||
if not _ACK == self._read_data(len(_ACK)):
|
||||
raise RuntimeError("Did not receive expected ACK from PN532!")
|
||||
return True
|
||||
|
||||
def process_response(self, command, response_length=0, timeout=1):
|
||||
"""Process the response from the PN532 and expect up to response_length
|
||||
bytes back in a response. Note that less than the expected bytes might
|
||||
be returned! Will wait up to timeout seconds for a response and return
|
||||
a bytearray of response bytes, or None if no response is available
|
||||
within the timeout.
|
||||
"""
|
||||
if not self._wait_ready(timeout):
|
||||
return None
|
||||
# Read response bytes.
|
||||
|
@ -348,15 +370,41 @@ class PN532:
|
|||
otherwise a bytearray with the UID of the found card is returned.
|
||||
"""
|
||||
# Send passive read command for 1 card. Expect at most a 7 byte UUID.
|
||||
response = self.listen_for_passive_target(card_baud=card_baud, timeout=timeout)
|
||||
# If no response is available return None to indicate no card is present.
|
||||
if not response:
|
||||
return None
|
||||
return self.get_passive_target(timeout=timeout)
|
||||
|
||||
def listen_for_passive_target(self, card_baud=_MIFARE_ISO14443A, timeout=1):
|
||||
"""Send command to PN532 to begin listening for a Mifare card. This
|
||||
returns True if the command was received succesfully. Note, this does
|
||||
not also return the UID of a card! `get_passive_target` must be called
|
||||
to read the UID when a card is found. If just looking to see if a card
|
||||
is currently present use `read_passive_target` instead.
|
||||
"""
|
||||
# Send passive read command for 1 card. Expect at most a 7 byte UUID.
|
||||
try:
|
||||
response = self.call_function(
|
||||
_COMMAND_INLISTPASSIVETARGET,
|
||||
params=[0x01, card_baud],
|
||||
response_length=19,
|
||||
timeout=timeout,
|
||||
response = self.send_command(
|
||||
_COMMAND_INLISTPASSIVETARGET, params=[0x01, card_baud], timeout=timeout
|
||||
)
|
||||
except BusyError:
|
||||
return None # no card found!
|
||||
return False # _COMMAND_INLISTPASSIVETARGET failed
|
||||
return response
|
||||
|
||||
def get_passive_target(self, timeout=1):
|
||||
"""Will wait up to timeout seconds and return None if no card is found,
|
||||
otherwise a bytearray with the UID of the found card is returned.
|
||||
`listen_for_passive_target` must have been called first in order to put
|
||||
the PN532 into a listening mode.
|
||||
|
||||
It can be useful to use this when using the IRQ pin. Use the IRQ pin to
|
||||
detect when a card is present and then call this function to read the
|
||||
card's UID. This reduces the amount of time spend checking for a card.
|
||||
"""
|
||||
response = self.process_response(
|
||||
_COMMAND_INLISTPASSIVETARGET, response_length=19, timeout=timeout
|
||||
)
|
||||
# If no response is available return None to indicate no card is present.
|
||||
if response is None:
|
||||
return None
|
||||
|
|
67
examples/pn532_simplelisten.py
Normal file
67
examples/pn532_simplelisten.py
Normal file
|
@ -0,0 +1,67 @@
|
|||
"""
|
||||
This example shows connecting to the PN532 with I2C (requires clock
|
||||
stretching support), SPI, or UART. SPI is best, it uses the most pins but
|
||||
is the most reliable and universally supported. In this example, we also connect
|
||||
IRQ and poll that pin for a card. We don't try to read the card until we know
|
||||
there is one present. After initialization, try waving various 13.56MHz RFID
|
||||
cards over it!
|
||||
"""
|
||||
|
||||
import time
|
||||
import board
|
||||
import busio
|
||||
from digitalio import DigitalInOut
|
||||
|
||||
#
|
||||
# NOTE: pick the import that matches the interface being used
|
||||
#
|
||||
from adafruit_pn532.i2c import PN532_I2C
|
||||
|
||||
# from adafruit_pn532.spi import PN532_SPI
|
||||
# from adafruit_pn532.uart import PN532_UART
|
||||
|
||||
# I2C connection:
|
||||
i2c = busio.I2C(board.SCL, board.SDA)
|
||||
|
||||
# Non-hardware
|
||||
# pn532 = PN532_I2C(i2c, debug=False)
|
||||
|
||||
# With I2C, we recommend connecting RSTPD_N (reset) to a digital pin for manual
|
||||
# harware reset
|
||||
reset_pin = DigitalInOut(board.D6)
|
||||
# On Raspberry Pi, you must also connect a pin to P32 "H_Request" for hardware
|
||||
# wakeup! this means we don't need to do the I2C clock-stretch thing
|
||||
req_pin = DigitalInOut(board.D12)
|
||||
# Using the IRQ pin allows us to determine when a card is present by checking
|
||||
# to see if the pin is pulled low.
|
||||
irq_pin = DigitalInOut(board.D10)
|
||||
pn532 = PN532_I2C(i2c, debug=False, reset=reset_pin, req=req_pin, irq=irq_pin)
|
||||
|
||||
# SPI connection:
|
||||
# spi = busio.SPI(board.SCK, board.MOSI, board.MISO)
|
||||
# cs_pin = DigitalInOut(board.D5)
|
||||
# pn532 = PN532_SPI(spi, cs_pin, debug=False)
|
||||
|
||||
# UART connection
|
||||
# uart = busio.UART(board.TX, board.RX, baudrate=115200, timeout=100)
|
||||
# pn532 = PN532_UART(uart, debug=False)
|
||||
|
||||
ic, ver, rev, support = pn532.firmware_version
|
||||
print("Found PN532 with firmware version: {0}.{1}".format(ver, rev))
|
||||
|
||||
# Configure PN532 to communicate with MiFare cards
|
||||
pn532.SAM_configuration()
|
||||
|
||||
# Start listening for a card
|
||||
pn532.listen_for_passive_target()
|
||||
print("Waiting for RFID/NFC card...")
|
||||
while True:
|
||||
# Check if a card is available to read
|
||||
if irq_pin.value == 0:
|
||||
uid = pn532.get_passive_target()
|
||||
print("Found card with UID:", [hex(i) for i in uid])
|
||||
# Start listening for a card again
|
||||
pn532.listen_for_passive_target()
|
||||
else:
|
||||
print(".", end="")
|
||||
time.sleep(0.1)
|
Loading…
Reference in a new issue