cancel
Showing results for 
Search instead for 
Did you mean: 

Sending a select apdu message to a phone using st25r3911b

rabinniroula
Associate II

I have ported rfal platform to work on my esp32 and have successfully detected all kinds of cards. Now I want to send select APDU message to the phone but I am unsucessful at doing so.

The code I have used:

 

err = rfal_nfc.rfalIsoDepPollAHandleActivation(RFAL_ISODEP_FSXI_512, RFAL_ISODEP_NO_DID, RFAL_BR_424, &isoDepDev);
Serial.print("handle activation: ");
Serial.println(err);

err = rfal_nfc.rfalIsoDepStartApduTransceive(param);
Serial.print("APDU txrx error: ");
Serial.println(err);

if (err == ERR_NONE)
{
  do
  {
    rfal_nfc.rfalNfcWorker();
    err = rfal_nfc.rfalIsoDepGetApduTransceiveStatus();
    Serial.print(".");
    // delay(200);
    Serial.print(err);
  } while (err == ERR_BUSY);
  Serial.println("Received!");
  Serial.println(rxLen);
}

 

The param I've used is:

 

rfalIsoDepApduTxRxParam param;
rfalIsoDepApduBufFormat txapdu;
rfalIsoDepApduBufFormat rxapdu;
rfalIsoDepApduBufFormat temp;
uint16_t rxLen;
txapdu.apdu[0] = SELECT_APDU[0];
txapdu.apdu[1] = SELECT_APDU[1];
txapdu.apdu[2] = SELECT_APDU[2];
txapdu.apdu[3] = SELECT_APDU[3];
txapdu.apdu[4] = SELECT_APDU[4];
txapdu.apdu[5] = SELECT_APDU[5];
txapdu.apdu[6] = SELECT_APDU[6];
txapdu.apdu[7] = SELECT_APDU[7];
txapdu.apdu[8] = SELECT_APDU[8];
txapdu.apdu[9] = SELECT_APDU[9];
txapdu.apdu[10] = SELECT_APDU[10];
txapdu.apdu[11] = SELECT_APDU[11];
txapdu.apdu[12] = SELECT_APDU[12];
param.txBuf = &txapdu;
param.txBufLen = sizeof(txapdu);
param.rxBuf = &rxapdu;
param.rxLen = &rxLen;
param.FWT = isoDepDev.info.FWT;

param.dFWT = isoDepDev.info.dFWT;

param.FSx = RFAL_ISODEP_FSX_KEEP;      

//myParam.FSx = isoDepDevice.info.FSx;

param.DID = isoDepDev.info.DID;  
param.ourFSx = isoDepDev.info.FSx; 

 

The rxLen I get is always 42405. I couldn't find any examples to transceive apdu messages. Can you please help me? Thank you
17 REPLIES 17

Yes, 0x02 is prepended in the frame being sent.

Hi, 

please call rfalIsoDepInitializeWithParams() inside the loop before performing the Activation.

Next step for you: Are you actually getting I_nre in this case? Or is e.g. the sanity timer gRFAL.tmr.txRx hitting. Normally this should pretty much never hit as except for very rare case the ST25R3911B will signal proper interrupts.

And: Please check selRes if it is actually announcing ISODEP support in it. I would be surprised if a phone doesn't but you need to rule this out.

 

Ulysses

I added a breakpoint and debug print into st25r3911WriteFifo. The program put out the following.

st25r3911WriteFifo: 2 0 a4 4 0 7 ** ** * * ** * ** 0
st25r3911WriteFifo: f2 8

The first one has the select aid prepended with 0x02 but it's also sending the f2 8, is it correct?

rfalIsoDepInitializeWithParams() fixed it. Thank you

Well, the application I have written thus far is working perfectly. But today I found out that the android app expects an acknowledgement of 0x90 0x00 after it sends out the R-APDU. I tried sending 0x90 0x00 with another call to rfalIsoDepStartApduTransceive(). I did setup the param differently for it with the FWT, FSx being the same from previous call. But I don't believe it is being transmitted as the android app isn't responding to it.

 

uint8_t SUCCESS[] = {0x90, 0x00};

void loop()
{
  rfal_nfc.rfalNfcWorker(); // RFAL worker

  // Initialize as NFC-A poller
  err = rfal_nfc.rfalNfcaPollerInitialize();
  if (err != ERR_NONE)
  {
    Serial.println("Poller initialization failed.");
    delay(1000);
    return;
  }
  // Serial.println("Poller Initialized");

  // Check for NFC-A tag presence
  rfalNfcaSensRes sensRes;
  err = rfal_nfc.rfalNfcaPollerCheckPresence(RFAL_14443A_SHORTFRAME_CMD_REQA, &sensRes);
  if (err != ERR_NONE)
  {
    // Serial.println("No tag detected.");
    // delay(1000);
    return;
  }
  // Serial.println("NFC-A tag detected.");

  // Perform collision resolution
  bool collPending = false;
  rfalNfcaSelRes selRes;
  uint8_t nfcId[10];
  uint8_t nfcIdLen;

  uint8_t devCnt;
  rfalNfcaListenDevice dev[10];

  err = rfal_nfc.rfalNfcaPollerFullCollisionResolution(RFAL_COMPLIANCE_MODE_ISO, 10, dev, &devCnt);
  // err = rfal_nfc.rfalNfcaPollerSingleCollisionResolution(1, &collPending, &selRes, nfcId, &nfcIdLen);
  // Serial.printf("Selres ack: %d", selRes.sak);
  if (err != ERR_NONE)
  {
    Serial.printf("Collision resolution failed. %d\n", err);
    delay(1000);
    return;
  }
  Serial.printf("%d tags present.\n", devCnt);
  for (int i = 0; i < devCnt; i++)
  {
    // Serial.print(dev[0].nfcId1[i], HEX);
    // Serial.print(" ");
    Serial.printf("\t Tag %d UID: ", i);
    for (int j = 0; j < dev[i].nfcId1Len; j++)
    {
      Serial.print(dev[i].nfcId1[j], HEX);
      Serial.print("");
    }
  }
  Serial.println();

  rfal_nfc.rfalIsoDepInitializeWithParams(RFAL_COMPLIANCE_MODE_ISO, 20, 20, 20, 20);

  // Activate device
  rfalIsoDepDevice isoDepDev;
  err = rfal_nfc.rfalIsoDepPollAHandleActivation((rfalIsoDepFSxI)RFAL_ISODEP_FSDI_DEFAULT, RFAL_ISODEP_NO_DID, RFAL_BR_106, &isoDepDev);
  if (err != ERR_NONE)
  {
    Serial.print("Handle activation error: ");
    Serial.println(err);
    delay(1000);
    return;
  }
  // Serial.printf("Device activated. ERR=%d\n", err);

  // Set up APDU parameters
  rfalIsoDepApduTxRxParam param;
  rfalIsoDepApduBufFormat txapdu;
  rfalIsoDepApduBufFormat rxapdu;
  rfalIsoDepBufFormat tmp;
  uint16_t rxLen;

  memcpy(txapdu.apdu, SELECT_APDU, sizeof(SELECT_APDU));
  param.txBuf = &txapdu;
  param.txBufLen = sizeof(SELECT_APDU);
  param.rxBuf = &rxapdu;
  param.rxLen = &rxLen;
  param.tmpBuf = &tmp;
  param.FWT = isoDepDev.info.FWT;
  param.dFWT = isoDepDev.info.dFWT;
  param.FSx = RFAL_ISODEP_FSX_KEEP;
  param.DID = isoDepDev.info.DID;
  param.ourFSx = isoDepDev.info.FSx;

  Serial.println("Sending APDU...");
  err = rfal_nfc.rfalIsoDepStartApduTransceive(param);
  if (err != ERR_NONE)
  {
    Serial.print("Error in transceive: ");
    Serial.println(err);
    delay(1000);
    return;
  }

  // Wait for response
  do
  {
    rfal_nfc.rfalNfcWorker();
    err = rfal_nfc.rfalIsoDepGetApduTransceiveStatus();
  } while (err == ERR_BUSY);

  if (err != ERR_NONE)
  {
    Serial.printf("Error in response: %d \n", err);
    return;
  }

  if (err != ERR_NONE)
  {
    Serial.print("Error receiving APDU response: ");
    Serial.println(err);
  }
  else
  {
    // Serial.printf("APDU Response received! Len = %d\nResponse: ", rxLen);
    // for (uint8_t i = 0; i < rxLen; i++)
    // {
    //   Serial.print((char)rxapdu.apdu[i]);
    //   // Serial.print(" ");
    // }
    // Serial.println("");

    rfalIsoDepApduTxRxParam succ_param;
    rfalIsoDepApduBufFormat succ_txapdu;
    rfalIsoDepApduBufFormat succ_rxapdu;
    rfalIsoDepBufFormat succ_tmp;
    uint16_t succ_rxLen = 0;

    memset(succ_txapdu.apdu, 0x00, sizeof(succ_txapdu.apdu));
    memset(succ_rxapdu.apdu, 0x00, sizeof(succ_rxapdu.apdu));
    memcpy(succ_txapdu.apdu, SUCCESS, sizeof(SUCCESS));
    Serial.print("Debug: ");
    for (int i = 0; i < sizeof(SUCCESS); i++)
    {
      Serial.print(succ_txapdu.apdu[i], HEX);
    }
    Serial.println("");
    succ_param.txBuf = &succ_txapdu;
    succ_param.txBufLen = sizeof(SUCCESS);
    succ_param.rxBuf = &succ_rxapdu;
    succ_param.rxLen = &succ_rxLen;
    succ_param.tmpBuf = &succ_tmp;
    succ_param.FWT = isoDepDev.info.FWT;
    succ_param.dFWT = isoDepDev.info.dFWT;
    succ_param.FSx = RFAL_ISODEP_FSX_KEEP;
    succ_param.DID = isoDepDev.info.DID;
    succ_param.ourFSx = isoDepDev.info.FSx;

    rfal_nfc.rfalIsoDepInitializeWithParams(RFAL_COMPLIANCE_MODE_NFC, 20, 20, 20, 20);

    // err = rfal_nfc.rfalIsoDepPollAHandleActivation((rfalIsoDepFSxI)RFAL_ISODEP_FSDI_DEFAULT, RFAL_ISODEP_NO_DID, RFAL_BR_106, &isoDepDev);
    // Serial.printf("Success Activation: %d\n", err);
    err = rfal_nfc.rfalIsoDepStartApduTransceive(succ_param);
    if (err != ERR_NONE)
    {
      Serial.print("Error in transceive: ");
      Serial.println(err);
      delay(1000);
      return;
    }

    // Wait for response
    do
    {
      rfal_nfc.rfalNfcWorker();
      err = rfal_nfc.rfalIsoDepGetApduTransceiveStatus();
    } while (err == ERR_BUSY);

    if (err == ERR_NONE)
    {
      Serial.print("After success: ");
      for (uint8_t i = 0; i < succ_rxLen; i++)
      {
        Serial.print((char)succ_rxapdu.apdu[i]);
        // Serial.print(" ");
      }
      Serial.println();
    }
    else
    {
      Serial.printf("Success Transceive error! code = %d\n", err);
    }
  }
  // delay(1000); // Add delay between polling attempts
}

Hi,

 

Status codes of '90 00' are typically only used from PICC side. But of course nothing preventing a protocol to use it also the other direction.

I think the problem in your code is your repeated call to rfalIsoDepInitialize(). Once initialized and activated, just stay with the transceive of APDU. I think the initialize will have reset the 1-bit ISODEP block counter - thus the APDU ignored by the phone due to not fitting counter.

BR, Ulysses

rabinniroula
Associate II

How would i send apdu to multiple detected devices? I believe I should use the rfalIsoDepPollAHandleActivation() function with different DID values. I couldn't find much documentation on DID other than it's used to determine which device to activate and that it's a logical address, could you explain?

Brian TIDAL
ST Employee

Hi,

I would suggest to have a dedicated post for this new question.

Rgds

BT

In order to give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.