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