PN532 NFC library for Seeed Studio's NFC Shield

Fork of PN532 by Yihui Xiong

Committer:
yihui
Date:
Thu Nov 21 04:30:49 2013 +0000
Revision:
3:4189a10038e6
Child:
7:26c1b3b6c192
sync with https://github.com/Seeed-Studio/PN532/releases/tag/v0.9.

Who changed what in which revision?

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