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

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers emulatetag.cpp Source File

emulatetag.cpp

Go to the documentation of this file.
00001 /**************************************************************************/
00002 /*!
00003     @file     emulatetag.cpp
00004     @author   Armin Wieser
00005     @license  BSD
00006 */
00007 /**************************************************************************/
00008 
00009 #include "emulatetag.h "
00010 #include "PN532_debug.h"
00011 
00012 #include <string.h>
00013 
00014 #define MAX_TGREAD
00015 
00016 
00017 // Command APDU
00018 #define C_APDU_CLA   0
00019 #define C_APDU_INS   1 // instruction
00020 #define C_APDU_P1    2 // parameter 1
00021 #define C_APDU_P2    3 // parameter 2
00022 #define C_APDU_LC    4 // length command
00023 #define C_APDU_DATA  5 // data
00024 
00025 #define C_APDU_P1_SELECT_BY_ID   0x00
00026 #define C_APDU_P1_SELECT_BY_NAME 0x04
00027 
00028 // Response APDU
00029 #define R_APDU_SW1_COMMAND_COMPLETE 0x90 
00030 #define R_APDU_SW2_COMMAND_COMPLETE 0x00 
00031 
00032 #define R_APDU_SW1_NDEF_TAG_NOT_FOUND 0x6a
00033 #define R_APDU_SW2_NDEF_TAG_NOT_FOUND 0x82
00034 
00035 #define R_APDU_SW1_FUNCTION_NOT_SUPPORTED 0x6A
00036 #define R_APDU_SW2_FUNCTION_NOT_SUPPORTED 0x81
00037 
00038 #define R_APDU_SW1_MEMORY_FAILURE 0x65
00039 #define R_APDU_SW2_MEMORY_FAILURE 0x81
00040 
00041 #define R_APDU_SW1_END_OF_FILE_BEFORE_REACHED_LE_BYTES 0x62
00042 #define R_APDU_SW2_END_OF_FILE_BEFORE_REACHED_LE_BYTES 0x82
00043 
00044 // ISO7816-4 commands
00045 #define ISO7816_SELECT_FILE 0xA4
00046 #define ISO7816_READ_BINARY 0xB0
00047 #define ISO7816_UPDATE_BINARY 0xD6
00048 
00049 typedef enum { NONE, CC, NDEF } tag_file;   // CC ... Compatibility Container
00050 
00051 bool EmulateTag::init(){
00052   pn532.begin();
00053   return pn532.SAMConfig();
00054 }
00055 
00056 void EmulateTag::setNdefFile(const uint8_t* ndef, const int16_t ndefLength){
00057   if(ndefLength >  (NDEF_MAX_LENGTH -2)){
00058     DMSG("ndef file too large (> NDEF_MAX_LENGHT -2) - aborting");
00059     return;
00060   }
00061 
00062   ndef_file[0] = ndefLength >> 8;
00063   ndef_file[1] = ndefLength & 0xFF;
00064   memcpy(ndef_file+2, ndef, ndefLength);
00065 }
00066 
00067 void EmulateTag::setUid(uint8_t* uid){
00068   uidPtr = uid;
00069 }
00070 
00071 bool EmulateTag::emulate(const uint16_t tgInitAsTargetTimeout){
00072 
00073   // http://www.nxp.com/documents/application_note/AN133910.pdf
00074   uint8_t command[] = {
00075       PN532_COMMAND_TGINITASTARGET,
00076       0x05,                  // MODE: PICC only, Passive only
00077 
00078       0x04, 0x00,         // SENS_RES
00079       0x00, 0x00, 0x00,   // NFCID1
00080       0x20,               // SEL_RES
00081 
00082       0x01, 0xFE,         // Parameters to build POL_RES
00083       0xA2, 0xA3, 0xA4,
00084       0xA5, 0xA6, 0xA7,
00085       0xC0, 0xC1, 0xC2,
00086       0xC3, 0xC4, 0xC5,
00087       0xC6, 0xC7, 0xFF,
00088       0xFF,
00089       0xAA, 0x99, 0x88, //NFCID3t (10 bytes)
00090       0x77, 0x66, 0x55, 0x44,
00091       0x33, 0x22, 0x11,
00092 
00093       0, // length of general bytes
00094       0  // length of historical bytes
00095   };
00096 
00097   if(uidPtr != 0){  // if uid is set copy 3 bytes to nfcid1
00098     memcpy(command + 4, uidPtr, 3);
00099   }
00100 
00101   if(1 != pn532.tgInitAsTarget(command,sizeof(command), tgInitAsTargetTimeout)){
00102     DMSG("tgInitAsTarget failed or timed out!");
00103     return false;
00104   }
00105 
00106   uint8_t compatibility_container[] = {
00107     0, 0x0F,
00108     0x20,
00109     0, 0x54,
00110     0, 0xFF,
00111     0x04,       // T
00112     0x06,       // L
00113     0xE1, 0x04, // File identifier
00114     ((NDEF_MAX_LENGTH & 0xFF00) >> 8), (NDEF_MAX_LENGTH & 0xFF), // maximum NDEF file size
00115     0x00,       // read access 0x0 = granted
00116     0x00        // write access 0x0 = granted | 0xFF = deny
00117   };
00118 
00119   if(tagWriteable == false){
00120     compatibility_container[14] = 0xFF;
00121   }
00122 
00123   tagWrittenByInitiator = false;
00124 
00125   uint8_t rwbuf[128];
00126   uint8_t sendlen;
00127   int16_t status;
00128   tag_file currentFile = NONE;
00129   uint16_t cc_size = sizeof(compatibility_container);
00130   bool runLoop = true;
00131 
00132   while(runLoop){
00133     status = pn532.tgGetData(rwbuf, sizeof(rwbuf));
00134     if(status < 0){
00135       DMSG("tgGetData failed!\n");
00136       pn532.inRelease();
00137       return true;
00138     }
00139 
00140     uint8_t p1 = rwbuf[C_APDU_P1];
00141     uint8_t p2 = rwbuf[C_APDU_P2];
00142     uint8_t lc = rwbuf[C_APDU_LC];
00143     uint16_t p1p2_length = ((int16_t) p1 << 8) + p2;
00144 
00145     switch(rwbuf[C_APDU_INS]){
00146     case ISO7816_SELECT_FILE:
00147       switch(p1){
00148       case C_APDU_P1_SELECT_BY_ID:
00149     if(p2 != 0x0c){
00150       DMSG("C_APDU_P2 != 0x0c\n");
00151       setResponse(COMMAND_COMPLETE, rwbuf, &sendlen);
00152     } else if(lc == 2 && rwbuf[C_APDU_DATA] == 0xE1 && (rwbuf[C_APDU_DATA+1] == 0x03 || rwbuf[C_APDU_DATA+1] == 0x04)){
00153       setResponse(COMMAND_COMPLETE, rwbuf, &sendlen);
00154       if(rwbuf[C_APDU_DATA+1] == 0x03){
00155         currentFile = CC;
00156       } else if(rwbuf[C_APDU_DATA+1] == 0x04){
00157         currentFile = NDEF;
00158       }
00159     } else {
00160       setResponse(TAG_NOT_FOUND, rwbuf, &sendlen);
00161     }
00162     break;
00163       case C_APDU_P1_SELECT_BY_NAME: 
00164         const uint8_t ndef_tag_application_name_v2[] = {0, 0x7, 0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x01 };
00165     if(0 == memcmp(ndef_tag_application_name_v2, rwbuf + C_APDU_P2, sizeof(ndef_tag_application_name_v2))){
00166       setResponse(COMMAND_COMPLETE, rwbuf, &sendlen);
00167     } else{
00168       DMSG("function not supported\n");
00169       setResponse(FUNCTION_NOT_SUPPORTED, rwbuf, &sendlen);
00170     } 
00171     break;
00172       }
00173       break;
00174     case ISO7816_READ_BINARY:
00175       switch(currentFile){
00176       case NONE:
00177     setResponse(TAG_NOT_FOUND, rwbuf, &sendlen);
00178     break;
00179       case CC:
00180     if( p1p2_length > NDEF_MAX_LENGTH){
00181       setResponse(END_OF_FILE_BEFORE_REACHED_LE_BYTES, rwbuf, &sendlen);
00182     }else {
00183       memcpy(rwbuf,compatibility_container + p1p2_length, lc);
00184       setResponse(COMMAND_COMPLETE, rwbuf + lc, &sendlen, lc);
00185     }
00186     break;
00187       case NDEF:
00188     if( p1p2_length > NDEF_MAX_LENGTH){
00189       setResponse(END_OF_FILE_BEFORE_REACHED_LE_BYTES, rwbuf, &sendlen);
00190     }else {
00191       memcpy(rwbuf, ndef_file + p1p2_length, lc);
00192       setResponse(COMMAND_COMPLETE, rwbuf + lc, &sendlen, lc);
00193     }
00194     break;
00195       }
00196       break;    
00197     case ISO7816_UPDATE_BINARY:
00198       if(!tagWriteable){
00199       setResponse(FUNCTION_NOT_SUPPORTED, rwbuf, &sendlen);
00200       } else{      
00201     if( p1p2_length > NDEF_MAX_LENGTH){
00202       setResponse(MEMORY_FAILURE, rwbuf, &sendlen);
00203     }
00204     else{
00205       memcpy(ndef_file + p1p2_length, rwbuf + C_APDU_DATA, lc);
00206       setResponse(COMMAND_COMPLETE, rwbuf, &sendlen);
00207       tagWrittenByInitiator = true;
00208       
00209       uint16_t ndef_length = (ndef_file[0] << 8) + ndef_file[1];
00210       if ((ndef_length > 0) && (updateNdefCallback != 0)) {
00211         updateNdefCallback(ndef_file + 2, ndef_length);
00212       }
00213     }
00214       }
00215       break;
00216     default:
00217       DMSG("Command not supported!");
00218       DMSG_HEX(rwbuf[C_APDU_INS]);
00219       DMSG("\n");
00220       setResponse(FUNCTION_NOT_SUPPORTED, rwbuf, &sendlen);
00221     }
00222     status = pn532.tgSetData(rwbuf, sendlen);
00223     if(status < 0){
00224       DMSG("tgSetData failed\n!");
00225       pn532.inRelease();
00226       return true;
00227     }
00228   }
00229   pn532.inRelease();
00230   return true;
00231 }
00232 
00233 void EmulateTag::setResponse(responseCommand cmd, uint8_t* buf, uint8_t* sendlen, uint8_t sendlenOffset){
00234   switch(cmd){
00235   case COMMAND_COMPLETE:
00236     buf[0] = R_APDU_SW1_COMMAND_COMPLETE;
00237     buf[1] = R_APDU_SW2_COMMAND_COMPLETE;
00238     *sendlen = 2 + sendlenOffset;
00239     break;
00240   case TAG_NOT_FOUND:
00241     buf[0] = R_APDU_SW1_NDEF_TAG_NOT_FOUND;
00242     buf[1] = R_APDU_SW2_NDEF_TAG_NOT_FOUND;
00243     *sendlen = 2;    
00244     break;
00245   case FUNCTION_NOT_SUPPORTED:
00246     buf[0] = R_APDU_SW1_FUNCTION_NOT_SUPPORTED;
00247     buf[1] = R_APDU_SW2_FUNCTION_NOT_SUPPORTED;
00248     *sendlen = 2; 
00249     break;
00250   case MEMORY_FAILURE:
00251     buf[0] = R_APDU_SW1_MEMORY_FAILURE;
00252     buf[1] = R_APDU_SW2_MEMORY_FAILURE;
00253     *sendlen = 2;
00254     break;
00255   case END_OF_FILE_BEFORE_REACHED_LE_BYTES:
00256     buf[0] = R_APDU_SW1_END_OF_FILE_BEFORE_REACHED_LE_BYTES;
00257     buf[1] = R_APDU_SW2_END_OF_FILE_BEFORE_REACHED_LE_BYTES;
00258     *sendlen= 2;
00259     break;
00260   }
00261 }