├── .gitignore ├── LICENSE ├── MFRC522_I2C.cpp ├── MFRC522_I2C.h ├── README.md ├── binaries └── m5hack_esp32.bin ├── images.h ├── m5hack.ino ├── raw_githubusercontent_com.h └── z-sysinfo.ino /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Yohann Ciurlik 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MFRC522_I2C.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * MFRC522.cpp - Library to use ARDUINO RFID MODULE KIT 13.56 MHZ WITH TAGS I2C BY AROZCAN 3 | * MFRC522.cpp - Based on ARDUINO RFID MODULE KIT 13.56 MHZ WITH TAGS SPI Library BY COOQROBOT. 4 | * NOTE: Please also check the comments in MFRC522.h - they provide useful hints and background information. 5 | * Released into the public domain. 6 | * Author: arozcan @ https://github.com/arozcan/MFRC522-I2C-Library 7 | */ 8 | 9 | #include 10 | #include "MFRC522_I2C.h" 11 | #include 12 | 13 | ///////////////////////////////////////////////////////////////////////////////////// 14 | // Functions for setting up the Arduino 15 | ///////////////////////////////////////////////////////////////////////////////////// 16 | 17 | /** 18 | * Constructor. 19 | * Prepares the output pins. 20 | */ 21 | MFRC522::MFRC522( byte chipAddress 22 | //byte resetPowerDownPin ///< Arduino pin connected to MFRC522's reset and power down input (Pin 6, NRSTPD, active low) 23 | ) { 24 | _chipAddress = chipAddress; 25 | // _resetPowerDownPin = resetPowerDownPin; 26 | } // End constructor 27 | 28 | 29 | ///////////////////////////////////////////////////////////////////////////////////// 30 | // Basic interface functions for communicating with the MFRC522 31 | ///////////////////////////////////////////////////////////////////////////////////// 32 | 33 | /** 34 | * Writes a byte to the specified register in the MFRC522 chip. 35 | * The interface is described in the datasheet section 8.1.2. 36 | */ 37 | void MFRC522::PCD_WriteRegister( byte reg, ///< The register to write to. One of the PCD_Register enums. 38 | byte value ///< The value to write. 39 | ) { 40 | Wire.beginTransmission(_chipAddress); 41 | Wire.write(reg); 42 | Wire.write(value); 43 | Wire.endTransmission(); 44 | } // End PCD_WriteRegister() 45 | 46 | /** 47 | * Writes a number of bytes to the specified register in the MFRC522 chip. 48 | * The interface is described in the datasheet section 8.1.2. 49 | */ 50 | void MFRC522::PCD_WriteRegister( byte reg, ///< The register to write to. One of the PCD_Register enums. 51 | byte count, ///< The number of bytes to write to the register 52 | byte *values ///< The values to write. Byte array. 53 | ) { 54 | Wire.beginTransmission(_chipAddress); 55 | Wire.write(reg); 56 | for (byte index = 0; index < count; index++) { 57 | Wire.write(values[index]); 58 | } 59 | Wire.endTransmission(); 60 | } // End PCD_WriteRegister() 61 | 62 | /** 63 | * Reads a byte from the specified register in the MFRC522 chip. 64 | * The interface is described in the datasheet section 8.1.2. 65 | */ 66 | byte MFRC522::PCD_ReadRegister( byte reg ///< The register to read from. One of the PCD_Register enums. 67 | ) { 68 | byte value; 69 | //digitalWrite(_chipSelectPin, LOW); // Select slave 70 | Wire.beginTransmission(_chipAddress); 71 | Wire.write(reg); 72 | Wire.endTransmission(); 73 | 74 | Wire.requestFrom(_chipAddress, 1); 75 | value = Wire.read(); 76 | return value; 77 | } // End PCD_ReadRegister() 78 | 79 | /** 80 | * Reads a number of bytes from the specified register in the MFRC522 chip. 81 | * The interface is described in the datasheet section 8.1.2. 82 | */ 83 | void MFRC522::PCD_ReadRegister( byte reg, ///< The register to read from. One of the PCD_Register enums. 84 | byte count, ///< The number of bytes to read 85 | byte *values, ///< Byte array to store the values in. 86 | byte rxAlign ///< Only bit positions rxAlign..7 in values[0] are updated. 87 | ) { 88 | if (count == 0) { 89 | return; 90 | } 91 | byte address = reg; 92 | byte index = 0; // Index in values array. 93 | Wire.beginTransmission(_chipAddress); 94 | Wire.write(address); 95 | Wire.endTransmission(); 96 | Wire.requestFrom(_chipAddress, count); 97 | while (Wire.available()) { 98 | if (index == 0 && rxAlign) { // Only update bit positions rxAlign..7 in values[0] 99 | // Create bit mask for bit positions rxAlign..7 100 | byte mask = 0; 101 | for (byte i = rxAlign; i <= 7; i++) { 102 | mask |= (1 << i); 103 | } 104 | // Read value and tell that we want to read the same address again. 105 | byte value = Wire.read(); 106 | // Apply mask to both current value of values[0] and the new data in value. 107 | values[0] = (values[index] & ~mask) | (value & mask); 108 | } 109 | else { // Normal case 110 | values[index] = Wire.read(); 111 | } 112 | index++; 113 | } 114 | } // End PCD_ReadRegister() 115 | 116 | /** 117 | * Sets the bits given in mask in register reg. 118 | */ 119 | void MFRC522::PCD_SetRegisterBitMask( byte reg, ///< The register to update. One of the PCD_Register enums. 120 | byte mask ///< The bits to set. 121 | ) { 122 | byte tmp; 123 | tmp = PCD_ReadRegister(reg); 124 | PCD_WriteRegister(reg, tmp | mask); // set bit mask 125 | } // End PCD_SetRegisterBitMask() 126 | 127 | /** 128 | * Clears the bits given in mask from register reg. 129 | */ 130 | void MFRC522::PCD_ClearRegisterBitMask( byte reg, ///< The register to update. One of the PCD_Register enums. 131 | byte mask ///< The bits to clear. 132 | ) { 133 | byte tmp; 134 | tmp = PCD_ReadRegister(reg); 135 | PCD_WriteRegister(reg, tmp & (~mask)); // clear bit mask 136 | } // End PCD_ClearRegisterBitMask() 137 | 138 | 139 | /** 140 | * Use the CRC coprocessor in the MFRC522 to calculate a CRC_A. 141 | * 142 | * @return STATUS_OK on success, STATUS_??? otherwise. 143 | */ 144 | byte MFRC522::PCD_CalculateCRC( byte *data, ///< In: Pointer to the data to transfer to the FIFO for CRC calculation. 145 | byte length, ///< In: The number of bytes to transfer. 146 | byte *result ///< Out: Pointer to result buffer. Result is written to result[0..1], low byte first. 147 | ) { 148 | PCD_WriteRegister(CommandReg, PCD_Idle); // Stop any active command. 149 | PCD_WriteRegister(DivIrqReg, 0x04); // Clear the CRCIRq interrupt request bit 150 | PCD_SetRegisterBitMask(FIFOLevelReg, 0x80); // FlushBuffer = 1, FIFO initialization 151 | PCD_WriteRegister(FIFODataReg, length, data); // Write data to the FIFO 152 | PCD_WriteRegister(CommandReg, PCD_CalcCRC); // Start the calculation 153 | 154 | // Wait for the CRC calculation to complete. Each iteration of the while-loop takes 17.73�s. 155 | word i = 5000; 156 | byte n; 157 | while (1) { 158 | n = PCD_ReadRegister(DivIrqReg); // DivIrqReg[7..0] bits are: Set2 reserved reserved MfinActIRq reserved CRCIRq reserved reserved 159 | if (n & 0x04) { // CRCIRq bit set - calculation done 160 | break; 161 | } 162 | if (--i == 0) { // The emergency break. We will eventually terminate on this one after 89ms. Communication with the MFRC522 might be down. 163 | return STATUS_TIMEOUT; 164 | } 165 | } 166 | PCD_WriteRegister(CommandReg, PCD_Idle); // Stop calculating CRC for new content in the FIFO. 167 | 168 | // Transfer the result from the registers to the result buffer 169 | result[0] = PCD_ReadRegister(CRCResultRegL); 170 | result[1] = PCD_ReadRegister(CRCResultRegH); 171 | return STATUS_OK; 172 | } // End PCD_CalculateCRC() 173 | 174 | 175 | ///////////////////////////////////////////////////////////////////////////////////// 176 | // Functions for manipulating the MFRC522 177 | ///////////////////////////////////////////////////////////////////////////////////// 178 | 179 | /** 180 | * Initializes the MFRC522 chip. 181 | */ 182 | void MFRC522::PCD_Init() { 183 | // Set the chipSelectPin as digital output, do not select the slave yet 184 | 185 | // Set the resetPowerDownPin as digital output, do not reset or power down. 186 | // pinMode(_resetPowerDownPin, OUTPUT); 187 | 188 | 189 | // if (digitalRead(_resetPowerDownPin) == LOW) { //The MFRC522 chip is in power down mode. 190 | // digitalWrite(_resetPowerDownPin, HIGH); // Exit power down mode. This triggers a hard reset. 191 | // // 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. 192 | // delay(50); 193 | // } 194 | // else { // Perform a soft reset 195 | PCD_Reset(); 196 | // } 197 | 198 | // When communicating with a PICC we need a timeout if something goes wrong. 199 | // f_timer = 13.56 MHz / (2*TPreScaler+1) where TPreScaler = [TPrescaler_Hi:TPrescaler_Lo]. 200 | // TPrescaler_Hi are the four low bits in TModeReg. TPrescaler_Lo is TPrescalerReg. 201 | PCD_WriteRegister(TModeReg, 0x80); // TAuto=1; timer starts automatically at the end of the transmission in all communication modes at all speeds 202 | PCD_WriteRegister(TPrescalerReg, 0xA9); // TPreScaler = TModeReg[3..0]:TPrescalerReg, ie 0x0A9 = 169 => f_timer=40kHz, ie a timer period of 25�s. 203 | PCD_WriteRegister(TReloadRegH, 0x03); // Reload timer with 0x3E8 = 1000, ie 25ms before timeout. 204 | PCD_WriteRegister(TReloadRegL, 0xE8); 205 | 206 | PCD_WriteRegister(TxASKReg, 0x40); // Default 0x00. Force a 100 % ASK modulation independent of the ModGsPReg register setting 207 | 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) 208 | PCD_AntennaOn(); // Enable the antenna driver pins TX1 and TX2 (they were disabled by the reset) 209 | } // End PCD_Init() 210 | 211 | /** 212 | * Performs a soft reset on the MFRC522 chip and waits for it to be ready again. 213 | */ 214 | void MFRC522::PCD_Reset() { 215 | PCD_WriteRegister(CommandReg, PCD_SoftReset); // Issue the SoftReset command. 216 | // The datasheet does not mention how long the SoftRest command takes to complete. 217 | // But the MFRC522 might have been in soft power-down mode (triggered by bit 4 of CommandReg) 218 | // 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. 219 | delay(50); 220 | // Wait for the PowerDown bit in CommandReg to be cleared 221 | while (PCD_ReadRegister(CommandReg) & (1<<4)) { 222 | // PCD still restarting - unlikely after waiting 50ms, but better safe than sorry. 223 | } 224 | } // End PCD_Reset() 225 | 226 | /** 227 | * Turns the antenna on by enabling pins TX1 and TX2. 228 | * After a reset these pins are disabled. 229 | */ 230 | void MFRC522::PCD_AntennaOn() { 231 | byte value = PCD_ReadRegister(TxControlReg); 232 | if ((value & 0x03) != 0x03) { 233 | PCD_WriteRegister(TxControlReg, value | 0x03); 234 | } 235 | } // End PCD_AntennaOn() 236 | 237 | /** 238 | * Turns the antenna off by disabling pins TX1 and TX2. 239 | */ 240 | void MFRC522::PCD_AntennaOff() { 241 | PCD_ClearRegisterBitMask(TxControlReg, 0x03); 242 | } // End PCD_AntennaOff() 243 | 244 | /** 245 | * Get the current MFRC522 Receiver Gain (RxGain[2:0]) value. 246 | * See 9.3.3.6 / table 98 in http://www.nxp.com/documents/data_sheet/MFRC522.pdf 247 | * NOTE: Return value scrubbed with (0x07<<4)=01110000b as RCFfgReg may use reserved bits. 248 | * 249 | * @return Value of the RxGain, scrubbed to the 3 bits used. 250 | */ 251 | byte MFRC522::PCD_GetAntennaGain() { 252 | return PCD_ReadRegister(RFCfgReg) & (0x07<<4); 253 | } // End PCD_GetAntennaGain() 254 | 255 | /** 256 | * Set the MFRC522 Receiver Gain (RxGain) to value specified by given mask. 257 | * See 9.3.3.6 / table 98 in http://www.nxp.com/documents/data_sheet/MFRC522.pdf 258 | * NOTE: Given mask is scrubbed with (0x07<<4)=01110000b as RCFfgReg may use reserved bits. 259 | */ 260 | void MFRC522::PCD_SetAntennaGain(byte mask) { 261 | if (PCD_GetAntennaGain() != mask) { // only bother if there is a change 262 | PCD_ClearRegisterBitMask(RFCfgReg, (0x07<<4)); // clear needed to allow 000 pattern 263 | PCD_SetRegisterBitMask(RFCfgReg, mask & (0x07<<4)); // only set RxGain[2:0] bits 264 | } 265 | } // End PCD_SetAntennaGain() 266 | 267 | /** 268 | * Performs a self-test of the MFRC522 269 | * See 16.1.1 in http://www.nxp.com/documents/data_sheet/MFRC522.pdf 270 | * 271 | * @return Whether or not the test passed. 272 | */ 273 | bool MFRC522::PCD_PerformSelfTest() { 274 | // This follows directly the steps outlined in 16.1.1 275 | // 1. Perform a soft reset. 276 | PCD_Reset(); 277 | 278 | // 2. Clear the internal buffer by writing 25 bytes of 00h 279 | byte ZEROES[25] = {0x00}; 280 | PCD_SetRegisterBitMask(FIFOLevelReg, 0x80); // flush the FIFO buffer 281 | PCD_WriteRegister(FIFODataReg, 25, ZEROES); // write 25 bytes of 00h to FIFO 282 | PCD_WriteRegister(CommandReg, PCD_Mem); // transfer to internal buffer 283 | 284 | // 3. Enable self-test 285 | PCD_WriteRegister(AutoTestReg, 0x09); 286 | 287 | // 4. Write 00h to FIFO buffer 288 | PCD_WriteRegister(FIFODataReg, 0x00); 289 | 290 | // 5. Start self-test by issuing the CalcCRC command 291 | PCD_WriteRegister(CommandReg, PCD_CalcCRC); 292 | 293 | // 6. Wait for self-test to complete 294 | word i; 295 | byte n; 296 | for (i = 0; i < 0xFF; i++) { 297 | n = PCD_ReadRegister(DivIrqReg); // DivIrqReg[7..0] bits are: Set2 reserved reserved MfinActIRq reserved CRCIRq reserved reserved 298 | if (n & 0x04) { // CRCIRq bit set - calculation done 299 | break; 300 | } 301 | } 302 | PCD_WriteRegister(CommandReg, PCD_Idle); // Stop calculating CRC for new content in the FIFO. 303 | 304 | // 7. Read out resulting 64 bytes from the FIFO buffer. 305 | byte result[64]; 306 | PCD_ReadRegister(FIFODataReg, 64, result, 0); 307 | 308 | // Auto self-test done 309 | // Reset AutoTestReg register to be 0 again. Required for normal operation. 310 | PCD_WriteRegister(AutoTestReg, 0x00); 311 | 312 | // Determine firmware version (see section 9.3.4.8 in spec) 313 | byte version = PCD_ReadRegister(VersionReg); 314 | 315 | // Pick the appropriate reference values 316 | const byte *reference; 317 | switch (version) { 318 | case 0x88: // Fudan Semiconductor FM17522 clone 319 | reference = FM17522_firmware_reference; 320 | break; 321 | case 0x90: // Version 0.0 322 | reference = MFRC522_firmware_referenceV0_0; 323 | break; 324 | case 0x91: // Version 1.0 325 | reference = MFRC522_firmware_referenceV1_0; 326 | break; 327 | case 0x92: // Version 2.0 328 | reference = MFRC522_firmware_referenceV2_0; 329 | break; 330 | default: // Unknown version 331 | return false; 332 | } 333 | 334 | // Verify that the results match up to our expectations 335 | for (i = 0; i < 64; i++) { 336 | if (result[i] != pgm_read_byte(&(reference[i]))) { 337 | return false; 338 | } 339 | } 340 | 341 | // Test passed; all is good. 342 | return true; 343 | } // End PCD_PerformSelfTest() 344 | 345 | ///////////////////////////////////////////////////////////////////////////////////// 346 | // Functions for communicating with PICCs 347 | ///////////////////////////////////////////////////////////////////////////////////// 348 | 349 | /** 350 | * Executes the Transceive command. 351 | * CRC validation can only be done if backData and backLen are specified. 352 | * 353 | * @return STATUS_OK on success, STATUS_??? otherwise. 354 | */ 355 | byte MFRC522::PCD_TransceiveData( byte *sendData, ///< Pointer to the data to transfer to the FIFO. 356 | byte sendLen, ///< Number of bytes to transfer to the FIFO. 357 | byte *backData, ///< NULL or pointer to buffer if data should be read back after executing the command. 358 | byte *backLen, ///< In: Max number of bytes to write to *backData. Out: The number of bytes returned. 359 | byte *validBits, ///< In/Out: The number of valid bits in the last byte. 0 for 8 valid bits. Default NULL. 360 | byte rxAlign, ///< In: Defines the bit position in backData[0] for the first bit received. Default 0. 361 | bool checkCRC ///< In: True => The last two bytes of the response is assumed to be a CRC_A that must be validated. 362 | ) { 363 | byte waitIRq = 0x30; // RxIRq and IdleIRq 364 | return PCD_CommunicateWithPICC(PCD_Transceive, waitIRq, sendData, sendLen, backData, backLen, validBits, rxAlign, checkCRC); 365 | } // End PCD_TransceiveData() 366 | 367 | /** 368 | * Transfers data to the MFRC522 FIFO, executes a command, waits for completion and transfers data back from the FIFO. 369 | * CRC validation can only be done if backData and backLen are specified. 370 | * 371 | * @return STATUS_OK on success, STATUS_??? otherwise. 372 | */ 373 | byte MFRC522::PCD_CommunicateWithPICC( byte command, ///< The command to execute. One of the PCD_Command enums. 374 | byte waitIRq, ///< The bits in the ComIrqReg register that signals successful completion of the command. 375 | byte *sendData, ///< Pointer to the data to transfer to the FIFO. 376 | byte sendLen, ///< Number of bytes to transfer to the FIFO. 377 | byte *backData, ///< NULL or pointer to buffer if data should be read back after executing the command. 378 | byte *backLen, ///< In: Max number of bytes to write to *backData. Out: The number of bytes returned. 379 | byte *validBits, ///< In/Out: The number of valid bits in the last byte. 0 for 8 valid bits. 380 | byte rxAlign, ///< In: Defines the bit position in backData[0] for the first bit received. Default 0. 381 | bool checkCRC ///< In: True => The last two bytes of the response is assumed to be a CRC_A that must be validated. 382 | ) { 383 | byte n, _validBits; 384 | unsigned int i; 385 | 386 | // Prepare values for BitFramingReg 387 | byte txLastBits = validBits ? *validBits : 0; 388 | byte bitFraming = (rxAlign << 4) + txLastBits; // RxAlign = BitFramingReg[6..4]. TxLastBits = BitFramingReg[2..0] 389 | 390 | PCD_WriteRegister(CommandReg, PCD_Idle); // Stop any active command. 391 | PCD_WriteRegister(ComIrqReg, 0x7F); // Clear all seven interrupt request bits 392 | PCD_SetRegisterBitMask(FIFOLevelReg, 0x80); // FlushBuffer = 1, FIFO initialization 393 | PCD_WriteRegister(FIFODataReg, sendLen, sendData); // Write sendData to the FIFO 394 | PCD_WriteRegister(BitFramingReg, bitFraming); // Bit adjustments 395 | PCD_WriteRegister(CommandReg, command); // Execute the command 396 | if (command == PCD_Transceive) { 397 | PCD_SetRegisterBitMask(BitFramingReg, 0x80); // StartSend=1, transmission of data starts 398 | } 399 | 400 | // Wait for the command to complete. 401 | // In PCD_Init() we set the TAuto flag in TModeReg. This means the timer automatically starts when the PCD stops transmitting. 402 | // Each iteration of the do-while-loop takes 17.86�s. 403 | i = 2000; 404 | while (1) { 405 | n = PCD_ReadRegister(ComIrqReg); // ComIrqReg[7..0] bits are: Set1 TxIRq RxIRq IdleIRq HiAlertIRq LoAlertIRq ErrIRq TimerIRq 406 | if (n & waitIRq) { // One of the interrupts that signal success has been set. 407 | break; 408 | } 409 | if (n & 0x01) { // Timer interrupt - nothing received in 25ms 410 | return STATUS_TIMEOUT; 411 | } 412 | if (--i == 0) { // The emergency break. If all other condions fail we will eventually terminate on this one after 35.7ms. Communication with the MFRC522 might be down. 413 | return STATUS_TIMEOUT; 414 | } 415 | } 416 | 417 | // Stop now if any errors except collisions were detected. 418 | byte errorRegValue = PCD_ReadRegister(ErrorReg); // ErrorReg[7..0] bits are: WrErr TempErr reserved BufferOvfl CollErr CRCErr ParityErr ProtocolErr 419 | if (errorRegValue & 0x13) { // BufferOvfl ParityErr ProtocolErr 420 | return STATUS_ERROR; 421 | } 422 | 423 | // If the caller wants data back, get it from the MFRC522. 424 | if (backData && backLen) { 425 | n = PCD_ReadRegister(FIFOLevelReg); // Number of bytes in the FIFO 426 | if (n > *backLen) { 427 | return STATUS_NO_ROOM; 428 | } 429 | *backLen = n; // Number of bytes returned 430 | PCD_ReadRegister(FIFODataReg, n, backData, rxAlign); // Get received data from FIFO 431 | _validBits = PCD_ReadRegister(ControlReg) & 0x07; // RxLastBits[2:0] indicates the number of valid bits in the last received byte. If this value is 000b, the whole byte is valid. 432 | if (validBits) { 433 | *validBits = _validBits; 434 | } 435 | } 436 | 437 | // Tell about collisions 438 | if (errorRegValue & 0x08) { // CollErr 439 | return STATUS_COLLISION; 440 | } 441 | 442 | // Perform CRC_A validation if requested. 443 | if (backData && backLen && checkCRC) { 444 | // In this case a MIFARE Classic NAK is not OK. 445 | if (*backLen == 1 && _validBits == 4) { 446 | return STATUS_MIFARE_NACK; 447 | } 448 | // We need at least the CRC_A value and all 8 bits of the last byte must be received. 449 | if (*backLen < 2 || _validBits != 0) { 450 | return STATUS_CRC_WRONG; 451 | } 452 | // Verify CRC_A - do our own calculation and store the control in controlBuffer. 453 | byte controlBuffer[2]; 454 | n = PCD_CalculateCRC(&backData[0], *backLen - 2, &controlBuffer[0]); 455 | if (n != STATUS_OK) { 456 | return n; 457 | } 458 | if ((backData[*backLen - 2] != controlBuffer[0]) || (backData[*backLen - 1] != controlBuffer[1])) { 459 | return STATUS_CRC_WRONG; 460 | } 461 | } 462 | 463 | return STATUS_OK; 464 | } // End PCD_CommunicateWithPICC() 465 | 466 | /** 467 | * Transmits a REQuest command, Type A. Invites PICCs in state IDLE to go to READY and prepare for anticollision or selection. 7 bit frame. 468 | * Beware: When two PICCs are in the field at the same time I often get STATUS_TIMEOUT - probably due do bad antenna design. 469 | * 470 | * @return STATUS_OK on success, STATUS_??? otherwise. 471 | */ 472 | byte MFRC522::PICC_RequestA(byte *bufferATQA, ///< The buffer to store the ATQA (Answer to request) in 473 | byte *bufferSize ///< Buffer size, at least two bytes. Also number of bytes returned if STATUS_OK. 474 | ) { 475 | return PICC_REQA_or_WUPA(PICC_CMD_REQA, bufferATQA, bufferSize); 476 | } // End PICC_RequestA() 477 | 478 | /** 479 | * Transmits a 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. 480 | * Beware: When two PICCs are in the field at the same time I often get STATUS_TIMEOUT - probably due do bad antenna design. 481 | * 482 | * @return STATUS_OK on success, STATUS_??? otherwise. 483 | */ 484 | byte MFRC522::PICC_WakeupA( byte *bufferATQA, ///< The buffer to store the ATQA (Answer to request) in 485 | byte *bufferSize ///< Buffer size, at least two bytes. Also number of bytes returned if STATUS_OK. 486 | ) { 487 | return PICC_REQA_or_WUPA(PICC_CMD_WUPA, bufferATQA, bufferSize); 488 | } // End PICC_WakeupA() 489 | 490 | /** 491 | * Transmits REQA or WUPA commands. 492 | * Beware: When two PICCs are in the field at the same time I often get STATUS_TIMEOUT - probably due do bad antenna design. 493 | * 494 | * @return STATUS_OK on success, STATUS_??? otherwise. 495 | */ 496 | byte MFRC522::PICC_REQA_or_WUPA( byte command, ///< The command to send - PICC_CMD_REQA or PICC_CMD_WUPA 497 | byte *bufferATQA, ///< The buffer to store the ATQA (Answer to request) in 498 | byte *bufferSize ///< Buffer size, at least two bytes. Also number of bytes returned if STATUS_OK. 499 | ) { 500 | byte validBits; 501 | byte status; 502 | 503 | if (bufferATQA == NULL || *bufferSize < 2) { // The ATQA response is 2 bytes long. 504 | return STATUS_NO_ROOM; 505 | } 506 | PCD_ClearRegisterBitMask(CollReg, 0x80); // ValuesAfterColl=1 => Bits received after collision are cleared. 507 | validBits = 7; // For REQA and WUPA we need the short frame format - transmit only 7 bits of the last (and only) byte. TxLastBits = BitFramingReg[2..0] 508 | status = PCD_TransceiveData(&command, 1, bufferATQA, bufferSize, &validBits); 509 | if (status != STATUS_OK) { 510 | return status; 511 | } 512 | if (*bufferSize != 2 || validBits != 0) { // ATQA must be exactly 16 bits. 513 | return STATUS_ERROR; 514 | } 515 | return STATUS_OK; 516 | } // End PICC_REQA_or_WUPA() 517 | 518 | /** 519 | * Transmits SELECT/ANTICOLLISION commands to select a single PICC. 520 | * Before calling this function the PICCs must be placed in the READY(*) state by calling PICC_RequestA() or PICC_WakeupA(). 521 | * On success: 522 | * - The chosen PICC is in state ACTIVE(*) and all other PICCs have returned to state IDLE/HALT. (Figure 7 of the ISO/IEC 14443-3 draft.) 523 | * - The UID size and value of the chosen PICC is returned in *uid along with the SAK. 524 | * 525 | * A PICC UID consists of 4, 7 or 10 bytes. 526 | * Only 4 bytes can be specified in a SELECT command, so for the longer UIDs two or three iterations are used: 527 | * UID size Number of UID bytes Cascade levels Example of PICC 528 | * ======== =================== ============== =============== 529 | * single 4 1 MIFARE Classic 530 | * double 7 2 MIFARE Ultralight 531 | * triple 10 3 Not currently in use? 532 | * 533 | * @return STATUS_OK on success, STATUS_??? otherwise. 534 | */ 535 | byte MFRC522::PICC_Select( Uid *uid, ///< Pointer to Uid struct. Normally output, but can also be used to supply a known UID. 536 | byte validBits ///< The number of known UID bits supplied in *uid. Normally 0. If set you must also supply uid->size. 537 | ) { 538 | bool uidComplete; 539 | bool selectDone; 540 | bool useCascadeTag; 541 | byte cascadeLevel = 1; 542 | byte result; 543 | byte count; 544 | byte index; 545 | byte uidIndex; // The first index in uid->uidByte[] that is used in the current Cascade Level. 546 | int8_t currentLevelKnownBits; // The number of known UID bits in the current Cascade Level. 547 | byte buffer[9]; // The SELECT/ANTICOLLISION commands uses a 7 byte standard frame + 2 bytes CRC_A 548 | byte bufferUsed; // The number of bytes used in the buffer, ie the number of bytes to transfer to the FIFO. 549 | byte rxAlign; // Used in BitFramingReg. Defines the bit position for the first bit received. 550 | byte txLastBits; // Used in BitFramingReg. The number of valid bits in the last transmitted byte. 551 | byte *responseBuffer; 552 | byte responseLength; 553 | 554 | // Description of buffer structure: 555 | // Byte 0: SEL Indicates the Cascade Level: PICC_CMD_SEL_CL1, PICC_CMD_SEL_CL2 or PICC_CMD_SEL_CL3 556 | // Byte 1: NVB Number of Valid Bits (in complete command, not just the UID): High nibble: complete bytes, Low nibble: Extra bits. 557 | // Byte 2: UID-data or CT See explanation below. CT means Cascade Tag. 558 | // Byte 3: UID-data 559 | // Byte 4: UID-data 560 | // Byte 5: UID-data 561 | // Byte 6: BCC Block Check Character - XOR of bytes 2-5 562 | // Byte 7: CRC_A 563 | // Byte 8: CRC_A 564 | // The BCC and CRC_A is only transmitted if we know all the UID bits of the current Cascade Level. 565 | // 566 | // Description of bytes 2-5: (Section 6.5.4 of the ISO/IEC 14443-3 draft: UID contents and cascade levels) 567 | // UID size Cascade level Byte2 Byte3 Byte4 Byte5 568 | // ======== ============= ===== ===== ===== ===== 569 | // 4 bytes 1 uid0 uid1 uid2 uid3 570 | // 7 bytes 1 CT uid0 uid1 uid2 571 | // 2 uid3 uid4 uid5 uid6 572 | // 10 bytes 1 CT uid0 uid1 uid2 573 | // 2 CT uid3 uid4 uid5 574 | // 3 uid6 uid7 uid8 uid9 575 | 576 | // Sanity checks 577 | if (validBits > 80) { 578 | return STATUS_INVALID; 579 | } 580 | 581 | // Prepare MFRC522 582 | PCD_ClearRegisterBitMask(CollReg, 0x80); // ValuesAfterColl=1 => Bits received after collision are cleared. 583 | 584 | // Repeat Cascade Level loop until we have a complete UID. 585 | uidComplete = false; 586 | while (!uidComplete) { 587 | // Set the Cascade Level in the SEL byte, find out if we need to use the Cascade Tag in byte 2. 588 | switch (cascadeLevel) { 589 | case 1: 590 | buffer[0] = PICC_CMD_SEL_CL1; 591 | uidIndex = 0; 592 | useCascadeTag = validBits && uid->size > 4; // When we know that the UID has more than 4 bytes 593 | break; 594 | 595 | case 2: 596 | buffer[0] = PICC_CMD_SEL_CL2; 597 | uidIndex = 3; 598 | useCascadeTag = validBits && uid->size > 7; // When we know that the UID has more than 7 bytes 599 | break; 600 | 601 | case 3: 602 | buffer[0] = PICC_CMD_SEL_CL3; 603 | uidIndex = 6; 604 | useCascadeTag = false; // Never used in CL3. 605 | break; 606 | 607 | default: 608 | return STATUS_INTERNAL_ERROR; 609 | break; 610 | } 611 | 612 | // How many UID bits are known in this Cascade Level? 613 | currentLevelKnownBits = validBits - (8 * uidIndex); 614 | if (currentLevelKnownBits < 0) { 615 | currentLevelKnownBits = 0; 616 | } 617 | // Copy the known bits from uid->uidByte[] to buffer[] 618 | index = 2; // destination index in buffer[] 619 | if (useCascadeTag) { 620 | buffer[index++] = PICC_CMD_CT; 621 | } 622 | byte bytesToCopy = currentLevelKnownBits / 8 + (currentLevelKnownBits % 8 ? 1 : 0); // The number of bytes needed to represent the known bits for this level. 623 | if (bytesToCopy) { 624 | byte maxBytes = useCascadeTag ? 3 : 4; // Max 4 bytes in each Cascade Level. Only 3 left if we use the Cascade Tag 625 | if (bytesToCopy > maxBytes) { 626 | bytesToCopy = maxBytes; 627 | } 628 | for (count = 0; count < bytesToCopy; count++) { 629 | buffer[index++] = uid->uidByte[uidIndex + count]; 630 | } 631 | } 632 | // Now that the data has been copied we need to include the 8 bits in CT in currentLevelKnownBits 633 | if (useCascadeTag) { 634 | currentLevelKnownBits += 8; 635 | } 636 | 637 | // Repeat anti collision loop until we can transmit all UID bits + BCC and receive a SAK - max 32 iterations. 638 | selectDone = false; 639 | while (!selectDone) { 640 | // Find out how many bits and bytes to send and receive. 641 | if (currentLevelKnownBits >= 32) { // All UID bits in this Cascade Level are known. This is a SELECT. 642 | //Serial.print(F("SELECT: currentLevelKnownBits=")); Serial.println(currentLevelKnownBits, DEC); 643 | buffer[1] = 0x70; // NVB - Number of Valid Bits: Seven whole bytes 644 | // Calculate BCC - Block Check Character 645 | buffer[6] = buffer[2] ^ buffer[3] ^ buffer[4] ^ buffer[5]; 646 | // Calculate CRC_A 647 | result = PCD_CalculateCRC(buffer, 7, &buffer[7]); 648 | if (result != STATUS_OK) { 649 | return result; 650 | } 651 | txLastBits = 0; // 0 => All 8 bits are valid. 652 | bufferUsed = 9; 653 | // Store response in the last 3 bytes of buffer (BCC and CRC_A - not needed after tx) 654 | responseBuffer = &buffer[6]; 655 | responseLength = 3; 656 | } 657 | else { // This is an ANTICOLLISION. 658 | //Serial.print(F("ANTICOLLISION: currentLevelKnownBits=")); Serial.println(currentLevelKnownBits, DEC); 659 | txLastBits = currentLevelKnownBits % 8; 660 | count = currentLevelKnownBits / 8; // Number of whole bytes in the UID part. 661 | index = 2 + count; // Number of whole bytes: SEL + NVB + UIDs 662 | buffer[1] = (index << 4) + txLastBits; // NVB - Number of Valid Bits 663 | bufferUsed = index + (txLastBits ? 1 : 0); 664 | // Store response in the unused part of buffer 665 | responseBuffer = &buffer[index]; 666 | responseLength = sizeof(buffer) - index; 667 | } 668 | 669 | // Set bit adjustments 670 | rxAlign = txLastBits; // Having a seperate variable is overkill. But it makes the next line easier to read. 671 | PCD_WriteRegister(BitFramingReg, (rxAlign << 4) + txLastBits); // RxAlign = BitFramingReg[6..4]. TxLastBits = BitFramingReg[2..0] 672 | 673 | // Transmit the buffer and receive the response. 674 | result = PCD_TransceiveData(buffer, bufferUsed, responseBuffer, &responseLength, &txLastBits, rxAlign); 675 | if (result == STATUS_COLLISION) { // More than one PICC in the field => collision. 676 | result = PCD_ReadRegister(CollReg); // CollReg[7..0] bits are: ValuesAfterColl reserved CollPosNotValid CollPos[4:0] 677 | if (result & 0x20) { // CollPosNotValid 678 | return STATUS_COLLISION; // Without a valid collision position we cannot continue 679 | } 680 | byte collisionPos = result & 0x1F; // Values 0-31, 0 means bit 32. 681 | if (collisionPos == 0) { 682 | collisionPos = 32; 683 | } 684 | if (collisionPos <= currentLevelKnownBits) { // No progress - should not happen 685 | return STATUS_INTERNAL_ERROR; 686 | } 687 | // Choose the PICC with the bit set. 688 | currentLevelKnownBits = collisionPos; 689 | count = (currentLevelKnownBits - 1) % 8; // The bit to modify 690 | index = 1 + (currentLevelKnownBits / 8) + (count ? 1 : 0); // First byte is index 0. 691 | buffer[index] |= (1 << count); 692 | } 693 | else if (result != STATUS_OK) { 694 | return result; 695 | } 696 | else { // STATUS_OK 697 | if (currentLevelKnownBits >= 32) { // This was a SELECT. 698 | selectDone = true; // No more anticollision 699 | // We continue below outside the while. 700 | } 701 | else { // This was an ANTICOLLISION. 702 | // We now have all 32 bits of the UID in this Cascade Level 703 | currentLevelKnownBits = 32; 704 | // Run loop again to do the SELECT. 705 | } 706 | } 707 | } // End of while (!selectDone) 708 | 709 | // We do not check the CBB - it was constructed by us above. 710 | 711 | // Copy the found UID bytes from buffer[] to uid->uidByte[] 712 | index = (buffer[2] == PICC_CMD_CT) ? 3 : 2; // source index in buffer[] 713 | bytesToCopy = (buffer[2] == PICC_CMD_CT) ? 3 : 4; 714 | for (count = 0; count < bytesToCopy; count++) { 715 | uid->uidByte[uidIndex + count] = buffer[index++]; 716 | } 717 | 718 | // Check response SAK (Select Acknowledge) 719 | if (responseLength != 3 || txLastBits != 0) { // SAK must be exactly 24 bits (1 byte + CRC_A). 720 | return STATUS_ERROR; 721 | } 722 | // Verify CRC_A - do our own calculation and store the control in buffer[2..3] - those bytes are not needed anymore. 723 | result = PCD_CalculateCRC(responseBuffer, 1, &buffer[2]); 724 | if (result != STATUS_OK) { 725 | return result; 726 | } 727 | if ((buffer[2] != responseBuffer[1]) || (buffer[3] != responseBuffer[2])) { 728 | return STATUS_CRC_WRONG; 729 | } 730 | if (responseBuffer[0] & 0x04) { // Cascade bit set - UID not complete yes 731 | cascadeLevel++; 732 | } 733 | else { 734 | uidComplete = true; 735 | uid->sak = responseBuffer[0]; 736 | } 737 | } // End of while (!uidComplete) 738 | 739 | // Set correct uid->size 740 | uid->size = 3 * cascadeLevel + 1; 741 | 742 | return STATUS_OK; 743 | } // End PICC_Select() 744 | 745 | /** 746 | * Instructs a PICC in state ACTIVE(*) to go to state HALT. 747 | * 748 | * @return STATUS_OK on success, STATUS_??? otherwise. 749 | */ 750 | byte MFRC522::PICC_HaltA() { 751 | byte result; 752 | byte buffer[4]; 753 | 754 | // Build command buffer 755 | buffer[0] = PICC_CMD_HLTA; 756 | buffer[1] = 0; 757 | // Calculate CRC_A 758 | result = PCD_CalculateCRC(buffer, 2, &buffer[2]); 759 | if (result != STATUS_OK) { 760 | return result; 761 | } 762 | 763 | // Send the command. 764 | // The standard says: 765 | // If the PICC responds with any modulation during a period of 1 ms after the end of the frame containing the 766 | // HLTA command, this response shall be interpreted as 'not acknowledge'. 767 | // We interpret that this way: Only STATUS_TIMEOUT is an success. 768 | result = PCD_TransceiveData(buffer, sizeof(buffer), NULL, 0); 769 | if (result == STATUS_TIMEOUT) { 770 | return STATUS_OK; 771 | } 772 | if (result == STATUS_OK) { // That is ironically NOT ok in this case ;-) 773 | return STATUS_ERROR; 774 | } 775 | return result; 776 | } // End PICC_HaltA() 777 | 778 | 779 | ///////////////////////////////////////////////////////////////////////////////////// 780 | // Functions for communicating with MIFARE PICCs 781 | ///////////////////////////////////////////////////////////////////////////////////// 782 | 783 | /** 784 | * Executes the MFRC522 MFAuthent command. 785 | * This command manages MIFARE authentication to enable a secure communication to any MIFARE Mini, MIFARE 1K and MIFARE 4K card. 786 | * The authentication is described in the MFRC522 datasheet section 10.3.1.9 and http://www.nxp.com/documents/data_sheet/MF1S503x.pdf section 10.1. 787 | * For use with MIFARE Classic PICCs. 788 | * The PICC must be selected - ie in state ACTIVE(*) - before calling this function. 789 | * Remember to call PCD_StopCrypto1() after communicating with the authenticated PICC - otherwise no new communications can start. 790 | * 791 | * All keys are set to FFFFFFFFFFFFh at chip delivery. 792 | * 793 | * @return STATUS_OK on success, STATUS_??? otherwise. Probably STATUS_TIMEOUT if you supply the wrong key. 794 | */ 795 | byte MFRC522::PCD_Authenticate(byte command, ///< PICC_CMD_MF_AUTH_KEY_A or PICC_CMD_MF_AUTH_KEY_B 796 | byte blockAddr, ///< The block number. See numbering in the comments in the .h file. 797 | MIFARE_Key *key, ///< Pointer to the Crypteo1 key to use (6 bytes) 798 | Uid *uid ///< Pointer to Uid struct. The first 4 bytes of the UID is used. 799 | ) { 800 | byte waitIRq = 0x10; // IdleIRq 801 | 802 | // Build command buffer 803 | byte sendData[12]; 804 | sendData[0] = command; 805 | sendData[1] = blockAddr; 806 | for (byte i = 0; i < MF_KEY_SIZE; i++) { // 6 key bytes 807 | sendData[2+i] = key->keyByte[i]; 808 | } 809 | for (byte i = 0; i < 4; i++) { // The first 4 bytes of the UID 810 | sendData[8+i] = uid->uidByte[i]; 811 | } 812 | 813 | // Start the authentication. 814 | return PCD_CommunicateWithPICC(PCD_MFAuthent, waitIRq, &sendData[0], sizeof(sendData)); 815 | } // End PCD_Authenticate() 816 | 817 | /** 818 | * Used to exit the PCD from its authenticated state. 819 | * Remember to call this function after communicating with an authenticated PICC - otherwise no new communications can start. 820 | */ 821 | void MFRC522::PCD_StopCrypto1() { 822 | // Clear MFCrypto1On bit 823 | PCD_ClearRegisterBitMask(Status2Reg, 0x08); // Status2Reg[7..0] bits are: TempSensClear I2CForceHS reserved reserved MFCrypto1On ModemState[2:0] 824 | } // End PCD_StopCrypto1() 825 | 826 | /** 827 | * Reads 16 bytes (+ 2 bytes CRC_A) from the active PICC. 828 | * 829 | * For MIFARE Classic the sector containing the block must be authenticated before calling this function. 830 | * 831 | * For MIFARE Ultralight only addresses 00h to 0Fh are decoded. 832 | * The MF0ICU1 returns a NAK for higher addresses. 833 | * The MF0ICU1 responds to the READ command by sending 16 bytes starting from the page address defined by the command argument. 834 | * For example; if blockAddr is 03h then pages 03h, 04h, 05h, 06h are returned. 835 | * A roll-back is implemented: If blockAddr is 0Eh, then the contents of pages 0Eh, 0Fh, 00h and 01h are returned. 836 | * 837 | * The buffer must be at least 18 bytes because a CRC_A is also returned. 838 | * Checks the CRC_A before returning STATUS_OK. 839 | * 840 | * @return STATUS_OK on success, STATUS_??? otherwise. 841 | */ 842 | byte MFRC522::MIFARE_Read( byte blockAddr, ///< MIFARE Classic: The block (0-0xff) number. MIFARE Ultralight: The first page to return data from. 843 | byte *buffer, ///< The buffer to store the data in 844 | byte *bufferSize ///< Buffer size, at least 18 bytes. Also number of bytes returned if STATUS_OK. 845 | ) { 846 | byte result; 847 | 848 | // Sanity check 849 | if (buffer == NULL || *bufferSize < 18) { 850 | return STATUS_NO_ROOM; 851 | } 852 | 853 | // Build command buffer 854 | buffer[0] = PICC_CMD_MF_READ; 855 | buffer[1] = blockAddr; 856 | // Calculate CRC_A 857 | result = PCD_CalculateCRC(buffer, 2, &buffer[2]); 858 | if (result != STATUS_OK) { 859 | return result; 860 | } 861 | 862 | // Transmit the buffer and receive the response, validate CRC_A. 863 | return PCD_TransceiveData(buffer, 4, buffer, bufferSize, NULL, 0, true); 864 | } // End MIFARE_Read() 865 | 866 | /** 867 | * Writes 16 bytes to the active PICC. 868 | * 869 | * For MIFARE Classic the sector containing the block must be authenticated before calling this function. 870 | * 871 | * For MIFARE Ultralight the operation is called "COMPATIBILITY WRITE". 872 | * Even though 16 bytes are transferred to the Ultralight PICC, only the least significant 4 bytes (bytes 0 to 3) 873 | * are written to the specified address. It is recommended to set the remaining bytes 04h to 0Fh to all logic 0. 874 | * * 875 | * @return STATUS_OK on success, STATUS_??? otherwise. 876 | */ 877 | byte MFRC522::MIFARE_Write( byte blockAddr, ///< MIFARE Classic: The block (0-0xff) number. MIFARE Ultralight: The page (2-15) to write to. 878 | byte *buffer, ///< The 16 bytes to write to the PICC 879 | byte bufferSize ///< Buffer size, must be at least 16 bytes. Exactly 16 bytes are written. 880 | ) { 881 | byte result; 882 | 883 | // Sanity check 884 | if (buffer == NULL || bufferSize < 16) { 885 | return STATUS_INVALID; 886 | } 887 | 888 | // Mifare Classic protocol requires two communications to perform a write. 889 | // Step 1: Tell the PICC we want to write to block blockAddr. 890 | byte cmdBuffer[2]; 891 | cmdBuffer[0] = PICC_CMD_MF_WRITE; 892 | cmdBuffer[1] = blockAddr; 893 | result = PCD_MIFARE_Transceive(cmdBuffer, 2); // Adds CRC_A and checks that the response is MF_ACK. 894 | if (result != STATUS_OK) { 895 | return result; 896 | } 897 | 898 | // Step 2: Transfer the data 899 | result = PCD_MIFARE_Transceive(buffer, bufferSize); // Adds CRC_A and checks that the response is MF_ACK. 900 | if (result != STATUS_OK) { 901 | return result; 902 | } 903 | 904 | return STATUS_OK; 905 | } // End MIFARE_Write() 906 | 907 | /** 908 | * Writes a 4 byte page to the active MIFARE Ultralight PICC. 909 | * 910 | * @return STATUS_OK on success, STATUS_??? otherwise. 911 | */ 912 | byte MFRC522::MIFARE_Ultralight_Write( byte page, ///< The page (2-15) to write to. 913 | byte *buffer, ///< The 4 bytes to write to the PICC 914 | byte bufferSize ///< Buffer size, must be at least 4 bytes. Exactly 4 bytes are written. 915 | ) { 916 | byte result; 917 | 918 | // Sanity check 919 | if (buffer == NULL || bufferSize < 4) { 920 | return STATUS_INVALID; 921 | } 922 | 923 | // Build commmand buffer 924 | byte cmdBuffer[6]; 925 | cmdBuffer[0] = PICC_CMD_UL_WRITE; 926 | cmdBuffer[1] = page; 927 | memcpy(&cmdBuffer[2], buffer, 4); 928 | 929 | // Perform the write 930 | result = PCD_MIFARE_Transceive(cmdBuffer, 6); // Adds CRC_A and checks that the response is MF_ACK. 931 | if (result != STATUS_OK) { 932 | return result; 933 | } 934 | return STATUS_OK; 935 | } // End MIFARE_Ultralight_Write() 936 | 937 | /** 938 | * MIFARE Decrement subtracts the delta from the value of the addressed block, and stores the result in a volatile memory. 939 | * For MIFARE Classic only. The sector containing the block must be authenticated before calling this function. 940 | * Only for blocks in "value block" mode, ie with access bits [C1 C2 C3] = [110] or [001]. 941 | * Use MIFARE_Transfer() to store the result in a block. 942 | * 943 | * @return STATUS_OK on success, STATUS_??? otherwise. 944 | */ 945 | byte MFRC522::MIFARE_Decrement( byte blockAddr, ///< The block (0-0xff) number. 946 | long delta ///< This number is subtracted from the value of block blockAddr. 947 | ) { 948 | return MIFARE_TwoStepHelper(PICC_CMD_MF_DECREMENT, blockAddr, delta); 949 | } // End MIFARE_Decrement() 950 | 951 | /** 952 | * MIFARE Increment adds the delta to the value of the addressed block, and stores the result in a volatile memory. 953 | * For MIFARE Classic only. The sector containing the block must be authenticated before calling this function. 954 | * Only for blocks in "value block" mode, ie with access bits [C1 C2 C3] = [110] or [001]. 955 | * Use MIFARE_Transfer() to store the result in a block. 956 | * 957 | * @return STATUS_OK on success, STATUS_??? otherwise. 958 | */ 959 | byte MFRC522::MIFARE_Increment( byte blockAddr, ///< The block (0-0xff) number. 960 | long delta ///< This number is added to the value of block blockAddr. 961 | ) { 962 | return MIFARE_TwoStepHelper(PICC_CMD_MF_INCREMENT, blockAddr, delta); 963 | } // End MIFARE_Increment() 964 | 965 | /** 966 | * MIFARE Restore copies the value of the addressed block into a volatile memory. 967 | * For MIFARE Classic only. The sector containing the block must be authenticated before calling this function. 968 | * Only for blocks in "value block" mode, ie with access bits [C1 C2 C3] = [110] or [001]. 969 | * Use MIFARE_Transfer() to store the result in a block. 970 | * 971 | * @return STATUS_OK on success, STATUS_??? otherwise. 972 | */ 973 | byte MFRC522::MIFARE_Restore( byte blockAddr ///< The block (0-0xff) number. 974 | ) { 975 | // The datasheet describes Restore as a two step operation, but does not explain what data to transfer in step 2. 976 | // Doing only a single step does not work, so I chose to transfer 0L in step two. 977 | return MIFARE_TwoStepHelper(PICC_CMD_MF_RESTORE, blockAddr, 0L); 978 | } // End MIFARE_Restore() 979 | 980 | /** 981 | * Helper function for the two-step MIFARE Classic protocol operations Decrement, Increment and Restore. 982 | * 983 | * @return STATUS_OK on success, STATUS_??? otherwise. 984 | */ 985 | byte MFRC522::MIFARE_TwoStepHelper( byte command, ///< The command to use 986 | byte blockAddr, ///< The block (0-0xff) number. 987 | long data ///< The data to transfer in step 2 988 | ) { 989 | byte result; 990 | byte cmdBuffer[2]; // We only need room for 2 bytes. 991 | 992 | // Step 1: Tell the PICC the command and block address 993 | cmdBuffer[0] = command; 994 | cmdBuffer[1] = blockAddr; 995 | result = PCD_MIFARE_Transceive( cmdBuffer, 2); // Adds CRC_A and checks that the response is MF_ACK. 996 | if (result != STATUS_OK) { 997 | return result; 998 | } 999 | 1000 | // Step 2: Transfer the data 1001 | result = PCD_MIFARE_Transceive( (byte *)&data, 4, true); // Adds CRC_A and accept timeout as success. 1002 | if (result != STATUS_OK) { 1003 | return result; 1004 | } 1005 | 1006 | return STATUS_OK; 1007 | } // End MIFARE_TwoStepHelper() 1008 | 1009 | /** 1010 | * MIFARE Transfer writes the value stored in the volatile memory into one MIFARE Classic block. 1011 | * For MIFARE Classic only. The sector containing the block must be authenticated before calling this function. 1012 | * Only for blocks in "value block" mode, ie with access bits [C1 C2 C3] = [110] or [001]. 1013 | * 1014 | * @return STATUS_OK on success, STATUS_??? otherwise. 1015 | */ 1016 | byte MFRC522::MIFARE_Transfer( byte blockAddr ///< The block (0-0xff) number. 1017 | ) { 1018 | byte result; 1019 | byte cmdBuffer[2]; // We only need room for 2 bytes. 1020 | 1021 | // Tell the PICC we want to transfer the result into block blockAddr. 1022 | cmdBuffer[0] = PICC_CMD_MF_TRANSFER; 1023 | cmdBuffer[1] = blockAddr; 1024 | result = PCD_MIFARE_Transceive( cmdBuffer, 2); // Adds CRC_A and checks that the response is MF_ACK. 1025 | if (result != STATUS_OK) { 1026 | return result; 1027 | } 1028 | return STATUS_OK; 1029 | } // End MIFARE_Transfer() 1030 | 1031 | /** 1032 | * Helper routine to read the current value from a Value Block. 1033 | * 1034 | * Only for MIFARE Classic and only for blocks in "value block" mode, that 1035 | * is: with access bits [C1 C2 C3] = [110] or [001]. The sector containing 1036 | * the block must be authenticated before calling this function. 1037 | * 1038 | * @param[in] blockAddr The block (0x00-0xff) number. 1039 | * @param[out] value Current value of the Value Block. 1040 | * @return STATUS_OK on success, STATUS_??? otherwise. 1041 | */ 1042 | byte MFRC522::MIFARE_GetValue(byte blockAddr, long *value) { 1043 | byte status; 1044 | byte buffer[18]; 1045 | byte size = sizeof(buffer); 1046 | 1047 | // Read the block 1048 | status = MIFARE_Read(blockAddr, buffer, &size); 1049 | if (status == STATUS_OK) { 1050 | // Extract the value 1051 | *value = (long(buffer[3])<<24) | (long(buffer[2])<<16) | (long(buffer[1])<<8) | long(buffer[0]); 1052 | } 1053 | return status; 1054 | } // End MIFARE_GetValue() 1055 | 1056 | /** 1057 | * Helper routine to write a specific value into a Value Block. 1058 | * 1059 | * Only for MIFARE Classic and only for blocks in "value block" mode, that 1060 | * is: with access bits [C1 C2 C3] = [110] or [001]. The sector containing 1061 | * the block must be authenticated before calling this function. 1062 | * 1063 | * @param[in] blockAddr The block (0x00-0xff) number. 1064 | * @param[in] value New value of the Value Block. 1065 | * @return STATUS_OK on success, STATUS_??? otherwise. 1066 | */ 1067 | byte MFRC522::MIFARE_SetValue(byte blockAddr, long value) { 1068 | byte buffer[18]; 1069 | 1070 | // Translate the long into 4 bytes; repeated 2x in value block 1071 | buffer[0] = buffer[ 8] = (value & 0xFF); 1072 | buffer[1] = buffer[ 9] = (value & 0xFF00) >> 8; 1073 | buffer[2] = buffer[10] = (value & 0xFF0000) >> 16; 1074 | buffer[3] = buffer[11] = (value & 0xFF000000) >> 24; 1075 | // Inverse 4 bytes also found in value block 1076 | buffer[4] = ~buffer[0]; 1077 | buffer[5] = ~buffer[1]; 1078 | buffer[6] = ~buffer[2]; 1079 | buffer[7] = ~buffer[3]; 1080 | // Address 2x with inverse address 2x 1081 | buffer[12] = buffer[14] = blockAddr; 1082 | buffer[13] = buffer[15] = ~blockAddr; 1083 | 1084 | // Write the whole data block 1085 | return MIFARE_Write(blockAddr, buffer, 16); 1086 | } // End MIFARE_SetValue() 1087 | 1088 | ///////////////////////////////////////////////////////////////////////////////////// 1089 | // Support functions 1090 | ///////////////////////////////////////////////////////////////////////////////////// 1091 | 1092 | /** 1093 | * Wrapper for MIFARE protocol communication. 1094 | * Adds CRC_A, executes the Transceive command and checks that the response is MF_ACK or a timeout. 1095 | * 1096 | * @return STATUS_OK on success, STATUS_??? otherwise. 1097 | */ 1098 | byte MFRC522::PCD_MIFARE_Transceive( byte *sendData, ///< Pointer to the data to transfer to the FIFO. Do NOT include the CRC_A. 1099 | byte sendLen, ///< Number of bytes in sendData. 1100 | bool acceptTimeout ///< True => A timeout is also success 1101 | ) { 1102 | byte result; 1103 | byte cmdBuffer[18]; // We need room for 16 bytes data and 2 bytes CRC_A. 1104 | 1105 | // Sanity check 1106 | if (sendData == NULL || sendLen > 16) { 1107 | return STATUS_INVALID; 1108 | } 1109 | 1110 | // Copy sendData[] to cmdBuffer[] and add CRC_A 1111 | memcpy(cmdBuffer, sendData, sendLen); 1112 | result = PCD_CalculateCRC(cmdBuffer, sendLen, &cmdBuffer[sendLen]); 1113 | if (result != STATUS_OK) { 1114 | return result; 1115 | } 1116 | sendLen += 2; 1117 | 1118 | // Transceive the data, store the reply in cmdBuffer[] 1119 | byte waitIRq = 0x30; // RxIRq and IdleIRq 1120 | byte cmdBufferSize = sizeof(cmdBuffer); 1121 | byte validBits = 0; 1122 | result = PCD_CommunicateWithPICC(PCD_Transceive, waitIRq, cmdBuffer, sendLen, cmdBuffer, &cmdBufferSize, &validBits); 1123 | if (acceptTimeout && result == STATUS_TIMEOUT) { 1124 | return STATUS_OK; 1125 | } 1126 | if (result != STATUS_OK) { 1127 | return result; 1128 | } 1129 | // The PICC must reply with a 4 bit ACK 1130 | if (cmdBufferSize != 1 || validBits != 4) { 1131 | return STATUS_ERROR; 1132 | } 1133 | if (cmdBuffer[0] != MF_ACK) { 1134 | return STATUS_MIFARE_NACK; 1135 | } 1136 | return STATUS_OK; 1137 | } // End PCD_MIFARE_Transceive() 1138 | 1139 | /** 1140 | * Returns a __FlashStringHelper pointer to a status code name. 1141 | * 1142 | * @return const __FlashStringHelper * 1143 | */ 1144 | const __FlashStringHelper *MFRC522::GetStatusCodeName(byte code ///< One of the StatusCode enums. 1145 | ) { 1146 | switch (code) { 1147 | case STATUS_OK: return F("Success."); break; 1148 | case STATUS_ERROR: return F("Error in communication."); break; 1149 | case STATUS_COLLISION: return F("Collission detected."); break; 1150 | case STATUS_TIMEOUT: return F("Timeout in communication."); break; 1151 | case STATUS_NO_ROOM: return F("A buffer is not big enough."); break; 1152 | case STATUS_INTERNAL_ERROR: return F("Internal error in the code. Should not happen."); break; 1153 | case STATUS_INVALID: return F("Invalid argument."); break; 1154 | case STATUS_CRC_WRONG: return F("The CRC_A does not match."); break; 1155 | case STATUS_MIFARE_NACK: return F("A MIFARE PICC responded with NAK."); break; 1156 | default: return F("Unknown error"); break; 1157 | } 1158 | } // End GetStatusCodeName() 1159 | 1160 | /** 1161 | * Translates the SAK (Select Acknowledge) to a PICC type. 1162 | * 1163 | * @return PICC_Type 1164 | */ 1165 | byte MFRC522::PICC_GetType(byte sak ///< The SAK byte returned from PICC_Select(). 1166 | ) { 1167 | if (sak & 0x04) { // UID not complete 1168 | return PICC_TYPE_NOT_COMPLETE; 1169 | } 1170 | 1171 | switch (sak) { 1172 | case 0x09: return PICC_TYPE_MIFARE_MINI; break; 1173 | case 0x08: return PICC_TYPE_MIFARE_1K; break; 1174 | case 0x18: return PICC_TYPE_MIFARE_4K; break; 1175 | case 0x00: return PICC_TYPE_MIFARE_UL; break; 1176 | case 0x10: 1177 | case 0x11: return PICC_TYPE_MIFARE_PLUS; break; 1178 | case 0x01: return PICC_TYPE_TNP3XXX; break; 1179 | default: break; 1180 | } 1181 | 1182 | if (sak & 0x20) { 1183 | return PICC_TYPE_ISO_14443_4; 1184 | } 1185 | 1186 | if (sak & 0x40) { 1187 | return PICC_TYPE_ISO_18092; 1188 | } 1189 | 1190 | return PICC_TYPE_UNKNOWN; 1191 | } // End PICC_GetType() 1192 | 1193 | /** 1194 | * Returns a __FlashStringHelper pointer to the PICC type name. 1195 | * 1196 | * @return const __FlashStringHelper * 1197 | */ 1198 | const __FlashStringHelper *MFRC522::PICC_GetTypeName(byte piccType ///< One of the PICC_Type enums. 1199 | ) { 1200 | switch (piccType) { 1201 | case PICC_TYPE_ISO_14443_4: return F("PICC compliant with ISO/IEC 14443-4"); break; 1202 | case PICC_TYPE_ISO_18092: return F("PICC compliant with ISO/IEC 18092 (NFC)");break; 1203 | case PICC_TYPE_MIFARE_MINI: return F("MIFARE Mini, 320 bytes"); break; 1204 | case PICC_TYPE_MIFARE_1K: return F("MIFARE 1KB"); break; 1205 | case PICC_TYPE_MIFARE_4K: return F("MIFARE 4KB"); break; 1206 | case PICC_TYPE_MIFARE_UL: return F("MIFARE Ultralight or Ultralight C"); break; 1207 | case PICC_TYPE_MIFARE_PLUS: return F("MIFARE Plus"); break; 1208 | case PICC_TYPE_TNP3XXX: return F("MIFARE TNP3XXX"); break; 1209 | case PICC_TYPE_NOT_COMPLETE: return F("SAK indicates UID is not complete."); break; 1210 | case PICC_TYPE_UNKNOWN: 1211 | default: return F("Unknown type"); break; 1212 | } 1213 | } // End PICC_GetTypeName() 1214 | 1215 | /** 1216 | * Dumps debug info about the selected PICC to Serial. 1217 | * On success the PICC is halted after dumping the data. 1218 | * For MIFARE Classic the factory default key of 0xFFFFFFFFFFFF is tried. 1219 | */ 1220 | void MFRC522::PICC_DumpToSerial(Uid *uid ///< Pointer to Uid struct returned from a successful PICC_Select(). 1221 | ) { 1222 | MIFARE_Key key; 1223 | 1224 | // UID 1225 | Serial.print(F("Card UID:")); 1226 | for (byte i = 0; i < uid->size; i++) { 1227 | if(uid->uidByte[i] < 0x10) 1228 | Serial.print(F(" 0")); 1229 | else 1230 | Serial.print(F(" ")); 1231 | Serial.print(uid->uidByte[i], HEX); 1232 | } 1233 | Serial.println(); 1234 | 1235 | // PICC type 1236 | byte piccType = PICC_GetType(uid->sak); 1237 | Serial.print(F("PICC type: ")); 1238 | Serial.println(PICC_GetTypeName(piccType)); 1239 | 1240 | // Dump contents 1241 | switch (piccType) { 1242 | case PICC_TYPE_MIFARE_MINI: 1243 | case PICC_TYPE_MIFARE_1K: 1244 | case PICC_TYPE_MIFARE_4K: 1245 | // All keys are set to FFFFFFFFFFFFh at chip delivery from the factory. 1246 | for (byte i = 0; i < 6; i++) { 1247 | key.keyByte[i] = 0xFF; 1248 | } 1249 | PICC_DumpMifareClassicToSerial(uid, piccType, &key); 1250 | break; 1251 | 1252 | case PICC_TYPE_MIFARE_UL: 1253 | PICC_DumpMifareUltralightToSerial(); 1254 | break; 1255 | 1256 | case PICC_TYPE_ISO_14443_4: 1257 | case PICC_TYPE_ISO_18092: 1258 | case PICC_TYPE_MIFARE_PLUS: 1259 | case PICC_TYPE_TNP3XXX: 1260 | Serial.println(F("Dumping memory contents not implemented for that PICC type.")); 1261 | break; 1262 | 1263 | case PICC_TYPE_UNKNOWN: 1264 | case PICC_TYPE_NOT_COMPLETE: 1265 | default: 1266 | break; // No memory dump here 1267 | } 1268 | 1269 | Serial.println(); 1270 | PICC_HaltA(); // Already done if it was a MIFARE Classic PICC. 1271 | } // End PICC_DumpToSerial() 1272 | 1273 | /** 1274 | * Dumps memory contents of a MIFARE Classic PICC. 1275 | * On success the PICC is halted after dumping the data. 1276 | */ 1277 | void MFRC522::PICC_DumpMifareClassicToSerial( Uid *uid, ///< Pointer to Uid struct returned from a successful PICC_Select(). 1278 | byte piccType, ///< One of the PICC_Type enums. 1279 | MIFARE_Key *key ///< Key A used for all sectors. 1280 | ) { 1281 | byte no_of_sectors = 0; 1282 | switch (piccType) { 1283 | case PICC_TYPE_MIFARE_MINI: 1284 | // Has 5 sectors * 4 blocks/sector * 16 bytes/block = 320 bytes. 1285 | no_of_sectors = 5; 1286 | break; 1287 | 1288 | case PICC_TYPE_MIFARE_1K: 1289 | // Has 16 sectors * 4 blocks/sector * 16 bytes/block = 1024 bytes. 1290 | no_of_sectors = 16; 1291 | break; 1292 | 1293 | case PICC_TYPE_MIFARE_4K: 1294 | // Has (32 sectors * 4 blocks/sector + 8 sectors * 16 blocks/sector) * 16 bytes/block = 4096 bytes. 1295 | no_of_sectors = 40; 1296 | break; 1297 | 1298 | default: // Should not happen. Ignore. 1299 | break; 1300 | } 1301 | 1302 | // Dump sectors, highest address first. 1303 | if (no_of_sectors) { 1304 | Serial.println(F("Sector Block 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 AccessBits")); 1305 | for (int8_t i = no_of_sectors - 1; i >= 0; i--) { 1306 | PICC_DumpMifareClassicSectorToSerial(uid, key, i); 1307 | } 1308 | } 1309 | PICC_HaltA(); // Halt the PICC before stopping the encrypted session. 1310 | PCD_StopCrypto1(); 1311 | } // End PICC_DumpMifareClassicToSerial() 1312 | 1313 | /** 1314 | * Dumps memory contents of a sector of a MIFARE Classic PICC. 1315 | * Uses PCD_Authenticate(), MIFARE_Read() and PCD_StopCrypto1. 1316 | * Always uses PICC_CMD_MF_AUTH_KEY_A because only Key A can always read the sector trailer access bits. 1317 | */ 1318 | void MFRC522::PICC_DumpMifareClassicSectorToSerial(Uid *uid, ///< Pointer to Uid struct returned from a successful PICC_Select(). 1319 | MIFARE_Key *key, ///< Key A for the sector. 1320 | byte sector ///< The sector to dump, 0..39. 1321 | ) { 1322 | byte status; 1323 | byte firstBlock; // Address of lowest address to dump actually last block dumped) 1324 | byte no_of_blocks; // Number of blocks in sector 1325 | bool isSectorTrailer; // Set to true while handling the "last" (ie highest address) in the sector. 1326 | 1327 | // The access bits are stored in a peculiar fashion. 1328 | // There are four groups: 1329 | // g[3] Access bits for the sector trailer, block 3 (for sectors 0-31) or block 15 (for sectors 32-39) 1330 | // g[2] Access bits for block 2 (for sectors 0-31) or blocks 10-14 (for sectors 32-39) 1331 | // g[1] Access bits for block 1 (for sectors 0-31) or blocks 5-9 (for sectors 32-39) 1332 | // g[0] Access bits for block 0 (for sectors 0-31) or blocks 0-4 (for sectors 32-39) 1333 | // Each group has access bits [C1 C2 C3]. In this code C1 is MSB and C3 is LSB. 1334 | // The four CX bits are stored together in a nible cx and an inverted nible cx_. 1335 | byte c1, c2, c3; // Nibbles 1336 | byte c1_, c2_, c3_; // Inverted nibbles 1337 | bool invertedError; // True if one of the inverted nibbles did not match 1338 | byte g[4]; // Access bits for each of the four groups. 1339 | byte group; // 0-3 - active group for access bits 1340 | bool firstInGroup; // True for the first block dumped in the group 1341 | 1342 | // Determine position and size of sector. 1343 | if (sector < 32) { // Sectors 0..31 has 4 blocks each 1344 | no_of_blocks = 4; 1345 | firstBlock = sector * no_of_blocks; 1346 | } 1347 | else if (sector < 40) { // Sectors 32-39 has 16 blocks each 1348 | no_of_blocks = 16; 1349 | firstBlock = 128 + (sector - 32) * no_of_blocks; 1350 | } 1351 | else { // Illegal input, no MIFARE Classic PICC has more than 40 sectors. 1352 | return; 1353 | } 1354 | 1355 | // Dump blocks, highest address first. 1356 | byte byteCount; 1357 | byte buffer[18]; 1358 | byte blockAddr; 1359 | isSectorTrailer = true; 1360 | for (int8_t blockOffset = no_of_blocks - 1; blockOffset >= 0; blockOffset--) { 1361 | blockAddr = firstBlock + blockOffset; 1362 | // Sector number - only on first line 1363 | if (isSectorTrailer) { 1364 | if(sector < 10) 1365 | Serial.print(F(" ")); // Pad with spaces 1366 | else 1367 | Serial.print(F(" ")); // Pad with spaces 1368 | Serial.print(sector); 1369 | Serial.print(F(" ")); 1370 | } 1371 | else { 1372 | Serial.print(F(" ")); 1373 | } 1374 | // Block number 1375 | if(blockAddr < 10) 1376 | Serial.print(F(" ")); // Pad with spaces 1377 | else { 1378 | if(blockAddr < 100) 1379 | Serial.print(F(" ")); // Pad with spaces 1380 | else 1381 | Serial.print(F(" ")); // Pad with spaces 1382 | } 1383 | Serial.print(blockAddr); 1384 | Serial.print(F(" ")); 1385 | // Establish encrypted communications before reading the first block 1386 | if (isSectorTrailer) { 1387 | status = PCD_Authenticate(PICC_CMD_MF_AUTH_KEY_A, firstBlock, key, uid); 1388 | if (status != STATUS_OK) { 1389 | Serial.print(F("PCD_Authenticate() failed: ")); 1390 | Serial.println(GetStatusCodeName(status)); 1391 | return; 1392 | } 1393 | } 1394 | // Read block 1395 | byteCount = sizeof(buffer); 1396 | status = MIFARE_Read(blockAddr, buffer, &byteCount); 1397 | if (status != STATUS_OK) { 1398 | Serial.print(F("MIFARE_Read() failed: ")); 1399 | Serial.println(GetStatusCodeName(status)); 1400 | continue; 1401 | } 1402 | // Dump data 1403 | for (byte index = 0; index < 16; index++) { 1404 | if(buffer[index] < 0x10) 1405 | Serial.print(F(" 0")); 1406 | else 1407 | Serial.print(F(" ")); 1408 | Serial.print(buffer[index], HEX); 1409 | if ((index % 4) == 3) { 1410 | Serial.print(F(" ")); 1411 | } 1412 | } 1413 | // Parse sector trailer data 1414 | if (isSectorTrailer) { 1415 | c1 = buffer[7] >> 4; 1416 | c2 = buffer[8] & 0xF; 1417 | c3 = buffer[8] >> 4; 1418 | c1_ = buffer[6] & 0xF; 1419 | c2_ = buffer[6] >> 4; 1420 | c3_ = buffer[7] & 0xF; 1421 | invertedError = (c1 != (~c1_ & 0xF)) || (c2 != (~c2_ & 0xF)) || (c3 != (~c3_ & 0xF)); 1422 | g[0] = ((c1 & 1) << 2) | ((c2 & 1) << 1) | ((c3 & 1) << 0); 1423 | g[1] = ((c1 & 2) << 1) | ((c2 & 2) << 0) | ((c3 & 2) >> 1); 1424 | g[2] = ((c1 & 4) << 0) | ((c2 & 4) >> 1) | ((c3 & 4) >> 2); 1425 | g[3] = ((c1 & 8) >> 1) | ((c2 & 8) >> 2) | ((c3 & 8) >> 3); 1426 | isSectorTrailer = false; 1427 | } 1428 | 1429 | // Which access group is this block in? 1430 | if (no_of_blocks == 4) { 1431 | group = blockOffset; 1432 | firstInGroup = true; 1433 | } 1434 | else { 1435 | group = blockOffset / 5; 1436 | firstInGroup = (group == 3) || (group != (blockOffset + 1) / 5); 1437 | } 1438 | 1439 | if (firstInGroup) { 1440 | // Print access bits 1441 | Serial.print(F(" [ ")); 1442 | Serial.print((g[group] >> 2) & 1, DEC); Serial.print(F(" ")); 1443 | Serial.print((g[group] >> 1) & 1, DEC); Serial.print(F(" ")); 1444 | Serial.print((g[group] >> 0) & 1, DEC); 1445 | Serial.print(F(" ] ")); 1446 | if (invertedError) { 1447 | Serial.print(F(" Inverted access bits did not match! ")); 1448 | } 1449 | } 1450 | 1451 | if (group != 3 && (g[group] == 1 || g[group] == 6)) { // Not a sector trailer, a value block 1452 | long value = (long(buffer[3])<<24) | (long(buffer[2])<<16) | (long(buffer[1])<<8) | long(buffer[0]); 1453 | Serial.print(F(" Value=0x")); Serial.print(value, HEX); 1454 | Serial.print(F(" Adr=0x")); Serial.print(buffer[12], HEX); 1455 | } 1456 | Serial.println(); 1457 | } 1458 | 1459 | return; 1460 | } // End PICC_DumpMifareClassicSectorToSerial() 1461 | 1462 | /** 1463 | * Dumps memory contents of a MIFARE Ultralight PICC. 1464 | */ 1465 | void MFRC522::PICC_DumpMifareUltralightToSerial() { 1466 | byte status; 1467 | byte byteCount; 1468 | byte buffer[18]; 1469 | byte i; 1470 | 1471 | Serial.println(F("Page 0 1 2 3")); 1472 | // Try the mpages of the original Ultralight. Ultralight C has more pages. 1473 | for (byte page = 0; page < 16; page +=4) { // Read returns data for 4 pages at a time. 1474 | // Read pages 1475 | byteCount = sizeof(buffer); 1476 | status = MIFARE_Read(page, buffer, &byteCount); 1477 | if (status != STATUS_OK) { 1478 | Serial.print(F("MIFARE_Read() failed: ")); 1479 | Serial.println(GetStatusCodeName(status)); 1480 | break; 1481 | } 1482 | // Dump data 1483 | for (byte offset = 0; offset < 4; offset++) { 1484 | i = page + offset; 1485 | if(i < 10) 1486 | Serial.print(F(" ")); // Pad with spaces 1487 | else 1488 | Serial.print(F(" ")); // Pad with spaces 1489 | Serial.print(i); 1490 | Serial.print(F(" ")); 1491 | for (byte index = 0; index < 4; index++) { 1492 | i = 4 * offset + index; 1493 | if(buffer[i] < 0x10) 1494 | Serial.print(F(" 0")); 1495 | else 1496 | Serial.print(F(" ")); 1497 | Serial.print(buffer[i], HEX); 1498 | } 1499 | Serial.println(); 1500 | } 1501 | } 1502 | } // End PICC_DumpMifareUltralightToSerial() 1503 | 1504 | /** 1505 | * Calculates the bit pattern needed for the specified access bits. In the [C1 C2 C3] tupples C1 is MSB (=4) and C3 is LSB (=1). 1506 | */ 1507 | void MFRC522::MIFARE_SetAccessBits( byte *accessBitBuffer, ///< Pointer to byte 6, 7 and 8 in the sector trailer. Bytes [0..2] will be set. 1508 | byte g0, ///< Access bits [C1 C2 C3] for block 0 (for sectors 0-31) or blocks 0-4 (for sectors 32-39) 1509 | byte g1, ///< Access bits C1 C2 C3] for block 1 (for sectors 0-31) or blocks 5-9 (for sectors 32-39) 1510 | byte g2, ///< Access bits C1 C2 C3] for block 2 (for sectors 0-31) or blocks 10-14 (for sectors 32-39) 1511 | byte g3 ///< Access bits C1 C2 C3] for the sector trailer, block 3 (for sectors 0-31) or block 15 (for sectors 32-39) 1512 | ) { 1513 | byte c1 = ((g3 & 4) << 1) | ((g2 & 4) << 0) | ((g1 & 4) >> 1) | ((g0 & 4) >> 2); 1514 | byte c2 = ((g3 & 2) << 2) | ((g2 & 2) << 1) | ((g1 & 2) << 0) | ((g0 & 2) >> 1); 1515 | byte c3 = ((g3 & 1) << 3) | ((g2 & 1) << 2) | ((g1 & 1) << 1) | ((g0 & 1) << 0); 1516 | 1517 | accessBitBuffer[0] = (~c2 & 0xF) << 4 | (~c1 & 0xF); 1518 | accessBitBuffer[1] = c1 << 4 | (~c3 & 0xF); 1519 | accessBitBuffer[2] = c3 << 4 | c2; 1520 | } // End MIFARE_SetAccessBits() 1521 | 1522 | 1523 | /** 1524 | * Performs the "magic sequence" needed to get Chinese UID changeable 1525 | * Mifare cards to allow writing to sector 0, where the card UID is stored. 1526 | * 1527 | * Note that you do not need to have selected the card through REQA or WUPA, 1528 | * this sequence works immediately when the card is in the reader vicinity. 1529 | * This means you can use this method even on "bricked" cards that your reader does 1530 | * not recognise anymore (see MFRC522::MIFARE_UnbrickUidSector). 1531 | * 1532 | * Of course with non-bricked devices, you're free to select them before calling this function. 1533 | */ 1534 | bool MFRC522::MIFARE_OpenUidBackdoor(bool logErrors) { 1535 | // Magic sequence: 1536 | // > 50 00 57 CD (HALT + CRC) 1537 | // > 40 (7 bits only) 1538 | // < A (4 bits only) 1539 | // > 43 1540 | // < A (4 bits only) 1541 | // Then you can write to sector 0 without authenticating 1542 | 1543 | PICC_HaltA(); // 50 00 57 CD 1544 | 1545 | byte cmd = 0x40; 1546 | byte validBits = 7; /* Our command is only 7 bits. After receiving card response, 1547 | this will contain amount of valid response bits. */ 1548 | byte response[32]; // Card's response is written here 1549 | byte received; 1550 | byte status = PCD_TransceiveData(&cmd, (byte)1, response, &received, &validBits, (byte)0, false); // 40 1551 | if(status != STATUS_OK) { 1552 | if(logErrors) { 1553 | Serial.println(F("Card did not respond to 0x40 after HALT command. Are you sure it is a UID changeable one?")); 1554 | Serial.print(F("Error name: ")); 1555 | Serial.println(GetStatusCodeName(status)); 1556 | } 1557 | return false; 1558 | } 1559 | if (received != 1 || response[0] != 0x0A) { 1560 | if (logErrors) { 1561 | Serial.print(F("Got bad response on backdoor 0x40 command: ")); 1562 | Serial.print(response[0], HEX); 1563 | Serial.print(F(" (")); 1564 | Serial.print(validBits); 1565 | Serial.print(F(" valid bits)\r\n")); 1566 | } 1567 | return false; 1568 | } 1569 | 1570 | cmd = 0x43; 1571 | validBits = 8; 1572 | status = PCD_TransceiveData(&cmd, (byte)1, response, &received, &validBits, (byte)0, false); // 43 1573 | if(status != STATUS_OK) { 1574 | if(logErrors) { 1575 | Serial.println(F("Error in communication at command 0x43, after successfully executing 0x40")); 1576 | Serial.print(F("Error name: ")); 1577 | Serial.println(GetStatusCodeName(status)); 1578 | } 1579 | return false; 1580 | } 1581 | if (received != 1 || response[0] != 0x0A) { 1582 | if (logErrors) { 1583 | Serial.print(F("Got bad response on backdoor 0x43 command: ")); 1584 | Serial.print(response[0], HEX); 1585 | Serial.print(F(" (")); 1586 | Serial.print(validBits); 1587 | Serial.print(F(" valid bits)\r\n")); 1588 | } 1589 | return false; 1590 | } 1591 | 1592 | // You can now write to sector 0 without authenticating! 1593 | return true; 1594 | } // End MIFARE_OpenUidBackdoor() 1595 | 1596 | /** 1597 | * Reads entire block 0, including all manufacturer data, and overwrites 1598 | * that block with the new UID, a freshly calculated BCC, and the original 1599 | * manufacturer data. 1600 | * 1601 | * It assumes a default KEY A of 0xFFFFFFFFFFFF. 1602 | * Make sure to have selected the card before this function is called. 1603 | */ 1604 | bool MFRC522::MIFARE_SetUid(byte *newUid, byte uidSize, bool logErrors) { 1605 | 1606 | // UID + BCC byte can not be larger than 16 together 1607 | if (!newUid || !uidSize || uidSize > 15) { 1608 | if (logErrors) { 1609 | Serial.println(F("New UID buffer empty, size 0, or size > 15 given")); 1610 | } 1611 | return false; 1612 | } 1613 | 1614 | // Authenticate for reading 1615 | MIFARE_Key key = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; 1616 | byte status = PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, (byte)1, &key, &uid); 1617 | if (status != STATUS_OK) { 1618 | 1619 | if (status == STATUS_TIMEOUT) { 1620 | // We get a read timeout if no card is selected yet, so let's select one 1621 | 1622 | // Wake the card up again if sleeping 1623 | // byte atqa_answer[2]; 1624 | // byte atqa_size = 2; 1625 | // PICC_WakeupA(atqa_answer, &atqa_size); 1626 | 1627 | if (!PICC_IsNewCardPresent() || !PICC_ReadCardSerial()) { 1628 | Serial.println(F("No card was previously selected, and none are available. Failed to set UID.")); 1629 | return false; 1630 | } 1631 | 1632 | status = PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, (byte)1, &key, &uid); 1633 | if (status != STATUS_OK) { 1634 | // We tried, time to give up 1635 | if (logErrors) { 1636 | Serial.println(F("Failed to authenticate to card for reading, could not set UID: ")); 1637 | Serial.println(GetStatusCodeName(status)); 1638 | } 1639 | return false; 1640 | } 1641 | } 1642 | else { 1643 | if (logErrors) { 1644 | Serial.print(F("PCD_Authenticate() failed: ")); 1645 | Serial.println(GetStatusCodeName(status)); 1646 | } 1647 | return false; 1648 | } 1649 | } 1650 | 1651 | // Read block 0 1652 | byte block0_buffer[18]; 1653 | byte byteCount = sizeof(block0_buffer); 1654 | status = MIFARE_Read((byte)0, block0_buffer, &byteCount); 1655 | if (status != STATUS_OK) { 1656 | if (logErrors) { 1657 | Serial.print(F("MIFARE_Read() failed: ")); 1658 | Serial.println(GetStatusCodeName(status)); 1659 | Serial.println(F("Are you sure your KEY A for sector 0 is 0xFFFFFFFFFFFF?")); 1660 | } 1661 | return false; 1662 | } 1663 | 1664 | // Write new UID to the data we just read, and calculate BCC byte 1665 | byte bcc = 0; 1666 | for (int i = 0; i < uidSize; i++) { 1667 | block0_buffer[i] = newUid[i]; 1668 | bcc ^= newUid[i]; 1669 | } 1670 | 1671 | // Write BCC byte to buffer 1672 | block0_buffer[uidSize] = bcc; 1673 | 1674 | // Stop encrypted traffic so we can send raw bytes 1675 | PCD_StopCrypto1(); 1676 | 1677 | // Activate UID backdoor 1678 | if (!MIFARE_OpenUidBackdoor(logErrors)) { 1679 | if (logErrors) { 1680 | Serial.println(F("Activating the UID backdoor failed.")); 1681 | } 1682 | return false; 1683 | } 1684 | 1685 | // Write modified block 0 back to card 1686 | status = MIFARE_Write((byte)0, block0_buffer, (byte)16); 1687 | if (status != STATUS_OK) { 1688 | if (logErrors) { 1689 | Serial.print(F("MIFARE_Write() failed: ")); 1690 | Serial.println(GetStatusCodeName(status)); 1691 | } 1692 | return false; 1693 | } 1694 | 1695 | // Wake the card up again 1696 | byte atqa_answer[2]; 1697 | byte atqa_size = 2; 1698 | PICC_WakeupA(atqa_answer, &atqa_size); 1699 | 1700 | return true; 1701 | } 1702 | 1703 | /** 1704 | * Resets entire sector 0 to zeroes, so the card can be read again by readers. 1705 | */ 1706 | bool MFRC522::MIFARE_UnbrickUidSector(bool logErrors) { 1707 | MIFARE_OpenUidBackdoor(logErrors); 1708 | 1709 | byte block0_buffer[] = {0x01, 0x02, 0x03, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 1710 | 1711 | // Write modified block 0 back to card 1712 | byte status = MIFARE_Write((byte)0, block0_buffer, (byte)16); 1713 | if (status != STATUS_OK) { 1714 | if (logErrors) { 1715 | Serial.print(F("MIFARE_Write() failed: ")); 1716 | Serial.println(GetStatusCodeName(status)); 1717 | } 1718 | return false; 1719 | } 1720 | return true; 1721 | } 1722 | 1723 | ///////////////////////////////////////////////////////////////////////////////////// 1724 | // Convenience functions - does not add extra functionality 1725 | ///////////////////////////////////////////////////////////////////////////////////// 1726 | 1727 | /** 1728 | * Returns true if a PICC responds to PICC_CMD_REQA. 1729 | * Only "new" cards in state IDLE are invited. Sleeping cards in state HALT are ignored. 1730 | * 1731 | * @return bool 1732 | */ 1733 | bool MFRC522::PICC_IsNewCardPresent() { 1734 | byte bufferATQA[2]; 1735 | byte bufferSize = sizeof(bufferATQA); 1736 | byte result = PICC_RequestA(bufferATQA, &bufferSize); 1737 | return (result == STATUS_OK || result == STATUS_COLLISION); 1738 | } // End PICC_IsNewCardPresent() 1739 | 1740 | /** 1741 | * Simple wrapper around PICC_Select. 1742 | * Returns true if a UID could be read. 1743 | * Remember to call PICC_IsNewCardPresent(), PICC_RequestA() or PICC_WakeupA() first. 1744 | * The read UID is available in the class variable uid. 1745 | * 1746 | * @return bool 1747 | */ 1748 | bool MFRC522::PICC_ReadCardSerial() { 1749 | byte result = PICC_Select(&uid); 1750 | return (result == STATUS_OK); 1751 | } // End PICC_ReadCardSerial() 1752 | -------------------------------------------------------------------------------- /MFRC522_I2C.h: -------------------------------------------------------------------------------- 1 | /** 2 | * MFRC522_I2C.h - Library to use ARDUINO RFID MODULE KIT 13.56 MHZ WITH TAGS I2C BY AROZCAN 3 | * MFRC522_I2C.h - Based on ARDUINO RFID MODULE KIT 13.56 MHZ WITH TAGS SPI Library BY COOQROBOT. 4 | * Based on code Dr.Leong ( WWW.B2CQSHOP.COM ) 5 | * Created by Miguel Balboa (circuitito.com), Jan, 2012. 6 | * Rewritten by Søren Thing Andersen (access.thing.dk), fall of 2013 (Translation to English, refactored, comments, anti collision, cascade levels.) 7 | * Extended by Tom Clement with functionality to write to sector 0 of UID changeable Mifare cards. 8 | * Extended by Ahmet Remzi Ozcan with I2C functionality. 9 | * Author: arozcan @ https://github.com/arozcan/MFRC522-I2C-Library 10 | * Released into the public domain. 11 | * 12 | * Please read this file for an overview and then MFRC522.cpp for comments on the specific functions. 13 | * Search for "mf-rc522" on ebay.com to purchase the MF-RC522 board. 14 | * 15 | * There are three hardware components involved: 16 | * 1) The micro controller: An Arduino 17 | * 2) The PCD (short for Proximity Coupling Device): NXP MFRC522 Contactless Reader IC 18 | * 3) The PICC (short for Proximity Integrated Circuit Card): A card or tag using the ISO 14443A interface, eg Mifare or NTAG203. 19 | * 20 | * The microcontroller and card reader uses I2C for communication. 21 | * The protocol is described in the MFRC522 datasheet: http://www.nxp.com/documents/data_sheet/MFRC522.pdf 22 | * 23 | * The card reader and the tags communicate using a 13.56MHz electromagnetic field. 24 | * The protocol is defined in ISO/IEC 14443-3 Identification cards -- Contactless integrated circuit cards -- Proximity cards -- Part 3: Initialization and anticollision". 25 | * A free version of the final draft can be found at http://wg8.de/wg8n1496_17n3613_Ballot_FCD14443-3.pdf 26 | * Details are found in chapter 6, Type A – Initialization and anticollision. 27 | * 28 | * If only the PICC UID is wanted, the above documents has all the needed information. 29 | * To read and write from MIFARE PICCs, the MIFARE protocol is used after the PICC has been selected. 30 | * The MIFARE Classic chips and protocol is described in the datasheets: 31 | * 1K: http://www.nxp.com/documents/data_sheet/MF1S503x.pdf 32 | * 4K: http://www.nxp.com/documents/data_sheet/MF1S703x.pdf 33 | * Mini: http://www.idcardmarket.com/download/mifare_S20_datasheet.pdf 34 | * The MIFARE Ultralight chip and protocol is described in the datasheets: 35 | * Ultralight: http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf 36 | * Ultralight C: http://www.nxp.com/documents/short_data_sheet/MF0ICU2_SDS.pdf 37 | * 38 | * MIFARE Classic 1K (MF1S503x): 39 | * Has 16 sectors * 4 blocks/sector * 16 bytes/block = 1024 bytes. 40 | * The blocks are numbered 0-63. 41 | * Block 3 in each sector is the Sector Trailer. See http://www.nxp.com/documents/data_sheet/MF1S503x.pdf sections 8.6 and 8.7: 42 | * Bytes 0-5: Key A 43 | * Bytes 6-8: Access Bits 44 | * Bytes 9: User data 45 | * Bytes 10-15: Key B (or user data) 46 | * Block 0 is read-only manufacturer data. 47 | * To access a block, an authentication using a key from the block's sector must be performed first. 48 | * Example: To read from block 10, first authenticate using a key from sector 3 (blocks 8-11). 49 | * All keys are set to FFFFFFFFFFFFh at chip delivery. 50 | * Warning: Please read section 8.7 "Memory Access". It includes this text: if the PICC detects a format violation the whole sector is irreversibly blocked. 51 | * To use a block in "value block" mode (for Increment/Decrement operations) you need to change the sector trailer. Use PICC_SetAccessBits() to calculate the bit patterns. 52 | * MIFARE Classic 4K (MF1S703x): 53 | * Has (32 sectors * 4 blocks/sector + 8 sectors * 16 blocks/sector) * 16 bytes/block = 4096 bytes. 54 | * The blocks are numbered 0-255. 55 | * The last block in each sector is the Sector Trailer like above. 56 | * MIFARE Classic Mini (MF1 IC S20): 57 | * Has 5 sectors * 4 blocks/sector * 16 bytes/block = 320 bytes. 58 | * The blocks are numbered 0-19. 59 | * The last block in each sector is the Sector Trailer like above. 60 | * 61 | * MIFARE Ultralight (MF0ICU1): 62 | * Has 16 pages of 4 bytes = 64 bytes. 63 | * Pages 0 + 1 is used for the 7-byte UID. 64 | * Page 2 contains the last check digit for the UID, one byte manufacturer internal data, and the lock bytes (see http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf section 8.5.2) 65 | * Page 3 is OTP, One Time Programmable bits. Once set to 1 they cannot revert to 0. 66 | * Pages 4-15 are read/write unless blocked by the lock bytes in page 2. 67 | * MIFARE Ultralight C (MF0ICU2): 68 | * Has 48 pages of 4 bytes = 192 bytes. 69 | * Pages 0 + 1 is used for the 7-byte UID. 70 | * Page 2 contains the last check digit for the UID, one byte manufacturer internal data, and the lock bytes (see http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf section 8.5.2) 71 | * Page 3 is OTP, One Time Programmable bits. Once set to 1 they cannot revert to 0. 72 | * Pages 4-39 are read/write unless blocked by the lock bytes in page 2. 73 | * Page 40 Lock bytes 74 | * Page 41 16 bit one way counter 75 | * Pages 42-43 Authentication configuration 76 | * Pages 44-47 Authentication key 77 | */ 78 | #ifndef MFRC522_h 79 | #define MFRC522_h 80 | 81 | #include 82 | #include 83 | 84 | // Firmware data for self-test 85 | // Reference values based on firmware version 86 | // Hint: if needed, you can remove unused self-test data to save flash memory 87 | // 88 | // Version 0.0 (0x90) 89 | // Philips Semiconductors; Preliminary Specification Revision 2.0 - 01 August 2005; 16.1 Sefttest 90 | const byte MFRC522_firmware_referenceV0_0[] PROGMEM = { 91 | 0x00, 0x87, 0x98, 0x0f, 0x49, 0xFF, 0x07, 0x19, 92 | 0xBF, 0x22, 0x30, 0x49, 0x59, 0x63, 0xAD, 0xCA, 93 | 0x7F, 0xE3, 0x4E, 0x03, 0x5C, 0x4E, 0x49, 0x50, 94 | 0x47, 0x9A, 0x37, 0x61, 0xE7, 0xE2, 0xC6, 0x2E, 95 | 0x75, 0x5A, 0xED, 0x04, 0x3D, 0x02, 0x4B, 0x78, 96 | 0x32, 0xFF, 0x58, 0x3B, 0x7C, 0xE9, 0x00, 0x94, 97 | 0xB4, 0x4A, 0x59, 0x5B, 0xFD, 0xC9, 0x29, 0xDF, 98 | 0x35, 0x96, 0x98, 0x9E, 0x4F, 0x30, 0x32, 0x8D 99 | }; 100 | // Version 1.0 (0x91) 101 | // NXP Semiconductors; Rev. 3.8 - 17 September 2014; 16.1.1 Self test 102 | const byte MFRC522_firmware_referenceV1_0[] PROGMEM = { 103 | 0x00, 0xC6, 0x37, 0xD5, 0x32, 0xB7, 0x57, 0x5C, 104 | 0xC2, 0xD8, 0x7C, 0x4D, 0xD9, 0x70, 0xC7, 0x73, 105 | 0x10, 0xE6, 0xD2, 0xAA, 0x5E, 0xA1, 0x3E, 0x5A, 106 | 0x14, 0xAF, 0x30, 0x61, 0xC9, 0x70, 0xDB, 0x2E, 107 | 0x64, 0x22, 0x72, 0xB5, 0xBD, 0x65, 0xF4, 0xEC, 108 | 0x22, 0xBC, 0xD3, 0x72, 0x35, 0xCD, 0xAA, 0x41, 109 | 0x1F, 0xA7, 0xF3, 0x53, 0x14, 0xDE, 0x7E, 0x02, 110 | 0xD9, 0x0F, 0xB5, 0x5E, 0x25, 0x1D, 0x29, 0x79 111 | }; 112 | // Version 2.0 (0x92) 113 | // NXP Semiconductors; Rev. 3.8 - 17 September 2014; 16.1.1 Self test 114 | const byte MFRC522_firmware_referenceV2_0[] PROGMEM = { 115 | 0x00, 0xEB, 0x66, 0xBA, 0x57, 0xBF, 0x23, 0x95, 116 | 0xD0, 0xE3, 0x0D, 0x3D, 0x27, 0x89, 0x5C, 0xDE, 117 | 0x9D, 0x3B, 0xA7, 0x00, 0x21, 0x5B, 0x89, 0x82, 118 | 0x51, 0x3A, 0xEB, 0x02, 0x0C, 0xA5, 0x00, 0x49, 119 | 0x7C, 0x84, 0x4D, 0xB3, 0xCC, 0xD2, 0x1B, 0x81, 120 | 0x5D, 0x48, 0x76, 0xD5, 0x71, 0x61, 0x21, 0xA9, 121 | 0x86, 0x96, 0x83, 0x38, 0xCF, 0x9D, 0x5B, 0x6D, 122 | 0xDC, 0x15, 0xBA, 0x3E, 0x7D, 0x95, 0x3B, 0x2F 123 | }; 124 | // Clone 125 | // Fudan Semiconductor FM17522 (0x88) 126 | const byte FM17522_firmware_reference[] PROGMEM = { 127 | 0x00, 0xD6, 0x78, 0x8C, 0xE2, 0xAA, 0x0C, 0x18, 128 | 0x2A, 0xB8, 0x7A, 0x7F, 0xD3, 0x6A, 0xCF, 0x0B, 129 | 0xB1, 0x37, 0x63, 0x4B, 0x69, 0xAE, 0x91, 0xC7, 130 | 0xC3, 0x97, 0xAE, 0x77, 0xF4, 0x37, 0xD7, 0x9B, 131 | 0x7C, 0xF5, 0x3C, 0x11, 0x8F, 0x15, 0xC3, 0xD7, 132 | 0xC1, 0x5B, 0x00, 0x2A, 0xD0, 0x75, 0xDE, 0x9E, 133 | 0x51, 0x64, 0xAB, 0x3E, 0xE9, 0x15, 0xB5, 0xAB, 134 | 0x56, 0x9A, 0x98, 0x82, 0x26, 0xEA, 0x2A, 0x62 135 | }; 136 | 137 | class MFRC522 { 138 | public: 139 | // MFRC522 registers. Described in chapter 9 of the datasheet. 140 | enum PCD_Register { 141 | // Page 0: Command and status 142 | // 0x00 // reserved for future use 143 | CommandReg = 0x01 , // starts and stops command execution 144 | ComIEnReg = 0x02 , // enable and disable interrupt request control bits 145 | DivIEnReg = 0x03 , // enable and disable interrupt request control bits 146 | ComIrqReg = 0x04 , // interrupt request bits 147 | DivIrqReg = 0x05 , // interrupt request bits 148 | ErrorReg = 0x06 , // error bits showing the error status of the last command executed 149 | Status1Reg = 0x07 , // communication status bits 150 | Status2Reg = 0x08 , // receiver and transmitter status bits 151 | FIFODataReg = 0x09 , // input and output of 64 byte FIFO buffer 152 | FIFOLevelReg = 0x0A , // number of bytes stored in the FIFO buffer 153 | WaterLevelReg = 0x0B , // level for FIFO underflow and overflow warning 154 | ControlReg = 0x0C , // miscellaneous control registers 155 | BitFramingReg = 0x0D , // adjustments for bit-oriented frames 156 | CollReg = 0x0E , // bit position of the first bit-collision detected on the RF interface 157 | // 0x0F // reserved for future use 158 | 159 | // Page 1: Command 160 | // 0x10 // reserved for future use 161 | ModeReg = 0x11 , // defines general modes for transmitting and receiving 162 | TxModeReg = 0x12 , // defines transmission data rate and framing 163 | RxModeReg = 0x13 , // defines reception data rate and framing 164 | TxControlReg = 0x14 , // controls the logical behavior of the antenna driver pins TX1 and TX2 165 | TxASKReg = 0x15 , // controls the setting of the transmission modulation 166 | TxSelReg = 0x16 , // selects the internal sources for the antenna driver 167 | RxSelReg = 0x17 , // selects internal receiver settings 168 | RxThresholdReg = 0x18 , // selects thresholds for the bit decoder 169 | DemodReg = 0x19 , // defines demodulator settings 170 | // 0x1A // reserved for future use 171 | // 0x1B // reserved for future use 172 | MfTxReg = 0x1C , // controls some MIFARE communication transmit parameters 173 | MfRxReg = 0x1D , // controls some MIFARE communication receive parameters 174 | // 0x1E // reserved for future use 175 | SerialSpeedReg = 0x1F , // selects the speed of the serial UART interface 176 | 177 | // Page 2: Configuration 178 | // 0x20 // reserved for future use 179 | CRCResultRegH = 0x21 , // shows the MSB and LSB values of the CRC calculation 180 | CRCResultRegL = 0x22 , 181 | // 0x23 // reserved for future use 182 | ModWidthReg = 0x24 , // controls the ModWidth setting? 183 | // 0x25 // reserved for future use 184 | RFCfgReg = 0x26 , // configures the receiver gain 185 | GsNReg = 0x27 , // selects the conductance of the antenna driver pins TX1 and TX2 for modulation 186 | CWGsPReg = 0x28 , // defines the conductance of the p-driver output during periods of no modulation 187 | ModGsPReg = 0x29 , // defines the conductance of the p-driver output during periods of modulation 188 | TModeReg = 0x2A , // defines settings for the internal timer 189 | TPrescalerReg = 0x2B , // the lower 8 bits of the TPrescaler value. The 4 high bits are in TModeReg. 190 | TReloadRegH = 0x2C , // defines the 16-bit timer reload value 191 | TReloadRegL = 0x2D , 192 | TCounterValueRegH = 0x2E , // shows the 16-bit timer value 193 | TCounterValueRegL = 0x2F , 194 | 195 | // Page 3: Test Registers 196 | // 0x30 // reserved for future use 197 | TestSel1Reg = 0x31 , // general test signal configuration 198 | TestSel2Reg = 0x32 , // general test signal configuration 199 | TestPinEnReg = 0x33 , // enables pin output driver on pins D1 to D7 200 | TestPinValueReg = 0x34 , // defines the values for D1 to D7 when it is used as an I/O bus 201 | TestBusReg = 0x35 , // shows the status of the internal test bus 202 | AutoTestReg = 0x36 , // controls the digital self test 203 | VersionReg = 0x37 , // shows the software version 204 | AnalogTestReg = 0x38 , // controls the pins AUX1 and AUX2 205 | TestDAC1Reg = 0x39 , // defines the test value for TestDAC1 206 | TestDAC2Reg = 0x3A , // defines the test value for TestDAC2 207 | TestADCReg = 0x3B // shows the value of ADC I and Q channels 208 | // 0x3C // reserved for production tests 209 | // 0x3D // reserved for production tests 210 | // 0x3E // reserved for production tests 211 | // 0x3F // reserved for production tests 212 | }; 213 | 214 | // MFRC522 commands. Described in chapter 10 of the datasheet. 215 | enum PCD_Command { 216 | PCD_Idle = 0x00, // no action, cancels current command execution 217 | PCD_Mem = 0x01, // stores 25 bytes into the internal buffer 218 | PCD_GenerateRandomID = 0x02, // generates a 10-byte random ID number 219 | PCD_CalcCRC = 0x03, // activates the CRC coprocessor or performs a self test 220 | PCD_Transmit = 0x04, // transmits data from the FIFO buffer 221 | PCD_NoCmdChange = 0x07, // no command change, can be used to modify the CommandReg register bits without affecting the command, for example, the PowerDown bit 222 | PCD_Receive = 0x08, // activates the receiver circuits 223 | PCD_Transceive = 0x0C, // transmits data from FIFO buffer to antenna and automatically activates the receiver after transmission 224 | PCD_MFAuthent = 0x0E, // performs the MIFARE standard authentication as a reader 225 | PCD_SoftReset = 0x0F // resets the MFRC522 226 | }; 227 | 228 | // MFRC522 RxGain[2:0] masks, defines the receiver's signal voltage gain factor (on the PCD). 229 | // Described in 9.3.3.6 / table 98 of the datasheet at http://www.nxp.com/documents/data_sheet/MFRC522.pdf 230 | enum PCD_RxGain { 231 | RxGain_18dB = 0x00 << 4, // 000b - 18 dB, minimum 232 | RxGain_23dB = 0x01 << 4, // 001b - 23 dB 233 | RxGain_18dB_2 = 0x02 << 4, // 010b - 18 dB, it seems 010b is a duplicate for 000b 234 | RxGain_23dB_2 = 0x03 << 4, // 011b - 23 dB, it seems 011b is a duplicate for 001b 235 | RxGain_33dB = 0x04 << 4, // 100b - 33 dB, average, and typical default 236 | RxGain_38dB = 0x05 << 4, // 101b - 38 dB 237 | RxGain_43dB = 0x06 << 4, // 110b - 43 dB 238 | RxGain_48dB = 0x07 << 4, // 111b - 48 dB, maximum 239 | RxGain_min = 0x00 << 4, // 000b - 18 dB, minimum, convenience for RxGain_18dB 240 | RxGain_avg = 0x04 << 4, // 100b - 33 dB, average, convenience for RxGain_33dB 241 | RxGain_max = 0x07 << 4 // 111b - 48 dB, maximum, convenience for RxGain_48dB 242 | }; 243 | 244 | // Commands sent to the PICC. 245 | enum PICC_Command { 246 | // The commands used by the PCD to manage communication with several PICCs (ISO 14443-3, Type A, section 6.4) 247 | PICC_CMD_REQA = 0x26, // REQuest command, Type A. Invites PICCs in state IDLE to go to READY and prepare for anticollision or selection. 7 bit frame. 248 | PICC_CMD_WUPA = 0x52, // Wake-UP command, Type A. Invites PICCs in state IDLE and HALT to go to READY(*) and prepare for anticollision or selection. 7 bit frame. 249 | PICC_CMD_CT = 0x88, // Cascade Tag. Not really a command, but used during anti collision. 250 | PICC_CMD_SEL_CL1 = 0x93, // Anti collision/Select, Cascade Level 1 251 | PICC_CMD_SEL_CL2 = 0x95, // Anti collision/Select, Cascade Level 2 252 | PICC_CMD_SEL_CL3 = 0x97, // Anti collision/Select, Cascade Level 3 253 | PICC_CMD_HLTA = 0x50, // HaLT command, Type A. Instructs an ACTIVE PICC to go to state HALT. 254 | // The commands used for MIFARE Classic (from http://www.nxp.com/documents/data_sheet/MF1S503x.pdf, Section 9) 255 | // Use PCD_MFAuthent to authenticate access to a sector, then use these commands to read/write/modify the blocks on the sector. 256 | // The read/write commands can also be used for MIFARE Ultralight. 257 | PICC_CMD_MF_AUTH_KEY_A = 0x60, // Perform authentication with Key A 258 | PICC_CMD_MF_AUTH_KEY_B = 0x61, // Perform authentication with Key B 259 | PICC_CMD_MF_READ = 0x30, // Reads one 16 byte block from the authenticated sector of the PICC. Also used for MIFARE Ultralight. 260 | PICC_CMD_MF_WRITE = 0xA0, // Writes one 16 byte block to the authenticated sector of the PICC. Called "COMPATIBILITY WRITE" for MIFARE Ultralight. 261 | PICC_CMD_MF_DECREMENT = 0xC0, // Decrements the contents of a block and stores the result in the internal data register. 262 | PICC_CMD_MF_INCREMENT = 0xC1, // Increments the contents of a block and stores the result in the internal data register. 263 | PICC_CMD_MF_RESTORE = 0xC2, // Reads the contents of a block into the internal data register. 264 | PICC_CMD_MF_TRANSFER = 0xB0, // Writes the contents of the internal data register to a block. 265 | // The commands used for MIFARE Ultralight (from http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf, Section 8.6) 266 | // The PICC_CMD_MF_READ and PICC_CMD_MF_WRITE can also be used for MIFARE Ultralight. 267 | PICC_CMD_UL_WRITE = 0xA2 // Writes one 4 byte page to the PICC. 268 | }; 269 | 270 | // MIFARE constants that does not fit anywhere else 271 | enum MIFARE_Misc { 272 | MF_ACK = 0xA, // The MIFARE Classic uses a 4 bit ACK/NAK. Any other value than 0xA is NAK. 273 | MF_KEY_SIZE = 6 // A Mifare Crypto1 key is 6 bytes. 274 | }; 275 | 276 | // PICC types we can detect. Remember to update PICC_GetTypeName() if you add more. 277 | enum PICC_Type { 278 | PICC_TYPE_UNKNOWN = 0, 279 | PICC_TYPE_ISO_14443_4 = 1, // PICC compliant with ISO/IEC 14443-4 280 | PICC_TYPE_ISO_18092 = 2, // PICC compliant with ISO/IEC 18092 (NFC) 281 | PICC_TYPE_MIFARE_MINI = 3, // MIFARE Classic protocol, 320 bytes 282 | PICC_TYPE_MIFARE_1K = 4, // MIFARE Classic protocol, 1KB 283 | PICC_TYPE_MIFARE_4K = 5, // MIFARE Classic protocol, 4KB 284 | PICC_TYPE_MIFARE_UL = 6, // MIFARE Ultralight or Ultralight C 285 | PICC_TYPE_MIFARE_PLUS = 7, // MIFARE Plus 286 | PICC_TYPE_TNP3XXX = 8, // Only mentioned in NXP AN 10833 MIFARE Type Identification Procedure 287 | PICC_TYPE_NOT_COMPLETE = 255 // SAK indicates UID is not complete. 288 | }; 289 | 290 | // Return codes from the functions in this class. Remember to update GetStatusCodeName() if you add more. 291 | enum StatusCode { 292 | STATUS_OK = 1, // Success 293 | STATUS_ERROR = 2, // Error in communication 294 | STATUS_COLLISION = 3, // Collission detected 295 | STATUS_TIMEOUT = 4, // Timeout in communication. 296 | STATUS_NO_ROOM = 5, // A buffer is not big enough. 297 | STATUS_INTERNAL_ERROR = 6, // Internal error in the code. Should not happen ;-) 298 | STATUS_INVALID = 7, // Invalid argument. 299 | STATUS_CRC_WRONG = 8, // The CRC_A does not match 300 | STATUS_MIFARE_NACK = 9 // A MIFARE PICC responded with NAK. 301 | }; 302 | 303 | // A struct used for passing the UID of a PICC. 304 | typedef struct { 305 | byte size; // Number of bytes in the UID. 4, 7 or 10. 306 | byte uidByte[10]; 307 | byte sak; // The SAK (Select acknowledge) byte returned from the PICC after successful selection. 308 | } Uid; 309 | 310 | // A struct used for passing a MIFARE Crypto1 key 311 | typedef struct { 312 | byte keyByte[MF_KEY_SIZE]; 313 | } MIFARE_Key; 314 | 315 | // Member variables 316 | Uid uid; // Used by PICC_ReadCardSerial(). 317 | 318 | // Size of the MFRC522 FIFO 319 | static const byte FIFO_SIZE = 64; // The FIFO is 64 bytes. 320 | 321 | ///////////////////////////////////////////////////////////////////////////////////// 322 | // Functions for setting up the Arduino 323 | ///////////////////////////////////////////////////////////////////////////////////// 324 | MFRC522(byte chipAddress); 325 | 326 | ///////////////////////////////////////////////////////////////////////////////////// 327 | // Basic interface functions for communicating with the MFRC522 328 | ///////////////////////////////////////////////////////////////////////////////////// 329 | void PCD_WriteRegister(byte reg, byte value); 330 | void PCD_WriteRegister(byte reg, byte count, byte *values); 331 | byte PCD_ReadRegister(byte reg); 332 | void PCD_ReadRegister(byte reg, byte count, byte *values, byte rxAlign = 0); 333 | void setBitMask(unsigned char reg, unsigned char mask); 334 | void PCD_SetRegisterBitMask(byte reg, byte mask); 335 | void PCD_ClearRegisterBitMask(byte reg, byte mask); 336 | byte PCD_CalculateCRC(byte *data, byte length, byte *result); 337 | 338 | ///////////////////////////////////////////////////////////////////////////////////// 339 | // Functions for manipulating the MFRC522 340 | ///////////////////////////////////////////////////////////////////////////////////// 341 | void PCD_Init(); 342 | void PCD_Reset(); 343 | void PCD_AntennaOn(); 344 | void PCD_AntennaOff(); 345 | byte PCD_GetAntennaGain(); 346 | void PCD_SetAntennaGain(byte mask); 347 | bool PCD_PerformSelfTest(); 348 | 349 | ///////////////////////////////////////////////////////////////////////////////////// 350 | // Functions for communicating with PICCs 351 | ///////////////////////////////////////////////////////////////////////////////////// 352 | byte PCD_TransceiveData(byte *sendData, byte sendLen, byte *backData, byte *backLen, byte *validBits = NULL, byte rxAlign = 0, bool checkCRC = false); 353 | byte PCD_CommunicateWithPICC(byte command, byte waitIRq, byte *sendData, byte sendLen, byte *backData = NULL, byte *backLen = NULL, byte *validBits = NULL, byte rxAlign = 0, bool checkCRC = false); 354 | byte PICC_RequestA(byte *bufferATQA, byte *bufferSize); 355 | byte PICC_WakeupA(byte *bufferATQA, byte *bufferSize); 356 | byte PICC_REQA_or_WUPA(byte command, byte *bufferATQA, byte *bufferSize); 357 | byte PICC_Select(Uid *uid, byte validBits = 0); 358 | byte PICC_HaltA(); 359 | 360 | ///////////////////////////////////////////////////////////////////////////////////// 361 | // Functions for communicating with MIFARE PICCs 362 | ///////////////////////////////////////////////////////////////////////////////////// 363 | byte PCD_Authenticate(byte command, byte blockAddr, MIFARE_Key *key, Uid *uid); 364 | void PCD_StopCrypto1(); 365 | byte MIFARE_Read(byte blockAddr, byte *buffer, byte *bufferSize); 366 | byte MIFARE_Write(byte blockAddr, byte *buffer, byte bufferSize); 367 | byte MIFARE_Decrement(byte blockAddr, long delta); 368 | byte MIFARE_Increment(byte blockAddr, long delta); 369 | byte MIFARE_Restore(byte blockAddr); 370 | byte MIFARE_Transfer(byte blockAddr); 371 | byte MIFARE_Ultralight_Write(byte page, byte *buffer, byte bufferSize); 372 | byte MIFARE_GetValue(byte blockAddr, long *value); 373 | byte MIFARE_SetValue(byte blockAddr, long value); 374 | 375 | ///////////////////////////////////////////////////////////////////////////////////// 376 | // Support functions 377 | ///////////////////////////////////////////////////////////////////////////////////// 378 | byte PCD_MIFARE_Transceive(byte *sendData, byte sendLen, bool acceptTimeout = false); 379 | // old function used too much memory, now name moved to flash; if you need char, copy from flash to memory 380 | //const char *GetStatusCodeName(byte code); 381 | const __FlashStringHelper *GetStatusCodeName(byte code); 382 | byte PICC_GetType(byte sak); 383 | // old function used too much memory, now name moved to flash; if you need char, copy from flash to memory 384 | //const char *PICC_GetTypeName(byte type); 385 | const __FlashStringHelper *PICC_GetTypeName(byte type); 386 | void PICC_DumpToSerial(Uid *uid); 387 | void PICC_DumpMifareClassicToSerial(Uid *uid, byte piccType, MIFARE_Key *key); 388 | void PICC_DumpMifareClassicSectorToSerial(Uid *uid, MIFARE_Key *key, byte sector); 389 | void PICC_DumpMifareUltralightToSerial(); 390 | void MIFARE_SetAccessBits(byte *accessBitBuffer, byte g0, byte g1, byte g2, byte g3); 391 | bool MIFARE_OpenUidBackdoor(bool logErrors); 392 | bool MIFARE_SetUid(byte *newUid, byte uidSize, bool logErrors); 393 | bool MIFARE_UnbrickUidSector(bool logErrors); 394 | 395 | ///////////////////////////////////////////////////////////////////////////////////// 396 | // Convenience functions - does not add extra functionality 397 | ///////////////////////////////////////////////////////////////////////////////////// 398 | bool PICC_IsNewCardPresent(); 399 | bool PICC_ReadCardSerial(); 400 | 401 | private: 402 | byte _chipAddress; 403 | byte _resetPowerDownPin; // Arduino pin connected to MFRC522's reset and power down input (Pin 6, NRSTPD, active low) 404 | byte MIFARE_TwoStepHelper(byte command, byte blockAddr, long data); 405 | }; 406 | 407 | #endif 408 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # m5hack 2 | RFID & WIFI Tools on M5Stack ESP32 3 | -------------------------------------------------------------------------------- /binaries/m5hack_esp32.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spawnrider/m5hack/8a30c4f337ea2818d2f2939ab1c51f2fda53abe6/binaries/m5hack_esp32.bin -------------------------------------------------------------------------------- /m5hack.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "MFRC522_I2C.h" 7 | #include "images.h" 8 | 9 | #define MAIN_DECLARED 10 | 11 | // 0x28 is i2c address on SDA. Check your address with i2cscanner if not match. 12 | MFRC522 mfrc522(0x28); // Create MFRC522 instance. 13 | 14 | void setup() { 15 | #include 16 | #include 17 | 18 | // RFID init 19 | Serial.begin(115200); // Initialize serial communications with the PC 20 | Wire.begin(); // Initialize I2C 21 | mfrc522.PCD_Init(); // Init MFRC522 22 | 23 | M5.Speaker.setVolume(1); 24 | M5.Speaker.update(); 25 | 26 | ezt::setDebug(INFO); 27 | ez.begin(); 28 | } 29 | 30 | void loop() { 31 | ezMenu mainmenu("Spawnrider M5H@ck"); 32 | mainmenu.txtSmall(); 33 | mainmenu.addItem("RFID Tools", menu_rfid); 34 | mainmenu.addItem("WIFI Tools", menu_not_implemented); 35 | mainmenu.addItem("Built-in wifi & other settings", ez.settings.menu); 36 | mainmenu.addItem("M5H@ck settings", menu_m5hack); 37 | mainmenu.upOnFirst("last|up"); 38 | mainmenu.downOnLast("first|down"); 39 | mainmenu.run(); 40 | } 41 | 42 | void menu_rfid() { 43 | ezMenu rfidmenu("RFID Tools"); 44 | rfidmenu.txtSmall(); 45 | rfidmenu.addItem("Get UID", rfid_tools); 46 | rfidmenu.addItem("Reader infos", show_reader_infos); 47 | rfidmenu.addItem("Back"); 48 | rfidmenu.upOnFirst("last|up"); 49 | rfidmenu.downOnLast("first|down"); 50 | rfidmenu.run(); 51 | } 52 | 53 | void rfid_tools() { 54 | ez.screen.clear(); 55 | 56 | char cardUid[15]; 57 | int i = 0; 58 | do { 59 | if(i > 10) return; 60 | M5.Lcd.println("Put the NFC Card on the reader..."); 61 | // Look for new cards, and select one if present 62 | delay(500); 63 | i++; 64 | } while (! mfrc522.PICC_IsNewCardPresent() || ! mfrc522.PICC_ReadCardSerial()); 65 | 66 | // Now a card is selected. The UID and SAK is in mfrc522.uid. 67 | //M5.Speaker.beep(); 68 | 69 | // Dump UID 70 | Serial.print(F("Card UID:")); 71 | for (byte i = 0; i < mfrc522.uid.size; i++) { 72 | Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "); 73 | Serial.print(mfrc522.uid.uidByte[i], HEX); 74 | sprintf(&cardUid[i * 2], "%02X", mfrc522.uid.uidByte[i]); 75 | //M5.Lcd.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "); 76 | //M5.Lcd.print(mfrc522.uid.uidByte[i], HEX); 77 | } 78 | Serial.println(); 79 | 80 | ez.msgBox("Card UID", cardUid); 81 | } 82 | 83 | void show_reader_infos() { 84 | // Get the MFRC522 software version 85 | byte v = mfrc522.PCD_ReadRegister(mfrc522.VersionReg); 86 | Serial.print(F("MFRC522 Software Version: 0x")); 87 | Serial.print(v, HEX); 88 | if (v == 0x91) { 89 | Serial.print(F(" = v1.0")); 90 | ez.msgBox("MFRC522 Software Version", "Version v1.0"); 91 | } else if (v == 0x92){ 92 | Serial.print(F(" = v2.0")); 93 | ez.msgBox("MFRC522 Software Version", "Version v2.0"); 94 | } else { 95 | Serial.print(F(" (unknown)")); 96 | ez.msgBox("MFRC522 Software Version", "Unknown version"); 97 | } 98 | Serial.println(""); 99 | // When 0x00 or 0xFF is returned, communication probably failed 100 | if ((v == 0x00) || (v == 0xFF)) { 101 | Serial.println(F("WARNING: Communication failure, is the MFRC522 properly connected?")); 102 | ez.msgBox("MFRC522 Software Version", "Communication failure, is the MFRC522 properly connected?"); 103 | } 104 | } 105 | 106 | void menu_not_implemented() { 107 | ez.msgBox("Not implemented", "To be implemented"); 108 | } 109 | 110 | void menu_m5hack() { 111 | ezMenu systemenu("Spawnrider M5H@ck"); 112 | systemenu.txtSmall(); 113 | systemenu.addItem("System Information", sysInfo); 114 | systemenu.addItem("WiFi Settings", ez.wifi.menu); 115 | systemenu.addItem("About M5H@ck", aboutM5Hack); 116 | systemenu.addItem("Updates via https", mainmenu_ota); 117 | systemenu.addItem("Power Off", powerOff); 118 | systemenu.addItem("Back"); 119 | systemenu.upOnFirst("last|up"); 120 | systemenu.downOnLast("first|down"); 121 | systemenu.run(); 122 | } 123 | 124 | void mainmenu_ota() { 125 | if (ez.msgBox("Get OTA_https", "This will replace the current program with a new version from GitHub.", "Cancel#OK#") == "OK") { 126 | ezProgressBar progress_bar("OTA update in progress", "Downloading ...", "Abort"); 127 | #include "raw_githubusercontent_com.h" // the root certificate is now in const char * root_cert 128 | if (ez.wifi.update("https://raw.githubusercontent.com/spawnrider/m5hack/master/binaries/m5hack_esp32.bin", root_cert, &progress_bar)) { 129 | ez.msgBox("Over The Air updater", "OTA download successful. Reboot to new firmware", "Reboot"); 130 | ESP.restart(); 131 | } else { 132 | ez.msgBox("OTA error", ez.wifi.updateError(), "OK"); 133 | } 134 | } 135 | } 136 | 137 | void powerOff() { 138 | m5.powerOFF(); 139 | } 140 | 141 | void aboutM5Hack() { 142 | ez.msgBox("About M5H@ck", "M5H@ck was written by | Yohann Ciurlik | | https://spawnrider.net"); 143 | } 144 | -------------------------------------------------------------------------------- /raw_githubusercontent_com.h: -------------------------------------------------------------------------------- 1 | // This is the root certificate include file for raw.githubusercontent.com 2 | // as obtained by the get_cert script on: Wed Aug 15 20:22:14 CEST 2018 3 | // 4 | // 5 | // Certificate info: 6 | // issuer= /C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance EV Root CA 7 | // notAfter=Oct 22 12:00:00 2028 GMT 8 | // 9 | 10 | const char* root_cert = \ 11 | "-----BEGIN CERTIFICATE-----\n" \ 12 | "MIIEsTCCA5mgAwIBAgIQBOHnpNxc8vNtwCtCuF0VnzANBgkqhkiG9w0BAQsFADBs\n" \ 13 | "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n" \ 14 | "d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j\n" \ 15 | "ZSBFViBSb290IENBMB4XDTEzMTAyMjEyMDAwMFoXDTI4MTAyMjEyMDAwMFowcDEL\n" \ 16 | "MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3\n" \ 17 | "LmRpZ2ljZXJ0LmNvbTEvMC0GA1UEAxMmRGlnaUNlcnQgU0hBMiBIaWdoIEFzc3Vy\n" \ 18 | "YW5jZSBTZXJ2ZXIgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2\n" \ 19 | "4C/CJAbIbQRf1+8KZAayfSImZRauQkCbztyfn3YHPsMwVYcZuU+UDlqUH1VWtMIC\n" \ 20 | "Kq/QmO4LQNfE0DtyyBSe75CxEamu0si4QzrZCwvV1ZX1QK/IHe1NnF9Xt4ZQaJn1\n" \ 21 | "itrSxwUfqJfJ3KSxgoQtxq2lnMcZgqaFD15EWCo3j/018QsIJzJa9buLnqS9UdAn\n" \ 22 | "4t07QjOjBSjEuyjMmqwrIw14xnvmXnG3Sj4I+4G3FhahnSMSTeXXkgisdaScus0X\n" \ 23 | "sh5ENWV/UyU50RwKmmMbGZJ0aAo3wsJSSMs5WqK24V3B3aAguCGikyZvFEohQcft\n" \ 24 | "bZvySC/zA/WiaJJTL17jAgMBAAGjggFJMIIBRTASBgNVHRMBAf8ECDAGAQH/AgEA\n" \ 25 | "MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw\n" \ 26 | "NAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2Vy\n" \ 27 | "dC5jb20wSwYDVR0fBEQwQjBAoD6gPIY6aHR0cDovL2NybDQuZGlnaWNlcnQuY29t\n" \ 28 | "L0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVWUm9vdENBLmNybDA9BgNVHSAENjA0MDIG\n" \ 29 | "BFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQ\n" \ 30 | "UzAdBgNVHQ4EFgQUUWj/kK8CB3U8zNllZGKiErhZcjswHwYDVR0jBBgwFoAUsT7D\n" \ 31 | "aQP4v0cB1JgmGggC72NkK8MwDQYJKoZIhvcNAQELBQADggEBABiKlYkD5m3fXPwd\n" \ 32 | "aOpKj4PWUS+Na0QWnqxj9dJubISZi6qBcYRb7TROsLd5kinMLYBq8I4g4Xmk/gNH\n" \ 33 | "E+r1hspZcX30BJZr01lYPf7TMSVcGDiEo+afgv2MW5gxTs14nhr9hctJqvIni5ly\n" \ 34 | "/D6q1UEL2tU2ob8cbkdJf17ZSHwD2f2LSaCYJkJA69aSEaRkCldUxPUd1gJea6zu\n" \ 35 | "xICaEnL6VpPX/78whQYwvwt/Tv9XBZ0k7YXDK/umdaisLRbvfXknsuvCnQsH6qqF\n" \ 36 | "0wGjIChBWUMo0oHjqvbsezt3tkBigAVBRQHvFwY+3sAzm2fTYS5yh+Rp/BIAV0Ae\n" \ 37 | "cPUeybQ=\n" \ 38 | "-----END CERTIFICATE-----\n"; 39 | -------------------------------------------------------------------------------- /z-sysinfo.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * This is a "z-sketch". It means you can run this sketch on its own, or use it as a sub-sketch of some bigger program 4 | * See the M5ez user manual under z-sketches at https://github.com/ropg/M5ez 5 | * 6 | */ 7 | 8 | #ifndef MAIN_DECLARED 9 | 10 | #include 11 | #include 12 | 13 | void setup() { 14 | ez.begin(); 15 | sysInfo(); 16 | } 17 | 18 | void loop() { 19 | 20 | } 21 | 22 | String exit_button = ""; 23 | 24 | #else 25 | 26 | String exit_button = "Exit"; 27 | 28 | #endif // #ifndef MAIN_DECLARED 29 | 30 | 31 | 32 | void sysInfo() { 33 | sysInfoPage1(); 34 | while(true) { 35 | String btn = ez.buttons.poll(); 36 | if (btn == "up") sysInfoPage1(); 37 | if (btn == "down") sysInfoPage2(); 38 | if (btn == "Exit") break; 39 | } 40 | } 41 | 42 | #include 43 | 44 | void sysInfoPage1() { 45 | const byte tab = 120; 46 | ez.screen.clear(); 47 | ez.header.show("System Info (1/2)"); 48 | ez.buttons.show("#" + exit_button + "#down"); 49 | ez.canvas.font(&FreeSans9pt7b); 50 | ez.canvas.lmargin(10); 51 | ez.canvas.println(""); 52 | ez.canvas.print("CPU freq:"); ez.canvas.x(tab); ez.canvas.println(String(ESP.getCpuFreqMHz()) + " MHz"); 53 | ez.canvas.print("CPU cores:"); ez.canvas.x(tab); ez.canvas.println("2"); // :) 54 | ez.canvas.print("Chip rev.:"); ez.canvas.x(tab); ez.canvas.println(String(ESP.getChipRevision())); 55 | ez.canvas.print("Flash speed:"); ez.canvas.x(tab); ez.canvas.println(String(ESP.getFlashChipSpeed() / 1000000) + " MHz"); 56 | ez.canvas.print("Flash size:"); ez.canvas.x(tab); ez.canvas.println(String(ESP.getFlashChipSize() / 1000000) + " MB"); 57 | ez.canvas.print("ESP SDK:"); ez.canvas.x(tab); ez.canvas.println(String(ESP.getSdkVersion())); 58 | ez.canvas.print("M5ez:"); ez.canvas.x(tab); ez.canvas.println(String(ez.version())); 59 | } 60 | 61 | void sysInfoPage2() { 62 | const String SD_Type[5] = {"NONE", "MMC", "SD", "SDHC", "UNKNOWN"}; 63 | const byte tab = 140; 64 | ez.screen.clear(); 65 | ez.header.show("System Info (2/2)"); 66 | ez.buttons.show("up#" + exit_button + "#"); 67 | ez.canvas.font(&FreeSans9pt7b); 68 | ez.canvas.lmargin(10); 69 | ez.canvas.println(""); 70 | ez.canvas.print("Free RAM:"); ez.canvas.x(tab); ez.canvas.println(String((long)ESP.getFreeHeap()) + " bytes"); 71 | ez.canvas.print("Min. free seen:"); ez.canvas.x(tab); ez.canvas.println(String((long)esp_get_minimum_free_heap_size()) + " bytes"); 72 | const int sd_type = SD.cardType(); 73 | 74 | SPIFFS.begin(); 75 | ez.canvas.print("SPIFFS size:"); ez.canvas.x(tab); ez.canvas.println(String((long)SPIFFS.totalBytes()) + " bytes"); 76 | ez.canvas.print("SPIFFS used:"); ez.canvas.x(tab); ez.canvas.println(String((long)SPIFFS.usedBytes()) + " bytes"); 77 | ez.canvas.print("SD type:"); ez.canvas.x(tab); ez.canvas.println(SD_Type[sd_type]); 78 | if (sd_type != 0) { 79 | ez.canvas.print("SD size:"); ez.canvas.x(tab); ez.canvas.println(String((long)SD.cardSize() / 1000000) + " MB"); 80 | ez.canvas.print("SD used:"); ez.canvas.x(tab); ez.canvas.println(String((long)SD.usedBytes() / 1000000) + " MB"); 81 | } 82 | } 83 | --------------------------------------------------------------------------------