PN532 NFC library for Seeed Studio's NFC Shield
Fork of PN532 by
Embed:
(wiki syntax)
Show/hide line numbers
MifareUltralight.cpp
00001 #include "MifareUltralight.h" 00002 00003 #include "PN532_debug.h" 00004 00005 #define ULTRALIGHT_PAGE_SIZE 4 00006 #define ULTRALIGHT_READ_SIZE 4 // we should be able to read 16 uint8_ts at a time 00007 00008 #define ULTRALIGHT_DATA_START_PAGE 4 00009 #define ULTRALIGHT_MESSAGE_LENGTH_INDEX 1 00010 #define ULTRALIGHT_DATA_START_INDEX 2 00011 #define ULTRALIGHT_MAX_PAGE 63 00012 00013 #define NFC_FORUM_TAG_TYPE_2 ("NFC Forum Type 2") 00014 00015 MifareUltralight::MifareUltralight(PN532& nfcShield) 00016 { 00017 nfc = &nfcShield; 00018 ndefStartIndex = 0; 00019 messageLength = 0; 00020 } 00021 00022 MifareUltralight::~MifareUltralight() 00023 { 00024 } 00025 00026 NfcTag MifareUltralight::read(uint8_t * uid, unsigned int uidLength) 00027 { 00028 if (isUnformatted()) 00029 { 00030 DMSG("WARNING: Tag is not formatted."); 00031 return NfcTag(uid, uidLength, NFC_FORUM_TAG_TYPE_2); 00032 } 00033 00034 readCapabilityContainer(); // meta info for tag 00035 findNdefMessage(); 00036 calculateBufferSize(); 00037 00038 if (messageLength == 0) { // data is 0x44 0x03 0x00 0xFE 00039 NdefMessage message = NdefMessage(); 00040 message.addEmptyRecord(); 00041 return NfcTag(uid, uidLength, NFC_FORUM_TAG_TYPE_2, message); 00042 } 00043 00044 bool success; 00045 uint8_t page; 00046 uint8_t index = 0; 00047 uint8_t buffer[bufferSize]; 00048 for (page = ULTRALIGHT_DATA_START_PAGE; page < ULTRALIGHT_MAX_PAGE; page++) 00049 { 00050 // read the data 00051 success = nfc->mifareultralight_ReadPage(page, &buffer[index]); 00052 if (success) 00053 { 00054 #ifdef MIFARE_ULTRALIGHT_DEBUG 00055 DMSG("Page ");Serial.print(page);DMSG(" "); 00056 nfc->PrintHexChar(&buffer[index], ULTRALIGHT_PAGE_SIZE); 00057 #endif 00058 } 00059 else 00060 { 00061 DMSG("Read failed ");DMSG_INT(page); 00062 // TODO error handling 00063 messageLength = 0; 00064 break; 00065 } 00066 00067 if (index >= (messageLength + ndefStartIndex)) 00068 { 00069 break; 00070 } 00071 00072 index += ULTRALIGHT_PAGE_SIZE; 00073 } 00074 00075 NdefMessage ndefMessage = NdefMessage(&buffer[ndefStartIndex], messageLength); 00076 return NfcTag(uid, uidLength, NFC_FORUM_TAG_TYPE_2, ndefMessage); 00077 00078 } 00079 00080 bool MifareUltralight::write(NdefMessage& m, uint8_t * uid, unsigned int uidLength) 00081 { 00082 00083 if (isUnformatted()) 00084 { 00085 printf("WARNING: Tag is not formatted.\r\n"); 00086 return false; 00087 } 00088 readCapabilityContainer(); // meta info for tag 00089 00090 messageLength = m.getEncodedSize(); 00091 ndefStartIndex = messageLength < 0xFF ? 2 : 4; 00092 calculateBufferSize(); 00093 00094 if(bufferSize>tagCapacity) { 00095 /* #ifdef MIFARE_ULTRALIGHT_DEBUG 00096 Serial.print(F("Encoded Message length exceeded tag Capacity "));Serial.println(tagCapacity); 00097 #endif*/ 00098 return false; 00099 } 00100 00101 uint8_t encoded[bufferSize]; 00102 uint8_t * src = encoded; 00103 unsigned int position = 0; 00104 uint8_t page = ULTRALIGHT_DATA_START_PAGE; 00105 00106 // Set message size. With ultralight should always be less than 0xFF but who knows? 00107 00108 encoded[0] = 0x3; 00109 if (messageLength < 0xFF) 00110 { 00111 encoded[1] = messageLength; 00112 } 00113 else 00114 { 00115 encoded[1] = 0xFF; 00116 encoded[2] = ((messageLength >> 8) & 0xFF); 00117 encoded[3] = (messageLength & 0xFF); 00118 } 00119 00120 m.encode(encoded+ndefStartIndex); 00121 // this is always at least 1 byte copy because of terminator. 00122 memset(encoded+ndefStartIndex+messageLength,0,bufferSize-ndefStartIndex-messageLength); 00123 encoded[ndefStartIndex+messageLength] = 0xFE; // terminator 00124 00125 while (position < bufferSize){ //bufferSize is always times pagesize so no "last chunk" check 00126 // write page 00127 if (!nfc->mifareultralight_WritePage(page, src)) 00128 return false; 00129 page++; 00130 src+=ULTRALIGHT_PAGE_SIZE; 00131 position+=ULTRALIGHT_PAGE_SIZE; 00132 } 00133 return true; 00134 } 00135 bool MifareUltralight::isUnformatted() 00136 { 00137 uint8_t page = 4; 00138 uint8_t data[ULTRALIGHT_READ_SIZE]; 00139 bool success = nfc->mifareultralight_ReadPage (page, data); 00140 if (success) 00141 { 00142 return (data[0] == 0xFF && data[1] == 0xFF && data[2] == 0xFF && data[3] == 0xFF); 00143 } 00144 else 00145 { 00146 DMSG("Error. Failed read page ");DMSG_INT(page); 00147 return false; 00148 } 00149 } 00150 00151 // page 3 has tag capabilities 00152 void MifareUltralight::readCapabilityContainer() 00153 { 00154 uint8_t data[ULTRALIGHT_PAGE_SIZE]; 00155 int success = nfc->mifareultralight_ReadPage (3, data); 00156 if (success) 00157 { 00158 // See AN1303 - different rules for Mifare Family uint8_t2 = (additional data + 48)/8 00159 tagCapacity = data[2] * 8; 00160 #ifdef MIFARE_ULTRALIGHT_DEBUG 00161 DMSG("Tag capacity "));Serial.print(tagCapacity);DMSG(F(" uint8_ts"); 00162 #endif 00163 00164 // TODO future versions should get lock information 00165 } 00166 } 00167 00168 // read enough of the message to find the ndef message length 00169 void MifareUltralight::findNdefMessage() 00170 { 00171 int page; 00172 uint8_t data[12]; // 3 pages 00173 uint8_t* data_ptr = &data[0]; 00174 00175 // the nxp read command reads 4 pages, unfortunately adafruit give me one page at a time 00176 bool success = true; 00177 for (page = 4; page < 6; page++) 00178 { 00179 success = success && nfc->mifareultralight_ReadPage(page, data_ptr); 00180 #ifdef MIFARE_ULTRALIGHT_DEBUG 00181 DMSG("Page "));Serial.print(page);Serial.print(F(" - "); 00182 nfc->PrintHexChar(data_ptr, 4); 00183 #endif 00184 data_ptr += ULTRALIGHT_PAGE_SIZE; 00185 } 00186 00187 if (success) 00188 { 00189 if (data[0] == 0x03) 00190 { 00191 messageLength = data[1]; 00192 ndefStartIndex = 2; 00193 } 00194 else if (data[5] == 0x3) // page 5 uint8_t 1 00195 { 00196 // TODO should really read the lock control TLV to ensure uint8_t[5] is correct 00197 messageLength = data[6]; 00198 ndefStartIndex = 7; 00199 } 00200 } 00201 00202 #ifdef MIFARE_ULTRALIGHT_DEBUG 00203 DMSG("messageLength ");DMSG(messageLength); 00204 DMSG("ndefStartIndex ");DMSG(ndefStartIndex); 00205 #endif 00206 } 00207 00208 // buffer is larger than the message, need to handle some data before and after 00209 // message and need to ensure we read full pages 00210 void MifareUltralight::calculateBufferSize() 00211 { 00212 // TLV terminator 0xFE is 1 uint8_t 00213 bufferSize = messageLength + ndefStartIndex + 1; 00214 00215 if (bufferSize % ULTRALIGHT_READ_SIZE != 0) 00216 { 00217 // buffer must be an increment of page size 00218 bufferSize = ((bufferSize / ULTRALIGHT_READ_SIZE) + 1) * ULTRALIGHT_READ_SIZE; 00219 } 00220 }
Generated on Tue Jul 12 2022 17:32:26 by 1.7.2