From 0b258bfe0fdde6aa6ff1ecd5e7c1065d245541ee Mon Sep 17 00:00:00 2001 From: Rotzbua Date: Mon, 22 May 2017 12:25:18 +0200 Subject: [PATCH] refactor and split class move hardware manipulation functions into new class --- examples/ChangeUID/ChangeUID.ino | 6 +- examples/FixBrickedUID/FixBrickedUID.ino | 6 +- src/MFRC522.cpp | 230 +---------------------- src/MFRC522.h | 14 +- src/MFRC522Debug.cpp | 46 +++++ src/MFRC522Debug.h | 14 ++ src/MFRC522Hack.cpp | 203 ++++++++++++++++++++ src/MFRC522Hack.h | 22 +++ 8 files changed, 299 insertions(+), 242 deletions(-) create mode 100644 src/MFRC522Debug.cpp create mode 100644 src/MFRC522Debug.h create mode 100644 src/MFRC522Hack.cpp create mode 100644 src/MFRC522Hack.h diff --git a/examples/ChangeUID/ChangeUID.ino b/examples/ChangeUID/ChangeUID.ino index fc53471..1a6217d 100644 --- a/examples/ChangeUID/ChangeUID.ino +++ b/examples/ChangeUID/ChangeUID.ino @@ -25,11 +25,13 @@ #include #include +#include constexpr uint8_t RST_PIN = 9; // Configurable, see typical pin layout above constexpr uint8_t SS_PIN = 10; // Configurable, see typical pin layout above -MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance +MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance. +MFRC522Hack mfrc522Hack(&mfrc522); // Create MFRC522Hack instance. /* Set your new UID here! */ byte newUid[] = {0xDE, 0xAD, 0xBE, 0xEF}; @@ -92,7 +94,7 @@ void loop() { // } // Set new UID - if ( mfrc522.MIFARE_SetUid(newUid, (byte)4, true) ) { + if ( mfrc522Hack.MIFARE_SetUid(newUid, (byte)4, true) ) { Serial.println(F("Wrote new UID to card.")); } diff --git a/examples/FixBrickedUID/FixBrickedUID.ino b/examples/FixBrickedUID/FixBrickedUID.ino index df7a166..959ec47 100644 --- a/examples/FixBrickedUID/FixBrickedUID.ino +++ b/examples/FixBrickedUID/FixBrickedUID.ino @@ -24,11 +24,13 @@ #include #include +#include constexpr uint8_t RST_PIN = 9; // Configurable, see typical pin layout above constexpr uint8_t SS_PIN = 10; // Configurable, see typical pin layout above -MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance +MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance. +MFRC522Hack mfrc522Hack(&mfrc522); // Create MFRC522Hack instance. MFRC522::MIFARE_Key key; @@ -46,7 +48,7 @@ void setup() { } void loop() { - if ( mfrc522.MIFARE_UnbrickUidSector(false) ) { + if ( mfrc522Hack.MIFARE_UnbrickUidSector(false) ) { Serial.println(F("Cleared sector 0, set UID to 1234. Card should be responsive again now.")); } delay(1000); diff --git a/src/MFRC522.cpp b/src/MFRC522.cpp index e6ed6d2..95bf498 100644 --- a/src/MFRC522.cpp +++ b/src/MFRC522.cpp @@ -6,6 +6,7 @@ #include #include "MFRC522.h" +#include "MFRC522Debug.h" ///////////////////////////////////////////////////////////////////////////////////// // Functions for setting up the Arduino @@ -1213,18 +1214,7 @@ MFRC522::StatusCode MFRC522::PCD_MIFARE_Transceive( byte *sendData, ///< Pointe */ const __FlashStringHelper *MFRC522::GetStatusCodeName(MFRC522::StatusCode code ///< One of the StatusCode enums. ) { - switch (code) { - case STATUS_OK: return F("Success."); - case STATUS_ERROR: return F("Error in communication."); - case STATUS_COLLISION: return F("Collission detected."); - case STATUS_TIMEOUT: return F("Timeout in communication."); - case STATUS_NO_ROOM: return F("A buffer is not big enough."); - case STATUS_INTERNAL_ERROR: return F("Internal error in the code. Should not happen."); - case STATUS_INVALID: return F("Invalid argument."); - case STATUS_CRC_WRONG: return F("The CRC_A does not match."); - case STATUS_MIFARE_NACK: return F("A MIFARE PICC responded with NAK."); - default: return F("Unknown error"); - } + return MFRC522Debug::GetStatusCodeName(code); } // End GetStatusCodeName() /** @@ -1261,20 +1251,7 @@ MFRC522::PICC_Type MFRC522::PICC_GetType(byte sak ///< The SAK byte returned fr */ const __FlashStringHelper *MFRC522::PICC_GetTypeName(PICC_Type piccType ///< One of the PICC_Type enums. ) { - switch (piccType) { - case PICC_TYPE_ISO_14443_4: return F("PICC compliant with ISO/IEC 14443-4"); - case PICC_TYPE_ISO_18092: return F("PICC compliant with ISO/IEC 18092 (NFC)"); - case PICC_TYPE_MIFARE_MINI: return F("MIFARE Mini, 320 bytes"); - case PICC_TYPE_MIFARE_1K: return F("MIFARE 1KB"); - case PICC_TYPE_MIFARE_4K: return F("MIFARE 4KB"); - case PICC_TYPE_MIFARE_UL: return F("MIFARE Ultralight or Ultralight C"); - case PICC_TYPE_MIFARE_PLUS: return F("MIFARE Plus"); - case PICC_TYPE_MIFARE_DESFIRE: return F("MIFARE DESFire"); - case PICC_TYPE_TNP3XXX: return F("MIFARE TNP3XXX"); - case PICC_TYPE_NOT_COMPLETE: return F("SAK indicates UID is not complete."); - case PICC_TYPE_UNKNOWN: - default: return F("Unknown type"); - } + return MFRC522Debug::PICC_GetTypeName(piccType); } // End PICC_GetTypeName() /** @@ -1628,207 +1605,6 @@ void MFRC522::MIFARE_SetAccessBits( byte *accessBitBuffer, ///< Pointer to byte accessBitBuffer[2] = c3 << 4 | c2; } // End MIFARE_SetAccessBits() - -/** - * Performs the "magic sequence" needed to get Chinese UID changeable - * Mifare cards to allow writing to sector 0, where the card UID is stored. - * - * Note that you do not need to have selected the card through REQA or WUPA, - * this sequence works immediately when the card is in the reader vicinity. - * This means you can use this method even on "bricked" cards that your reader does - * not recognise anymore (see MFRC522::MIFARE_UnbrickUidSector). - * - * Of course with non-bricked devices, you're free to select them before calling this function. - */ -bool MFRC522::MIFARE_OpenUidBackdoor(bool logErrors) { - // Magic sequence: - // > 50 00 57 CD (HALT + CRC) - // > 40 (7 bits only) - // < A (4 bits only) - // > 43 - // < A (4 bits only) - // Then you can write to sector 0 without authenticating - - PICC_HaltA(); // 50 00 57 CD - - byte cmd = 0x40; - byte validBits = 7; /* Our command is only 7 bits. After receiving card response, - this will contain amount of valid response bits. */ - byte response[32]; // Card's response is written here - byte received; - MFRC522::StatusCode status = PCD_TransceiveData(&cmd, (byte)1, response, &received, &validBits, (byte)0, false); // 40 - if(status != STATUS_OK) { - if(logErrors) { - Serial.println(F("Card did not respond to 0x40 after HALT command. Are you sure it is a UID changeable one?")); - Serial.print(F("Error name: ")); - Serial.println(GetStatusCodeName(status)); - } - return false; - } - if (received != 1 || response[0] != 0x0A) { - if (logErrors) { - Serial.print(F("Got bad response on backdoor 0x40 command: ")); - Serial.print(response[0], HEX); - Serial.print(F(" (")); - Serial.print(validBits); - Serial.print(F(" valid bits)\r\n")); - } - return false; - } - - cmd = 0x43; - validBits = 8; - status = PCD_TransceiveData(&cmd, (byte)1, response, &received, &validBits, (byte)0, false); // 43 - if(status != STATUS_OK) { - if(logErrors) { - Serial.println(F("Error in communication at command 0x43, after successfully executing 0x40")); - Serial.print(F("Error name: ")); - Serial.println(GetStatusCodeName(status)); - } - return false; - } - if (received != 1 || response[0] != 0x0A) { - if (logErrors) { - Serial.print(F("Got bad response on backdoor 0x43 command: ")); - Serial.print(response[0], HEX); - Serial.print(F(" (")); - Serial.print(validBits); - Serial.print(F(" valid bits)\r\n")); - } - return false; - } - - // You can now write to sector 0 without authenticating! - return true; -} // End MIFARE_OpenUidBackdoor() - -/** - * Reads entire block 0, including all manufacturer data, and overwrites - * that block with the new UID, a freshly calculated BCC, and the original - * manufacturer data. - * - * It assumes a default KEY A of 0xFFFFFFFFFFFF. - * Make sure to have selected the card before this function is called. - */ -bool MFRC522::MIFARE_SetUid(byte *newUid, byte uidSize, bool logErrors) { - - // UID + BCC byte can not be larger than 16 together - if (!newUid || !uidSize || uidSize > 15) { - if (logErrors) { - Serial.println(F("New UID buffer empty, size 0, or size > 15 given")); - } - return false; - } - - // Authenticate for reading - MIFARE_Key key = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; - MFRC522::StatusCode status = PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, (byte)1, &key, &uid); - if (status != STATUS_OK) { - - if (status == STATUS_TIMEOUT) { - // We get a read timeout if no card is selected yet, so let's select one - - // Wake the card up again if sleeping -// byte atqa_answer[2]; -// byte atqa_size = 2; -// PICC_WakeupA(atqa_answer, &atqa_size); - - if (!PICC_IsNewCardPresent() || !PICC_ReadCardSerial()) { - Serial.println(F("No card was previously selected, and none are available. Failed to set UID.")); - return false; - } - - status = PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, (byte)1, &key, &uid); - if (status != STATUS_OK) { - // We tried, time to give up - if (logErrors) { - Serial.println(F("Failed to authenticate to card for reading, could not set UID: ")); - Serial.println(GetStatusCodeName(status)); - } - return false; - } - } - else { - if (logErrors) { - Serial.print(F("PCD_Authenticate() failed: ")); - Serial.println(GetStatusCodeName(status)); - } - return false; - } - } - - // Read block 0 - byte block0_buffer[18]; - byte byteCount = sizeof(block0_buffer); - status = MIFARE_Read((byte)0, block0_buffer, &byteCount); - if (status != STATUS_OK) { - if (logErrors) { - Serial.print(F("MIFARE_Read() failed: ")); - Serial.println(GetStatusCodeName(status)); - Serial.println(F("Are you sure your KEY A for sector 0 is 0xFFFFFFFFFFFF?")); - } - return false; - } - - // Write new UID to the data we just read, and calculate BCC byte - byte bcc = 0; - for (uint8_t i = 0; i < uidSize; i++) { - block0_buffer[i] = newUid[i]; - bcc ^= newUid[i]; - } - - // Write BCC byte to buffer - block0_buffer[uidSize] = bcc; - - // Stop encrypted traffic so we can send raw bytes - PCD_StopCrypto1(); - - // Activate UID backdoor - if (!MIFARE_OpenUidBackdoor(logErrors)) { - if (logErrors) { - Serial.println(F("Activating the UID backdoor failed.")); - } - return false; - } - - // Write modified block 0 back to card - status = MIFARE_Write((byte)0, block0_buffer, (byte)16); - if (status != STATUS_OK) { - if (logErrors) { - Serial.print(F("MIFARE_Write() failed: ")); - Serial.println(GetStatusCodeName(status)); - } - return false; - } - - // Wake the card up again - byte atqa_answer[2]; - byte atqa_size = 2; - PICC_WakeupA(atqa_answer, &atqa_size); - - return true; -} - -/** - * Resets entire sector 0 to zeroes, so the card can be read again by readers. - */ -bool MFRC522::MIFARE_UnbrickUidSector(bool logErrors) { - MIFARE_OpenUidBackdoor(logErrors); - - byte block0_buffer[] = {0x01, 0x02, 0x03, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - - // Write modified block 0 back to card - MFRC522::StatusCode status = MIFARE_Write((byte)0, block0_buffer, (byte)16); - if (status != STATUS_OK) { - if (logErrors) { - Serial.print(F("MIFARE_Write() failed: ")); - Serial.println(GetStatusCodeName(status)); - } - return false; - } - return true; -} - ///////////////////////////////////////////////////////////////////////////////////// // Convenience functions - does not add extra functionality ///////////////////////////////////////////////////////////////////////////////////// diff --git a/src/MFRC522.h b/src/MFRC522.h index 114a84d..c1a022a 100644 --- a/src/MFRC522.h +++ b/src/MFRC522.h @@ -389,12 +389,10 @@ public: // Support functions ///////////////////////////////////////////////////////////////////////////////////// StatusCode PCD_MIFARE_Transceive(byte *sendData, byte sendLen, bool acceptTimeout = false); - // old function used too much memory, now name moved to flash; if you need char, copy from flash to memory - //const char *GetStatusCodeName(byte code); - static const __FlashStringHelper *GetStatusCodeName(StatusCode code); static PICC_Type PICC_GetType(byte sak); - // old function used too much memory, now name moved to flash; if you need char, copy from flash to memory - //const char *PICC_GetTypeName(byte type); + + // Support functions for debuging - proxy for MFRC522Debug to keep backwarts compatibility + static const __FlashStringHelper *GetStatusCodeName(StatusCode code); static const __FlashStringHelper *PICC_GetTypeName(PICC_Type type); // Support functions for debuging @@ -407,12 +405,6 @@ public: // Advanced functions for MIFARE void MIFARE_SetAccessBits(byte *accessBitBuffer, byte g0, byte g1, byte g2, byte g3); - DEPRECATED_MSG("will move to extra class in next version") - bool MIFARE_OpenUidBackdoor(bool logErrors); - DEPRECATED_MSG("will move to extra class in next version") - bool MIFARE_SetUid(byte *newUid, byte uidSize, bool logErrors); - DEPRECATED_MSG("will move to extra class in next version") - bool MIFARE_UnbrickUidSector(bool logErrors); ///////////////////////////////////////////////////////////////////////////////////// // Convenience functions - does not add extra functionality diff --git a/src/MFRC522Debug.cpp b/src/MFRC522Debug.cpp new file mode 100644 index 0000000..29f995f --- /dev/null +++ b/src/MFRC522Debug.cpp @@ -0,0 +1,46 @@ + +#include "MFRC522Debug.h" + +/** + * Returns a __FlashStringHelper pointer to the PICC type name. + * + * @return const __FlashStringHelper * + */ +const __FlashStringHelper *MFRC522Debug::PICC_GetTypeName(MFRC522::PICC_Type piccType ///< One of the PICC_Type enums. +) { + switch (piccType) { + case MFRC522::PICC_TYPE_ISO_14443_4: return F("PICC compliant with ISO/IEC 14443-4"); + case MFRC522::PICC_TYPE_ISO_18092: return F("PICC compliant with ISO/IEC 18092 (NFC)"); + case MFRC522::PICC_TYPE_MIFARE_MINI: return F("MIFARE Mini, 320 bytes"); + case MFRC522::PICC_TYPE_MIFARE_1K: return F("MIFARE 1KB"); + case MFRC522::PICC_TYPE_MIFARE_4K: return F("MIFARE 4KB"); + case MFRC522::PICC_TYPE_MIFARE_UL: return F("MIFARE Ultralight or Ultralight C"); + case MFRC522::PICC_TYPE_MIFARE_PLUS: return F("MIFARE Plus"); + case MFRC522::PICC_TYPE_MIFARE_DESFIRE: return F("MIFARE DESFire"); + case MFRC522::PICC_TYPE_TNP3XXX: return F("MIFARE TNP3XXX"); + case MFRC522::PICC_TYPE_NOT_COMPLETE: return F("SAK indicates UID is not complete."); + case MFRC522::PICC_TYPE_UNKNOWN: + default: return F("Unknown type"); + } +} // End PICC_GetTypeName() + +/** + * Returns a __FlashStringHelper pointer to a status code name. + * + * @return const __FlashStringHelper * + */ +const __FlashStringHelper *MFRC522Debug::GetStatusCodeName(MFRC522::StatusCode code ///< One of the StatusCode enums. +) { + switch (code) { + case MFRC522::STATUS_OK: return F("Success."); + case MFRC522::STATUS_ERROR: return F("Error in communication."); + case MFRC522::STATUS_COLLISION: return F("Collission detected."); + case MFRC522::STATUS_TIMEOUT: return F("Timeout in communication."); + case MFRC522::STATUS_NO_ROOM: return F("A buffer is not big enough."); + case MFRC522::STATUS_INTERNAL_ERROR: return F("Internal error in the code. Should not happen."); + case MFRC522::STATUS_INVALID: return F("Invalid argument."); + case MFRC522::STATUS_CRC_WRONG: return F("The CRC_A does not match."); + case MFRC522::STATUS_MIFARE_NACK: return F("A MIFARE PICC responded with NAK."); + default: return F("Unknown error"); + } +} // End GetStatusCodeName() diff --git a/src/MFRC522Debug.h b/src/MFRC522Debug.h new file mode 100644 index 0000000..5c01248 --- /dev/null +++ b/src/MFRC522Debug.h @@ -0,0 +1,14 @@ +#include "MFRC522.h" + +#ifndef MFRC522Debug_h +#define MFRC522Debug_h + +class MFRC522Debug { +private: + +public: + // Get human readable code and type + static const __FlashStringHelper *PICC_GetTypeName(MFRC522::PICC_Type type); + static const __FlashStringHelper *GetStatusCodeName(MFRC522::StatusCode code); +}; +#endif // MFRC522Debug_h diff --git a/src/MFRC522Hack.cpp b/src/MFRC522Hack.cpp new file mode 100644 index 0000000..12d532b --- /dev/null +++ b/src/MFRC522Hack.cpp @@ -0,0 +1,203 @@ +#include "MFRC522Hack.h" + +/** + * Performs the "magic sequence" needed to get Chinese UID changeable + * Mifare cards to allow writing to sector 0, where the card UID is stored. + * + * Note that you do not need to have selected the card through REQA or WUPA, + * this sequence works immediately when the card is in the reader vicinity. + * This means you can use this method even on "bricked" cards that your reader does + * not recognise anymore (see MFRC522Hack::MIFARE_UnbrickUidSector). + * + * Of course with non-bricked devices, you're free to select them before calling this function. + */ +bool MFRC522Hack::MIFARE_OpenUidBackdoor(bool logErrors) { + // Magic sequence: + // > 50 00 57 CD (HALT + CRC) + // > 40 (7 bits only) + // < A (4 bits only) + // > 43 + // < A (4 bits only) + // Then you can write to sector 0 without authenticating + + _device->PICC_HaltA(); // 50 00 57 CD + + byte cmd = 0x40; + byte validBits = 7; /* Our command is only 7 bits. After receiving card response, + this will contain amount of valid response bits. */ + byte response[32]; // Card's response is written here + byte received; + MFRC522::StatusCode status = _device->PCD_TransceiveData(&cmd, (byte) 1, response, &received, &validBits, (byte) 0, + false); // 40 + if (status != MFRC522::STATUS_OK) { + if (logErrors) { + Serial.println( + F("Card did not respond to 0x40 after HALT command. Are you sure it is a UID changeable one?")); + Serial.print(F("Error name: ")); + Serial.println(MFRC522Debug::GetStatusCodeName(status)); + } + return false; + } + if (received != 1 || response[0] != 0x0A) { + if (logErrors) { + Serial.print(F("Got bad response on backdoor 0x40 command: ")); + Serial.print(response[0], HEX); + Serial.print(F(" (")); + Serial.print(validBits); + Serial.print(F(" valid bits)\r\n")); + } + return false; + } + + cmd = 0x43; + validBits = 8; + status = _device->PCD_TransceiveData(&cmd, (byte) 1, response, &received, &validBits, (byte) 0, false); // 43 + if (status != MFRC522::STATUS_OK) { + if (logErrors) { + Serial.println(F("Error in communication at command 0x43, after successfully executing 0x40")); + Serial.print(F("Error name: ")); + Serial.println(MFRC522Debug::GetStatusCodeName(status)); + } + return false; + } + if (received != 1 || response[0] != 0x0A) { + if (logErrors) { + Serial.print(F("Got bad response on backdoor 0x43 command: ")); + Serial.print(response[0], HEX); + Serial.print(F(" (")); + Serial.print(validBits); + Serial.print(F(" valid bits)\r\n")); + } + return false; + } + + // You can now write to sector 0 without authenticating! + return true; +} // End MIFARE_OpenUidBackdoor() + +/** + * Reads entire block 0, including all manufacturer data, and overwrites + * that block with the new UID, a freshly calculated BCC, and the original + * manufacturer data. + * + * It assumes a default KEY A of 0xFFFFFFFFFFFF. + * Make sure to have selected the card before this function is called. + */ +bool MFRC522Hack::MIFARE_SetUid(byte *newUid, byte uidSize, bool logErrors) { + + // UID + BCC byte can not be larger than 16 together + if (!newUid || !uidSize || uidSize > 15) { + if (logErrors) { + Serial.println(F("New UID buffer empty, size 0, or size > 15 given")); + } + return false; + } + + // Authenticate for reading + MFRC522::MIFARE_Key key = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + MFRC522::StatusCode status = _device->PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, (byte) 1, &key, &(_device->uid)); + if (status != MFRC522::STATUS_OK) { + + if (status == MFRC522::STATUS_TIMEOUT) { + // We get a read timeout if no card is selected yet, so let's select one + + // Wake the card up again if sleeping +// byte atqa_answer[2]; +// byte atqa_size = 2; +// PICC_WakeupA(atqa_answer, &atqa_size); + + if (!_device->PICC_IsNewCardPresent() || !_device->PICC_ReadCardSerial()) { + Serial.println(F("No card was previously selected, and none are available. Failed to set UID.")); + return false; + } + + status = _device->PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, (byte) 1, &key, &(_device->uid)); + if (status != MFRC522::STATUS_OK) { + // We tried, time to give up + if (logErrors) { + Serial.println(F("Failed to authenticate to card for reading, could not set UID: ")); + Serial.println(MFRC522Debug::GetStatusCodeName(status)); + } + return false; + } + } else { + if (logErrors) { + Serial.print(F("PCD_Authenticate() failed: ")); + Serial.println(MFRC522Debug::GetStatusCodeName(status)); + } + return false; + } + } + + // Read block 0 + byte block0_buffer[18]; + byte byteCount = sizeof(block0_buffer); + status = _device->MIFARE_Read((byte) 0, block0_buffer, &byteCount); + if (status != MFRC522::STATUS_OK) { + if (logErrors) { + Serial.print(F("MIFARE_Read() failed: ")); + Serial.println(MFRC522Debug::GetStatusCodeName(status)); + Serial.println(F("Are you sure your KEY A for sector 0 is 0xFFFFFFFFFFFF?")); + } + return false; + } + + // Write new UID to the data we just read, and calculate BCC byte + byte bcc = 0; + for (uint8_t i = 0; i < uidSize; i++) { + block0_buffer[i] = newUid[i]; + bcc ^= newUid[i]; + } + + // Write BCC byte to buffer + block0_buffer[uidSize] = bcc; + + // Stop encrypted traffic so we can send raw bytes + _device->PCD_StopCrypto1(); + + // Activate UID backdoor + if (!MIFARE_OpenUidBackdoor(logErrors)) { + if (logErrors) { + Serial.println(F("Activating the UID backdoor failed.")); + } + return false; + } + + // Write modified block 0 back to card + status = _device->MIFARE_Write((byte) 0, block0_buffer, (byte) 16); + if (status != MFRC522::STATUS_OK) { + if (logErrors) { + Serial.print(F("MIFARE_Write() failed: ")); + Serial.println(MFRC522Debug::GetStatusCodeName(status)); + } + return false; + } + + // Wake the card up again + byte atqa_answer[2]; + byte atqa_size = 2; + _device->PICC_WakeupA(atqa_answer, &atqa_size); + + return true; +} + +/** + * Resets entire sector 0 to zeroes, so the card can be read again by readers. + */ +bool MFRC522Hack::MIFARE_UnbrickUidSector(bool logErrors) { + MIFARE_OpenUidBackdoor(logErrors); + + byte block0_buffer[] = {0x01, 0x02, 0x03, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00}; + + // Write modified block 0 back to card + MFRC522::StatusCode status = _device->MIFARE_Write((byte) 0, block0_buffer, (byte) 16); + if (status != MFRC522::STATUS_OK) { + if (logErrors) { + Serial.print(F("MIFARE_Write() failed: ")); + Serial.println(MFRC522Debug::GetStatusCodeName(status)); + } + return false; + } + return true; +} diff --git a/src/MFRC522Hack.h b/src/MFRC522Hack.h new file mode 100644 index 0000000..e865f00 --- /dev/null +++ b/src/MFRC522Hack.h @@ -0,0 +1,22 @@ +#ifndef MFRC522HACK_H +#define MFRC522HACK_H + +#include +#include "MFRC522.h" +#include "MFRC522Debug.h" + +class MFRC522Hack { +private: + MFRC522 *const _device; +public: + MFRC522Hack(MFRC522 *device) : _device(device) {}; + + bool MIFARE_OpenUidBackdoor(bool logErrors); + + bool MIFARE_SetUid(byte *newUid, byte uidSize, bool logErrors); + + bool MIFARE_UnbrickUidSector(bool logErrors); +}; + + +#endif //MFRC522HACK_H