Generic library for working with PN532-like chips

Fork of PN532 by Seeed

Committer:
r4z0r7o3
Date:
Wed Feb 04 19:04:54 2015 +0000
Revision:
10:f959b305a571
Parent:
5:51f820fbd18a
Try multiple known auth. keys on classic.  Also fixed all debugging messages so they all end with newlines.

Who changed what in which revision?

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