PN532 NFC library for Seeed Studio's NFC Shield

Fork of PN532 by Yihui Xiong

Committer:
icefeet
Date:
Tue Oct 07 15:09:46 2014 +0000
Revision:
5:51f820fbd18a
Parent:
3:4189a10038e6
Added support for Ultralight Write

Who changed what in which revision?

UserRevisionLine numberNew contents of line
yihui 3:4189a10038e6 1 #include "MifareClassic.h"
yihui 3:4189a10038e6 2 #include "PN532_debug.h"
yihui 3:4189a10038e6 3
yihui 3:4189a10038e6 4 #define BLOCK_SIZE 16
yihui 3:4189a10038e6 5 #define LONG_TLV_SIZE 4
yihui 3:4189a10038e6 6 #define SHORT_TLV_SIZE 2
yihui 3:4189a10038e6 7
yihui 3:4189a10038e6 8 #define MIFARE_CLASSIC ("Mifare Classic")
yihui 3:4189a10038e6 9
yihui 3:4189a10038e6 10 MifareClassic::MifareClassic(PN532& nfcShield)
yihui 3:4189a10038e6 11 {
yihui 3:4189a10038e6 12 _nfcShield = &nfcShield;
yihui 3:4189a10038e6 13 }
yihui 3:4189a10038e6 14
yihui 3:4189a10038e6 15 MifareClassic::~MifareClassic()
yihui 3:4189a10038e6 16 {
yihui 3:4189a10038e6 17 }
yihui 3:4189a10038e6 18
yihui 3:4189a10038e6 19 NfcTag MifareClassic::read(uint8_t *uid, unsigned int uidLength)
yihui 3:4189a10038e6 20 {
yihui 3:4189a10038e6 21 uint8_t key[6] = { 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7 };
yihui 3:4189a10038e6 22 int currentBlock = 4;
yihui 3:4189a10038e6 23 int messageStartIndex = 0;
yihui 3:4189a10038e6 24 int messageLength = 0;
yihui 3:4189a10038e6 25 uint8_t data[BLOCK_SIZE];
yihui 3:4189a10038e6 26
yihui 3:4189a10038e6 27 // read first block to get message length
yihui 3:4189a10038e6 28 int success = _nfcShield->mifareclassic_AuthenticateBlock(uid, uidLength, currentBlock, 0, key);
yihui 3:4189a10038e6 29 if (success)
yihui 3:4189a10038e6 30 {
yihui 3:4189a10038e6 31 success = _nfcShield->mifareclassic_ReadDataBlock(currentBlock, data);
yihui 3:4189a10038e6 32 if (success)
yihui 3:4189a10038e6 33 {
yihui 3:4189a10038e6 34 if (!decodeTlv(data, messageLength, messageStartIndex)) {
yihui 3:4189a10038e6 35 return NfcTag(uid, uidLength, "ERROR"); // TODO should the error message go in NfcTag?
yihui 3:4189a10038e6 36 }
yihui 3:4189a10038e6 37 }
yihui 3:4189a10038e6 38 else
yihui 3:4189a10038e6 39 {
yihui 3:4189a10038e6 40 DMSG("Error. Failed read block ");
yihui 3:4189a10038e6 41 DMSG_INT(currentBlock);
yihui 3:4189a10038e6 42 return NfcTag(uid, uidLength, MIFARE_CLASSIC);
yihui 3:4189a10038e6 43 }
yihui 3:4189a10038e6 44 }
yihui 3:4189a10038e6 45 else
yihui 3:4189a10038e6 46 {
yihui 3:4189a10038e6 47 DMSG("Tag is not NDEF formatted.");
yihui 3:4189a10038e6 48 // TODO set tag.isFormatted = false
yihui 3:4189a10038e6 49 return NfcTag(uid, uidLength, MIFARE_CLASSIC);
yihui 3:4189a10038e6 50 }
yihui 3:4189a10038e6 51
yihui 3:4189a10038e6 52 // this should be nested in the message length loop
yihui 3:4189a10038e6 53 int index = 0;
yihui 3:4189a10038e6 54 int bufferSize = getBufferSize(messageLength);
yihui 3:4189a10038e6 55 uint8_t buffer[bufferSize];
yihui 3:4189a10038e6 56
yihui 3:4189a10038e6 57 #ifdef MIFARE_CLASSIC_DEBUG
yihui 3:4189a10038e6 58 DMSG("Message Length ");
yihui 3:4189a10038e6 59 DMSG_INT(messageLength);
yihui 3:4189a10038e6 60 DMSG("Buffer Size ");
yihui 3:4189a10038e6 61 DMSG_INT(bufferSize);
yihui 3:4189a10038e6 62 #endif
yihui 3:4189a10038e6 63
yihui 3:4189a10038e6 64 while (index < bufferSize)
yihui 3:4189a10038e6 65 {
yihui 3:4189a10038e6 66
yihui 3:4189a10038e6 67 // authenticate on every sector
yihui 3:4189a10038e6 68 if (_nfcShield->mifareclassic_IsFirstBlock(currentBlock))
yihui 3:4189a10038e6 69 {
yihui 3:4189a10038e6 70 success = _nfcShield->mifareclassic_AuthenticateBlock(uid, uidLength, currentBlock, 0, key);
yihui 3:4189a10038e6 71 if (!success)
yihui 3:4189a10038e6 72 {
yihui 3:4189a10038e6 73 DMSG("Error. Block Authentication failed for ");
yihui 3:4189a10038e6 74 DMSG_INT(currentBlock);
yihui 3:4189a10038e6 75 // TODO error handling
yihui 3:4189a10038e6 76 }
yihui 3:4189a10038e6 77 }
yihui 3:4189a10038e6 78
yihui 3:4189a10038e6 79 // read the data
yihui 3:4189a10038e6 80 success = _nfcShield->mifareclassic_ReadDataBlock(currentBlock, &buffer[index]);
yihui 3:4189a10038e6 81 if (success)
yihui 3:4189a10038e6 82 {
yihui 3:4189a10038e6 83 #ifdef MIFARE_CLASSIC_DEBUG
yihui 3:4189a10038e6 84 DMSG("Block ");
yihui 3:4189a10038e6 85 DMSG_INT(currentBlock);
yihui 3:4189a10038e6 86 _nfcShield->PrintHexChar(&buffer[index], BLOCK_SIZE);
yihui 3:4189a10038e6 87 #endif
yihui 3:4189a10038e6 88 }
yihui 3:4189a10038e6 89 else
yihui 3:4189a10038e6 90 {
yihui 3:4189a10038e6 91 DMSG("Read failed ");
yihui 3:4189a10038e6 92 DMSG_INT(currentBlock);
yihui 3:4189a10038e6 93 // TODO handle errors here
yihui 3:4189a10038e6 94 }
yihui 3:4189a10038e6 95
yihui 3:4189a10038e6 96 index += BLOCK_SIZE;
yihui 3:4189a10038e6 97 currentBlock++;
yihui 3:4189a10038e6 98
yihui 3:4189a10038e6 99 // skip the trailer block
yihui 3:4189a10038e6 100 if (_nfcShield->mifareclassic_IsTrailerBlock(currentBlock))
yihui 3:4189a10038e6 101 {
yihui 3:4189a10038e6 102 #ifdef MIFARE_CLASSIC_DEBUG
yihui 3:4189a10038e6 103 DMSG("Skipping block ");
yihui 3:4189a10038e6 104 DMSG_INT(currentBlock);
yihui 3:4189a10038e6 105 #endif
yihui 3:4189a10038e6 106 currentBlock++;
yihui 3:4189a10038e6 107 }
yihui 3:4189a10038e6 108 }
yihui 3:4189a10038e6 109
yihui 3:4189a10038e6 110 return NfcTag(uid, uidLength, MIFARE_CLASSIC, &buffer[messageStartIndex], messageLength);
yihui 3:4189a10038e6 111 }
yihui 3:4189a10038e6 112
yihui 3:4189a10038e6 113 int MifareClassic::getBufferSize(int messageLength)
yihui 3:4189a10038e6 114 {
yihui 3:4189a10038e6 115
yihui 3:4189a10038e6 116 int bufferSize = messageLength;
yihui 3:4189a10038e6 117
yihui 3:4189a10038e6 118 // TLV header is 2 or 4 uint8_ts, TLV terminator is 1 uint8_t.
yihui 3:4189a10038e6 119 if (messageLength < 0xFF)
yihui 3:4189a10038e6 120 {
yihui 3:4189a10038e6 121 bufferSize += SHORT_TLV_SIZE + 1;
yihui 3:4189a10038e6 122 }
yihui 3:4189a10038e6 123 else
yihui 3:4189a10038e6 124 {
yihui 3:4189a10038e6 125 bufferSize += LONG_TLV_SIZE + 1;
yihui 3:4189a10038e6 126 }
yihui 3:4189a10038e6 127
yihui 3:4189a10038e6 128 // bufferSize needs to be a multiple of BLOCK_SIZE
yihui 3:4189a10038e6 129 if (bufferSize % BLOCK_SIZE != 0)
yihui 3:4189a10038e6 130 {
yihui 3:4189a10038e6 131 bufferSize = ((bufferSize / BLOCK_SIZE) + 1) * BLOCK_SIZE;
yihui 3:4189a10038e6 132 }
yihui 3:4189a10038e6 133
yihui 3:4189a10038e6 134 return bufferSize;
yihui 3:4189a10038e6 135 }
yihui 3:4189a10038e6 136
yihui 3:4189a10038e6 137 // skip null tlvs (0x0) before the real message
yihui 3:4189a10038e6 138 // technically unlimited null tlvs, but we assume
yihui 3:4189a10038e6 139 // T & L of TLV in the first block we read
yihui 3:4189a10038e6 140 int MifareClassic::getNdefStartIndex(uint8_t *data)
yihui 3:4189a10038e6 141 {
yihui 3:4189a10038e6 142
yihui 3:4189a10038e6 143 for (int i = 0; i < BLOCK_SIZE; i++)
yihui 3:4189a10038e6 144 {
yihui 3:4189a10038e6 145 if (data[i] == 0x0)
yihui 3:4189a10038e6 146 {
yihui 3:4189a10038e6 147 // do nothing, skip
yihui 3:4189a10038e6 148 }
yihui 3:4189a10038e6 149 else if (data[i] == 0x3)
yihui 3:4189a10038e6 150 {
yihui 3:4189a10038e6 151 return i;
yihui 3:4189a10038e6 152 }
yihui 3:4189a10038e6 153 else
yihui 3:4189a10038e6 154 {
yihui 3:4189a10038e6 155 DMSG("Unknown TLV ");
yihui 3:4189a10038e6 156 DMSG_HEX(data[i]);
yihui 3:4189a10038e6 157 return -2;
yihui 3:4189a10038e6 158 }
yihui 3:4189a10038e6 159 }
yihui 3:4189a10038e6 160
yihui 3:4189a10038e6 161 return -1;
yihui 3:4189a10038e6 162 }
yihui 3:4189a10038e6 163
yihui 3:4189a10038e6 164 // Decode the NDEF data length from the Mifare TLV
yihui 3:4189a10038e6 165 // Leading null TLVs (0x0) are skipped
yihui 3:4189a10038e6 166 // Assuming T & L of TLV will be in the first block
yihui 3:4189a10038e6 167 // messageLength and messageStartIndex written to the parameters
yihui 3:4189a10038e6 168 // success or failure status is returned
yihui 3:4189a10038e6 169 //
yihui 3:4189a10038e6 170 // { 0x3, LENGTH }
yihui 3:4189a10038e6 171 // { 0x3, 0xFF, LENGTH, LENGTH }
yihui 3:4189a10038e6 172 bool MifareClassic::decodeTlv(uint8_t *data, int &messageLength, int &messageStartIndex)
yihui 3:4189a10038e6 173 {
yihui 3:4189a10038e6 174 int i = getNdefStartIndex(data);
yihui 3:4189a10038e6 175
yihui 3:4189a10038e6 176 if (i < 0 || data[i] != 0x3)
yihui 3:4189a10038e6 177 {
yihui 3:4189a10038e6 178 DMSG("Error. Can't decode message length.");
yihui 3:4189a10038e6 179 return false;
yihui 3:4189a10038e6 180 }
yihui 3:4189a10038e6 181 else
yihui 3:4189a10038e6 182 {
yihui 3:4189a10038e6 183 if (data[i+1] == 0xFF)
yihui 3:4189a10038e6 184 {
yihui 3:4189a10038e6 185 messageLength = ((0xFF & data[i+2]) << 8) | (0xFF & data[i+3]);
yihui 3:4189a10038e6 186 messageStartIndex = i + LONG_TLV_SIZE;
yihui 3:4189a10038e6 187 }
yihui 3:4189a10038e6 188 else
yihui 3:4189a10038e6 189 {
yihui 3:4189a10038e6 190 messageLength = data[i+1];
yihui 3:4189a10038e6 191 messageStartIndex = i + SHORT_TLV_SIZE;
yihui 3:4189a10038e6 192 }
yihui 3:4189a10038e6 193 }
yihui 3:4189a10038e6 194
yihui 3:4189a10038e6 195 return true;
yihui 3:4189a10038e6 196 }
yihui 3:4189a10038e6 197
yihui 3:4189a10038e6 198 bool MifareClassic::write(NdefMessage& m, uint8_t * uid, unsigned int uidLength)
yihui 3:4189a10038e6 199 {
yihui 3:4189a10038e6 200
yihui 3:4189a10038e6 201 uint8_t encoded[m.getEncodedSize()];
yihui 3:4189a10038e6 202 m.encode(encoded);
yihui 3:4189a10038e6 203
yihui 3:4189a10038e6 204 uint8_t buffer[getBufferSize(sizeof(encoded))];
yihui 3:4189a10038e6 205 memset(buffer, 0, sizeof(buffer));
yihui 3:4189a10038e6 206
yihui 3:4189a10038e6 207 #ifdef MIFARE_CLASSIC_DEBUG
yihui 3:4189a10038e6 208 DMSG("sizeof(encoded) "));DMSG(sizeof(encoded);
yihui 3:4189a10038e6 209 DMSG("sizeof(buffer) "));DMSG(sizeof(buffer);
yihui 3:4189a10038e6 210 #endif
yihui 3:4189a10038e6 211
yihui 3:4189a10038e6 212 if (sizeof(encoded) < 0xFF)
yihui 3:4189a10038e6 213 {
yihui 3:4189a10038e6 214 buffer[0] = 0x3;
yihui 3:4189a10038e6 215 buffer[1] = sizeof(encoded);
yihui 3:4189a10038e6 216 memcpy(&buffer[2], encoded, sizeof(encoded));
yihui 3:4189a10038e6 217 buffer[2+sizeof(encoded)] = 0xFE; // terminator
yihui 3:4189a10038e6 218 }
yihui 3:4189a10038e6 219 else
yihui 3:4189a10038e6 220 {
yihui 3:4189a10038e6 221 buffer[0] = 0x3;
yihui 3:4189a10038e6 222 buffer[1] = 0xFF;
yihui 3:4189a10038e6 223 buffer[2] = ((sizeof(encoded) >> 8) & 0xFF);
yihui 3:4189a10038e6 224 buffer[3] = (sizeof(encoded) & 0xFF);
yihui 3:4189a10038e6 225 memcpy(&buffer[4], encoded, sizeof(encoded));
yihui 3:4189a10038e6 226 buffer[4+sizeof(encoded)] = 0xFE; // terminator
yihui 3:4189a10038e6 227 }
yihui 3:4189a10038e6 228
yihui 3:4189a10038e6 229 // Write to tag
yihui 3:4189a10038e6 230 int index = 0;
yihui 3:4189a10038e6 231 int currentBlock = 4;
yihui 3:4189a10038e6 232 uint8_t key[6] = { 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7 }; // this is Sector 1 - 15 key
yihui 3:4189a10038e6 233
yihui 3:4189a10038e6 234 while (index < sizeof(buffer))
yihui 3:4189a10038e6 235 {
yihui 3:4189a10038e6 236
yihui 3:4189a10038e6 237 if (_nfcShield->mifareclassic_IsFirstBlock(currentBlock))
yihui 3:4189a10038e6 238 {
yihui 3:4189a10038e6 239 int success = _nfcShield->mifareclassic_AuthenticateBlock(uid, uidLength, currentBlock, 0, key);
yihui 3:4189a10038e6 240 if (!success)
yihui 3:4189a10038e6 241 {
yihui 3:4189a10038e6 242 DMSG("Error. Block Authentication failed for ");DMSG_INT(currentBlock);
yihui 3:4189a10038e6 243 return false;
yihui 3:4189a10038e6 244 }
yihui 3:4189a10038e6 245 }
yihui 3:4189a10038e6 246 int write_success = _nfcShield->mifareclassic_WriteDataBlock (currentBlock, &buffer[index]);
yihui 3:4189a10038e6 247 if (write_success)
yihui 3:4189a10038e6 248 {
yihui 3:4189a10038e6 249 #ifdef MIFARE_CLASSIC_DEBUG
yihui 3:4189a10038e6 250 DMSG("Wrote block ");Serial.print(currentBlock);DMSG(" - ");
yihui 3:4189a10038e6 251 _nfcShield->PrintHexChar(&buffer[index], BLOCK_SIZE);
yihui 3:4189a10038e6 252 #endif
yihui 3:4189a10038e6 253 }
yihui 3:4189a10038e6 254 else
yihui 3:4189a10038e6 255 {
yihui 3:4189a10038e6 256 DMSG("Write failed ");DMSG_INT(currentBlock);
yihui 3:4189a10038e6 257 return false;
yihui 3:4189a10038e6 258 }
yihui 3:4189a10038e6 259 index += BLOCK_SIZE;
yihui 3:4189a10038e6 260 currentBlock++;
yihui 3:4189a10038e6 261
yihui 3:4189a10038e6 262 if (_nfcShield->mifareclassic_IsTrailerBlock(currentBlock))
yihui 3:4189a10038e6 263 {
yihui 3:4189a10038e6 264 // can't write to trailer block
yihui 3:4189a10038e6 265 #ifdef MIFARE_CLASSIC_DEBUG
yihui 3:4189a10038e6 266 DMSG("Skipping block ");DMSG(currentBlock);
yihui 3:4189a10038e6 267 #endif
yihui 3:4189a10038e6 268 currentBlock++;
yihui 3:4189a10038e6 269 }
yihui 3:4189a10038e6 270
yihui 3:4189a10038e6 271 }
yihui 3:4189a10038e6 272
yihui 3:4189a10038e6 273 return true;
yihui 3:4189a10038e6 274 }