some additional fixes
Fork of PN532 by
MifareUltralight.cpp@5:51f820fbd18a, 2014-10-07 (annotated)
- Committer:
- icefeet
- Date:
- Tue Oct 07 15:09:46 2014 +0000
- Revision:
- 5:51f820fbd18a
- Parent:
- 3:4189a10038e6
Added support for Ultralight Write
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 | |
icefeet | 5:51f820fbd18a | 80 | bool MifareUltralight::write(NdefMessage& m, uint8_t * uid, unsigned int uidLength) |
icefeet | 5:51f820fbd18a | 81 | { |
icefeet | 5:51f820fbd18a | 82 | |
icefeet | 5:51f820fbd18a | 83 | if (isUnformatted()) |
icefeet | 5:51f820fbd18a | 84 | { |
icefeet | 5:51f820fbd18a | 85 | printf("WARNING: Tag is not formatted.\r\n"); |
icefeet | 5:51f820fbd18a | 86 | return false; |
icefeet | 5:51f820fbd18a | 87 | } |
icefeet | 5:51f820fbd18a | 88 | readCapabilityContainer(); // meta info for tag |
icefeet | 5:51f820fbd18a | 89 | |
icefeet | 5:51f820fbd18a | 90 | messageLength = m.getEncodedSize(); |
icefeet | 5:51f820fbd18a | 91 | ndefStartIndex = messageLength < 0xFF ? 2 : 4; |
icefeet | 5:51f820fbd18a | 92 | calculateBufferSize(); |
icefeet | 5:51f820fbd18a | 93 | |
icefeet | 5:51f820fbd18a | 94 | if(bufferSize>tagCapacity) { |
icefeet | 5:51f820fbd18a | 95 | /* #ifdef MIFARE_ULTRALIGHT_DEBUG |
icefeet | 5:51f820fbd18a | 96 | Serial.print(F("Encoded Message length exceeded tag Capacity "));Serial.println(tagCapacity); |
icefeet | 5:51f820fbd18a | 97 | #endif*/ |
icefeet | 5:51f820fbd18a | 98 | return false; |
icefeet | 5:51f820fbd18a | 99 | } |
icefeet | 5:51f820fbd18a | 100 | |
icefeet | 5:51f820fbd18a | 101 | uint8_t encoded[bufferSize]; |
icefeet | 5:51f820fbd18a | 102 | uint8_t * src = encoded; |
icefeet | 5:51f820fbd18a | 103 | unsigned int position = 0; |
icefeet | 5:51f820fbd18a | 104 | uint8_t page = ULTRALIGHT_DATA_START_PAGE; |
icefeet | 5:51f820fbd18a | 105 | |
icefeet | 5:51f820fbd18a | 106 | // Set message size. With ultralight should always be less than 0xFF but who knows? |
icefeet | 5:51f820fbd18a | 107 | |
icefeet | 5:51f820fbd18a | 108 | encoded[0] = 0x3; |
icefeet | 5:51f820fbd18a | 109 | if (messageLength < 0xFF) |
icefeet | 5:51f820fbd18a | 110 | { |
icefeet | 5:51f820fbd18a | 111 | encoded[1] = messageLength; |
icefeet | 5:51f820fbd18a | 112 | } |
icefeet | 5:51f820fbd18a | 113 | else |
icefeet | 5:51f820fbd18a | 114 | { |
icefeet | 5:51f820fbd18a | 115 | encoded[1] = 0xFF; |
icefeet | 5:51f820fbd18a | 116 | encoded[2] = ((messageLength >> 8) & 0xFF); |
icefeet | 5:51f820fbd18a | 117 | encoded[3] = (messageLength & 0xFF); |
icefeet | 5:51f820fbd18a | 118 | } |
icefeet | 5:51f820fbd18a | 119 | |
icefeet | 5:51f820fbd18a | 120 | m.encode(encoded+ndefStartIndex); |
icefeet | 5:51f820fbd18a | 121 | // this is always at least 1 byte copy because of terminator. |
icefeet | 5:51f820fbd18a | 122 | memset(encoded+ndefStartIndex+messageLength,0,bufferSize-ndefStartIndex-messageLength); |
icefeet | 5:51f820fbd18a | 123 | encoded[ndefStartIndex+messageLength] = 0xFE; // terminator |
icefeet | 5:51f820fbd18a | 124 | |
icefeet | 5:51f820fbd18a | 125 | while (position < bufferSize){ //bufferSize is always times pagesize so no "last chunk" check |
icefeet | 5:51f820fbd18a | 126 | // write page |
icefeet | 5:51f820fbd18a | 127 | if (!nfc->mifareultralight_WritePage(page, src)) |
icefeet | 5:51f820fbd18a | 128 | return false; |
icefeet | 5:51f820fbd18a | 129 | page++; |
icefeet | 5:51f820fbd18a | 130 | src+=ULTRALIGHT_PAGE_SIZE; |
icefeet | 5:51f820fbd18a | 131 | position+=ULTRALIGHT_PAGE_SIZE; |
icefeet | 5:51f820fbd18a | 132 | } |
icefeet | 5:51f820fbd18a | 133 | return true; |
icefeet | 5:51f820fbd18a | 134 | } |
yihui | 3:4189a10038e6 | 135 | bool MifareUltralight::isUnformatted() |
yihui | 3:4189a10038e6 | 136 | { |
yihui | 3:4189a10038e6 | 137 | uint8_t page = 4; |
yihui | 3:4189a10038e6 | 138 | uint8_t data[ULTRALIGHT_READ_SIZE]; |
yihui | 3:4189a10038e6 | 139 | bool success = nfc->mifareultralight_ReadPage (page, data); |
yihui | 3:4189a10038e6 | 140 | if (success) |
yihui | 3:4189a10038e6 | 141 | { |
yihui | 3:4189a10038e6 | 142 | return (data[0] == 0xFF && data[1] == 0xFF && data[2] == 0xFF && data[3] == 0xFF); |
yihui | 3:4189a10038e6 | 143 | } |
yihui | 3:4189a10038e6 | 144 | else |
yihui | 3:4189a10038e6 | 145 | { |
yihui | 3:4189a10038e6 | 146 | DMSG("Error. Failed read page ");DMSG_INT(page); |
yihui | 3:4189a10038e6 | 147 | return false; |
yihui | 3:4189a10038e6 | 148 | } |
yihui | 3:4189a10038e6 | 149 | } |
yihui | 3:4189a10038e6 | 150 | |
yihui | 3:4189a10038e6 | 151 | // page 3 has tag capabilities |
yihui | 3:4189a10038e6 | 152 | void MifareUltralight::readCapabilityContainer() |
yihui | 3:4189a10038e6 | 153 | { |
yihui | 3:4189a10038e6 | 154 | uint8_t data[ULTRALIGHT_PAGE_SIZE]; |
yihui | 3:4189a10038e6 | 155 | int success = nfc->mifareultralight_ReadPage (3, data); |
yihui | 3:4189a10038e6 | 156 | if (success) |
yihui | 3:4189a10038e6 | 157 | { |
yihui | 3:4189a10038e6 | 158 | // See AN1303 - different rules for Mifare Family uint8_t2 = (additional data + 48)/8 |
yihui | 3:4189a10038e6 | 159 | tagCapacity = data[2] * 8; |
yihui | 3:4189a10038e6 | 160 | #ifdef MIFARE_ULTRALIGHT_DEBUG |
yihui | 3:4189a10038e6 | 161 | DMSG("Tag capacity "));Serial.print(tagCapacity);DMSG(F(" uint8_ts"); |
yihui | 3:4189a10038e6 | 162 | #endif |
yihui | 3:4189a10038e6 | 163 | |
yihui | 3:4189a10038e6 | 164 | // TODO future versions should get lock information |
yihui | 3:4189a10038e6 | 165 | } |
yihui | 3:4189a10038e6 | 166 | } |
yihui | 3:4189a10038e6 | 167 | |
yihui | 3:4189a10038e6 | 168 | // read enough of the message to find the ndef message length |
yihui | 3:4189a10038e6 | 169 | void MifareUltralight::findNdefMessage() |
yihui | 3:4189a10038e6 | 170 | { |
yihui | 3:4189a10038e6 | 171 | int page; |
yihui | 3:4189a10038e6 | 172 | uint8_t data[12]; // 3 pages |
yihui | 3:4189a10038e6 | 173 | uint8_t* data_ptr = &data[0]; |
yihui | 3:4189a10038e6 | 174 | |
yihui | 3:4189a10038e6 | 175 | // the nxp read command reads 4 pages, unfortunately adafruit give me one page at a time |
yihui | 3:4189a10038e6 | 176 | bool success = true; |
yihui | 3:4189a10038e6 | 177 | for (page = 4; page < 6; page++) |
yihui | 3:4189a10038e6 | 178 | { |
yihui | 3:4189a10038e6 | 179 | success = success && nfc->mifareultralight_ReadPage(page, data_ptr); |
yihui | 3:4189a10038e6 | 180 | #ifdef MIFARE_ULTRALIGHT_DEBUG |
yihui | 3:4189a10038e6 | 181 | DMSG("Page "));Serial.print(page);Serial.print(F(" - "); |
yihui | 3:4189a10038e6 | 182 | nfc->PrintHexChar(data_ptr, 4); |
yihui | 3:4189a10038e6 | 183 | #endif |
yihui | 3:4189a10038e6 | 184 | data_ptr += ULTRALIGHT_PAGE_SIZE; |
yihui | 3:4189a10038e6 | 185 | } |
yihui | 3:4189a10038e6 | 186 | |
yihui | 3:4189a10038e6 | 187 | if (success) |
yihui | 3:4189a10038e6 | 188 | { |
yihui | 3:4189a10038e6 | 189 | if (data[0] == 0x03) |
yihui | 3:4189a10038e6 | 190 | { |
yihui | 3:4189a10038e6 | 191 | messageLength = data[1]; |
yihui | 3:4189a10038e6 | 192 | ndefStartIndex = 2; |
yihui | 3:4189a10038e6 | 193 | } |
yihui | 3:4189a10038e6 | 194 | else if (data[5] == 0x3) // page 5 uint8_t 1 |
yihui | 3:4189a10038e6 | 195 | { |
yihui | 3:4189a10038e6 | 196 | // TODO should really read the lock control TLV to ensure uint8_t[5] is correct |
yihui | 3:4189a10038e6 | 197 | messageLength = data[6]; |
yihui | 3:4189a10038e6 | 198 | ndefStartIndex = 7; |
yihui | 3:4189a10038e6 | 199 | } |
yihui | 3:4189a10038e6 | 200 | } |
yihui | 3:4189a10038e6 | 201 | |
yihui | 3:4189a10038e6 | 202 | #ifdef MIFARE_ULTRALIGHT_DEBUG |
yihui | 3:4189a10038e6 | 203 | DMSG("messageLength ");DMSG(messageLength); |
yihui | 3:4189a10038e6 | 204 | DMSG("ndefStartIndex ");DMSG(ndefStartIndex); |
yihui | 3:4189a10038e6 | 205 | #endif |
yihui | 3:4189a10038e6 | 206 | } |
yihui | 3:4189a10038e6 | 207 | |
yihui | 3:4189a10038e6 | 208 | // buffer is larger than the message, need to handle some data before and after |
yihui | 3:4189a10038e6 | 209 | // message and need to ensure we read full pages |
yihui | 3:4189a10038e6 | 210 | void MifareUltralight::calculateBufferSize() |
yihui | 3:4189a10038e6 | 211 | { |
yihui | 3:4189a10038e6 | 212 | // TLV terminator 0xFE is 1 uint8_t |
yihui | 3:4189a10038e6 | 213 | bufferSize = messageLength + ndefStartIndex + 1; |
yihui | 3:4189a10038e6 | 214 | |
yihui | 3:4189a10038e6 | 215 | if (bufferSize % ULTRALIGHT_READ_SIZE != 0) |
yihui | 3:4189a10038e6 | 216 | { |
yihui | 3:4189a10038e6 | 217 | // buffer must be an increment of page size |
yihui | 3:4189a10038e6 | 218 | bufferSize = ((bufferSize / ULTRALIGHT_READ_SIZE) + 1) * ULTRALIGHT_READ_SIZE; |
yihui | 3:4189a10038e6 | 219 | } |
yihui | 3:4189a10038e6 | 220 | } |