Using NFC Library in 'raw' APDU mode : how to set FWI/FWTX?

Custom device using nrf5340, with NFC card emulation functionality.

To use the NFC, I understand that I should use the supplied nfc_t4t library (binary) and its api. I have this working ok for type 4 card emulation using the NDEF application functionality built in to the library..

I now need to create an application that will emulate other functions, and so I am trying to the use the library in 'raw APDU' mode. This is basically working, but I have run into a timeout issue : certain elements of my APDU processing can take some 10's of ms, and this is apparently causing my nfc reader to timeout its request. This causes the library to have some issues : I get logs like this:

[00:05:13.375,488] <err> nfc_platform: Tried to read data pointer: 4 bytes, read 0.
[00:05:13.375,488] <err> nfc_platform: Reading nfc ring buffer failed, resetting ring buffer.

 I think these are basically when I do the nfc_t4t_response_pdu_send() call to send the response PDU. Any ideas on what this means for my operation?

The reader never manages to get a valid response, this seems to be related to the time it takes for my code to process the APDU (around 35ms for a basic select operation, due to it being sent to a ISO7816 contact card for processing...). In the NFC spec I see this:

"When the Card Emulator needs more time than the defined FWT to process the received block, it uses an S(WTX) request for a waiting time extension. An S(WTX) request contains a 1-byte INF field as specified in Table 84"

How can I tell the library that I want it to send this S(WTX) frame? It seems it needs to be sent for each received command? The only param I see to set is the FWI (which sets the max FWT as I understand it). When I try to set this to the max (before doing nfc_t4t_setup()) :

                uint32_t fwi = NFC_T4T_FWI_MAX_VAL_EMV;
                if ((ret=nfc_t4t_parameter_set(NFC_T4T_PARAM_FWI, &fwi, sizeof(fwi)))!=0) {
                    log_warn("nfcmgr: t4t fwi set fails (%d)",ret);
                }
Then it gives me an error -22
Doing a get of the FWI_MAX says its set to 4.
Is there a way to get the library to tell the reader that I want to increase the waiting timeout for a specific received command?
thanks
Parents Reply Children
  • Ok, I see that this option essentially calls my code in the IRQ context directly using platform_internal_irq.c - not surprising it ends up in an assert().

    By creating a 'test' callback function which is IRQ safe, and just makes a fixed response to the DATA_IND event using nfc_t4t_response_pdu_send() , the reader operates as expected.

    However, if there is any delay (more than a couple of ms) in generating the response (eg I use the system queue to schedule the response outside of the callback) then the reader does not manage to see the response correctly.

    I think this demonstrates that the problem is not in the platform.c or platform_internal.c code but in the library (as already hinted at in your previous responses).

    My callback code for the build case with CONFIG_NFC_THREAD_CALLBACK=n:

    static uint8_t _nok_resp[] = { 0x6a, 0x82};
    static void _apdu_cmd_test_resp(void* p_ctx) {
        struct _nfc_ctx* ctx = (struct _nfc_ctx*)p_ctx;
        if (ctx==NULL) {
            return;
        }
        int ret;
        if ((ret=nfc_t4t_response_pdu_send(_nok_resp, sizeof(_nok_resp)))!=0) {
            log_warn("nfcmgr: t4t apdu test resp NOT sent after %dms error (%d)", (gettime_ms()-ctx->lastRead), ret);
        } else {
            log_warn("nfcmgr:t4t apdu test resp sent after %dms", (gettime_ms()-ctx->lastRead));
        }
    }

    static void _apdu_cmd_test_print(void* p_ctx) {
        log_warn("nfcmgr: test event %d", (int32_t)p_ctx);
    }

    // ADPU type operation test callback, called directly on IRQ, just always responds with 'no'
    static void _nfc_t4t_test_cb_from_irq(void *context, nfc_t4t_event_t event, const uint8_t *data, size_t data_length, uint32_t flags) {
        struct _nfc_ctx* ctx = (struct _nfc_ctx*)context;
        if (ctx==NULL) {
            return;
        }
        switch(event) {        
            case NFC_T4T_EVENT_FIELD_ON: {
                ctx->nfc_active = true;
                wsched_request(_apdu_cmd_test_print, (void*)NFC_T4T_EVENT_FIELD_ON);
                break;
            }
            case NFC_T4T_EVENT_FIELD_OFF: {
                ///< External Reader polling stopped
                ctx->nfc_active = false;
                wsched_request(_apdu_cmd_test_print, (void*)NFC_T4T_EVENT_FIELD_OFF);
                break;
            }
            case NFC_T4T_EVENT_DATA_IND: {
                ctx->lastRead = gettime_ms();
                int ret=nfc_t4t_response_pdu_send(_nok_resp, sizeof(_nok_resp));
                wsched_request(_apdu_cmd_test_print, (void*)ret);
    //            wsched_request(_apdu_cmd_test_print, (void*)NFC_T4T_EVENT_DATA_IND);
                // will generate a response
    //            wsched_request(_apdu_cmd_test_resp, ctx);
                break;
            }
            case NFC_T4T_EVENT_DATA_TRANSMITTED: {
                // just to log
                wsched_request(_apdu_cmd_test_print, (void*)NFC_T4T_EVENT_DATA_TRANSMITTED);
                break;
            }
            default: {
                wsched_request(_apdu_cmd_test_print, (void*)event);
                break;
            }
        }
    }
    Note if the case for DATA_IND uses the  system work queue to schedule the  function _apdu_cmd_test_resp()  then the problem occurs, if it directly does pdu_send() then it does not.
  • any word back on this?

    I have rewritten my code to process the callback from the IRQ directly (CONFIG_NFC_THREAD_CALLBACK=n) instead of using platform_internal_thread.c and always get the same result (works if response sent immediately, bad NFC if takes > 3-4ms).

  • Hi, I'd really like to make some progress on this as its blocking my POCs for digital wallet solutions (access control, authentication etc) using the NFC channel.

    Any ideas on the way to move forward?

  • Hi,

    I am sorry for little feedback from our end. We are looking into a couple of alternatives, but unfortunately no conclusions yet.

    Regards,
    Terje

  • Hi

    Any progress? I'm worried this is going to turn out to be a hardware issue and need to know before we commit to mass production....

Related