/ 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