简体   繁体   English

安卓手机无法读取PN532模拟卡

[英]PN532 emulated card not read by an Android phone

I am using Arduino UNO with elechouse's library and a PN532 module connected through SPI .我正在将Arduino UNOelechouse 的库和通过SPI连接的PN532模块一起使用。

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 .我正在尝试使用该库中的emulate_tag_ndef示例模拟卡,但是当我尝试使用Samsung Galaxy S7上的NFC工具应用程序读取模拟卡时,我得到一个空序列号,但没有收到Ndef消息与类似。

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.当我尝试根据Github上链接问题下方的帖子更改库中的命令数组时,我的手机根本无法检测到模拟卡。

The PN532 works in all other NFC modes (read/write, peer-to-peer) all right for me. PN532可以在所有其他NFC模式(读/写、点对点)下正常工作。

好吧,我尝试了很多解决方案,我可以勇敢地声称Android仅适用于PN532的HCE模式,而Ios仅适用于NDEF。

Give a look to this issue on Seeeds studio:在 Seeeds 工作室查看此问题:

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

Android phones will only accept Felica Cards. Android 手机仅接受 Felica 卡。 If you put some random IDs, it will not be detected as NDEF card.如果你放一些随机的 ID,它不会被检测为 NDEF 卡。

To emulate it right, you have to set the card ID in this way:要正确模拟它,您必须以这种方式设置卡 ID:

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. NFCID1t 是卡的 UID,你可以在你的草图上设置一些东西。
NFCID2t has to be exactly how I wrote in the code above => Felica card NFCID2t 必须与我在上面的代码中编写的完全相同 => Felica 卡
NFCID3t can be some random numbers. NFCID3t 可以是一些随机数。

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).您会看到您的草图还有其他问题,有时无法调试或查看它为什么不起作用(例如,如果您有多个 NDEF 标签)。 So, the most important tool to test your PN532 is this one from NXP:因此,测试 PN532 的最重要工具是来自 NXP 的这个工具:
https://play.google.com/store/apps/details?id=com.nxp.taginfolite 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 :编辑:这就是我从PN532 库更新emulatetag.cpp方式

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;
}

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();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM