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_ACK =
Mifare Acknowledge
0x0A
- 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
Modify and show antenna gain level level = 1: 18dB, 2: 23dB, 3: 33dB, 4: 38dB, 5: 43dB, 6: 48dB.
-
#antenna_off ⇒ Object
Turn antenna off.
-
#antenna_on ⇒ Object
Turn antenna on.
-
#identify_model(sak) ⇒ Object
Lookup PICC name using sak.
-
#initialize(nrstpd = 24, chip = 0, spd = 8000000, timer = 256) ⇒ MFRC522
constructor
shows the value of ADC I and Q channels.
-
#internal_timer(timer = nil) ⇒ Object
Control transceive timeout value.
-
#mifare_crypto1_authenticate(command, block_addr, sector_key, uid) ⇒ Object
Start Crypto1 communication between reader and Mifare PICC.
-
#mifare_crypto1_deauthenticate ⇒ Object
Stop Crypto1 communication.
-
#pcd_config_reset ⇒ Object
Reset PCD config to default.
-
#picc_halt ⇒ Object
Instruct PICC in ACTIVE state go to HALT state.
-
#picc_request(picc_command) ⇒ Object
Wakes PICC from HALT or IDLE to ACTIVE state Accept PICC_REQA and PICC_WUPA command.
-
#picc_select ⇒ Object
Select PICC for further communication.
-
#picc_transceive(send_data, accept_timeout = false) ⇒ Object
Append CRC to buffer and check CRC or Mifare acknowledge.
-
#reestablish_picc_communication(uid) ⇒ Object
Trying to restart picc.
-
#soft_reset ⇒ Object
PCD software reset.
-
#transceiver_baud_rate(direction, value = nil) ⇒ Object
Control transceiver baud rate value = 0: 106kBd, 1: 212kBd, 2: 424kBd, 3: 848kBd.
Constructor Details
#initialize(nrstpd = 24, chip = 0, spd = 8000000, timer = 256) ⇒ MFRC522
shows the value of ADC I and Q channels
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/mfrc522.rb', line 103 def initialize(nrstpd = 24, chip = 0, spd = 8000000, timer = 256) 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 @timer = timer # 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 pcd_config_reset # Set default setting antenna_on # Turn antenna on. They were disabled by the reset. end |
Instance Method Details
#antenna_gain(level = nil) ⇒ Object
Modify and show antenna gain level level = 1: 18dB, 2: 23dB, 3: 33dB, 4: 38dB, 5: 43dB, 6: 48dB
184 185 186 187 188 189 190 |
# File 'lib/mfrc522.rb', line 184 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
Turn antenna off
178 179 180 |
# File 'lib/mfrc522.rb', line 178 def antenna_off write_spi_clear_bitmask(TxControlReg, 0x03) end |
#antenna_on ⇒ Object
Turn antenna on
173 174 175 |
# File 'lib/mfrc522.rb', line 173 def antenna_on write_spi_set_bitmask(TxControlReg, 0x03) end |
#identify_model(sak) ⇒ Object
Lookup PICC name using sak
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 |
# File 'lib/mfrc522.rb', line 341 def identify_model(sak) # SAK coding separation reference: # http://cache.nxp.com/documents/application_note/AN10833.pdf # http://www.nxp.com/documents/application_note/130830.pdf if sak & 0x04 != 0 return :picc_uid_not_complete end if sak & 0x02 != 0 return :picc_reserved_future_use end if sak & 0x08 != 0 if sak & 0x10 != 0 return :picc_mifare_4k end if sak & 0x01 != 0 return :picc_mifare_mini end return :picc_mifare_1k end if sak & 0x10 != 0 if sak & 0x01 != 0 return :picc_mifare_plus_4k_sl2 end return :picc_mifare_plus_2k_sl2 end if sak == 0x00 return :picc_mifare_ultralight end if sak & 0x20 != 0 return :picc_iso_14443_4 end if sak & 0x40 != 0 return :picc_iso_18092 end return :picc_unknown end |
#internal_timer(timer = nil) ⇒ Object
Control transceive timeout value
150 151 152 153 154 155 156 |
# File 'lib/mfrc522.rb', line 150 def internal_timer(timer = nil) if timer write_spi(TReloadRegH, (timer >> 8) & 0xFF) write_spi(TReloadRegL, (timer & 0xFF)) end (read_spi(TReloadRegH) << 8) | read_spi(TReloadRegL) end |
#mifare_crypto1_authenticate(command, block_addr, sector_key, uid) ⇒ Object
Start Crypto1 communication between reader and Mifare PICC
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
396 397 398 399 400 401 402 403 404 405 406 |
# File 'lib/mfrc522.rb', line 396 def mifare_crypto1_authenticate(command, block_addr, sector_key, uid) # Buffer[12]: {command, block_addr, sector_key[6], uid[4]} buffer = [command, block_addr] buffer.concat(sector_key[0..5]) buffer.concat(uid[0..3]) communicate_with_picc(PCD_MFAuthent, buffer) # Check MFCrypto1On bit (read_spi(Status2Reg) & 0x08) != 0 end |
#mifare_crypto1_deauthenticate ⇒ Object
Stop Crypto1 communication
409 410 411 |
# File 'lib/mfrc522.rb', line 409 def mifare_crypto1_deauthenticate write_spi_clear_bitmask(Status2Reg, 0x08) # Clear MFCrypto1On bit end |
#pcd_config_reset ⇒ Object
Reset PCD config to default
137 138 139 140 141 142 143 144 145 146 147 |
# File 'lib/mfrc522.rb', line 137 def pcd_config_reset # Clear ValuesAfterColl bit write_spi_clear_bitmask(CollReg, 0x80) # Reset transceiver baud rate to 106 kBd transceiver_baud_rate(:tx, 0) transceiver_baud_rate(:rx, 0) # Set PCD timer value for 302us default timer internal_timer(@timer) end |
#picc_halt ⇒ Object
Instruct PICC in ACTIVE state go to HALT state
203 204 205 206 207 208 209 210 211 |
# File 'lib/mfrc522.rb', line 203 def picc_halt buffer = append_crc([PICC_HLTA, 0]) 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 status == :status_picc_timeout end |
#picc_request(picc_command) ⇒ Object
Wakes PICC from HALT or IDLE to ACTIVE state Accept PICC_REQA and PICC_WUPA command
194 195 196 197 198 199 200 |
# File 'lib/mfrc522.rb', line 194 def picc_request(picc_command) pcd_config_reset status, _received_data, valid_bits = communicate_with_picc(PCD_Transceive, picc_command, 0x07) status == :status_ok && valid_bits == 0 # REQA or WUPA command return 16 bits(full byte) end |
#picc_select ⇒ Object
Select PICC for further communication
PICC must be in state ACTIVE
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 |
# File 'lib/mfrc522.rb', line 216 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 pcd_config_reset cascade_levels = [PICC_SEL_CL1, PICC_SEL_CL2, PICC_SEL_CL3] uid = [] sak = 0 cascade_levels.each do |cascade_level| buffer = [cascade_level] current_level_known_bits = 0 received_data = [] valid_bits = 0 loop do if current_level_known_bits >= 32 # Prepare to do a complete select if we knew everything # ensure there's nothing weird in buffer if buffer.size != 6 && !buffer.select{|b| !buffer.is_a?(Fixnum)}.empty? current_level_known_bits = 0 buffer = [cascade_level] next end 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 buffer = append_crc(buffer) 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 # Select it status, received_data, valid_bits = communicate_with_picc(PCD_Transceive, buffer, framing_bit) # Append received UID into buffer if not doing full select buffer = buffer[0...all_full_byte] + received_data[0..3] if current_level_known_bits < 32 # Handle collision if status == :status_collision collision = read_spi(CollReg) # CollPosNotValid - We don't know where collision happened raise CollisionError if (collision & 0x20) != 0 collision_position = collision & 0x1F collision_position = 32 if collision_position == 0 # Values 0-31, 0 means bit 32 raise CollisionError if collision_position <= current_level_known_bits # Mark the collision 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 raise CommunicationError, status end end # We've finished current cascade level # Check and collect all uid stored in buffer # Append UID uid << buffer[2] if buffer[2] != PICC_CT uid << buffer[3] << buffer[4] << buffer[5] # Check the result of full select # Select Acknowledge is 1 byte + CRC16 raise UnexpectedDataError, 'Unknown SAK format' if received_data.size != 3 || valid_bits != 0 raise IncorrectCRCError unless check_crc(received_data) sak = received_data[0] break if (sak & 0x04) == 0 # No more cascade level end return uid, sak end |
#picc_transceive(send_data, accept_timeout = false) ⇒ Object
Append CRC to buffer and check CRC or Mifare acknowledge
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 |
# File 'lib/mfrc522.rb', line 414 def picc_transceive(send_data, accept_timeout = false) send_data = append_crc(send_data) puts "Sending Data: #{send_data.map{|x|x.to_s(16).rjust(2,'0').upcase}}" if ENV['DEBUG'] # Transfer data status, received_data, valid_bits = communicate_with_picc(PCD_Transceive, send_data) return [] if status == :status_picc_timeout && accept_timeout raise PICCTimeoutError if status == :status_picc_timeout raise CommunicationError, status if status != :status_ok puts "Received Data: #{received_data.map{|x|x.to_s(16).rjust(2,'0').upcase}}" if ENV['DEBUG'] # Data exists, check CRC and return if received_data.size > 1 raise IncorrectCRCError unless check_crc(received_data) return received_data[0..-3] end raise UnexpectedDataError, 'Incorrect Mifare ACK format' if received_data.size != 1 || valid_bits != 4 # ACK is 4 bits long raise MifareNakError, received_data[0] if received_data[0] != PICC_MF_ACK received_data end |
#reestablish_picc_communication(uid) ⇒ Object
Trying to restart picc
326 327 328 329 330 331 332 333 334 335 336 337 338 |
# File 'lib/mfrc522.rb', line 326 def reestablish_picc_communication(uid) picc_halt picc_request(PICC_WUPA) begin new_uid, _new_sak = picc_select status = true rescue CommunicationError status = false end status && uid == new_uid end |
#soft_reset ⇒ Object
PCD software reset
125 126 127 128 129 130 131 132 133 134 |
# File 'lib/mfrc522.rb', line 125 def soft_reset write_spi(CommandReg, PCD_SoftReset) sleep 1.0 / 20.0 # wait 50ms write_spi(TModeReg, 0x87) # Start timer by setting TAuto=1, and higher part of TPrescalerReg write_spi(TPrescalerReg, 0xFF) # Set lower part of TPrescalerReg, and results in 302us timer (f_timer = 13.56 MHz / (2*TPreScaler+1)) 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) end |
#transceiver_baud_rate(direction, value = nil) ⇒ Object
Control transceiver baud rate value = 0: 106kBd, 1: 212kBd, 2: 424kBd, 3: 848kBd
160 161 162 163 164 165 166 167 168 169 170 |
# File 'lib/mfrc522.rb', line 160 def transceiver_baud_rate(direction, value = nil) reg = {tx: TxModeReg, rx: RxModeReg} if value value <<= 4 value |= 0x80 if value != 0 write_spi(reg.fetch(direction), value) end (read_spi(reg.fetch(direction)) >> 4) & 0x07 end |