PN532 Driver library This library provides an abstract API to drive the pn532 nfc chip, with I2C/HSU/SPI interface. Its based on the Seeed Studio's Arduino version.

Dependents:   PN532_ReadUid Nfctest2

Committer:
dotnfc
Date:
Tue Sep 13 06:17:35 2016 +0000
Revision:
1:b5922b3b3257
Parent:
0:db8030e71f55
Remove ununsed files.

Who changed what in which revision?

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