Skip to main content
Visitor II
October 28, 2024
Solved

Sending a select apdu message to a phone using st25r3911b

  • October 28, 2024
  • 3 replies
  • 2909 views

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
    This topic has been closed for replies.
    Best answer by Ulysses HERNIOSUS

    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

    3 replies

    Visitor II
    October 28, 2024
    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; 

    Is there anything wrong with my param?

    Technical Moderator
    November 5, 2024

    Hi

    when exiting from the do { ... } while (err == ERR_BUSY); loop, the error code is not checked. The rfalIsoDepGetApduTransceiveStatus probably returns an ERR_TIMEOUT due to no response from the tag. When the error code is different from ERR_NONE, the rxLen is not updated and contains probably garbage from the stack.

    Can you log the error code when exiting from the do while loop ?

    Also, can you print the content of param.txBuf?

    Note that rfal_t4t.c provides an rfalT4TPollerCompose API to build the SELECT application, SELECT file, READ BINARY and UPDATE BINARY Commands APDU. 

    An example of APDU transceive is available in ndefT4TTransceiveTxRx function in ndef_t4t.c file.

    Rgds

    BT

    Visitor II
    November 11, 2024

     

    #include <SPI.h>
    #include "rfal_rf.h"
    #include "rfal_nfc.h"
    #include "rfal_rfst25r3911.h"
    #include "ndef_class.h"
    
    // Initialize SPI and RFAL instances
    SPIClass dev_spi;
    RfalRfST25R3911BClass rfst25r3911b(&dev_spi, 5, 17);
    RfalNfcClass rfal_nfc(&rfst25r3911b);
    NdefClass ndef(&rfal_nfc);
    
    // Define constants
    #define APDU_CMD_LEN 13
    uint8_t SELECT_APDU[] = {}; // I can't disclose this for security reasons
    ReturnCode err;
    void setup() {
     Serial.begin(115200);
     dev_spi.begin();
    
     // Initialize RFAL
     err = rfal_nfc.rfalNfcInitialize();
     if (err != ERR_NONE) {
     Serial.println("RFAL initialization failed.");
     while (true);
     }
     Serial.println("RFAL Initialized");
    
     err = rfst25r3911b.rfalFieldOnAndStartGT();
     if (err != ERR_NONE) {
     Serial.println("Field activation failed.");
     while (true);
     }
     Serial.println("Field On");
    
     pinMode(LED_BUILTIN, OUTPUT);
     digitalWrite(LED_BUILTIN, LOW);
    }
    
    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;
     err = rfal_nfc.rfalNfcaPollerSingleCollisionResolution(1, &collPending, &selRes, nfcId, &nfcIdLen);
     if (err != ERR_NONE) {
     Serial.println("Collision resolution failed.");
     delay(1000);
     return;
     }
     Serial.print("Tag selected. UID: ");
     for (int i = 0; i < nfcIdLen; i++) {
     Serial.print(nfcId[i], HEX);
     Serial.print(" ");
     }
     Serial.println();
    
     // 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.println("Device activated");
    
     // Set up APDU parameters
     rfalIsoDepApduTxRxParam param;
     rfalIsoDepApduBufFormat txapdu;
     rfalIsoDepApduBufFormat rxapdu;
     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.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.println("APDU Response received:");
     // for (uint8_t i = 0; i < rxLen; i++) {
     // Serial.print(rxapdu.apdu[i], HEX);
     // Serial.print(" ");
     // }
     // Serial.println();
     // }
    
     // delay(1000); // Add delay between polling attempts
    }

    This is the full code that I'm using, there's no transceive happening. No response the length of the response is 0. What did I do wrong here?

     

    Visitor II
    November 20, 2024

    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?

    Technical Moderator
    November 20, 2024

    Hi,

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

    Rgds

    BT