Class: Mfrc522

Inherits:
Object
  • Object
show all
Defined in:
lib/mfrc522.rb

Constant Summary collapse

PICC_REQA =

PICC commands used by the PCD to manage communication with several PICCs (ISO 14443-3, Type A, section 6.4)

0x26
PICC_WUPA =

REQuest command, Type A. Invites PICCs in state IDLE to go to READY and prepare for anticollision or selection. 7 bit frame.

0x52
PICC_CT =

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.

0x88
PICC_SEL_CL1 =

Cascade Tag. Not really a command, but used during anti collision.

0x93
PICC_SEL_CL2 =

Anti collision/Select, Cascade Level 1

0x95
PICC_SEL_CL3 =

Anti collision/Select, Cascade Level 2

0x97
PICC_HLTA =

Anti collision/Select, Cascade Level 3

0x50
PICC_MF_AUTH_KEY_A =

The commands used for MIFARE Classic (from www.mouser.com/ds/2/302/MF1S503x-89574.pdf, Section 9) Use PCD_MFAuthent to authenticate access to a sector, then use these commands to read/write/modify the blocks on the sector. The read/write commands can also be used for MIFARE Ultralight.

0x60
PICC_MF_AUTH_KEY_B =

Perform authentication with Key A

0x61
PICC_MF_READ =

Perform authentication with Key B

0x30
PICC_MF_WRITE =

Reads one 16 byte block from the authenticated sector of the PICC. Also used for MIFARE Ultralight.

0xA0
PICC_MF_DECREMENT =

Writes one 16 byte block to the authenticated sector of the PICC. Called “COMPATIBILITY WRITE” for MIFARE Ultralight.

0xC0
PICC_MF_INCREMENT =

Decrements the contents of a block and stores the result in the internal data register.

0xC1
PICC_MF_RESTORE =

Increments the contents of a block and stores the result in the internal data register.

0xC2
PICC_MF_TRANSFER =

Reads the contents of a block into the internal data register.

0xB0
PICC_UL_WRITE =

The commands used for MIFARE Ultralight (from www.nxp.com/documents/data_sheet/MF0ICU1.pdf, Section 8.6) The PICC_MF_READ and PICC_MF_WRITE can also be used for MIFARE Ultralight.

0xA2
PICC_MF_ACK =

Writes one 4 byte page to the PICC.

0xA
PCD_Idle =

PCD commands

0x00
PCD_Mem =

no action, cancels current command execution

0x01
PCD_GenRandomID =

stores 25 bytes into the internal buffer

0x02
PCD_CalcCRC =

generates a 10-byte random ID number

0x03
PCD_Transmit =

activates the CRC coprocessor or performs a self test

0x04
PCD_NoCmdChange =

transmits data from the FIFO buffer

0x07
PCD_Receive =

no command change, can be used to modify the CommandReg register bits without affecting the command, for example, the PowerDown bit

0x08
PCD_Transceive =

activates the receiver circuits

0x0C
PCD_MFAuthent =

transmits data from FIFO buffer to antenna and automatically activates the receiver after transmission

0x0E
PCD_SoftReset =

performs the MIFARE standard authentication as a reader

0x0F
CommandReg =

PCD Command and Status Registers

0x01
ComIEnReg =

starts and stops command execution

0x02
DivIEnReg =

enable and disable interrupt request control bits

0x03
ComIrqReg =

enable and disable interrupt request control bits

0x04
DivIrqReg =

interrupt request bits

0x05
ErrorReg =

interrupt request bits

0x06
Status1Reg =

error bits showing the error status of the last command executed

0x07
Status2Reg =

communication status bits

0x08
FIFODataReg =

receiver and transmitter status bits

0x09
FIFOLevelReg =

input and output of 64 byte FIFO buffer

0x0A
WaterLevelReg =

number of bytes stored in the FIFO buffer

0x0B
ControlReg =

level for FIFO underflow and overflow warning

0x0C
BitFramingReg =

miscellaneous control registers

0x0D
CollReg =

adjustments for bit-oriented frames

0x0E
ModeReg =

PCD Command Registers

0x11
TxModeReg =

defines general modes for transmitting and receiving

0x12
RxModeReg =

defines transmission data rate and framing

0x13
TxControlReg =

defines reception data rate and framing

0x14
TxASKReg =

controls the logical behavior of the antenna driver pins TX1 and TX2

0x15
TxSelReg =

controls the setting of the transmission modulation

0x16
RxSelReg =

selects the internal sources for the antenna driver

0x17
RxThresholdReg =

selects internal receiver settings

0x18
DemodReg =

selects thresholds for the bit decoder

0x19
MfTxReg =

defines demodulator settings

0x1C
MfRxReg =

controls some MIFARE communication transmit parameters

0x1D
SerialSpeedReg =

controls some MIFARE communication receive parameters

0x1F
CRCResultRegH =

PCD Configuration Registers

0x21
CRCResultRegL =

shows the MSB and LSB values of the CRC calculation

0x22
ModWidthReg =

controls the ModWidth setting?

0x24
RFCfgReg =

configures the receiver gain

0x26
GsNReg =

selects the conductance of the antenna driver pins TX1 and TX2 for modulation

0x27
CWGsPReg =

defines the conductance of the p-driver output during periods of no modulation

0x28
ModGsPReg =

defines the conductance of the p-driver output during periods of modulation

0x29
TModeReg =

defines settings for the internal timer

0x2A
TPrescalerReg =

the lower 8 bits of the TPrescaler value. The 4 high bits are in TModeReg.

0x2B
TReloadRegH =

defines the 16-bit timer reload value

0x2C
TReloadRegL =
0x2D
TCounterValueRegH =

shows the 16-bit timer value

0x2E
TCounterValueRegL =
0x2F
TestSel1Reg =

PCD Test Registers

0x31
TestSel2Reg =

general test signal configuration

0x32
TestPinEnReg =

general test signal configuration

0x33
TestPinValueReg =

enables pin output driver on pins D1 to D7

0x34
TestBusReg =

defines the values for D1 to D7 when it is used as an I/O bus

0x35
AutoTestReg =

shows the status of the internal test bus

0x36
VersionReg =

controls the digital self test

0x37
AnalogTestReg =

shows the software version

0x38
TestDAC1Reg =

controls the pins AUX1 and AUX2

0x39
TestDAC2Reg =

defines the test value for TestDAC1

0x3A
TestADCReg =

defines the test value for TestDAC2

0x3B

Instance Method Summary collapse

Constructor Details

#initialize(nrstpd = 24, chip = 0, spd = 8000000, timer = 50) ⇒ Mfrc522

shows the value of ADC I and Q channels



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
# File 'lib/mfrc522.rb', line 101

def initialize(nrstpd = 24, chip = 0, spd = 8000000, timer = 50)
  chip_option = { 0 => PiPiper::Spi::CHIP_SELECT_0,
                  1 => PiPiper::Spi::CHIP_SELECT_1,
                  2 => PiPiper::Spi::CHIP_SELECT_BOTH,
                  3 => PiPiper::Spi::CHIP_SELECT_NONE }
  @spi_chip = chip_option[chip]
  @spi_spd = spd

  # Power it up
  nrstpd_pin = PiPiper::Pin.new(pin: nrstpd, direction: :out)
  nrstpd_pin.on
  sleep 1.0 / 20.0 # Wait 50ms

  soft_reset # Perform software reset

  write_spi(TModeReg, 0x8D) # Start timer by setting TAuto=1, and higher part of TPrescalerReg
  write_spi(TPrescalerReg, 0x3E) # Set lower part of TPrescalerReg, and results in 2khz timer (f_timer = 13.56 MHz / (2*TPreScaler+1))
  write_spi(TReloadRegH, (timer >> 8))
  write_spi(TReloadRegL, (timer & 0xFF)) # 50 ticks @2khz defines 25ms per timer cycle
  
  write_spi(TxASKReg, 0x40) # Default 0x00. Force a 100 % ASK modulation independent of the ModGsPReg register setting
  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)

  antenna_on # Turn antenna on. They were disabled by the reset.
end

Instance Method Details

#antenna_gain(level = nil) ⇒ Object

level = 1: 18dB, 2: 23dB, 3: 33dB, 4: 38dB, 5: 43dB, 6: 48dB



179
180
181
182
183
184
185
# File 'lib/mfrc522.rb', line 179

def antenna_gain(level = nil)
  unless level.nil?
    level = 1 if level > 6 || level < 1
    write_spi_set_bitmask(RFCfgReg, ((level + 1) << 4))
  end
  (read_spi(RFCfgReg) & 0x70) >> 4
end

#antenna_offObject



174
175
176
# File 'lib/mfrc522.rb', line 174

def antenna_off
  write_spi_clear_bitmask(TxControlReg, 0x03)
end

#antenna_onObject



169
170
171
172
# File 'lib/mfrc522.rb', line 169

def antenna_on
  value = read_spi(TxControlReg)
  write_spi_set_bitmask(TxControlReg, 0x03) if (value & 0x03) != 0x03
end

#append_crc(data) ⇒ Object



212
213
214
215
216
217
218
# File 'lib/mfrc522.rb', line 212

def append_crc(data)
  status, crc = calculate_crc(data)
  return status if status != :status_ok
  data << crc[0] << crc[1]

  return :status_ok, data
end

#calculate_crc(data) ⇒ Object



187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# File 'lib/mfrc522.rb', line 187

def calculate_crc(data)
  write_spi(CommandReg, PCD_Idle)               # Stop any active command.
  write_spi(DivIrqReg, 0x04)                    # Clear the CRCIRq interrupt request bit
  write_spi_set_bitmask(FIFOLevelReg, 0x80)     # FlushBuffer = 1, FIFO initialization
  write_spi(FIFODataReg, data)                  # Write data to the FIFO
  write_spi(CommandReg, PCD_CalcCRC)            # Start the calculation

  # Wait for the command to complete
  i = 5000
  loop do
    irq = read_spi(DivIrqReg)
    break if (irq & 0x04) != 0
    return :status_pcd_timeout if i == 0
    i -= 1
  end

  write_spi(CommandReg, PCD_Idle)               # Stop calculating CRC for new content in the FIFO.

  result = []
  result << read_spi(CRCResultRegL)
  result << read_spi(CRCResultRegH)
  
  return :status_ok, result
end

#check_crc(data) ⇒ Object



220
221
222
223
224
225
226
# File 'lib/mfrc522.rb', line 220

def check_crc(data)
  status, crc = calculate_crc(data[0..-3])
  return status if status != :status_ok
  return :status_crc_error if data[-2] != crc[0] || data[-1] != crc[1]

  return :status_ok
end

#communicate_with_picc(command, send_data, framing_bit = 0, check_crc = false) ⇒ Object



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
# File 'lib/mfrc522.rb', line 228

def communicate_with_picc(command, send_data, framing_bit = 0, check_crc = false)
  wait_irq = 0x00
  wait_irq = 0x10 if command == PCD_MFAuthent
  wait_irq = 0x30 if command == PCD_Transceive

  write_spi(CommandReg, PCD_Idle)               # Stop any active command.
  write_spi(ComIrqReg, 0x7F)                    # Clear all seven interrupt request bits
  write_spi_set_bitmask(FIFOLevelReg, 0x80)     # FlushBuffer = 1, FIFO initialization
  write_spi(FIFODataReg, send_data)             # Write sendData to the FIFO
  write_spi(BitFramingReg, framing_bit)         # Bit adjustments
  write_spi(CommandReg, command)                # Execute the command
  if command == PCD_Transceive
    write_spi_set_bitmask(BitFramingReg, 0x80)  # StartSend=1, transmission of data starts
  end

  # Wait for the command to complete
  i = 2000
  loop do
    irq = read_spi(ComIrqReg)
    break if (irq & wait_irq) != 0
    return :status_picc_timeout if (irq & 0x01) != 0
    return :status_pcd_timeout if i == 0
    i -= 1
  end

  # Check for error
  error = read_spi(ErrorReg)
  return :status_error if (error & 0x13) != 0 # BufferOvfl ParityErr ProtocolErr

  # Receiving data
  received_data = []
  data_length = read_spi(FIFOLevelReg)
  while data_length > 0 do
    data = read_spi(FIFODataReg)
    received_data << data
    data_length -=1
  end
  valid_bits = read_spi(ControlReg) & 0x07

  # Check CRC if requested
  if !received_data.empty? && check_crc
    return :status_mifare_nack if received_data.count == 1 && valid_bits == 4
    return :status_crc_error if received_data.count < 2 || valid_bits != 0

    status = check_crc(received_data)
    return status if status != :status_ok
  end

  status = :status_ok
  status = :status_collision if (error & 0x08) != 0 # CollErr

  return status, received_data, valid_bits
end

#mifare_authenticate(command, block_addr, sector_key, uid) ⇒ Object

PICC must be selected before calling for authentication Remember to deauthenticate after communication, or no new communication can be made

Accept PICC_MF_AUTH_KEY_A or PICC_MF_AUTH_KEY_B command Checks datasheets for block address numbering of your PICC



450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
# File 'lib/mfrc522.rb', line 450

def mifare_authenticate(command, block_addr, sector_key, uid)
  #
  # Buffer[12]: {command, block_addr, sector_key[6], uid[4]}
  #
  buffer = [command, block_addr]
  buffer += sector_key[0..5]
  buffer += uid[0..3]

  status, _received_data, _valid_bits = communicate_with_picc(PCD_MFAuthent, buffer)

  return status if status != :status_ok
  return :status_auth_failed if (read_spi(Status2Reg) & 0x08) == 0

  return :status_ok
end

#mifare_deauthenticateObject



466
467
468
# File 'lib/mfrc522.rb', line 466

def mifare_deauthenticate
  write_spi_clear_bitmask(Status2Reg, 0x08) # Clear MFCrypto1On bit
end

#mifare_decrement(block_addr, delta) ⇒ Object

MIFARE Classic only



594
595
596
# File 'lib/mfrc522.rb', line 594

def mifare_decrement(block_addr, delta)
  mifare_two_step(PICC_MF_DECREMENT, block_addr, delta)
end

#mifare_get_value(block_addr) ⇒ Object

Helper for reading value block



526
527
528
529
530
531
532
533
# File 'lib/mfrc522.rb', line 526

def mifare_get_value(block_addr)
  status, received_data = mifare_read(block_addr)
  return status if status != :status_ok

  value = (received_data[3] << 24) + (received_data[2] << 16) + (received_data[1] << 8) + received_data[0]

  return :status_ok, value
end

#mifare_increment(block_addr, delta) ⇒ Object

MIFARE Classic only



589
590
591
# File 'lib/mfrc522.rb', line 589

def mifare_increment(block_addr, delta)
  mifare_two_step(PICC_MF_INCREMENT, block_addr, delta)
end

#mifare_read(block_addr) ⇒ Object



488
489
490
491
492
493
494
495
496
497
498
# File 'lib/mfrc522.rb', line 488

def mifare_read(block_addr)
  buffer = [PICC_MF_READ, block_addr]

  status, buffer = append_crc(buffer)
  return status if status != :status_ok

  status, received_data, _valid_bits = communicate_with_picc(PCD_Transceive, buffer, 0, true)
  return status if status != :status_ok

  return :status_ok, received_data
end

#mifare_restore(block_addr) ⇒ Object

MIFARE Classic only



599
600
601
# File 'lib/mfrc522.rb', line 599

def mifare_restore(block_addr)
  mifare_two_step(PICC_MF_RESTORE, block_addr, 0)
end

#mifare_set_value(block_addr, value) ⇒ Object

Helper for writing value block



536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
# File 'lib/mfrc522.rb', line 536

def mifare_set_value(block_addr, value)
  # Value block format
  #
  # byte 0..3:   32 bit value in little endian
  # byte 4..7:   copy of byte 0..3, with inverted bits (aka. XOR 255)
  # byte 8..11:  copy of byte 0..3
  # byte 12:     index of backup block (can be any value)
  # byte 13:     copy of byte 12 with inverted bits (aka. XOR 255)
  # byte 14:     copy of byte 12
  # byte 15:     copy of byte 13

  buffer[0]  = value & 0xFF
  buffer[1]  = (value >> 8) & 0xFF
  buffer[2]  = (value >> 16) & 0xFF
  buffer[3]  = (value >> 24) & 0xFF
  buffer[4]  = ~buffer[0]
  buffer[5]  = ~buffer[1]
  buffer[6]  = ~buffer[2]
  buffer[7]  = ~buffer[3]
  buffer[8]  = buffer[0]
  buffer[9]  = buffer[1]
  buffer[10] = buffer[2]
  buffer[11] = buffer[3]
  buffer[12] = block_addr
  buffer[13] = ~block_addr
  buffer[14] = buffer[12]
  buffer[15] = buffer[13]

  mifare_write(blockAddr, buffer)
end

#mifare_transceive(send_data, accept_timeout = false) ⇒ Object

Helper that append crc to buffer and check mifare acknowledge



471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
# File 'lib/mfrc522.rb', line 471

def mifare_transceive(send_data, accept_timeout = false)
  # Append CRC
  status, send_data = append_crc(send_data)
  return status if status != :status_ok

  # Transfer data
  status, received_data, valid_bits = communicate_with_picc(PCD_Transceive, send_data)
  return :status_ok if status == :status_picc_timeout && accept_timeout
  return status if status != :status_ok

  # Check mifare acknowledge
  return :status_error if received_data.count != 1 || valid_bits != 4 # ACK is 4 bits long
  return :status_mifare_nack if received_data[0] != PICC_MF_ACK

  return :status_ok
end

#mifare_transfer(block_addr) ⇒ Object

MIFARE Classic only



604
605
606
607
608
609
610
611
# File 'lib/mfrc522.rb', line 604

def mifare_transfer(block_addr)
  buffer = [PICC_MF_TRANSFER, block_addr]

  status = mifare_transceive(buffer)
  return status if status != :status_ok

  return :status_ok
end

#mifare_two_step(command, block_addr, value) ⇒ Object

Helper for increment, decrement, and restore command



568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
# File 'lib/mfrc522.rb', line 568

def mifare_two_step(command, block_addr, value)
  buffer = [command, block_addr]
  send_data = [ # Split integer into array of bytes
    value & 0xFF,
    (value >> 8) & 0xFF,
    (value >> 16) & 0xFF,
    (value >> 24) & 0xFF
  ]
  
  # Ask PICC if we can write to block_addr
  status = mifare_transceive(buffer)
  return status if status != :status_ok

  # Then start transfer our data
  status = mifare_transceive(send_data, true) # Accept timeout
  return status if status != :status_ok

  return :status_ok
end

#mifare_ultralight_write(page, send_data) ⇒ Object



514
515
516
517
518
519
520
521
522
523
# File 'lib/mfrc522.rb', line 514

def mifare_ultralight_write(page, send_data)
  # Page 2-15, each 4 bytes
  buffer = [PICC_UL_WRITE, page]
  buffer += send_data[0..3]

  status = mifare_transceive(buffer)
  return status if status != :status_ok

  return :status_ok
end

#mifare_write(block_addr, send_data) ⇒ Object



500
501
502
503
504
505
506
507
508
509
510
511
512
# File 'lib/mfrc522.rb', line 500

def mifare_write(block_addr, send_data)
  buffer = [PICC_MF_WRITE, block_addr]

  # Ask PICC if we can write to block_addr
  status = mifare_transceive(buffer)
  return status if status != :status_ok

  # Then start transfer our data
  status = mifare_transceive(send_data)
  return status if status != :status_ok

  return :status_ok
end

#picc_haltObject

Instruct PICC in ACTIVE state go to HALT



297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
# File 'lib/mfrc522.rb', line 297

def picc_halt
  buffer = [PICC_HLTA, 0]

  # Calculate CRC and append it into buffer
  status, buffer = append_crc(buffer)
  return status if status != :status_ok

  status, _received_data, _valid_bits = communicate_with_picc(PCD_Transceive, buffer)

  # PICC in HALT state will not respond
  # If PICC sent reply, means it didn't acknowledge the command we sent
  return :status_ok if status == :status_picc_timeout
  return :status_error if status == :status_ok

  return status
end

#picc_request(picc_command) ⇒ Object

Wakes PICC from HALT or IDLE to ACTIVE state

Accept PICC_REQA and PICC_WUPA command



285
286
287
288
289
290
291
292
293
294
# File 'lib/mfrc522.rb', line 285

def picc_request(picc_command)
  write_spi_clear_bitmask(CollReg, 0x80)  # ValuesAfterColl=1 => Bits received after collision are cleared.

  status, _received_data, valid_bits = communicate_with_picc(PCD_Transceive, picc_command, 0x07)

  return status if status != :status_ok
  return :status_error if valid_bits != 0 # REQA or WUPA command return 16 bits(full byte)

  return :status_ok
end

#picc_selectObject

PICC must be in state ACTIVE



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
# File 'lib/mfrc522.rb', line 315

def picc_select
  #  Description of buffer structure:
  #
  #  Byte 0: SEL   Indicates the Cascade Level: PICC_CMD_SEL_CL1, PICC_CMD_SEL_CL2 or PICC_CMD_SEL_CL3
  #  Byte 1: NVB   Number of Valid Bits (in complete command, not just the UID): High nibble: complete bytes, Low nibble: Extra bits. 
  #  Byte 2: UID-data or Cascade Tag
  #  Byte 3: UID-data
  #  Byte 4: UID-data
  #  Byte 5: UID-data
  #  Byte 6: Block Check Character - XOR of bytes 2-5
  #  Byte 7: CRC_A
  #  Byte 8: CRC_A
  #  The BCC and CRC_A are only transmitted if we know all the UID bits of the current Cascade Level.
  #
  #  Description of bytes 2-5
  #
  #  UID size  Cascade level Byte2 Byte3 Byte4 Byte5
  #  ========  ============= ===== ===== ===== =====
  #   4 bytes        1       uid0  uid1  uid2  uid3
  #   7 bytes        1       CT    uid0  uid1  uid2
  #                  2       uid3  uid4  uid5  uid6
  #  10 bytes        1       CT    uid0  uid1  uid2
  #                  2       CT    uid3  uid4  uid5
  #                  3       uid6  uid7  uid8  uid9

  write_spi_clear_bitmask(CollReg, 0x80)    # ValuesAfterColl=1 => Bits received after collision are cleared.
  select_level = [PICC_SEL_CL1, PICC_SEL_CL2, PICC_SEL_CL3]
  uid = []

  for current_cascade_level in 0..2
    buffer = [select_level[current_cascade_level]]
    current_level_known_bits = 0

    loop do
      if current_level_known_bits >= 32 # Prepare to do a complete select if we knew everything
        tx_last_bits = 0
        buffer[1] = 0x70 # NVB - We're sending full length byte[0..6]
        buffer << (buffer[2] ^ buffer[3] ^ buffer[4] ^ buffer[5]) # Block Check Character

        # Append CRC to buffer
        status, buffer = append_crc(buffer)
        return status if status != :status_ok
      else
        tx_last_bits = current_level_known_bits % 8
        uid_full_byte = current_level_known_bits / 8
        all_full_byte = 2 + uid_full_byte # length of SEL + NVB + UID
        buffer[1] = (all_full_byte << 4) + tx_last_bits # NVB
      end

      framing_bit = (tx_last_bits << 4) + tx_last_bits

      # Try to fetch UID
      status, received_data, valid_bits = communicate_with_picc(PCD_Transceive, buffer, framing_bit)
      return status if status != :status_ok

      # Append received UID into buffer if not doing full select
      buffer = buffer[0...all_full_byte] + received_data if current_level_known_bits < 32

      # Handle collision
      if status == :status_collision
        collision = read_spi(CollReg)

        return :status_collision if (collision & 0x20) != 0 # CollPosNotValid - We don't know where collision happened
        collision_position = collision & 0x1F
        collision_position = 32 if collision_position == 0 # Values 0-31, 0 means bit 32
        return :status_internal_error if collision_position <= current_level_known_bits
      
        # Mark the bit
        current_level_known_bits = collision_position
        uid_bit = (current_level_known_bits - 1) % 8
        uid_byte = (current_level_known_bits / 8) + (uid_bit != 0 ? 1 : 0)
        buffer[1 + uid_byte] |= (1 << uid_bit)
      elsif status == :status_ok
        break if current_level_known_bits >= 32
        current_level_known_bits = 32 # We've already known all bits, loop again for a complete select
      else
        return status
      end 
    end

    # We've finished current cascade level
    # Check and collect all uid in this level

    # Append UID
    uid << buffer[2] if buffer[2] != PICC_CT
    uid << buffer[3] << buffer[4] << buffer[5]

    # Check the result of full select
    return :status_sak_error if received_data.count != 3 || valid_bits != 0 # Select Acknowledge is 1 byte + CRC_A

    status = check_crc(received_data)
    return status if status != :status_ok

    sak = received_data[0]

    break if (received_data[0] & 0x04) == 0 # No more cascade level
  end

  return :status_ok, uid, sak
end

#picc_type(sak) ⇒ Object



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
# File 'lib/mfrc522.rb', line 416

def picc_type(sak)
  sak &= 0x7F

  case sak
  when 0x04
    'PICC_TYPE_NOT_COMPLETE'
  when 0x09
    'PICC_TYPE_MIFARE_MINI'
  when 0x08
    'PICC_TYPE_MIFARE_1K'
  when 0x18
    'PICC_TYPE_MIFARE_4K'
  when 0x00
    'PICC_TYPE_MIFARE_UL'
  when 0x10, 0x11
    'PICC_TYPE_MIFARE_PLUS'
  when 0x01
    'PICC_TYPE_TNP3XXX'
  when 0x20
    'PICC_TYPE_ISO_14443_4'
  when 0x40
    'PICC_TYPE_ISO_18092'
  else
    'PICC_TYPE_UNKNOWN'
  end
end

#read_spi(reg) ⇒ Object



132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/mfrc522.rb', line 132

def read_spi(reg)
  output = 0
  PiPiper::Spi.begin do |spi|
    spi.chip_select_active_low(true)
    spi.bit_order Spi::MSBFIRST
    spi.clock @spi_spd

    spi.chip_select(@spi_chip) do
      spi.write((reg << 1) & 0x7E | 0x80)
      output = spi.read
    end
  end
  output
end

#soft_resetObject



127
128
129
130
# File 'lib/mfrc522.rb', line 127

def soft_reset
  write_spi(CommandReg, PCD_SoftReset)
  sleep 1.0 / 20.0 # wait 50ms
end

#write_spi(reg, values) ⇒ Object



147
148
149
150
151
152
153
154
155
156
157
# File 'lib/mfrc522.rb', line 147

def write_spi(reg, values)
  PiPiper::Spi.begin do |spi|
    spi.chip_select_active_low(true)
    spi.bit_order Spi::MSBFIRST
    spi.clock @spi_spd

    spi.chip_select(@spi_chip) do
      spi.write((reg << 1) & 0x7E, *values)
    end
  end
end

#write_spi_clear_bitmask(reg, mask) ⇒ Object



164
165
166
167
# File 'lib/mfrc522.rb', line 164

def write_spi_clear_bitmask(reg, mask)
  value = read_spi(reg)
  write_spi(reg, value & (~mask))
end

#write_spi_set_bitmask(reg, mask) ⇒ Object



159
160
161
162
# File 'lib/mfrc522.rb', line 159

def write_spi_set_bitmask(reg, mask)
  value = read_spi(reg)
  write_spi(reg, value | mask)
end