23
23
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
24
# SOFTWARE.
25
25
"""
26
- `adafruit_PN532 `
26
+ ``adafruit_pn532` `
27
27
====================================================
28
28
29
29
This module will let you communicate with a PN532 RFID/NFC shield or breakout
43
43
44
44
* Adafruit CircuitPython firmware for the supported boards:
45
45
https://github.com/adafruit/circuitpython/releases
46
-
47
- * Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice
46
+ * Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice
48
47
"""
49
48
50
49
51
50
import time
52
- from digitalio import DigitalInOut , Direction
51
+ from digitalio import Direction
53
52
import adafruit_bus_device .i2c_device as i2c_device
54
53
import adafruit_bus_device .spi_device as spi_device
55
54
58
57
__version__ = "0.0.0-auto.0"
59
58
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_PN532.git"
60
59
61
-
60
+ # pylint: disable=bad-whitespace
62
61
_PREAMBLE = const (0x00 )
63
62
_STARTCODE1 = const (0x00 )
64
63
_STARTCODE2 = const (0xFF )
174
173
175
174
_ACK = b'\x00 \x00 \xFF \x00 \xFF \x00 '
176
175
_FRAME_START = b'\x00 \x00 \xFF '
176
+ # pylint: enable=bad-whitespace
177
+
178
+
179
+ def _reset (pin ):
180
+ """Perform a hardware reset toggle"""
181
+ pin .direction = Direction .OUTPUT
182
+ pin .value = True
183
+ time .sleep (0.1 )
184
+ pin .value = False
185
+ time .sleep (0.5 )
186
+ pin .value = True
187
+ time .sleep (0.1 )
177
188
178
189
def reverse_bit (num ):
190
+ """Turn an LSB byte to an MSB byte, and vice versa. Used for SPI as
191
+ it is LSB for the PN532, but 99% of SPI implementations are MSB only!"""
179
192
result = 0
180
193
for _ in range (8 ):
181
194
result <<= 1
@@ -197,26 +210,23 @@ def __init__(self, *, debug=False, reset=None):
197
210
"""
198
211
self .debug = debug
199
212
if reset :
200
- reset .direction = Direction .OUTPUT
201
- reset .value = True
202
- time .sleep (0.1 )
203
- reset .value = False
204
- time .sleep (0.1 )
205
- reset .value = True
206
- time .sleep (1 )
213
+ if debug :
214
+ print ("Resetting" )
215
+ _reset (reset )
216
+
207
217
try :
208
218
self ._wakeup ()
209
219
self .get_firmware_version () # first time often fails, try 2ce
210
220
return
211
- except :
221
+ except ( BusyError , RuntimeError ) :
212
222
pass
213
223
self .get_firmware_version ()
214
224
215
225
def _read_data (self , count ):
216
226
# Read raw data from device, not including status bytes:
217
227
# Subclasses MUST implement this!
218
228
raise NotImplementedError
219
-
229
+
220
230
def _write_data (self , framebytes ):
221
231
# Write raw bytestring data to device, not including status bytes:
222
232
# Subclasses MUST implement this!
@@ -227,10 +237,13 @@ def _wait_ready(self, timeout):
227
237
# Subclasses MUST implement this!
228
238
raise NotImplementedError
229
239
240
+ def _wakeup (self ):
241
+ # Send special command to wake up
242
+ raise NotImplementedError
230
243
231
244
def _write_frame (self , data ):
232
245
"""Write a frame to the PN532 with the specified data bytearray."""
233
- assert data is not None and 0 < len (data ) < 255 , 'Data must be array of 1 to 255 bytes.'
246
+ assert data is not None and 1 < len (data ) < 255 , 'Data must be array of 1 to 255 bytes.'
234
247
# Build frame to send as:
235
248
# - Preamble (0x00)
236
249
# - Start code (0x00, 0xFF)
@@ -266,6 +279,7 @@ def _read_frame(self, length):
266
279
response = self ._read_data (length + 8 )
267
280
if self .debug :
268
281
print ('Read frame:' , [hex (i ) for i in response ])
282
+
269
283
# Swallow all the 0x00 values that preceed 0xFF.
270
284
offset = 0
271
285
while response [offset ] == 0x00 :
@@ -276,7 +290,7 @@ def _read_frame(self, length):
276
290
raise RuntimeError ('Response frame preamble does not contain 0x00FF!' )
277
291
offset += 1
278
292
if offset >= len (response ):
279
- raise RuntimeError ('Response contains no data!' )
293
+ raise RuntimeError ('Response contains no data!' )
280
294
# Check length & length checksum match.
281
295
frame_len = response [offset ]
282
296
if (frame_len + response [offset + 1 ]) & 0xFF != 0 :
@@ -288,7 +302,7 @@ def _read_frame(self, length):
288
302
# Return frame data.
289
303
return response [offset + 2 :offset + 2 + frame_len ]
290
304
291
- def call_function (self , command , response_length = 0 , params = [], timeout = 1 ):
305
+ def call_function (self , command , response_length = 0 , params = [], timeout = 1 ): # pylint: disable=dangerous-default-value
292
306
"""Send specified command to the PN532 and expect up to response_length
293
307
bytes back in a response. Note that less than the expected bytes might
294
308
be returned! Params can optionally specify an array of bytes to send as
@@ -298,12 +312,16 @@ def call_function(self, command, response_length=0, params=[], timeout=1):
298
312
"""
299
313
# Build frame data with command and parameters.
300
314
data = bytearray (2 + len (params ))
301
- data [0 ] = _HOSTTOPN532
302
- data [1 ] = command & 0xFF
303
- for i in range ( len ( params ) ):
304
- data [2 + i ] = params [ i ]
315
+ data [0 ] = _HOSTTOPN532
316
+ data [1 ] = command & 0xFF
317
+ for i , val in enumerate ( params ):
318
+ data [2 + i ] = val
305
319
# Send frame and wait for response.
306
- self ._write_frame (data )
320
+ try :
321
+ self ._write_frame (data )
322
+ except OSError :
323
+ self ._wakeup ()
324
+ return None
307
325
if not self ._wait_ready (timeout ):
308
326
return None
309
327
# Verify ACK response and wait to be ready for function response.
@@ -328,7 +346,7 @@ def get_firmware_version(self):
328
346
raise RuntimeError ('Failed to detect the PN532' )
329
347
return tuple (response )
330
348
331
- def SAM_configuration (self ):
349
+ def SAM_configuration (self ): # pylint: disable=invalid-name
332
350
"""Configure the PN532 to read MiFare cards."""
333
351
# Send SAM configuration command with configuration for:
334
352
# - 0x01, normal mode
@@ -362,7 +380,7 @@ def read_passive_target(self, card_baud=_MIFARE_ISO14443A, timeout=1):
362
380
# Return UID of card.
363
381
return response [6 :6 + response [5 ]]
364
382
365
- def mifare_classic_authenticate_block (self , uid , block_number , key_number , key ):
383
+ def mifare_classic_authenticate_block (self , uid , block_number , key_number , key ): # pylint: disable=invalid-name
366
384
"""Authenticate specified block number for a MiFare classic card. Uid
367
385
should be a byte array with the UID of the card, block number should be
368
386
the block to authenticate, key number should be the key type (like
@@ -378,7 +396,7 @@ def mifare_classic_authenticate_block(self, uid, block_number, key_number, key):
378
396
params [1 ] = key_number & 0xFF
379
397
params [2 ] = block_number & 0xFF
380
398
params [3 :3 + keylen ] = key
381
- params [3 + keylen :] = uid
399
+ params [3 + keylen :] = uid
382
400
# Send InDataExchange request and verify response is 0x00.
383
401
response = self .call_function (_COMMAND_INDATAEXCHANGE ,
384
402
params = params ,
@@ -424,18 +442,21 @@ def mifare_classic_write_block(self, block_number, data):
424
442
class PN532_UART (PN532 ):
425
443
"""Driver for the PN532 connected over Serial UART"""
426
444
def __init__ (self , uart , * , irq = None , reset = None , debug = False ):
427
- """Create an instance of the PN532 class using Serial connection
445
+ """Create an instance of the PN532 class using Serial connection.
446
+ Optional IRQ pin (not used), reset pin and debugging output.
428
447
"""
429
448
self .debug = debug
430
449
self ._irq = irq
431
450
self ._uart = uart
432
451
super ().__init__ (debug = debug , reset = reset )
433
452
434
453
def _wakeup (self ):
454
+ """Send any special commands/data to wake up PN532"""
435
455
#self._write_frame([_HOSTTOPN532, _COMMAND_SAMCONFIGURATION, 0x01])
436
456
self .SAM_configuration ()
437
457
438
458
def _wait_ready (self , timeout = 1 ):
459
+ """Wait `timeout` seconds"""
439
460
time .sleep (timeout )
440
461
return True
441
462
@@ -446,41 +467,58 @@ def _read_data(self, count):
446
467
raise BusyError ("No data read from PN532" )
447
468
if self .debug :
448
469
print ("Reading: " , [hex (i ) for i in frame ])
470
+ else :
471
+ time .sleep (0.1 )
449
472
return frame
450
473
451
474
def _write_data (self , framebytes ):
475
+ """Write a specified count of bytes to the PN532"""
452
476
while self ._uart .read (1 ): # this would be a lot nicer if we could query the # of bytes
453
477
pass
454
478
self ._uart .write ('\x55 \x55 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 ' ) # wake up!
455
479
self ._uart .write (framebytes )
456
480
457
481
class PN532_I2C (PN532 ):
458
482
"""Driver for the PN532 connected over I2C."""
459
- def __init__ (self , i2c , * , irq = None , reset = None , debug = False ):
460
- """Create an instance of the PN532 class using either software SPI (if
461
- the sclk, mosi, and miso pins are specified) or hardware SPI if a
462
- spi parameter is passed. The cs pin must be a digital GPIO pin.
463
- Optionally specify a GPIO controller to override the default that uses
464
- the board's GPIO pins.
483
+ def __init__ (self , i2c , * , irq = None , reset = None , req = None , debug = False ):
484
+ """Create an instance of the PN532 class using I2C. Note that PN532
485
+ uses clock stretching. Optional IRQ pin (not used),
486
+ reset pin and debugging output.
465
487
"""
466
488
self .debug = debug
467
489
self ._irq = irq
490
+ self ._req = req
491
+ if reset :
492
+ _reset (reset )
468
493
self ._i2c = i2c_device .I2CDevice (i2c , _I2C_ADDRESS )
469
494
super ().__init__ (debug = debug , reset = reset )
470
495
471
- def _wakeup (self ):
496
+ def _wakeup (self ): # pylint: disable=no-self-use
497
+ """Send any special commands/data to wake up PN532"""
498
+ if self ._req :
499
+ self ._req .direction = Direction .OUTPUT
500
+ self ._req .value = True
501
+ time .sleep (0.1 )
502
+ self ._req .value = False
503
+ time .sleep (0.1 )
504
+ self ._req .value = True
472
505
time .sleep (0.5 )
473
506
474
507
def _wait_ready (self , timeout = 1 ):
508
+ """Poll PN532 if status byte is ready, up to `timeout` seconds"""
475
509
status = bytearray (1 )
476
- t = time .monotonic ()
477
- while (time .monotonic () - t ) < timeout :
478
- with self ._i2c :
479
- self ._i2c .readinto (status )
510
+ timestamp = time .monotonic ()
511
+ while (time .monotonic () - timestamp ) < timeout :
512
+ try :
513
+ with self ._i2c :
514
+ self ._i2c .readinto (status )
515
+ except OSError :
516
+ self ._wakeup ()
517
+ continue
480
518
if status == b'\x01 ' :
481
519
return True # No longer busy
482
520
else :
483
- time .sleep (0.1 ) # lets ask again soon!
521
+ time .sleep (0.05 ) # lets ask again soon!
484
522
# Timed out!
485
523
return False
486
524
@@ -495,15 +533,19 @@ def _read_data(self, count):
495
533
i2c .readinto (frame ) # ok get the data, plus statusbyte
496
534
if self .debug :
497
535
print ("Reading: " , [hex (i ) for i in frame [1 :]])
536
+ else :
537
+ time .sleep (0.1 )
498
538
return frame [1 :] # don't return the status byte
499
539
500
540
def _write_data (self , framebytes ):
541
+ """Write a specified count of bytes to the PN532"""
501
542
with self ._i2c as i2c :
502
543
i2c .write (framebytes )
503
544
504
545
class PN532_SPI (PN532 ):
505
- """Driver for the PN532 connected over SPI. Pass in a hardware or bitbang SPI device & chip select
506
- digitalInOut pin. Optional IRQ pin (not used), reset pin and debugging output."""
546
+ """Driver for the PN532 connected over SPI. Pass in a hardware or bitbang
547
+ SPI device & chip select digitalInOut pin. Optional IRQ pin (not used),
548
+ reset pin and debugging output."""
507
549
def __init__ (self , spi , cs_pin , * , irq = None , reset = None , debug = False ):
508
550
"""Create an instance of the PN532 class using SPI"""
509
551
self .debug = debug
@@ -512,20 +554,25 @@ def __init__(self, spi, cs_pin, *, irq=None, reset=None, debug=False):
512
554
super ().__init__ (debug = debug , reset = reset )
513
555
514
556
def _wakeup (self ):
557
+ """Send any special commands/data to wake up PN532"""
515
558
with self ._spi as spi :
516
559
time .sleep (1 )
560
+ spi .write (bytearray ([0x00 ]))
561
+ time .sleep (1 )
517
562
518
563
def _wait_ready (self , timeout = 1 ):
564
+ """Poll PN532 if status byte is ready, up to `timeout` seconds"""
519
565
status = bytearray ([reverse_bit (_SPI_STATREAD ), 0 ])
520
-
521
- t = time .monotonic ()
522
- while (time .monotonic () - t ) < timeout :
566
+
567
+ timestamp = time .monotonic ()
568
+ while (time .monotonic () - timestamp ) < timeout :
523
569
with self ._spi as spi :
570
+ time .sleep (0.02 ) # required
524
571
spi .write_readinto (status , status )
525
572
if reverse_bit (status [1 ]) == 0x01 : # LSB data is read in MSB
526
573
return True # Not busy anymore!
527
574
else :
528
- time .sleep (0.1 ) # pause a bit till we ask again
575
+ time .sleep (0.01 ) # pause a bit till we ask again
529
576
# We timed out!
530
577
return False
531
578
@@ -535,21 +582,23 @@ def _read_data(self, count):
535
582
frame = bytearray (count + 1 )
536
583
# Add the SPI data read signal byte, but LSB'ify it
537
584
frame [0 ] = reverse_bit (_SPI_DATAREAD )
538
-
585
+
539
586
with self ._spi as spi :
540
- time .sleep (0.01 ) # required
587
+ time .sleep (0.02 ) # required
541
588
spi .write_readinto (frame , frame )
542
- for i in range ( len ( frame ) ):
543
- frame [i ] = reverse_bit (frame [ i ] ) # turn LSB data to MSB
589
+ for i , val in enumerate ( frame ):
590
+ frame [i ] = reverse_bit (val ) # turn LSB data to MSB
544
591
if self .debug :
545
592
print ("Reading: " , [hex (i ) for i in frame [1 :]])
546
593
return frame [1 :]
547
594
548
595
def _write_data (self , framebytes ):
549
- # start by making a frame with data write in front, then rest of bytes, and LSBify it
550
- reversed = [reverse_bit (x ) for x in bytes ([_SPI_DATAWRITE ]) + framebytes ]
596
+ """Write a specified count of bytes to the PN532"""
597
+ # start by making a frame with data write in front,
598
+ # then rest of bytes, and LSBify it
599
+ rev_frame = [reverse_bit (x ) for x in bytes ([_SPI_DATAWRITE ]) + framebytes ]
551
600
if self .debug :
552
- print ("Writing: " , [hex (i ) for i in reversed ])
601
+ print ("Writing: " , [hex (i ) for i in rev_frame ])
553
602
with self ._spi as spi :
554
- time .sleep (0.01 ) # required
555
- spi .write (bytes (reversed ))
603
+ time .sleep (0.02 ) # required
604
+ spi .write (bytes (rev_frame ))
0 commit comments