YAHAL
Yet Another Hardware Abstraction Library
Loading...
Searching...
No Matches
mfrc522_drv.cpp
1/*
2* MFRC522.cpp - Library to use ARDUINO RFID MODULE KIT 13.56 MHZ WITH TAGS SPI W AND R BY COOQROBOT.
3* NOTE: Please also check the comments in MFRC522.h - they provide useful hints and background information.
4* Released into the public domain.
5*/
6
7#include <cstring> // for memcpy
8#include <cstdio>
9#include "mfrc522_drv.h"
10#include "spi_interface.h"
11#include "gpio_interface.h"
12#include "task.h"
13
14#ifndef MFRC522_SPICLOCK
15#define MFRC522_SPICLOCK (4000000u) // MFRC522 accept upto 10MHz, set to 4MHz.
16#endif
17
19// Functions for setting up the Arduino
21
27: _spi(spi), _reset(reset) {
28 _reset.gpioMode(GPIO::OUTPUT | GPIO::INIT_HIGH);
29 _spi.setSpeed(MFRC522_SPICLOCK);
30 _spi.generateCS(false);
31 _spi.setCS(HIGH);
32}
33
35// Basic interface functions for communicating with the MFRC522
37
42void mfrc522_drv::PCD_WriteRegister(PCD_Register reg, uint8_t value) {
43 uint8_t buf[2];
44 buf[0] = reg;
45 buf[1] = value;
46
47 _spi.setCS(LOW);
48 _spi.spiTx(buf, 2);
49 _spi.setCS(HIGH);
50}
51
56void mfrc522_drv::PCD_WriteRegister(PCD_Register reg,
57 uint8_t count,
58 uint8_t *values) {
59 uint8_t buf[4096];
60 buf[0] = reg;
61 for(size_t i=0; i < count; ++i) buf[i+1] = values[i];
62
63 _spi.setCS(LOW);
64 _spi.spiTx(buf, count+1);
65 _spi.setCS(HIGH);
66}
67
72uint8_t mfrc522_drv::PCD_ReadRegister(PCD_Register reg) {
73 uint8_t buf_tx[1];
74 uint8_t buf_rx[1];
75 buf_tx[0] = 0x80 | reg;
76
77 _spi.setCS(LOW);
78 _spi.spiTx(buf_tx, 1);
79 _spi.spiRx(0, buf_rx, 1);
80 _spi.setCS(HIGH);
81
82 return buf_rx[0];
83}
84
89void mfrc522_drv::PCD_ReadRegister(PCD_Register reg,
90 uint8_t count,
91 uint8_t *values,
92 uint8_t rxAlign) {
93 uint8_t buf_rx[1];
94 if (count == 0) return;
95
96 uint8_t address = 0x80 | reg; // MSB == 1 is for reading. LSB is not used in address. Datasheet section 8.1.2.3.
97 uint8_t index = 0; // Index in values array.
98
99 _spi.setCS(LOW);
100 count--; // One read is performed outside of the loop
101 _spi.spiTx(&address, 1); // Tell MFRC522 which address we want to read
102 if (rxAlign) { // Only update bit positions rxAlign..7 in values[0]
103 // Create bit mask for bit positions rxAlign..7
104 uint8_t mask = (0xFF << rxAlign) & 0xFF;
105 // Read value and tell that we want to read the same address again.
106 _spi.spiRx(address, buf_rx, 1);
107 uint8_t value = buf_rx[0];
108 // Apply mask to both current value of values[0] and the new data in value.
109 values[0] = (values[0] & ~mask) | (value & mask);
110 index++;
111 }
112 while (index < count) {
113 _spi.spiRx(address, buf_rx, 1); // Read value and tell that we want to read the same address again.
114 values[index] = buf_rx[0];
115 index++;
116 }
117 _spi.spiRx(0, buf_rx, 1); // Read value and tell that we want to read the same address again.
118 values[index] = buf_rx[0];
119 _spi.setCS(HIGH);
120
121}
122
127 uint8_t mask
128) {
129 uint8_t tmp;
130 tmp = PCD_ReadRegister(reg);
131 PCD_WriteRegister(reg, tmp | mask); // set bit mask
132} // End PCD_SetRegisterBitMask()
133
138 uint8_t mask) {
139 uint8_t tmp;
140 tmp = PCD_ReadRegister(reg);
141 PCD_WriteRegister(reg, tmp & (~mask)); // clear bit mask
142}
143
144
150mfrc522_drv::StatusCode mfrc522_drv::PCD_CalculateCRC(
151 uint8_t *data,
152 uint8_t length,
153 uint8_t *result
154) {
155 PCD_WriteRegister(CommandReg, PCD_Idle); // Stop any active command.
156 PCD_WriteRegister(DivIrqReg, 0x04); // Clear the CRCIRq interrupt request bit
157 PCD_WriteRegister(FIFOLevelReg, 0x80); // FlushBuffer = 1, FIFO initialization
158 PCD_WriteRegister(FIFODataReg, length, data); // Write data to the FIFO
159 PCD_WriteRegister(CommandReg, PCD_CalcCRC); // Start the calculation
160
161 // Wait for the CRC calculation to complete. Check for the register to
162 // indicate that the CRC calculation is complete in a loop. If the
163 // calculation is not indicated as complete in ~90ms, then time out
164 // the operation.
165 const uint32_t deadline = task::millis() + 89;
166
167 do {
168 // DivIrqReg[7..0] bits are: Set2 reserved reserved MfinActIRq reserved CRCIRq reserved reserved
169 uint8_t n = PCD_ReadRegister(DivIrqReg);
170 if (n & 0x04) { // CRCIRq bit set - calculation done
171 PCD_WriteRegister(CommandReg, PCD_Idle); // Stop calculating CRC for new content in the FIFO.
172 // Transfer the result from the registers to the result buffer
173 result[0] = PCD_ReadRegister(CRCResultRegL);
174 result[1] = PCD_ReadRegister(CRCResultRegH);
175 return STATUS_OK;
176 }
177 task::yield();
178 } while (static_cast<uint32_t> (task::millis()) < deadline);
179
180 // 89ms passed and nothing happened. Communication with the MFRC522 might be down.
181 return STATUS_TIMEOUT;
182}
183
184
186// Functions for manipulating the MFRC522
188
193 bool hardReset = false;
194
195 // First set the resetPowerDownPin as digital input, to check the MFRC522 power down mode.
196 _reset.gpioMode(GPIO::INPUT);
197
198 if (_reset.gpioRead() == LOW) { // The MFRC522 chip is in power down mode.
199 _reset.gpioMode(GPIO::OUTPUT); // Now set the resetPowerDownPin as digital output.
200 _reset.gpioWrite(LOW); // Make sure we have a clean LOW state.
201 task::sleep_ms(5);
202 _reset.gpioWrite(HIGH); // Exit power down mode. This triggers a hard reset.
203 // Section 8.8.2 in the datasheet says the oscillator start-up time is the start up time of the crystal + 37,74μs. Let us be generous: 50ms.
204 task::sleep_ms(50);
205 hardReset = true;
206 }
207
208 if (!hardReset) { // Perform a soft reset if we haven't triggered a hard reset above.
209 PCD_Reset();
210 }
211
212 // Reset baud rates
213 PCD_WriteRegister(TxModeReg, 0x00);
214 PCD_WriteRegister(RxModeReg, 0x00);
215 // Reset ModWidthReg
216 PCD_WriteRegister(ModWidthReg, 0x26);
217
218 // When communicating with a PICC we need a timeout if something goes wrong.
219 // f_timer = 13.56 MHz / (2*TPreScaler+1) where TPreScaler = [TPrescaler_Hi:TPrescaler_Lo].
220 // TPrescaler_Hi are the four low bits in TModeReg. TPrescaler_Lo is TPrescalerReg.
221 PCD_WriteRegister(TModeReg, 0x80); // TAuto=1; timer starts automatically at the end of the transmission in all communication modes at all speeds
222 PCD_WriteRegister(TPrescalerReg, 0xA9); // TPreScaler = TModeReg[3..0]:TPrescalerReg, ie 0x0A9 = 169 => f_timer=40kHz, ie a timer period of 25μs.
223 PCD_WriteRegister(TReloadRegH, 0x03); // Reload timer with 0x3E8 = 1000, ie 25ms before timeout.
224 PCD_WriteRegister(TReloadRegL, 0xE8);
225
226 PCD_WriteRegister(TxASKReg, 0x40); // Default 0x00. Force a 100 % ASK modulation independent of the ModGsPReg register setting
227 PCD_WriteRegister(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)
228 PCD_AntennaOn(); // Enable the antenna driver pins TX1 and TX2 (they were disabled by the reset)
229}
230
235 PCD_WriteRegister(CommandReg, PCD_SoftReset); // Issue the SoftReset command.
236 // The datasheet does not mention how long the SoftRest command takes to complete.
237 // But the MFRC522 might have been in soft power-down mode (triggered by bit 4 of CommandReg)
238 // Section 8.8.2 in the datasheet says the oscillator start-up time is the start up time of the crystal + 37,74μs. Let us be generous: 50ms.
239 uint8_t count = 0;
240 do {
241 // Wait for the PowerDown bit in CommandReg to be cleared (max 3x50ms)
242 task::sleep_ms(50);
243 } while ((PCD_ReadRegister(CommandReg) & (1 << 4)) && (++count) < 3);
244}
245
251 uint8_t value = PCD_ReadRegister(TxControlReg);
252 if ((value & 0x03) != 0x03) {
253 PCD_WriteRegister(TxControlReg, value | 0x03);
254 }
255}
256
261 PCD_ClearRegisterBitMask(TxControlReg, 0x03);
262}
263
272 return PCD_ReadRegister(RFCfgReg) & (0x07 << 4);
273}
274
281 if (PCD_GetAntennaGain() != mask) { // only bother if there is a change
282 PCD_ClearRegisterBitMask(RFCfgReg, (0x07 << 4)); // clear needed to allow 000 pattern
283 PCD_SetRegisterBitMask(RFCfgReg, mask & (0x07 << 4)); // only set RxGain[2:0] bits
284 }
285}
286
294 // This follows directly the steps outlined in 16.1.1
295 // 1. Perform a soft reset.
296 PCD_Reset();
297
298 // 2. Clear the internal buffer by writing 25 uint8_ts of 00h
299 uint8_t ZEROES[25] = {0x00};
300 PCD_WriteRegister(FIFOLevelReg, 0x80); // flush the FIFO buffer
301 PCD_WriteRegister(FIFODataReg, 25, ZEROES); // write 25 uint8_ts of 00h to FIFO
302 PCD_WriteRegister(CommandReg, PCD_Mem); // transfer to internal buffer
303
304 // 3. Enable self-test
305 PCD_WriteRegister(AutoTestReg, 0x09);
306
307 // 4. Write 00h to FIFO buffer
308 PCD_WriteRegister(FIFODataReg, 0x00);
309
310 // 5. Start self-test by issuing the CalcCRC command
311 PCD_WriteRegister(CommandReg, PCD_CalcCRC);
312
313 // 6. Wait for self-test to complete
314 uint8_t n;
315 for (uint8_t i = 0; i < 0xFF; i++) {
316 // The datasheet does not specify exact completion condition except
317 // that FIFO buffer should contain 64 uint8_ts.
318 // While selftest is initiated by CalcCRC command
319 // it behaves differently from normal CRC computation,
320 // so one can't reliably use DivIrqReg to check for completion.
321 // It is reported that some devices does not trigger CRCIRq flag
322 // during selftest.
323 n = PCD_ReadRegister(FIFOLevelReg);
324 if (n >= 64) {
325 break;
326 }
327 }
328 PCD_WriteRegister(CommandReg, PCD_Idle); // Stop calculating CRC for new content in the FIFO.
329
330 // 7. Read out resulting 64 uint8_ts from the FIFO buffer.
331 uint8_t result[64];
332 PCD_ReadRegister(FIFODataReg, 64, result, 0);
333
334 // Auto self-test done
335 // Reset AutoTestReg register to be 0 again. Required for normal operation.
336 PCD_WriteRegister(AutoTestReg, 0x00);
337
338 // Determine firmware version (see section 9.3.4.8 in spec)
339 uint8_t version = PCD_ReadRegister(VersionReg);
340
341 // Pick the appropriate reference values
342 const uint8_t *reference;
343 switch (version) {
344 case 0x88: // Fudan Semiconductor FM17522 clone
345 reference = FM17522_firmware_reference;
346 break;
347 case 0x90: // Version 0.0
348 reference = MFRC522_firmware_referenceV0_0;
349 break;
350 case 0x91: // Version 1.0
351 reference = MFRC522_firmware_referenceV1_0;
352 break;
353 case 0x92: // Version 2.0
354 reference = MFRC522_firmware_referenceV2_0;
355 break;
356 default: // Unknown version
357 return false; // abort test
358 }
359
360 // Verify that the results match up to our expectations
361 for (uint8_t i = 0; i < 64; i++) {
362 if (result[i] != reference[i]) {
363 return false;
364 }
365 }
366
367 // 8. Perform a re-init, because PCD does not work after test.
368 // Reset does not work as expected.
369 // "Auto self-test done" does not work as expected.
370 PCD_Init();
371
372 // Test passed; all is good.
373 return true;
374}
375
377// Power control
379
380//IMPORTANT NOTE!!!!
381//Calling any other function that uses CommandReg will disable soft power down mode !!!
382//For more details about power control, refer to the datasheet - page 33 (8.6)
383
384void mfrc522_drv::PCD_SoftPowerDown() {//Note : Only soft power down mode is available throught software
385 uint8_t val = PCD_ReadRegister(CommandReg); // Read state of the command register
386 val |= (1 << 4);// set PowerDown bit ( bit 4 ) to 1
387 PCD_WriteRegister(CommandReg, val);//write new value to the command register
388}
389
390void mfrc522_drv::PCD_SoftPowerUp() {
391 uint8_t val = PCD_ReadRegister(CommandReg); // Read state of the command register
392 val &= ~(1 << 4);// set PowerDown bit ( bit 4 ) to 0
393 PCD_WriteRegister(CommandReg, val);//write new value to the command register
394 // wait until PowerDown bit is cleared (this indicates end of wake up procedure)
395 const uint32_t timeout = (uint32_t) task::millis() + 500;// create timer for timeout (just in case)
396
397 while (task::millis() <= timeout) { // set timeout to 500 ms
398 val = PCD_ReadRegister(CommandReg);// Read state of the command register
399 if (!(val & (1 << 4))) { // if powerdown bit is 0
400 break;// wake up procedure is finished
401 }
402 task::yield();
403 }
404}
405
407// Functions for communicating with PICCs
409
416mfrc522_drv::StatusCode
418 uint8_t sendLen,
419 uint8_t *backData,
420 uint8_t *backLen,
421 uint8_t *validBits,
422 uint8_t rxAlign,
423 bool checkCRC
424) {
425 uint8_t waitIRq = 0x30; // RxIRq and IdleIRq
426 return PCD_CommunicateWithPICC(PCD_Transceive, waitIRq, sendData, sendLen, backData, backLen, validBits, rxAlign,
427 checkCRC);
428} // End PCD_TransceiveData()
429
436mfrc522_drv::StatusCode
438 uint8_t waitIRq,
439 uint8_t *sendData,
440 uint8_t sendLen,
441 uint8_t *backData,
442 uint8_t *backLen,
443 uint8_t *validBits,
444 uint8_t rxAlign,
445 bool checkCRC
446) {
447 // Prepare values for BitFramingReg
448 uint8_t txLastBits = validBits ? *validBits : 0;
449 uint8_t bitFraming =
450 (rxAlign << 4) + txLastBits; // RxAlign = BitFramingReg[6..4]. TxLastBits = BitFramingReg[2..0]
451
452 PCD_WriteRegister(CommandReg, PCD_Idle); // Stop any active command.
453 PCD_WriteRegister(ComIrqReg, 0x7F); // Clear all seven interrupt request bits
454 PCD_WriteRegister(FIFOLevelReg, 0x80); // FlushBuffer = 1, FIFO initialization
455 PCD_WriteRegister(FIFODataReg, sendLen, sendData); // Write sendData to the FIFO
456 PCD_WriteRegister(BitFramingReg, bitFraming); // Bit adjustments
457 PCD_WriteRegister(CommandReg, command); // Execute the command
458 if (command == PCD_Transceive) {
459 PCD_SetRegisterBitMask(BitFramingReg, 0x80); // StartSend=1, transmission of data starts
460 }
461
462 // In PCD_Init() we set the TAuto flag in TModeReg. This means the timer
463 // automatically starts when the PCD stops transmitting.
464 //
465 // Wait here for the command to complete. The bits specified in the
466 // `waitIRq` parameter define what bits constitute a completed command.
467 // When they are set in the ComIrqReg register, then the command is
468 // considered complete. If the command is not indicated as complete in
469 // ~36ms, then consider the command as timed out.
470 const uint32_t deadline = task::millis() + 36;
471 bool completed = false;
472
473 do {
474 uint8_t n = PCD_ReadRegister(
475 ComIrqReg); // ComIrqReg[7..0] bits are: Set1 TxIRq RxIRq IdleIRq HiAlertIRq LoAlertIRq ErrIRq TimerIRq
476 if (n & waitIRq) { // One of the interrupts that signal success has been set.
477 completed = true;
478 break;
479 }
480 if (n & 0x01) { // Timer interrupt - nothing received in 25ms
481 return STATUS_TIMEOUT;
482 }
483 task::yield();
484 } while (static_cast<uint32_t> (task::millis()) < deadline);
485
486 // 36ms and nothing happened. Communication with the MFRC522 might be down.
487 if (!completed) {
488 return STATUS_TIMEOUT;
489 }
490
491 // Stop now if any errors except collisions were detected.
492 uint8_t errorRegValue = PCD_ReadRegister(
493 ErrorReg); // ErrorReg[7..0] bits are: WrErr TempErr reserved BufferOvfl CollErr CRCErr ParityErr ProtocolErr
494 if (errorRegValue & 0x13) { // BufferOvfl ParityErr ProtocolErr
495 return STATUS_ERROR;
496 }
497
498 uint8_t _validBits = 0;
499
500 // If the caller wants data back, get it from the MFRC522.
501 if (backData && backLen) {
502 uint8_t n = PCD_ReadRegister(FIFOLevelReg); // Number of uint8_ts in the FIFO
503 if (n > *backLen) {
504 return STATUS_NO_ROOM;
505 }
506 *backLen = n; // Number of uint8_ts returned
507 PCD_ReadRegister(FIFODataReg, n, backData, rxAlign); // Get received data from FIFO
508 _validBits = PCD_ReadRegister(ControlReg) &
509 0x07; // RxLastBits[2:0] indicates the number of valid bits in the last received uint8_t. If this value is 000b, the whole uint8_t is valid.
510 if (validBits) {
511 *validBits = _validBits;
512 }
513 }
514
515 // Tell about collisions
516 if (errorRegValue & 0x08) { // CollErr
517 return STATUS_COLLISION;
518 }
519
520 // Perform CRC_A validation if requested.
521 if (backData && backLen && checkCRC) {
522 // In this case a MIFARE Classic NAK is not OK.
523 if (*backLen == 1 && _validBits == 4) {
524 return STATUS_MIFARE_NACK;
525 }
526 // We need at least the CRC_A value and all 8 bits of the last uint8_t must be received.
527 if (*backLen < 2 || _validBits != 0) {
528 return STATUS_CRC_WRONG;
529 }
530 // Verify CRC_A - do our own calculation and store the control in controlBuffer.
531 uint8_t controlBuffer[2];
532 mfrc522_drv::StatusCode status = PCD_CalculateCRC(&backData[0], *backLen - 2, &controlBuffer[0]);
533 if (status != STATUS_OK) {
534 return status;
535 }
536 if ((backData[*backLen - 2] != controlBuffer[0]) || (backData[*backLen - 1] != controlBuffer[1])) {
537 return STATUS_CRC_WRONG;
538 }
539 }
540
541 return STATUS_OK;
542} // End PCD_CommunicateWithPICC()
543
550mfrc522_drv::StatusCode
551mfrc522_drv::PICC_RequestA(uint8_t *bufferATQA,
552 uint8_t *bufferSize
553) {
554 return PICC_REQA_or_WUPA(PICC_CMD_REQA, bufferATQA, bufferSize);
555} // End PICC_RequestA()
556
563mfrc522_drv::StatusCode
564mfrc522_drv::PICC_WakeupA(uint8_t *bufferATQA,
565 uint8_t *bufferSize
566) {
567 return PICC_REQA_or_WUPA(PICC_CMD_WUPA, bufferATQA, bufferSize);
568} // End PICC_WakeupA()
569
576mfrc522_drv::StatusCode
578 uint8_t *bufferATQA,
579 uint8_t *bufferSize
580) {
581 uint8_t validBits;
582 mfrc522_drv::StatusCode status;
583
584 if (bufferATQA == nullptr || *bufferSize < 2) { // The ATQA response is 2 uint8_ts long.
585 return STATUS_NO_ROOM;
586 }
587 PCD_ClearRegisterBitMask(CollReg, 0x80); // ValuesAfterColl=1 => Bits received after collision are cleared.
588 validBits = 7; // For REQA and WUPA we need the short frame format - transmit only 7 bits of the last (and only) uint8_t. TxLastBits = BitFramingReg[2..0]
589 status = PCD_TransceiveData(&command, 1, bufferATQA, bufferSize, &validBits);
590 if (status != STATUS_OK) {
591 return status;
592 }
593 if (*bufferSize != 2 || validBits != 0) { // ATQA must be exactly 16 bits.
594 return STATUS_ERROR;
595 }
596 return STATUS_OK;
597} // End PICC_REQA_or_WUPA()
598
616mfrc522_drv::StatusCode mfrc522_drv::PICC_Select(
617 Uid *uid,
618 uint8_t validBits
619) {
620 bool uidComplete;
621 bool selectDone;
622 bool useCascadeTag;
623 uint8_t cascadeLevel = 1;
624 mfrc522_drv::StatusCode result;
625 uint8_t count;
626 uint8_t checkBit;
627 uint8_t index;
628 uint8_t uidIndex; // The first index in uid->uidByte[] that is used in the current Cascade Level.
629 int8_t currentLevelKnownBits; // The number of known UID bits in the current Cascade Level.
630 uint8_t buffer[9]; // The SELECT/ANTICOLLISION commands uses a 7 uint8_t standard frame + 2 uint8_ts CRC_A
631 uint8_t bufferUsed; // The number of uint8_ts used in the buffer, ie the number of uint8_ts to transfer to the FIFO.
632 uint8_t rxAlign; // Used in BitFramingReg. Defines the bit position for the first bit received.
633 uint8_t txLastBits; // Used in BitFramingReg. The number of valid bits in the last transmitted uint8_t.
634 uint8_t *responseBuffer;
635 uint8_t responseLength;
636
637 // Description of buffer structure:
638 // Byte 0: SEL Indicates the Cascade Level: PICC_CMD_SEL_CL1, PICC_CMD_SEL_CL2 or PICC_CMD_SEL_CL3
639 // Byte 1: NVB Number of Valid Bits (in complete command, not just the UID): High nibble: complete uint8_ts, Low nibble: Extra bits.
640 // Byte 2: UID-data or CT See explanation below. CT means Cascade Tag.
641 // Byte 3: UID-data
642 // Byte 4: UID-data
643 // Byte 5: UID-data
644 // Byte 6: BCC Block Check Character - XOR of uint8_ts 2-5
645 // Byte 7: CRC_A
646 // Byte 8: CRC_A
647 // The BCC and CRC_A are only transmitted if we know all the UID bits of the current Cascade Level.
648 //
649 // Description of uint8_ts 2-5: (Section 6.5.4 of the ISO/IEC 14443-3 draft: UID contents and cascade levels)
650 // UID size Cascade level Byte2 Byte3 Byte4 Byte5
651 // ======== ============= ===== ===== ===== =====
652 // 4 uint8_ts 1 uid0 uid1 uid2 uid3
653 // 7 uint8_ts 1 CT uid0 uid1 uid2
654 // 2 uid3 uid4 uid5 uid6
655 // 10 uint8_ts 1 CT uid0 uid1 uid2
656 // 2 CT uid3 uid4 uid5
657 // 3 uid6 uid7 uid8 uid9
658
659 // Sanity checks
660 if (validBits > 80) {
661 return STATUS_INVALID;
662 }
663
664 // Prepare MFRC522
665 PCD_ClearRegisterBitMask(CollReg, 0x80); // ValuesAfterColl=1 => Bits received after collision are cleared.
666
667 // Repeat Cascade Level loop until we have a complete UID.
668 uidComplete = false;
669 while (!uidComplete) {
670 // Set the Cascade Level in the SEL uint8_t, find out if we need to use the Cascade Tag in uint8_t 2.
671 switch (cascadeLevel) {
672 case 1:
673 buffer[0] = PICC_CMD_SEL_CL1;
674 uidIndex = 0;
675 useCascadeTag = validBits && uid->size > 4; // When we know that the UID has more than 4 uint8_ts
676 break;
677
678 case 2:
679 buffer[0] = PICC_CMD_SEL_CL2;
680 uidIndex = 3;
681 useCascadeTag = validBits && uid->size > 7; // When we know that the UID has more than 7 uint8_ts
682 break;
683
684 case 3:
685 buffer[0] = PICC_CMD_SEL_CL3;
686 uidIndex = 6;
687 useCascadeTag = false; // Never used in CL3.
688 break;
689
690 default:
691 return STATUS_INTERNAL_ERROR;
692 break;
693 }
694
695 // How many UID bits are known in this Cascade Level?
696 currentLevelKnownBits = validBits - (8 * uidIndex);
697 if (currentLevelKnownBits < 0) {
698 currentLevelKnownBits = 0;
699 }
700 // Copy the known bits from uid->uidByte[] to buffer[]
701 index = 2; // destination index in buffer[]
702 if (useCascadeTag) {
703 buffer[index++] = PICC_CMD_CT;
704 }
705 uint8_t uint8_tsToCopy = currentLevelKnownBits / 8 + (currentLevelKnownBits % 8 ? 1
706 : 0); // The number of uint8_ts needed to represent the known bits for this level.
707 if (uint8_tsToCopy) {
708 uint8_t maxBytes = useCascadeTag ? 3
709 : 4; // Max 4 uint8_ts in each Cascade Level. Only 3 left if we use the Cascade Tag
710 if (uint8_tsToCopy > maxBytes) {
711 uint8_tsToCopy = maxBytes;
712 }
713 for (count = 0; count < uint8_tsToCopy; count++) {
714 buffer[index++] = uid->uidByte[uidIndex + count];
715 }
716 }
717 // Now that the data has been copied we need to include the 8 bits in CT in currentLevelKnownBits
718 if (useCascadeTag) {
719 currentLevelKnownBits += 8;
720 }
721
722 // Repeat anti collision loop until we can transmit all UID bits + BCC and receive a SAK - max 32 iterations.
723 selectDone = false;
724 while (!selectDone) {
725 // Find out how many bits and uint8_ts to send and receive.
726 if (currentLevelKnownBits >= 32) { // All UID bits in this Cascade Level are known. This is a SELECT.
727 //Serial.print(F("SELECT: currentLevelKnownBits=")); Serial.println(currentLevelKnownBits, DEC);
728 buffer[1] = 0x70; // NVB - Number of Valid Bits: Seven whole uint8_ts
729 // Calculate BCC - Block Check Character
730 buffer[6] = buffer[2] ^ buffer[3] ^ buffer[4] ^ buffer[5];
731 // Calculate CRC_A
732 result = PCD_CalculateCRC(buffer, 7, &buffer[7]);
733 if (result != STATUS_OK) {
734 return result;
735 }
736 txLastBits = 0; // 0 => All 8 bits are valid.
737 bufferUsed = 9;
738 // Store response in the last 3 uint8_ts of buffer (BCC and CRC_A - not needed after tx)
739 responseBuffer = &buffer[6];
740 responseLength = 3;
741 } else { // This is an ANTICOLLISION.
742 //Serial.print(F("ANTICOLLISION: currentLevelKnownBits=")); Serial.println(currentLevelKnownBits, DEC);
743 txLastBits = currentLevelKnownBits % 8;
744 count = currentLevelKnownBits / 8; // Number of whole uint8_ts in the UID part.
745 index = 2 + count; // Number of whole uint8_ts: SEL + NVB + UIDs
746 buffer[1] = (index << 4) + txLastBits; // NVB - Number of Valid Bits
747 bufferUsed = index + (txLastBits ? 1 : 0);
748 // Store response in the unused part of buffer
749 responseBuffer = &buffer[index];
750 responseLength = sizeof(buffer) - index;
751 }
752
753 // Set bit adjustments
754 rxAlign = txLastBits; // Having a separate variable is overkill. But it makes the next line easier to read.
755 PCD_WriteRegister(BitFramingReg, (rxAlign << 4) +
756 txLastBits); // RxAlign = BitFramingReg[6..4]. TxLastBits = BitFramingReg[2..0]
757
758 // Transmit the buffer and receive the response.
759 result = PCD_TransceiveData(buffer, bufferUsed, responseBuffer, &responseLength, &txLastBits, rxAlign);
760 if (result == STATUS_COLLISION) { // More than one PICC in the field => collision.
761 uint8_t valueOfCollReg = PCD_ReadRegister(
762 CollReg); // CollReg[7..0] bits are: ValuesAfterColl reserved CollPosNotValid CollPos[4:0]
763 if (valueOfCollReg & 0x20) { // CollPosNotValid
764 return STATUS_COLLISION; // Without a valid collision position we cannot continue
765 }
766 uint8_t collisionPos = valueOfCollReg & 0x1F; // Values 0-31, 0 means bit 32.
767 if (collisionPos == 0) {
768 collisionPos = 32;
769 }
770 if (collisionPos <= currentLevelKnownBits) { // No progress - should not happen
771 return STATUS_INTERNAL_ERROR;
772 }
773 // Choose the PICC with the bit set.
774 currentLevelKnownBits = collisionPos;
775 count = currentLevelKnownBits % 8; // The bit to modify
776 checkBit = (currentLevelKnownBits - 1) % 8;
777 index = 1 + (currentLevelKnownBits / 8) + (count ? 1 : 0); // First uint8_t is index 0.
778 buffer[index] |= (1 << checkBit);
779 } else if (result != STATUS_OK) {
780 return result;
781 } else { // STATUS_OK
782 if (currentLevelKnownBits >= 32) { // This was a SELECT.
783 selectDone = true; // No more anticollision
784 // We continue below outside the while.
785 } else { // This was an ANTICOLLISION.
786 // We now have all 32 bits of the UID in this Cascade Level
787 currentLevelKnownBits = 32;
788 // Run loop again to do the SELECT.
789 }
790 }
791 } // End of while (!selectDone)
792
793 // We do not check the CBB - it was constructed by us above.
794
795 // Copy the found UID uint8_ts from buffer[] to uid->uidByte[]
796 index = (buffer[2] == PICC_CMD_CT) ? 3 : 2; // source index in buffer[]
797 uint8_tsToCopy = (buffer[2] == PICC_CMD_CT) ? 3 : 4;
798 for (count = 0; count < uint8_tsToCopy; count++) {
799 uid->uidByte[uidIndex + count] = buffer[index++];
800 }
801
802 // Check response SAK (Select Acknowledge)
803 if (responseLength != 3 || txLastBits != 0) { // SAK must be exactly 24 bits (1 uint8_t + CRC_A).
804 return STATUS_ERROR;
805 }
806 // Verify CRC_A - do our own calculation and store the control in buffer[2..3] - those uint8_ts are not needed anymore.
807 result = PCD_CalculateCRC(responseBuffer, 1, &buffer[2]);
808 if (result != STATUS_OK) {
809 return result;
810 }
811 if ((buffer[2] != responseBuffer[1]) || (buffer[3] != responseBuffer[2])) {
812 return STATUS_CRC_WRONG;
813 }
814 if (responseBuffer[0] & 0x04) { // Cascade bit set - UID not complete yes
815 cascadeLevel++;
816 } else {
817 uidComplete = true;
818 uid->sak = responseBuffer[0];
819 }
820 } // End of while (!uidComplete)
821
822 // Set correct uid->size
823 uid->size = 3 * cascadeLevel + 1;
824
825 return STATUS_OK;
826} // End PICC_Select()
827
833mfrc522_drv::StatusCode mfrc522_drv::PICC_HaltA() {
834 mfrc522_drv::StatusCode result;
835 uint8_t buffer[4];
836
837 // Build command buffer
838 buffer[0] = PICC_CMD_HLTA;
839 buffer[1] = 0;
840 // Calculate CRC_A
841 result = PCD_CalculateCRC(buffer, 2, &buffer[2]);
842 if (result != STATUS_OK) {
843 return result;
844 }
845
846 // Send the command.
847 // The standard says:
848 // If the PICC responds with any modulation during a period of 1 ms after the end of the frame containing the
849 // HLTA command, this response shall be interpreted as 'not acknowledge'.
850 // We interpret that this way: Only STATUS_TIMEOUT is a success.
851 result = PCD_TransceiveData(buffer, sizeof(buffer), nullptr, 0);
852 if (result == STATUS_TIMEOUT) {
853 return STATUS_OK;
854 }
855 if (result == STATUS_OK) { // That is ironically NOT ok in this case ;-)
856 return STATUS_ERROR;
857 }
858 return result;
859} // End PICC_HaltA()
860
862// Functions for communicating with MIFARE PICCs
864
877mfrc522_drv::StatusCode
879 uint8_t blockAddr,
880 MIFARE_Key *key,
881 Uid *uid
882) {
883 uint8_t waitIRq = 0x10; // IdleIRq
884
885 // Build command buffer
886 uint8_t sendData[12];
887 sendData[0] = command;
888 sendData[1] = blockAddr;
889 for (uint8_t i = 0; i < MF_KEY_SIZE; i++) { // 6 key uint8_ts
890 sendData[2 + i] = key->keyByte[i];
891 }
892 // Use the last uid uint8_ts as specified in http://cache.nxp.com/documents/application_note/AN10927.pdf
893 // section 3.2.5 "MIFARE Classic Authentication".
894 // The only missed case is the MF1Sxxxx shortcut activation,
895 // but it requires cascade tag (CT) uint8_t, that is not part of uid.
896 for (uint8_t i = 0; i < 4; i++) { // The last 4 uint8_ts of the UID
897 sendData[8 + i] = uid->uidByte[i + uid->size - 4];
898 }
899
900 // Start the authentication.
901 return PCD_CommunicateWithPICC(PCD_MFAuthent, waitIRq, &sendData[0], sizeof(sendData));
902} // End PCD_Authenticate()
903
909 // Clear MFCrypto1On bit
910 PCD_ClearRegisterBitMask(Status2Reg,
911 0x08); // Status2Reg[7..0] bits are: TempSensClear I2CForceHS reserved reserved MFCrypto1On ModemState[2:0]
912} // End PCD_StopCrypto1()
913
930mfrc522_drv::StatusCode mfrc522_drv::MIFARE_Read(
931 uint8_t blockAddr,
932 uint8_t *buffer,
933 uint8_t *bufferSize
934) {
935 mfrc522_drv::StatusCode result;
936
937 // Sanity check
938 if (buffer == nullptr || *bufferSize < 18) {
939 return STATUS_NO_ROOM;
940 }
941
942 // Build command buffer
943 buffer[0] = PICC_CMD_MF_READ;
944 buffer[1] = blockAddr;
945 // Calculate CRC_A
946 result = PCD_CalculateCRC(buffer, 2, &buffer[2]);
947 if (result != STATUS_OK) {
948 return result;
949 }
950
951 // Transmit the buffer and receive the response, validate CRC_A.
952 return PCD_TransceiveData(buffer, 4, buffer, bufferSize, nullptr, 0, true);
953} // End MIFARE_Read()
954
966mfrc522_drv::StatusCode mfrc522_drv::MIFARE_Write(
967 uint8_t blockAddr,
968 uint8_t *buffer,
969 uint8_t bufferSize
970) {
971 mfrc522_drv::StatusCode result;
972
973 // Sanity check
974 if (buffer == nullptr || bufferSize < 16) {
975 return STATUS_INVALID;
976 }
977
978 // Mifare Classic protocol requires two communications to perform a write.
979 // Step 1: Tell the PICC we want to write to block blockAddr.
980 uint8_t cmdBuffer[2];
981 cmdBuffer[0] = PICC_CMD_MF_WRITE;
982 cmdBuffer[1] = blockAddr;
983 result = PCD_MIFARE_Transceive(cmdBuffer, 2); // Adds CRC_A and checks that the response is MF_ACK.
984 if (result != STATUS_OK) {
985 return result;
986 }
987
988 // Step 2: Transfer the data
989 result = PCD_MIFARE_Transceive(buffer, bufferSize); // Adds CRC_A and checks that the response is MF_ACK.
990 if (result != STATUS_OK) {
991 return result;
992 }
993
994 return STATUS_OK;
995} // End MIFARE_Write()
996
1002mfrc522_drv::StatusCode mfrc522_drv::MIFARE_Ultralight_Write(uint8_t page,
1003 uint8_t *buffer,
1004 uint8_t bufferSize
1005) {
1006 mfrc522_drv::StatusCode result;
1007
1008 // Sanity check
1009 if (buffer == nullptr || bufferSize < 4) {
1010 return STATUS_INVALID;
1011 }
1012
1013 // Build commmand buffer
1014 uint8_t cmdBuffer[6];
1015 cmdBuffer[0] = PICC_CMD_UL_WRITE;
1016 cmdBuffer[1] = page;
1017 memcpy(&cmdBuffer[2], buffer, 4);
1018
1019 // Perform the write
1020 result = PCD_MIFARE_Transceive(cmdBuffer, 6); // Adds CRC_A and checks that the response is MF_ACK.
1021 if (result != STATUS_OK) {
1022 return result;
1023 }
1024 return STATUS_OK;
1025} // End MIFARE_Ultralight_Write()
1026
1035mfrc522_drv::StatusCode mfrc522_drv::MIFARE_Decrement(uint8_t blockAddr,
1036 int32_t delta
1037) {
1038 return MIFARE_TwoStepHelper(PICC_CMD_MF_DECREMENT, blockAddr, delta);
1039} // End MIFARE_Decrement()
1040
1049mfrc522_drv::StatusCode mfrc522_drv::MIFARE_Increment(uint8_t blockAddr,
1050 int32_t delta
1051) {
1052 return MIFARE_TwoStepHelper(PICC_CMD_MF_INCREMENT, blockAddr, delta);
1053} // End MIFARE_Increment()
1054
1063mfrc522_drv::StatusCode mfrc522_drv::MIFARE_Restore(uint8_t blockAddr
1064) {
1065 // The datasheet describes Restore as a two step operation, but does not explain what data to transfer in step 2.
1066 // Doing only a single step does not work, so I chose to transfer 0L in step two.
1067 return MIFARE_TwoStepHelper(PICC_CMD_MF_RESTORE, blockAddr, 0L);
1068} // End MIFARE_Restore()
1069
1075mfrc522_drv::StatusCode mfrc522_drv::MIFARE_TwoStepHelper(uint8_t command,
1076 uint8_t blockAddr,
1077 int32_t data
1078) {
1079 mfrc522_drv::StatusCode result;
1080 uint8_t cmdBuffer[2]; // We only need room for 2 uint8_ts.
1081
1082 // Step 1: Tell the PICC the command and block address
1083 cmdBuffer[0] = command;
1084 cmdBuffer[1] = blockAddr;
1085 result = PCD_MIFARE_Transceive(cmdBuffer, 2); // Adds CRC_A and checks that the response is MF_ACK.
1086 if (result != STATUS_OK) {
1087 return result;
1088 }
1089
1090 // Step 2: Transfer the data
1091 result = PCD_MIFARE_Transceive((uint8_t *) &data, 4, true); // Adds CRC_A and accept timeout as success.
1092 if (result != STATUS_OK) {
1093 return result;
1094 }
1095
1096 return STATUS_OK;
1097} // End MIFARE_TwoStepHelper()
1098
1106mfrc522_drv::StatusCode mfrc522_drv::MIFARE_Transfer(uint8_t blockAddr
1107) {
1108 mfrc522_drv::StatusCode result;
1109 uint8_t cmdBuffer[2]; // We only need room for 2 uint8_ts.
1110
1111 // Tell the PICC we want to transfer the result into block blockAddr.
1112 cmdBuffer[0] = PICC_CMD_MF_TRANSFER;
1113 cmdBuffer[1] = blockAddr;
1114 result = PCD_MIFARE_Transceive(cmdBuffer, 2); // Adds CRC_A and checks that the response is MF_ACK.
1115 if (result != STATUS_OK) {
1116 return result;
1117 }
1118 return STATUS_OK;
1119} // End MIFARE_Transfer()
1120
1132mfrc522_drv::StatusCode mfrc522_drv::MIFARE_GetValue(uint8_t blockAddr, int32_t *value) {
1133 mfrc522_drv::StatusCode status;
1134 uint8_t buffer[18];
1135 uint8_t size = sizeof(buffer);
1136
1137 // Read the block
1138 status = MIFARE_Read(blockAddr, buffer, &size);
1139 if (status == STATUS_OK) {
1140 // Extract the value
1141 *value = (int32_t(buffer[3]) << 24) | (int32_t(buffer[2]) << 16) | (int32_t(buffer[1]) << 8) |
1142 int32_t(buffer[0]);
1143 }
1144 return status;
1145} // End MIFARE_GetValue()
1146
1158mfrc522_drv::StatusCode mfrc522_drv::MIFARE_SetValue(uint8_t blockAddr, int32_t value) {
1159 uint8_t buffer[18];
1160
1161 // Translate the int32_t into 4 uint8_ts; repeated 2x in value block
1162 buffer[0] = buffer[8] = (value & 0xFF);
1163 buffer[1] = buffer[9] = (value & 0xFF00) >> 8;
1164 buffer[2] = buffer[10] = (value & 0xFF0000) >> 16;
1165 buffer[3] = buffer[11] = (value & 0xFF000000) >> 24;
1166 // Inverse 4 uint8_ts also found in value block
1167 buffer[4] = ~buffer[0];
1168 buffer[5] = ~buffer[1];
1169 buffer[6] = ~buffer[2];
1170 buffer[7] = ~buffer[3];
1171 // Address 2x with inverse address 2x
1172 buffer[12] = buffer[14] = blockAddr;
1173 buffer[13] = buffer[15] = ~blockAddr;
1174
1175 // Write the whole data block
1176 return MIFARE_Write(blockAddr, buffer, 16);
1177} // End MIFARE_SetValue()
1178
1188mfrc522_drv::StatusCode mfrc522_drv::PCD_NTAG216_AUTH(uint8_t *passWord, uint8_t pACK[]) //Authenticate with 32bit password
1189{
1190 // TODO: Fix cmdBuffer length and rxlength. They really should match.
1191 // (Better still, rxlength should not even be necessary.)
1192
1193 mfrc522_drv::StatusCode result;
1194 uint8_t cmdBuffer[18]; // We need room for 16 uint8_ts data and 2 uint8_ts CRC_A.
1195
1196 cmdBuffer[0] = 0x1B; //Comando de autentificacion
1197
1198 for (uint8_t i = 0; i < 4; i++)
1199 cmdBuffer[i + 1] = passWord[i];
1200
1201 result = PCD_CalculateCRC(cmdBuffer, 5, &cmdBuffer[5]);
1202
1203 if (result != STATUS_OK) {
1204 return result;
1205 }
1206
1207 // Transceive the data, store the reply in cmdBuffer[]
1208 uint8_t waitIRq = 0x30; // RxIRq and IdleIRq
1209// uint8_t cmdBufferSize = sizeof(cmdBuffer);
1210 uint8_t validBits = 0;
1211 uint8_t rxlength = 5;
1212 result = PCD_CommunicateWithPICC(PCD_Transceive, waitIRq, cmdBuffer, 7, cmdBuffer, &rxlength, &validBits);
1213
1214 pACK[0] = cmdBuffer[0];
1215 pACK[1] = cmdBuffer[1];
1216
1217 if (result != STATUS_OK) {
1218 return result;
1219 }
1220
1221 return STATUS_OK;
1222} // End PCD_NTAG216_AUTH()
1223
1224
1226// Support functions
1228
1236 uint8_t *sendData,
1237 uint8_t sendLen,
1238 bool acceptTimeout
1239) {
1240 mfrc522_drv::StatusCode result;
1241 uint8_t cmdBuffer[18]; // We need room for 16 uint8_ts data and 2 uint8_ts CRC_A.
1242
1243 // Sanity check
1244 if (sendData == nullptr || sendLen > 16) {
1245 return STATUS_INVALID;
1246 }
1247
1248 // Copy sendData[] to cmdBuffer[] and add CRC_A
1249 memcpy(cmdBuffer, sendData, sendLen);
1250 result = PCD_CalculateCRC(cmdBuffer, sendLen, &cmdBuffer[sendLen]);
1251 if (result != STATUS_OK) {
1252 return result;
1253 }
1254 sendLen += 2;
1255
1256 // Transceive the data, store the reply in cmdBuffer[]
1257 uint8_t waitIRq = 0x30; // RxIRq and IdleIRq
1258 uint8_t cmdBufferSize = sizeof(cmdBuffer);
1259 uint8_t validBits = 0;
1260 result = PCD_CommunicateWithPICC(PCD_Transceive, waitIRq, cmdBuffer, sendLen, cmdBuffer, &cmdBufferSize,
1261 &validBits);
1262 if (acceptTimeout && result == STATUS_TIMEOUT) {
1263 return STATUS_OK;
1264 }
1265 if (result != STATUS_OK) {
1266 return result;
1267 }
1268 // The PICC must reply with a 4 bit ACK
1269 if (cmdBufferSize != 1 || validBits != 4) {
1270 return STATUS_ERROR;
1271 }
1272 if (cmdBuffer[0] != MF_ACK) {
1273 return STATUS_MIFARE_NACK;
1274 }
1275 return STATUS_OK;
1276} // End PCD_MIFARE_Transceive()
1277
1283const char *mfrc522_drv::GetStatusCodeName(mfrc522_drv::StatusCode code
1284) {
1285 switch (code) {
1286 case STATUS_OK:
1287 return ("Success.");
1288 case STATUS_ERROR:
1289 return ("Error in communication.");
1290 case STATUS_COLLISION:
1291 return ("Collision detected.");
1292 case STATUS_TIMEOUT:
1293 return ("Timeout in communication.");
1294 case STATUS_NO_ROOM:
1295 return ("A buffer is not big enough.");
1296 case STATUS_INTERNAL_ERROR:
1297 return ("Internal error in the code. Should not happen.");
1298 case STATUS_INVALID:
1299 return ("Invalid argument.");
1300 case STATUS_CRC_WRONG:
1301 return ("The CRC_A does not match.");
1302 case STATUS_MIFARE_NACK:
1303 return ("A MIFARE PICC responded with NAK.");
1304 default:
1305 return ("Unknown error");
1306 }
1307} // End GetStatusCodeName()
1308
1314mfrc522_drv::PICC_Type mfrc522_drv::PICC_GetType(uint8_t sak
1315) {
1316 // http://www.nxp.com/documents/application_note/AN10833.pdf
1317 // 3.2 Coding of Select Acknowledge (SAK)
1318 // ignore 8-bit (iso14443 starts with LSBit = bit 1)
1319 // fixes wrong type for manufacturer Infineon (http://nfc-tools.org/index.php?title=ISO14443A)
1320 sak &= 0x7F;
1321 switch (sak) {
1322 case 0x04:
1323 return PICC_TYPE_NOT_COMPLETE; // UID not complete
1324 case 0x09:
1325 return PICC_TYPE_MIFARE_MINI;
1326 case 0x08:
1327 return PICC_TYPE_MIFARE_1K;
1328 case 0x18:
1329 return PICC_TYPE_MIFARE_4K;
1330 case 0x00:
1331 return PICC_TYPE_MIFARE_UL;
1332 case 0x10:
1333 case 0x11:
1334 return PICC_TYPE_MIFARE_PLUS;
1335 case 0x01:
1336 return PICC_TYPE_TNP3XXX;
1337 case 0x20:
1338 return PICC_TYPE_ISO_14443_4;
1339 case 0x40:
1340 return PICC_TYPE_ISO_18092;
1341 default:
1342 return PICC_TYPE_UNKNOWN;
1343 }
1344} // End PICC_GetType()
1345
1351const char *mfrc522_drv::PICC_GetTypeName(PICC_Type piccType
1352) {
1353 switch (piccType) {
1354 case PICC_TYPE_ISO_14443_4:
1355 return ("PICC compliant with ISO/IEC 14443-4");
1356 case PICC_TYPE_ISO_18092:
1357 return ("PICC compliant with ISO/IEC 18092 (NFC)");
1358 case PICC_TYPE_MIFARE_MINI:
1359 return ("MIFARE Mini, 320 uint8_ts");
1360 case PICC_TYPE_MIFARE_1K:
1361 return ("MIFARE 1KB");
1362 case PICC_TYPE_MIFARE_4K:
1363 return ("MIFARE 4KB");
1364 case PICC_TYPE_MIFARE_UL:
1365 return ("MIFARE Ultralight or Ultralight C");
1366 case PICC_TYPE_MIFARE_PLUS:
1367 return ("MIFARE Plus");
1368 case PICC_TYPE_MIFARE_DESFIRE:
1369 return ("MIFARE DESFire");
1370 case PICC_TYPE_TNP3XXX:
1371 return ("MIFARE TNP3XXX");
1372 case PICC_TYPE_NOT_COMPLETE:
1373 return ("SAK indicates UID is not complete.");
1374 case PICC_TYPE_UNKNOWN:
1375 default:
1376 return ("Unknown type");
1377 }
1378} // End PICC_GetTypeName()
1379
1385 // Get the MFRC522 firmware version
1386 uint8_t v = PCD_ReadRegister(VersionReg);
1387 printf("Firmware Version: 0x");
1388 printf("%x", v);
1389 // Lookup which version
1390 switch (v) {
1391 case 0x88:
1392 printf(" = (clone)\n");
1393 break;
1394 case 0x90:
1395 printf((" = v0.0\n"));
1396 break;
1397 case 0x91:
1398 printf((" = v1.0\n"));
1399 break;
1400 case 0x92:
1401 printf((" = v2.0\n"));
1402 break;
1403 case 0x12:
1404 printf(" = counterfeit chip\n");
1405 break;
1406 default:
1407 printf(" = (unknown)\n");
1408 }
1409 // When 0x00 or 0xFF is returned, communication probably failed
1410 if ((v == 0x00) || (v == 0xFF))
1411 printf("WARNING: Communication failure, is the MFRC522 properly connected?\n");
1412} // End PCD_DumpVersionToSerial()
1413
1420) {
1421 MIFARE_Key key;
1422
1423 // Dump UID, SAK and Type
1425
1426 // Dump contents
1427 PICC_Type piccType = PICC_GetType(uid->sak);
1428 switch (piccType) {
1429 case PICC_TYPE_MIFARE_MINI:
1430 case PICC_TYPE_MIFARE_1K:
1431 case PICC_TYPE_MIFARE_4K:
1432 // All keys are set to FFFFFFFFFFFFh at chip delivery from the factory.
1433 for (uint8_t i = 0; i < 6; i++) {
1434 key.keyByte[i] = 0xFF;
1435 }
1436 PICC_DumpMifareClassicToSerial(uid, piccType, &key);
1437 break;
1438
1439 case PICC_TYPE_MIFARE_UL:
1441 break;
1442
1443 case PICC_TYPE_ISO_14443_4:
1444 case PICC_TYPE_MIFARE_DESFIRE:
1445 case PICC_TYPE_ISO_18092:
1446 case PICC_TYPE_MIFARE_PLUS:
1447 case PICC_TYPE_TNP3XXX:
1448 printf("Dumping memory contents not implemented for that PICC type.\n");
1449 break;
1450
1451 case PICC_TYPE_UNKNOWN:
1452 case PICC_TYPE_NOT_COMPLETE:
1453 default:
1454 break; // No memory dump here
1455 }
1456
1457 printf("\n");
1458 PICC_HaltA(); // Already done if it was a MIFARE Classic PICC.
1459} // End PICC_DumpToSerial()
1460
1465 // UID
1466 printf("Card UID:");
1467 for (uint8_t i = 0; i < uid->size; i++) {
1468 if (uid->uidByte[i] < 0x10)
1469 printf(" 0");
1470 else
1471 printf(" ");
1472 printf("%x", uid->uidByte[i]);
1473 }
1474 printf("\n");
1475
1476 // SAK
1477 printf("Card SAK: ");
1478 if (uid->sak < 0x10)
1479 printf("0");
1480 printf("%x\n", uid->sak);
1481
1482 // (suggested) PICC type
1483 PICC_Type piccType = PICC_GetType(uid->sak);
1484 printf("PICC type: ");
1485 printf(PICC_GetTypeName(piccType));
1486 printf("\n");
1487} // End PICC_DumpDetailsToSerial()
1488
1494 Uid *uid,
1495 PICC_Type piccType,
1496 MIFARE_Key *key
1497) {
1498 uint8_t no_of_sectors = 0;
1499 switch (piccType) {
1500 case PICC_TYPE_MIFARE_MINI:
1501 // Has 5 sectors * 4 blocks/sector * 16 uint8_ts/block = 320 uint8_ts.
1502 no_of_sectors = 5;
1503 break;
1504
1505 case PICC_TYPE_MIFARE_1K:
1506 // Has 16 sectors * 4 blocks/sector * 16 uint8_ts/block = 1024 uint8_ts.
1507 no_of_sectors = 16;
1508 break;
1509
1510 case PICC_TYPE_MIFARE_4K:
1511 // Has (32 sectors * 4 blocks/sector + 8 sectors * 16 blocks/sector) * 16 uint8_ts/block = 4096 uint8_ts.
1512 no_of_sectors = 40;
1513 break;
1514
1515 default: // Should not happen. Ignore.
1516 break;
1517 }
1518
1519 // Dump sectors, highest address first.
1520 if (no_of_sectors) {
1521 printf("Sector Block 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 AccessBits\n");
1522 for (int8_t i = no_of_sectors - 1; i >= 0; i--) {
1524 }
1525 }
1526 PICC_HaltA(); // Halt the PICC before stopping the encrypted session.
1528} // End PICC_DumpMifareClassicToSerial()
1529
1536 Uid *uid,
1537 MIFARE_Key *key,
1538 uint8_t sector
1539) {
1540 mfrc522_drv::StatusCode status;
1541 uint8_t firstBlock; // Address of lowest address to dump actually last block dumped)
1542 uint8_t no_of_blocks; // Number of blocks in sector
1543 bool isSectorTrailer; // Set to true while handling the "last" (ie highest address) in the sector.
1544
1545 // The access bits are stored in a peculiar fashion.
1546 // There are four groups:
1547 // g[3] Access bits for the sector trailer, block 3 (for sectors 0-31) or block 15 (for sectors 32-39)
1548 // g[2] Access bits for block 2 (for sectors 0-31) or blocks 10-14 (for sectors 32-39)
1549 // g[1] Access bits for block 1 (for sectors 0-31) or blocks 5-9 (for sectors 32-39)
1550 // g[0] Access bits for block 0 (for sectors 0-31) or blocks 0-4 (for sectors 32-39)
1551 // Each group has access bits [C1 C2 C3]. In this code C1 is MSB and C3 is LSB.
1552 // The four CX bits are stored together in a nible cx and an inverted nible cx_.
1553 uint8_t c1, c2, c3; // Nibbles
1554 uint8_t c1_, c2_, c3_; // Inverted nibbles
1555 bool invertedError; // True if one of the inverted nibbles did not match
1556 uint8_t g[4]; // Access bits for each of the four groups.
1557 uint8_t group; // 0-3 - active group for access bits
1558 bool firstInGroup; // True for the first block dumped in the group
1559
1560 // Determine position and size of sector.
1561 if (sector < 32) { // Sectors 0..31 has 4 blocks each
1562 no_of_blocks = 4;
1563 firstBlock = sector * no_of_blocks;
1564 } else if (sector < 40) { // Sectors 32-39 has 16 blocks each
1565 no_of_blocks = 16;
1566 firstBlock = 128 + (sector - 32) * no_of_blocks;
1567 } else { // Illegal input, no MIFARE Classic PICC has more than 40 sectors.
1568 return;
1569 }
1570
1571 // Dump blocks, highest address first.
1572 uint8_t uint8_tCount;
1573 uint8_t buffer[18];
1574 uint8_t blockAddr;
1575 isSectorTrailer = true;
1576 invertedError = false; // Avoid "unused variable" warning.
1577 for (int8_t blockOffset = no_of_blocks - 1; blockOffset >= 0; blockOffset--) {
1578 blockAddr = firstBlock + blockOffset;
1579 // Sector number - only on first line
1580 if (isSectorTrailer) {
1581 if (sector < 10)
1582 printf(" "); // Pad with spaces
1583 else
1584 printf(" "); // Pad with spaces
1585 printf("%d", sector);
1586 printf(" ");
1587 } else {
1588 printf(" ");
1589 }
1590 // Block number
1591 if (blockAddr < 10)
1592 printf(" "); // Pad with spaces
1593 else {
1594 if (blockAddr < 100)
1595 printf(" "); // Pad with spaces
1596 else
1597 printf(" "); // Pad with spaces
1598 }
1599 printf("%d", blockAddr);
1600 printf(" ");
1601 // Establish encrypted communications before reading the first block
1602 if (isSectorTrailer) {
1603 status = PCD_Authenticate(PICC_CMD_MF_AUTH_KEY_A, firstBlock, key, uid);
1604 if (status != STATUS_OK) {
1605 printf("PCD_Authenticate() failed: ");
1606 printf(GetStatusCodeName(status));
1607 printf("\n");
1608 return;
1609 }
1610 }
1611 // Read block
1612 uint8_tCount = sizeof(buffer);
1613 status = MIFARE_Read(blockAddr, buffer, &uint8_tCount);
1614 if (status != STATUS_OK) {
1615 printf("MIFARE_Read() failed: ");
1616 printf(GetStatusCodeName(status));
1617 printf("\n");
1618 continue;
1619 }
1620 // Dump data
1621 for (uint8_t index = 0; index < 16; index++) {
1622 if (buffer[index] < 0x10)
1623 printf(" 0");
1624 else
1625 printf(" ");
1626 printf("%x", buffer[index]);
1627 if ((index % 4) == 3) {
1628 printf(" ");
1629 }
1630 }
1631 // Parse sector trailer data
1632 if (isSectorTrailer) {
1633 c1 = buffer[7] >> 4;
1634 c2 = buffer[8] & 0xF;
1635 c3 = buffer[8] >> 4;
1636 c1_ = buffer[6] & 0xF;
1637 c2_ = buffer[6] >> 4;
1638 c3_ = buffer[7] & 0xF;
1639 invertedError = (c1 != (~c1_ & 0xF)) || (c2 != (~c2_ & 0xF)) || (c3 != (~c3_ & 0xF));
1640 g[0] = ((c1 & 1) << 2) | ((c2 & 1) << 1) | ((c3 & 1) << 0);
1641 g[1] = ((c1 & 2) << 1) | ((c2 & 2) << 0) | ((c3 & 2) >> 1);
1642 g[2] = ((c1 & 4) << 0) | ((c2 & 4) >> 1) | ((c3 & 4) >> 2);
1643 g[3] = ((c1 & 8) >> 1) | ((c2 & 8) >> 2) | ((c3 & 8) >> 3);
1644 isSectorTrailer = false;
1645 }
1646
1647 // Which access group is this block in?
1648 if (no_of_blocks == 4) {
1649 group = blockOffset;
1650 firstInGroup = true;
1651 } else {
1652 group = blockOffset / 5;
1653 firstInGroup = (group == 3) || (group != (blockOffset + 1) / 5);
1654 }
1655
1656 if (firstInGroup) {
1657 // Print access bits
1658 printf(" [ ");
1659 printf("%d", (g[group] >> 2) & 1);
1660 printf(" ");
1661 printf("%d", (g[group] >> 1) & 1);
1662 printf(" ");
1663 printf("%d", (g[group] >> 0) & 1);
1664 printf(" ] ");
1665 if (invertedError) {
1666 printf(" Inverted access bits did not match! ");
1667 }
1668 }
1669
1670 if (group != 3 && (g[group] == 1 || g[group] == 6)) { // Not a sector trailer, a value block
1671 int32_t value = (int32_t(buffer[3]) << 24) | (int32_t(buffer[2]) << 16) | (int32_t(buffer[1]) << 8) |
1672 int32_t(buffer[0]);
1673 printf(" Value=0x");
1674 printf("%lx", value);
1675 printf(" Adr=0x");
1676 printf("%x", buffer[12]);
1677 }
1678 printf("\n");
1679 }
1680 return;
1681} // End PICC_DumpMifareClassicSectorToSerial()
1682
1687 mfrc522_drv::StatusCode status;
1688 uint8_t uint8_tCount;
1689 uint8_t buffer[18];
1690 uint8_t i;
1691
1692 printf("Page 0 1 2 3");
1693 // Try the mpages of the original Ultralight. Ultralight C has more pages.
1694 for (uint8_t page = 0; page < 16; page += 4) { // Read returns data for 4 pages at a time.
1695 // Read pages
1696 uint8_tCount = sizeof(buffer);
1697 status = MIFARE_Read(page, buffer, &uint8_tCount);
1698 if (status != STATUS_OK) {
1699 printf("MIFARE_Read() failed: ");
1700 printf(GetStatusCodeName(status));
1701 break;
1702 }
1703 // Dump data
1704 for (uint8_t offset = 0; offset < 4; offset++) {
1705 i = page + offset;
1706 if (i < 10)
1707 printf(" "); // Pad with spaces
1708 else
1709 printf(" "); // Pad with spaces
1710 printf("%d",i);
1711 printf(" ");
1712 for (uint8_t index = 0; index < 4; index++) {
1713 i = 4 * offset + index;
1714 if (buffer[i] < 0x10)
1715 printf(" 0");
1716 else
1717 printf(" ");
1718 printf("%02x", buffer[i]);
1719 }
1720 printf("\n");
1721 }
1722 }
1723} // End PICC_DumpMifareUltralightToSerial()
1724
1729 uint8_t *accessBitBuffer,
1730 uint8_t g0,
1731 uint8_t g1,
1732 uint8_t g2,
1733 uint8_t g3
1734) {
1735 uint8_t c1 = ((g3 & 4) << 1) | ((g2 & 4) << 0) | ((g1 & 4) >> 1) | ((g0 & 4) >> 2);
1736 uint8_t c2 = ((g3 & 2) << 2) | ((g2 & 2) << 1) | ((g1 & 2) << 0) | ((g0 & 2) >> 1);
1737 uint8_t c3 = ((g3 & 1) << 3) | ((g2 & 1) << 2) | ((g1 & 1) << 1) | ((g0 & 1) << 0);
1738
1739 accessBitBuffer[0] = (~c2 & 0xF) << 4 | (~c1 & 0xF);
1740 accessBitBuffer[1] = c1 << 4 | (~c3 & 0xF);
1741 accessBitBuffer[2] = c3 << 4 | c2;
1742} // End MIFARE_SetAccessBits()
1743
1744
1757 // Magic sequence:
1758 // > 50 00 57 CD (HALT + CRC)
1759 // > 40 (7 bits only)
1760 // < A (4 bits only)
1761 // > 43
1762 // < A (4 bits only)
1763 // Then you can write to sector 0 without authenticating
1764
1765 PICC_HaltA(); // 50 00 57 CD
1766
1767 uint8_t cmd = 0x40;
1768 uint8_t validBits = 7; /* Our command is only 7 bits. After receiving card response,
1769 this will contain amount of valid response bits. */
1770 uint8_t response[32]; // Card's response is written here
1771 uint8_t received = sizeof(response);
1772 mfrc522_drv::StatusCode status = PCD_TransceiveData(&cmd, (uint8_t) 1, response, &received, &validBits, (uint8_t) 0,
1773 false); // 40
1774 if (status != STATUS_OK) {
1775 if (logErrors) {
1776 printf(
1777 "Card did not respond to 0x40 after HALT command. Are you sure it is a UID changeable one?");
1778 printf("Error name: ");
1779 printf(GetStatusCodeName(status));
1780 printf("\n");
1781 }
1782 return false;
1783 }
1784 if (received != 1 || response[0] != 0x0A) {
1785 if (logErrors) {
1786 printf("Got bad response on backdoor 0x40 command: ");
1787 printf("%x", response[0]);
1788 printf(" (");
1789 printf("%d", validBits);
1790 printf(" valid bits)\r\n");
1791 }
1792 return false;
1793 }
1794
1795 cmd = 0x43;
1796 validBits = 8;
1797 status = PCD_TransceiveData(&cmd, (uint8_t) 1, response, &received, &validBits, (uint8_t) 0, false); // 43
1798 if (status != STATUS_OK) {
1799 if (logErrors) {
1800 printf("Error in communication at command 0x43, after successfully executing 0x40\n");
1801 printf("Error name: ");
1802 printf("%s", GetStatusCodeName(status));
1803 }
1804 return false;
1805 }
1806 if (received != 1 || response[0] != 0x0A) {
1807 if (logErrors) {
1808 printf("Got bad response on backdoor 0x43 command: ");
1809 printf("%x", response[0]);
1810 printf(" (");
1811 printf("%d", validBits);
1812 printf(" valid bits)\r\n");
1813 }
1814 return false;
1815 }
1816
1817 // You can now write to sector 0 without authenticating!
1818 return true;
1819} // End MIFARE_OpenUidBackdoor()
1820
1829bool mfrc522_drv::MIFARE_SetUid(uint8_t *newUid, uint8_t uidSize, bool logErrors) {
1830
1831 // UID + BCC uint8_t can not be larger than 16 together
1832 if (!newUid || !uidSize || uidSize > 15) {
1833 if (logErrors) {
1834 printf("New UID buffer empty, size 0, or size > 15 given\n");
1835 }
1836 return false;
1837 }
1838
1839 // Authenticate for reading
1840 MIFARE_Key key = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
1841 mfrc522_drv::StatusCode status = PCD_Authenticate(mfrc522_drv::PICC_CMD_MF_AUTH_KEY_A, (uint8_t) 1, &key, &uid);
1842 if (status != STATUS_OK) {
1843
1844 if (status == STATUS_TIMEOUT) {
1845 // We get a read timeout if no card is selected yet, so let's select one
1846
1847 // Wake the card up again if sleeping
1848// uint8_t atqa_answer[2];
1849// uint8_t atqa_size = 2;
1850// PICC_WakeupA(atqa_answer, &atqa_size);
1851
1853 printf("No card was previously selected, and none are available. Failed to set UID.\n");
1854 return false;
1855 }
1856
1857 status = PCD_Authenticate(mfrc522_drv::PICC_CMD_MF_AUTH_KEY_A, (uint8_t) 1, &key, &uid);
1858 if (status != STATUS_OK) {
1859 // We tried, time to give up
1860 if (logErrors) {
1861 printf("Failed to authenticate to card for reading, could not set UID: \n");
1862 printf("%s\n", GetStatusCodeName(status));
1863 }
1864 return false;
1865 }
1866 } else {
1867 if (logErrors) {
1868 printf("PCD_Authenticate() failed: ");
1869 printf("%s\n", GetStatusCodeName(status));
1870 }
1871 return false;
1872 }
1873 }
1874
1875 // Read block 0
1876 uint8_t block0_buffer[18];
1877 uint8_t uint8_tCount = sizeof(block0_buffer);
1878 status = MIFARE_Read((uint8_t) 0, block0_buffer, &uint8_tCount);
1879 if (status != STATUS_OK) {
1880 if (logErrors) {
1881 printf("MIFARE_Read() failed: ");
1882 printf("%s\n", GetStatusCodeName(status));
1883 printf("Are you sure your KEY A for sector 0 is 0xFFFFFFFFFFFF?\n");
1884 }
1885 return false;
1886 }
1887
1888 // Write new UID to the data we just read, and calculate BCC uint8_t
1889 uint8_t bcc = 0;
1890 for (uint8_t i = 0; i < uidSize; i++) {
1891 block0_buffer[i] = newUid[i];
1892 bcc ^= newUid[i];
1893 }
1894
1895 // Write BCC uint8_t to buffer
1896 block0_buffer[uidSize] = bcc;
1897
1898 // Stop encrypted traffic so we can send raw uint8_ts
1900
1901 // Activate UID backdoor
1902 if (!MIFARE_OpenUidBackdoor(logErrors)) {
1903 if (logErrors) {
1904 printf("Activating the UID backdoor failed.\n");
1905 }
1906 return false;
1907 }
1908
1909 // Write modified block 0 back to card
1910 status = MIFARE_Write((uint8_t) 0, block0_buffer, (uint8_t) 16);
1911 if (status != STATUS_OK) {
1912 if (logErrors) {
1913 printf("MIFARE_Write() failed: \n");
1914 printf("%s\n", GetStatusCodeName(status));
1915 }
1916 return false;
1917 }
1918
1919 // Wake the card up again
1920 uint8_t atqa_answer[2];
1921 uint8_t atqa_size = 2;
1922 PICC_WakeupA(atqa_answer, &atqa_size);
1923
1924 return true;
1925}
1926
1931 MIFARE_OpenUidBackdoor(logErrors);
1932
1933 uint8_t block0_buffer[] = {0x01, 0x02, 0x03, 0x04, 0x04, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1934 0x00};
1935
1936 // Write modified block 0 back to card
1937 mfrc522_drv::StatusCode status = MIFARE_Write((uint8_t) 0, block0_buffer, (uint8_t) 16);
1938 if (status != STATUS_OK) {
1939 if (logErrors) {
1940 printf("MIFARE_Write() failed: \n");
1941 printf("%s\n", GetStatusCodeName(status));
1942 }
1943 return false;
1944 }
1945 return true;
1946}
1947
1949// Convenience functions - does not add extra functionality
1951
1959 uint8_t bufferATQA[2];
1960 uint8_t bufferSize = sizeof(bufferATQA);
1961
1962 // Reset baud rates
1963 PCD_WriteRegister(TxModeReg, 0x00);
1964 PCD_WriteRegister(RxModeReg, 0x00);
1965 // Reset ModWidthReg
1966 PCD_WriteRegister(ModWidthReg, 0x26);
1967
1968 mfrc522_drv::StatusCode result = PICC_RequestA(bufferATQA, &bufferSize);
1969 return (result == STATUS_OK || result == STATUS_COLLISION);
1970}
1971
1981 mfrc522_drv::StatusCode result = PICC_Select(&uid);
1982 return (result == STATUS_OK);
1983}
void PICC_DumpDetailsToSerial(Uid *uid)
StatusCode MIFARE_TwoStepHelper(uint8_t command, uint8_t blockAddr, int32_t data)
void PICC_DumpToSerial(Uid *uid)
static const char * PICC_GetTypeName(PICC_Type type)
StatusCode PCD_CommunicateWithPICC(uint8_t command, uint8_t waitIRq, uint8_t *sendData, uint8_t sendLen, uint8_t *backData=nullptr, uint8_t *backLen=nullptr, uint8_t *validBits=nullptr, uint8_t rxAlign=0, bool checkCRC=false)
void PCD_WriteRegister(PCD_Register reg, uint8_t value)
StatusCode MIFARE_SetValue(uint8_t blockAddr, int32_t value)
StatusCode MIFARE_Restore(uint8_t blockAddr)
StatusCode MIFARE_Decrement(uint8_t blockAddr, int32_t delta)
StatusCode MIFARE_Ultralight_Write(uint8_t page, uint8_t *buffer, uint8_t bufferSize)
void PCD_DumpVersionToSerial()
void PCD_StopCrypto1()
StatusCode MIFARE_GetValue(uint8_t blockAddr, int32_t *value)
StatusCode PCD_CalculateCRC(uint8_t *data, uint8_t length, uint8_t *result)
virtual bool PICC_IsNewCardPresent()
bool PCD_PerformSelfTest()
void MIFARE_SetAccessBits(uint8_t *accessBitBuffer, uint8_t g0, uint8_t g1, uint8_t g2, uint8_t g3)
void PCD_SetRegisterBitMask(PCD_Register reg, uint8_t mask)
static PICC_Type PICC_GetType(uint8_t sak)
StatusCode PCD_NTAG216_AUTH(uint8_t *passWord, uint8_t pACK[])
virtual StatusCode PICC_Select(Uid *uid, uint8_t validBits=0)
uint8_t PCD_ReadRegister(PCD_Register reg)
StatusCode PCD_TransceiveData(uint8_t *sendData, uint8_t sendLen, uint8_t *backData, uint8_t *backLen, uint8_t *validBits=nullptr, uint8_t rxAlign=0, bool checkCRC=false)
StatusCode PCD_MIFARE_Transceive(uint8_t *sendData, uint8_t sendLen, bool acceptTimeout=false)
void PCD_ClearRegisterBitMask(PCD_Register reg, uint8_t mask)
StatusCode PICC_HaltA()
StatusCode PICC_RequestA(uint8_t *bufferATQA, uint8_t *bufferSize)
StatusCode MIFARE_Read(uint8_t blockAddr, uint8_t *buffer, uint8_t *bufferSize)
void PCD_SetAntennaGain(uint8_t mask)
static const char * GetStatusCodeName(StatusCode code)
StatusCode MIFARE_Increment(uint8_t blockAddr, int32_t delta)
void PCD_AntennaOn()
virtual bool PICC_ReadCardSerial()
mfrc522_drv(spi_interface &spi, gpio_interface &reset)
void PICC_DumpMifareClassicToSerial(Uid *uid, PICC_Type piccType, MIFARE_Key *key)
uint8_t PCD_GetAntennaGain()
StatusCode MIFARE_Transfer(uint8_t blockAddr)
void PICC_DumpMifareClassicSectorToSerial(Uid *uid, MIFARE_Key *key, uint8_t sector)
StatusCode PCD_Authenticate(uint8_t command, uint8_t blockAddr, MIFARE_Key *key, Uid *uid)
void PICC_DumpMifareUltralightToSerial()
StatusCode PICC_REQA_or_WUPA(uint8_t command, uint8_t *bufferATQA, uint8_t *bufferSize)
bool MIFARE_OpenUidBackdoor(bool logErrors)
bool MIFARE_SetUid(uint8_t *newUid, uint8_t uidSize, bool logErrors)
bool MIFARE_UnbrickUidSector(bool logErrors)
StatusCode PICC_WakeupA(uint8_t *bufferATQA, uint8_t *bufferSize)
void PCD_AntennaOff()
StatusCode MIFARE_Write(uint8_t blockAddr, uint8_t *buffer, uint8_t bufferSize)