MifareUltralight.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. #include <MifareUltralight.h>
  2. MifareUltralight::MifareUltralight(MFRC522 *nfcShield)
  3. {
  4. nfc = nfcShield;
  5. }
  6. MifareUltralight::~MifareUltralight()
  7. {
  8. }
  9. NfcTag MifareUltralight::read()
  10. {
  11. if (isUnformatted())
  12. {
  13. #ifdef NDEF_USE_SERIAL
  14. Serial.println(F("WARNING: Tag is not formatted."));
  15. #endif
  16. return NfcTag(nfc->uid.uidByte, nfc->uid.size, NfcTag::TYPE_2);
  17. }
  18. uint16_t messageLength = 0;
  19. uint16_t ndefStartIndex = 0;
  20. findNdefMessage(&messageLength, &ndefStartIndex);
  21. uint16_t bufferSize = calculateBufferSize(messageLength, ndefStartIndex);
  22. if (messageLength == 0) { // data is 0x44 0x03 0x00 0xFE
  23. NdefMessage message = NdefMessage();
  24. message.addEmptyRecord();
  25. return NfcTag(nfc->uid.uidByte, nfc->uid.size, NfcTag::TYPE_2, message);
  26. }
  27. uint8_t index = 0;
  28. byte buffer[bufferSize];
  29. for (uint8_t page = ULTRALIGHT_DATA_START_PAGE; page < ULTRALIGHT_MAX_PAGE; page+=(ULTRALIGHT_READ_SIZE/ULTRALIGHT_PAGE_SIZE))
  30. {
  31. // read the data
  32. byte dataSize = ULTRALIGHT_READ_SIZE + 2;
  33. MFRC522::StatusCode status = nfc->MIFARE_Read(page, &buffer[index], &dataSize);
  34. if (status == MFRC522::STATUS_OK)
  35. {
  36. #ifdef MIFARE_ULTRALIGHT_DEBUG
  37. Serial.print(F("Page "));Serial.print(page);Serial.print(" ");
  38. PrintHexChar(&buffer[index], ULTRALIGHT_PAGE_SIZE);
  39. PrintHexChar(&buffer[index+ULTRALIGHT_PAGE_SIZE], ULTRALIGHT_PAGE_SIZE);
  40. PrintHexChar(&buffer[index+2*ULTRALIGHT_PAGE_SIZE], ULTRALIGHT_PAGE_SIZE);
  41. PrintHexChar(&buffer[index+3*ULTRALIGHT_PAGE_SIZE], ULTRALIGHT_PAGE_SIZE);
  42. #endif
  43. }
  44. else
  45. {
  46. #ifdef NDEF_USE_SERIAL
  47. Serial.print(F("Read failed "));Serial.println(page);
  48. #endif
  49. return NfcTag(nfc->uid.uidByte, nfc->uid.size, NfcTag::TYPE_2);
  50. }
  51. if (index >= (messageLength + ndefStartIndex))
  52. {
  53. break;
  54. }
  55. index += ULTRALIGHT_READ_SIZE;
  56. }
  57. return NfcTag(nfc->uid.uidByte, nfc->uid.size, NfcTag::TYPE_2, &buffer[ndefStartIndex], messageLength);
  58. }
  59. boolean MifareUltralight::isUnformatted()
  60. {
  61. uint8_t page = 4;
  62. byte dataSize = ULTRALIGHT_READ_SIZE+2;
  63. byte data[dataSize];
  64. MFRC522::StatusCode status = nfc->MIFARE_Read(page, data, &dataSize);
  65. if (status == MFRC522::STATUS_OK && dataSize >= 4)
  66. {
  67. return (data[0] == 0xFF && data[1] == 0xFF && data[2] == 0xFF && data[3] == 0xFF);
  68. }
  69. else
  70. {
  71. #ifdef NDEF_USE_SERIAL
  72. Serial.print(F("Error. Failed read page "));Serial.println(page);
  73. #endif
  74. return false;
  75. }
  76. }
  77. // page 3 has tag capabilities
  78. uint16_t MifareUltralight::readTagSize()
  79. {
  80. uint16_t tagCapacity = 0;
  81. byte dataSize = ULTRALIGHT_READ_SIZE+2;
  82. byte data[dataSize];
  83. MFRC522::StatusCode status = nfc->MIFARE_Read(3, data, &dataSize);
  84. if (status == MFRC522::STATUS_OK && dataSize >= 2)
  85. {
  86. // See AN1303 - different rules for Mifare Family byte2 = (additional data + 48)/8
  87. tagCapacity = data[2] * 8;
  88. #ifdef MIFARE_ULTRALIGHT_DEBUG
  89. Serial.print(F("Tag capacity "));Serial.print(tagCapacity);Serial.println(F(" bytes"));
  90. #endif
  91. // TODO future versions should get lock information
  92. }
  93. return tagCapacity;
  94. }
  95. // read enough of the message to find the ndef message length
  96. void MifareUltralight::findNdefMessage(uint16_t *messageLength, uint16_t *ndefStartIndex)
  97. {
  98. byte dataSize = ULTRALIGHT_READ_SIZE + 2;
  99. byte data[dataSize]; // 3 pages, but 4 + CRC are returned
  100. if(nfc->MIFARE_Read(4, data, &dataSize) == MFRC522::STATUS_OK)
  101. {
  102. #ifdef MIFARE_ULTRALIGHT_DEBUG
  103. Serial.println(F("Pages 4-7"));
  104. PrintHexChar(data, 18);
  105. PrintHexChar(data+ULTRALIGHT_PAGE_SIZE, 18);
  106. PrintHexChar(data+2*ULTRALIGHT_PAGE_SIZE, 18);
  107. PrintHexChar(data+3*ULTRALIGHT_PAGE_SIZE, 18);
  108. #endif
  109. if (data[0] == 0x03)
  110. {
  111. *messageLength = data[1];
  112. *ndefStartIndex = 2;
  113. }
  114. else if (data[5] == 0x3) // page 5 byte 1
  115. {
  116. // TODO should really read the lock control TLV to ensure byte[5] is correct
  117. *messageLength = data[6];
  118. *ndefStartIndex = 7;
  119. }
  120. }
  121. #ifdef MIFARE_ULTRALIGHT_DEBUG
  122. Serial.print(F("messageLength "));Serial.println(*messageLength);
  123. Serial.print(F("ndefStartIndex "));Serial.println(*ndefStartIndex);
  124. #endif
  125. }
  126. // buffer is larger than the message, need to handle some data before and after
  127. // message and need to ensure we read full pages
  128. uint16_t MifareUltralight::calculateBufferSize(uint16_t messageLength, uint16_t ndefStartIndex)
  129. {
  130. // TLV terminator 0xFE is 1 byte
  131. uint16_t bufferSize = messageLength + ndefStartIndex + 1;
  132. if (bufferSize % ULTRALIGHT_READ_SIZE != 0)
  133. {
  134. // buffer must be an increment of page size
  135. bufferSize = ((bufferSize / ULTRALIGHT_READ_SIZE) + 1) * ULTRALIGHT_READ_SIZE;
  136. }
  137. //MFRC522 also return CRC
  138. bufferSize += 2;
  139. return bufferSize;
  140. }
  141. boolean MifareUltralight::write(NdefMessage& m)
  142. {
  143. if (isUnformatted())
  144. {
  145. #ifdef NDEF_USE_SERIAL
  146. Serial.println(F("WARNING: Tag is not formatted."));
  147. #endif
  148. return false;
  149. }
  150. uint16_t tagCapacity = readTagSize(); // meta info for tag
  151. uint16_t messageLength = m.getEncodedSize();
  152. uint16_t ndefStartIndex = messageLength < 0xFF ? 2 : 4;
  153. uint16_t bufferSize = calculateBufferSize(messageLength, ndefStartIndex);
  154. if(bufferSize>tagCapacity) {
  155. #ifdef MIFARE_ULTRALIGHT_DEBUG
  156. Serial.print(F("Encoded Message length exceeded tag Capacity "));Serial.println(tagCapacity);
  157. #endif
  158. return false;
  159. }
  160. uint8_t encoded[bufferSize];
  161. uint8_t * src = encoded;
  162. unsigned int position = 0;
  163. uint8_t page = ULTRALIGHT_DATA_START_PAGE;
  164. // Set message size. With ultralight should always be less than 0xFF but who knows?
  165. encoded[0] = 0x3;
  166. if (messageLength < 0xFF)
  167. {
  168. encoded[1] = messageLength;
  169. }
  170. else
  171. {
  172. encoded[1] = 0xFF;
  173. encoded[2] = ((messageLength >> 8) & 0xFF);
  174. encoded[3] = (messageLength & 0xFF);
  175. }
  176. m.encode(encoded+ndefStartIndex);
  177. // this is always at least 1 byte copy because of terminator.
  178. memset(encoded+ndefStartIndex+messageLength,0,bufferSize-ndefStartIndex-messageLength);
  179. encoded[ndefStartIndex+messageLength] = 0xFE; // terminator
  180. #ifdef MIFARE_ULTRALIGHT_DEBUG
  181. Serial.print(F("messageLength "));Serial.println(messageLength);
  182. Serial.print(F("Tag Capacity "));Serial.println(tagCapacity);
  183. PrintHex(encoded,bufferSize);
  184. #endif
  185. while (position < bufferSize){ //bufferSize is always times pagesize so no "last chunk" check
  186. // Although we have to provide 16 bytes to MIFARE_Write only 4 of them are written onto the tag
  187. byte writeBuffer[16] = {0};
  188. memcpy (writeBuffer, src, 4);
  189. // write page
  190. if (nfc->MIFARE_Write(page, writeBuffer, 16) != MFRC522::STATUS_OK)
  191. return false;
  192. #ifdef MIFARE_ULTRALIGHT_DEBUG
  193. Serial.print(F("Wrote page "));Serial.print(page);Serial.print(F(" - "));
  194. PrintHex(src,ULTRALIGHT_PAGE_SIZE);
  195. #endif
  196. page++;
  197. src+=ULTRALIGHT_PAGE_SIZE;
  198. position+=ULTRALIGHT_PAGE_SIZE;
  199. }
  200. return true;
  201. }
  202. // Mifare Ultralight can't be reset to factory state
  203. // zero out tag data like the NXP Tag Write Android application
  204. boolean MifareUltralight::clean()
  205. {
  206. uint16_t tagCapacity = readTagSize();
  207. uint8_t pages = (tagCapacity / ULTRALIGHT_PAGE_SIZE) + ULTRALIGHT_DATA_START_PAGE;
  208. // factory tags have 0xFF, but OTP-CC blocks have already been set so we use 0x00
  209. byte data[16] = { 0 };
  210. for (int i = ULTRALIGHT_DATA_START_PAGE; i < pages; i++)
  211. {
  212. #ifdef MIFARE_ULTRALIGHT_DEBUG
  213. Serial.print(F("Wrote page "));Serial.print(i);Serial.print(F(" - "));
  214. PrintHex(data, ULTRALIGHT_PAGE_SIZE);
  215. #endif
  216. if (nfc->MIFARE_Write(i, data, 16) != MFRC522::STATUS_OK)
  217. {
  218. return false;
  219. }
  220. }
  221. return true;
  222. }