0

我正在使用Arduino UNOelechouse的库和一个PN532通过SPI.

我正在尝试使用该emulate_tag_ndef库中的示例模拟一张卡片,但是当我尝试使用我的NFC工具应用程序读取模拟卡片时Samsung Galaxy S7,我得到一个空序列号并且我没有收到与此类Ndef似的消息。

当我尝试根据链接问题上的帖子更改库中的命令数组Github时,我的手机根本无法检测到模拟卡。

PN532所有其他NFC模式(读/写,点对点)的工作对我来说都很好。

4

3 回答 3

1

好吧,我尝试了很多解决方案,我可以勇敢地声称,Android 只能在 HCE 模式下使用 PN532,而 Ios 只能在 NDEF 下使用。

于 2021-12-04T10:08:40.990 回答
0

在 Seeeds 工作室看一下这个问题:

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

Android 手机只接受 Felica 卡。如果你放一些随机的ID,它不会被检测为NDEF卡。

要正确模拟它,您必须以这种方式设置卡 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 是卡的 UID,你可以在你的草图上设置一些东西。
NFCID2t 必须完全是我在上面的代码中编写的 => Felica 卡
NFCID3t 可以是一些随机数。

你会看到你的草图会有其他问题,有时无法调试或查看它为什么不起作用(例如,如果你有多个 NDEF 标签)。因此,测试 PN532 的最重要工具是来自 NXP 的这个工具:https:
//play.google.com/store/apps/details? id=com.nxp.taginfolite

这会给你很多信息。这个应用程序也可以读取您的卡片,即使它没有以正确的方式格式化。

编辑:这就是我emulatetag.cppPN532 库更新的方式:

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;
}
于 2020-01-13T10:03:52.347 回答
0

只是像我一样取消注释一些东西,它应该可以工作。

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();
}
于 2020-01-28T04:21:56.713 回答