some additional fixes
Fork of PN532 by
Diff: MifareUltralight.cpp
- Revision:
- 3:4189a10038e6
- Child:
- 5:51f820fbd18a
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MifareUltralight.cpp Thu Nov 21 04:30:49 2013 +0000 @@ -0,0 +1,165 @@ +#include "MifareUltralight.h" + +#include "PN532_debug.h" + +#define ULTRALIGHT_PAGE_SIZE 4 +#define ULTRALIGHT_READ_SIZE 4 // we should be able to read 16 uint8_ts at a time + +#define ULTRALIGHT_DATA_START_PAGE 4 +#define ULTRALIGHT_MESSAGE_LENGTH_INDEX 1 +#define ULTRALIGHT_DATA_START_INDEX 2 +#define ULTRALIGHT_MAX_PAGE 63 + +#define NFC_FORUM_TAG_TYPE_2 ("NFC Forum Type 2") + +MifareUltralight::MifareUltralight(PN532& nfcShield) +{ + nfc = &nfcShield; + ndefStartIndex = 0; + messageLength = 0; +} + +MifareUltralight::~MifareUltralight() +{ +} + +NfcTag MifareUltralight::read(uint8_t * uid, unsigned int uidLength) +{ + if (isUnformatted()) + { + DMSG("WARNING: Tag is not formatted."); + return NfcTag(uid, uidLength, NFC_FORUM_TAG_TYPE_2); + } + + readCapabilityContainer(); // meta info for tag + findNdefMessage(); + calculateBufferSize(); + + if (messageLength == 0) { // data is 0x44 0x03 0x00 0xFE + NdefMessage message = NdefMessage(); + message.addEmptyRecord(); + return NfcTag(uid, uidLength, NFC_FORUM_TAG_TYPE_2, message); + } + + bool success; + uint8_t page; + uint8_t index = 0; + uint8_t buffer[bufferSize]; + for (page = ULTRALIGHT_DATA_START_PAGE; page < ULTRALIGHT_MAX_PAGE; page++) + { + // read the data + success = nfc->mifareultralight_ReadPage(page, &buffer[index]); + if (success) + { + #ifdef MIFARE_ULTRALIGHT_DEBUG + DMSG("Page ");Serial.print(page);DMSG(" "); + nfc->PrintHexChar(&buffer[index], ULTRALIGHT_PAGE_SIZE); + #endif + } + else + { + DMSG("Read failed ");DMSG_INT(page); + // TODO error handling + messageLength = 0; + break; + } + + if (index >= (messageLength + ndefStartIndex)) + { + break; + } + + index += ULTRALIGHT_PAGE_SIZE; + } + + NdefMessage ndefMessage = NdefMessage(&buffer[ndefStartIndex], messageLength); + return NfcTag(uid, uidLength, NFC_FORUM_TAG_TYPE_2, ndefMessage); + +} + +bool MifareUltralight::isUnformatted() +{ + uint8_t page = 4; + uint8_t data[ULTRALIGHT_READ_SIZE]; + bool success = nfc->mifareultralight_ReadPage (page, data); + if (success) + { + return (data[0] == 0xFF && data[1] == 0xFF && data[2] == 0xFF && data[3] == 0xFF); + } + else + { + DMSG("Error. Failed read page ");DMSG_INT(page); + return false; + } +} + +// page 3 has tag capabilities +void MifareUltralight::readCapabilityContainer() +{ + uint8_t data[ULTRALIGHT_PAGE_SIZE]; + int success = nfc->mifareultralight_ReadPage (3, data); + if (success) + { + // See AN1303 - different rules for Mifare Family uint8_t2 = (additional data + 48)/8 + tagCapacity = data[2] * 8; + #ifdef MIFARE_ULTRALIGHT_DEBUG + DMSG("Tag capacity "));Serial.print(tagCapacity);DMSG(F(" uint8_ts"); + #endif + + // TODO future versions should get lock information + } +} + +// read enough of the message to find the ndef message length +void MifareUltralight::findNdefMessage() +{ + int page; + uint8_t data[12]; // 3 pages + uint8_t* data_ptr = &data[0]; + + // the nxp read command reads 4 pages, unfortunately adafruit give me one page at a time + bool success = true; + for (page = 4; page < 6; page++) + { + success = success && nfc->mifareultralight_ReadPage(page, data_ptr); + #ifdef MIFARE_ULTRALIGHT_DEBUG + DMSG("Page "));Serial.print(page);Serial.print(F(" - "); + nfc->PrintHexChar(data_ptr, 4); + #endif + data_ptr += ULTRALIGHT_PAGE_SIZE; + } + + if (success) + { + if (data[0] == 0x03) + { + messageLength = data[1]; + ndefStartIndex = 2; + } + else if (data[5] == 0x3) // page 5 uint8_t 1 + { + // TODO should really read the lock control TLV to ensure uint8_t[5] is correct + messageLength = data[6]; + ndefStartIndex = 7; + } + } + + #ifdef MIFARE_ULTRALIGHT_DEBUG + DMSG("messageLength ");DMSG(messageLength); + DMSG("ndefStartIndex ");DMSG(ndefStartIndex); + #endif +} + +// buffer is larger than the message, need to handle some data before and after +// message and need to ensure we read full pages +void MifareUltralight::calculateBufferSize() +{ + // TLV terminator 0xFE is 1 uint8_t + bufferSize = messageLength + ndefStartIndex + 1; + + if (bufferSize % ULTRALIGHT_READ_SIZE != 0) + { + // buffer must be an increment of page size + bufferSize = ((bufferSize / ULTRALIGHT_READ_SIZE) + 1) * ULTRALIGHT_READ_SIZE; + } +}