get_version works
This commit is contained in:
parent
14b438a3fb
commit
d5ca98fbaa
1 changed files with 44 additions and 82 deletions
|
@ -143,8 +143,8 @@ PN532_GPIO_P33 = 3
|
||||||
PN532_GPIO_P34 = 4
|
PN532_GPIO_P34 = 4
|
||||||
PN532_GPIO_P35 = 5
|
PN532_GPIO_P35 = 5
|
||||||
|
|
||||||
PN532_ACK = bytearray([0x01, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00])
|
PN532_ACK = b'\x01\x00\x00\xFF\x00\xFF\x00'
|
||||||
PN532_FRAME_START = bytearray([0x01, 0x00, 0x00, 0xFF])
|
PN532_FRAME_START = b'\x01\x00\x00\xFF'
|
||||||
|
|
||||||
|
|
||||||
class PN532_I2C(object):
|
class PN532_I2C(object):
|
||||||
|
@ -154,28 +154,22 @@ class PN532_I2C(object):
|
||||||
PN532 (see: http://www.raspberrypi.org/forums/viewtopic.php?f=32&t=98070&p=720659#p720659)
|
PN532 (see: http://www.raspberrypi.org/forums/viewtopic.php?f=32&t=98070&p=720659#p720659)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, i2c):
|
def __init__(self, i2c, irq=None, *, debug=False):
|
||||||
"""Create an instance of the PN532 class using either software SPI (if
|
"""Create an instance of the PN532 class using either software SPI (if
|
||||||
the sclk, mosi, and miso pins are specified) or hardware SPI if a
|
the sclk, mosi, and miso pins are specified) or hardware SPI if a
|
||||||
spi parameter is passed. The cs pin must be a digital GPIO pin.
|
spi parameter is passed. The cs pin must be a digital GPIO pin.
|
||||||
Optionally specify a GPIO controller to override the default that uses
|
Optionally specify a GPIO controller to override the default that uses
|
||||||
the board's GPIO pins.
|
the board's GPIO pins.
|
||||||
"""
|
"""
|
||||||
self._i2cdevice = i2c_device.I2CDevice(i2c, PN532_I2C_ADDRESS)
|
self.debug = debug
|
||||||
|
self._i2c = i2c_device.I2CDevice(i2c, PN532_I2C_ADDRESS)
|
||||||
def _uint8_add(self, a, b):
|
self._irq = irq
|
||||||
"""Add add two values as unsigned 8-bit values."""
|
self.get_firmware_version()
|
||||||
return ((a & 0xFF) + (b & 0xFF)) & 0xFF
|
|
||||||
|
|
||||||
def _busy_wait_ms(self, ms):
|
|
||||||
"""Busy wait for the specified number of milliseconds."""
|
|
||||||
time.delay(ms/1000.0)
|
|
||||||
|
|
||||||
def _write_frame(self, data):
|
def _write_frame(self, data):
|
||||||
"""Write a frame to the PN532 with the specified data bytearray."""
|
"""Write a frame to the PN532 with the specified data bytearray."""
|
||||||
assert data is not None and 0 < len(data) < 255, 'Data must be array of 1 to 255 bytes.'
|
assert data is not None and 0 < len(data) < 255, 'Data must be array of 1 to 255 bytes.'
|
||||||
# Build frame to send as:
|
# Build frame to send as:
|
||||||
# - SPI data write (0x01)
|
|
||||||
# - Preamble (0x00)
|
# - Preamble (0x00)
|
||||||
# - Start code (0x00, 0xFF)
|
# - Start code (0x00, 0xFF)
|
||||||
# - Command length (1 byte)
|
# - Command length (1 byte)
|
||||||
|
@ -185,34 +179,31 @@ class PN532_I2C(object):
|
||||||
# - Postamble (0x00)
|
# - Postamble (0x00)
|
||||||
length = len(data)
|
length = len(data)
|
||||||
frame = bytearray(length+8)
|
frame = bytearray(length+8)
|
||||||
frame[0] = PN532_SPI_DATAWRITE
|
frame[0] = PN532_PREAMBLE
|
||||||
frame[1] = PN532_PREAMBLE
|
frame[1] = PN532_STARTCODE1
|
||||||
frame[2] = PN532_STARTCODE1
|
frame[2] = PN532_STARTCODE2
|
||||||
frame[3] = PN532_STARTCODE2
|
checksum = sum(frame[0:3])
|
||||||
frame[4] = length & 0xFF
|
frame[3] = length & 0xFF
|
||||||
frame[5] = self._uint8_add(~length, 1)
|
frame[4] = (~length + 1) & 0xFF
|
||||||
frame[6:-2] = data
|
frame[5:-2] = data
|
||||||
checksum = reduce(self._uint8_add, data, 0xFF)
|
checksum += sum(data)
|
||||||
frame[-2] = ~checksum & 0xFF
|
frame[-2] = ~checksum & 0xFF
|
||||||
frame[-1] = PN532_POSTAMBLE
|
frame[-1] = PN532_POSTAMBLE
|
||||||
# Send frame.
|
# Send frame.
|
||||||
logger.debug('Write frame: 0x{0}'.format(binascii.hexlify(frame)))
|
if self.debug:
|
||||||
self._gpio.set_low(self._cs)
|
print('Write frame: ', [hex(i) for i in frame])
|
||||||
self._busy_wait_ms(2)
|
with self._i2c:
|
||||||
self._spi.write(frame)
|
self._i2c.write(bytes(frame))
|
||||||
self._gpio.set_high(self._cs)
|
|
||||||
|
|
||||||
def _read_data(self, count):
|
def _read_data(self, count):
|
||||||
"""Read a specified count of bytes from the PN532."""
|
"""Read a specified count of bytes from the PN532."""
|
||||||
# Build a read request frame.
|
# Build a read request frame.
|
||||||
frame = bytearray(count)
|
frame = bytearray(count)
|
||||||
frame[0] = PN532_SPI_DATAREAD
|
with self._i2c:
|
||||||
# Send the frame and return the response, ignoring the SPI header byte.
|
self._i2c.readinto(frame)
|
||||||
self._gpio.set_low(self._cs)
|
if self.debug:
|
||||||
self._busy_wait_ms(2)
|
print("Reading: ", [hex(i) for i in frame])
|
||||||
response = self._spi.transfer(frame)
|
return frame
|
||||||
self._gpio.set_high(self._cs)
|
|
||||||
return response
|
|
||||||
|
|
||||||
def _read_frame(self, length):
|
def _read_frame(self, length):
|
||||||
"""Read a response frame from the PN532 of at most length bytes in size.
|
"""Read a response frame from the PN532 of at most length bytes in size.
|
||||||
|
@ -222,7 +213,8 @@ class PN532_I2C(object):
|
||||||
"""
|
"""
|
||||||
# Read frame with expected length of data.
|
# Read frame with expected length of data.
|
||||||
response = self._read_data(length+8)
|
response = self._read_data(length+8)
|
||||||
logger.debug('Read frame: 0x{0}'.format(binascii.hexlify(response)))
|
if self.debug:
|
||||||
|
print('Read frame:', [hex(i) for i in response])
|
||||||
# Check frame starts with 0x01 and then has 0x00FF (preceeded by optional
|
# Check frame starts with 0x01 and then has 0x00FF (preceeded by optional
|
||||||
# zeros).
|
# zeros).
|
||||||
if response[0] != 0x01:
|
if response[0] != 0x01:
|
||||||
|
@ -243,42 +235,24 @@ class PN532_I2C(object):
|
||||||
if (frame_len + response[offset+1]) & 0xFF != 0:
|
if (frame_len + response[offset+1]) & 0xFF != 0:
|
||||||
raise RuntimeError('Response length checksum did not match length!')
|
raise RuntimeError('Response length checksum did not match length!')
|
||||||
# Check frame checksum value matches bytes.
|
# Check frame checksum value matches bytes.
|
||||||
checksum = reduce(self._uint8_add, response[offset+2:offset+2+frame_len+1], 0)
|
checksum = sum(response[offset+2:offset+2+frame_len+1]) & 0xFF
|
||||||
if checksum != 0:
|
if checksum != 0:
|
||||||
raise RuntimeError('Response checksum did not match expected value!')
|
raise RuntimeError('Response checksum did not match expected value: ', checksum)
|
||||||
# Return frame data.
|
# Return frame data.
|
||||||
return response[offset+2:offset+2+frame_len]
|
return response[offset+2:offset+2+frame_len]
|
||||||
|
|
||||||
def _wait_ready(self, timeout_sec=1):
|
def _wait_ready(self, timeout=1):
|
||||||
"""Wait until the PN532 is ready to receive commands. At most wait
|
if self._irq:
|
||||||
timeout_sec seconds for the PN532 to be ready. If the PN532 is ready
|
print("TODO IRQ")
|
||||||
before the timeout is exceeded then True will be returned, otherwise
|
else:
|
||||||
False is returned when the timeout is exceeded.
|
time.sleep(timeout)
|
||||||
"""
|
|
||||||
start = time.time()
|
|
||||||
# Send a SPI status read command and read response.
|
|
||||||
self._gpio.set_low(self._cs)
|
|
||||||
self._busy_wait_ms(2)
|
|
||||||
response = self._spi.transfer([PN532_SPI_STATREAD, 0x00])
|
|
||||||
self._gpio.set_high(self._cs)
|
|
||||||
# Loop until a ready response is received.
|
|
||||||
while response[1] != PN532_SPI_READY:
|
|
||||||
# Check if the timeout has been exceeded.
|
|
||||||
if time.time() - start >= timeout_sec:
|
|
||||||
return False
|
|
||||||
# Wait a little while and try reading the status again.
|
|
||||||
time.sleep(0.01)
|
|
||||||
self._gpio.set_low(self._cs)
|
|
||||||
self._busy_wait_ms(2)
|
|
||||||
response = self._spi.transfer([PN532_SPI_STATREAD, 0x00])
|
|
||||||
self._gpio.set_high(self._cs)
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def call_function(self, command, response_length=0, params=[], timeout_sec=1):
|
def call_function(self, command, response_length=0, params=[], timeout=1):
|
||||||
"""Send specified command to the PN532 and expect up to response_length
|
"""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
|
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
|
be returned! Params can optionally specify an array of bytes to send as
|
||||||
parameters to the function call. Will wait up to timeout_secs seconds
|
parameters to the function call. Will wait up to timeout seconds
|
||||||
for a response and return a bytearray of response bytes, or None if no
|
for a response and return a bytearray of response bytes, or None if no
|
||||||
response is available within the timeout.
|
response is available within the timeout.
|
||||||
"""
|
"""
|
||||||
|
@ -286,16 +260,16 @@ class PN532_I2C(object):
|
||||||
data = bytearray(2+len(params))
|
data = bytearray(2+len(params))
|
||||||
data[0] = PN532_HOSTTOPN532
|
data[0] = PN532_HOSTTOPN532
|
||||||
data[1] = command & 0xFF
|
data[1] = command & 0xFF
|
||||||
data[2:] = params
|
for i in range(len(params)):
|
||||||
|
data[2+i] = params[i]
|
||||||
# Send frame and wait for response.
|
# Send frame and wait for response.
|
||||||
self._write_frame(data)
|
self._write_frame(data)
|
||||||
if not self._wait_ready(timeout_sec):
|
if not self._wait_ready(timeout):
|
||||||
return None
|
return None
|
||||||
# Verify ACK response and wait to be ready for function response.
|
# Verify ACK response and wait to be ready for function response.
|
||||||
response = self._read_data(len(PN532_ACK))
|
if not PN532_ACK == self._read_data(len(PN532_ACK)):
|
||||||
if response != PN532_ACK:
|
|
||||||
raise RuntimeError('Did not receive expected ACK from PN532!')
|
raise RuntimeError('Did not receive expected ACK from PN532!')
|
||||||
if not self._wait_ready(timeout_sec):
|
if not self._wait_ready(timeout):
|
||||||
return None
|
return None
|
||||||
# Read response bytes.
|
# Read response bytes.
|
||||||
response = self._read_frame(response_length+2)
|
response = self._read_frame(response_length+2)
|
||||||
|
@ -305,25 +279,13 @@ class PN532_I2C(object):
|
||||||
# Return response data.
|
# Return response data.
|
||||||
return response[2:]
|
return response[2:]
|
||||||
|
|
||||||
def begin(self):
|
|
||||||
"""Initialize communication with the PN532. Must be called before any
|
|
||||||
other calls are made against the PN532.
|
|
||||||
"""
|
|
||||||
# Assert CS pin low for a second for PN532 to be ready.
|
|
||||||
self._gpio.set_low(self._cs)
|
|
||||||
time.sleep(1.0)
|
|
||||||
# Call GetFirmwareVersion to sync up with the PN532. This might not be
|
|
||||||
# required but is done in the Arduino library and kept for consistency.
|
|
||||||
self.get_firmware_version()
|
|
||||||
self._gpio.set_high(self._cs)
|
|
||||||
|
|
||||||
def get_firmware_version(self):
|
def get_firmware_version(self):
|
||||||
"""Call PN532 GetFirmwareVersion function and return a tuple with the IC,
|
"""Call PN532 GetFirmwareVersion function and return a tuple with the IC,
|
||||||
Ver, Rev, and Support values.
|
Ver, Rev, and Support values.
|
||||||
"""
|
"""
|
||||||
response = self.call_function(PN532_COMMAND_GETFIRMWAREVERSION, 4)
|
response = self.call_function(PN532_COMMAND_GETFIRMWAREVERSION, 4, timeout=0.1)
|
||||||
if response is None:
|
if response is None:
|
||||||
raise RuntimeError('Failed to detect the PN532! Make sure there is sufficient power (use a 1 amp or greater power supply), the PN532 is wired correctly to the device, and the solder joints on the PN532 headers are solidly connected.')
|
raise RuntimeError('Failed to detect the PN532')
|
||||||
return (response[0], response[1], response[2], response[3])
|
return (response[0], response[1], response[2], response[3])
|
||||||
|
|
||||||
def SAM_configuration(self):
|
def SAM_configuration(self):
|
||||||
|
@ -336,9 +298,9 @@ class PN532_I2C(object):
|
||||||
# check the command was executed as expected.
|
# check the command was executed as expected.
|
||||||
self.call_function(PN532_COMMAND_SAMCONFIGURATION, params=[0x01, 0x14, 0x01])
|
self.call_function(PN532_COMMAND_SAMCONFIGURATION, params=[0x01, 0x14, 0x01])
|
||||||
|
|
||||||
def read_passive_target(self, card_baud=PN532_MIFARE_ISO14443A, timeout_sec=1):
|
def read_passive_target(self, card_baud=PN532_MIFARE_ISO14443A, timeout=1):
|
||||||
"""Wait for a MiFare card to be available and return its UID when found.
|
"""Wait for a MiFare card to be available and return its UID when found.
|
||||||
Will wait up to timeout_sec seconds and return None if no card is 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.
|
otherwise a bytearray with the UID of the found card is returned.
|
||||||
"""
|
"""
|
||||||
# Send passive read command for 1 card. Expect at most a 7 byte UUID.
|
# Send passive read command for 1 card. Expect at most a 7 byte UUID.
|
||||||
|
|
Loading…
Reference in a new issue