T4T tag callback blocks

Hello,

I am trying to develop an application where I can turn on/off the NFC T4T tag emulation using interrupt-driven buttons.

However, after the first read of the NFC tag, only NFC callback events can be run, while blocking any other code to run(Including button interrupts, and logging).

I couldn't solve the issue by myself, and I would appreciate it if you can help.

I attached my code below.

/*
 * Copyright (c) 2018 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
 */

#include <zephyr/kernel.h>
#include <zephyr/sys/reboot.h>

#include <nfc_t4t_lib.h>
#include <nfc/t4t/ndef_file.h>
#include <nfc/ndef/msg.h>
#include <nfc/ndef/text_rec.h>

#include <dk_buttons_and_leds.h>

#define MAX_REC_COUNT		1
#define NDEF_MSG_BUF_SIZE	128

#define NFC_FIELD_LED		DK_LED1
#define NFC_SW_BUTTON 		DK_BTN1_MSK

int nfc_state;

/* Text message in English with its language code. */
static const uint8_t en_payload[] = {
	'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!'
};
static const uint8_t en_code[] = {'e', 'n'};

/* Buffer used to hold an NFC NDEF message. */
static uint8_t ndef_msg_buf[NDEF_MSG_BUF_SIZE];


static void nfc_callback(void *context,
			 nfc_t4t_event_t event,
			 const uint8_t *data,
			 size_t data_length)
{
	ARG_UNUSED(context);
	ARG_UNUSED(data);
	ARG_UNUSED(data_length);

	switch (event) {
	case NFC_T4T_EVENT_FIELD_ON:
		dk_set_led_on(NFC_FIELD_LED);
		break;
	case NFC_T4T_EVENT_FIELD_OFF:
		dk_set_led_off(NFC_FIELD_LED);
		break;
	default:
		break;
	}
}


/**
 * @brief Function for encoding the NDEF text message.
 */
static int welcome_msg_encode(uint8_t *buffer, uint32_t *len)
{
	int err;

	/* Create NFC NDEF text record description in English */
	NFC_NDEF_TEXT_RECORD_DESC_DEF(nfc_en_text_rec,
				      UTF_8,
				      en_code,
				      sizeof(en_code),
				      en_payload,
				      sizeof(en_payload));

	/* Create NFC NDEF message description, capacity - MAX_REC_COUNT
	 * records
	 */
	NFC_NDEF_MSG_DEF(nfc_text_msg, MAX_REC_COUNT);

	/* Add text records to NDEF text message */
	err = nfc_ndef_msg_record_add(&NFC_NDEF_MSG(nfc_text_msg),
				   &NFC_NDEF_TEXT_RECORD_DESC(nfc_en_text_rec));
	if (err < 0) {
		printk("Cannot add first record!\n");
		return err;
	}
	
	err = nfc_ndef_msg_encode(&NFC_NDEF_MSG(nfc_text_msg),
				      buffer,
				      len);
	if (err < 0) {
		printk("Cannot encode message!\n");
	}

	return err;
}

static void button_changed(uint32_t button_state, uint32_t has_changed)
{
	int err;
	if (has_changed & NFC_SW_BUTTON) {
		uint32_t user_button_state = button_state & NFC_SW_BUTTON;

		if (user_button_state == 1) {
			if (nfc_state == 1) {
				err = nfc_t4t_emulation_stop();
				if (err) {
					printk("Cannot stop emulation\n");
				} else {
					printk("Emulation stopped\n");
					nfc_state = 0;
				}
			} else {
				err = nfc_t4t_emulation_start();
				if (err) {
					printk("Cannot start emulation\n");
				} else {
					printk("Emulation started\n");
					nfc_state = 1;
				}
			}
		}
	}
}

int main(void)
{
	uint32_t len = nfc_t4t_ndef_file_msg_size_get(sizeof(ndef_msg_buf));

	printk("Starting NFC Text Record example\n");

	/* Configure LED-pins as outputs */
	if (dk_leds_init() < 0) {
		printk("Cannot init LEDs!\n");
		goto fail;
	}

	if (dk_buttons_init(button_changed) < 0) {
		printk("Cannot init buttons!\n");
		goto fail;
	}


	/* Set up NFC */
	if (nfc_t4t_setup(nfc_callback, NULL) < 0) {
		printk("Cannot setup NFC T2T library!\n");
		goto fail;
	}


	/* Encode welcome message */
	if (welcome_msg_encode(nfc_t4t_ndef_file_msg_get(ndef_msg_buf), &len) < 0) {
		printk("Cannot encode message!\n");
		goto fail;
	}

	nfc_t4t_ndef_file_encode(ndef_msg_buf, &len);

	/* Set created message as the NFC payload */
	if (nfc_t4t_ndef_rwpayload_set(ndef_msg_buf, sizeof(ndef_msg_buf)) < 0) {
		printk("Cannot set payload!\n");
		goto fail;
	}


	/* Start sensing NFC field */
	if (nfc_t4t_emulation_start() < 0) {
		printk("Cannot start emulation!\n");
		goto fail;
	}
	nfc_state = 1;

	printk("NFC configuration done\n");

	return 0;

fail:
#if CONFIG_REBOOT
	sys_reboot(SYS_REBOOT_COLD);
#endif /* CONFIG_REBOOT */

	return -EIO;
}

  • Hi, 

    Thank you for the clarification.

    If the issue is the event timings, do you think it is possible to tune NFC T4T parameters to make it work correctly for both Android and iOS polling devices?

    If yes, where can I find exhaustive information about those parameters and their values?

    Best regards,

    Zhama

  • I believe the queue is in platform_internal_thread.c somewhere. I see that depending on whether CONFIG_NFC_SWI_NUMBER is set or not, it will either set up a software interrupt, or call the cb_work handler directly. My guess is that the SWI interrupt are happening too close to one another, so that one event is lost somhow, while using the scheduler, and cb_work, it has SW to handle these kind of errors, such as a timeout or something.

    BR,

    Edvin

Related