PN532 emulated card not read by an Android phone

青春壹個敷衍的年華 提交于 2021-01-29 11:42:20

问题


I am using Arduino UNO with elechouse's library and a PN532 module connected through SPI.

I am trying to emulate a card using the emulate_tag_ndef example in that library, but when I try to read the emulated card with the NFC Tools app on my Samsung Galaxy S7, I get an empty serial number and I don't get the Ndef message similarly to this.

When I try to change the command array in the library according to the post lower on the linked issue on Github, then the emulated card cannot be detected by my phone at all.

The PN532 works in all other NFC modes (read/write, peer-to-peer) all right for me.


回答1:


Give a look to this issue on Seeeds studio:

https://github.com/Seeed-Studio/PN532/issues/88

Android phones will only accept Felica Cards. If you put some random IDs, it will not be detected as NDEF card.

To emulate it right, you have to set the card ID in this way:

uint8_t command[] = {
  PN532_COMMAND_TGINITASTARGET,
  0x05,                  // MODE: 0x04 = PICC only, 0x01 = Passive only (0x02 = DEP only)

  // MIFARE PARAMS
  0x04, 0x00,         // SENS_RES (seeeds studio set it to 0x04, nxp to 0x08)
  0x00, 0x00, 0x00,   // NFCID1t    (is set over sketch with setUID())
  0x20,               // SEL_RES    (0x20=Mifare DelFire, 0x60=custom)

  // FELICA PARAMS
  0x01, 0xFE,         // NFCID2t (8 bytes) https://github.com/adafruit/Adafruit-PN532/blob/master/Adafruit_PN532.cpp FeliCa NEEDS TO BEGIN WITH 0x01 0xFE!
  0x05, 0x01, 0x86,
  0x04, 0x02, 0x02,
  0x03, 0x00,         // PAD (8 bytes)
  0x4B, 0x02, 0x4F, 
  0x49, 0x8A, 0x00,   
  0xFF, 0xFF,         // System code (2 bytes)

  0x01, 0x01, 0x66,   // NFCID3t (10 bytes)
  0x6D, 0x01, 0x01, 0x10,
  0x02, 0x00, 0x00,

  0x00, // length of general bytes
  0x00  // length of historical bytes
};

NFCID1t is the card UID, you can set something on your sketch.
NFCID2t has to be exactly how I wrote in the code above => Felica card
NFCID3t can be some random numbers.

You will see that there will be other issues with your sketch and sometimes it is impossible to debug or see why it does not work (for example if you have multiple NDEF Tags). So, the most important tool to test your PN532 is this one from NXP:
https://play.google.com/store/apps/details?id=com.nxp.taginfolite

This will give you a lot of info. This app can also read your card, even if it is not formatted in the right way.

Edit: This is how I updated the emulatetag.cpp from PN532 library:

bool EmulateTag::emulate(const uint16_t tgInitAsTargetTimeout){

  // https://www.nxp.com/docs/en/nxp/application-notes/AN133910.pdf
    // Doc: 
    //     Mode: 0x00 any command is accepted. 0x02 only ATR_REQ. 0x04 only RATS (ISO1443-4)
    //     Mifare: SENS_RES => bit 6 and 7 must be 0!
    //             NFCID1t  => first byte must be 0x08 according to the ISO
    //             SEL_RES  => bit 6 must be 1, to enable NFC protocol (example 0x40)
    //     FeliCa: NFCID2t => first 2 bytes must be 0x01 and 0xFE
    //      
  uint8_t command[] = {
      PN532_COMMAND_TGINITASTARGET,
      0x05,                  // MODE: 0x04 = PICC only, 0x01 = Passive only (0x02 = DEP only)

      // MIFARE PARAMS
      0x04, 0x00,         // SENS_RES (seeeds studio set it to 0x04, nxp to 0x08)
      0x00, 0x00, 0x00,   // NFCID1t    (is set over sketch with setUID())
      0x20,               // SEL_RES    (0x20=Mifare DelFire, 0x60=custom)

      // FELICA PARAMS
      0x01, 0xFE,         // NFCID2t (8 bytes) https://github.com/adafruit/Adafruit-PN532/blob/master/Adafruit_PN532.cpp FeliCa NEEDS TO BEGIN WITH 0x01 0xFE!
      0x05, 0x01, 0x86,
      0x04, 0x02, 0x02,
      0x03, 0x00,         // PAD (8 bytes)
      0x4B, 0x02, 0x4F, 
      0x49, 0x8A, 0x00,   
      0xFF, 0xFF,         // System code (2 bytes)

      0x01, 0x01, 0x66,   // NFCID3t (10 bytes)
      0x6D, 0x01, 0x01, 0x10,
      0x02, 0x00, 0x00,

      0x00, // length of general bytes
      0x00  // length of historical bytes
  };

  if(uidPtr != 0){  // if uid is set copy 3 bytes to nfcid1
    memcpy(command + 4, uidPtr, 3);
  }

  switch(pn532.tgInitAsTarget(command,sizeof(command), tgInitAsTargetTimeout))
  {
      case 1: break;
      case 0: DMSG("tgInitAsTarget timed out!"); return false; break;
      case -2: DMSG("tgInitAsTarget failed!"); return false;  break;
  }

  uint8_t compatibility_container[] = {
    0, 0x0F,
    0x20,
    0, 0x54,
    0, 0xFF,
    0x04,       // T
    0x06,       // L
    0xE1, 0x04, // File identifier
    ((NDEF_MAX_LENGTH & 0xFF00) >> 8), (NDEF_MAX_LENGTH & 0xFF), // maximum NDEF file size
    0x00,       // read access 0x0 = granted
    0x00        // write access 0x0 = granted | 0xFF = deny
  };

  if(tagWriteable == false){
    compatibility_container[14] = 0xFF;
  }

  tagWrittenByInitiator = false;

  uint8_t rwbuf[128];
  uint8_t sendlen;
  int16_t status;
  int16_t totalReads = 0;
  tag_file currentFile = NONE;
  uint16_t cc_size = sizeof(compatibility_container);
  bool runLoop = true;

  while(runLoop){
    status = pn532.tgGetData(rwbuf, sizeof(rwbuf));
    if(status < 0){
      if (status == -2)
      {
        if (totalReads == 0)
        {
          if (pn532.tgInitAsTarget(command, sizeof(command), 1000) == 1) continue;
        }
        else
        {
          DMSG("Transmission over.\n");
          pn532.inRelease();
          return true;
        }
      }
      DMSG("tgGetData failed!\n");
      pn532.inRelease();
      return false;
    }
    totalReads++;

    uint8_t p1 = rwbuf[C_APDU_P1];
    uint8_t p2 = rwbuf[C_APDU_P2];
    uint8_t lc = rwbuf[C_APDU_LC];
    uint16_t p1p2_length = ((int16_t) p1 << 8) + p2;

    switch(rwbuf[C_APDU_INS]){
      case ISO7816_SELECT_FILE:
        switch(p1){
          case C_APDU_P1_SELECT_BY_ID:
            if(p2 != 0x0c){
              DMSG("C_APDU_P2 != 0x0c\n");
              setResponse(COMMAND_COMPLETE, rwbuf, &sendlen);
            } else if(lc == 2 && rwbuf[C_APDU_DATA] == 0xE1 && (rwbuf[C_APDU_DATA+1] == 0x03 || rwbuf[C_APDU_DATA+1] == 0x04)){
              setResponse(COMMAND_COMPLETE, rwbuf, &sendlen);
              if(rwbuf[C_APDU_DATA+1] == 0x03){
                currentFile = CC;
              } else if(rwbuf[C_APDU_DATA+1] == 0x04){
                currentFile = NDEF;
              }
            } else {
            setResponse(TAG_NOT_FOUND, rwbuf, &sendlen);
            }
            break;
          case C_APDU_P1_SELECT_BY_NAME: 
            const uint8_t ndef_tag_application_name_v2[] = {0, 0x07, 0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x01 };
            if(0 == memcmp(ndef_tag_application_name_v2, rwbuf + C_APDU_P2, sizeof(ndef_tag_application_name_v2))){
              setResponse(COMMAND_COMPLETE, rwbuf, &sendlen);
            } else{
              DMSG("function not supported\n");
              setResponse(FUNCTION_NOT_SUPPORTED, rwbuf, &sendlen);
            } 
            break;
        }
        break;
      case ISO7816_READ_BINARY:
        switch(currentFile){
          case NONE:
            setResponse(TAG_NOT_FOUND, rwbuf, &sendlen);
            break;
          case CC:
            if( p1p2_length > NDEF_MAX_LENGTH){
              setResponse(END_OF_FILE_BEFORE_REACHED_LE_BYTES, rwbuf, &sendlen);
            }else {
              memcpy(rwbuf,compatibility_container + p1p2_length, lc);
              setResponse(COMMAND_COMPLETE, rwbuf + lc, &sendlen, lc);
            }
            break;
          case NDEF:
            if( p1p2_length > NDEF_MAX_LENGTH){
              setResponse(END_OF_FILE_BEFORE_REACHED_LE_BYTES, rwbuf, &sendlen);
            }else {
              memcpy(rwbuf, ndef_file + p1p2_length, lc);
              setResponse(COMMAND_COMPLETE, rwbuf + lc, &sendlen, lc);
            }
            break;
        }
        break;    
      case ISO7816_UPDATE_BINARY:
        if(!tagWriteable){
          setResponse(FUNCTION_NOT_SUPPORTED, rwbuf, &sendlen);
        } else{      
          if( p1p2_length > NDEF_MAX_LENGTH){
            setResponse(MEMORY_FAILURE, rwbuf, &sendlen);
          }
          else{
            memcpy(ndef_file + p1p2_length, rwbuf + C_APDU_DATA, lc);
            setResponse(COMMAND_COMPLETE, rwbuf, &sendlen);
            tagWrittenByInitiator = true;      
            uint16_t ndef_length = (ndef_file[0] << 8) + ndef_file[1];
            if ((ndef_length > 0) && (updateNdefCallback != 0)) {
              updateNdefCallback(ndef_file + 2, ndef_length);
            }
          }
        }
        break;
      default:
        DMSG("Command not supported!");
        DMSG_HEX(rwbuf[C_APDU_INS]);
        DMSG("\n");
        setResponse(FUNCTION_NOT_SUPPORTED, rwbuf, &sendlen);
    }

    status = pn532.tgSetData(rwbuf, sendlen);
    if(status < 0){
      DMSG("tgSetData failed\n!");
      pn532.inRelease();
      return true;
    }
  }
  pn532.inRelease();
  return true;
}



回答2:


just uncomment some stuff like I did and it should work.

void setup()
{
Serial.begin(115200);
Serial.println("------- Emulate Tag --------");

message = NdefMessage();
message.addUriRecord("http://www.elechouse.com");
messageSize = message.getEncodedSize();
if (messageSize > sizeof(ndefBuf)) {
  Serial.println("ndefBuf is too small");
  while (1) { }
}

Serial.print("Ndef encoded message size: ");
Serial.println(messageSize);

message.encode(ndefBuf);

// comment out this command for no ndef message
nfc.setNdefFile(ndefBuf, messageSize);

// uid must be 3 bytes!
nfc.setUid(uid);

nfc.init();
}

void loop(){
// uncomment for overriding ndef in case a write to this tag occured
nfc.setNdefFile(ndefBuf, messageSize); 

// start emulation (blocks)
nfc.emulate();

// or start emulation with timeout
if(!nfc.emulate(1000)){ // timeout 1 second
  Serial.println("timed out");
}

// deny writing to the tag
// nfc.setTagWriteable(false);

if(nfc.writeOccured()){
   Serial.println("\nWrite occured !");
   uint8_t* tag_buf;
   uint16_t length;

   nfc.getContent(&tag_buf, &length);
   NdefMessage msg = NdefMessage(tag_buf, length);
   msg.print();
}


来源:https://stackoverflow.com/questions/59702411/pn532-emulated-card-not-read-by-an-android-phone

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!