to colorize a colorful pixel with a simple touch using nfc technology

Dependencies:   Chainable_RGB_LED mbed

use Arch, NFC Shield and Grove - Chainable RGB LED to DIY a touch pixel. Then use an Android with NFC support to colorize it.

The project is on https://github.com/Seeed-Studio/TouchPixel

Committer:
yihui
Date:
Fri Dec 27 01:46:32 2013 +0000
Revision:
0:88960f3eeb2c
initial

Who changed what in which revision?

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