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-12 08:51 PM
Yes, 0x02 is prepended in the frame being sent.
2024-11-13 12:02 AM
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
2024-11-14 07:48 PM
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?
2024-11-14 08:24 PM
rfalIsoDepInitializeWithParams() fixed it. Thank you
2024-11-18 10:55 PM
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
}
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-11-20 12:34 AM
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?
2024-11-20 02:41 AM
Hi,
I would suggest to have a dedicated post for this new question.
Rgds
BT