Class: Mfrc522
- Inherits:
-
Object
- Object
- Mfrc522
- 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
-
#antenna_gain(level = nil) ⇒ Object
level = 1: 18dB, 2: 23dB, 3: 33dB, 4: 38dB, 5: 43dB, 6: 48dB.
- #antenna_off ⇒ Object
- #antenna_on ⇒ Object
- #append_crc(data) ⇒ Object
- #calculate_crc(data) ⇒ Object
- #check_crc(data) ⇒ Object
- #communicate_with_picc(command, send_data, framing_bit = 0, check_crc = false) ⇒ Object
-
#initialize(nrstpd = 24, chip = 0, spd = 8000000, timer = 50) ⇒ Mfrc522
constructor
shows the value of ADC I and Q channels.
-
#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.
- #mifare_deauthenticate ⇒ Object
-
#mifare_decrement(block_addr, delta) ⇒ Object
MIFARE Classic only.
-
#mifare_get_value(block_addr) ⇒ Object
Helper for reading value block.
-
#mifare_increment(block_addr, delta) ⇒ Object
MIFARE Classic only.
- #mifare_read(block_addr) ⇒ Object
-
#mifare_restore(block_addr) ⇒ Object
MIFARE Classic only.
-
#mifare_set_value(block_addr, value) ⇒ Object
Helper for writing value block.
-
#mifare_transceive(send_data, accept_timeout = false) ⇒ Object
Helper that append crc to buffer and check mifare acknowledge.
-
#mifare_transfer(block_addr) ⇒ Object
MIFARE Classic only.
-
#mifare_two_step(command, block_addr, value) ⇒ Object
Helper for increment, decrement, and restore command.
- #mifare_ultralight_write(page, send_data) ⇒ Object
- #mifare_write(block_addr, send_data) ⇒ Object
-
#picc_halt ⇒ Object
Instruct PICC in ACTIVE state go to HALT.
-
#picc_request(picc_command) ⇒ Object
Wakes PICC from HALT or IDLE to ACTIVE state.
-
#picc_select ⇒ Object
PICC must be in state ACTIVE.
- #picc_type(sak) ⇒ Object
- #read_spi(reg) ⇒ Object
- #soft_reset ⇒ Object
- #write_spi(reg, values) ⇒ Object
- #write_spi_clear_bitmask(reg, mask) ⇒ Object
- #write_spi_set_bitmask(reg, mask) ⇒ Object
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_off ⇒ Object
174 175 176 |
# File 'lib/mfrc522.rb', line 174 def antenna_off write_spi_clear_bitmask(TxControlReg, 0x03) end |
#antenna_on ⇒ Object
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_deauthenticate ⇒ Object
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_halt ⇒ Object
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_select ⇒ Object
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_reset ⇒ Object
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 |