def felica_ReadWithoutEncryption(self, serviceCodeList: List[int], blockList: List[int]) -> (int, List[bytearray]): """ Sends FeliCa Read Without Encryption command :param serviceCodeList: Service Code List (Big Endian) :param blockList: Block List (Big Endian, This API only accepts 2-byte block list element) :returns: (status, blockData) status 1: Success, < 0: error blockData Block Data """ no_data = [] numService = len(serviceCodeList) if (numService > FELICA_READ_MAX_SERVICE_NUM): DMSG("numService is too large\n") return -1, no_data numBlock = len(blockList) if (numBlock > FELICA_READ_MAX_BLOCK_NUM): DMSG("numBlock is too large\n") return -2, no_data cmd = bytearray([FELICA_CMD_READ_WITHOUT_ENCRYPTION]) + self._felicaIDm[:8] + bytearray([numService]) for i in range(numService): cmd.append(serviceCodeList[i] & 0xFF) cmd.append((serviceCodeList[i] >> 8) & 0xff) cmd.append(numBlock) for i in range(numBlock): cmd.append((blockList[i] >> 8) & 0xFF) cmd.append(blockList[i] & 0xff) status, response = self.felica_SendCommand(cmd) if (status != 1): DMSG("Read Without Encryption command failed\n") return -3, no_data # length check responseLength = len(response) if (responseLength != 12 + 16 * numBlock): DMSG("Read Without Encryption command failed (wrong response length)\n") return -4, no_data # status flag check if (response[9] != 0 or response[10] != 0): DMSG("Read Without Encryption command failed (Status Flag: ") DMSG_HEX(response[9]) DMSG_HEX(response[10]) DMSG(")\n") return -5, no_data k = 12 blockData = [] for i in range(numBlock): start = 12+ i * 16 blockData.append(response[start: start + 16]) return 1, blockData
def readPassiveTargetID(self, cardbaudrate: int, timeout: int = 1000, inlist: bool = False) -> (bool, bytearray): """ Waits for an ISO14443A target to enter the field :param cardBaudRate: Baud rate of the card :param timeout: The number of tries before timing out :param inlist: If set to True, the card will be inlisted :returns: (True if successful, uid of the card) """ header = bytearray([ PN532_COMMAND_INLISTPASSIVETARGET, 1, # max 1 cards at once (we can set this to 2 later) cardbaudrate & 0xFF, ]) if (self._interface.writeCommand(header)) : return False, bytearray() # command failed # read data packet status, response = self._interface.readResponse(timeout) if (status < 0): return False, bytearray() # check some basic stuff # ISO14443A card response should be in the following format: # byte Description # ------------- ------------------------------------------ # b0 Tags Found # b1 Tag Number (only one used in this example) # b2..3 SENS_RES # b4 SEL_RES # b5 NFCID Length # b6..NFCIDLen NFCID if (response[0] != 1): return False, bytearray() sens_res = response[2] sens_res <<= 8 sens_res |= response[3] DMSG("ATQA: 0x") DMSG_HEX(sens_res) DMSG("SAK: 0x") DMSG_HEX(response[4]) DMSG("\n") # Card appears to be Mifare Classic uidLength = response[5] uid = bytearray(response[6:6 + uidLength]) if (inlist) : self.inListedTag = response[1] return True, uid
def felica_WriteWithoutEncryption(self, serviceCodeList: List[int], blockList: List[int], blockData: List[bytearray]) -> int: """ Sends FeliCa Write Without Encryption command :param serviceCodeList: Service Code List (Big Endian) :param blockList: Block List (Big Endian, This API only accepts 2-byte block list element) :returns: status 1: Success, < 0: error """ numService, numBlock = len(serviceCodeList), len(blockList) if (numService > FELICA_WRITE_MAX_SERVICE_NUM): DMSG("numService is too large\n") return -1 if (numBlock > FELICA_WRITE_MAX_BLOCK_NUM): DMSG("numBlock is too large\n") return -2 cmd = bytearray([FELICA_CMD_WRITE_WITHOUT_ENCRYPTION]) + self._felicaIDm[:8] + bytearray([numService]) for i in range(numService): cmd.append(serviceCodeList[i] & 0xFF) cmd.append((serviceCodeList[i] >> 8) & 0xff) cmd.append(numBlock) for i in range(numBlock): cmd.append((blockList[i] >> 8) & 0xFF) cmd.append(blockList[i] & 0xff) for i in range(numBlock): for k in range(16): cmd.append(blockData[i][k]) status, response = self.felica_SendCommand(cmd) responseLength = len(response) if (status != 1): DMSG("Write Without Encryption command failed\n") return -3 # length check if (responseLength != 11): DMSG("Write Without Encryption command failed (wrong response length)\n") return -4 # status flag check if (response[9] != 0 or response[10] != 0): DMSG("Write Without Encryption command failed (Status Flag: ") DMSG_HEX(response[9]) DMSG_HEX(response[10]) DMSG(")\n") return -5 return 1
def writeCommand(self, header: bytearray, body: bytearray = bytearray()) -> int: # dump serial buffer if (self._serial.inWaiting()): DMSG("Dump serial buffer: ") ret = self._serial.read() DMSG_HEX(ret) self.command = header[0] self._serial.write( PN532_WAKEUP ) # Extra long Preamble in case PN532 is in low VBat mode self._serial.write( bytearray([PN532_PREAMBLE, PN532_STARTCODE1, PN532_STARTCODE2])) length = len(header) + len( body) + 1 # length of data field: TFI + DATA self._serial.write( bytearray([length, (~length + 1) & 0xff, PN532_HOSTTOPN532])) # checksum of length dsum = PN532_HOSTTOPN532 + sum(header) + sum(body) DMSG("\nWrite: ") self._serial.write(header) self._serial.write(body) checksum = (~dsum + 1) & 0xff # checksum of TFI + DATA self._serial.write(bytearray([checksum, PN532_POSTAMBLE])) return self.readAckFrame()
def felica_Release(self) -> int: """ Release FeliCa card :returns: 1: Success, < 0: error """ # InRelease header = bytearray([ PN532_COMMAND_INRELEASE, 0x00, # All target ]) DMSG("Release all FeliCa target\n") if (self._interface.writeCommand(header)): DMSG("No ACK\n") return -1 # no ACK # Wait card response frameLength, response = self._interface.readResponse() if (frameLength < 0): DMSG("Could not receive response\n") return -2 # Check status (response[0]) if ((response[0] & 0x3F)!=0): DMSG("Status code indicates an error: ") DMSG_HEX(response[7]) DMSG("\n") return -3 return 1
def wakeup(self): self._serial.write(PN532_WAKEUP) # dump serial buffer if (self._serial.inWaiting()): DMSG("Dump serial buffer: ") ret = self._serial.read() DMSG_HEX(ret)
def readGPIO(self) -> int: """ Reads the state of the PN532's GPIO pins (P3) :returns: An 8-bit value containing the pin state where: pinState[0] = P30 pinState[1] = P31 pinState[2] = P32 pinState[3] = P33 pinState[4] = P34 pinState[5] = P35 """ header = bytearray([PN532_COMMAND_READGPIO]) # Send the READGPIO command (0x0C) if (self._interface.writeCommand(header)): return 0x0 status, response = self._interface.readResponse() # READGPIO response without prefix and suffix should be in the following format: # # byte Description # ------------- ------------------------------------------ # b0 P3 GPIO Pins # b1 P7 GPIO Pins (not used ... taken by I2C) # b2 Interface Mode Pins (not used ... bus select pins) DMSG("P3 GPIO: ") DMSG_HEX(response[0]) DMSG("P7 GPIO: ") DMSG_HEX(response[1]) DMSG("I0I1 GPIO: ") DMSG_HEX(response[2]) DMSG("\n") return response[0]
def felica_SendCommand(self, command: bytearray) -> (int, bytearray): """ Sends FeliCa command to the currently inlisted peer :param command: FeliCa command packet. (e.g. 00 FF FF 00 00 for Polling command) :returns: (status, response) status 1: Success, < 0: error response: FeliCa response packet. (e.g. 01 NFCID2(8 bytes) PAD(8 bytes) for Polling response) """ commandlength = len(command) no_data = bytearray() if (commandlength > 0xFE): DMSG("Command length too long\n") return -1, no_data header = bytearray([ PN532_COMMAND_INDATAEXCHANGE, self.inListedTag, commandlength + 1, ]) if (self._interface.writeCommand(header, command)): DMSG("Could not send FeliCa command\n") return -2, no_data # Wait card response status, response = self._interface.readResponse() if (status < 0): DMSG("Could not receive response\n") return -3, no_data # Check status (response[0]) if ((response[0] & 0x3F) != 0): DMSG("Status code indicates an error: ") DMSG_HEX(response[0]) DMSG("\n") return -4, no_data # length check responseLength = response[1] - 1 if ((status - 2) != responseLength): DMSG("Wrong response length\n") return -5, no_data response_data = response[2: 2 + responseLength] return 1, response_data
def writeGPIO(self, pinstate: int) -> bool: """ Writes an 8-bit value that sets the state of the PN532's GPIO (P3) :warning: This function is provided exclusively for board testing and is dangerous since it will throw an error if any pin other than the ones marked "Can be used as GPIO" are modified! All pins that can not be used as GPIO should ALWAYS be left high (value = 1) or the system will become unstable and a HW reset will be required to recover the PN532. pinState[0] = P30 Can be used as GPIO pinState[1] = P31 Can be used as GPIO pinState[2] = P32 *** RESERVED (Must be 1!) *** pinState[3] = P33 Can be used as GPIO pinState[4] = P34 *** RESERVED (Must be 1!) *** pinState[5] = P35 Can be used as GPIO :returns 1 if everything executed properly, 0 for an error """ # Make sure pinstate does not try to toggle P32 or P34 pinstate |= (1 << PN532_GPIO_P32) | (1 << PN532_GPIO_P34) # Fill command buffer header = bytearray([PN532_COMMAND_WRITEGPIO, (PN532_GPIO_VALIDATIONBIT | pinstate), # P3 Pins 0x00]) # P7 GPIO Pins (not used ... taken by I2C) DMSG("Writing P3 GPIO: ") DMSG_HEX(header) DMSG("\n") # Send the WRITEGPIO command (0x0E) if (self._interface.writeCommand(header)): return False status, response = self._interface.readResponse() return status >= 0
def felica_Polling(self, systemCode: int, requestCode: int, timeout: int = 1000) -> (int, bytearray, bytearray, int): """ Poll FeliCa card. PN532 acting as reader/initiator, peer acting as card/responder. :param timeout: :param systemCode: Designation of System Code. When sending FFFFh as System Code, all FeliCa cards can return response. :param requestCode: Designation of Request Data as follows: 00h: No Request 01h: System Code request (to acquire System Code of the card) 02h: Communication performance request :returns: (status, idm, pwm, systemCodeResponse) status 0 = no card, 1 = FeliCa card detected, <0 = error idm IDm of the card (8 bytes) pmm PMm of the card (8 bytes) systemCodeResponse System Code of the card (Optional, 2bytes) """ header = bytearray([ PN532_COMMAND_INLISTPASSIVETARGET, 1, 1, FELICA_CMD_POLLING, (systemCode >> 8) & 0xFF, systemCode & 0xFF, requestCode & 0xFF, 0, ]) no_data = bytearray() if (self._interface.writeCommand(header)): DMSG("Could not send Polling command\n") return -1, no_data, no_data, 0 status, response = self._interface.readResponse(timeout) if (status < 0): DMSG("Could not receive response\n") return -2, no_data, no_data, 0 # Check NbTg (response[7]) if (response[0] == 0): DMSG("No card had detected\n") return 0, no_data, no_data, 0 elif (response[0] != 1): DMSG("Unhandled number of targets inlisted. NbTg: ") DMSG_HEX(response[7]) DMSG("\n") return -3, no_data, no_data, 0 self.inListedTag = response[1] DMSG("Tag number: ") DMSG_HEX(response[1]) DMSG("\n") # length check responseLength = response[2] if (responseLength != 18 and responseLength != 20): DMSG("Wrong response length\n") return -4, no_data, no_data, 0 idm = response[4:12] pwm = response[12:24] self._felicaIDm = idm self._felicaPMm = pwm if (responseLength == 20): systemCodeResponse = (response[20] << 8) + response[21] else: systemCodeResponse = 0 return 1, idm, pwm, systemCodeResponse