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 /**************************************************************************/
yihui 0:88960f3eeb2c 2 /*!
yihui 0:88960f3eeb2c 3 @file emulatetag.cpp
yihui 0:88960f3eeb2c 4 @author Armin Wieser
yihui 0:88960f3eeb2c 5 @license BSD
yihui 0:88960f3eeb2c 6 */
yihui 0:88960f3eeb2c 7 /**************************************************************************/
yihui 0:88960f3eeb2c 8
yihui 0:88960f3eeb2c 9 #include "emulatetag.h"
yihui 0:88960f3eeb2c 10 #include "PN532_debug.h"
yihui 0:88960f3eeb2c 11
yihui 0:88960f3eeb2c 12 #include <string.h>
yihui 0:88960f3eeb2c 13
yihui 0:88960f3eeb2c 14 #define MAX_TGREAD
yihui 0:88960f3eeb2c 15
yihui 0:88960f3eeb2c 16
yihui 0:88960f3eeb2c 17 // Command APDU
yihui 0:88960f3eeb2c 18 #define C_APDU_CLA 0
yihui 0:88960f3eeb2c 19 #define C_APDU_INS 1 // instruction
yihui 0:88960f3eeb2c 20 #define C_APDU_P1 2 // parameter 1
yihui 0:88960f3eeb2c 21 #define C_APDU_P2 3 // parameter 2
yihui 0:88960f3eeb2c 22 #define C_APDU_LC 4 // length command
yihui 0:88960f3eeb2c 23 #define C_APDU_DATA 5 // data
yihui 0:88960f3eeb2c 24
yihui 0:88960f3eeb2c 25 #define C_APDU_P1_SELECT_BY_ID 0x00
yihui 0:88960f3eeb2c 26 #define C_APDU_P1_SELECT_BY_NAME 0x04
yihui 0:88960f3eeb2c 27
yihui 0:88960f3eeb2c 28 // Response APDU
yihui 0:88960f3eeb2c 29 #define R_APDU_SW1_COMMAND_COMPLETE 0x90
yihui 0:88960f3eeb2c 30 #define R_APDU_SW2_COMMAND_COMPLETE 0x00
yihui 0:88960f3eeb2c 31
yihui 0:88960f3eeb2c 32 #define R_APDU_SW1_NDEF_TAG_NOT_FOUND 0x6a
yihui 0:88960f3eeb2c 33 #define R_APDU_SW2_NDEF_TAG_NOT_FOUND 0x82
yihui 0:88960f3eeb2c 34
yihui 0:88960f3eeb2c 35 #define R_APDU_SW1_FUNCTION_NOT_SUPPORTED 0x6A
yihui 0:88960f3eeb2c 36 #define R_APDU_SW2_FUNCTION_NOT_SUPPORTED 0x81
yihui 0:88960f3eeb2c 37
yihui 0:88960f3eeb2c 38 #define R_APDU_SW1_MEMORY_FAILURE 0x65
yihui 0:88960f3eeb2c 39 #define R_APDU_SW2_MEMORY_FAILURE 0x81
yihui 0:88960f3eeb2c 40
yihui 0:88960f3eeb2c 41 #define R_APDU_SW1_END_OF_FILE_BEFORE_REACHED_LE_BYTES 0x62
yihui 0:88960f3eeb2c 42 #define R_APDU_SW2_END_OF_FILE_BEFORE_REACHED_LE_BYTES 0x82
yihui 0:88960f3eeb2c 43
yihui 0:88960f3eeb2c 44 // ISO7816-4 commands
yihui 0:88960f3eeb2c 45 #define ISO7816_SELECT_FILE 0xA4
yihui 0:88960f3eeb2c 46 #define ISO7816_READ_BINARY 0xB0
yihui 0:88960f3eeb2c 47 #define ISO7816_UPDATE_BINARY 0xD6
yihui 0:88960f3eeb2c 48
yihui 0:88960f3eeb2c 49 typedef enum { NONE, CC, NDEF } tag_file; // CC ... Compatibility Container
yihui 0:88960f3eeb2c 50
yihui 0:88960f3eeb2c 51 bool EmulateTag::init(){
yihui 0:88960f3eeb2c 52 pn532.begin();
yihui 0:88960f3eeb2c 53 return pn532.SAMConfig();
yihui 0:88960f3eeb2c 54 }
yihui 0:88960f3eeb2c 55
yihui 0:88960f3eeb2c 56 void EmulateTag::setNdefFile(const uint8_t* ndef, const int16_t ndefLength){
yihui 0:88960f3eeb2c 57 if(ndefLength > (NDEF_MAX_LENGTH -2)){
yihui 0:88960f3eeb2c 58 DMSG("ndef file too large (> NDEF_MAX_LENGHT -2) - aborting");
yihui 0:88960f3eeb2c 59 return;
yihui 0:88960f3eeb2c 60 }
yihui 0:88960f3eeb2c 61
yihui 0:88960f3eeb2c 62 ndef_file[0] = ndefLength >> 8;
yihui 0:88960f3eeb2c 63 ndef_file[1] = ndefLength & 0xFF;
yihui 0:88960f3eeb2c 64 memcpy(ndef_file+2, ndef, ndefLength);
yihui 0:88960f3eeb2c 65 }
yihui 0:88960f3eeb2c 66
yihui 0:88960f3eeb2c 67 void EmulateTag::setUid(uint8_t* uid){
yihui 0:88960f3eeb2c 68 uidPtr = uid;
yihui 0:88960f3eeb2c 69 }
yihui 0:88960f3eeb2c 70
yihui 0:88960f3eeb2c 71 bool EmulateTag::emulate(const uint16_t tgInitAsTargetTimeout){
yihui 0:88960f3eeb2c 72
yihui 0:88960f3eeb2c 73 uint8_t command[] = {
yihui 0:88960f3eeb2c 74 PN532_COMMAND_TGINITASTARGET,
yihui 0:88960f3eeb2c 75 5, // MODE: PICC only, Passive only
yihui 0:88960f3eeb2c 76
yihui 0:88960f3eeb2c 77 0x04, 0x00, // SENS_RES
yihui 0:88960f3eeb2c 78 0x00, 0x00, 0x00, // NFCID1
yihui 0:88960f3eeb2c 79 0x20, // SEL_RES
yihui 0:88960f3eeb2c 80
yihui 0:88960f3eeb2c 81 0,0,0,0,0,0,0,0,
yihui 0:88960f3eeb2c 82 0,0,0,0,0,0,0,0, // FeliCaParams
yihui 0:88960f3eeb2c 83 0,0,
yihui 0:88960f3eeb2c 84
yihui 0:88960f3eeb2c 85 0,0,0,0,0,0,0,0,0,0, // NFCID3t
yihui 0:88960f3eeb2c 86
yihui 0:88960f3eeb2c 87 0, // length of general bytes
yihui 0:88960f3eeb2c 88 0 // length of historical bytes
yihui 0:88960f3eeb2c 89 };
yihui 0:88960f3eeb2c 90
yihui 0:88960f3eeb2c 91 if(uidPtr != 0){ // if uid is set copy 3 bytes to nfcid1
yihui 0:88960f3eeb2c 92 memcpy(command + 4, uidPtr, 3);
yihui 0:88960f3eeb2c 93 }
yihui 0:88960f3eeb2c 94
yihui 0:88960f3eeb2c 95 if(1 != pn532.tgInitAsTarget(command,sizeof(command), tgInitAsTargetTimeout)){
yihui 0:88960f3eeb2c 96 DMSG("tgInitAsTarget failed or timed out!");
yihui 0:88960f3eeb2c 97 return false;
yihui 0:88960f3eeb2c 98 }
yihui 0:88960f3eeb2c 99
yihui 0:88960f3eeb2c 100 uint8_t compatibility_container[] = {
yihui 0:88960f3eeb2c 101 0, 0x0F,
yihui 0:88960f3eeb2c 102 0x20,
yihui 0:88960f3eeb2c 103 0, 0x54,
yihui 0:88960f3eeb2c 104 0, 0xFF,
yihui 0:88960f3eeb2c 105 0x04, // T
yihui 0:88960f3eeb2c 106 0x06, // L
yihui 0:88960f3eeb2c 107 0xE1, 0x04, // File identifier
yihui 0:88960f3eeb2c 108 ((NDEF_MAX_LENGTH & 0xFF00) >> 8), (NDEF_MAX_LENGTH & 0xFF), // maximum NDEF file size
yihui 0:88960f3eeb2c 109 0x00, // read access 0x0 = granted
yihui 0:88960f3eeb2c 110 0x00 // write access 0x0 = granted | 0xFF = deny
yihui 0:88960f3eeb2c 111 };
yihui 0:88960f3eeb2c 112
yihui 0:88960f3eeb2c 113 if(tagWriteable == false){
yihui 0:88960f3eeb2c 114 compatibility_container[14] = 0xFF;
yihui 0:88960f3eeb2c 115 }
yihui 0:88960f3eeb2c 116
yihui 0:88960f3eeb2c 117 tagWrittenByInitiator = false;
yihui 0:88960f3eeb2c 118
yihui 0:88960f3eeb2c 119 uint8_t rwbuf[128];
yihui 0:88960f3eeb2c 120 uint8_t sendlen;
yihui 0:88960f3eeb2c 121 int16_t status;
yihui 0:88960f3eeb2c 122 tag_file currentFile = NONE;
yihui 0:88960f3eeb2c 123 uint16_t cc_size = sizeof(compatibility_container);
yihui 0:88960f3eeb2c 124 bool runLoop = true;
yihui 0:88960f3eeb2c 125
yihui 0:88960f3eeb2c 126 while(runLoop){
yihui 0:88960f3eeb2c 127 status = pn532.tgGetData(rwbuf, sizeof(rwbuf));
yihui 0:88960f3eeb2c 128 if(status < 0){
yihui 0:88960f3eeb2c 129 DMSG("tgGetData failed!\n");
yihui 0:88960f3eeb2c 130 pn532.inRelease();
yihui 0:88960f3eeb2c 131 return true;
yihui 0:88960f3eeb2c 132 }
yihui 0:88960f3eeb2c 133
yihui 0:88960f3eeb2c 134 uint8_t p1 = rwbuf[C_APDU_P1];
yihui 0:88960f3eeb2c 135 uint8_t p2 = rwbuf[C_APDU_P2];
yihui 0:88960f3eeb2c 136 uint8_t lc = rwbuf[C_APDU_LC];
yihui 0:88960f3eeb2c 137 uint16_t p1p2_length = ((int16_t) p1 << 8) + p2;
yihui 0:88960f3eeb2c 138
yihui 0:88960f3eeb2c 139 switch(rwbuf[C_APDU_INS]){
yihui 0:88960f3eeb2c 140 case ISO7816_SELECT_FILE:
yihui 0:88960f3eeb2c 141 switch(p1){
yihui 0:88960f3eeb2c 142 case C_APDU_P1_SELECT_BY_ID:
yihui 0:88960f3eeb2c 143 if(p2 != 0x0c){
yihui 0:88960f3eeb2c 144 DMSG("C_APDU_P2 != 0x0c\n");
yihui 0:88960f3eeb2c 145 setResponse(COMMAND_COMPLETE, rwbuf, &sendlen);
yihui 0:88960f3eeb2c 146 } else if(lc == 2 && rwbuf[C_APDU_DATA] == 0xE1 && (rwbuf[C_APDU_DATA+1] == 0x03 || rwbuf[C_APDU_DATA+1] == 0x04)){
yihui 0:88960f3eeb2c 147 setResponse(COMMAND_COMPLETE, rwbuf, &sendlen);
yihui 0:88960f3eeb2c 148 if(rwbuf[C_APDU_DATA+1] == 0x03){
yihui 0:88960f3eeb2c 149 currentFile = CC;
yihui 0:88960f3eeb2c 150 } else if(rwbuf[C_APDU_DATA+1] == 0x04){
yihui 0:88960f3eeb2c 151 currentFile = NDEF;
yihui 0:88960f3eeb2c 152 }
yihui 0:88960f3eeb2c 153 } else {
yihui 0:88960f3eeb2c 154 setResponse(TAG_NOT_FOUND, rwbuf, &sendlen);
yihui 0:88960f3eeb2c 155 }
yihui 0:88960f3eeb2c 156 break;
yihui 0:88960f3eeb2c 157 case C_APDU_P1_SELECT_BY_NAME:
yihui 0:88960f3eeb2c 158 const uint8_t ndef_tag_application_name_v2[] = {0, 0x7, 0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x01 };
yihui 0:88960f3eeb2c 159 if(0 == memcmp(ndef_tag_application_name_v2, rwbuf + C_APDU_P2, sizeof(ndef_tag_application_name_v2))){
yihui 0:88960f3eeb2c 160 setResponse(COMMAND_COMPLETE, rwbuf, &sendlen);
yihui 0:88960f3eeb2c 161 } else{
yihui 0:88960f3eeb2c 162 DMSG("function not supported\n");
yihui 0:88960f3eeb2c 163 setResponse(FUNCTION_NOT_SUPPORTED, rwbuf, &sendlen);
yihui 0:88960f3eeb2c 164 }
yihui 0:88960f3eeb2c 165 break;
yihui 0:88960f3eeb2c 166 }
yihui 0:88960f3eeb2c 167 break;
yihui 0:88960f3eeb2c 168 case ISO7816_READ_BINARY:
yihui 0:88960f3eeb2c 169 switch(currentFile){
yihui 0:88960f3eeb2c 170 case NONE:
yihui 0:88960f3eeb2c 171 setResponse(TAG_NOT_FOUND, rwbuf, &sendlen);
yihui 0:88960f3eeb2c 172 break;
yihui 0:88960f3eeb2c 173 case CC:
yihui 0:88960f3eeb2c 174 if( p1p2_length > NDEF_MAX_LENGTH){
yihui 0:88960f3eeb2c 175 setResponse(END_OF_FILE_BEFORE_REACHED_LE_BYTES, rwbuf, &sendlen);
yihui 0:88960f3eeb2c 176 }else {
yihui 0:88960f3eeb2c 177 memcpy(rwbuf,compatibility_container + p1p2_length, lc);
yihui 0:88960f3eeb2c 178 setResponse(COMMAND_COMPLETE, rwbuf + lc, &sendlen, lc);
yihui 0:88960f3eeb2c 179 }
yihui 0:88960f3eeb2c 180 break;
yihui 0:88960f3eeb2c 181 case NDEF:
yihui 0:88960f3eeb2c 182 if( p1p2_length > NDEF_MAX_LENGTH){
yihui 0:88960f3eeb2c 183 setResponse(END_OF_FILE_BEFORE_REACHED_LE_BYTES, rwbuf, &sendlen);
yihui 0:88960f3eeb2c 184 }else {
yihui 0:88960f3eeb2c 185 memcpy(rwbuf, ndef_file + p1p2_length, lc);
yihui 0:88960f3eeb2c 186 setResponse(COMMAND_COMPLETE, rwbuf + lc, &sendlen, lc);
yihui 0:88960f3eeb2c 187 }
yihui 0:88960f3eeb2c 188 break;
yihui 0:88960f3eeb2c 189 }
yihui 0:88960f3eeb2c 190 break;
yihui 0:88960f3eeb2c 191 case ISO7816_UPDATE_BINARY:
yihui 0:88960f3eeb2c 192 if(!tagWriteable){
yihui 0:88960f3eeb2c 193 setResponse(FUNCTION_NOT_SUPPORTED, rwbuf, &sendlen);
yihui 0:88960f3eeb2c 194 } else{
yihui 0:88960f3eeb2c 195 if( p1p2_length > NDEF_MAX_LENGTH){
yihui 0:88960f3eeb2c 196 setResponse(MEMORY_FAILURE, rwbuf, &sendlen);
yihui 0:88960f3eeb2c 197 }
yihui 0:88960f3eeb2c 198 else{
yihui 0:88960f3eeb2c 199 memcpy(ndef_file + p1p2_length, rwbuf + C_APDU_DATA, lc);
yihui 0:88960f3eeb2c 200 setResponse(COMMAND_COMPLETE, rwbuf, &sendlen);
yihui 0:88960f3eeb2c 201 tagWrittenByInitiator = true;
yihui 0:88960f3eeb2c 202
yihui 0:88960f3eeb2c 203 uint16_t ndef_length = (ndef_file[0] << 8) + ndef_file[1];
yihui 0:88960f3eeb2c 204 if ((ndef_length > 0) && (updateNdefCallback != 0)) {
yihui 0:88960f3eeb2c 205 updateNdefCallback(ndef_file + 2, ndef_length);
yihui 0:88960f3eeb2c 206 }
yihui 0:88960f3eeb2c 207 }
yihui 0:88960f3eeb2c 208 }
yihui 0:88960f3eeb2c 209 break;
yihui 0:88960f3eeb2c 210 default:
yihui 0:88960f3eeb2c 211 DMSG("Command not supported!");
yihui 0:88960f3eeb2c 212 DMSG_HEX(rwbuf[C_APDU_INS]);
yihui 0:88960f3eeb2c 213 DMSG("\n");
yihui 0:88960f3eeb2c 214 setResponse(FUNCTION_NOT_SUPPORTED, rwbuf, &sendlen);
yihui 0:88960f3eeb2c 215 }
yihui 0:88960f3eeb2c 216 status = pn532.tgSetData(rwbuf, sendlen);
yihui 0:88960f3eeb2c 217 if(status < 0){
yihui 0:88960f3eeb2c 218 DMSG("tgSetData failed\n!");
yihui 0:88960f3eeb2c 219 pn532.inRelease();
yihui 0:88960f3eeb2c 220 return true;
yihui 0:88960f3eeb2c 221 }
yihui 0:88960f3eeb2c 222 }
yihui 0:88960f3eeb2c 223 pn532.inRelease();
yihui 0:88960f3eeb2c 224 return true;
yihui 0:88960f3eeb2c 225 }
yihui 0:88960f3eeb2c 226
yihui 0:88960f3eeb2c 227 void EmulateTag::setResponse(responseCommand cmd, uint8_t* buf, uint8_t* sendlen, uint8_t sendlenOffset){
yihui 0:88960f3eeb2c 228 switch(cmd){
yihui 0:88960f3eeb2c 229 case COMMAND_COMPLETE:
yihui 0:88960f3eeb2c 230 buf[0] = R_APDU_SW1_COMMAND_COMPLETE;
yihui 0:88960f3eeb2c 231 buf[1] = R_APDU_SW2_COMMAND_COMPLETE;
yihui 0:88960f3eeb2c 232 *sendlen = 2 + sendlenOffset;
yihui 0:88960f3eeb2c 233 break;
yihui 0:88960f3eeb2c 234 case TAG_NOT_FOUND:
yihui 0:88960f3eeb2c 235 buf[0] = R_APDU_SW1_NDEF_TAG_NOT_FOUND;
yihui 0:88960f3eeb2c 236 buf[1] = R_APDU_SW2_NDEF_TAG_NOT_FOUND;
yihui 0:88960f3eeb2c 237 *sendlen = 2;
yihui 0:88960f3eeb2c 238 break;
yihui 0:88960f3eeb2c 239 case FUNCTION_NOT_SUPPORTED:
yihui 0:88960f3eeb2c 240 buf[0] = R_APDU_SW1_FUNCTION_NOT_SUPPORTED;
yihui 0:88960f3eeb2c 241 buf[1] = R_APDU_SW2_FUNCTION_NOT_SUPPORTED;
yihui 0:88960f3eeb2c 242 *sendlen = 2;
yihui 0:88960f3eeb2c 243 break;
yihui 0:88960f3eeb2c 244 case MEMORY_FAILURE:
yihui 0:88960f3eeb2c 245 buf[0] = R_APDU_SW1_MEMORY_FAILURE;
yihui 0:88960f3eeb2c 246 buf[1] = R_APDU_SW2_MEMORY_FAILURE;
yihui 0:88960f3eeb2c 247 *sendlen = 2;
yihui 0:88960f3eeb2c 248 break;
yihui 0:88960f3eeb2c 249 case END_OF_FILE_BEFORE_REACHED_LE_BYTES:
yihui 0:88960f3eeb2c 250 buf[0] = R_APDU_SW1_END_OF_FILE_BEFORE_REACHED_LE_BYTES;
yihui 0:88960f3eeb2c 251 buf[1] = R_APDU_SW2_END_OF_FILE_BEFORE_REACHED_LE_BYTES;
yihui 0:88960f3eeb2c 252 *sendlen= 2;
yihui 0:88960f3eeb2c 253 break;
yihui 0:88960f3eeb2c 254 }
yihui 0:88960f3eeb2c 255 }