PN532 NFC shield of Adafruit based on PN532 of Seeed.
Fork of PN532 by
MifareUltralight.cpp@3:4189a10038e6, 2013-11-21 (annotated)
- Committer:
- yihui
- Date:
- Thu Nov 21 04:30:49 2013 +0000
- Revision:
- 3:4189a10038e6
- Child:
- 5:51f820fbd18a
sync with https://github.com/Seeed-Studio/PN532/releases/tag/v0.9.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
yihui | 3:4189a10038e6 | 1 | #include "MifareUltralight.h" |
yihui | 3:4189a10038e6 | 2 | |
yihui | 3:4189a10038e6 | 3 | #include "PN532_debug.h" |
yihui | 3:4189a10038e6 | 4 | |
yihui | 3:4189a10038e6 | 5 | #define ULTRALIGHT_PAGE_SIZE 4 |
yihui | 3:4189a10038e6 | 6 | #define ULTRALIGHT_READ_SIZE 4 // we should be able to read 16 uint8_ts at a time |
yihui | 3:4189a10038e6 | 7 | |
yihui | 3:4189a10038e6 | 8 | #define ULTRALIGHT_DATA_START_PAGE 4 |
yihui | 3:4189a10038e6 | 9 | #define ULTRALIGHT_MESSAGE_LENGTH_INDEX 1 |
yihui | 3:4189a10038e6 | 10 | #define ULTRALIGHT_DATA_START_INDEX 2 |
yihui | 3:4189a10038e6 | 11 | #define ULTRALIGHT_MAX_PAGE 63 |
yihui | 3:4189a10038e6 | 12 | |
yihui | 3:4189a10038e6 | 13 | #define NFC_FORUM_TAG_TYPE_2 ("NFC Forum Type 2") |
yihui | 3:4189a10038e6 | 14 | |
yihui | 3:4189a10038e6 | 15 | MifareUltralight::MifareUltralight(PN532& nfcShield) |
yihui | 3:4189a10038e6 | 16 | { |
yihui | 3:4189a10038e6 | 17 | nfc = &nfcShield; |
yihui | 3:4189a10038e6 | 18 | ndefStartIndex = 0; |
yihui | 3:4189a10038e6 | 19 | messageLength = 0; |
yihui | 3:4189a10038e6 | 20 | } |
yihui | 3:4189a10038e6 | 21 | |
yihui | 3:4189a10038e6 | 22 | MifareUltralight::~MifareUltralight() |
yihui | 3:4189a10038e6 | 23 | { |
yihui | 3:4189a10038e6 | 24 | } |
yihui | 3:4189a10038e6 | 25 | |
yihui | 3:4189a10038e6 | 26 | NfcTag MifareUltralight::read(uint8_t * uid, unsigned int uidLength) |
yihui | 3:4189a10038e6 | 27 | { |
yihui | 3:4189a10038e6 | 28 | if (isUnformatted()) |
yihui | 3:4189a10038e6 | 29 | { |
yihui | 3:4189a10038e6 | 30 | DMSG("WARNING: Tag is not formatted."); |
yihui | 3:4189a10038e6 | 31 | return NfcTag(uid, uidLength, NFC_FORUM_TAG_TYPE_2); |
yihui | 3:4189a10038e6 | 32 | } |
yihui | 3:4189a10038e6 | 33 | |
yihui | 3:4189a10038e6 | 34 | readCapabilityContainer(); // meta info for tag |
yihui | 3:4189a10038e6 | 35 | findNdefMessage(); |
yihui | 3:4189a10038e6 | 36 | calculateBufferSize(); |
yihui | 3:4189a10038e6 | 37 | |
yihui | 3:4189a10038e6 | 38 | if (messageLength == 0) { // data is 0x44 0x03 0x00 0xFE |
yihui | 3:4189a10038e6 | 39 | NdefMessage message = NdefMessage(); |
yihui | 3:4189a10038e6 | 40 | message.addEmptyRecord(); |
yihui | 3:4189a10038e6 | 41 | return NfcTag(uid, uidLength, NFC_FORUM_TAG_TYPE_2, message); |
yihui | 3:4189a10038e6 | 42 | } |
yihui | 3:4189a10038e6 | 43 | |
yihui | 3:4189a10038e6 | 44 | bool success; |
yihui | 3:4189a10038e6 | 45 | uint8_t page; |
yihui | 3:4189a10038e6 | 46 | uint8_t index = 0; |
yihui | 3:4189a10038e6 | 47 | uint8_t buffer[bufferSize]; |
yihui | 3:4189a10038e6 | 48 | for (page = ULTRALIGHT_DATA_START_PAGE; page < ULTRALIGHT_MAX_PAGE; page++) |
yihui | 3:4189a10038e6 | 49 | { |
yihui | 3:4189a10038e6 | 50 | // read the data |
yihui | 3:4189a10038e6 | 51 | success = nfc->mifareultralight_ReadPage(page, &buffer[index]); |
yihui | 3:4189a10038e6 | 52 | if (success) |
yihui | 3:4189a10038e6 | 53 | { |
yihui | 3:4189a10038e6 | 54 | #ifdef MIFARE_ULTRALIGHT_DEBUG |
yihui | 3:4189a10038e6 | 55 | DMSG("Page ");Serial.print(page);DMSG(" "); |
yihui | 3:4189a10038e6 | 56 | nfc->PrintHexChar(&buffer[index], ULTRALIGHT_PAGE_SIZE); |
yihui | 3:4189a10038e6 | 57 | #endif |
yihui | 3:4189a10038e6 | 58 | } |
yihui | 3:4189a10038e6 | 59 | else |
yihui | 3:4189a10038e6 | 60 | { |
yihui | 3:4189a10038e6 | 61 | DMSG("Read failed ");DMSG_INT(page); |
yihui | 3:4189a10038e6 | 62 | // TODO error handling |
yihui | 3:4189a10038e6 | 63 | messageLength = 0; |
yihui | 3:4189a10038e6 | 64 | break; |
yihui | 3:4189a10038e6 | 65 | } |
yihui | 3:4189a10038e6 | 66 | |
yihui | 3:4189a10038e6 | 67 | if (index >= (messageLength + ndefStartIndex)) |
yihui | 3:4189a10038e6 | 68 | { |
yihui | 3:4189a10038e6 | 69 | break; |
yihui | 3:4189a10038e6 | 70 | } |
yihui | 3:4189a10038e6 | 71 | |
yihui | 3:4189a10038e6 | 72 | index += ULTRALIGHT_PAGE_SIZE; |
yihui | 3:4189a10038e6 | 73 | } |
yihui | 3:4189a10038e6 | 74 | |
yihui | 3:4189a10038e6 | 75 | NdefMessage ndefMessage = NdefMessage(&buffer[ndefStartIndex], messageLength); |
yihui | 3:4189a10038e6 | 76 | return NfcTag(uid, uidLength, NFC_FORUM_TAG_TYPE_2, ndefMessage); |
yihui | 3:4189a10038e6 | 77 | |
yihui | 3:4189a10038e6 | 78 | } |
yihui | 3:4189a10038e6 | 79 | |
yihui | 3:4189a10038e6 | 80 | bool MifareUltralight::isUnformatted() |
yihui | 3:4189a10038e6 | 81 | { |
yihui | 3:4189a10038e6 | 82 | uint8_t page = 4; |
yihui | 3:4189a10038e6 | 83 | uint8_t data[ULTRALIGHT_READ_SIZE]; |
yihui | 3:4189a10038e6 | 84 | bool success = nfc->mifareultralight_ReadPage (page, data); |
yihui | 3:4189a10038e6 | 85 | if (success) |
yihui | 3:4189a10038e6 | 86 | { |
yihui | 3:4189a10038e6 | 87 | return (data[0] == 0xFF && data[1] == 0xFF && data[2] == 0xFF && data[3] == 0xFF); |
yihui | 3:4189a10038e6 | 88 | } |
yihui | 3:4189a10038e6 | 89 | else |
yihui | 3:4189a10038e6 | 90 | { |
yihui | 3:4189a10038e6 | 91 | DMSG("Error. Failed read page ");DMSG_INT(page); |
yihui | 3:4189a10038e6 | 92 | return false; |
yihui | 3:4189a10038e6 | 93 | } |
yihui | 3:4189a10038e6 | 94 | } |
yihui | 3:4189a10038e6 | 95 | |
yihui | 3:4189a10038e6 | 96 | // page 3 has tag capabilities |
yihui | 3:4189a10038e6 | 97 | void MifareUltralight::readCapabilityContainer() |
yihui | 3:4189a10038e6 | 98 | { |
yihui | 3:4189a10038e6 | 99 | uint8_t data[ULTRALIGHT_PAGE_SIZE]; |
yihui | 3:4189a10038e6 | 100 | int success = nfc->mifareultralight_ReadPage (3, data); |
yihui | 3:4189a10038e6 | 101 | if (success) |
yihui | 3:4189a10038e6 | 102 | { |
yihui | 3:4189a10038e6 | 103 | // See AN1303 - different rules for Mifare Family uint8_t2 = (additional data + 48)/8 |
yihui | 3:4189a10038e6 | 104 | tagCapacity = data[2] * 8; |
yihui | 3:4189a10038e6 | 105 | #ifdef MIFARE_ULTRALIGHT_DEBUG |
yihui | 3:4189a10038e6 | 106 | DMSG("Tag capacity "));Serial.print(tagCapacity);DMSG(F(" uint8_ts"); |
yihui | 3:4189a10038e6 | 107 | #endif |
yihui | 3:4189a10038e6 | 108 | |
yihui | 3:4189a10038e6 | 109 | // TODO future versions should get lock information |
yihui | 3:4189a10038e6 | 110 | } |
yihui | 3:4189a10038e6 | 111 | } |
yihui | 3:4189a10038e6 | 112 | |
yihui | 3:4189a10038e6 | 113 | // read enough of the message to find the ndef message length |
yihui | 3:4189a10038e6 | 114 | void MifareUltralight::findNdefMessage() |
yihui | 3:4189a10038e6 | 115 | { |
yihui | 3:4189a10038e6 | 116 | int page; |
yihui | 3:4189a10038e6 | 117 | uint8_t data[12]; // 3 pages |
yihui | 3:4189a10038e6 | 118 | uint8_t* data_ptr = &data[0]; |
yihui | 3:4189a10038e6 | 119 | |
yihui | 3:4189a10038e6 | 120 | // the nxp read command reads 4 pages, unfortunately adafruit give me one page at a time |
yihui | 3:4189a10038e6 | 121 | bool success = true; |
yihui | 3:4189a10038e6 | 122 | for (page = 4; page < 6; page++) |
yihui | 3:4189a10038e6 | 123 | { |
yihui | 3:4189a10038e6 | 124 | success = success && nfc->mifareultralight_ReadPage(page, data_ptr); |
yihui | 3:4189a10038e6 | 125 | #ifdef MIFARE_ULTRALIGHT_DEBUG |
yihui | 3:4189a10038e6 | 126 | DMSG("Page "));Serial.print(page);Serial.print(F(" - "); |
yihui | 3:4189a10038e6 | 127 | nfc->PrintHexChar(data_ptr, 4); |
yihui | 3:4189a10038e6 | 128 | #endif |
yihui | 3:4189a10038e6 | 129 | data_ptr += ULTRALIGHT_PAGE_SIZE; |
yihui | 3:4189a10038e6 | 130 | } |
yihui | 3:4189a10038e6 | 131 | |
yihui | 3:4189a10038e6 | 132 | if (success) |
yihui | 3:4189a10038e6 | 133 | { |
yihui | 3:4189a10038e6 | 134 | if (data[0] == 0x03) |
yihui | 3:4189a10038e6 | 135 | { |
yihui | 3:4189a10038e6 | 136 | messageLength = data[1]; |
yihui | 3:4189a10038e6 | 137 | ndefStartIndex = 2; |
yihui | 3:4189a10038e6 | 138 | } |
yihui | 3:4189a10038e6 | 139 | else if (data[5] == 0x3) // page 5 uint8_t 1 |
yihui | 3:4189a10038e6 | 140 | { |
yihui | 3:4189a10038e6 | 141 | // TODO should really read the lock control TLV to ensure uint8_t[5] is correct |
yihui | 3:4189a10038e6 | 142 | messageLength = data[6]; |
yihui | 3:4189a10038e6 | 143 | ndefStartIndex = 7; |
yihui | 3:4189a10038e6 | 144 | } |
yihui | 3:4189a10038e6 | 145 | } |
yihui | 3:4189a10038e6 | 146 | |
yihui | 3:4189a10038e6 | 147 | #ifdef MIFARE_ULTRALIGHT_DEBUG |
yihui | 3:4189a10038e6 | 148 | DMSG("messageLength ");DMSG(messageLength); |
yihui | 3:4189a10038e6 | 149 | DMSG("ndefStartIndex ");DMSG(ndefStartIndex); |
yihui | 3:4189a10038e6 | 150 | #endif |
yihui | 3:4189a10038e6 | 151 | } |
yihui | 3:4189a10038e6 | 152 | |
yihui | 3:4189a10038e6 | 153 | // buffer is larger than the message, need to handle some data before and after |
yihui | 3:4189a10038e6 | 154 | // message and need to ensure we read full pages |
yihui | 3:4189a10038e6 | 155 | void MifareUltralight::calculateBufferSize() |
yihui | 3:4189a10038e6 | 156 | { |
yihui | 3:4189a10038e6 | 157 | // TLV terminator 0xFE is 1 uint8_t |
yihui | 3:4189a10038e6 | 158 | bufferSize = messageLength + ndefStartIndex + 1; |
yihui | 3:4189a10038e6 | 159 | |
yihui | 3:4189a10038e6 | 160 | if (bufferSize % ULTRALIGHT_READ_SIZE != 0) |
yihui | 3:4189a10038e6 | 161 | { |
yihui | 3:4189a10038e6 | 162 | // buffer must be an increment of page size |
yihui | 3:4189a10038e6 | 163 | bufferSize = ((bufferSize / ULTRALIGHT_READ_SIZE) + 1) * ULTRALIGHT_READ_SIZE; |
yihui | 3:4189a10038e6 | 164 | } |
yihui | 3:4189a10038e6 | 165 | } |