/ adafruit_pn532 / adafruit_pn532.py
adafruit_pn532.py
  1  # Adafruit PN532 NFC/RFID control library.
  2  # Author: Tony DiCola
  3  #
  4  # The MIT License (MIT)
  5  #
  6  # Copyright (c) 2015-2018 Adafruit Industries
  7  #
  8  # Permission is hereby granted, free of charge, to any person obtaining a copy
  9  # of this software and associated documentation files (the "Software"), to deal
 10  # in the Software without restriction, including without limitation the rights
 11  # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 12  # copies of the Software, and to permit persons to whom the Software is
 13  # furnished to do so, subject to the following conditions:
 14  #
 15  # The above copyright notice and this permission notice shall be included in all
 16  # copies or substantial portions of the Software.
 17  #
 18  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 19  # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 20  # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 21  # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 22  # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 23  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 24  # SOFTWARE.
 25  """
 26  ``adafruit_pn532``
 27  ====================================================
 28  
 29  This module will let you communicate with a PN532 RFID/NFC shield or breakout
 30  using I2C, SPI or UART.
 31  
 32  * Author(s): Original Raspberry Pi code by Tony DiCola, CircuitPython by ladyada
 33  
 34  Implementation Notes
 35  --------------------
 36  
 37  **Hardware:**
 38  
 39  * Adafruit `PN532 Breakout <https://www.adafruit.com/product/364>`_
 40  * Adafruit `PN532 Shield <https://www.adafruit.com/product/789>`_
 41  
 42  **Software and Dependencies:**
 43  
 44  * Adafruit CircuitPython firmware for the supported boards:
 45    https://github.com/adafruit/circuitpython/releases
 46  * Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice
 47  """
 48  
 49  import time
 50  from digitalio import Direction
 51  
 52  from micropython import const
 53  
 54  __version__ = "0.0.0-auto.0"
 55  __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_PN532.git"
 56  
 57  # pylint: disable=bad-whitespace
 58  _PREAMBLE = const(0x00)
 59  _STARTCODE1 = const(0x00)
 60  _STARTCODE2 = const(0xFF)
 61  _POSTAMBLE = const(0x00)
 62  
 63  _HOSTTOPN532 = const(0xD4)
 64  _PN532TOHOST = const(0xD5)
 65  
 66  # PN532 Commands
 67  _COMMAND_DIAGNOSE = const(0x00)
 68  _COMMAND_GETFIRMWAREVERSION = const(0x02)
 69  _COMMAND_GETGENERALSTATUS = const(0x04)
 70  _COMMAND_READREGISTER = const(0x06)
 71  _COMMAND_WRITEREGISTER = const(0x08)
 72  _COMMAND_READGPIO = const(0x0C)
 73  _COMMAND_WRITEGPIO = const(0x0E)
 74  _COMMAND_SETSERIALBAUDRATE = const(0x10)
 75  _COMMAND_SETPARAMETERS = const(0x12)
 76  _COMMAND_SAMCONFIGURATION = const(0x14)
 77  _COMMAND_POWERDOWN = const(0x16)
 78  _COMMAND_RFCONFIGURATION = const(0x32)
 79  _COMMAND_RFREGULATIONTEST = const(0x58)
 80  _COMMAND_INJUMPFORDEP = const(0x56)
 81  _COMMAND_INJUMPFORPSL = const(0x46)
 82  _COMMAND_INLISTPASSIVETARGET = const(0x4A)
 83  _COMMAND_INATR = const(0x50)
 84  _COMMAND_INPSL = const(0x4E)
 85  _COMMAND_INDATAEXCHANGE = const(0x40)
 86  _COMMAND_INCOMMUNICATETHRU = const(0x42)
 87  _COMMAND_INDESELECT = const(0x44)
 88  _COMMAND_INRELEASE = const(0x52)
 89  _COMMAND_INSELECT = const(0x54)
 90  _COMMAND_INAUTOPOLL = const(0x60)
 91  _COMMAND_TGINITASTARGET = const(0x8C)
 92  _COMMAND_TGSETGENERALBYTES = const(0x92)
 93  _COMMAND_TGGETDATA = const(0x86)
 94  _COMMAND_TGSETDATA = const(0x8E)
 95  _COMMAND_TGSETMETADATA = const(0x94)
 96  _COMMAND_TGGETINITIATORCOMMAND = const(0x88)
 97  _COMMAND_TGRESPONSETOINITIATOR = const(0x90)
 98  _COMMAND_TGGETTARGETSTATUS = const(0x8A)
 99  
100  _RESPONSE_INDATAEXCHANGE = const(0x41)
101  _RESPONSE_INLISTPASSIVETARGET = const(0x4B)
102  
103  _WAKEUP = const(0x55)
104  
105  _MIFARE_ISO14443A = const(0x00)
106  
107  # Mifare Commands
108  MIFARE_CMD_AUTH_A = const(0x60)
109  MIFARE_CMD_AUTH_B = const(0x61)
110  MIFARE_CMD_READ = const(0x30)
111  MIFARE_CMD_WRITE = const(0xA0)
112  MIFARE_CMD_TRANSFER = const(0xB0)
113  MIFARE_CMD_DECREMENT = const(0xC0)
114  MIFARE_CMD_INCREMENT = const(0xC1)
115  MIFARE_CMD_STORE = const(0xC2)
116  MIFARE_ULTRALIGHT_CMD_WRITE = const(0xA2)
117  
118  # Prefixes for NDEF Records (to identify record type)
119  NDEF_URIPREFIX_NONE = const(0x00)
120  NDEF_URIPREFIX_HTTP_WWWDOT = const(0x01)
121  NDEF_URIPREFIX_HTTPS_WWWDOT = const(0x02)
122  NDEF_URIPREFIX_HTTP = const(0x03)
123  NDEF_URIPREFIX_HTTPS = const(0x04)
124  NDEF_URIPREFIX_TEL = const(0x05)
125  NDEF_URIPREFIX_MAILTO = const(0x06)
126  NDEF_URIPREFIX_FTP_ANONAT = const(0x07)
127  NDEF_URIPREFIX_FTP_FTPDOT = const(0x08)
128  NDEF_URIPREFIX_FTPS = const(0x09)
129  NDEF_URIPREFIX_SFTP = const(0x0A)
130  NDEF_URIPREFIX_SMB = const(0x0B)
131  NDEF_URIPREFIX_NFS = const(0x0C)
132  NDEF_URIPREFIX_FTP = const(0x0D)
133  NDEF_URIPREFIX_DAV = const(0x0E)
134  NDEF_URIPREFIX_NEWS = const(0x0F)
135  NDEF_URIPREFIX_TELNET = const(0x10)
136  NDEF_URIPREFIX_IMAP = const(0x11)
137  NDEF_URIPREFIX_RTSP = const(0x12)
138  NDEF_URIPREFIX_URN = const(0x13)
139  NDEF_URIPREFIX_POP = const(0x14)
140  NDEF_URIPREFIX_SIP = const(0x15)
141  NDEF_URIPREFIX_SIPS = const(0x16)
142  NDEF_URIPREFIX_TFTP = const(0x17)
143  NDEF_URIPREFIX_BTSPP = const(0x18)
144  NDEF_URIPREFIX_BTL2CAP = const(0x19)
145  NDEF_URIPREFIX_BTGOEP = const(0x1A)
146  NDEF_URIPREFIX_TCPOBEX = const(0x1B)
147  NDEF_URIPREFIX_IRDAOBEX = const(0x1C)
148  NDEF_URIPREFIX_FILE = const(0x1D)
149  NDEF_URIPREFIX_URN_EPC_ID = const(0x1E)
150  NDEF_URIPREFIX_URN_EPC_TAG = const(0x1F)
151  NDEF_URIPREFIX_URN_EPC_PAT = const(0x20)
152  NDEF_URIPREFIX_URN_EPC_RAW = const(0x21)
153  NDEF_URIPREFIX_URN_EPC = const(0x22)
154  NDEF_URIPREFIX_URN_NFC = const(0x23)
155  
156  _GPIO_VALIDATIONBIT = const(0x80)
157  _GPIO_P30 = const(0)
158  _GPIO_P31 = const(1)
159  _GPIO_P32 = const(2)
160  _GPIO_P33 = const(3)
161  _GPIO_P34 = const(4)
162  _GPIO_P35 = const(5)
163  
164  _ACK = b"\x00\x00\xFF\x00\xFF\x00"
165  _FRAME_START = b"\x00\x00\xFF"
166  # pylint: enable=bad-whitespace
167  
168  
169  def _reset(pin):
170      """Perform a hardware reset toggle"""
171      pin.direction = Direction.OUTPUT
172      pin.value = True
173      time.sleep(0.1)
174      pin.value = False
175      time.sleep(0.5)
176      pin.value = True
177      time.sleep(0.1)
178  
179  
180  class BusyError(Exception):
181      """Base class for exceptions in this module."""
182  
183  
184  class PN532:
185      """PN532 driver base, must be extended for I2C/SPI/UART interfacing"""
186  
187      def __init__(self, *, debug=False, reset=None):
188          """Create an instance of the PN532 class
189          """
190          self.debug = debug
191          if reset:
192              if debug:
193                  print("Resetting")
194              _reset(reset)
195  
196          try:
197              self._wakeup()
198              _ = self.firmware_version  # first time often fails, try 2ce
199              return
200          except (BusyError, RuntimeError):
201              pass
202          _ = self.firmware_version
203  
204      def _read_data(self, count):
205          # Read raw data from device, not including status bytes:
206          # Subclasses MUST implement this!
207          raise NotImplementedError
208  
209      def _write_data(self, framebytes):
210          # Write raw bytestring data to device, not including status bytes:
211          # Subclasses MUST implement this!
212          raise NotImplementedError
213  
214      def _wait_ready(self, timeout):
215          # Check if busy up to max length of 'timeout' seconds
216          # Subclasses MUST implement this!
217          raise NotImplementedError
218  
219      def _wakeup(self):
220          # Send special command to wake up
221          raise NotImplementedError
222  
223      def _write_frame(self, data):
224          """Write a frame to the PN532 with the specified data bytearray."""
225          assert (
226              data is not None and 1 < len(data) < 255
227          ), "Data must be array of 1 to 255 bytes."
228          # Build frame to send as:
229          # - Preamble (0x00)
230          # - Start code  (0x00, 0xFF)
231          # - Command length (1 byte)
232          # - Command length checksum
233          # - Command bytes
234          # - Checksum
235          # - Postamble (0x00)
236          length = len(data)
237          frame = bytearray(length + 8)
238          frame[0] = _PREAMBLE
239          frame[1] = _STARTCODE1
240          frame[2] = _STARTCODE2
241          checksum = sum(frame[0:3])
242          frame[3] = length & 0xFF
243          frame[4] = (~length + 1) & 0xFF
244          frame[5:-2] = data
245          checksum += sum(data)
246          frame[-2] = ~checksum & 0xFF
247          frame[-1] = _POSTAMBLE
248          # Send frame.
249          if self.debug:
250              print("Write frame: ", [hex(i) for i in frame])
251          self._write_data(bytes(frame))
252  
253      def _read_frame(self, length):
254          """Read a response frame from the PN532 of at most length bytes in size.
255          Returns the data inside the frame if found, otherwise raises an exception
256          if there is an error parsing the frame.  Note that less than length bytes
257          might be returned!
258          """
259          # Read frame with expected length of data.
260          response = self._read_data(length + 8)
261          if self.debug:
262              print("Read frame:", [hex(i) for i in response])
263  
264          # Swallow all the 0x00 values that preceed 0xFF.
265          offset = 0
266          while response[offset] == 0x00:
267              offset += 1
268              if offset >= len(response):
269                  raise RuntimeError("Response frame preamble does not contain 0x00FF!")
270          if response[offset] != 0xFF:
271              raise RuntimeError("Response frame preamble does not contain 0x00FF!")
272          offset += 1
273          if offset >= len(response):
274              raise RuntimeError("Response contains no data!")
275          # Check length & length checksum match.
276          frame_len = response[offset]
277          if (frame_len + response[offset + 1]) & 0xFF != 0:
278              raise RuntimeError("Response length checksum did not match length!")
279          # Check frame checksum value matches bytes.
280          checksum = sum(response[offset + 2 : offset + 2 + frame_len + 1]) & 0xFF
281          if checksum != 0:
282              raise RuntimeError(
283                  "Response checksum did not match expected value: ", checksum
284              )
285          # Return frame data.
286          return response[offset + 2 : offset + 2 + frame_len]
287  
288      def call_function(
289          self, command, response_length=0, params=[], timeout=1
290      ):  # pylint: disable=dangerous-default-value
291          """Send specified command to the PN532 and expect up to response_length
292          bytes back in a response.  Note that less than the expected bytes might
293          be returned!  Params can optionally specify an array of bytes to send as
294          parameters to the function call.  Will wait up to timeout seconds
295          for a response and return a bytearray of response bytes, or None if no
296          response is available within the timeout.
297          """
298          if not self.send_command(command, params=params, timeout=timeout):
299              return None
300          return self.process_response(
301              command, response_length=response_length, timeout=timeout
302          )
303  
304      def send_command(
305          self, command, params=[], timeout=1
306      ):  # pylint: disable=dangerous-default-value
307          """Send specified command to the PN532 and wait for an acknowledgment.
308          Will wait up to timeout seconds for the acknowlegment and return True.
309          If no acknowlegment is received, False is returned.
310          """
311          # Build frame data with command and parameters.
312          data = bytearray(2 + len(params))
313          data[0] = _HOSTTOPN532
314          data[1] = command & 0xFF
315          for i, val in enumerate(params):
316              data[2 + i] = val
317          # Send frame and wait for response.
318          try:
319              self._write_frame(data)
320          except OSError:
321              self._wakeup()
322              return False
323          if not self._wait_ready(timeout):
324              return False
325          # Verify ACK response and wait to be ready for function response.
326          if not _ACK == self._read_data(len(_ACK)):
327              raise RuntimeError("Did not receive expected ACK from PN532!")
328          return True
329  
330      def process_response(self, command, response_length=0, timeout=1):
331          """Process the response from the PN532 and expect up to response_length
332          bytes back in a response.  Note that less than the expected bytes might
333          be returned! Will wait up to timeout seconds for a response and return
334          a bytearray of response bytes, or None if no response is available
335          within the timeout.
336          """
337          if not self._wait_ready(timeout):
338              return None
339          # Read response bytes.
340          response = self._read_frame(response_length + 2)
341          # Check that response is for the called function.
342          if not (response[0] == _PN532TOHOST and response[1] == (command + 1)):
343              raise RuntimeError("Received unexpected command response!")
344          # Return response data.
345          return response[2:]
346  
347      @property
348      def firmware_version(self):
349          """Call PN532 GetFirmwareVersion function and return a tuple with the IC,
350          Ver, Rev, and Support values.
351          """
352          response = self.call_function(_COMMAND_GETFIRMWAREVERSION, 4, timeout=0.5)
353          if response is None:
354              raise RuntimeError("Failed to detect the PN532")
355          return tuple(response)
356  
357      def SAM_configuration(self):  # pylint: disable=invalid-name
358          """Configure the PN532 to read MiFare cards."""
359          # Send SAM configuration command with configuration for:
360          # - 0x01, normal mode
361          # - 0x14, timeout 50ms * 20 = 1 second
362          # - 0x01, use IRQ pin
363          # Note that no other verification is necessary as call_function will
364          # check the command was executed as expected.
365          self.call_function(_COMMAND_SAMCONFIGURATION, params=[0x01, 0x14, 0x01])
366  
367      def read_passive_target(self, card_baud=_MIFARE_ISO14443A, timeout=1):
368          """Wait for a MiFare card to be available and return its UID when found.
369          Will wait up to timeout seconds and return None if no card is found,
370          otherwise a bytearray with the UID of the found card is returned.
371          """
372          # Send passive read command for 1 card.  Expect at most a 7 byte UUID.
373          response = self.listen_for_passive_target(card_baud=card_baud, timeout=timeout)
374          # If no response is available return None to indicate no card is present.
375          if not response:
376              return None
377          return self.get_passive_target(timeout=timeout)
378  
379      def listen_for_passive_target(self, card_baud=_MIFARE_ISO14443A, timeout=1):
380          """Send command to PN532 to begin listening for a Mifare card. This
381          returns True if the command was received succesfully. Note, this does
382          not also return the UID of a card! `get_passive_target` must be called
383          to read the UID when a card is found. If just looking to see if a card
384          is currently present use `read_passive_target` instead.
385          """
386          # Send passive read command for 1 card.  Expect at most a 7 byte UUID.
387          try:
388              response = self.send_command(
389                  _COMMAND_INLISTPASSIVETARGET, params=[0x01, card_baud], timeout=timeout
390              )
391          except BusyError:
392              return False  # _COMMAND_INLISTPASSIVETARGET failed
393          return response
394  
395      def get_passive_target(self, timeout=1):
396          """Will wait up to timeout seconds and return None if no card is found,
397          otherwise a bytearray with the UID of the found card is returned.
398          `listen_for_passive_target` must have been called first in order to put
399          the PN532 into a listening mode.
400  
401          It can be useful to use this when using the IRQ pin. Use the IRQ pin to
402          detect when a card is present and then call this function to read the
403          card's UID. This reduces the amount of time spend checking for a card.
404          """
405          response = self.process_response(
406              _COMMAND_INLISTPASSIVETARGET, response_length=19, timeout=timeout
407          )
408          # If no response is available return None to indicate no card is present.
409          if response is None:
410              return None
411          # Check only 1 card with up to a 7 byte UID is present.
412          if response[0] != 0x01:
413              raise RuntimeError("More than one card detected!")
414          if response[5] > 7:
415              raise RuntimeError("Found card with unexpectedly long UID!")
416          # Return UID of card.
417          return response[6 : 6 + response[5]]
418  
419      def mifare_classic_authenticate_block(
420          self, uid, block_number, key_number, key
421      ):  # pylint: disable=invalid-name
422          """Authenticate specified block number for a MiFare classic card.  Uid
423          should be a byte array with the UID of the card, block number should be
424          the block to authenticate, key number should be the key type (like
425          MIFARE_CMD_AUTH_A or MIFARE_CMD_AUTH_B), and key should be a byte array
426          with the key data.  Returns True if the block was authenticated, or False
427          if not authenticated.
428          """
429          # Build parameters for InDataExchange command to authenticate MiFare card.
430          uidlen = len(uid)
431          keylen = len(key)
432          params = bytearray(3 + uidlen + keylen)
433          params[0] = 0x01  # Max card numbers
434          params[1] = key_number & 0xFF
435          params[2] = block_number & 0xFF
436          params[3 : 3 + keylen] = key
437          params[3 + keylen :] = uid
438          # Send InDataExchange request and verify response is 0x00.
439          response = self.call_function(
440              _COMMAND_INDATAEXCHANGE, params=params, response_length=1
441          )
442          return response[0] == 0x00
443  
444      def mifare_classic_read_block(self, block_number):
445          """Read a block of data from the card.  Block number should be the block
446          to read.  If the block is successfully read a bytearray of length 16 with
447          data starting at the specified block will be returned.  If the block is
448          not read then None will be returned.
449          """
450          # Send InDataExchange request to read block of MiFare data.
451          response = self.call_function(
452              _COMMAND_INDATAEXCHANGE,
453              params=[0x01, MIFARE_CMD_READ, block_number & 0xFF],
454              response_length=17,
455          )
456          # Check first response is 0x00 to show success.
457          if response[0] != 0x00:
458              return None
459          # Return first 4 bytes since 16 bytes are always returned.
460          return response[1:]
461  
462      def mifare_classic_write_block(self, block_number, data):
463          """Write a block of data to the card.  Block number should be the block
464          to write and data should be a byte array of length 16 with the data to
465          write.  If the data is successfully written then True is returned,
466          otherwise False is returned.
467          """
468          assert (
469              data is not None and len(data) == 16
470          ), "Data must be an array of 16 bytes!"
471          # Build parameters for InDataExchange command to do MiFare classic write.
472          params = bytearray(19)
473          params[0] = 0x01  # Max card numbers
474          params[1] = MIFARE_CMD_WRITE
475          params[2] = block_number & 0xFF
476          params[3:] = data
477          # Send InDataExchange request.
478          response = self.call_function(
479              _COMMAND_INDATAEXCHANGE, params=params, response_length=1
480          )
481          return response[0] == 0x0
482  
483      def ntag2xx_write_block(self, block_number, data):
484          """Write a block of data to the card.  Block number should be the block
485          to write and data should be a byte array of length 4 with the data to
486          write.  If the data is successfully written then True is returned,
487          otherwise False is returned.
488          """
489          assert data is not None and len(data) == 4, "Data must be an array of 4 bytes!"
490          # Build parameters for InDataExchange command to do NTAG203 classic write.
491          params = bytearray(3 + len(data))
492          params[0] = 0x01  # Max card numbers
493          params[1] = MIFARE_ULTRALIGHT_CMD_WRITE
494          params[2] = block_number & 0xFF
495          params[3:] = data
496          # Send InDataExchange request.
497          response = self.call_function(
498              _COMMAND_INDATAEXCHANGE, params=params, response_length=1
499          )
500          return response[0] == 0x00
501  
502      def ntag2xx_read_block(self, block_number):
503          """Read a block of data from the card.  Block number should be the block
504          to read.  If the block is successfully read a bytearray of length 16 with
505          data starting at the specified block will be returned.  If the block is
506          not read then None will be returned.
507          """
508          return self.mifare_classic_read_block(block_number)[
509              0:4
510          ]  # only 4 bytes per page