-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrc522i2c.py
534 lines (425 loc) · 17.4 KB
/
rc522i2c.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
#!/usr/bin/env python3
# -*- coding: utf8 -*-
import errno
from machine import I2C
class MRFC522:
# Define register values from datasheet
# Page 0: Command & Status register
COMMANDREG = 0x01 # Start and stops command execution
COMIENREG = 0x02 # Enable and disable interrupt request control bits
COMIRQREG = 0x04 # Interrupt request bits
DIVIRQREG = 0x05 # Interrupt request bits
ERRORREG = 0x06 # Error bits showing the error status of the last command
STATUS2REG = 0x08 # Receiver and transmitter status bits
FIFODATAREG = 0x09 # Input and output of 64 byte FIFO buffer
FIFOLEVELREG = 0x0A # Number of bytes stored in the FIFO buffer
CONTROLREG = 0x0C # Miscellaneous control register
BITFRAMINGREG = 0x0D # Adjustments for bit-oriented frames
# Page 1: Command register
MODEREG = 0x11 # Defines general modes for transmitting and receiving
TXCONTROLREG = 0x14 # Controls the logical behavior of the antenna
# driver pins
TXASKREG = 0x15 # Controls the setting of the transmission modulation
# Page 2: Configuration register
CRCRESULTREGMSB = 0x21 # Shows the MSB of the CRC calculation
CRCRESULTREGLSB = 0x22 # Shows the LSB of the CRC calculation
TMODEREG = 0x2A # Defines settings for the internal timer
TPRESCALERREG = 0x2B # Defines settings for internal timer
TRELOADREGH = 0x2C # Defines 16-bit timer reload value
TRELOADREGL = 0x2D # Defines 16-bit timer reload value
# Page 3: Test register
VERSIONREG = 0x37 # Shows the software version
# MRFC522 Commands
MRFC522_IDLE = 0x00 # No actions, cancels current command execution
MRFC522_CALCCRC = 0x03 # Activates the CRC coprocessor and performs
# a self test
MRFC522_TRANSCEIVE = 0x0C # Transmits data from FIFO buffer to
# anntenna and automatically activates the receiver after
# transmission
MRFC522_MFAUTHENT = 0x0E # Performs the MIFARE standard authentication
# as a reader
MRFC522_SOFTRESET = 0x0F # Resets the MRFC522
# MIFARE Classic Commands
MIFARE_REQUEST = [0x26]
MIFARE_WAKEUP = [0x52]
MIFARE_ANTICOLCL1 = [0x93, 0x20]
MIFARE_SELECTCL1 = [0x93, 0x70]
MIFARE_ANTICOLCL2 = [0x95, 0x20]
MIFARE_SELECTCL2 = [0x95, 0x70]
MIFARE_HALT = [0x50, 0x00]
MIFARE_AUTHKEY1 = [0x60]
MIFARE_AUTHKEY2 = [0x61]
MIFARE_READ = [0x30]
MIFARE_WRITE = [0xA0]
MIFARE_DECREMENT = [0xC0]
MIFARE_INCREMENT = [0xC1]
MIFARE_RESTORE = [0xC2]
MIFARE_TRANSFER = [0xB0]
MIFARE_KEY = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]
MIFARE_USERDATA = [ 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14, 16, 17, 18,
20, 21, 22, 24, 25, 26, 28, 29, 30, 32, 33, 34, 36, 37,
38, 40, 41, 42, 44, 45, 46, 48, 49, 50, 52, 53, 54, 56,
57, 58, 60, 61, 62]
MI_OK = 0
MI_NOTAGERR = 1
MI_ERR = 2
MAX_LEN = 16
# i2cbus = I2C(0,freq=1000000)
i2caddress = 0x28
def __init__(self,bus,address=None):
if address is not None:
self.i2caddress=address
self.i2cbus=bus
try:
self.MRFC522_init()
except OSError as e:
if e.args[0] == errno.ENODEV:
address=self.i2cbus.scan()
if len(address)==1:
self.i2caddress = address[0]
self.MRFC522_init()
def showReaderDetails(self):
version = self.MRFC522_read(self.VERSIONREG)
if (version == 0x91):
print('MRFC522 Software Version:',hex(version),' = v1.0')
elif (version == 0x92):
print('MRFC522 Software Version:',hex(version),' = v2.0')
else:
print('MRFC522 Software Version:',hex(version),'')
def scan(self):
status = None
backData = []
backBits = None
# None bits of the last byte
self.MRFC522_write(self.BITFRAMINGREG, 0x07)
buffer = []
buffer.extend(self.MIFARE_REQUEST)
(status, backData, backBits) = self.transceiveCard(buffer)
if ((status != self.MI_OK) | (backBits != 0x10)):
status = self.MI_ERR
return (status, backData, backBits)
def serialNumberValid(self, serialNumber):
i = 0
serialCheck = 0
while (i < (len(serialNumber) - 1)):
serialCheck = serialCheck ^ serialNumber[i]
i = i + 1
if (serialCheck != serialNumber[i]):
return False
else:
return True
def transceive(self):
status = None
backData = []
backBits = None
# All bits of the last byte
self.MRFC522_write(self.BITFRAMINGREG, 0x00)
buffer = []
buffer.extend(self.MIFARE_ANTICOLCL1)
(status, backData, backBits) = self.transceiveCard(buffer)
if (status == self.MI_OK):
if (self.serialNumberValid(backData)):
status = self.MI_OK
else:
status = self.MI_ERR
return (status, backData, backBits)
def transceiveCard(self, data):
status = None
backData = []
backBits = None
IRqInv = 0x80 # Signal on pin IRQ is inverted
TxIEn = 0x40 # Allow the transmitter to interrupt requests
RxIEn = 0x20 # Allow the receiver to interrupt requests
IdleIEn = 0x10 # Allow the idle interrupt request
LoAlertIEn = 0x04 # Allow the low Alert interrupt request
ErrIEn = 0x02 # Allow the error interrupt request
TimerIEn = 0x01 # Allow the timer interrupt request
self.MRFC522_write(self.COMIENREG, (IRqInv |
TxIEn |
RxIEn |
IdleIEn |
LoAlertIEn |
ErrIEn |
TimerIEn))
# Indicates that the bits in the ComIrqReg register are set
Set1 = 0x80
self.MRFC522_clearBitMask(self.COMIRQREG, Set1)
# Immediatly clears the internal FIFO buffer's read and write pointer
# and ErrorReg register's BufferOvfl bit
FlushBuffer = 0x80
self.MRFC522_setBitMask(self.FIFOLEVELREG, FlushBuffer)
# Cancel running commands
self.MRFC522_write(self.COMMANDREG, self.MRFC522_IDLE)
# Write data in FIFO register
i = 0
while (i < len(data)):
self.MRFC522_write(self.FIFODATAREG, data[i])
i = i + 1
# Countinously repeat the transmission of data from the FIFO buffer and
# the reception of data from the RF field.
self.MRFC522_write(self.COMMANDREG, self.MRFC522_TRANSCEIVE)
# Starts the transmission of data, only valid in combination with the
# Transceive command
StartSend = 0x80
self.MRFC522_setBitMask(self.BITFRAMINGREG, StartSend)
# The timer has decrement the value in TCounterValReg register to zero
TimerIRq = 0x01
# The receiver has detected the end of a valid data stream
RxIRq = 0x20
# A command was terminated or unknown command is started
IdleIRq = 0x10
# Wait for an interrupt
i = 2000
while True:
comIRqReg = self.MRFC522_read(self.COMIRQREG)
if (comIRqReg & TimerIRq):
# Timeout
break
if (comIRqReg & RxIRq):
# Valid data available in FIFO
break
if (comIRqReg & IdleIRq):
# Command terminate
break
if (i == 0):
# Watchdog expired
break
# Clear the StartSend bit in BitFramingReg register
self.MRFC522_clearBitMask(self.BITFRAMINGREG, StartSend)
# Retrieve data from FIFODATAREG
if (i != 0):
# The host or a MFRC522's internal state machine tries to write
# data to the FIFO buffer even though it is already full
BufferOvfl = 0x10
# A bit collision is detected
ColErr = 0x08
# Parity check failed
ParityErr = 0x02
# Set to logic 1 if the SOF is incorrect
ProtocolErr = 0x01
errorTest = (BufferOvfl | ColErr | ParityErr | ProtocolErr)
errorReg = self.MRFC522_read(self.ERRORREG)
# Test if any of the errors above happend
if (~(errorReg & errorTest)):
status = self.MI_OK
# Indicates any error bit in thr ErrorReg register is set
ErrIRq = 0x02
# Test if the timer expired and an error occured
if (comIRqReg & TimerIRq & ErrIRq):
status = self.MI_NOTAGERR
fifoLevelReg = self.MRFC522_read(self.FIFOLEVELREG)
# Edge cases
if fifoLevelReg == 0:
fifoLevelReg = 1
if fifoLevelReg > self.MAX_LEN:
fifoLevelReg = self.MAX_LEN
# Indicates the number of valid bits in the last received byte
RxLastBits = 0x08
lastBits = self.MRFC522_read(self.CONTROLREG) & RxLastBits
if (lastBits != 0):
backBits = (fifoLevelReg - 1) * 8 + lastBits
else:
backBits = fifoLevelReg * 8
i = 0
while (i < fifoLevelReg):
backData.append(self.MRFC522_read(self.FIFODATAREG))
i = i + 1
else:
status.MI_ERR
return (status, backData, backBits)
def calculateCRC(self, data):
# Clear the bit that indicates taht the CalcCRC command is active
# and all data is processed
CRCIRq = 0x04
self.MRFC522_clearBitMask(self.DIVIRQREG, CRCIRq)
# Immedialty clears the internal FIFO buffer's read and write pointer
# and ErrorReg register's BufferOvfl bit
FlushBuffer = 0x80
self.MRFC522_setBitMask(self.FIFOLEVELREG, FlushBuffer)
# Write data to FIFO
i = 0
while (i < len(data)):
self.MRFC522_write(self.FIFODATAREG, data[i])
i = i + 1
# Execute CRC calculation
self.MRFC522_write(self.COMMANDREG, self.MRFC522_CALCCRC)
i = 255
while True:
divirqreg = self.MRFC522_read(self.DIVIRQREG)
i = i - 1
if (i == 0):
# Watchdog expired
break
if (divirqreg & CRCIRq):
# CRC is calculated
break
# Retrieve CRC from CRCRESULTREG
crc = []
crc.append(self.MRFC522_read(self.CRCRESULTREGLSB))
crc.append(self.MRFC522_read(self.CRCRESULTREGMSB))
return (crc)
def select(self, serialNumber):
status = None
backData = []
backBits = None
buffer = []
buffer.extend(self.MIFARE_SELECTCL1)
i = 0
while (i < 5):
buffer.append(serialNumber[i])
i = i + 1
crc = self.calculateCRC(buffer)
buffer.extend(crc)
(status, backData, backBits) = self.transceiveCard(buffer)
return (status, backData, backBits)
def authenticate(self, mode, blockAddr, key, serialNumber):
status = None
backData = []
backBits = None
buffer = []
buffer.extend(mode)
buffer.append(blockAddr)
buffer.extend(key)
i = 0
while (i < 4):
buffer.append(serialNumber[i])
i = i + 1
(status, backData, backBits) = self.authenticateCard(buffer)
return (status, backData, backBits)
def deauthenticate(self):
# Indicates that the MIFARE Crypto1 unit is switched on and
# therfore all data communication with the card is encrypted
# Can ONLY be set to logic 1 by a successfull execution of
# the MFAuthent command
MFCrypto1On = 0x08
self.MRFC522_clearBitMask(self.STATUS2REG, MFCrypto1On)
def authenticateCard(self, data):
status = None
backData = []
backBits = None
IRqInv = 0x80 # Signal on pin IRQ is inverted
IdleIEn = 0x10 # Allow the idle interrupt request
ErrIEn = 0x02 # Allow the error interrupt request
self.MRFC522_write(self.COMIENREG, (IRqInv | IdleIEn | ErrIEn))
# Indicates that the bits in the ComIrqReg register are set
Set1 = 0x80
self.MRFC522_clearBitMask(self.COMIRQREG, Set1)
# Immedialty clears the interl FIFO buffer's read and write pointer
# and ErrorReg register's BufferOvfl bit
FlushBuffer = 0x80
self.MRFC522_setBitMask(self.FIFOLEVELREG, FlushBuffer)
# Cancel running commands
self.MRFC522_write(self.COMMANDREG, self.MRFC522_IDLE)
# Write data in FIFO register
i = 0
while (i < len(data)):
self.MRFC522_write(self.FIFODATAREG, data[i])
i = i + 1
# This command manages MIFARE authentication to anable a secure
# communication to any MIFARE card
self.MRFC522_write(self.COMMANDREG, self.MRFC522_MFAUTHENT)
# The timer has decrement the value in TCounterValReg register to zero
TimerIRq = 0x01
# The receiver has detected the end of a valid data stream
RxIRq = 0x20
# A command was terminated or unknown command is started
IdleIRq = 0x10
# Wait for an interrupt
i = 2000
while True:
comIRqReg = self.MRFC522_read(self.COMIRQREG)
if (comIRqReg & TimerIRq):
# Timeout
break
if (comIRqReg & RxIRq):
# Valid data available in FIFO
break
if (comIRqReg & IdleIRq):
# Command terminate
break
if (i == 0):
# Watchdog expired
break
# Clear the StartSend bit in BitFramingReg register
StartSend = 0x80
self.MRFC522_clearBitMask(self.BITFRAMINGREG, StartSend)
# Retrieve data from FIFODATAREG
if (i != 0):
# The host or a MFRC522's internal state machine tries to write
# data to the FIFO buffer even though it is already full
BufferOvfl = 0x10
# A bit collision is detected
ColErr = 0x08
# Parity check failed
ParityErr = 0x02
# Set to logic 1 if the SOF is incorrect
ProtocolErr = 0x01
errorTest = (BufferOvfl | ColErr | ParityErr | ProtocolErr)
errorReg = self.MRFC522_read(self.ERRORREG)
# Test if any of the errors above happend
if (~(errorReg & errorTest)):
status = self.MI_OK
# Indicates any error bit in thr ErrorReg register is set
ErrIRq = 0x02
# Test if the timer expired and an error occured
if (comIRqReg & TimerIRq & ErrIRq):
status = self.MI_NOTAGERR
else:
status = self.MI_ERR
return (status, backData, backBits)
def read(self, blockAddr):
status = None
backData = []
backBits = None
buffer = []
buffer.extend(self.MIFARE_READ)
buffer.append(blockAddr)
crc = self.calculateCRC(buffer)
buffer.extend(crc)
(status, backData, backBits) = self.transceiveCard(buffer)
return (status, backData, backBits)
def write(self, blockAddr, data):
status = None
backData = []
backBits = None
buffer = []
buffer.extend(self.MIFARE_WRITE)
buffer.append(blockAddr)
crc = self.calculateCRC(buffer)
buffer.extend(crc)
(status, backData, backBits) = self.transceiveCard(buffer)
if (status == self.MI_OK):
buffer.clear()
buffer.extend(data)
crc = self.calculateCRC(buffer)
buffer.extend(crc)
(status, backData, backBits) = self.transceiveCard(buffer)
return (status, backData, backBits)
def MRFC522_antennaOn(self):
value = self.MRFC522_read(self.TXCONTROLREG)
if (~(value & 0x03)):
self.MRFC522_setBitMask(self.TXCONTROLREG, 0x03)
def MRFC522_antennaOff(self):
self.MRFC522_clearBitMask(self.TXCONTROLREG, 0x03)
def MRFC522_reset(self):
self.MRFC522_write(self.COMMANDREG, self.MRFC522_SOFTRESET)
def MRFC522_init(self):
self.MRFC522_reset()
self.MRFC522_write(self.TMODEREG, 0x8D)
self.MRFC522_write(self.TPRESCALERREG, 0x3E)
self.MRFC522_write(self.TRELOADREGL, 30)
self.MRFC522_write(self.TRELOADREGH, 0)
self.MRFC522_write(self.TXASKREG, 0x40)
self.MRFC522_write(self.MODEREG, 0x3D)
self.MRFC522_antennaOn()
def MRFC522_read(self, address):
value = self.i2cbus.readfrom_mem(self.i2caddress, address,1)
return value[0]
def MRFC522_write(self, address, value):
self.i2cbus.writeto_mem(self.i2caddress, address,bytearray([value]))
def MRFC522_setBitMask(self, address, mask):
value = self.MRFC522_read(address)
self.MRFC522_write(address, value | mask)
def MRFC522_clearBitMask(self, address, mask):
value = self.MRFC522_read(address)
self.MRFC522_write(address, value & (~mask))