basic UID reading works

This commit is contained in:
ladyada 2018-08-21 00:10:46 -04:00
parent d5ca98fbaa
commit faaf7fad4d
2 changed files with 107 additions and 74 deletions

View file

@ -30,61 +30,61 @@ import adafruit_bus_device.spi_device as spi_device
from micropython import const from micropython import const
PN532_PREAMBLE = const(0x00) _PREAMBLE = const(0x00)
PN532_STARTCODE1 = const(0x00) _STARTCODE1 = const(0x00)
PN532_STARTCODE2 = const(0xFF) _STARTCODE2 = const(0xFF)
PN532_POSTAMBLE = const(0x00) _POSTAMBLE = const(0x00)
PN532_HOSTTOPN532 = const(0xD4) _HOSTTOPN532 = const(0xD4)
PN532_PN532TOHOST = const(0xD5) _PN532TOHOST = const(0xD5)
# PN532 Commands # PN532 Commands
PN532_COMMAND_DIAGNOSE = const(0x00) _COMMAND_DIAGNOSE = const(0x00)
PN532_COMMAND_GETFIRMWAREVERSION = const(0x02) _COMMAND_GETFIRMWAREVERSION = const(0x02)
PN532_COMMAND_GETGENERALSTATUS = const(0x04) _COMMAND_GETGENERALSTATUS = const(0x04)
PN532_COMMAND_READREGISTER = const(0x06) _COMMAND_READREGISTER = const(0x06)
PN532_COMMAND_WRITEREGISTER = const(0x08) _COMMAND_WRITEREGISTER = const(0x08)
PN532_COMMAND_READGPIO = const(0x0C) _COMMAND_READGPIO = const(0x0C)
PN532_COMMAND_WRITEGPIO = const(0x0E) _COMMAND_WRITEGPIO = const(0x0E)
PN532_COMMAND_SETSERIALBAUDRATE = const(0x10) _COMMAND_SETSERIALBAUDRATE = const(0x10)
PN532_COMMAND_SETPARAMETERS = const(0x12) _COMMAND_SETPARAMETERS = const(0x12)
PN532_COMMAND_SAMCONFIGURATION = const(0x14) _COMMAND_SAMCONFIGURATION = const(0x14)
PN532_COMMAND_POWERDOWN = const(0x16) _COMMAND_POWERDOWN = const(0x16)
PN532_COMMAND_RFCONFIGURATION = const(0x32) _COMMAND_RFCONFIGURATION = const(0x32)
PN532_COMMAND_RFREGULATIONTEST = const(0x58) _COMMAND_RFREGULATIONTEST = const(0x58)
PN532_COMMAND_INJUMPFORDEP = const(0x56) _COMMAND_INJUMPFORDEP = const(0x56)
PN532_COMMAND_INJUMPFORPSL = const(0x46) _COMMAND_INJUMPFORPSL = const(0x46)
PN532_COMMAND_INLISTPASSIVETARGET = const(0x4A) _COMMAND_INLISTPASSIVETARGET = const(0x4A)
PN532_COMMAND_INATR = const(0x50) _COMMAND_INATR = const(0x50)
PN532_COMMAND_INPSL = const(0x4E) _COMMAND_INPSL = const(0x4E)
PN532_COMMAND_INDATAEXCHANGE = const(0x40) _COMMAND_INDATAEXCHANGE = const(0x40)
PN532_COMMAND_INCOMMUNICATETHRU = const(0x42) _COMMAND_INCOMMUNICATETHRU = const(0x42)
PN532_COMMAND_INDESELECT = const(0x44) _COMMAND_INDESELECT = const(0x44)
PN532_COMMAND_INRELEASE = const(0x52) _COMMAND_INRELEASE = const(0x52)
PN532_COMMAND_INSELECT = const(0x54) _COMMAND_INSELECT = const(0x54)
PN532_COMMAND_INAUTOPOLL = const(0x60) _COMMAND_INAUTOPOLL = const(0x60)
PN532_COMMAND_TGINITASTARGET = const(0x8C) _COMMAND_TGINITASTARGET = const(0x8C)
PN532_COMMAND_TGSETGENERALBYTES = const(0x92) _COMMAND_TGSETGENERALBYTES = const(0x92)
PN532_COMMAND_TGGETDATA = const(0x86) _COMMAND_TGGETDATA = const(0x86)
PN532_COMMAND_TGSETDATA = const(0x8E) _COMMAND_TGSETDATA = const(0x8E)
PN532_COMMAND_TGSETMETADATA = const(0x94) _COMMAND_TGSETMETADATA = const(0x94)
PN532_COMMAND_TGGETINITIATORCOMMAND = const(0x88) _COMMAND_TGGETINITIATORCOMMAND = const(0x88)
PN532_COMMAND_TGRESPONSETOINITIATOR = const(0x90) _COMMAND_TGRESPONSETOINITIATOR = const(0x90)
PN532_COMMAND_TGGETTARGETSTATUS = const(0x8A) _COMMAND_TGGETTARGETSTATUS = const(0x8A)
PN532_RESPONSE_INDATAEXCHANGE = const(0x41) _RESPONSE_INDATAEXCHANGE = const(0x41)
PN532_RESPONSE_INLISTPASSIVETARGET = const(0x4B) _RESPONSE_INLISTPASSIVETARGET = const(0x4B)
PN532_WAKEUP = const(0x55) _WAKEUP = const(0x55)
PN532_SPI_STATREAD = const(0x02) _SPI_STATREAD = const(0x02)
PN532_SPI_DATAWRITE = const(0x01) _SPI_DATAWRITE = const(0x01)
PN532_SPI_DATAREAD = const(0x03) _SPI_DATAREAD = const(0x03)
PN532_SPI_READY = const(0x01) _SPI_READY = const(0x01)
PN532_I2C_ADDRESS = const(0x24) _I2C_ADDRESS = const(0x24)
PN532_MIFARE_ISO14443A = 0x00 _MIFARE_ISO14443A = 0x00
# Mifare Commands # Mifare Commands
MIFARE_CMD_AUTH_A = const(0x60) MIFARE_CMD_AUTH_A = const(0x60)
@ -135,17 +135,20 @@ NDEF_URIPREFIX_URN_EPC_RAW = const(0x21)
NDEF_URIPREFIX_URN_EPC = const(0x22) NDEF_URIPREFIX_URN_EPC = const(0x22)
NDEF_URIPREFIX_URN_NFC = const(0x23) NDEF_URIPREFIX_URN_NFC = const(0x23)
PN532_GPIO_VALIDATIONBIT = 0x80 _GPIO_VALIDATIONBIT = const(0x80)
PN532_GPIO_P30 = 0 _GPIO_P30 = const(0)
PN532_GPIO_P31 = 1 _GPIO_P31 = const(1)
PN532_GPIO_P32 = 2 _GPIO_P32 = const(2)
PN532_GPIO_P33 = 3 _GPIO_P33 = const(3)
PN532_GPIO_P34 = 4 _GPIO_P34 = const(4)
PN532_GPIO_P35 = 5 _GPIO_P35 = const(5)
PN532_ACK = b'\x01\x00\x00\xFF\x00\xFF\x00' _ACK = b'\x01\x00\x00\xFF\x00\xFF\x00'
PN532_FRAME_START = b'\x01\x00\x00\xFF' _FRAME_START = b'\x01\x00\x00\xFF'
class BusyError(Exception):
"""Base class for exceptions in this module."""
pass
class PN532_I2C(object): class PN532_I2C(object):
"""PN532 breakout board representation. Requires a SPI connection to the """PN532 breakout board representation. Requires a SPI connection to the
@ -162,7 +165,7 @@ class PN532_I2C(object):
the board's GPIO pins. the board's GPIO pins.
""" """
self.debug = debug self.debug = debug
self._i2c = i2c_device.I2CDevice(i2c, PN532_I2C_ADDRESS) self._i2c = i2c_device.I2CDevice(i2c, _I2C_ADDRESS)
self._irq = irq self._irq = irq
self.get_firmware_version() self.get_firmware_version()
@ -179,16 +182,16 @@ 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_PREAMBLE frame[0] = _PREAMBLE
frame[1] = PN532_STARTCODE1 frame[1] = _STARTCODE1
frame[2] = PN532_STARTCODE2 frame[2] = _STARTCODE2
checksum = sum(frame[0:3]) checksum = sum(frame[0:3])
frame[3] = length & 0xFF frame[3] = length & 0xFF
frame[4] = (~length + 1) & 0xFF frame[4] = (~length + 1) & 0xFF
frame[5:-2] = data frame[5:-2] = data
checksum += sum(data) checksum += sum(data)
frame[-2] = ~checksum & 0xFF frame[-2] = ~checksum & 0xFF
frame[-1] = PN532_POSTAMBLE frame[-1] = _POSTAMBLE
# Send frame. # Send frame.
if self.debug: if self.debug:
print('Write frame: ', [hex(i) for i in frame]) print('Write frame: ', [hex(i) for i in frame])
@ -200,6 +203,9 @@ class PN532_I2C(object):
# Build a read request frame. # Build a read request frame.
frame = bytearray(count) frame = bytearray(count)
with self._i2c: with self._i2c:
self._i2c.readinto(frame, end=1) # read ready byte!
if frame[0] != 0x01: # not ready
raise BusyError
self._i2c.readinto(frame) self._i2c.readinto(frame)
if self.debug: if self.debug:
print("Reading: ", [hex(i) for i in frame]) print("Reading: ", [hex(i) for i in frame])
@ -258,7 +264,7 @@ class PN532_I2C(object):
""" """
# Build frame data with command and parameters. # Build frame data with command and parameters.
data = bytearray(2+len(params)) data = bytearray(2+len(params))
data[0] = PN532_HOSTTOPN532 data[0] = _HOSTTOPN532
data[1] = command & 0xFF data[1] = command & 0xFF
for i in range(len(params)): for i in range(len(params)):
data[2+i] = params[i] data[2+i] = params[i]
@ -267,14 +273,14 @@ class PN532_I2C(object):
if not self._wait_ready(timeout): 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.
if not PN532_ACK == self._read_data(len(PN532_ACK)): if not _ACK == self._read_data(len(_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): 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)
# Check that response is for the called function. # Check that response is for the called function.
if not (response[0] == PN532_PN532TOHOST and response[1] == (command+1)): if not (response[0] == _PN532TOHOST and response[1] == (command+1)):
raise RuntimeError('Received unexpected command response!') raise RuntimeError('Received unexpected command response!')
# Return response data. # Return response data.
return response[2:] return response[2:]
@ -283,10 +289,10 @@ class PN532_I2C(object):
"""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, timeout=0.1) response = self.call_function(_COMMAND_GETFIRMWAREVERSION, 4, timeout=0.1)
if response is None: if response is None:
raise RuntimeError('Failed to detect the PN532') raise RuntimeError('Failed to detect the PN532')
return (response[0], response[1], response[2], response[3]) return tuple(response)
def SAM_configuration(self): def SAM_configuration(self):
"""Configure the PN532 to read MiFare cards.""" """Configure the PN532 to read MiFare cards."""
@ -296,17 +302,21 @@ class PN532_I2C(object):
# - 0x01, use IRQ pin # - 0x01, use IRQ pin
# Note that no other verification is necessary as call_function will # Note that no other verification is necessary as call_function will
# 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(_COMMAND_SAMCONFIGURATION, params=[0x01, 0x14, 0x01])
def read_passive_target(self, card_baud=PN532_MIFARE_ISO14443A, timeout=1): def read_passive_target(self, card_baud=_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 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.
response = self.call_function(PN532_COMMAND_INLISTPASSIVETARGET, try:
params=[0x01, card_baud], response = self.call_function(_COMMAND_INLISTPASSIVETARGET,
response_length=17) params=[0x01, card_baud],
response_length=17,
timeout=timeout)
except BusyError:
return None # no card found!
# If no response is available return None to indicate no card is present. # If no response is available return None to indicate no card is present.
if response is None: if response is None:
return None return None
@ -336,7 +346,7 @@ class PN532_I2C(object):
params[3:3+keylen] = key params[3:3+keylen] = key
params[3+keylen:] = uid params[3+keylen:] = uid
# Send InDataExchange request and verify response is 0x00. # Send InDataExchange request and verify response is 0x00.
response = self.call_function(PN532_COMMAND_INDATAEXCHANGE, response = self.call_function(_COMMAND_INDATAEXCHANGE,
params=params, params=params,
response_length=1) response_length=1)
return response[0] == 0x00 return response[0] == 0x00
@ -348,7 +358,7 @@ class PN532_I2C(object):
not read then None will be returned. not read then None will be returned.
""" """
# Send InDataExchange request to read block of MiFare data. # Send InDataExchange request to read block of MiFare data.
response = self.call_function(PN532_COMMAND_INDATAEXCHANGE, response = self.call_function(_COMMAND_INDATAEXCHANGE,
params=[0x01, MIFARE_CMD_READ, block_number & 0xFF], params=[0x01, MIFARE_CMD_READ, block_number & 0xFF],
response_length=17) response_length=17)
# Check first response is 0x00 to show success. # Check first response is 0x00 to show success.
@ -371,7 +381,7 @@ class PN532_I2C(object):
params[2] = block_number & 0xFF params[2] = block_number & 0xFF
params[3:] = data params[3:] = data
# Send InDataExchange request. # Send InDataExchange request.
response = self.call_function(PN532_COMMAND_INDATAEXCHANGE, response = self.call_function(_COMMAND_INDATAEXCHANGE,
params=params, params=params,
response_length=1) response_length=1)
return response[0] == 0x00 return response[0] == 0x00

23
examples/main.py Normal file
View file

@ -0,0 +1,23 @@
from Adafruit_Circuitpython_PN532 import adafruit_pn532
from digitalio import DigitalInOut, Direction, Pull
import board
import time
import busio
# I2C connection:
i2c = busio.I2C(board.SCL, board.SDA)
pn532 = adafruit_pn532.PN532_I2C(i2c)
ic, ver, rev, support = pn532.get_firmware_version()
print('Found PN532 with firmware version: {0}.{1}'.format(ver, rev))
# Configure PN532 to communicate with MiFare cards.
pn532.SAM_configuration()
print('Waiting for MiFare card...')
while True:
# Check if a card is available to read
uid = pn532.read_passive_target(timeout=0.25)
# Try again if no card is available.
if uid is None:
continue
print('Found card with UID:', [hex(i) for i in uid])