diff --git a/README.md b/README.md index 9f5f904..05bb409 100644 --- a/README.md +++ b/README.md @@ -41,9 +41,9 @@ This is a port of [Seeed Studios's PN532 Arduino Library](https://github.com/See ## Power The Raspberry Pi 3.3v regulator does not provide enough current to drive the PN532 chip. -If you try to run the PN532 off your Raspberry Pi it will reset randomly and may not respond to commands. -Instead you will need another power source (3.3v) to power the PN532. Some people have been able to run -the PN532 off of the 5V rail of the raspberry pi but this is not the recommended way of powering it. +If you try to run the PN532 off your Raspberry Pi 3.3v it will reset randomly and may not respond to commands. +Instead you will need another power source (3.3v or 5v) to power the PN532. It is generally safe to tap into the +5v pin on the Raspberry Pi so long as your power supply can provide enough power for the PN532 and the pi. ## I2C Interface diff --git a/pn532pi/interfaces/pn532i2c.py b/pn532pi/interfaces/pn532i2c.py index 7f0a192..ffd2005 100644 --- a/pn532pi/interfaces/pn532i2c.py +++ b/pn532pi/interfaces/pn532i2c.py @@ -2,6 +2,7 @@ from pn532pi.nfc.pn532_log import DMSG from quick2wire.i2c import I2CMaster, writing, reading +import errno from pn532pi.interfaces.pn532Interface import Pn532Interface, PN532_PREAMBLE, PN532_STARTCODE1, PN532_STARTCODE2, PN532_HOSTTOPN532, \ PN532_INVALID_FRAME, PN532_POSTAMBLE, PN532_PN532TOHOST, PN532_ACK_WAIT_TIME, PN532_TIMEOUT, \ @@ -154,18 +155,24 @@ def _readAckFrame(self) -> int: DMSG('\n') t = 0 - while 1: - responses = self._wire.transaction(reading(PN532_I2C_ADDRESS, len(PN532_ACK) + 1)) - data = bytearray(responses[0]) - if (data[0] & 1): - # check first byte --- status - break # PN532 is ready - + while t <= PN532_ACK_WAIT_TIME: + try: + responses = self._wire.transaction(reading(PN532_I2C_ADDRESS, len(PN532_ACK) + 1)) + data = bytearray(responses[0]) + if (data[0] & 1): + # check first byte --- status + break # PN532 is ready + except IOError as e: + # As of Python 3.3 IOError is the same as OSError so we should check the error code + if e.errno != errno.EIO: + raise # Reraise the error + # Otherwise do nothing, sleep and try again + time.sleep(.001) # sleep 1 ms t+=1 - if (t > PN532_ACK_WAIT_TIME): - DMSG("Time out when waiting for ACK\n") - return PN532_TIMEOUT + else: + DMSG("Time out when waiting for ACK\n") + return PN532_TIMEOUT DMSG("ready at : ") DMSG(time.time()) diff --git a/pn532pi/nfc/pn532.py b/pn532pi/nfc/pn532.py index 9c71c73..1e430ea 100644 --- a/pn532pi/nfc/pn532.py +++ b/pn532pi/nfc/pn532.py @@ -4,7 +4,7 @@ @license BSD """ -from typing import List +from typing import List, NamedTuple from pn532pi.interfaces.pn532Interface import Pn532Interface, PN532_TIMEOUT @@ -126,6 +126,33 @@ FELICA_WRITE_MAX_BLOCK_NUM = 10 # for typical FeliCa card FELICA_REQ_SERVICE_MAX_NODE_NUM = 32 +# Support options in FW Version Info +SUPPORTS_ISO18092 = 0b100 +SUPPORTS_ISO14443_A = 0b010 +SUPPORTS_ISO14443_B = 0b001 +class Pn532FirmwareInfo(NamedTuple): + """ + Information contained in the response to the + GetFirmwareVersion command + """ + ic_version: int + fw_major: int + fw_minor: int + support_opts: int + iso18092: bool + iso14443_a: bool + iso14443_b: bool + + def __str__(self) -> str: + all_opts = [('ISO18092', self.iso18092), ('ISO4443-A', self.iso14443_a), + ('ISO4443-B', self.iso14443_b)] + opts = [name for name, supported in all_opts if supported] + return (f'Pn532FirmwareInfo(IC Version: {hex(self.ic_version)}, ' + f'FW Version: {self.fw_major}.{self.fw_minor}, ' + f'Supports: {opts} ({hex(self.support_opts)}))') + + def __repr__(self) -> str: + return str(self) class Pn532: def __init__(self, interface: Pn532Interface): @@ -149,6 +176,8 @@ def getFirmwareVersion(self) -> int: """ Checks the firmware version of the PN5xx chip + See https://www.nxp.com/docs/en/user-guide/141520.pdf page 73 + :returns: The chip's firmware version and ID """ if (self._interface.writeCommand(bytearray([PN532_COMMAND_GETFIRMWAREVERSION]))): @@ -168,6 +197,20 @@ def getFirmwareVersion(self) -> int: # response |= self.pn532_packetbuffer[3] return int.from_bytes(response, byteorder='big') + + def getFirmwareInfo(self) -> tuple: + """ + Parse the firmware version info into its separate parts + Format: |ic_version[8] | fw_version[8] | fw_revision[8] | support_opts[8]| + """ + firmware_data = self.getFirmwareVersion() + opts, fw_min, fw_maj, ic_ver = [(firmware_data >> i) & 0xFF for i in range(0, 32, 8)] + + return Pn532FirmwareInfo(ic_ver, fw_maj, fw_min, opts, + bool(opts & SUPPORTS_ISO18092), + bool(opts & SUPPORTS_ISO14443_A), + bool(opts & SUPPORTS_ISO14443_B)) + def readRegister(self, reg: int) -> int: """ diff --git a/setup.py b/setup.py index f06158e..6b3ad95 100644 --- a/setup.py +++ b/setup.py @@ -5,9 +5,9 @@ setuptools.setup( name="pn532pi", - version="1.6", + version="1.7", author="gassajor000", - author_email="lgassjsg@example.com", + author_email="43421414+gassajor000@users.noreply.github.com", description="PN532 library for Raspberry Pi", long_description=long_description, long_description_content_type="text/markdown",