2024-10-27 09:35 PM - edited 2024-10-27 10:05 PM
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;
Solved! Go to Solution.
2024-11-18 11:07 PM
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
2024-10-27 09:42 PM
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?
2024-11-05 08:19 AM - edited 2024-11-05 08:28 AM
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
2024-11-11 01:25 AM
#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?
2024-11-11 12:20 PM
Hi,
what is the return code of rfalIsoDepStartApduTransceive? what is the return code of rfalIsoDepGetApduTransceiveStatus when exiting the do while loop?
Rgds
BT
2024-11-11 07:00 PM
It's ERR_TIMEOUT (4). When I send the same APDU message from a PN532 using the indataexchange() function, I get a response back but it isn't working with st25r3911b
2024-11-12 02:45 AM
Hi,
the tmpBuf is not initialized. it should point to a rfalIsoDepBufFormat buffer. Anyway, I believe this is not the cause of the no response issue. Can you connect a logic analyzer on the SPI (CLK, MOSI, MISO, SS) + IRQ_3911B and send us the log file?
Thanks
Rgds
BT
2024-11-12 03:15 AM
I did initialize tmpBuf and added it to param. But it still is not working, I don't have a logic analyzer at my disposal. Can you suggest some other method?
2024-11-12 04:35 AM - edited 2024-11-12 04:38 AM
Hi,
I would try the following:
BR, Ulysses
2024-11-12 06:19 AM
I believe I should call the rfalIsoDepInitializeWithParams() should be called only once or should it be in the loop?