From c2da758ca9a4a96dc7b02b18597b532b9ed73915 Mon Sep 17 00:00:00 2001 From: Don Coleman Date: Mon, 25 Aug 2014 16:38:06 -0500 Subject: [PATCH] erase(), format(), clean() erase - erases tag by writing an empty NDEF record format - format tag as NDEF (Mifare Classic only) clean - reset a tag to factory state (or close to factory state) Mifare Classic format now adds an empty NDEF record --- MifareClassic.cpp | 18 ++++++++++++++++-- MifareUltralight.cpp | 43 +++++++++++++++++++++++++++++++++---------- MifareUltralight.h | 1 + NfcAdapter.cpp | 35 ++++++++++++++++++++++++++++------- NfcAdapter.h | 8 ++++++-- 5 files changed, 84 insertions(+), 21 deletions(-) diff --git a/MifareClassic.cpp b/MifareClassic.cpp index ffdfc24..f591c93 100644 --- a/MifareClassic.cpp +++ b/MifareClassic.cpp @@ -186,9 +186,12 @@ bool MifareClassic::decodeTlv(byte *data, int &messageLength, int &messageStartI return true; } +// Intialized NDEF tag contains one empty NDEF TLV 03 00 FE - AN1304 6.3.1 +// We are formatting in read/write mode with a NDEF TLV 03 03 and an empty NDEF record D0 00 00 FE - AN1304 6.3.2 boolean MifareClassic::formatNDEF(byte * uid, unsigned int uidLength) { uint8_t keya[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + uint8_t emptyNdefMesg[16] = {0x03, 0x03, 0xD0, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; uint8_t sectorbuffer0[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; uint8_t sectorbuffer4[16] = {0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0x7F, 0x07, 0x88, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; @@ -207,10 +210,21 @@ boolean MifareClassic::formatNDEF(byte * uid, unsigned int uidLength) { for (int i=4; i<64; i+=4) { success = _nfcShield->mifareclassic_AuthenticateBlock (uid, uidLength, i, 0, keya); + if (success) { - if (!(_nfcShield->mifareclassic_WriteDataBlock (i, sectorbuffer0))) + if (i == 4) // special handling for block 4 + { + if (!(_nfcShield->mifareclassic_WriteDataBlock (i, emptyNdefMesg))) + { + Serial.print(F("Unable to write block "));Serial.println(i); + } + } + else { - Serial.print(F("Unable to write block "));Serial.println(i); + if (!(_nfcShield->mifareclassic_WriteDataBlock (i, sectorbuffer0))) + { + Serial.print(F("Unable to write block "));Serial.println(i); + } } if (!(_nfcShield->mifareclassic_WriteDataBlock (i+1, sectorbuffer0))) { diff --git a/MifareUltralight.cpp b/MifareUltralight.cpp index c862d4f..9cf941b 100644 --- a/MifareUltralight.cpp +++ b/MifareUltralight.cpp @@ -170,25 +170,25 @@ boolean MifareUltralight::write(NdefMessage& m, byte * uid, unsigned int uidLeng return false; } readCapabilityContainer(); // meta info for tag - + messageLength = m.getEncodedSize(); ndefStartIndex = messageLength < 0xFF ? 2 : 4; calculateBufferSize(); - + if(bufferSize>tagCapacity) { #ifdef MIFARE_ULTRALIGHT_DEBUG Serial.print(F("Encoded Message length exceeded tag Capacity "));Serial.println(tagCapacity); #endif return false; } - + uint8_t encoded[bufferSize]; uint8_t * src = encoded; unsigned int position = 0; uint8_t page = ULTRALIGHT_DATA_START_PAGE; - + // Set message size. With ultralight should always be less than 0xFF but who knows? - + encoded[0] = 0x3; if (messageLength < 0xFF) { @@ -200,24 +200,24 @@ boolean MifareUltralight::write(NdefMessage& m, byte * uid, unsigned int uidLeng encoded[2] = ((messageLength >> 8) & 0xFF); encoded[3] = (messageLength & 0xFF); } - + m.encode(encoded+ndefStartIndex); // this is always at least 1 byte copy because of terminator. - memset(encoded+ndefStartIndex+messageLength,0,bufferSize-ndefStartIndex-messageLength); + memset(encoded+ndefStartIndex+messageLength,0,bufferSize-ndefStartIndex-messageLength); encoded[ndefStartIndex+messageLength] = 0xFE; // terminator - + #ifdef MIFARE_ULTRALIGHT_DEBUG Serial.print(F("messageLength "));Serial.println(messageLength); Serial.print(F("Tag Capacity "));Serial.println(tagCapacity); nfc->PrintHex(encoded,bufferSize); #endif - + while (position < bufferSize){ //bufferSize is always times pagesize so no "last chunk" check // write page if (!nfc->mifareultralight_WritePage(page, src)) return false; #ifdef MIFARE_ULTRALIGHT_DEBUG - Serial.print(F("Written page "));Serial.print(page);Serial.print(F(" - ")); + Serial.print(F("Wrote page "));Serial.print(page);Serial.print(F(" - ")); nfc->PrintHex(src,ULTRALIGHT_PAGE_SIZE); #endif page++; @@ -226,3 +226,26 @@ boolean MifareUltralight::write(NdefMessage& m, byte * uid, unsigned int uidLeng } return true; } + +// Mifare Ultralight can't be reset to factory state +// zero out tag data like the NXP Tag Write Android application +boolean MifareUltralight::clean() +{ + readCapabilityContainer(); // meta info for tag + + uint8_t pages = (tagCapacity / ULTRALIGHT_PAGE_SIZE) + ULTRALIGHT_DATA_START_PAGE; + + // factory tags have 0xFF, but OTP-CC blocks have already been set so we use 0x00 + uint8_t data[4] = { 0x00, 0x00, 0x00, 0x00 }; + + for (int i = ULTRALIGHT_DATA_START_PAGE; i < pages; i++) { + #ifdef MIFARE_ULTRALIGHT_DEBUG + Serial.print(F("Wrote page "));Serial.print(i);Serial.print(F(" - ")); + nfc->PrintHex(data, ULTRALIGHT_PAGE_SIZE); + #endif + if (!nfc->mifareultralight_WritePage(i, data)) { + return false; + } + } + return true; +} diff --git a/MifareUltralight.h b/MifareUltralight.h index 66643b7..2b98849 100644 --- a/MifareUltralight.h +++ b/MifareUltralight.h @@ -12,6 +12,7 @@ class MifareUltralight ~MifareUltralight(); NfcTag read(byte *uid, unsigned int uidLength); boolean write(NdefMessage& ndefMessage, byte *uid, unsigned int uidLength); + boolean clean(); private: PN532* nfc; unsigned int tagCapacity; diff --git a/NfcAdapter.cpp b/NfcAdapter.cpp index b69468b..3cc9c62 100644 --- a/NfcAdapter.cpp +++ b/NfcAdapter.cpp @@ -48,6 +48,14 @@ boolean NfcAdapter::tagPresent(unsigned long timeout) return success; } +boolean NfcAdapter::erase() +{ + boolean success; + NdefMessage message = NdefMessage(); + message.addEmptyRecord(); + return write(message); +} + boolean NfcAdapter::format() { boolean success; @@ -64,22 +72,35 @@ boolean NfcAdapter::format() return success; } -boolean NfcAdapter::erase() +boolean NfcAdapter::clean() { - boolean success; - if (uidLength == 4) + uint8_t type = guessTagType(); + + if (type == TAG_TYPE_MIFARE_CLASSIC) { + #ifdef NDEF_DEBUG + Serial.println(F("Cleaning Mifare Classic")); + #endif MifareClassic mifareClassic = MifareClassic(*shield); - success = mifareClassic.formatMifare(uid, uidLength); + return mifareClassic.formatMifare(uid, uidLength); + } + else if (type == TAG_TYPE_2) + { + #ifdef NDEF_DEBUG + Serial.println(F("Cleaning Mifare Ultralight")); + #endif + MifareUltralight ultralight = MifareUltralight(*shield); + return ultralight.clean(); } else { - Serial.print(F("Unsupported Tag. Length is "));Serial.println(uidLength); - success = false; + Serial.print(F("No driver for card type "));Serial.println(type); + return false; } - return success; + } + NfcTag NfcAdapter::read() { uint8_t type = guessTagType(); diff --git a/NfcAdapter.h b/NfcAdapter.h index c65b076..1ef9e59 100644 --- a/NfcAdapter.h +++ b/NfcAdapter.h @@ -29,8 +29,12 @@ class NfcAdapter { boolean tagPresent(unsigned long timeout=0); // tagAvailable NfcTag read(); boolean write(NdefMessage& ndefMessage); - boolean erase(); // brings MifareClassic at original state - boolean format(); // format MifareClassic to NDEF + // erase tag by writing an empty NDEF record + boolean erase(); + // format a tag as NDEF + boolean format(); + // reset tag back to factory state + boolean clean(); private: PN532* shield; byte uid[7]; // Buffer to store the returned UID