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