diff --git a/adafruit_pn532/adafruit_pn532.py b/adafruit_pn532/adafruit_pn532.py index a0e7dd5..e324ce6 100644 --- a/adafruit_pn532/adafruit_pn532.py +++ b/adafruit_pn532/adafruit_pn532.py @@ -295,6 +295,19 @@ def call_function( 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 @@ def call_function( 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 @@ def read_passive_target(self, card_baud=_MIFARE_ISO14443A, timeout=1): 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 diff --git a/examples/pn532_simplelisten.py b/examples/pn532_simplelisten.py new file mode 100644 index 0000000..29717b7 --- /dev/null +++ b/examples/pn532_simplelisten.py @@ -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)