[MRFC630] Can't response from APDU command

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

[MRFC630] Can't response from APDU command

10,428 Views
jtpark
Contributor IV

Greetings,

I have met the issue of response from APDU.

I checked the RATS's response.

However, when I send the APDU's command to mfrc630, I can't response anything.

command of APDU is as below.

APDU ={0x00, 0xA4, 0x04, 0x00, 0x07 ,_data 7byte,0x00}    // Commend[13byte]
I think about that I get the data with 0x90, 0x00 but I can't take a response.
Source code is as below.

     fifo_flush();

    mfrc630_write_reg(MFRC630_REG_TXCRCPRESET, MFRC630_RECOM_14443A_CRC | MFRC630_CRC_ON);
    mfrc630_write_reg(MFRC630_REG_RXCRCCON, MFRC630_RECOM_14443A_CRC | MFRC630_CRC_ON);


   uint8_t timer_for_timeout = 0;  // should match the enabled interupt.

   mfrc630_write_reg(MFRC630_REG_IRQ0EN, MFRC630_IRQ0EN_IDLE_IRQEN | MFRC630_IRQ0EN_ERR_IRQEN);
   mfrc630_write_reg(MFRC630_REG_IRQ1EN, MFRC630_IRQ1EN_TIMER0_IRQEN);


  mfrc630_timer_set_control(timer_for_timeout, MFRC630_TCONTROL_CLK_211KHZ | MFRC630_TCONTROL_START_TX_END);
  mfrc630_timer_set_reload(timer_for_timeout, 10000);  // 2000 ticks of 5 usec is 10 ms.
  mfrc630_timer_set_value(timer_for_timeout, 10000);

  uint8_t irq1_value = 0;
  uint8_t irq0_value = 0;

  mfrc630_clear_irq0();  // clear irq0
  mfrc630_clear_irq1();  // clear irq1

  mfrc630_cmd_transceive(DF_data, 13);
  while (!(irq1_value & (1 << timer_for_timeout))) {


    irq1_value = mfrc630_irq1();
    if (irq1_value & MFRC630_IRQ1_GLOBAL_IRQ)    break;    

  }


   mfrc630_cmd_idle();

   if (irq1_value & (1 << timer_for_timeout))   return 0;
   
  irq0_value = mfrc630_irq0();
  if (irq0_value & MFRC630_IRQ0_ERR_IRQ)     return 0;

Would you please let me know what problem do I have?

Thanks.

0 Kudos
Reply
22 Replies

8,479 Views
minabf61
Contributor III

Hi All,

I am back again with another problem. Please help if you can. Now that I managed to read and write from HCE for some strange reason I am limited to only 14 bytes read from fifo. I know that fifo can handle 512 bytes and I have set it to do so however eventhough I can write files as big as I need but I can not read them back if the file is bigger than a 14 bytes file!! My investigation shows that the problem comes from the fact that from the beginning the fifo length 's read as 14 bytes where as in my case it should have been 18 bytes! ignoring the length of the fifo, I read 18 bytes but the problem is, I got the last 4 byte all zeros! Could anyone recognise this issue?I really appreciate your help and thought.

0 Kudos
Reply

8,441 Views
RadomirT
Contributor II

Hi,

if you use mfrc630 lib:

uint8_t mfrc630_transfer(uint8_t cmd[], uint32_t cmdSize, uint8_t data[], uint32_t* dataSize)
{

....

// all seems to be well...
uint8_t buffer_length = mfrc630_fifo_length();
//printf("mfrc630_fifo_length %d\n", buffer_length);
uint8_t rx_len = (buffer_length <= *dataSize) ? buffer_length : *dataSize;
mfrc630_read_fifo(data, rx_len);
*dataSize = rx_len;

return rx_len;

}

In this case before you call this function:

uint8_t res[512];
uint32_t resSize = sizeof(res);
status = mfrc630_transfer(req, reqSize, res, &resSize); 

8,432 Views
minabf61
Contributor III

Hi @RadomirT 

Thanks so much for coming back to me.

my problem is "mfrc630_14443p4_transfer" function. What is data and dataSize in it? If you look at this function, data and dataSize has never been used inside it so I know this is the response so I swaped res with data.

plus in uint8_t buffer_length = mfrc630_fifo_length() inside "mfrc630_transfer" function, the buffer_length never exceed 14bytes! hence the data is limited to 14 bytes!

Have you tried reading and writing into desfire card's created file? I could not find any apdu commands relating to that in your code.

Any idea?

Kind regards,

Mina

0 Kudos
Reply

8,411 Views
RadomirT
Contributor II

from NXP phpalI14443p4_Sw.c:

phStatus_t phpalI14443p4_Sw_Exchange()
{

/* I-BLOCK TRANSMISSION LOOP */

...

phpalI14443p4_Sw_IsoHandling()

...

/* I-BLOCK RECEPTION LOOP */

.....

phpalI14443p4_Sw_IsoHandling()

...

}

 

8,417 Views
RadomirT
Contributor II

OK, data are just send to printf() for debug reason, it is just for example.

uint8_t mfrc630_14443p4_transfer(uint8_t cmd[], uint32_t cmdSize, uint8_t data[], uint32_t* dataSize)
{

....

uint32_t resSize = sizeof(res);
status = mfrc630_transfer(req, reqSize, res, &resSize);
if(status>0)
{
MFRC630_PRINTF("14443P4 (%lub) < ", resSize);
print_block(res, resSize);

/* NXP phpalI14443p4_Sw.c */
/* I-Block handling */
if (0u != (PHPAL_I14443P4_SW_IS_I_BLOCK(res[PHPAL_I14443P4_SW_PCB_POS])))
{
//OK
break;
}
/* R(ACK) handling */
else if ((PHPAL_I14443P4_SW_IS_R_BLOCK(res[PHPAL_I14443P4_SW_PCB_POS]) > 0U) && (PHPAL_I14443P4_SW_IS_ACK(res[PHPAL_I14443P4_SW_PCB_POS]) > 0U))
{
break;
}

res[] is internal buffer, in code is missing final data handling (memcpy res[] to data[]). According I14443P4 maybe you should check I-Block pcb and with R(ACK) block ask for consequent I-Block frames?

RadomirT_0-1650971926748.png

Never got so far in debuging.... just tested with android HCE Test tool to printf() console.

8,409 Views
minabf61
Contributor III

Hi @RadomirT

 

I think you have directed me to the right place, many thanks for that. At least I know where the problem comes from. So I need to develop my code to do the I-block handeling which I got no information about it. 

Kind regards,

Mina

0 Kudos
Reply

8,405 Views
AlexanderB
NXP Employee
NXP Employee

Hi,

if you do not have access to the official ISO/IEC 14443-3 and 14443-4 standards I can recommend to have a look at ECMA-340. Which is actually quite the same.

It will explain everything you need to know about the PCB (Protocol Control Byte) handling. Googling ISO 14443-4 PCB Block Handling and other combinations also will give you plenty of results to learn about the process of it. 

In case you rather read code instead of googling you can always look into the NFC Reader Library to check how it is handled there. 

Greetings, Alex

8,401 Views
minabf61
Contributor III

Many thanks @AlexanderB. I will look into ECMA-340 while trying to understand NXP's phpalI14443p4_Sw.c file.

Kind regards,

Mina

0 Kudos
Reply

8,370 Views
minabf61
Contributor III

Hi all,

Just to keep the community updated, I found out what the problem was. So when sending RATS to get ATS I needed to set the FSDI to the desired frame size it was set to 16 bytes hence I was not able to recieve more than 16 bytes.

 

The most significant half-byte b8 to b5 is called FSDI and codes FSD. The FSD defines the maximum
size of a frame the PCD is able to receive.

 
 
FSDI"0""1""2""3""4""5""6""7""8""9-F"
FSD(bytes)16243240486496128256RFU

 

 

Many thanks for all your help. I found it out while reading the standart.

 
 

Kind regards,

Mina

 

0 Kudos
Reply

8,447 Views
AlexanderB
NXP Employee
NXP Employee

Hello @minabf61 ,

please help me to understand your setup first. You speak of HCE (Host Card Emulation) but the product from the title "MFRC630" does not support HCE. It is a R/W (PCD) only without the capability to emulate a card (PICC). 

So I assume that you are reading from another HCE target with the MFCRC630? 
What is the HCE target?

Please do not hold back with information. As more as I know the better I can help you  

Best regards,
Alexander

 

8,425 Views
minabf61
Contributor III

Hi @AlexanderB ,

yes I am reading from another HCE target with the CLRC663(using mainly MFRC630 functions). So my HCE target is an android app. I have the same issue using only the desfire card so can not blaim the android app for it. 

I am sending APDU commands to read and write into desfire card (or the HCE) I have no problem writing into the card and gettting the success response, bearing in mind that using other devices I can fully read whatever I wrote in the file. 

I also need to be able to read what I wrote into the file, but am limited to 14 bytes read!

Here I attached my code:

 

typedef struct {

uint8_t FileNo[1];
uint8_t Offset[3];
uint8_t Length[3];

}EmulatedCard;

//============================================================

uint8_t ReadDataSetting[18] = {0};    // I know my data is 18 bytes as I wrote 16bytes into the file +2                                                                   // bytes operation status
EmulatedCard LockSettig = {{0x01}, {0x07, 0x00, 0x00}, {sizeof(ReadDataSetting), 0x00, 0x00}};
MIFARE_Emulated_ReadData( ReadDataSetting, sizeof(ReadDataSetting), LockSettig.FileNo, LockSettig.Offset, LockSettig.Length);

//============================================================

void MIFARE_Emulated_ReadData(uint8_t ReadData[], uint32_t* ReadDataSize, uint8_t FileNo[], uint8_t Offset[], uint8_t Length[]){

uint8_t cmd[8] = {0};
cmd[0] = 0xBD; // --------------Command for Reading
memcpy(cmd +1, FileNo, 1);
memcpy(cmd +2, Offset, 3);
memcpy(cmd +5, Length, 3);

uint8_t status = CLRC663_14443p4_transfer(cmd, sizeof(cmd), ReadData, &ReadDataSize);
}

// ================================================================

uint8_t CLRC663_14443p4_transfer(uint8_t cmd[], uint32_t cmdSize, uint8_t data[], uint32_t* dataSize)
{
uint8_t req[cmdSize+1];
req[0] = get_pcb();
memcpy(&req[1], cmd, cmdSize);
uint32_t reqSize = sizeof(req);

uint8_t status = 0;

uint32_t retries = 6;
uint8_t bCheckNad;
do
{
uint32_t dataSize = sizeof(data);
status = CLRC663_transfer(req, reqSize, data, &dataSize);
if(status>0)
{

/* NXP phpalI14443p4_Sw.c */
/* I-Block handling */
if (0u != (PHPAL_I14443P4_SW_IS_I_BLOCK(data[PHPAL_I14443P4_SW_PCB_POS])))
{
//OK
break;
}
/* R(ACK) handling */
else if ((PHPAL_I14443P4_SW_IS_R_BLOCK(data[PHPAL_I14443P4_SW_PCB_POS]) > 0U) && (PHPAL_I14443P4_SW_IS_ACK(data[PHPAL_I14443P4_SW_PCB_POS]) > 0U))
{
break;
}
/* S(WTX) handling */
else if ((PHPAL_I14443P4_SW_IS_S_BLOCK(data[PHPAL_I14443P4_SW_PCB_POS]) > 0U) && (PHPAL_I14443P4_SW_IS_WTX(data[PHPAL_I14443P4_SW_PCB_POS]) > 0U))
{
/* Retrieve WTXM */
uint8_t bWtxm = data[dataSize-1u];

/* Ignore and clear the Power Level Indication */
bWtxm &= 0x3FU;

/* Generate S(WTX) frame */

/* S-Block PCB */
req[PHPAL_I14443P4_SW_PCB_POS] = PHPAL_I14443P4_SW_S_BLOCK | PHPAL_I14443P4_SW_S_BLOCK_RFU_BITS;
req[PHPAL_I14443P4_SW_PCB_POS] |= PHPAL_I14443P4_SW_PCB_WTX;
req[PHPAL_I14443P4_SW_PCB_POS+1] = bWtxm;
reqSize = 2;

//TODO: wait?
}
/* S(DESELECT) handling */
else if ((PHPAL_I14443P4_SW_IS_S_BLOCK(data[PHPAL_I14443P4_SW_PCB_POS]) > 0U) && (PHPAL_I14443P4_SW_IS_DESELECT(data[PHPAL_I14443P4_SW_PCB_POS]) > 0U))
{
/* S-Block PCB */
req[PHPAL_I14443P4_SW_PCB_POS] = PHPAL_I14443P4_SW_S_BLOCK | PHPAL_I14443P4_SW_S_BLOCK_RFU_BITS;
reqSize = 1;

}
/* We received an invalid block */
else
{
break;
}
}
else
break;

--retries;
}while(retries!=0);
return status;
}

// ===============================================================

uint8_t CLRC663_transfer(uint8_t cmd[], uint32_t cmdSize, uint8_t data[], uint32_t* dataSize)
{
CLRC663_flush_fifo();

CLRC663_write_reg(CLRC663_REG_TXCRCPRESET, CLRC663_RECOM_14443A_CRC | CLRC663_CRC_ON);
CLRC663_write_reg(CLRC663_REG_RXCRCCON, CLRC663_RECOM_14443A_CRC | CLRC663_CRC_ON);

// configure a timeout timer.
uint8_t timer_for_timeout = 0; // should match the enabled interupt.

// enable the global IRQ for idle, errors and timer.
CLRC663_write_reg(CLRC663_REG_IRQ0EN, CLRC663_IRQ0EN_IDLE_IRQEN | CLRC663_IRQ0EN_ERR_IRQEN);
CLRC663_write_reg(CLRC663_REG_IRQ1EN, CLRC663_IRQ1EN_TIMER0_IRQEN);


// Set timer to 221 kHz clock, start at the end of Tx.
CLRC663_timer_set_control(timer_for_timeout, CLRC663_TCONTROL_CLK_211KHZ | CLRC663_TCONTROL_START_TX_END);
// Frame waiting time: FWT = (256 x 16/fc) x 2 FWI
// FWI defaults to four... so that would mean wait for a maximum of ~ 5ms
CLRC663_timer_set_reload(timer_for_timeout, 20000); // 20000 ticks of 5 usec is 100 ms.
CLRC663_timer_set_value(timer_for_timeout, 20000);

uint8_t irq1_value = 0;
uint8_t irq0_value = 0;


CLRC663_clear_irq0(); // clear irq0
CLRC663_clear_irq1(); // clear irq1

// Go into send, then straight after in receive.
CLRC663_cmd_transceive(cmd, cmdSize);

// block until we are done
while (!(irq1_value & (1 << timer_for_timeout))) {
irq1_value = CLRC663_irq1();
if (irq1_value & CLRC663_IRQ1_GLOBAL_IRQ) {
break; // stop polling irq1 and quit the timeout loop.
}
}
CLRC663_cmd_idle();

if (irq1_value & (1 << timer_for_timeout)) {
return 0;
}

irq0_value = CLRC663_irq0();
if ((!(irq0_value &CLRC663_IRQ0_RX_IRQ)) || (irq0_value & CLRC663_IRQ0_ERR_IRQ)) {
// some error
if((irq0_value & CLRC663_IRQ0_ERR_IRQ)) {
uint8_t error = CLRC663_read_reg(CLRC663_REG_ERROR);
}
return 0;
}
//HAL_Delay(10);
// all seems to be well...
uint16_t buffer_length = CLRC663_fifo_length();
uint8_t rx_len = (buffer_length <= *dataSize) ? buffer_length : *dataSize;
fifo_readall(data, rx_len);
// CLRC663_read_fifo(data, rx_len);
*dataSize = rx_len;

return rx_len;
}

so at this line, buffer_length = CLRC663_fifo_length() , fifo length does not go higher than 14 bytes and hence I can't read any more data.

I really appreciate any help.

Kind regards,

Mina

0 Kudos
Reply

8,846 Views
mina_farah
Contributor II

Many thanks RadomirT and  AlexanderB. It is now working! Can't believe it!

0 Kudos
Reply

9,137 Views
RadomirT
Contributor II

Hi @AlexanderB,

I tested with pcb byte and is working. I am using APDU commands SELECT with:
uint8_t ppse[] = {0x32, 0x50, 0x41, 0x59, 0x2e, 0x53, 0x59, 0x53, 0x2e, 0x44, 0x44, 0x46, 0x30, 0x31};
uint8_t app_visa[] = {0xa0, 0x00, 0x00, 0x00, 0x03, 0x10, 0x10};
or
uint8_t app_mast[] = {0xa0, 0x00, 0x00, 0x00, 0x04, 0x10, 0x10};

and from VISA/MASTER cards I'v got correct response.

There is issue if I use my phone in mode HCE (HCE Test tool - VISA image) I am able to send/receive RATS/ATS but for PPSE I got always some error:
RATS (5b): 05 78 80 40 00
APDU PPSE (2b): F2 08

I tested also with VISA/MASTER and if I am far enough with the card from CLRC663 dev board it's also return F2 01. I can not find any explanation to this response. What is meaning of this?

Thanks for your help,
Radomir

8,886 Views
mina_farah
Contributor II

Hi RadomirT,

 

Have you find any solution to your problem. I have exactly the same issue I keep getting f2 01 most of the time even thought I sometimes I get 90 00 but most of the time f2 01 is what I get. Could you please help if you get to the solution I am stuck on this for months now. Thanks in advance.

0 Kudos
Reply

8,876 Views
RadomirT
Contributor II

Hi,

I finished implemetation of:

  • ISO14443A-4: wrapper for APDU commands
  • ISO7816-4 APDU: commands for SELECT PPSE/AID - working with VISA/MASTERCARD, support for HCE on Andriod (HCE Test Tool)

Solution you can find in github repo:

STM32F1-CLRC663

8,870 Views
mina_farah
Contributor II

Wow! Many thanks. I think my issue is that I am just toggling between 0x02 and 0x03 with each commands where as it seems there is more into it that than just toggling. I am going to use that bit of your code fingers crossed it solves my issue. Again many thanks for your help.

0 Kudos
Reply

8,861 Views
AlexanderB
NXP Employee
NXP Employee

Hello Mina,

you can also have a look into the NFC Reader Library which incoporates all necessary abstraction layers to talk with any external device on any specified protocol layer. 

Speaking about the PCB (Protocol control byte) you are at level ISO/IEC-14443-4 which in the reader library is covered at the protocol abstraction layer iso14443p4 (see phpall14443p4.h for its available APIs).

Best regards,

Alexander

9,738 Views
AlexanderB
NXP Employee
NXP Employee

Hello jtpark‌,

after a RATS/ATS exchange the tag is in Layer-4 and you have to use the ISO-DEP protocol for communication. Your frame looks like a SELECT APPLICATION according to ISO-7816-4. This frame you would have to embedded into the ISO-DEP block format.

You can check following specifications: 

@see NFC Forum Digital Protocol TS [16 ISO-DEP Protocol]

@see ISO/IEC 14443-4 Part 4: Transmission Protocol [7 Half-duplex block transmission protocol]

To give a short summary about it. You are missing the PCB (Protocol control byte), in case you do not use DID. For an information block (I-Block) without DID or chaining the PCB would look like 0000 001Xb, where 'X' is the block number and alternating from frame to frame (02h, 03h, 02h, 03h, ....)

For a quick test you can just set the PCB at the front of your command and you should get a response: 

APDU ={0x02, 0x00, 0xA4, 0x04, 0x00, 0x07 ,_data 7byte, 0x00} 

I hope this was helpful.

Edit: You can use the NXP NFC Reader Library which offers several classes to handle the ISO-DEP protocol (it comes with a couple of rules about error detection, recovery etc...), activation and other things quite handy for a proper specification compliant communication. 

Or you can just use it as a guideline for your own implementation.

Best regards,

Alexander

9,384 Views
VaradrajSK
Contributor I

Hi Alexander,

I have a similar requirement wherein I want to use the MFRC630 reader to send and receive ISO 7816-4 APDU commands. I tried your suggestions above but could not get any response from the card.

Is there any library or example project from NXP that you can point me to? Where can i find the NXP NFC Reader Library for MFRC630 that you mentioned here?

Thanks,

Varad

0 Kudos
Reply

9,133 Views
AlexanderB
NXP Employee
NXP Employee

Hello,

the MFRC630 belongs to the RC663 family. Please go to https://www.nxp.com/design/designs/nfc-reader-library-software-support-for-nfc-frontend-solutions:NF... and download the library for the 663. 

In the library you will find various examples showing different scenarios and functionality. For layer-4 abstraction have a closer look at phpalI14443p4.

Best regards,
Alexander