NFC library code for type 4 NDEF card emulation : cannot disable nfc after enabling, or redo setup to change to (say) type 2 or ADPU handling config without ASSERT()

Smartbadge epaper custom board using nrf5340/nrf7002, with an NFC loop to allow NFC card emulation/communication. Building using NCS2.9 with sysbuild.

I want to be able to dynamically change my NFC card emulation under user control, between 

-off (no emulation response)

- type 2 card with NDEF

 - type 4 card with NDEF

- type 4 ISODEP APDU cmd/response

Looking at the NFC samples I created code that looks like this:

bool nfcmgr_enable(nfc_ref_t inst, nfc_card_type_t ctype, nfc_cb_t cb_fn, void* cb_ctx) {
    if (inst==NULL) {
        return false;
    }
    struct _nfc_ctx* ctx = (struct _nfc_ctx*)inst;
    ctx->cb_fn = cb_fn;
    ctx->cb_ctx = cb_ctx;
    ctx->ctype = ctype;
    //uint8_t selres = 0x00;      // TBD do we need to play with SEL_RES (aka SAK)?
    //nfc_t4t_parameter_set(NFC_T4T_PARAM_SELRES, &selres, 1);
    switch (ctype) {
        case NFC_TYPE4_APDU: {
            // register with nfc_t4t
            if (ctx->setupdone==false) {
                int ret = nfc_t4t_setup(_nfc_t4t_apdu_cb, &_ctx);
                if (ret!=0) {
                    log_warn("nfcmgr : could not setup nfc_t4t library for APDU operation, error %d", ret);
                    return false;
                }
            }
            nfc_t4t_emulation_start();
            ctx->enabled = true;
            break;
        }
        case NFC_TYPE2_NDEF: {
            // else type 2 also possible as a simple data storage tag only (no ISODEP)
            // register with nfc_t4t
#ifdef CONFIG_NFC_T2T_NRFXLIB
            if (ctx->setupdone==false) {
                int ret = nfc_t2t_setup(_nfc_t2t_cb, &_ctx);
                if (ret==0) {
                    log_warn("nfcmgr : could not setup nfc_t2t library for basic NDEF card, error %d", ret);
                    return false;
                }
            }
            ctx->setupdone = true;
            nfc_t2t_payload_raw_set(ctx->ndef_buff, MAXLEN_NDEF); //ctx->ndef_sz);
            nfc_t2t_emulation_start();
            ctx->enabled = true;
#else  /* CONFIG_NFC_T2T_NRFXLIB*/
            log_warn("nfcmgr : nfc_t2t library not enabled");        
#endif  /* CONFIG_NFC_T2T_NRFXLIB*/
            break;
        }
        case NFC_TYPE4_NDEF: {
            // register with nfc_t4t
            if (ctx->setupdone==false) {
                int ret = nfc_t4t_setup(_nfc_t4t_ndef_cb, &_ctx);
                if (ret!=0) {
                    log_warn("nfcmgr : could not setup nfc_t4t library for basic NDEF card, error %d", ret);
                    return false;
                }
            }
            ctx->setupdone = true;
            nfc_t4t_ndef_rwpayload_set(ctx->ndef_buff, MAXLEN_NDEF); //ctx->ndef_sz);
            nfc_t4t_emulation_start();
            ctx->enabled = true;
            break;
        }
        default: {
            log_warn("nfcmgr : could not setup unknown mode %d", ctx->ctype);
            return false;
        }
    }
    return true;
}

void nfcmgr_disable(nfc_ref_t inst) {
    if (inst==NULL) {
        return;
    }
    struct _nfc_ctx* ctx = (struct _nfc_ctx*)inst;
    ctx->cb_fn = NULL;
    ctx->cb_ctx = NULL;
    log_warn("nfcmgr : nfc disable disabled as crashes...");
#ifdef CRASH
    if (ctx->enabled) {
        switch (ctx->ctype) {
            case NFC_TYPE4_NDEF: {
                nfc_t4t_emulation_stop();
                nfc_t4t_done();     // release NFC periph
                break;
            }
            case NFC_TYPE4_APDU: {
                nfc_t4t_emulation_stop();
                nfc_t4t_done();     // release NFC periph
                break;
            }
            case NFC_TYPE2_NDEF: {
#ifdef CONFIG_NFC_T2T_NRFXLIB
                nfc_t2t_emulation_stop();
                nfc_t2t_done();     // release NFC periph
#endif  /* CONFIG_NFC_T2T_NRFXLIB*/
                break;
            }
            default: {
                log_warn("nfcmgr : could not disable unknown mode %d", ctx->ctype);
                break;
            }
        }
    }
#endif
    ctx->enabled = false;
}

It works to enable the NFC operation the first time eg for type 4 using the ndef library to do the HL exchanges.

I am experiencing a problem to disable the nfc emulation, as when I call nfc_t4t_emulation_stop() it fails the assert 

    NRFX_ASSERT(m_nfct_cb.state == NRFX_DRV_STATE_INITIALIZED);
in nrfc_nfct_disable(void) in modules/hal/nordic/nrfx/drivers/src/nrfx_nfct.c
This is called from nfc_t4t_emulation_stop() via the RPC mechanism (not sure why the code uses this by the way?)
Given the emulation was working, I don't see why the state is now not initialized?
Ay ideas on how to use the nfc driver/libraries in this way? For the moment as you can see I have just ifdef'd out the code, but it means I cannot change the NFC mode on the fly or disable it once its enabled....
thanks
  • Hi

    Do you by chance call nfc_t4t_emulation_stop() after nfc_t4t_done()? Since nfc_t4t_done() calls nrfx_nfct_uninit() and that might be why the emulation_stop() calls. Which nfc_t4t_emulation_stop() call is it that returns this assert?

    Best regards,

    Simon

  • Do you by chance call nfc_t4t_emulation_stop() after nfc_t4t_done()? Since nfc_t4t_done() calls nrfx_nfct_uninit() and that might be why the emulation_stop() calls. Which nfc_t4t_emulation_stop() call is it that returns this assert?

    As per the posted code, in nfc_disable:

    nfc_t4t_emulation_stop();
    nfc_t4t_done(); // release NFC periph

    Its the first call to emulation_stop() that breaks it...

  • Okay, so you can confirm that there are no calls to nfc_t4t_done() before the emulation_stop() function on your end?

    Then you can try the following. There was an issue that has not yet been added to the upstream SDK it seems where the T2T and T4T libraries weren't designed to co-exist, so you need to reset the register explicitly to set up NFC for both tag types correctly. Call this after nfc_t2t_setup() and see if that helps:

    /* Reset the SELRES Protocol field for the T2T platform */
    
    NRF_NFCT->SELRES = NRF_NFCT->SELRES & ~NFCT_SELRES_PROTOCOL_Msk;

    It might not be relevant to the issue we're seeing here, but I think you need to do it down the line.

    Best regards,

    Simon

  • Well, for my test I did not enable t2t at all, just switched t4t on and off...

    I think I have found the issue: I had previously had a error return when calling 

                    int ret = nfc_t4t_setup(_nfc_t4t_ndef_cb, &_ctx);
    a second time (in my test of nfc on/nfc off / nfc on / nfc off...)
    I therefore added a flag to only do the setup first time. Then, my test did: 

    1/ Boot

    2/ Nfc on 

                                       nfc_t4t_setup(_nfc_t4t_ndef_cb, &_ctx);
                    nfc_t4t_ndef_rwpayload_set(ctx->ndef_buff, MAXLEN_NDEF); 
                    nfc_t4t_emulation_start();
    ->OK

    NFC off:

                    nfc_t4t_emulation_stop();
                    nfc_t4t_done();     // release NFC periph
    ->OK 

    NFC on (note: the code has a flag which means it doesnt try to nfc_t4t_setup more than once, so no setup this time)

                    nfc_t4t_ndef_rwpayload_set(ctx->ndef_buff, MAXLEN_NDEF); //ctx->ndef_sz);
                    nfc_t4t_emulation_start();
    ->OK

    NFC off

                    nfc_t4t_emulation_stop();
    -> ASSERT in modules/hal/nordic/nrfx/drivers/src/nrfx_nfct.c
    void nrfx_nfct_disable(void)
    {
        NRFX_ASSERT(m_nfct_cb.state == NRFX_DRV_STATE_INITIALIZED);

        nrfy_nfct_int_disable(NRF_NFCT, NRF_NFCT_DISABLE_ALL_INT);
        nrfy_nfct_task_trigger(NRF_NFCT, NRF_NFCT_TASK_DISABLE);

        NRFX_LOG_INFO("Stop");
    }
    debugger shows m_nfct_cb.state is in fact NRFX_DRV_STATE_UNINITIALIZED.
    It appears this state is set to NRFX_DRV_STATE_INITIALIZED in nrfx_nfct_init() and back to NRFX_DRV_STATE_UNINITIALIZED in nrfx_nfct_uninit().... The call method makes it difficult to work out which nfc_t4t_XXX function actually calls the nrfx_nfct_YYY functions....
    I removed the 'only do setup once' flag, and retried: and this time it works -> no assert. So, I guess nfc_t4t_setup() is what calls the nrfx_nfct_init()....
    And the previous error returned from the setup call was because my code would call the enable() twice (with no disable()) due to a bug : as long as I do the stop before redoing the setup/start, it seems to be ok!
    So:
    Start sequence is
       nfc_t4t_setup(_nfc_t4t_ndef_cb, &_ctx);
       // set ndef payload if want NDEF procedures, don't if want to manage raw APDUs ourselves
       nfc_t4t_ndef_rwpayload_set(ctx->ndef_buff, MAXLEN_NDEF); 
       nfc_t4t_emulation_start();
     
    Stop sequence:
       nfc_t4t_emulation_stop();
       nfc_t4t_done();     
     
    I have added the fix you indicate for the case when I want to do type 2 cards as well, thanks.
  • Hi

    Glad to hear you figured it out Brian. Are there any follow-ups or should we close this case then?

    Best regards,

    Simon

Related