mfrc522 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. checksums.yaml +7 -0
  2. data/lib/mfrc522.rb +613 -0
  3. metadata +64 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 76a0b3ccef69418c9bf365ca7ec159ad003c4fc2
4
+ data.tar.gz: 6024457f6053c4ae84dc28d839ee344bf0252365
5
+ SHA512:
6
+ metadata.gz: 76f98482e7e002bec39c51fc8b695e9dd25cbe16021c412397f743be6cd6b64747c5bdc29d993d63996194ad4828ccbd3f9736aae85768a38b7fc7916e52d110
7
+ data.tar.gz: a0fb447aa70005e6d4f1ae1d350783fe89663666c6ba5cdebaa053b00fe72dd30fe037df4af055d5689edabc83d041f9a77c220d778b39d435ab936ca8554623
@@ -0,0 +1,613 @@
1
+ require 'pi_piper'
2
+ include PiPiper
3
+
4
+ class Mfrc522
5
+
6
+ # PICC commands used by the PCD to manage communication with several PICCs (ISO 14443-3, Type A, section 6.4)
7
+ PICC_REQA = 0x26 # REQuest command, Type A. Invites PICCs in state IDLE to go to READY and prepare for anticollision or selection. 7 bit frame.
8
+ PICC_WUPA = 0x52 # Wake-UP command, Type A. Invites PICCs in state IDLE and HALT to go to READY(*) and prepare for anticollision or selection. 7 bit frame.
9
+ PICC_CT = 0x88 # Cascade Tag. Not really a command, but used during anti collision.
10
+ PICC_SEL_CL1 = 0x93 # Anti collision/Select, Cascade Level 1
11
+ PICC_SEL_CL2 = 0x95 # Anti collision/Select, Cascade Level 2
12
+ PICC_SEL_CL3 = 0x97 # Anti collision/Select, Cascade Level 3
13
+ PICC_HLTA = 0x50 # HaLT command, Type A. Instructs an ACTIVE PICC to go to state HALT.
14
+ # The commands used for MIFARE Classic (from http://www.mouser.com/ds/2/302/MF1S503x-89574.pdf, Section 9)
15
+ # Use PCD_MFAuthent to authenticate access to a sector, then use these commands to read/write/modify the blocks on the sector.
16
+ # The read/write commands can also be used for MIFARE Ultralight.
17
+ PICC_MF_AUTH_KEY_A = 0x60 # Perform authentication with Key A
18
+ PICC_MF_AUTH_KEY_B = 0x61 # Perform authentication with Key B
19
+ PICC_MF_READ = 0x30 # Reads one 16 byte block from the authenticated sector of the PICC. Also used for MIFARE Ultralight.
20
+ PICC_MF_WRITE = 0xA0 # Writes one 16 byte block to the authenticated sector of the PICC. Called "COMPATIBILITY WRITE" for MIFARE Ultralight.
21
+ PICC_MF_DECREMENT = 0xC0 # Decrements the contents of a block and stores the result in the internal data register.
22
+ PICC_MF_INCREMENT = 0xC1 # Increments the contents of a block and stores the result in the internal data register.
23
+ PICC_MF_RESTORE = 0xC2 # Reads the contents of a block into the internal data register.
24
+ PICC_MF_TRANSFER = 0xB0 # Writes the contents of the internal data register to a block.
25
+ # The commands used for MIFARE Ultralight (from http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf, Section 8.6)
26
+ # The PICC_MF_READ and PICC_MF_WRITE can also be used for MIFARE Ultralight.
27
+ PICC_UL_WRITE = 0xA2 # Writes one 4 byte page to the PICC.
28
+ #
29
+ PICC_MF_ACK = 0xA # Mifare Acknowledge
30
+
31
+ # PCD commands
32
+ PCD_Idle = 0x00 # no action, cancels current command execution
33
+ PCD_Mem = 0x01 # stores 25 bytes into the internal buffer
34
+ PCD_GenRandomID = 0x02 # generates a 10-byte random ID number
35
+ PCD_CalcCRC = 0x03 # activates the CRC coprocessor or performs a self test
36
+ PCD_Transmit = 0x04 # transmits data from the FIFO buffer
37
+ PCD_NoCmdChange = 0x07 # no command change, can be used to modify the CommandReg register bits without affecting the command, for example, the PowerDown bit
38
+ PCD_Receive = 0x08 # activates the receiver circuits
39
+ PCD_Transceive = 0x0C # transmits data from FIFO buffer to antenna and automatically activates the receiver after transmission
40
+ PCD_MFAuthent = 0x0E # performs the MIFARE standard authentication as a reader
41
+ PCD_SoftReset = 0x0F # resets the MFRC522
42
+
43
+ # PCD Command and Status Registers
44
+ CommandReg = 0x01 # starts and stops command execution
45
+ ComIEnReg = 0x02 # enable and disable interrupt request control bits
46
+ DivIEnReg = 0x03 # enable and disable interrupt request control bits
47
+ ComIrqReg = 0x04 # interrupt request bits
48
+ DivIrqReg = 0x05 # interrupt request bits
49
+ ErrorReg = 0x06 # error bits showing the error status of the last command executed
50
+ Status1Reg = 0x07 # communication status bits
51
+ Status2Reg = 0x08 # receiver and transmitter status bits
52
+ FIFODataReg = 0x09 # input and output of 64 byte FIFO buffer
53
+ FIFOLevelReg = 0x0A # number of bytes stored in the FIFO buffer
54
+ WaterLevelReg = 0x0B # level for FIFO underflow and overflow warning
55
+ ControlReg = 0x0C # miscellaneous control registers
56
+ BitFramingReg = 0x0D # adjustments for bit-oriented frames
57
+ CollReg = 0x0E # bit position of the first bit-collision detected on the RF interface
58
+
59
+ # PCD Command Registers
60
+ ModeReg = 0x11 # defines general modes for transmitting and receiving
61
+ TxModeReg = 0x12 # defines transmission data rate and framing
62
+ RxModeReg = 0x13 # defines reception data rate and framing
63
+ TxControlReg = 0x14 # controls the logical behavior of the antenna driver pins TX1 and TX2
64
+ TxASKReg = 0x15 # controls the setting of the transmission modulation
65
+ TxSelReg = 0x16 # selects the internal sources for the antenna driver
66
+ RxSelReg = 0x17 # selects internal receiver settings
67
+ RxThresholdReg = 0x18 # selects thresholds for the bit decoder
68
+ DemodReg = 0x19 # defines demodulator settings
69
+ MfTxReg = 0x1C # controls some MIFARE communication transmit parameters
70
+ MfRxReg = 0x1D # controls some MIFARE communication receive parameters
71
+ SerialSpeedReg = 0x1F # selects the speed of the serial UART interface
72
+
73
+ # PCD Configuration Registers
74
+ CRCResultRegH = 0x21 # shows the MSB and LSB values of the CRC calculation
75
+ CRCResultRegL = 0x22
76
+ ModWidthReg = 0x24 # controls the ModWidth setting?
77
+ RFCfgReg = 0x26 # configures the receiver gain
78
+ GsNReg = 0x27 # selects the conductance of the antenna driver pins TX1 and TX2 for modulation
79
+ CWGsPReg = 0x28 # defines the conductance of the p-driver output during periods of no modulation
80
+ ModGsPReg = 0x29 # defines the conductance of the p-driver output during periods of modulation
81
+ TModeReg = 0x2A # defines settings for the internal timer
82
+ TPrescalerReg = 0x2B # the lower 8 bits of the TPrescaler value. The 4 high bits are in TModeReg.
83
+ TReloadRegH = 0x2C # defines the 16-bit timer reload value
84
+ TReloadRegL = 0x2D
85
+ TCounterValueRegH = 0x2E # shows the 16-bit timer value
86
+ TCounterValueRegL = 0x2F
87
+
88
+ # PCD Test Registers
89
+ TestSel1Reg = 0x31 # general test signal configuration
90
+ TestSel2Reg = 0x32 # general test signal configuration
91
+ TestPinEnReg = 0x33 # enables pin output driver on pins D1 to D7
92
+ TestPinValueReg = 0x34 # defines the values for D1 to D7 when it is used as an I/O bus
93
+ TestBusReg = 0x35 # shows the status of the internal test bus
94
+ AutoTestReg = 0x36 # controls the digital self test
95
+ VersionReg = 0x37 # shows the software version
96
+ AnalogTestReg = 0x38 # controls the pins AUX1 and AUX2
97
+ TestDAC1Reg = 0x39 # defines the test value for TestDAC1
98
+ TestDAC2Reg = 0x3A # defines the test value for TestDAC2
99
+ TestADCReg = 0x3B # shows the value of ADC I and Q channels
100
+
101
+ def initialize(nrstpd = 24, chip = 0, spd = 8000000, timer = 50)
102
+ chip_option = { 0 => PiPiper::Spi::CHIP_SELECT_0,
103
+ 1 => PiPiper::Spi::CHIP_SELECT_1,
104
+ 2 => PiPiper::Spi::CHIP_SELECT_BOTH,
105
+ 3 => PiPiper::Spi::CHIP_SELECT_NONE }
106
+ @spi_chip = chip_option[chip]
107
+ @spi_spd = spd
108
+
109
+ # Power it up
110
+ nrstpd_pin = PiPiper::Pin.new(pin: nrstpd, direction: :out)
111
+ nrstpd_pin.on
112
+ sleep 1.0 / 20.0 # Wait 50ms
113
+
114
+ soft_reset # Perform software reset
115
+
116
+ write_spi(TModeReg, 0x8D) # Start timer by setting TAuto=1, and higher part of TPrescalerReg
117
+ write_spi(TPrescalerReg, 0x3E) # Set lower part of TPrescalerReg, and results in 2khz timer (f_timer = 13.56 MHz / (2*TPreScaler+1))
118
+ write_spi(TReloadRegH, (timer >> 8))
119
+ write_spi(TReloadRegL, (timer & 0xFF)) # 50 ticks @2khz defines 25ms per timer cycle
120
+
121
+ write_spi(TxASKReg, 0x40) # Default 0x00. Force a 100 % ASK modulation independent of the ModGsPReg register setting
122
+ write_spi(ModeReg, 0x3D) # Default 0x3F. Set the preset value for the CRC coprocessor for the CalcCRC command to 0x6363 (ISO 14443-3 part 6.2.4)
123
+
124
+ antenna_on # Turn antenna on. They were disabled by the reset.
125
+ end
126
+
127
+ def soft_reset
128
+ write_spi(CommandReg, PCD_SoftReset)
129
+ sleep 1.0 / 20.0 # wait 50ms
130
+ end
131
+
132
+ def read_spi(reg)
133
+ output = 0
134
+ PiPiper::Spi.begin do |spi|
135
+ spi.chip_select_active_low(true)
136
+ spi.bit_order Spi::MSBFIRST
137
+ spi.clock @spi_spd
138
+
139
+ spi.chip_select(@spi_chip) do
140
+ spi.write((reg << 1) & 0x7E | 0x80)
141
+ output = spi.read
142
+ end
143
+ end
144
+ output
145
+ end
146
+
147
+ def write_spi(reg, values)
148
+ PiPiper::Spi.begin do |spi|
149
+ spi.chip_select_active_low(true)
150
+ spi.bit_order Spi::MSBFIRST
151
+ spi.clock @spi_spd
152
+
153
+ spi.chip_select(@spi_chip) do
154
+ spi.write((reg << 1) & 0x7E, *values)
155
+ end
156
+ end
157
+ end
158
+
159
+ def write_spi_set_bitmask(reg, mask)
160
+ value = read_spi(reg)
161
+ write_spi(reg, value | mask)
162
+ end
163
+
164
+ def write_spi_clear_bitmask(reg, mask)
165
+ value = read_spi(reg)
166
+ write_spi(reg, value & (~mask))
167
+ end
168
+
169
+ def antenna_on
170
+ value = read_spi(TxControlReg)
171
+ write_spi_set_bitmask(TxControlReg, 0x03) if (value & 0x03) != 0x03
172
+ end
173
+
174
+ def antenna_off
175
+ write_spi_clear_bitmask(TxControlReg, 0x03)
176
+ end
177
+
178
+ # level = 1: 18dB, 2: 23dB, 3: 33dB, 4: 38dB, 5: 43dB, 6: 48dB
179
+ def antenna_gain(level = nil)
180
+ unless level.nil?
181
+ level = 1 if level > 6 || level < 1
182
+ write_spi_set_bitmask(RFCfgReg, ((level + 1) << 4))
183
+ end
184
+ (read_spi(RFCfgReg) & 0x70) >> 4
185
+ end
186
+
187
+ def calculate_crc(data)
188
+ write_spi(CommandReg, PCD_Idle) # Stop any active command.
189
+ write_spi(DivIrqReg, 0x04) # Clear the CRCIRq interrupt request bit
190
+ write_spi_set_bitmask(FIFOLevelReg, 0x80) # FlushBuffer = 1, FIFO initialization
191
+ write_spi(FIFODataReg, data) # Write data to the FIFO
192
+ write_spi(CommandReg, PCD_CalcCRC) # Start the calculation
193
+
194
+ # Wait for the command to complete
195
+ i = 5000
196
+ loop do
197
+ irq = read_spi(DivIrqReg)
198
+ break if (irq & 0x04) != 0
199
+ return :status_pcd_timeout if i == 0
200
+ i -= 1
201
+ end
202
+
203
+ write_spi(CommandReg, PCD_Idle) # Stop calculating CRC for new content in the FIFO.
204
+
205
+ result = []
206
+ result << read_spi(CRCResultRegL)
207
+ result << read_spi(CRCResultRegH)
208
+
209
+ return :status_ok, result
210
+ end
211
+
212
+ def append_crc(data)
213
+ status, crc = calculate_crc(data)
214
+ return status if status != :status_ok
215
+ data << crc[0] << crc[1]
216
+
217
+ return :status_ok, data
218
+ end
219
+
220
+ def check_crc(data)
221
+ status, crc = calculate_crc(data[0..-3])
222
+ return status if status != :status_ok
223
+ return :status_crc_error if data[-2] != crc[0] || data[-1] != crc[1]
224
+
225
+ return :status_ok
226
+ end
227
+
228
+ def communicate_with_picc(command, send_data, framing_bit = 0, check_crc = false)
229
+ wait_irq = 0x00
230
+ wait_irq = 0x10 if command == PCD_MFAuthent
231
+ wait_irq = 0x30 if command == PCD_Transceive
232
+
233
+ write_spi(CommandReg, PCD_Idle) # Stop any active command.
234
+ write_spi(ComIrqReg, 0x7F) # Clear all seven interrupt request bits
235
+ write_spi_set_bitmask(FIFOLevelReg, 0x80) # FlushBuffer = 1, FIFO initialization
236
+ write_spi(FIFODataReg, send_data) # Write sendData to the FIFO
237
+ write_spi(BitFramingReg, framing_bit) # Bit adjustments
238
+ write_spi(CommandReg, command) # Execute the command
239
+ if command == PCD_Transceive
240
+ write_spi_set_bitmask(BitFramingReg, 0x80) # StartSend=1, transmission of data starts
241
+ end
242
+
243
+ # Wait for the command to complete
244
+ i = 2000
245
+ loop do
246
+ irq = read_spi(ComIrqReg)
247
+ break if (irq & wait_irq) != 0
248
+ return :status_picc_timeout if (irq & 0x01) != 0
249
+ return :status_pcd_timeout if i == 0
250
+ i -= 1
251
+ end
252
+
253
+ # Check for error
254
+ error = read_spi(ErrorReg)
255
+ return :status_error if (error & 0x13) != 0 # BufferOvfl ParityErr ProtocolErr
256
+
257
+ # Receiving data
258
+ received_data = []
259
+ data_length = read_spi(FIFOLevelReg)
260
+ while data_length > 0 do
261
+ data = read_spi(FIFODataReg)
262
+ received_data << data
263
+ data_length -=1
264
+ end
265
+ valid_bits = read_spi(ControlReg) & 0x07
266
+
267
+ # Check CRC if requested
268
+ if !received_data.empty? && check_crc
269
+ return :status_mifare_nack if received_data.count == 1 && valid_bits == 4
270
+ return :status_crc_error if received_data.count < 2 || valid_bits != 0
271
+
272
+ status = check_crc(received_data)
273
+ return status if status != :status_ok
274
+ end
275
+
276
+ status = :status_ok
277
+ status = :status_collision if (error & 0x08) != 0 # CollErr
278
+
279
+ return status, received_data, valid_bits
280
+ end
281
+
282
+ # Wakes PICC from HALT or IDLE to ACTIVE state
283
+ #
284
+ # Accept PICC_REQA and PICC_WUPA command
285
+ def picc_request(picc_command)
286
+ write_spi_clear_bitmask(CollReg, 0x80) # ValuesAfterColl=1 => Bits received after collision are cleared.
287
+
288
+ status, _received_data, valid_bits = communicate_with_picc(PCD_Transceive, picc_command, 0x07)
289
+
290
+ return status if status != :status_ok
291
+ return :status_error if valid_bits != 0 # REQA or WUPA command return 16 bits(full byte)
292
+
293
+ return :status_ok
294
+ end
295
+
296
+ # Instruct PICC in ACTIVE state go to HALT
297
+ def picc_halt
298
+ buffer = [PICC_HLTA, 0]
299
+
300
+ # Calculate CRC and append it into buffer
301
+ status, buffer = append_crc(buffer)
302
+ return status if status != :status_ok
303
+
304
+ status, _received_data, _valid_bits = communicate_with_picc(PCD_Transceive, buffer)
305
+
306
+ # PICC in HALT state will not respond
307
+ # If PICC sent reply, means it didn't acknowledge the command we sent
308
+ return :status_ok if status == :status_picc_timeout
309
+ return :status_error if status == :status_ok
310
+
311
+ return status
312
+ end
313
+
314
+ # PICC must be in state ACTIVE
315
+ def picc_select
316
+ # Description of buffer structure:
317
+ #
318
+ # Byte 0: SEL Indicates the Cascade Level: PICC_CMD_SEL_CL1, PICC_CMD_SEL_CL2 or PICC_CMD_SEL_CL3
319
+ # Byte 1: NVB Number of Valid Bits (in complete command, not just the UID): High nibble: complete bytes, Low nibble: Extra bits.
320
+ # Byte 2: UID-data or Cascade Tag
321
+ # Byte 3: UID-data
322
+ # Byte 4: UID-data
323
+ # Byte 5: UID-data
324
+ # Byte 6: Block Check Character - XOR of bytes 2-5
325
+ # Byte 7: CRC_A
326
+ # Byte 8: CRC_A
327
+ # The BCC and CRC_A are only transmitted if we know all the UID bits of the current Cascade Level.
328
+ #
329
+ # Description of bytes 2-5
330
+ #
331
+ # UID size Cascade level Byte2 Byte3 Byte4 Byte5
332
+ # ======== ============= ===== ===== ===== =====
333
+ # 4 bytes 1 uid0 uid1 uid2 uid3
334
+ # 7 bytes 1 CT uid0 uid1 uid2
335
+ # 2 uid3 uid4 uid5 uid6
336
+ # 10 bytes 1 CT uid0 uid1 uid2
337
+ # 2 CT uid3 uid4 uid5
338
+ # 3 uid6 uid7 uid8 uid9
339
+
340
+ write_spi_clear_bitmask(CollReg, 0x80) # ValuesAfterColl=1 => Bits received after collision are cleared.
341
+ select_level = [PICC_SEL_CL1, PICC_SEL_CL2, PICC_SEL_CL3]
342
+ uid = []
343
+
344
+ for current_cascade_level in 0..2
345
+ buffer = [select_level[current_cascade_level]]
346
+ current_level_known_bits = 0
347
+
348
+ loop do
349
+ if current_level_known_bits >= 32 # Prepare to do a complete select if we knew everything
350
+ tx_last_bits = 0
351
+ buffer[1] = 0x70 # NVB - We're sending full length byte[0..6]
352
+ buffer << (buffer[2] ^ buffer[3] ^ buffer[4] ^ buffer[5]) # Block Check Character
353
+
354
+ # Append CRC to buffer
355
+ status, buffer = append_crc(buffer)
356
+ return status if status != :status_ok
357
+ else
358
+ tx_last_bits = current_level_known_bits % 8
359
+ uid_full_byte = current_level_known_bits / 8
360
+ all_full_byte = 2 + uid_full_byte # length of SEL + NVB + UID
361
+ buffer[1] = (all_full_byte << 4) + tx_last_bits # NVB
362
+ end
363
+
364
+ framing_bit = (tx_last_bits << 4) + tx_last_bits
365
+
366
+ # Try to fetch UID
367
+ status, received_data, valid_bits = communicate_with_picc(PCD_Transceive, buffer, framing_bit)
368
+ return status if status != :status_ok
369
+
370
+ # Append received UID into buffer if not doing full select
371
+ buffer = buffer[0...all_full_byte] + received_data if current_level_known_bits < 32
372
+
373
+ # Handle collision
374
+ if status == :status_collision
375
+ collision = read_spi(CollReg)
376
+
377
+ return :status_collision if (collision & 0x20) != 0 # CollPosNotValid - We don't know where collision happened
378
+ collision_position = collision & 0x1F
379
+ collision_position = 32 if collision_position == 0 # Values 0-31, 0 means bit 32
380
+ return :status_internal_error if collision_position <= current_level_known_bits
381
+
382
+ # Mark the bit
383
+ current_level_known_bits = collision_position
384
+ uid_bit = (current_level_known_bits - 1) % 8
385
+ uid_byte = (current_level_known_bits / 8) + (uid_bit != 0 ? 1 : 0)
386
+ buffer[1 + uid_byte] |= (1 << uid_bit)
387
+ elsif status == :status_ok
388
+ break if current_level_known_bits >= 32
389
+ current_level_known_bits = 32 # We've already known all bits, loop again for a complete select
390
+ else
391
+ return status
392
+ end
393
+ end
394
+
395
+ # We've finished current cascade level
396
+ # Check and collect all uid in this level
397
+
398
+ # Append UID
399
+ uid << buffer[2] if buffer[2] != PICC_CT
400
+ uid << buffer[3] << buffer[4] << buffer[5]
401
+
402
+ # Check the result of full select
403
+ return :status_sak_error if received_data.count != 3 || valid_bits != 0 # Select Acknowledge is 1 byte + CRC_A
404
+
405
+ status = check_crc(received_data)
406
+ return status if status != :status_ok
407
+
408
+ sak = received_data[0]
409
+
410
+ break if (received_data[0] & 0x04) == 0 # No more cascade level
411
+ end
412
+
413
+ return :status_ok, uid, sak
414
+ end
415
+
416
+ def picc_type(sak)
417
+ sak &= 0x7F
418
+
419
+ case sak
420
+ when 0x04
421
+ 'PICC_TYPE_NOT_COMPLETE'
422
+ when 0x09
423
+ 'PICC_TYPE_MIFARE_MINI'
424
+ when 0x08
425
+ 'PICC_TYPE_MIFARE_1K'
426
+ when 0x18
427
+ 'PICC_TYPE_MIFARE_4K'
428
+ when 0x00
429
+ 'PICC_TYPE_MIFARE_UL'
430
+ when 0x10, 0x11
431
+ 'PICC_TYPE_MIFARE_PLUS'
432
+ when 0x01
433
+ 'PICC_TYPE_TNP3XXX'
434
+ when 0x20
435
+ 'PICC_TYPE_ISO_14443_4'
436
+ when 0x40
437
+ 'PICC_TYPE_ISO_18092'
438
+ else
439
+ 'PICC_TYPE_UNKNOWN'
440
+ end
441
+ end
442
+
443
+ #
444
+ # PICC must be selected before calling for authentication
445
+ # Remember to deauthenticate after communication, or no new communication can be made
446
+ #
447
+ # Accept PICC_MF_AUTH_KEY_A or PICC_MF_AUTH_KEY_B command
448
+ # Checks datasheets for block address numbering of your PICC
449
+ #
450
+ def mifare_authenticate(command, block_addr, sector_key, uid)
451
+ #
452
+ # Buffer[12]: {command, block_addr, sector_key[6], uid[4]}
453
+ #
454
+ buffer = [command, block_addr]
455
+ buffer += sector_key[0..5]
456
+ buffer += uid[0..3]
457
+
458
+ status, _received_data, _valid_bits = communicate_with_picc(PCD_MFAuthent, buffer)
459
+
460
+ return status if status != :status_ok
461
+ return :status_auth_failed if (read_spi(Status2Reg) & 0x08) == 0
462
+
463
+ return :status_ok
464
+ end
465
+
466
+ def mifare_deauthenticate
467
+ write_spi_clear_bitmask(Status2Reg, 0x08) # Clear MFCrypto1On bit
468
+ end
469
+
470
+ # Helper that append crc to buffer and check mifare acknowledge
471
+ def mifare_transceive(send_data, accept_timeout = false)
472
+ # Append CRC
473
+ status, send_data = append_crc(send_data)
474
+ return status if status != :status_ok
475
+
476
+ # Transfer data
477
+ status, received_data, valid_bits = communicate_with_picc(PCD_Transceive, send_data)
478
+ return :status_ok if status == :status_picc_timeout && accept_timeout
479
+ return status if status != :status_ok
480
+
481
+ # Check mifare acknowledge
482
+ return :status_error if received_data.count != 1 || valid_bits != 4 # ACK is 4 bits long
483
+ return :status_mifare_nack if received_data[0] != PICC_MF_ACK
484
+
485
+ return :status_ok
486
+ end
487
+
488
+ def mifare_read(block_addr)
489
+ buffer = [PICC_MF_READ, block_addr]
490
+
491
+ status, buffer = append_crc(buffer)
492
+ return status if status != :status_ok
493
+
494
+ status, received_data, _valid_bits = communicate_with_picc(PCD_Transceive, buffer, 0, true)
495
+ return status if status != :status_ok
496
+
497
+ return :status_ok, received_data
498
+ end
499
+
500
+ def mifare_write(block_addr, send_data)
501
+ buffer = [PICC_MF_WRITE, block_addr]
502
+
503
+ # Ask PICC if we can write to block_addr
504
+ status = mifare_transceive(buffer)
505
+ return status if status != :status_ok
506
+
507
+ # Then start transfer our data
508
+ status = mifare_transceive(send_data)
509
+ return status if status != :status_ok
510
+
511
+ return :status_ok
512
+ end
513
+
514
+ def mifare_ultralight_write(page, send_data)
515
+ # Page 2-15, each 4 bytes
516
+ buffer = [PICC_UL_WRITE, page]
517
+ buffer += send_data[0..3]
518
+
519
+ status = mifare_transceive(buffer)
520
+ return status if status != :status_ok
521
+
522
+ return :status_ok
523
+ end
524
+
525
+ # Helper for reading value block
526
+ def mifare_get_value(block_addr)
527
+ status, received_data = mifare_read(block_addr)
528
+ return status if status != :status_ok
529
+
530
+ value = (received_data[3] << 24) + (received_data[2] << 16) + (received_data[1] << 8) + received_data[0]
531
+
532
+ return :status_ok, value
533
+ end
534
+
535
+ # Helper for writing value block
536
+ def mifare_set_value(block_addr, value)
537
+ # Value block format
538
+ #
539
+ # byte 0..3: 32 bit value in little endian
540
+ # byte 4..7: copy of byte 0..3, with inverted bits (aka. XOR 255)
541
+ # byte 8..11: copy of byte 0..3
542
+ # byte 12: index of backup block (can be any value)
543
+ # byte 13: copy of byte 12 with inverted bits (aka. XOR 255)
544
+ # byte 14: copy of byte 12
545
+ # byte 15: copy of byte 13
546
+
547
+ buffer[0] = value & 0xFF
548
+ buffer[1] = (value >> 8) & 0xFF
549
+ buffer[2] = (value >> 16) & 0xFF
550
+ buffer[3] = (value >> 24) & 0xFF
551
+ buffer[4] = ~buffer[0]
552
+ buffer[5] = ~buffer[1]
553
+ buffer[6] = ~buffer[2]
554
+ buffer[7] = ~buffer[3]
555
+ buffer[8] = buffer[0]
556
+ buffer[9] = buffer[1]
557
+ buffer[10] = buffer[2]
558
+ buffer[11] = buffer[3]
559
+ buffer[12] = block_addr
560
+ buffer[13] = ~block_addr
561
+ buffer[14] = buffer[12]
562
+ buffer[15] = buffer[13]
563
+
564
+ mifare_write(blockAddr, buffer)
565
+ end
566
+
567
+ # Helper for increment, decrement, and restore command
568
+ def mifare_two_step(command, block_addr, value)
569
+ buffer = [command, block_addr]
570
+ send_data = [ # Split integer into array of bytes
571
+ value & 0xFF,
572
+ (value >> 8) & 0xFF,
573
+ (value >> 16) & 0xFF,
574
+ (value >> 24) & 0xFF
575
+ ]
576
+
577
+ # Ask PICC if we can write to block_addr
578
+ status = mifare_transceive(buffer)
579
+ return status if status != :status_ok
580
+
581
+ # Then start transfer our data
582
+ status = mifare_transceive(send_data, true) # Accept timeout
583
+ return status if status != :status_ok
584
+
585
+ return :status_ok
586
+ end
587
+
588
+ # MIFARE Classic only
589
+ def mifare_increment(block_addr, delta)
590
+ mifare_two_step(PICC_MF_INCREMENT, block_addr, delta)
591
+ end
592
+
593
+ # MIFARE Classic only
594
+ def mifare_decrement(block_addr, delta)
595
+ mifare_two_step(PICC_MF_DECREMENT, block_addr, delta)
596
+ end
597
+
598
+ # MIFARE Classic only
599
+ def mifare_restore(block_addr)
600
+ mifare_two_step(PICC_MF_RESTORE, block_addr, 0)
601
+ end
602
+
603
+ # MIFARE Classic only
604
+ def mifare_transfer(block_addr)
605
+ buffer = [PICC_MF_TRANSFER, block_addr]
606
+
607
+ status = mifare_transceive(buffer)
608
+ return status if status != :status_ok
609
+
610
+ return :status_ok
611
+ end
612
+ end
613
+
metadata ADDED
@@ -0,0 +1,64 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mfrc522
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - atitan
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-03-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: pi_piper
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 2.0.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '2.0'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 2.0.0
33
+ description:
34
+ email: commit@atifans.net
35
+ executables: []
36
+ extensions: []
37
+ extra_rdoc_files: []
38
+ files:
39
+ - lib/mfrc522.rb
40
+ homepage: https://github.com/atitan/MFRC522_Ruby
41
+ licenses:
42
+ - MIT
43
+ metadata: {}
44
+ post_install_message:
45
+ rdoc_options: []
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ requirements: []
59
+ rubyforge_project:
60
+ rubygems_version: 2.4.6
61
+ signing_key:
62
+ specification_version: 4
63
+ summary: MFRC522 RFID Reader Library for RaspberryPi
64
+ test_files: []