Merge pull request #64 from tcfranks/main
resubmit pr Typting Annotations
This commit is contained in:
commit
0061f33008
5 changed files with 124 additions and 47 deletions
|
@ -31,6 +31,14 @@ from digitalio import Direction
|
|||
|
||||
from micropython import const
|
||||
|
||||
try:
|
||||
from typing import Optional, Tuple, Union
|
||||
from typing_extensions import Literal
|
||||
from circuitpython_typing import ReadableBuffer
|
||||
from digitalio import DigitalInOut # pylint: disable=ungrouped-imports
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
__version__ = "0.0.0+auto.0"
|
||||
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_PN532.git"
|
||||
|
||||
|
@ -151,7 +159,13 @@ class BusyError(Exception):
|
|||
class PN532:
|
||||
"""PN532 driver base, must be extended for I2C/SPI/UART interfacing"""
|
||||
|
||||
def __init__(self, *, debug=False, irq=None, reset=None):
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
debug: bool = False,
|
||||
irq: Optional[DigitalInOut] = None,
|
||||
reset: Optional[DigitalInOut] = None
|
||||
) -> None:
|
||||
"""Create an instance of the PN532 class"""
|
||||
self.low_power = True
|
||||
self.debug = debug
|
||||
|
@ -160,26 +174,26 @@ class PN532:
|
|||
self.reset()
|
||||
_ = self.firmware_version
|
||||
|
||||
def _read_data(self, count):
|
||||
def _read_data(self, count: int) -> Union[bytes, bytearray]:
|
||||
# Read raw data from device, not including status bytes:
|
||||
# Subclasses MUST implement this!
|
||||
raise NotImplementedError
|
||||
|
||||
def _write_data(self, framebytes):
|
||||
def _write_data(self, framebytes: bytes) -> None:
|
||||
# Write raw bytestring data to device, not including status bytes:
|
||||
# Subclasses MUST implement this!
|
||||
raise NotImplementedError
|
||||
|
||||
def _wait_ready(self, timeout):
|
||||
def _wait_ready(self, timeout: float) -> bool:
|
||||
# Check if busy up to max length of 'timeout' seconds
|
||||
# Subclasses MUST implement this!
|
||||
raise NotImplementedError
|
||||
|
||||
def _wakeup(self):
|
||||
def _wakeup(self) -> None:
|
||||
# Send special command to wake up
|
||||
raise NotImplementedError
|
||||
|
||||
def reset(self):
|
||||
def reset(self) -> None:
|
||||
"""Perform a hardware reset toggle and then wake up the PN532"""
|
||||
if self._reset_pin:
|
||||
if self.debug:
|
||||
|
@ -191,7 +205,7 @@ class PN532:
|
|||
time.sleep(0.1)
|
||||
self._wakeup()
|
||||
|
||||
def _write_frame(self, data):
|
||||
def _write_frame(self, data: bytearray) -> None:
|
||||
"""Write a frame to the PN532 with the specified data bytearray."""
|
||||
assert (
|
||||
data is not None and 1 < len(data) < 255
|
||||
|
@ -221,7 +235,7 @@ class PN532:
|
|||
print("Write frame: ", [hex(i) for i in frame])
|
||||
self._write_data(bytes(frame))
|
||||
|
||||
def _read_frame(self, length):
|
||||
def _read_frame(self, length: int) -> Union[bytes, bytearray]:
|
||||
"""Read a response frame from the PN532 of at most length bytes in size.
|
||||
Returns the data inside the frame if found, otherwise raises an exception
|
||||
if there is an error parsing the frame. Note that less than length bytes
|
||||
|
@ -257,8 +271,12 @@ class PN532:
|
|||
return response[offset + 2 : offset + 2 + frame_len]
|
||||
|
||||
def call_function(
|
||||
self, command, response_length=0, params=[], timeout=1
|
||||
): # pylint: disable=dangerous-default-value
|
||||
self,
|
||||
command: int,
|
||||
response_length: int = 0,
|
||||
params: ReadableBuffer = b"",
|
||||
timeout: float = 1,
|
||||
) -> Optional[Union[bytes, bytearray]]:
|
||||
"""Send specified command to the PN532 and expect up to response_length
|
||||
bytes back in a response. Note that less than the expected bytes might
|
||||
be returned! Params can optionally specify an array of bytes to send as
|
||||
|
@ -273,11 +291,11 @@ class PN532:
|
|||
)
|
||||
|
||||
def send_command(
|
||||
self, command, params=[], timeout=1
|
||||
): # pylint: disable=dangerous-default-value
|
||||
self, command: int, params: ReadableBuffer = b"", timeout: float = 1
|
||||
) -> bool:
|
||||
"""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.
|
||||
Will wait up to timeout seconds for the acknowledgment and return True.
|
||||
If no acknowledgment is received, False is returned.
|
||||
"""
|
||||
if self.low_power:
|
||||
self._wakeup()
|
||||
|
@ -300,7 +318,9 @@ class PN532:
|
|||
raise RuntimeError("Did not receive expected ACK from PN532!")
|
||||
return True
|
||||
|
||||
def process_response(self, command, response_length=0, timeout=1):
|
||||
def process_response(
|
||||
self, command: int, response_length: int = 0, timeout: float = 1
|
||||
) -> Optional[Union[bytes, bytearray]]:
|
||||
"""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
|
||||
|
@ -317,7 +337,7 @@ class PN532:
|
|||
# Return response data.
|
||||
return response[2:]
|
||||
|
||||
def power_down(self):
|
||||
def power_down(self) -> bool:
|
||||
"""Put the PN532 into a low power state. If the reset pin is connected a
|
||||
hard power down is performed, if not, a soft power down is performed
|
||||
instead. Returns True if the PN532 was powered down successfully or
|
||||
|
@ -333,7 +353,7 @@ class PN532:
|
|||
return self.low_power
|
||||
|
||||
@property
|
||||
def firmware_version(self):
|
||||
def firmware_version(self) -> Tuple[int, int, int, int]:
|
||||
"""Call PN532 GetFirmwareVersion function and return a tuple with the IC,
|
||||
Ver, Rev, and Support values.
|
||||
"""
|
||||
|
@ -342,7 +362,7 @@ class PN532:
|
|||
raise RuntimeError("Failed to detect the PN532")
|
||||
return tuple(response)
|
||||
|
||||
def SAM_configuration(self): # pylint: disable=invalid-name
|
||||
def SAM_configuration(self) -> None: # pylint: disable=invalid-name
|
||||
"""Configure the PN532 to read MiFare cards."""
|
||||
# Send SAM configuration command with configuration for:
|
||||
# - 0x01, normal mode
|
||||
|
@ -352,7 +372,9 @@ class PN532:
|
|||
# check the command was executed as expected.
|
||||
self.call_function(_COMMAND_SAMCONFIGURATION, params=[0x01, 0x14, 0x01])
|
||||
|
||||
def read_passive_target(self, card_baud=_MIFARE_ISO14443A, timeout=1):
|
||||
def read_passive_target(
|
||||
self, card_baud: int = _MIFARE_ISO14443A, timeout: float = 1
|
||||
) -> Optional[bytearray]:
|
||||
"""Wait for a MiFare card to be available and return its UID when found.
|
||||
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.
|
||||
|
@ -364,9 +386,11 @@ class PN532:
|
|||
return None
|
||||
return self.get_passive_target(timeout=timeout)
|
||||
|
||||
def listen_for_passive_target(self, card_baud=_MIFARE_ISO14443A, timeout=1):
|
||||
def listen_for_passive_target(
|
||||
self, card_baud: int = _MIFARE_ISO14443A, timeout: float = 1
|
||||
) -> bool:
|
||||
"""Send command to PN532 to begin listening for a Mifare card. This
|
||||
returns True if the command was received succesfully. Note, this does
|
||||
returns True if the command was received successfully. 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.
|
||||
|
@ -380,7 +404,9 @@ class PN532:
|
|||
return False # _COMMAND_INLISTPASSIVETARGET failed
|
||||
return response
|
||||
|
||||
def get_passive_target(self, timeout=1):
|
||||
def get_passive_target(
|
||||
self, timeout: float = 1
|
||||
) -> Optional[Union[bytes, bytearray]]:
|
||||
"""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
|
||||
|
@ -404,9 +430,13 @@ class PN532:
|
|||
# Return UID of card.
|
||||
return response[6 : 6 + response[5]]
|
||||
|
||||
def mifare_classic_authenticate_block(
|
||||
self, uid, block_number, key_number, key
|
||||
): # pylint: disable=invalid-name
|
||||
def mifare_classic_authenticate_block( # pylint: disable=invalid-name
|
||||
self,
|
||||
uid: ReadableBuffer,
|
||||
block_number: int,
|
||||
key_number: Literal[0x60, 0x61],
|
||||
key: ReadableBuffer,
|
||||
) -> bool:
|
||||
"""Authenticate specified block number for a MiFare classic card. Uid
|
||||
should be a byte array with the UID of the card, block number should be
|
||||
the block to authenticate, key number should be the key type (like
|
||||
|
@ -429,7 +459,9 @@ class PN532:
|
|||
)
|
||||
return response[0] == 0x00
|
||||
|
||||
def mifare_classic_read_block(self, block_number):
|
||||
def mifare_classic_read_block(
|
||||
self, block_number: int
|
||||
) -> Optional[Union[bytes, bytearray]]:
|
||||
"""Read a block of data from the card. Block number should be the block
|
||||
to read. If the block is successfully read a bytearray of length 16 with
|
||||
data starting at the specified block will be returned. If the block is
|
||||
|
@ -447,7 +479,9 @@ class PN532:
|
|||
# Return first 4 bytes since 16 bytes are always returned.
|
||||
return response[1:]
|
||||
|
||||
def mifare_classic_write_block(self, block_number, data):
|
||||
def mifare_classic_write_block(
|
||||
self, block_number: int, data: ReadableBuffer
|
||||
) -> bool:
|
||||
"""Write a block of data to the card. Block number should be the block
|
||||
to write and data should be a byte array of length 16 with the data to
|
||||
write. If the data is successfully written then True is returned,
|
||||
|
@ -468,7 +502,7 @@ class PN532:
|
|||
)
|
||||
return response[0] == 0x0
|
||||
|
||||
def ntag2xx_write_block(self, block_number, data):
|
||||
def ntag2xx_write_block(self, block_number: int, data: ReadableBuffer) -> bool:
|
||||
"""Write a block of data to the card. Block number should be the block
|
||||
to write and data should be a byte array of length 4 with the data to
|
||||
write. If the data is successfully written then True is returned,
|
||||
|
@ -487,7 +521,9 @@ class PN532:
|
|||
)
|
||||
return response[0] == 0x00
|
||||
|
||||
def ntag2xx_read_block(self, block_number):
|
||||
def ntag2xx_read_block(
|
||||
self, block_number: int
|
||||
) -> Optional[Union[bytes, bytearray]]:
|
||||
"""Read a block of data from the card. Block number should be the block
|
||||
to read. If the block is successfully read the first 4 bytes (after the
|
||||
leading 0x00 byte) will be returned.
|
||||
|
|
|
@ -23,6 +23,13 @@ from digitalio import Direction
|
|||
from micropython import const
|
||||
from adafruit_pn532.adafruit_pn532 import PN532, BusyError
|
||||
|
||||
try:
|
||||
from typing import Optional
|
||||
from digitalio import DigitalInOut # pylint: disable=ungrouped-imports
|
||||
from busio import I2C
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
_I2C_ADDRESS = const(0x24)
|
||||
|
||||
|
||||
|
@ -30,8 +37,15 @@ class PN532_I2C(PN532):
|
|||
"""Driver for the PN532 connected over I2C."""
|
||||
|
||||
def __init__(
|
||||
self, i2c, address=_I2C_ADDRESS, *, irq=None, reset=None, req=None, debug=False
|
||||
):
|
||||
self,
|
||||
i2c: I2C,
|
||||
address: int = _I2C_ADDRESS,
|
||||
*,
|
||||
irq: Optional[DigitalInOut] = None,
|
||||
reset: Optional[DigitalInOut] = None,
|
||||
req: Optional[DigitalInOut] = None,
|
||||
debug: bool = False
|
||||
) -> None:
|
||||
"""Create an instance of the PN532 class using I2C. Note that PN532
|
||||
uses clock stretching. Optional IRQ pin (not used),
|
||||
resetp pin and debugging output.
|
||||
|
@ -41,7 +55,7 @@ class PN532_I2C(PN532):
|
|||
self._i2c = i2c_device.I2CDevice(i2c, address)
|
||||
super().__init__(debug=debug, irq=irq, reset=reset)
|
||||
|
||||
def _wakeup(self):
|
||||
def _wakeup(self) -> None:
|
||||
"""Send any special commands/data to wake up PN532"""
|
||||
if self._reset_pin:
|
||||
self._reset_pin.value = True
|
||||
|
@ -55,7 +69,7 @@ class PN532_I2C(PN532):
|
|||
self.low_power = False
|
||||
self.SAM_configuration() # Put the PN532 back in normal mode
|
||||
|
||||
def _wait_ready(self, timeout=1):
|
||||
def _wait_ready(self, timeout: float = 1) -> bool:
|
||||
"""Poll PN532 if status byte is ready, up to `timeout` seconds"""
|
||||
status = bytearray(1)
|
||||
timestamp = time.monotonic()
|
||||
|
@ -67,11 +81,11 @@ class PN532_I2C(PN532):
|
|||
continue
|
||||
if status == b"\x01":
|
||||
return True # No longer busy
|
||||
time.sleep(0.01) # lets ask again soon!
|
||||
time.sleep(0.01) # let's ask again soon!
|
||||
# Timed out!
|
||||
return False
|
||||
|
||||
def _read_data(self, count):
|
||||
def _read_data(self, count: int) -> bytearray:
|
||||
"""Read a specified count of bytes from the PN532."""
|
||||
# Build a read request frame.
|
||||
frame = bytearray(count + 1)
|
||||
|
@ -84,7 +98,7 @@ class PN532_I2C(PN532):
|
|||
print("Reading: ", [hex(i) for i in frame[1:]])
|
||||
return frame[1:] # don't return the status byte
|
||||
|
||||
def _write_data(self, framebytes):
|
||||
def _write_data(self, framebytes: bytes) -> None:
|
||||
"""Write a specified count of bytes to the PN532"""
|
||||
with self._i2c as i2c:
|
||||
i2c.write(framebytes)
|
||||
|
|
|
@ -14,6 +14,14 @@ using SPI.
|
|||
|
||||
"""
|
||||
|
||||
try:
|
||||
from typing import Optional
|
||||
from circuitpython_typing import ReadableBuffer
|
||||
from digitalio import DigitalInOut
|
||||
from busio import SPI
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
__version__ = "0.0.0+auto.0"
|
||||
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_PN532.git"
|
||||
|
||||
|
@ -28,7 +36,7 @@ _SPI_DATAREAD = const(0x03)
|
|||
_SPI_READY = const(0x01)
|
||||
|
||||
|
||||
def reverse_bit(num):
|
||||
def reverse_bit(num: int) -> int:
|
||||
"""Turn an LSB byte to an MSB byte, and vice versa. Used for SPI as
|
||||
it is LSB for the PN532, but 99% of SPI implementations are MSB only!"""
|
||||
result = 0
|
||||
|
@ -44,13 +52,21 @@ class PN532_SPI(PN532):
|
|||
SPI device & chip select digitalInOut pin. Optional IRQ pin (not used),
|
||||
reset pin and debugging output."""
|
||||
|
||||
def __init__(self, spi, cs_pin, *, irq=None, reset=None, debug=False):
|
||||
def __init__(
|
||||
self,
|
||||
spi: SPI,
|
||||
cs_pin: DigitalInOut,
|
||||
*,
|
||||
irq: Optional[DigitalInOut] = None,
|
||||
reset: Optional[DigitalInOut] = None,
|
||||
debug: bool = False
|
||||
) -> None:
|
||||
"""Create an instance of the PN532 class using SPI"""
|
||||
self.debug = debug
|
||||
self._spi = spi_device.SPIDevice(spi, cs_pin)
|
||||
super().__init__(debug=debug, irq=irq, reset=reset)
|
||||
|
||||
def _wakeup(self):
|
||||
def _wakeup(self) -> None:
|
||||
"""Send any special commands/data to wake up PN532"""
|
||||
if self._reset_pin:
|
||||
self._reset_pin.value = True
|
||||
|
@ -61,7 +77,7 @@ class PN532_SPI(PN532):
|
|||
self.low_power = False
|
||||
self.SAM_configuration() # Put the PN532 back in normal mode
|
||||
|
||||
def _wait_ready(self, timeout=1):
|
||||
def _wait_ready(self, timeout: float = 1) -> bool:
|
||||
"""Poll PN532 if status byte is ready, up to `timeout` seconds"""
|
||||
status_cmd = bytearray([reverse_bit(_SPI_STATREAD), 0x00])
|
||||
status_response = bytearray([0x00, 0x00])
|
||||
|
@ -77,7 +93,7 @@ class PN532_SPI(PN532):
|
|||
# We timed out!
|
||||
return False
|
||||
|
||||
def _read_data(self, count):
|
||||
def _read_data(self, count: int) -> bytearray:
|
||||
"""Read a specified count of bytes from the PN532."""
|
||||
# Build a read request frame.
|
||||
frame = bytearray(count + 1)
|
||||
|
@ -92,7 +108,7 @@ class PN532_SPI(PN532):
|
|||
print("Reading: ", [hex(i) for i in frame[1:]])
|
||||
return frame[1:]
|
||||
|
||||
def _write_data(self, framebytes):
|
||||
def _write_data(self, framebytes: ReadableBuffer) -> None:
|
||||
"""Write a specified count of bytes to the PN532"""
|
||||
# start by making a frame with data write in front,
|
||||
# then rest of bytes, and LSBify it
|
||||
|
|
|
@ -17,6 +17,13 @@ using UART.
|
|||
__version__ = "0.0.0+auto.0"
|
||||
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_PN532.git"
|
||||
|
||||
try:
|
||||
from typing import Optional
|
||||
from circuitpython_typing import ReadableBuffer
|
||||
from digitalio import DigitalInOut
|
||||
from busio import UART
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
import time
|
||||
from adafruit_pn532.adafruit_pn532 import PN532, BusyError
|
||||
|
@ -25,7 +32,9 @@ from adafruit_pn532.adafruit_pn532 import PN532, BusyError
|
|||
class PN532_UART(PN532):
|
||||
"""Driver for the PN532 connected over Serial UART"""
|
||||
|
||||
def __init__(self, uart, *, reset=None, debug=False):
|
||||
def __init__(
|
||||
self, uart: UART, *, reset: Optional[DigitalInOut] = None, debug: bool = False
|
||||
) -> None:
|
||||
"""Create an instance of the PN532 class using Serial connection.
|
||||
Optional reset pin and debugging output.
|
||||
"""
|
||||
|
@ -33,7 +42,7 @@ class PN532_UART(PN532):
|
|||
self._uart = uart
|
||||
super().__init__(debug=debug, reset=reset)
|
||||
|
||||
def _wakeup(self):
|
||||
def _wakeup(self) -> None:
|
||||
"""Send any special commands/data to wake up PN532"""
|
||||
if self._reset_pin:
|
||||
self._reset_pin.value = True
|
||||
|
@ -44,7 +53,7 @@ class PN532_UART(PN532):
|
|||
) # wake up!
|
||||
self.SAM_configuration()
|
||||
|
||||
def _wait_ready(self, timeout=1):
|
||||
def _wait_ready(self, timeout: float = 1) -> bool:
|
||||
"""Wait `timeout` seconds"""
|
||||
timestamp = time.monotonic()
|
||||
while (time.monotonic() - timestamp) < timeout:
|
||||
|
@ -54,7 +63,7 @@ class PN532_UART(PN532):
|
|||
# Timed out!
|
||||
return False
|
||||
|
||||
def _read_data(self, count):
|
||||
def _read_data(self, count: int) -> bytes:
|
||||
"""Read a specified count of bytes from the PN532."""
|
||||
frame = self._uart.read(count)
|
||||
if not frame:
|
||||
|
@ -63,7 +72,7 @@ class PN532_UART(PN532):
|
|||
print("Reading: ", [hex(i) for i in frame])
|
||||
return frame
|
||||
|
||||
def _write_data(self, framebytes):
|
||||
def _write_data(self, framebytes: ReadableBuffer) -> None:
|
||||
"""Write a specified count of bytes to the PN532"""
|
||||
self._uart.reset_input_buffer()
|
||||
self._uart.write(framebytes)
|
||||
|
|
|
@ -4,4 +4,6 @@
|
|||
|
||||
Adafruit-Blinka
|
||||
adafruit-circuitpython-busdevice
|
||||
adafruit-circuitpython-typing
|
||||
pyserial
|
||||
typing-extensions~=4.0
|
||||
|
|
Loading…
Reference in a new issue