Generic library for working with PN532-like chips

Fork of PN532 by Seeed

Committer:
r4z0r7o3
Date:
Wed Feb 04 19:26:03 2015 +0000
Revision:
11:5b8afec8bee6
Parent:
10:f959b305a571
Fix missing space in tag print()

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 }