Transmit and receive not working together with ESB protocol

Hi,

We have modified the PTX "main.c" and "esb.c" file for NRF5840 to transmit and receive data packets with our Patient monitor.

The packets are transmitted at 992HZ and received at 4HZ. We have modified the "cmsis_timer.c" file to create a microsecond timer.

The payload for transmit is 21bytes and for receive is 9bytes respectively.

We enable the receive initially and we have setup a timer for 992Hz timing. Inside the timer callback function we stop the receive, start the transmit and then start the receive functions respectively.

With this arrangement, we have observed a strange behaviour that the transmit and receive both work together only when we add a print statement as mentioned below.

printk("\n  \n");
We have observed that, without this above print statement inside the timer callback function, the transmit does not work and only receive works fine.
We would want to get transmit and receive working together without this print statement.
I have attached the source code files which we have modified. Please let us know how to resolve this issue.
/*
 * Copyright (c) 2018 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
 */
#include <zephyr/drivers/clock_control.h>
#include <zephyr/drivers/clock_control/nrf_clock_control.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/irq.h>
#include <zephyr/logging/log.h>
#include <nrf.h>
#include <esb.h>
#include <zephyr/device.h>
#include <zephyr/devicetree.h>
#include <zephyr/kernel.h>
#include <zephyr/types.h>
#include <zephyr/zephyr.h>
#include <cmsis_os.h>
#include <sys/printk.h>
// #include <sys/unistd.h>
// #include <zephyr/posix/unistd.h>

/* specify delay between greetings (in us); compute equivalent in ticks */
// #define TIMER_TICKS  1008
#define TIMER_TICKS 978
#define DELAY_TIMER_TICKS 250
#define TIMER_SEC_TICKS  1000000
#define ECG_FW_CH_LENTYPE 0x5A // 5A for MR400. 59 for Expression
#define ECG_FW_CH_PREAMBLE 0xAA
#define TOT_CMD_DATA_BYTES 4
#define TOT_SPARE_BYTES 3
#define TOT_ADDRESS_BYTES 4
#define TOT_ECG_DATA_BYTES 18
#define TOT_FWC_BYTES 26

#define NELEMS(x) (sizeof(x) / sizeof((x)[0]))

extern int dbg_events[];
extern int dbg_events_idx;
extern bool end_event;
extern bool tx_start_event;
void timer_callback(void const *arg);
void delay_function(void);
void delay_timer_callback(void const *arg);
osTimerDef(myTimer, timer_callback);
osTimerDef(myTimer_delay, delay_timer_callback);

//One second timer for debug print of total messages transmitted and received over past second
void sec_timer_callback(void const *arg);
osTimerDef(my_sec_timer, sec_timer_callback);

//Back channel message received for channel selection (commands 0x04 and 0x05)
unsigned char channel1_filter = 0x03;
unsigned char channel2_filter = 0x03;
int filter_recvd;

//Functions to set LED's 3 and 4 to visually indicate filter selection
int channel1_filter_led_set(void);
int channel2_filter_led_set(void);
void decimalToBinary(int num, int *val1, int *val2);

//Initialize ECG Packet for Forward Channel Transmission at 992 Hz
void initFwdChData(void);

//Channel 4 setting for Primary frequency of 2.440 GHz and Secondary frequency of 2.448 GHz
typedef enum hop_frequency
{
	primary_hop = 40,
	secondary_hop = 48
} hop_values;

int frequency_hop;
int network;
int networkGroup;
unsigned int networkAddress;
int counter;
bool packet_tx_done = true;
bool packet_ready = true;
bool delay_timer_flag = false;

//Counters for numer of TX messages and RX messages since last reset (1 second)
int				second_rx_cnt=0;
int				second_tx_cnt=0;

//ECG data sample variables for 2 Leads and 3 time slices (T0, T1, T2)
short int ch1DataA;
short int ch1DataB;
short int ch1DataC;
short int ch2DataA;
short int ch2DataB;
short int ch2DataC;

int rawLeadDataCh1;
int rawLeadDataCh2;
int led_count;

int led_value = 0;
osTimerId delay_timer_id;
bool tx_delay_done = false;
bool			print_metrics = false;

//ECG Waveform Simulation Array from MR400 divided by 10
static const short ECG_DAT[] = {
	-34, -32, -23, -23, -18, -18, -18, -12, -15, -20,
	-11, -18, -29, -32, -34, -29, -25, -28, -32, -19,
	-15, -6, -13, -16, -21, -21, -20, -14, -25, -28,
	-38, -36, -30, -28, -37, -25, -20, -13, -11, -9,
	-14, -18, -13, -17, -27, -28, -35, -39, -35, -31,
	-33, -36, -32, -25, -13, -17, -20, -13, -14, -15,
	-24, -25, -30, -29, -41, -35, -32, -39, -25, -19,
	-20, -16, -14, -18, -10, -7, -14, -15, -31, -27,
	-33, -29, -35, -23, -24, -19, -9, -8, -10, -12,
	-5, -7, -10, -9, -24, -31, -32, -33, -40, -36, // 100
	-29, -26, -17, -17, -11, -8, -12, -5, -3, -11,
	-13, -19, -29, -35, -32, -26, -26, -25, -18, -19,
	-15, -5, -6, -12, -14, -18, -18, -23, -32, -35,
	-25, -32, -28, -33, -27, -17, -14, -7, -14, -5,
	-10, -8, -18, -10, -18, -31, -27, -37, -31, -30,
	-28, -19, -6, -1, -1, -1, 6, 3, 10, 8,
	12, 1, 9, 6, 10, 14, 23, 18, 31, 36,
	46, 52, 49, 56, 56, 56, 50, 52, 49, 39,
	40, 46, 48, 51, 51, 55, 63, 65, 66, 73,
	69, 73, 68, 58, 57, 50, 46, 50, 43, 42, // 200
	52, 55, 50, 61, 57, 54, 60, 47, 45, 37,
	36, 19, 19, 20, 13, 16, 9, 11, 18, 16,
	20, 22, 17, 13, 4, -2, -14, -18, -26, -32,
	-29, -36, -25, -27, -22, -13, -12, -14, -15, -8,
	-9, -12, -10, -13, -32, -33, -33, -28, -25, -31,
	-28, -20, -19, -14, -10, -14, -6, -4, -13, -14,
	-20, -31, -37, -34, -28, -28, -28, -20, -21, -18,
	-19, -19, -12, -15, -8, -9, -27, -35, -38, -27,
	-34, -30, -34, -28, -17, -15, -7, -15, -6, -12,
	-10, -8, -13, -21, -22, -30, -28, -34, -32, -29, // 300
	-19, -18, -12, -12, -12, -17, -9, -15, -18, -25,
	-36, -29, -32, -39, -34, -37, -41, -39, -34, -35,
	-41, -43, -49, -49, -61, -68, -79, -82, -81, -81,
	-53, -41, -28, 6, 32, 62, 99, 123, 154, 187,
	217, 249, 277, 301, 331, 363, 391, 431, 452, 484,
	522, 540, 563, 572, 571, 557, 548, 539, 511, 490,
	452, 417, 382, 350, 313, 279, 240, 218, 176, 153,
	117, 88, 60, 28, 0, -34, -60, -79, -85, -96,
	-106, -110, -116, -103, -98, -99, -91, -80, -73, -72,
	-59, -54, -54, -46, -45, -45, -40, -38, -45, -43, // 400
	-36, -37, -32, -29, -34, -38, -34, -29, -30, -47,
	-44, -50, -47, -42, -43, -43, -37, -38, -35, -24,
	-37, -30, -32, -24, -24, -41, -49, -51, -41, -48,
	-44, -48, -43, -33, -31, -24, -31, -23, -28, -26,
	-23, -27, -35, -36, -44, -41, -36, -35, -45, -35,
	-21, -28, -15, -27, -20, -23, -17, -20, -28, -27,
	-32, -35, -30, -38, -28, -32, -31, -25, -15, -9,
	-12, -6, -7, -7, -15, -25, -28, -25, -24, -30,
	-15, -23, -23, -6, 2, 4, 5, -1, 7, 0,
	-5, -3, -17, -11, -15, -11, -18, -7, -10, -6, // 500
	1, 13, 8, 6, 13, 11, 9, 12, -1, -6,
	-5, -5, -11, -8, -2, 0, 7, 17, 20, 22,
	17, 25, 16, 21, 9, 5, 9, 3, 7, 12,
	0, 11, 17, 26, 28, 25, 35, 30, 40, 36,
	37, 21, 26, 25, 24, 17, 22, 17, 22, 31,
	44, 37, 41, 48, 42, 43, 46, 43, 36, 37,
	30, 33, 39, 41, 42, 51, 51, 56, 67, 65,
	71, 67, 74, 71, 65, 55, 52, 62, 56, 61,
	70, 64, 76, 79, 87, 92, 88, 94, 93, 94,
	88, 79, 78, 69, 72, 78, 80, 83, 82, 85, // 600
	91, 92, 104, 97, 93, 98, 82, 74, 74, 68,
	65, 70, 63, 61, 69, 71, 77, 75, 81, 77,
	71, 71, 70, 62, 51, 48, 37, 39, 44, 35,
	39, 39, 44, 41, 44, 34, 29, 25, 29, 12,
	13, -2, -10, -15, -23, -30, -19, -22, -29, -21,
	-21, -12, -15, -21, -22, -24, -33, -35, -53, -52,
	-52, -59, -55, -50, -48, -41, -42, -37, -34, -39,
	-31, -29, -36, -37, -53, -50, -55, -52, -58, -46,
	-47, -41, -43, -28, -31, -32, -37, -39, -30, -42,
	-45, -53, -55, -56, -51, -48, -53, -48, -51, -49, // 700
	-41, -49, -40, -45, -31, -41, -45, -52, -52, -49,
	-58, -53, -51, -49, -40, -39, -33, -33, -32, -25,
	-29, -22, -25, -33, -43, -48, -50, -45, -52, -43,
	-36, -35, -31, -22, -28, -19, -24, -24, -24, -30,
	-40, -42, -51, -49, -43, -53, -49, -50, -34, -39,
	-25, -25, -31, -23, -30, -34, -43, -43, -49, -52,
	-48, -43, -44, -48, -45, -26, -28, -21, -24, -29,
	-30, -31, -27, -39, -43, -42, -53, -47, -44, -51,
	-37, -32, -34, -31, -29, -22, -27, -23, -29, -29,
	-44, -51, -56, -39, -46, -47, -36, -32, -23, -23, // 800
	-26, -28, -21, -22, -25, -23, -37, -43, -44, -44,
	-50, -47, -40, -38, -30, -31, -25, -22, -27, -19,
	-17, -25, -26, -43, -40, -46, -43, -37, -37, -38,
	-31, -20, -18, -20, -21, -14, -16, -20, -19, -35,
	-43, -45, -46, -41, -37, -43, -38, -41, -27, -20,
	-28, -20, -25, -23, -20, -23, -30, -30, -38, -35,
	-42, -40, -38, -29, -28, -23, -24, -24, -17, -21,
	-15, -17, -24, -35, -39, -40, -47, -41, -44, -36,
	-24, -21, -12, -20, -23, -17, -17, -17, -23, -32,
	-33, -42, -39, -33, -43, -39, -28, -25, -18, -17, // 900
	-17, -23, -15, -22, -26, -23, -35, -41, -43, -38,
	-33, -35, -27, -24, -18, -20, -13, -16, -21, -21,
	-22, -18, -30, -34, -33, -32, -39, -36, -31, -30,
	-24, -15, -11, -9, -14, -18, -14, -20, -19, -34,
	-30, -35, -32, -39, -40, -29, -24, -16, -15, -6,
	-8, -14, -15, -17, -14, -28, -34, -35, -35, -42,
	-39, -33, -31, -23, -24, -19, -16, -20, -12, -9,
	-17, -18, -35, -32, -38, -35, -30, -30, -30, -24,
	-25, -22, -12, -13, -18, -20, -12, -12, -29, -37,
	-39, -28, -32768};

int total_items_ecg_dat = NELEMS(ECG_DAT);

//Structure used to set up Nordic Radio Packet and settings
typedef struct NetTable_t
{
	unsigned int addr;
	char cfgHi;
	char cfgLo1;
	char cfgLo2;
} NetTable;

//Table of Address Bytes, CFGHi, CFGLo1, and CFGLo2 for Channels 1-10
NetTable NetworkTable[] =
	{
		{0xBB44BBB5, 0xAF, 138, 154},
		{0x9B449B95, 0xAF, 72, 88},
		{0xBA44BAB5, 0xAF, 74, 90},
		{0x99449996, 0xAF, 80, 96},
		{0xA944A9A5, 0xAF, 70, 86},
		{0xA6565656, 0xAF, 144, 160},
		{0xC5556666, 0xAF, 110, 126},
		{0xA6669999, 0xAF, 108, 124},
		{0x96969696, 0xAF, 116, 132},
		{0xCCCC5555, 0xAF, 106, 122},
		{0xBBBBBBBB, 0xAF, 4, 20},
		{0x9B9B9B9B, 0xAF, 6, 22},
		{0xBABABABA, 0xAF, 12, 28},
		{0x99999999, 0xAF, 14, 30},
		{0xA9A9A9A9, 0xAF, 36, 52}
	};

// Structure for ECG Forward Channel Packet
typedef struct
{
	//	char 	wPreamble;
	//	char 	wAddress[TOT_ADDRESS_BYTES];
	char wLenType;
	char wECGData[TOT_ECG_DATA_BYTES];
	char wEcgSeqNumber;
	char wEcgStatusData;
} EcgForwardChannelPacket;

static EcgForwardChannelPacket EcgFWCPckt = {
	//		 0x00,
	//	    {0x00,0x00,0x00,0x00},
	0x00,
	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
	0x00,
	0x00};

LOG_MODULE_REGISTER(esb_ptx, CONFIG_ESB_PTX_APP_LOG_LEVEL);
#if 0
static const struct gpio_dt_spec leds[] = {
	GPIO_DT_SPEC_GET(DT_ALIAS(led0), gpios),
	GPIO_DT_SPEC_GET(DT_ALIAS(led1), gpios),
	GPIO_DT_SPEC_GET(DT_ALIAS(led2), gpios),
	GPIO_DT_SPEC_GET(DT_ALIAS(led3), gpios),
};

BUILD_ASSERT(DT_SAME_NODE(DT_GPIO_CTLR(DT_ALIAS(led0), gpios),
			  DT_GPIO_CTLR(DT_ALIAS(led1), gpios)) &&
	     DT_SAME_NODE(DT_GPIO_CTLR(DT_ALIAS(led0), gpios),
			  DT_GPIO_CTLR(DT_ALIAS(led2), gpios)) &&
	     DT_SAME_NODE(DT_GPIO_CTLR(DT_ALIAS(led0), gpios),
			  DT_GPIO_CTLR(DT_ALIAS(led3), gpios)),
	     "All LEDs must be on the same port");
#endif

/* The devicetree node identifier for the "led3" alias. */
#define LED0_NODE DT_ALIAS(led0)
static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios);
#define LED1_NODE DT_ALIAS(led1)
static const struct gpio_dt_spec led_1 = GPIO_DT_SPEC_GET(LED1_NODE, gpios);
#define LED2_NODE DT_ALIAS(led2)
static const struct gpio_dt_spec led_3 = GPIO_DT_SPEC_GET(LED2_NODE, gpios);
#define LED3_NODE DT_ALIAS(led3)
static const struct gpio_dt_spec led_4 = GPIO_DT_SPEC_GET(LED3_NODE, gpios);
int led_count;

static bool ready = false;
static struct esb_payload rx_payload;

static struct esb_payload tx_payload = ESB_CREATE_PAYLOAD(0,
														  0x00,
														  0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
														  0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
														  0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
														  0x00,
														  0x00);

#define _RADIO_SHORTS_COMMON                                       \
	(RADIO_SHORTS_READY_START_Msk | RADIO_SHORTS_END_DISABLE_Msk | \
	 RADIO_SHORTS_ADDRESS_RSSISTART_Msk |                          \
	 RADIO_SHORTS_DISABLED_RSSISTOP_Msk)

//Function to Process Nordic Events
void event_handler(struct esb_evt const *event)
{
	ready = true;

	switch (event->evt_id)
	{
	case ESB_EVENT_TX_SUCCESS:
		// LOG_DBG("TX SUCCESS EVENT");
		break;
	case ESB_EVENT_TX_FAILED:
		LOG_DBG("TX FAILED EVENT");
		break;
	case ESB_EVENT_RX_RECEIVED:
		if (esb_read_rx_payload(&rx_payload) == 0)
		{
#if 0
			LOG_DBG("Packet received, len %d, data: "
				"0x%02x, 0x%02x, 0x%02x, 0x%02x, "
				"0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x ",
				rx_payload.length, rx_payload.data[0],
				rx_payload.data[1], rx_payload.data[2],
				rx_payload.data[3], rx_payload.data[4],
				rx_payload.data[5], rx_payload.data[6],
				rx_payload.data[7],rx_payload.data[8]);
#endif
#if 0
				if(rx_payload.data[1] == 0x04)
				{
					printk("Filter data 0x04 : 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x \r\n",rx_payload.data[1], rx_payload.data[2],
				rx_payload.data[3], rx_payload.data[4], rx_payload.data[5]);
					channel1_filter = rx_payload.data[2];
					//filter_recvd = 1;

				}
#endif
			//if ((rx_payload.data[1] == 0x05) && (channel2_filter != rx_payload.data[2]))
			if (rx_payload.data[1] == 0x05)
			{

				printk("Filter data 0x05 : 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x \r\n", rx_payload.data[1], rx_payload.data[2],
					   rx_payload.data[3], rx_payload.data[4], rx_payload.data[5]);
				
				if (channel2_filter != rx_payload.data[2])
				{
					channel2_filter = rx_payload.data[2];
					filter_recvd = 2;
				}
			}
			second_rx_cnt++;	

		}
		break;
	}
}

//Function to start system clocks
int clocks_start(void)
{
	int err;
	int res;
	struct onoff_manager *clk_mgr;
	struct onoff_client clk_cli;

	clk_mgr = z_nrf_clock_control_get_onoff(CLOCK_CONTROL_NRF_SUBSYS_HF);
	if (!clk_mgr)
	{
		LOG_ERR("Unable to get the Clock manager");
		return -ENXIO;
	}

	sys_notify_init_spinwait(&clk_cli.notify);

	err = onoff_request(clk_mgr, &clk_cli);
	if (err < 0)
	{
		LOG_ERR("Clock request failed: %d", err);
		return err;
	}

	do
	{
		err = sys_notify_fetch_result(&clk_cli.notify, &res);
		if (!err && res)
		{
			LOG_ERR("Clock could not be started: %d", res);
			return res;
		}
	} while (err);

	LOG_DBG("HF clock started");
	return 0;
}

//Function to initialize Nordic Radio at Start Up for RX
int esb_initialize(void)
{
	int err;
	 
	//Nordic radio can have 8 Address Bytes.  MR400 implementation uses 4 Address Bytes in base_addr_0
	uint8_t base_addr_0[4] = {0x99, 0x44, 0x99, 0x96};
	uint8_t base_addr_1[4] = {0x00, 0x00, 0x00, 0x00};

	//Nordic address prefix MR400 uses 1 and it is set to LS Byte of Address Bytes
	uint8_t addr_prefix[8] = {0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

	struct esb_config config = ESB_DEFAULT_CONFIG;

	config.protocol = ESB_PROTOCOL_ESB;
	config.retransmit_delay = 600;
	config.bitrate = ESB_BITRATE_1MBPS;
	config.event_handler = event_handler;
	config.mode = ESB_MODE_PRX;
	config.selective_auto_ack = true;
	config.payload_length = 9;

	err = esb_init(&config);

	if (err)
	{
		printk("esb_init failed \r\n");
		return err;
	}

	err = esb_set_base_address_0(base_addr_0);
	if (err)
	{
		return err;
	}

	err = esb_set_base_address_1(base_addr_1);
	if (err)
	{
		return err;
	}

	err = esb_set_prefixes(addr_prefix, ARRAY_SIZE(addr_prefix));
	if (err)
	{
		return err;
	}
	tx_payload.noack = 1;
	rx_payload.noack = 1;

	return 0;
}

//Function to set Nordic Radio in TX mode
int esb_initialize_tx(void)
{
	int err;


	struct esb_config config = ESB_DEFAULT_CONFIG;

	config.protocol = ESB_PROTOCOL_ESB;
	config.retransmit_delay = 600;
	config.bitrate = ESB_BITRATE_1MBPS;
	config.event_handler = event_handler;
	config.mode = ESB_MODE_PTX;
	config.selective_auto_ack = true;
	config.payload_length = 21;

	err = esb_init_tx(&config);

	if (err)
	{
		return err;
	}

	return 0;
}

//Function to set Nordic Radio in RX mode
int esb_initialize_rx(void)
{
	int err;


	struct esb_config config = ESB_DEFAULT_CONFIG;

	config.protocol = ESB_PROTOCOL_ESB;
	config.retransmit_delay = 600;
	config.bitrate = ESB_BITRATE_1MBPS;
	config.event_handler = event_handler;
	config.mode = ESB_MODE_PRX;
	config.selective_auto_ack = true;
	config.payload_length = 9;

	err = esb_init_rx(&config);
	if (err)
	{
		return err;
	}

	return 0;
}

//Function to initialize LED's 1, 3, 4
static int leds_init(void)
{
	int ret = 0;

	if (!device_is_ready(led.port))
	{
		printk(" error device_is_ready \r\n");
		return -ENODEV;
	}

	ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
	if (ret < 0)
	{
		printk(" error gpio_pin_configure_dt \r\n");
		return -2;
	}

	if (!device_is_ready(led_1.port))
	{
		printk(" error device_is_ready \r\n");
		return -ENODEV;
	}

	ret = gpio_pin_configure_dt(&led_1, GPIO_OUTPUT_ACTIVE);
	if (ret < 0)
	{
		printk(" error gpio_pin_configure_dt \r\n");
		return -2;
	}

	if (!device_is_ready(led_3.port))
	{
		printk(" error device_is_ready \r\n");
		return -ENODEV;
	}

	ret = gpio_pin_configure_dt(&led_3, GPIO_OUTPUT_ACTIVE);
	if (ret < 0)
	{
		printk(" error gpio_pin_configure_dt \r\n");
		return -2;
	}

	if (!device_is_ready(led_4.port))
	{
		printk(" error device_is_ready \r\n");
		return -ENODEV;
	}

	ret = gpio_pin_configure_dt(&led_4, GPIO_OUTPUT_ACTIVE);
	if (ret < 0)
	{
		printk(" error gpio_pin_configure_dt \r\n");
		return -2;
	}

	return 0;
}

//Function to initialize the Forward Channel Message.
void initFwdChData(void)
{
	int ret = 0;
	// Each FWC packet consists of 28 bytes (26 data bytes + 2 CRC bytes) which is transmitted at a rate of 992 Hz (1.008065 ms)
	// 1. Header - Preamble (8 Bits) + Address (32 Bits) + Length (4 Bits) + Type (4 Bits)
	// 2. ECG DATA "A" - Data1 (16 bits) + Data2 (16 Bits) + Data3 (16 bits)
	// 3. ECG DATA "B" - Data1 (16 bits) + Data2 (16 Bits) + Data3 (16 bits)
	// 4. ECG DATA "C" - Data1 (16 bits) + Data2 (16 Bits) + Data3 (16 bits)
	// 5. Status Information - Status Code (8 bits) + Status Data (8 bits)
	// 6. CRC - CRC data (16 bits). The CRC bytes are calculated by the Radio firmware block and not calculated here.

	// EcgFWCPckt.wPreamble = ECG_FW_CH_PREAMBLE; // Preamble
	EcgFWCPckt.wLenType = ECG_FW_CH_LENTYPE; // Length/type
	EcgFWCPckt.wEcgSeqNumber = 0x00;
	EcgFWCPckt.wEcgStatusData = 0x00;

	network = 4;
	// Get the Network Address from the network table
	networkAddress = NetworkTable[network - 1].addr;

	// EcgFWCPckt.wAddress[0] = (networkAddress >> 24) & 0xFF;
	// EcgFWCPckt.wAddress[1] = (networkAddress >> 16) & 0xFF;
	// EcgFWCPckt.wAddress[2] = (networkAddress >> 8) & 0xFF;
	// EcgFWCPckt.wAddress[3] = networkAddress & 0xFF;

	ch1DataA = 0;
	ch1DataB = 0;
	ch1DataC = 0;
	ch2DataA = 0;
	ch2DataB = 0;
	ch2DataC = 0;

	// ECG DATA "A"
	// DATA 1
	EcgFWCPckt.wECGData[0] = ch1DataA & 0xFF;
	EcgFWCPckt.wECGData[1] = (ch1DataA & 0xFF00) >> 8;

	// DATA 2
	EcgFWCPckt.wECGData[2] = ch2DataA & 0xFF;
	EcgFWCPckt.wECGData[3] = (ch2DataA & 0xFF00) >> 8;

	// DATA 3
	// The 0x55 value for Data A-3 prevents a long series of 0 bit values
	// in the packet transmission
	EcgFWCPckt.wECGData[4] = 0x55;
	EcgFWCPckt.wECGData[5] = 0x55;

	// ECG DATA "B"
	// DATA 1
	EcgFWCPckt.wECGData[6] = ch1DataB & 0xFF;
	EcgFWCPckt.wECGData[7] = (ch1DataB & 0xFF00) >> 8;

	// DATA 2
	EcgFWCPckt.wECGData[8] = ch2DataB & 0xFF;
	EcgFWCPckt.wECGData[9] = (ch2DataB & 0xFF00) >> 8;

	// DATA 3
	// The 0x55 value for Data B-3 prevents a long series of 0 bit values
	// in the packet transmission
	EcgFWCPckt.wECGData[10] = 0x55;
	EcgFWCPckt.wECGData[11] = 0x55;

	// ECG DATA "C"
	// DATA 1
	EcgFWCPckt.wECGData[12] = ch1DataC & 0xFF;
	EcgFWCPckt.wECGData[13] = (ch1DataC & 0xFF00) >> 8;

	// DATA 2
	EcgFWCPckt.wECGData[14] = ch2DataC & 0xFF;
	EcgFWCPckt.wECGData[15] = (ch2DataC & 0xFF00) >> 8;

	// DATA 3
	// The 0x55 value for Data C-3 prevents a long series of 0 bit values
	// in the packet transmission
	EcgFWCPckt.wECGData[16] = 0x55;
	EcgFWCPckt.wECGData[17] = 0x55;

	// Status Code/ Sequence #
	EcgFWCPckt.wEcgSeqNumber++;
	EcgFWCPckt.wEcgSeqNumber = EcgFWCPckt.wEcgSeqNumber & 0xFF;
	bool packet_tx_done = true;
	bool packet_ready = false;

	channel2_filter = 0x03;
	channel1_filter = 0x03;

	// Set the radio frequency and start rx
	frequency_hop = primary_hop;
	esb_set_rf_channel(frequency_hop);
	esb_start_rx();
	frequency_hop = secondary_hop;

	ret = gpio_pin_set(led_3.port, led_3.pin, 0);
	if (ret)
	{
		LOG_ERR("LED3 set 1 error: %d", ret);
	}
	ret = gpio_pin_set(led_4.port, led_4.pin, 1);
	if (ret)
	{
		LOG_ERR("LED4 set 1 error: %d", ret);
	}
}

void delay_function(void)
{
	delay_timer_flag = true;
	while (delay_timer_flag == false);
}

void delay_timer_callback(void const *arg)
{
	tx_delay_done = true;
}

void sec_timer_callback(void const *arg)
{
	print_metrics = true;
}

void decimalToBinary(int num, int *val1, int *val2) {
	// Stores binary representation of number.
	int binaryNum[3] = {0, 0, 0}; // Assuming 32 bit integer.
	int i = 0;

	for (; num > 0;)
	{
		binaryNum[i++] = num % 2;
		num /= 2;
	}

	*val1 = binaryNum[1];
	*val2 = binaryNum[0];
}

int channel1_filter_led_set(void)
{

	int ret = 0, value_led2 = 0, value_led4 = 0;

	decimalToBinary((channel1_filter - 2), &value_led2, &value_led4);

	ret = gpio_pin_set(led_3.port, led_3.pin, value_led2);
	if (ret)
	{
		LOG_ERR("LED3 set 1 error: %d", ret);
	}

	ret = gpio_pin_set(led_4.port, led_4.pin, value_led4);
	if (ret)
	{
		LOG_ERR("LED4 set 1 error: %d", ret);
	}
}

int channel2_filter_led_set(void)
{

	int ret = 0, value_led2 = 0, value_led4 = 0;
	decimalToBinary((channel2_filter - 2), &value_led2, &value_led4);

	ret = gpio_pin_set(led_3.port, led_3.pin, value_led2);
	if (ret)
	{
		LOG_ERR("LED3 set 1 error: %d", ret);
	}

	ret = gpio_pin_set(led_4.port, led_4.pin, value_led4);
	if (ret)
	{
		LOG_ERR("LED4 set 1 error: %d", ret);
	}
	filter_recvd = 0;
}

void timer_callback(void const *arg)
{

	int ret = 0, err = 0;

	//*************** Tasks to do here ****************
	//	1. In init(), set radio for RX
	//	2. Set radio Frequency Register with frequency variable
	//	3. Set Radio for TX (TX_EN) (There may be a sequence required and a wait for READY event)
	//*************************************************

	if ((packet_ready == true) && (packet_tx_done == false))
	{
		esb_stop_rx();

		// delay_function();
		esb_set_rf_channel(frequency_hop);

		esb_initialize_tx();

		// delay_function();

		esb_flush_tx();


		err = esb_write_payload(&tx_payload);
		if (err)
		{
			LOG_ERR("Payload write failed, err %d", err);
		}

		second_tx_cnt++;

		esb_flush_tx();
		// delay_function();
		// turn off/on led
		// usleep(10);
		// k_sleep(K_USEC(10));
		// printk("\r\n Inside timer handler, after write payload \r\n");
		printk("\n  \n");
		//if (esb_is_idle() != true)
		//{
		//	printk("ESB not idle \r\n");
		//}
		//printk("\r     \r");
		//printk("\r\r\r\r\r\r\r\r\r\r\n");
		packet_tx_done = true;
		//printk("BEfore while \r\n");
		//while((tx_start_event == true)&&(end_event == false))
		//{
			
			
		//}
		//printk("tx complete\r\n");
		//tx_start_event = false;
		//end_event = false;
		//esb_stop_tx();

#if 0
	led_value = !led_value;
	printk("led_value : %d \r\n",led_value);
	ret = gpio_pin_set(&led_1.port, led_1.pin, led_value);
	if (ret) {
		LOG_ERR("LED1 set 0 error: %d", ret);
	}

#endif
		ret = gpio_pin_toggle_dt(&led_1);
		if (ret < 0)
		{
			return;
		}

		esb_set_rf_channel(primary_hop);
		esb_initialize_rx();
		// delay_function();
		esb_start_rx();

	}
	//**************** After TX Success ***************
	//	4. Set Radio for RX (RX_EN) (There may be  a sequence required and a wait for READY event)
	//*************************************************
}

void main(void)
{
	int err, i = 0, ret = 0;

	osTimerId timer_id;
	osTimerId timer_sec_id;

	LOG_INF("Enhanced ShockBurst ptx sample");
	printk(" \r\n ** total_items_ecg_dat: %d **\r\n", total_items_ecg_dat);

	err = clocks_start();
	if (err)
	{
		return;
	}

	err = leds_init();
	if (err)
	{
		return;
	}

	err = esb_initialize();
	if (err)
	{
		LOG_ERR("ESB initialization failed, err %d", err);
		return;
	}

	initFwdChData();

	LOG_INF("Initialization complete");
	LOG_INF("Sending test packet");
	delay_timer_id = osTimerCreate_US(osTimer(myTimer_delay), osTimerOnce, NULL);
	timer_id = osTimerCreate_US(osTimer(myTimer), osTimerPeriodic, NULL);
	osTimerStart_US(timer_id, TIMER_TICKS);

	timer_sec_id = osTimerCreate_US(osTimer(my_sec_timer), osTimerPeriodic, NULL);
	osTimerStart_US(timer_sec_id, TIMER_SEC_TICKS);
	while (1)
	{
		if (packet_tx_done == true)
		{
			packet_ready == false;
			//********************* Tasks to do *************
			//	1. Set a frequency variable to Primary or Secondary frequency for next transmission based on hopping pattern/network
			//************************************************

			if (frequency_hop == primary_hop)
			{
				frequency_hop = secondary_hop;
			}
			else if (frequency_hop == secondary_hop)
			{
				frequency_hop = primary_hop;
			}
			else
			{
				frequency_hop = primary_hop;
			}

			// At Max QRS value, set LED 4 ON
			if (ECG_DAT[counter] == -572)
			{
				// turn on led
				ret = gpio_pin_set(&led, led.pin, 1);
				if (ret)
				{
					LOG_ERR("LED3 set 1 error: %d", ret);
				}
				led_count = 1;
			}

			// Move T-1 Data to T-2 Data and T Data to T-1 Data
			ch1DataC = ch1DataB;
			ch2DataC = ch2DataB;
			ch1DataB = ch1DataA;
			ch2DataB = ch2DataA;

			ch1DataA = ECG_DAT[counter];
			ch2DataA = ECG_DAT[counter];

			// ECG DATA "A"
			// DATA 1
			EcgFWCPckt.wECGData[0] = ch1DataA & 0xFF;
			EcgFWCPckt.wECGData[1] = (ch1DataA & 0xFF00) >> 8;

			// DATA 2
			EcgFWCPckt.wECGData[2] = ch2DataA & 0xFF;
			EcgFWCPckt.wECGData[3] = (ch2DataA & 0xFF00) >> 8;

			// DATA 3
			// The 0x55 value for Data A-3 prevents a long series of 0 bit values
			// in the packet transmission
			EcgFWCPckt.wECGData[4] = 0x55;
			EcgFWCPckt.wECGData[5] = 0x55;

			// ECG DATA "B"
			// DATA 1
			EcgFWCPckt.wECGData[6] = ch1DataB & 0xFF;
			EcgFWCPckt.wECGData[7] = (ch1DataB & 0xFF00) >> 8;

			// DATA 2
			EcgFWCPckt.wECGData[8] = ch2DataB & 0xFF;
			EcgFWCPckt.wECGData[9] = (ch2DataB & 0xFF00) >> 8;

			// DATA 3
			// The 0x55 value for Data B-3 prevents a long series of 0 bit values
			// in the packet transmission
			EcgFWCPckt.wECGData[10] = 0x55;
			EcgFWCPckt.wECGData[11] = 0x55;

			// ECG DATA "C"
			// DATA 1
			EcgFWCPckt.wECGData[12] = ch1DataC & 0xFF;
			EcgFWCPckt.wECGData[13] = (ch1DataC & 0xFF00) >> 8;

			// DATA 2
			EcgFWCPckt.wECGData[14] = ch2DataC & 0xFF;
			EcgFWCPckt.wECGData[15] = (ch2DataC & 0xFF00) >> 8;

			// DATA 3
			// The 0x55 value for Data C-3 prevents a long series of 0 bit values
			// in the packet transmission
			EcgFWCPckt.wECGData[16] = 0x55;
			EcgFWCPckt.wECGData[17] = 0x55;

			// Set sequence number for next packet transmission
			EcgFWCPckt.wEcgSeqNumber++;
			EcgFWCPckt.wEcgSeqNumber = EcgFWCPckt.wEcgSeqNumber & 0xFF;

			//*************** Tasks to do ******************
			//	1. Write EcgFWCPckt.wEcgStatusData = New Structure[EcgFWCPckt.wEcgSeqNumber & 0x3F]
			//**********************************************

			// Copy ECG packet data into transmit payload
			memcpy(tx_payload.data, &EcgFWCPckt, 21);

			// Set counter index for ECG simulated data
			if (counter < total_items_ecg_dat)
			{
				counter = counter + 1;
			}
			else
			{
				counter = 0;
			}

			if (led_count > 0)
			{
				led_count++;
			}
			if (led_count > 250)
			{
				// turn off led
				ret = gpio_pin_set(&led, led.pin, 0);
				if (ret)
				{
					LOG_ERR("LED3 set 0 error: %d", ret);
				}
				led_count = 0;
			}

			esb_flush_tx();

			packet_ready == true;
			packet_tx_done = false;
		}
		else
		{ // packet_tx_done = false

#if 0
			if(filter_recvd == 1)
			{	
				channel1_filter_led_set();
			}
#endif
			if (filter_recvd == 2)
			{
				channel2_filter_led_set();
			}

			if (delay_timer_flag == true)
			{
				osTimerStart_US(delay_timer_id, DELAY_TIMER_TICKS);
				while (tx_delay_done == false);
				tx_delay_done = false;
				osTimerStop(delay_timer_id);
				delay_timer_flag = false;
			}

			if( print_metrics == true )
			{
				printk("second_tx_cnt: %d     second_rx_cnt: %d \r\n", second_tx_cnt, second_rx_cnt);
				second_rx_cnt = 0;
				second_tx_cnt = 0;
				print_metrics = false;
			}
			
			//*************** Tasks to do ***********************
			//	1. Set up a structure of 64 chars to hold status data
			//	2. In init() function initialize structure with current value sent as data.
			//	3. Based on index (SequenceNumber & 0x3F), fill in designated RX data
			//		a. Plan is to fill in Filter setting with data received from MR400
			//		b. Based on Filter Setting, set battery remaining time to designated value
			//	4. Process any received data into Status Data
			//***************************************************
		}
		// k_sleep(K_MSEC(100));
	}
}
/*
 * Copyright (c) 2018 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
 */
#include <errno.h>
#include <zephyr/irq.h>
#include <zephyr/sys/byteorder.h>
#include <nrf.h>
#include <esb.h>
#ifdef DPPI_PRESENT
#include <nrfx_dppi.h>
#else
#include <nrfx_ppi.h>
#endif
#include <helpers/nrfx_gppi.h>
#include <stddef.h>
#include <string.h>
#include <nrf_erratas.h>

/* Constants */

/* 2 Mb RX wait for acknowledgment time-out value.
 * Smallest reliable value: 160.
 */
#define RX_ACK_TIMEOUT_US_2MBPS 160
/* 1 Mb RX wait for acknowledgment time-out value. */
#define RX_ACK_TIMEOUT_US_1MBPS 300
/* 250 Kb RX wait for acknowledgment time-out value. */
#define RX_ACK_TIMEOUT_US_250KBPS 300
/* 1 Mb RX wait for acknowledgment time-out (combined with BLE). */
#define RX_ACK_TIMEOUT_US_1MBPS_BLE 300

/* Minimum retransmit time */
#define RETRANSMIT_DELAY_MIN 435

/* Interrupt flags */
/* Interrupt mask value for TX success. */
#define INT_TX_SUCCESS_MSK 0x01
/* Interrupt mask value for TX failure. */
#define INT_TX_FAILED_MSK 0x02
/* Interrupt mask value for RX_DR. */
#define INT_RX_DATA_RECEIVED_MSK 0x04

/* Mask value to signal updating BASE0 radio address. */
#define ADDR_UPDATE_MASK_BASE0 (1 << 0)
/* Mask value to signal updating BASE1 radio address. */
#define ADDR_UPDATE_MASK_BASE1 (1 << 1)
/* Mask value to signal updating radio prefixes. */
#define ADDR_UPDATE_MASK_PREFIX (1 << 2)

 /* The maximum value for PID. */
#define PID_MAX 3

#define BIT_MASK_UINT_8(x) (0xFF >> (8 - (x)))

#define RADIO_SHORTS_COMMON                                                    \
	(RADIO_SHORTS_READY_START_Msk | RADIO_SHORTS_END_DISABLE_Msk |         \
	 RADIO_SHORTS_ADDRESS_RSSISTART_Msk |                                  \
	 RADIO_SHORTS_DISABLED_RSSISTOP_Msk)

#ifdef CONFIG_ESB_SYS_TIMER0
#define ESB_SYS_TIMER NRF_TIMER0
#define ESB_SYS_TIMER_IRQn TIMER0_IRQn
#endif
#ifdef CONFIG_ESB_SYS_TIMER1
#define ESB_SYS_TIMER NRF_TIMER1
#define ESB_SYS_TIMER_IRQn TIMER1_IRQn
#endif
#ifdef CONFIG_ESB_SYS_TIMER2
#define ESB_SYS_TIMER NRF_TIMER2
#define ESB_SYS_TIMER_IRQn TIMER2_IRQn
#endif
#ifdef CONFIG_ESB_SYS_TIMER3
#define ESB_SYS_TIMER NRF_TIMER3
#define ESB_SYS_TIMER_IRQn TIMER3_IRQn
#endif
#ifdef CONFIG_ESB_SYS_TIMER4
#define ESB_SYS_TIMER NRF_TIMER4
#define ESB_SYS_TIMER_IRQn TIMER4_IRQn
#endif


int dbg_ready_counter;
int dbg_disabled_counter;
int dbg_end_counter;
bool end_event = false;
bool tx_start_event = false;
/* Internal Enhanced ShockBurst module state. */
enum esb_state {
	ESB_STATE_IDLE,		/* Idle. */
	ESB_STATE_PTX_TX,       /* Transmitting without acknowledgment. */
	ESB_STATE_PTX_TX_ACK,   /* Transmitting with acknowledgment. */
	ESB_STATE_PTX_RX_ACK,   /* Transmitting with acknowledgment and
				 * reception of payload with the
				 * acknowledgment response.
				 */
	ESB_STATE_PRX,		/* Receiving packets without ACK. */
	ESB_STATE_PRX_SEND_ACK, /* Transmitting ACK in RX mode. */
};

/* Pipe info PID and CRC and acknowledgment payload. */
struct pipe_info {
	uint16_t crc;	  /* CRC of the last received packet.
			   * Used to detect retransmits.
			   */
	uint8_t pid;	  /* Packet ID of the last received packet
			   * Used to detect retransmits.
			   */
	bool ack_payload; /* State of the transmission of ACK payloads. */
};

/* Structure used by the PRX to organize ACK payloads for multiple pipes. */
struct payload_wrap {
	/* Pointer to the ACK payload. */
	struct esb_payload  *p_payload;
	/* Value used to determine if the current payload pointer is used. */
	bool in_use;
	/* Pointer to the next ACK payload queued on the same pipe. */
	struct payload_wrap *p_next;
};

/* First-in, first-out queue of payloads to be transmitted. */
struct payload_tx_fifo {
	 /* Payload queue */
	struct esb_payload *payload[CONFIG_ESB_TX_FIFO_SIZE];

	uint32_t back;	/* Back of the queue (last in). */
	uint32_t front;	/* Front of queue (first out). */
	uint32_t count;	/* Number of elements in the queue. */
};

/* First-in, first-out queue of received payloads. */
struct payload_rx_fifo {
	 /* Payload queue */
	struct esb_payload *payload[CONFIG_ESB_RX_FIFO_SIZE];

	uint32_t back;	/* Back of the queue (last in). */
	uint32_t front;	/* Front of queue (first out). */
	uint32_t count;	/* Number of elements in the queue. */
};

/* Enhanced ShockBurst address.
 *
 * Enhanced ShockBurst addresses consist of a base address and a prefix
 * that is unique for each pipe. See @ref esb_addressing in the ESB user
 * guide for more information.
 */
struct esb_address {
	uint8_t base_addr_p0[4];	/* Base address for pipe 0, in big endian. */
	uint8_t base_addr_p1[4];   /* Base address for pipe 1-7, in big endian. */
	uint8_t pipe_prefixes[8];	/* Address prefix for  0 to pipe7. */
	uint8_t num_pipes;		/* Number of pipes available. */
	uint8_t addr_length;	/* Length of the address plus the prefix. */
	uint8_t rx_pipes_enabled;	/* Bitfield for enabled pipes. */
	uint8_t rf_channel;        /* Channel to use (between 0 and 100). */
};


static bool esb_initialized;
static struct esb_config esb_cfg;
static volatile enum esb_state esb_state = ESB_STATE_IDLE;

/* Default address configuration for ESB.
 * Roughly equal to the nRF24Lxx defaults, except for the number of pipes,
 * because more pipes are supported.
 */
__ALIGN(4)
/*
static struct esb_address esb_addr = {
	.base_addr_p0 = {0xE7, 0xE7, 0xE7, 0xE7},
	.base_addr_p1 = {0xC2, 0xC2, 0xC2, 0xC2},
	.pipe_prefixes = {0xE7, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8},
	.addr_length = 5,
	.num_pipes = CONFIG_ESB_PIPE_COUNT,
	.rf_channel = 2,
	.rx_pipes_enabled = 0xFF
};
*/
static struct esb_address esb_addr = {
	.base_addr_p0 = {0x99, 0x44, 0x99, 0x96},
	.base_addr_p1 = {0x00, 0x00, 0x00, 0x00},
	.pipe_prefixes = {0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
	.addr_length = 4,
	.num_pipes = 1,
	.rf_channel = 40,
	.rx_pipes_enabled = 0xFF
};
/*Ajit change*/

static esb_event_handler event_handler;
static struct esb_payload *current_payload;

/* FIFOs and buffers */
static struct payload_tx_fifo tx_fifo;
static struct payload_rx_fifo rx_fifo;

#if 0
static uint8_t tx_payload_buffer[CONFIG_ESB_MAX_PAYLOAD_LENGTH + 2];
static uint8_t rx_payload_buffer[CONFIG_ESB_MAX_PAYLOAD_LENGTH + 2];
#endif
//Ajit change
static uint8_t tx_payload_buffer[CONFIG_ESB_MAX_PAYLOAD_LENGTH];
static uint8_t rx_payload_buffer[CONFIG_ESB_MAX_PAYLOAD_LENGTH];


/* Random access buffer variables for ACK payload handling */
struct payload_wrap ack_pl_wrap[CONFIG_ESB_TX_FIFO_SIZE];
struct payload_wrap *ack_pl_wrap_pipe[CONFIG_ESB_PIPE_COUNT];

/* Run time variables */
static uint8_t pids[CONFIG_ESB_PIPE_COUNT];
static struct pipe_info rx_pipe_info[CONFIG_ESB_PIPE_COUNT];
static volatile uint32_t interrupt_flags;
static volatile uint32_t retransmits_remaining;
static volatile uint32_t last_tx_attempts;
static volatile uint32_t wait_for_ack_timeout_us;

static uint32_t radio_shorts_common = RADIO_SHORTS_COMMON;

/* PPI or DPPI instances */
#ifdef DPPI_PRESENT
typedef uint8_t ppi_channel_t;
#else
typedef nrf_ppi_channel_t ppi_channel_t;
#endif

static ppi_channel_t ppi_ch_radio_ready_timer_start;
static ppi_channel_t ppi_ch_radio_address_timer_stop;
static ppi_channel_t ppi_ch_timer_compare0_radio_disable;
static ppi_channel_t ppi_ch_timer_compare1_radio_txen;
static ppi_channel_t ppi_ch_timer_compare1_radio_rxen;

static uint32_t ppi_all_channels_mask;

/* These function pointers are changed dynamically, depending on protocol
 * configuration and state. Note that they will be 0 initialized.
 */
static void (*on_radio_disabled)(void);
static void (*on_radio_end)(void);
static void (*update_rf_payload_format)(uint32_t payload_length);
int esb_init_tx(const struct esb_config *config);
int esb_init_rx(const struct esb_config *config);
/*  The following functions are assigned to the function pointers above. */
static void on_radio_disabled_tx_noack(void);
static void on_radio_disabled_tx(void);
static void on_radio_disabled_tx_wait_for_ack(void);
static void on_radio_disabled_rx(void);
static void on_radio_disabled_rx_ack(void);

void mband_frequency_set(void);

/*  Function to do bytewise bit-swap on an unsigned 32-bit value */
static uint32_t bytewise_bit_swap(const uint8_t *input)
{
#if __CORTEX_M == (0x04U)
	uint32_t inp = (*(uint32_t *)input);

	return sys_cpu_to_be32((uint32_t)__RBIT(inp));
#else
	uint32_t inp = sys_cpu_to_le32(*(uint32_t *)input);

	inp = (inp & 0xF0F0F0F0) >> 4 | (inp & 0x0F0F0F0F) << 4;
	inp = (inp & 0xCCCCCCCC) >> 2 | (inp & 0x33333333) << 2;
	inp = (inp & 0xAAAAAAAA) >> 1 | (inp & 0x55555555) << 1;
	return inp;
#endif
}

/* Convert a base address from nRF24L format to nRF5 format */
static uint32_t addr_conv(const uint8_t *addr)
{
	return __REV(bytewise_bit_swap(addr));
}

static inline void apply_errata143_workaround(void)
{
	/* Workaround for Errata 143
	 * Check if the most significant bytes of address 0 (including
	 * prefix) match those of another address. It's recommended to
	 * use a unique address 0 since this will avoid the 3dBm penalty
	 * incurred from the workaround.
	 */
	uint32_t base_address_mask =
		esb_addr.addr_length == 5 ? 0xFFFF0000 : 0xFF000000;

	/* Load the two addresses before comparing them to ensure
	 * defined ordering of volatile accesses.
	 */
	uint32_t addr0 = NRF_RADIO->BASE0 & base_address_mask;
	uint32_t addr1 = NRF_RADIO->BASE1 & base_address_mask;

	if (addr0 == addr1) {
		uint32_t prefix0 = NRF_RADIO->PREFIX0 & 0x000000FF;
		uint32_t prefix1 = (NRF_RADIO->PREFIX0 & 0x0000FF00) >> 8;
		uint32_t prefix2 = (NRF_RADIO->PREFIX0 & 0x00FF0000) >> 16;
		uint32_t prefix3 = (NRF_RADIO->PREFIX0 & 0xFF000000) >> 24;
		uint32_t prefix4 = NRF_RADIO->PREFIX1 & 0x000000FF;
		uint32_t prefix5 = (NRF_RADIO->PREFIX1 & 0x0000FF00) >> 8;
		uint32_t prefix6 = (NRF_RADIO->PREFIX1 & 0x00FF0000) >> 16;
		uint32_t prefix7 = (NRF_RADIO->PREFIX1 & 0xFF000000) >> 24;

		if (prefix0 == prefix1 || prefix0 == prefix2 ||
			prefix0 == prefix3 || prefix0 == prefix4 ||
			prefix0 == prefix5 || prefix0 == prefix6 ||
			prefix0 == prefix7) {
			/* This will cause a 3dBm sensitivity loss,
			 * avoid using such address combinations if possible.
			 */
			*(volatile uint32_t *)0x40001774 =
				((*(volatile uint32_t *)0x40001774) & 0xfffffffe) | 0x01000000;
		}
	}
}

void mband_frequency_set(void)
{
	NRF_RADIO->FREQUENCY = (RADIO_FREQUENCY_MAP_Low << RADIO_FREQUENCY_MAP_Pos);
}

static void update_rf_payload_format_esb_dpl(uint32_t payload_length)
{
#if (CONFIG_ESB_MAX_PAYLOAD_LENGTH <= 32)
	/* Using 6 bits for length */
	/*Ajit change*/
	NRF_RADIO->PCNF0 = (0 << RADIO_PCNF0_S0LEN_Pos) |
			   (0 << RADIO_PCNF0_LFLEN_Pos) |
			   (0 << RADIO_PCNF0_S1LEN_Pos);
#else
	/* Using 8 bits for length */
	NRF_RADIO->PCNF0 = (0 << RADIO_PCNF0_S0LEN_Pos) |
			   (8 << RADIO_PCNF0_LFLEN_Pos) |
			   (3 << RADIO_PCNF0_S1LEN_Pos);
#endif


//Ajit change 
		NRF_RADIO->PCNF1 =
		(RADIO_PCNF1_WHITEEN_Disabled << RADIO_PCNF1_WHITEEN_Pos) |
		(RADIO_PCNF1_ENDIAN_Big << RADIO_PCNF1_ENDIAN_Pos) |
		((esb_addr.addr_length - 1) << RADIO_PCNF1_BALEN_Pos) |
		(CONFIG_ESB_MAX_PAYLOAD_LENGTH << RADIO_PCNF1_STATLEN_Pos) |
		(CONFIG_ESB_MAX_PAYLOAD_LENGTH << RADIO_PCNF1_MAXLEN_Pos);
}

static void update_rf_payload_format_esb(uint32_t payload_length)
{

/*Ajit change*/
	NRF_RADIO->PCNF0 = (0 << RADIO_PCNF0_S0LEN_Pos) |
			   (0 << RADIO_PCNF0_LFLEN_Pos) |
			   (0 << RADIO_PCNF0_S1LEN_Pos);
//Ajit Change

	NRF_RADIO->PCNF1 =
		(RADIO_PCNF1_WHITEEN_Disabled << RADIO_PCNF1_WHITEEN_Pos) |
		(RADIO_PCNF1_ENDIAN_Big << RADIO_PCNF1_ENDIAN_Pos) |
		((esb_addr.addr_length - 1) << RADIO_PCNF1_BALEN_Pos) |
		(payload_length << RADIO_PCNF1_STATLEN_Pos) |
		(payload_length << RADIO_PCNF1_MAXLEN_Pos);

}

static void update_radio_addresses(uint8_t update_mask)
{
	if ((update_mask & ADDR_UPDATE_MASK_BASE0) != 0) {
		NRF_RADIO->BASE0 = addr_conv(esb_addr.base_addr_p0);
	}

	if ((update_mask & ADDR_UPDATE_MASK_BASE1) != 0) {
		NRF_RADIO->BASE1 = addr_conv(esb_addr.base_addr_p1);
	}

	if ((update_mask & ADDR_UPDATE_MASK_PREFIX) != 0) {
		NRF_RADIO->PREFIX0 =
			bytewise_bit_swap(&esb_addr.pipe_prefixes[0]);
		NRF_RADIO->PREFIX1 =
			bytewise_bit_swap(&esb_addr.pipe_prefixes[4]);
	}

	/* Workaround for Errata 143 */
#if NRF52_ERRATA_143_ENABLE_WORKAROUND
	if (nrf52_errata_143()) {
		apply_errata143_workaround();
	}
#endif
}

static void update_radio_tx_power(void)
{
	NRF_RADIO->TXPOWER = esb_cfg.tx_output_power
			     << RADIO_TXPOWER_TXPOWER_Pos;
}

static bool update_radio_bitrate(void)
{
	NRF_RADIO->MODE = esb_cfg.bitrate << RADIO_MODE_MODE_Pos;

	switch (esb_cfg.bitrate) {
	case ESB_BITRATE_2MBPS:
#if defined(CONFIG_SOC_SERIES_NRF52X) || defined(CONFIG_SOC_NRF5340_CPUNET)
	case ESB_BITRATE_2MBPS_BLE:
#endif
		wait_for_ack_timeout_us = RX_ACK_TIMEOUT_US_2MBPS;
		break;

	case ESB_BITRATE_1MBPS:
		wait_for_ack_timeout_us = RX_ACK_TIMEOUT_US_1MBPS;
		break;

#ifdef CONFIG_SOC_SERIES_NRF51X
	case ESB_BITRATE_250KBPS:
		wait_for_ack_timeout_us = RX_ACK_TIMEOUT_US_250KBPS;
		break;
#endif /* CONFIG_SOC_SERIES_NRF51X */

	case ESB_BITRATE_1MBPS_BLE:
		wait_for_ack_timeout_us = RX_ACK_TIMEOUT_US_1MBPS_BLE;
		break;

	default:
		/* Should not be reached */
		return false;
	}

	return true;
}

static bool update_radio_protocol(void)
{
	switch (esb_cfg.protocol) {
	case ESB_PROTOCOL_ESB_DPL:
		update_rf_payload_format = update_rf_payload_format_esb_dpl;
		break;

	case ESB_PROTOCOL_ESB:
		update_rf_payload_format = update_rf_payload_format_esb;
		break;

	default:
		/* Should not be reached */
		return false;
	}
	return true;
}

static bool update_radio_crc(void)
{
	switch (esb_cfg.crc) {
	case ESB_CRC_16BIT:
		NRF_RADIO->CRCINIT = 0xFFFFUL;  /* Initial value */
		NRF_RADIO->CRCPOLY = 0x1021UL; /* CRC poly: x^16+x^12^x^5+1 */ // Ajit change from 0x11021
		NRF_RADIO->CRCCNF = ESB_CRC_16BIT << RADIO_CRCCNF_LEN_Pos;
		//(" ** After setting CRC registers ** NRF_RADIO->CRCCNF: 0x%x \r\n",NRF_RADIO->CRCCNF);
		break;

	case ESB_CRC_8BIT:
		NRF_RADIO->CRCINIT = 0xFFUL;  /* Initial value */
		NRF_RADIO->CRCPOLY = 0x107UL; /* CRC poly: x^8+x^2^x^1+1 */
		NRF_RADIO->CRCCNF = ESB_CRC_8BIT << RADIO_CRCCNF_LEN_Pos;
		break;

	case ESB_CRC_OFF:
		NRF_RADIO->CRCINIT = 0x00UL;
		NRF_RADIO->CRCPOLY = 0x00UL;
		NRF_RADIO->CRCCNF = ESB_CRC_OFF << RADIO_CRCCNF_LEN_Pos;
		break;

	default:
		return false;
	}

	return true;
}

static bool update_radio_parameters(void)
{
	bool params_valid = true;

	update_radio_tx_power();
	params_valid &= update_radio_bitrate();
	params_valid &= update_radio_protocol();
	params_valid &= update_radio_crc();
	update_rf_payload_format(esb_cfg.payload_length);
	params_valid &=
	    (esb_cfg.retransmit_delay >= RETRANSMIT_DELAY_MIN);

	return params_valid;
}

static void reset_fifos(void)
{
	tx_fifo.back = 0;
	tx_fifo.front = 0;
	tx_fifo.count = 0;

	rx_fifo.back = 0;
	rx_fifo.front = 0;
	rx_fifo.count = 0;
}

static void initialize_fifos(void)
{
	static struct esb_payload rx_payload[CONFIG_ESB_RX_FIFO_SIZE];
	static struct esb_payload tx_payload[CONFIG_ESB_TX_FIFO_SIZE];

	reset_fifos();

	for (size_t i = 0; i < CONFIG_ESB_TX_FIFO_SIZE; i++) {
		tx_fifo.payload[i] = &tx_payload[i];
	}

	for (size_t i = 0; i < CONFIG_ESB_RX_FIFO_SIZE; i++) {
		rx_fifo.payload[i] = &rx_payload[i];
	}

	for (size_t i = 0; i < CONFIG_ESB_TX_FIFO_SIZE; i++) {
		ack_pl_wrap[i].p_payload = &tx_payload[i];
		ack_pl_wrap[i].in_use = false;
		ack_pl_wrap[i].p_next = 0;
	}

	for (size_t i = 0; i < CONFIG_ESB_PIPE_COUNT; i++) {
		ack_pl_wrap_pipe[i] = 0;
	}
}

static void tx_fifo_remove_last(void)
{
	if (tx_fifo.count == 0) {
		return;
	}

	uint32_t key = irq_lock();

	tx_fifo.count--;
	if (++tx_fifo.front >= CONFIG_ESB_TX_FIFO_SIZE) {
		tx_fifo.front = 0;
	}

	irq_unlock(key);
}

/*  Function to push the content of the rx_buffer to the RX FIFO.
 *
 *  The module will point the register NRF_RADIO->PACKETPTR to a buffer for
 *  receiving packets. After receiving a packet the module will call this
 *  function to copy the received data to the RX FIFO.
 *
 *  @param  pipe Pipe number to set for the packet.
 *  @param  pid  Packet ID.
 *
 *  @retval true   Operation successful.
 *  @retval false  Operation failed.
 */
static bool rx_fifo_push_rfbuf(uint8_t pipe, uint8_t pid)
{
	if (rx_fifo.count >= CONFIG_ESB_RX_FIFO_SIZE) {
		return false;
	}

	if (esb_cfg.protocol == ESB_PROTOCOL_ESB_DPL) {
		if (rx_payload_buffer[0] > CONFIG_ESB_MAX_PAYLOAD_LENGTH) {
			return false;
		}
		rx_fifo.payload[rx_fifo.back]->length = rx_payload_buffer[0];
	} else if (esb_cfg.mode == ESB_MODE_PTX) {
		/* Received packet is an acknowledgment */
		rx_fifo.payload[rx_fifo.back]->length = 0;
	} else {
		rx_fifo.payload[rx_fifo.back]->length = esb_cfg.payload_length;
	}

//	memcpy(rx_fifo.payload[rx_fifo.back]->data, &rx_payload_buffer[2],
//	       rx_fifo.payload[rx_fifo.back]->length);

	memcpy(rx_fifo.payload[rx_fifo.back]->data, &rx_payload_buffer[0],
	       rx_fifo.payload[rx_fifo.back]->length);

	rx_fifo.payload[rx_fifo.back]->pipe = pipe;
	rx_fifo.payload[rx_fifo.back]->rssi = NRF_RADIO->RSSISAMPLE;
	rx_fifo.payload[rx_fifo.back]->pid = pid;
	rx_fifo.payload[rx_fifo.back]->noack = !(rx_payload_buffer[1] & 0x01);

	if (++rx_fifo.back >= CONFIG_ESB_RX_FIFO_SIZE) {
		rx_fifo.back = 0;
	}
	rx_fifo.count++;

	return true;
}

static void sys_timer_init(void)
{
	/* Configure the system timer with a 1 MHz base frequency */
	ESB_SYS_TIMER->PRESCALER = 4;
	ESB_SYS_TIMER->BITMODE = TIMER_BITMODE_BITMODE_16Bit;
	ESB_SYS_TIMER->SHORTS = TIMER_SHORTS_COMPARE1_CLEAR_Msk |
				TIMER_SHORTS_COMPARE1_STOP_Msk;
}

static void ppi_init(void)
{
#ifdef DPPI_PRESENT
	nrfx_dppi_channel_alloc(&ppi_ch_radio_ready_timer_start);
	nrfx_dppi_channel_alloc(&ppi_ch_radio_address_timer_stop);
	nrfx_dppi_channel_alloc(&ppi_ch_timer_compare0_radio_disable);
	nrfx_dppi_channel_alloc(&ppi_ch_timer_compare1_radio_txen);

	NRF_RADIO->PUBLISH_READY          = DPPIC_SUBSCRIBE_CHG_EN_EN_Msk | ppi_ch_radio_ready_timer_start;
	ESB_SYS_TIMER->SUBSCRIBE_START    = DPPIC_SUBSCRIBE_CHG_EN_EN_Msk | ppi_ch_radio_ready_timer_start;
	NRF_RADIO->PUBLISH_ADDRESS        = DPPIC_SUBSCRIBE_CHG_EN_EN_Msk | ppi_ch_radio_address_timer_stop;
	ESB_SYS_TIMER->SUBSCRIBE_SHUTDOWN = DPPIC_SUBSCRIBE_CHG_EN_EN_Msk | ppi_ch_radio_address_timer_stop;
	ESB_SYS_TIMER->PUBLISH_COMPARE[0] = DPPIC_SUBSCRIBE_CHG_EN_EN_Msk | ppi_ch_timer_compare0_radio_disable;
	NRF_RADIO->SUBSCRIBE_DISABLE      = DPPIC_SUBSCRIBE_CHG_EN_EN_Msk | ppi_ch_timer_compare0_radio_disable;
	ESB_SYS_TIMER->PUBLISH_COMPARE[1] = DPPIC_SUBSCRIBE_CHG_EN_EN_Msk | ppi_ch_timer_compare1_radio_txen;
	NRF_RADIO->SUBSCRIBE_TXEN         = DPPIC_SUBSCRIBE_CHG_EN_EN_Msk | ppi_ch_timer_compare1_radio_txen;
#else
	nrfx_ppi_channel_alloc(&ppi_ch_radio_ready_timer_start);
	nrfx_ppi_channel_alloc(&ppi_ch_radio_address_timer_stop);
	nrfx_ppi_channel_alloc(&ppi_ch_timer_compare0_radio_disable);
	nrfx_ppi_channel_alloc(&ppi_ch_timer_compare1_radio_txen);
	nrfx_ppi_channel_alloc(&ppi_ch_timer_compare1_radio_rxen);
	

	nrfx_ppi_channel_assign(ppi_ch_radio_ready_timer_start,
		(uint32_t)&NRF_RADIO->EVENTS_READY, (uint32_t)&ESB_SYS_TIMER->TASKS_START);
	nrfx_ppi_channel_assign(ppi_ch_radio_address_timer_stop,
		(uint32_t)&NRF_RADIO->EVENTS_ADDRESS, (uint32_t)&ESB_SYS_TIMER->TASKS_SHUTDOWN);
	nrfx_ppi_channel_assign(ppi_ch_timer_compare0_radio_disable,
		(uint32_t)&ESB_SYS_TIMER->EVENTS_COMPARE[0], (uint32_t)&NRF_RADIO->TASKS_DISABLE);
	nrfx_ppi_channel_assign(ppi_ch_timer_compare1_radio_txen,
		(uint32_t)&ESB_SYS_TIMER->EVENTS_COMPARE[1], (uint32_t)&NRF_RADIO->TASKS_TXEN);
	nrfx_ppi_channel_assign(ppi_ch_timer_compare1_radio_rxen,
		(uint32_t)&ESB_SYS_TIMER->EVENTS_COMPARE[2], (uint32_t)&NRF_RADIO->TASKS_RXEN);	
#endif
	ppi_all_channels_mask = (1 << ppi_ch_radio_ready_timer_start) | (1 << ppi_ch_radio_address_timer_stop) |
							(1 << ppi_ch_timer_compare0_radio_disable) | (1 << ppi_ch_timer_compare1_radio_txen) | (1 << ppi_ch_timer_compare1_radio_rxen);
}

static void start_tx_transaction(void)
{
	bool ack;

	last_tx_attempts = 1;
	/* Prepare the payload */
	current_payload = tx_fifo.payload[tx_fifo.front];

	switch (esb_cfg.protocol) {
	case ESB_PROTOCOL_ESB:
		update_rf_payload_format(current_payload->length);
#if 0
		tx_payload_buffer[0] = current_payload->pid;
		tx_payload_buffer[1] = 0;
		memcpy(&tx_payload_buffer[2], current_payload->data,
		       current_payload->length);
#endif
//Ajit change
		memcpy(&tx_payload_buffer, current_payload->data,
		       current_payload->length);	   
#if 0
		NRF_RADIO->SHORTS = radio_shorts_common |
				    RADIO_SHORTS_DISABLED_RXEN_Msk;
		NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk |
				      RADIO_INTENSET_READY_Msk;

		/* Configure the retransmit counter */
		retransmits_remaining = esb_cfg.retransmit_count;
		on_radio_disabled = on_radio_disabled_tx;
		esb_state = ESB_STATE_PTX_TX_ACK;
#endif 
#if 0
		printk("Printing tx data before transmitting...\r\n");
		int i = 0;
		for(i=0; i < current_payload->length; i++)
		{
			printk("tx_payload_buffer[%d] : %x \r\n",i,tx_payload_buffer[i]);
		}
#endif
#if 1
		// Ajit change for tx to work
		//NRF_RADIO->SHORTS = radio_shorts_common;


		NRF_RADIO->SHORTS = radio_shorts_common | RADIO_SHORTS_DISABLED_RXEN_Msk;
		//NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk | RADIO_INTENSET_READY_Msk;
		//NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk;
		NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk;
		nrfx_gppi_channels_disable(1 << ppi_ch_timer_compare1_radio_rxen);
		nrfx_gppi_channels_enable(1 << ppi_ch_timer_compare1_radio_txen);
		on_radio_disabled = on_radio_disabled_tx_noack;
		esb_state = ESB_STATE_PTX_TX;

#endif
		break;

	case ESB_PROTOCOL_ESB_DPL:
		ack = !current_payload->noack || !esb_cfg.selective_auto_ack;
#if 0
		tx_payload_buffer[0] = current_payload->length;
		tx_payload_buffer[1] = current_payload->pid << 1;
		tx_payload_buffer[1] |= current_payload->noack ? 0x00 : 0x01;
		memcpy(&tx_payload_buffer[2], current_payload->data,
		       current_payload->length);
#endif
//Ajit change
		memcpy(&tx_payload_buffer, current_payload->data,
		       current_payload->length);	   

		/* Handling ack if noack is set to false or if
		 * selective auto ack is turned off
		 */
		if (ack) {
			NRF_RADIO->SHORTS = radio_shorts_common |
					    RADIO_SHORTS_DISABLED_RXEN_Msk;
			NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk |
					      RADIO_INTENSET_READY_Msk;

			/* Configure the retransmit counter */
			retransmits_remaining = esb_cfg.retransmit_count;
			on_radio_disabled = on_radio_disabled_tx;
			esb_state = ESB_STATE_PTX_TX_ACK;
		} else {
			NRF_RADIO->SHORTS = radio_shorts_common;
			NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk;
			on_radio_disabled = on_radio_disabled_tx_noack;
			esb_state = ESB_STATE_PTX_TX;
		}
		break;

	default:
		/* Should not be reached */
		break;
	}

	NRF_RADIO->TXADDRESS = current_payload->pipe;
	NRF_RADIO->RXADDRESSES = 1 << current_payload->pipe;
	//NRF_RADIO->FREQUENCY = esb_addr.rf_channel;
	NRF_RADIO->FREQUENCY = esb_addr.rf_channel & RADIO_FREQUENCY_FREQUENCY_Msk;

	NRF_RADIO->PACKETPTR = (uint32_t)tx_payload_buffer;

	NVIC_ClearPendingIRQ(RADIO_IRQn);
	irq_enable(RADIO_IRQn);

	NRF_RADIO->EVENTS_ADDRESS = 0;
	NRF_RADIO->EVENTS_PAYLOAD = 0;
	NRF_RADIO->EVENTS_DISABLED = 0;
	NRF_RADIO->TASKS_TXEN = 1;
	tx_start_event = true;
}

static void on_radio_disabled_tx_noack(void)
{
	interrupt_flags |= INT_TX_SUCCESS_MSK;
	tx_fifo_remove_last();
	if (tx_fifo.count == 0) {
		esb_state = ESB_STATE_IDLE;
		NVIC_SetPendingIRQ(ESB_EVT_IRQ);
	} else {
		NVIC_SetPendingIRQ(ESB_EVT_IRQ);
		start_tx_transaction();
	}
}

static void on_radio_disabled_tx(void)
{
	printk("Inside on_radio_disabled_tx \r\n");
	/* Remove the DISABLED -> RXEN shortcut, to make sure the radio stays
	 * disabled after the RX window
	 */
	NRF_RADIO->SHORTS = radio_shorts_common;

	/* Make sure the timer is started the next time the radio is ready,
	 * and that it will disable the radio automatically if no packet is
	 * received by the time defined in wait_for_ack_timeout_us
	 */
	ESB_SYS_TIMER->CC[0] = wait_for_ack_timeout_us;
	ESB_SYS_TIMER->CC[1] = esb_cfg.retransmit_delay - 130;
	ESB_SYS_TIMER->TASKS_CLEAR = 1;
	ESB_SYS_TIMER->EVENTS_COMPARE[0] = 0;
	ESB_SYS_TIMER->EVENTS_COMPARE[1] = 0;

	/* Remove */
	ESB_SYS_TIMER->TASKS_START = 1;

	nrfx_gppi_channels_enable(ppi_all_channels_mask);
	nrfx_gppi_channels_disable(1 << ppi_ch_timer_compare1_radio_txen);


	NRF_RADIO->EVENTS_END = 0;

	if (esb_cfg.protocol == ESB_PROTOCOL_ESB) {
		update_rf_payload_format(0);
	}

	NRF_RADIO->PACKETPTR = (uint32_t)rx_payload_buffer;
	on_radio_disabled = on_radio_disabled_tx_wait_for_ack;
	esb_state = ESB_STATE_PTX_RX_ACK;
}

static void on_radio_disabled_tx_wait_for_ack(void)
{
	/* This marks the completion of a TX_RX sequence (TX with ACK) */

	/* Make sure the timer will not deactivate the radio if a packet is
	 * received.
	 */
	nrfx_gppi_channels_disable(ppi_all_channels_mask);

	/* If the radio has received a packet and the CRC status is OK */
	if (NRF_RADIO->EVENTS_END && NRF_RADIO->CRCSTATUS != 0) {
		ESB_SYS_TIMER->TASKS_SHUTDOWN = 1;

		interrupt_flags |= INT_TX_SUCCESS_MSK;
		last_tx_attempts = esb_cfg.retransmit_count -
				   retransmits_remaining + 1;

		tx_fifo_remove_last();

		if (esb_cfg.protocol != ESB_PROTOCOL_ESB &&
		    rx_payload_buffer[0] > 0) {
			if (rx_fifo_push_rfbuf((uint8_t)NRF_RADIO->TXADDRESS,
					       rx_payload_buffer[1] >> 1)) {
				interrupt_flags |=
					INT_RX_DATA_RECEIVED_MSK;
			}
		}
		if ((tx_fifo.count == 0) ||
		    (esb_cfg.tx_mode == ESB_TXMODE_MANUAL)) {
			esb_state = ESB_STATE_IDLE;
			NVIC_SetPendingIRQ(ESB_EVT_IRQ);
		} else {
			NVIC_SetPendingIRQ(ESB_EVT_IRQ);
			start_tx_transaction();
		}
	} else {
		if (retransmits_remaining-- == 0) {
			ESB_SYS_TIMER->TASKS_SHUTDOWN = 1;

			/* All retransmits are expended, and the TX operation is
			 * suspended
			 */
			last_tx_attempts = esb_cfg.retransmit_count + 1;
			interrupt_flags |= INT_TX_FAILED_MSK;

			esb_state = ESB_STATE_IDLE;
			NVIC_SetPendingIRQ(ESB_EVT_IRQ);
		} else {
			/* There are still more retransmits left, TX mode should
			 * be entered again as soon as the system timer reaches
			 * CC[1].
			 */
			NRF_RADIO->SHORTS = radio_shorts_common |
					    RADIO_SHORTS_DISABLED_RXEN_Msk;
			update_rf_payload_format(current_payload->length);
			NRF_RADIO->PACKETPTR = (uint32_t)tx_payload_buffer;
			on_radio_disabled = on_radio_disabled_tx;
			esb_state = ESB_STATE_PTX_TX_ACK;
			ESB_SYS_TIMER->TASKS_START = 1;
			nrfx_gppi_channels_enable(1 << ppi_ch_timer_compare1_radio_txen);
			if (ESB_SYS_TIMER->EVENTS_COMPARE[1]) {
				NRF_RADIO->TASKS_TXEN = 1;
			}
		}
	}
}

static void clear_events_restart_rx(void)
{
	NRF_RADIO->SHORTS = radio_shorts_common;
	update_rf_payload_format(esb_cfg.payload_length);
	NRF_RADIO->PACKETPTR = (uint32_t)rx_payload_buffer;
	NRF_RADIO->EVENTS_DISABLED = 0;
	NRF_RADIO->TASKS_DISABLE = 1;

	while (NRF_RADIO->EVENTS_DISABLED == 0) {
		/* wait for register to settle */
	}

	NRF_RADIO->EVENTS_DISABLED = 0;
	NRF_RADIO->SHORTS = radio_shorts_common |
			    RADIO_SHORTS_DISABLED_TXEN_Msk;

	NRF_RADIO->TASKS_RXEN = 1;
}

static void on_radio_disabled_rx_dpl(bool retransmit_payload,
				     struct pipe_info *pipe_info)
{
	uint32_t pipe = NRF_RADIO->RXMATCH;

	if (tx_fifo.count > 0 && ack_pl_wrap_pipe[pipe] != 0) {
		current_payload = ack_pl_wrap_pipe[pipe]->p_payload;

		/* Pipe stays in ACK with payload until TX FIFO is empty */
		/* Do not report TX success on first ack payload or retransmit */
		if (pipe_info->ack_payload == true && !retransmit_payload) {
			ack_pl_wrap_pipe[pipe]->in_use = false;
			ack_pl_wrap_pipe[pipe] = ack_pl_wrap_pipe[pipe]->p_next;
			tx_fifo.count--;
			if (tx_fifo.count > 0 && ack_pl_wrap_pipe[pipe] != 0) {
				current_payload = ack_pl_wrap_pipe[pipe]->p_payload;
			} else {
				current_payload = 0;
			}

			/* ACK payloads also require TX_DS */
			/* (page 40 of the 'nRF24LE1_Product_Specification_rev1_6.pdf') */
			interrupt_flags |= INT_TX_SUCCESS_MSK;
		}

		if (current_payload != 0) {
			pipe_info->ack_payload = true;
			update_rf_payload_format(current_payload->length);
			tx_payload_buffer[0] = current_payload->length;
			memcpy(&tx_payload_buffer[2],
					current_payload->data,
					current_payload->length);
		} else {
			pipe_info->ack_payload = false;
			update_rf_payload_format(0);
			tx_payload_buffer[0] = 0;
		}
	} else {
		pipe_info->ack_payload = false;
		update_rf_payload_format(0);
		tx_payload_buffer[0] = 0;
	}

	tx_payload_buffer[1] = rx_payload_buffer[1];
}

static void on_radio_disabled_rx(void)
{
	bool retransmit_payload = false;
	bool send_rx_event = true;
	struct pipe_info *pipe_info;

	if (NRF_RADIO->CRCSTATUS == 0) {
		clear_events_restart_rx();
		return;
	}

	if (rx_fifo.count >= CONFIG_ESB_RX_FIFO_SIZE) {
		clear_events_restart_rx();
		return;
	}

	pipe_info = &rx_pipe_info[NRF_RADIO->RXMATCH];
	if (NRF_RADIO->RXCRC == pipe_info->crc &&
	    (rx_payload_buffer[1] >> 1) == pipe_info->pid) {
		retransmit_payload = true;
		send_rx_event = false;
	}

	pipe_info->pid = rx_payload_buffer[1] >> 1;
	pipe_info->crc = NRF_RADIO->RXCRC;

	//Ajit change//
	nrfx_gppi_channels_enable(ppi_all_channels_mask);
	nrfx_gppi_channels_disable(1 << ppi_ch_timer_compare1_radio_rxen);

	//Ajit change

	/* Check if an ack should be sent */
	if ((esb_cfg.selective_auto_ack == false) ||
	    ((rx_payload_buffer[1] & 0x01) == 1)) {
		NRF_RADIO->SHORTS = radio_shorts_common |
				    RADIO_SHORTS_DISABLED_RXEN_Msk;

		switch (esb_cfg.protocol) {
		case ESB_PROTOCOL_ESB_DPL:
			on_radio_disabled_rx_dpl(retransmit_payload, pipe_info);
			break;

		case ESB_PROTOCOL_ESB:
			update_rf_payload_format(0);
			tx_payload_buffer[0] = rx_payload_buffer[0];
			tx_payload_buffer[1] = 0;
			break;
		}

		esb_state = ESB_STATE_PRX_SEND_ACK;
		NRF_RADIO->TXADDRESS = NRF_RADIO->RXMATCH;

		NRF_RADIO->PACKETPTR = (uint32_t)tx_payload_buffer;
		on_radio_disabled = on_radio_disabled_rx_ack;
	} else {
		clear_events_restart_rx();
	}

	if (send_rx_event) {
		/* Push the new packet to the RX buffer and trigger a received
		 * event if the operation was
		 * successful.
		 */
		if (rx_fifo_push_rfbuf(NRF_RADIO->RXMATCH, pipe_info->pid)) {
			interrupt_flags |= INT_RX_DATA_RECEIVED_MSK;
			NVIC_SetPendingIRQ(ESB_EVT_IRQ);
		}
	}
}

static void on_radio_disabled_rx_ack(void)
{
	NRF_RADIO->SHORTS = radio_shorts_common |
			    RADIO_SHORTS_DISABLED_TXEN_Msk;
	update_rf_payload_format(esb_cfg.payload_length);

	NRF_RADIO->PACKETPTR = (uint32_t)rx_payload_buffer;
	on_radio_disabled = on_radio_disabled_rx;

	esb_state = ESB_STATE_PRX;
}

/* Retrieve interrupt flags and reset them.
 *
 * @param[out] interrupts	Interrupt flags.
 */
static void get_and_clear_irqs(uint32_t *interrupts)
{
	__ASSERT_NO_MSG(interrupts != NULL);

	uint32_t key = irq_lock();

	*interrupts = interrupt_flags;
	interrupt_flags = 0;

	irq_unlock(key);
}

static void radio_irq_handler(void)
{

#if 0
	if (NRF_RADIO->EVENTS_TXREADY) {

			NRF_RADIO->EVENTS_TXREADY = 0;
			//printk("Inside EVENTS_TXREADY \r\n");

	}

	if (NRF_RADIO->EVENTS_RXREADY) {

			NRF_RADIO->EVENTS_RXREADY = 0;
			//printk("Inside EVENTS_RXREADY \r\n");
	}
#endif

	if (NRF_RADIO->EVENTS_READY &&
	    (NRF_RADIO->INTENSET & RADIO_INTENSET_READY_Msk)) {

		dbg_ready_counter++;

		NRF_RADIO->EVENTS_READY = 0;
		ESB_SYS_TIMER->TASKS_START;
	}

	if (NRF_RADIO->EVENTS_END &&
	    (NRF_RADIO->INTENSET & RADIO_INTENSET_END_Msk)) {
			
		dbg_end_counter++;
		NRF_RADIO->EVENTS_END = 0;
		/* Call the correct on_radio_end function, depending on the
		 * current protocol state.
		 */
		end_event = true;

		if (on_radio_end) {
			on_radio_end();
		}
	}

	if (NRF_RADIO->EVENTS_DISABLED &&
	    (NRF_RADIO->INTENSET & RADIO_INTENSET_DISABLED_Msk)) {

			
		dbg_disabled_counter++;
		NRF_RADIO->EVENTS_DISABLED = 0;

		/* Call the correct on_radio_disable function, depending on the
		 * current protocol state.
		 */


		if (on_radio_disabled) {
			on_radio_disabled();
		}
	}
}

static void esb_evt_irq_handler(void)
{
	uint32_t interrupts;
	struct esb_evt event;

	event.tx_attempts = last_tx_attempts;
	get_and_clear_irqs(&interrupts);
	if (event_handler != NULL) {
		if (interrupts & INT_TX_SUCCESS_MSK) {
			event.evt_id = ESB_EVENT_TX_SUCCESS;
			event_handler(&event);
		}
		if (interrupts & INT_TX_FAILED_MSK) {
			event.evt_id = ESB_EVENT_TX_FAILED;
			event_handler(&event);
		}
		if (interrupts & INT_RX_DATA_RECEIVED_MSK) {
			event.evt_id = ESB_EVENT_RX_RECEIVED;
			event_handler(&event);
		}
	}
}

ISR_DIRECT_DECLARE(RADIO_IRQHandler)
{
	radio_irq_handler();

	ISR_DIRECT_PM();

	return 1;
}


ISR_DIRECT_DECLARE(ESB_EVT_IRQHandler)
{
	esb_evt_irq_handler();

	ISR_DIRECT_PM();

	return 1;
}

ISR_DIRECT_DECLARE(ESB_SYS_TIMER_IRQHandler)
{
	ISR_DIRECT_PM();

	return 1;
}

int esb_init(const struct esb_config *config)
{
	if (config == NULL) {
		return -EINVAL;
	}

	if (esb_initialized) {
		esb_disable();
	}

	event_handler = config->event_handler; 

	memcpy(&esb_cfg, config, sizeof(esb_cfg)); //separate

	interrupt_flags = 0;

	memset(rx_pipe_info, 0, sizeof(rx_pipe_info));
	memset(pids, 0, sizeof(pids));

	update_radio_parameters(); //separate

	/* Configure radio address registers according to ESB default values */
	NRF_RADIO->BASE0 = 0xE7E7E7E7;
	NRF_RADIO->BASE1 = 0x43434343;
	NRF_RADIO->PREFIX0 = 0x23C343E7;
	NRF_RADIO->PREFIX1 = 0x13E363A3;

	initialize_fifos();
	sys_timer_init();
	ppi_init();

	IRQ_DIRECT_CONNECT(RADIO_IRQn, CONFIG_ESB_RADIO_IRQ_PRIORITY,
			   RADIO_IRQHandler, 0);
	IRQ_DIRECT_CONNECT(ESB_EVT_IRQ, CONFIG_ESB_EVENT_IRQ_PRIORITY,
			   ESB_EVT_IRQHandler, 0);
	IRQ_DIRECT_CONNECT(ESB_SYS_TIMER_IRQn, CONFIG_ESB_EVENT_IRQ_PRIORITY,
			   ESB_SYS_TIMER_IRQHandler, 0);

	irq_enable(RADIO_IRQn);
	irq_enable(ESB_EVT_IRQ);
	irq_enable(ESB_SYS_TIMER_IRQn);

	esb_state = ESB_STATE_IDLE; //separate
	esb_initialized = true; //separate

#ifdef CONFIG_SOC_NRF52832
	if ((NRF_FICR->INFO.VARIANT & 0x0000FF00) == 0x00004500) {
		/* Check if the device is an nRF52832 Rev. 2. */
		/* Workaround for nRF52832 rev 2 errata 182 */
		*(volatile uint32_t *)0x4000173C |= (1 << 10);
	}
#endif

	return 0;
}



int esb_init_tx(const struct esb_config *config)
{
	if (config == NULL) {
		return -EINVAL;
	}

	memcpy(&esb_cfg, config, sizeof(esb_cfg)); //separate

	update_radio_parameters(); //separate

	esb_state = ESB_STATE_IDLE; //separate

	return 0;
}



int esb_init_rx(const struct esb_config *config)
{
	if (config == NULL) {
		return -EINVAL;
	}

	memcpy(&esb_cfg, config, sizeof(esb_cfg)); //separate

	update_radio_parameters(); //separate

	esb_state = ESB_STATE_IDLE; //separate

	return 0;
}


int esb_suspend(void)
{
	if (esb_state != ESB_STATE_IDLE) {
		return -EBUSY;
	}

	/*  Clear PPI */
	nrfx_gppi_channels_disable(ppi_all_channels_mask);

	esb_state = ESB_STATE_IDLE;

	return 0;
}

void esb_disable(void)
{
	/*  Clear PPI */
	nrfx_gppi_channels_disable(ppi_all_channels_mask);

	esb_state = ESB_STATE_IDLE;
	esb_initialized = false;

	reset_fifos();

	memset(rx_pipe_info, 0, sizeof(rx_pipe_info));
	memset(pids, 0, sizeof(pids));

	/*  Disable the interrupts used by ESB */
	irq_disable(RADIO_IRQn);
	irq_disable(ESB_SYS_TIMER_IRQn);
	irq_disable(ESB_EVT_IRQ);

	NRF_RADIO->SHORTS =
	    RADIO_SHORTS_READY_START_Enabled << RADIO_SHORTS_READY_START_Pos |
	    RADIO_SHORTS_END_DISABLE_Enabled << RADIO_SHORTS_END_DISABLE_Pos;
}

bool esb_is_idle(void)
{
	return (esb_state == ESB_STATE_IDLE);
}

static struct payload_wrap *find_free_payload_cont(void)
{
	for (int i = 0; i < CONFIG_ESB_TX_FIFO_SIZE; i++) {
		if (!ack_pl_wrap[i].in_use)
			return &ack_pl_wrap[i];
	}
	return 0;
}

int esb_write_payload(const struct esb_payload *payload)
{
	if (!esb_initialized) {
		return -EACCES;
	}
	if (payload == NULL) {
		return -EINVAL;
	}
	if (payload->length == 0 ||
	    payload->length > CONFIG_ESB_MAX_PAYLOAD_LENGTH ||
	    (esb_cfg.protocol == ESB_PROTOCOL_ESB &&
	     payload->length > esb_cfg.payload_length)) {
		return -EMSGSIZE;
	}
	if (tx_fifo.count >= CONFIG_ESB_TX_FIFO_SIZE) {
		return -ENOMEM;
	}
	if (payload->pipe >= CONFIG_ESB_PIPE_COUNT) {
		return -EINVAL;
	}

	uint32_t key = irq_lock();

	if (esb_cfg.mode == ESB_MODE_PTX) {
		memcpy(tx_fifo.payload[tx_fifo.back], payload,
			sizeof(struct esb_payload));

		pids[payload->pipe] = (pids[payload->pipe] + 1) % (PID_MAX + 1);
		tx_fifo.payload[tx_fifo.back]->pid = pids[payload->pipe];

		if (++tx_fifo.back >= CONFIG_ESB_TX_FIFO_SIZE) {
			tx_fifo.back = 0;
		}
		tx_fifo.count++;
	} else {
		struct payload_wrap *new_ack_payload = find_free_payload_cont();

		if (new_ack_payload != 0) {
			new_ack_payload->in_use = true;
			new_ack_payload->p_next = 0;
			memcpy(new_ack_payload->p_payload, payload, sizeof(struct esb_payload));

			pids[payload->pipe] = (pids[payload->pipe] + 1) % (PID_MAX + 1);
			new_ack_payload->p_payload->pid = pids[payload->pipe];

			if (ack_pl_wrap_pipe[payload->pipe] == 0) {
				ack_pl_wrap_pipe[payload->pipe] = new_ack_payload;
			} else {
				struct payload_wrap *pl = ack_pl_wrap_pipe[payload->pipe];

				while (pl->p_next != 0) {
					pl = (struct payload_wrap *)pl->p_next;
				}
				pl->p_next = (struct payload_wrap *)new_ack_payload;
			}
			tx_fifo.count++;
		}
	}

	irq_unlock(key);
	if (esb_cfg.mode == ESB_MODE_PTX &&
	    esb_cfg.tx_mode == ESB_TXMODE_AUTO &&
	    esb_state == ESB_STATE_IDLE) {
		start_tx_transaction();
	}

	return 0;
}

int esb_read_rx_payload(struct esb_payload *payload)
{
	if (!esb_initialized) {
		return -EACCES;
	}
	if (payload == NULL) {
		return -EINVAL;
	}

	if (rx_fifo.count == 0) {
		return -ENODATA;
	}

	uint32_t key = irq_lock();

	payload->length = rx_fifo.payload[rx_fifo.front]->length;
	payload->pipe = rx_fifo.payload[rx_fifo.front]->pipe;
	payload->rssi = rx_fifo.payload[rx_fifo.front]->rssi;
	payload->pid = rx_fifo.payload[rx_fifo.front]->pid;
	payload->noack = rx_fifo.payload[rx_fifo.front]->noack;
	memcpy(payload->data, rx_fifo.payload[rx_fifo.front]->data,
	       payload->length);

	if (++rx_fifo.front >= CONFIG_ESB_RX_FIFO_SIZE) {
		rx_fifo.front = 0;
	}

	rx_fifo.count--;

	irq_unlock(key);

	return 0;
}

int esb_start_tx(void)
{
	if (esb_state != ESB_STATE_IDLE) {
		printk("inside esb_start_tx , esb_state != ESB_STATE_IDLE \r\n");
		return -EBUSY;
	}

	if (tx_fifo.count == 0) {
		return -ENODATA;
	}
	start_tx_transaction();

	return 0;
}

int esb_start_rx(void)
{
	if (esb_state != ESB_STATE_IDLE) {
		printk("inside esb_start_rx , esb_state != ESB_STATE_IDLE \r\n");
		return -EBUSY;
	}

	nrfx_gppi_channels_disable(1 << ppi_ch_timer_compare1_radio_txen);
	nrfx_gppi_channels_enable(1 << ppi_ch_timer_compare1_radio_rxen);

	NRF_RADIO->INTENCLR = 0xFFFFFFFF;
	NRF_RADIO->EVENTS_DISABLED = 0;
	on_radio_disabled = on_radio_disabled_rx;


	NRF_RADIO->SHORTS = radio_shorts_common |
			    RADIO_SHORTS_DISABLED_TXEN_Msk;
	NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk;
	esb_state = ESB_STATE_PRX;


	NRF_RADIO->RXADDRESSES = esb_addr.rx_pipes_enabled;
	//NRF_RADIO->FREQUENCY = esb_addr.rf_channel;
	NRF_RADIO->FREQUENCY = esb_addr.rf_channel & RADIO_FREQUENCY_FREQUENCY_Msk;
	NRF_RADIO->PACKETPTR = (uint32_t)rx_payload_buffer;

	NVIC_ClearPendingIRQ(RADIO_IRQn);
	irq_enable(RADIO_IRQn);

	NRF_RADIO->EVENTS_ADDRESS = 0;
	NRF_RADIO->EVENTS_PAYLOAD = 0;
	NRF_RADIO->EVENTS_DISABLED = 0;

	NRF_RADIO->TASKS_RXEN = 1;
	
	return 0;
}

int esb_stop_tx(void)
{
//	NRF_RADIO->SHORTS = 0;
//	NRF_RADIO->EVENTS_DISABLED = 0;
//Ajit
	NRF_RADIO->SHORTS = 0;
	NRF_RADIO->INTENCLR = 0xFFFFFFFF;
//	on_radio_disabled = NULL;
	NRF_RADIO->EVENTS_DISABLED = 0;
//ajit

	NRF_RADIO->TASKS_DISABLE = 1;
	while (NRF_RADIO->EVENTS_DISABLED == 0) {
		/* wait for register to settle */
	}
	esb_state = ESB_STATE_IDLE;
	return 0;
}

int esb_stop_rx(void)
{
	if (esb_state != ESB_STATE_PRX && esb_state != ESB_STATE_PRX_SEND_ACK) {
		printk("return invalid from esb_stop_rx \r\n");
		return -EINVAL;
	}

	NRF_RADIO->SHORTS = 0;
	NRF_RADIO->INTENCLR = 0xFFFFFFFF;
	on_radio_disabled = NULL;
	NRF_RADIO->EVENTS_DISABLED = 0;
	NRF_RADIO->TASKS_DISABLE = 1;
	while (NRF_RADIO->EVENTS_DISABLED == 0) {
		/* wait for register to settle */
	}

	esb_state = ESB_STATE_IDLE;

	return 0;
}

int esb_flush_tx(void)
{
	if (!esb_initialized) {
		return -EACCES;
	}

	uint32_t key = irq_lock();

	tx_fifo.count = 0;
	tx_fifo.back = 0;
	tx_fifo.front = 0;

	irq_unlock(key);

	return 0;
}

int esb_pop_tx(void)
{
	if (!esb_initialized) {
		return -EACCES;
	}
	if (tx_fifo.count == 0) {
		return -ENODATA;
	}

	uint32_t key = irq_lock();

	if (++tx_fifo.back >= CONFIG_ESB_TX_FIFO_SIZE) {
		tx_fifo.back = 0;
	}
	tx_fifo.count--;

	irq_unlock(key);

	return 0;
}

int esb_flush_rx(void)
{
	if (!esb_initialized) {
		return -EACCES;
	}

	uint32_t key = irq_lock();

	rx_fifo.count = 0;
	rx_fifo.back = 0;
	rx_fifo.front = 0;

	memset(rx_pipe_info, 0, sizeof(rx_pipe_info));

	irq_unlock(key);

	return 0;
}

int esb_set_address_length(uint8_t length)
{
	if (esb_state != ESB_STATE_IDLE) {
		return -EBUSY;
	}
	if (!(length > 2 && length < 6)) {
		return -EINVAL;
	}

	esb_addr.addr_length = length;

	update_rf_payload_format(esb_cfg.payload_length);

	return 0;
}

int esb_set_base_address_0(const uint8_t *addr)
{
	if (esb_state != ESB_STATE_IDLE) {
		return -EBUSY;
	}
	if (addr == NULL) {
		return -EINVAL;
	}

	memcpy(esb_addr.base_addr_p0, addr, sizeof(esb_addr.base_addr_p0));

	update_radio_addresses(ADDR_UPDATE_MASK_BASE0);

	return 0;
}

int esb_set_base_address_1(const uint8_t *addr)
{
	if (esb_state != ESB_STATE_IDLE) {
		return -EBUSY;
	}
	if (addr == NULL) {
		return -EINVAL;
	}

	memcpy(esb_addr.base_addr_p1, addr, sizeof(esb_addr.base_addr_p1));

	update_radio_addresses(ADDR_UPDATE_MASK_BASE1);

	return 0;
}

int esb_set_prefixes(const uint8_t *prefixes, uint8_t num_pipes)
{
	if (esb_state != ESB_STATE_IDLE) {
		return -EBUSY;
	}
	if (prefixes == NULL) {
		return -EINVAL;
	}
	if (!(num_pipes <= CONFIG_ESB_PIPE_COUNT)) {
		return -EINVAL;
	}

	memcpy(esb_addr.pipe_prefixes, prefixes, num_pipes);
	esb_addr.num_pipes = num_pipes;
	esb_addr.rx_pipes_enabled = BIT_MASK_UINT_8(num_pipes);

	update_radio_addresses(ADDR_UPDATE_MASK_PREFIX);

	return 0;
}

int esb_update_prefix(uint8_t pipe, uint8_t prefix)
{
	if (esb_state != ESB_STATE_IDLE) {
		return -EBUSY;
	}
	if (pipe >= CONFIG_ESB_PIPE_COUNT) {
		return -EINVAL;
	}

	esb_addr.pipe_prefixes[pipe] = prefix;

	update_radio_addresses(ADDR_UPDATE_MASK_PREFIX);

	return 0;
}

int esb_enable_pipes(uint8_t enable_mask)
{
	if (esb_state != ESB_STATE_IDLE) {
		return -EBUSY;
	}
	if ((enable_mask | BIT_MASK_UINT_8(CONFIG_ESB_PIPE_COUNT)) !=
	    BIT_MASK_UINT_8(CONFIG_ESB_PIPE_COUNT)) {
		return -EINVAL;
	}

	esb_addr.rx_pipes_enabled = enable_mask;

	return 0;
}

int esb_set_rf_channel(uint32_t channel)
{
	if (esb_state != ESB_STATE_IDLE) {
		return -EBUSY;
	}
	if (channel > 100) {
		return -EINVAL;
	}

	esb_addr.rf_channel = channel;

	return 0;
}

int esb_get_rf_channel(uint32_t *channel)
{
	if (channel == NULL) {
		return -EINVAL;
	}

	*channel = esb_addr.rf_channel;

	return 0;
}

int esb_set_tx_power(enum esb_tx_power tx_output_power)
{
	if (esb_state != ESB_STATE_IDLE) {
		return -EBUSY;
	}

	if (esb_cfg.tx_output_power != tx_output_power) {
		esb_cfg.tx_output_power = tx_output_power;
		update_radio_tx_power();
	}

	return 0;
}

int esb_set_retransmit_delay(uint16_t delay)
{
	if (esb_state != ESB_STATE_IDLE) {
		return -EBUSY;
	}
	if (delay < RETRANSMIT_DELAY_MIN) {
		return -EINVAL;
	}

	esb_cfg.retransmit_delay = delay;

	return 0;
}

int esb_set_retransmit_count(uint16_t count)
{
	if (esb_state != ESB_STATE_IDLE) {
		return -EBUSY;
	}

	esb_cfg.retransmit_count = count;

	return 0;
}

int esb_set_bitrate(enum esb_bitrate bitrate)
{
	if (esb_state != ESB_STATE_IDLE) {
		return -EBUSY;
	}

	esb_cfg.bitrate = bitrate;

	return update_radio_bitrate() ? 0 : -EINVAL;
}

int esb_reuse_pid(uint8_t pipe)
{
	if (esb_state != ESB_STATE_IDLE) {
		return -EBUSY;
	}
	if (!(pipe < CONFIG_ESB_PIPE_COUNT)) {
		return -EINVAL;
	}

	pids[pipe] = (pids[pipe] + PID_MAX) % (PID_MAX + 1);

	return 0;
}
/*
 * Copyright (c) 2018 Intel Corporation
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <zephyr/kernel.h>
#include <cmsis_os.h>
#include <string.h>

#define ACTIVE 1
#define NOT_ACTIVE 0

static void zephyr_timer_wrapper(struct k_timer *timer);

struct timer_obj {
	struct k_timer ztimer;
	os_timer_type type;
	uint32_t status;
	void (*callback_function)(void const *argument);
	void *arg;
};

K_MEM_SLAB_DEFINE(cmsis_timer_slab, sizeof(struct timer_obj),
		  CONFIG_CMSIS_TIMER_MAX_COUNT, __alignof__(struct timer_obj));

static void zephyr_timer_wrapper(struct k_timer *timer)
{
	struct timer_obj *cm_timer;

	cm_timer = CONTAINER_OF(timer, struct timer_obj, ztimer);
	(cm_timer->callback_function)(cm_timer->arg);
}

/**
 * @brief Create a Timer
 */
osTimerId osTimerCreate(const osTimerDef_t *timer_def, os_timer_type type,
			void *argument)
{
	struct timer_obj *timer;

	if (timer_def == NULL) {
		return NULL;
	}

	if (type != osTimerOnce && type != osTimerPeriodic) {
		return NULL;
	}

	if (k_mem_slab_alloc(&cmsis_timer_slab, (void **)&timer, K_MSEC(100)) == 0) {
		(void)memset(timer, 0, sizeof(struct timer_obj));
	} else {
		return NULL;
	}

	timer->callback_function = timer_def->ptimer;
	timer->arg = argument;
	timer->type = type;
	timer->status = NOT_ACTIVE;

	k_timer_init(&timer->ztimer, zephyr_timer_wrapper, NULL);

	return (osTimerId)timer;
}



osTimerId osTimerCreate_US(const osTimerDef_t *timer_def, os_timer_type type,
			void *argument)
{
	struct timer_obj *timer;

	if (timer_def == NULL) {
		return NULL;
	}

	if (type != osTimerOnce && type != osTimerPeriodic) {
		return NULL;
	}

	if (k_mem_slab_alloc(&cmsis_timer_slab, (void **)&timer, K_USEC(100000)) == 0) {
		(void)memset(timer, 0, sizeof(struct timer_obj));
	} else {
		return NULL;
	}

	timer->callback_function = timer_def->ptimer;
	timer->arg = argument;
	timer->type = type;
	timer->status = NOT_ACTIVE;

	k_timer_init(&timer->ztimer, zephyr_timer_wrapper, NULL);

	return (osTimerId)timer;
}


/**
 * @brief Start or restart a Timer
 */
osStatus osTimerStart(osTimerId timer_id, uint32_t millisec)
{
	struct timer_obj *timer = (struct timer_obj *) timer_id;

	if (timer == NULL) {
		return osErrorParameter;
	}

	if (k_is_in_isr()) {
		return osErrorISR;
	}

	if (timer->type == osTimerOnce) {
		k_timer_start(&timer->ztimer, K_MSEC(millisec), K_NO_WAIT);
	} else if (timer->type == osTimerPeriodic) {
		k_timer_start(&timer->ztimer, K_MSEC(millisec),
			      K_MSEC(millisec));
	}

	timer->status = ACTIVE;
	return osOK;
}



osStatus osTimerStart_US(osTimerId timer_id, uint32_t microsec)
{
	struct timer_obj *timer = (struct timer_obj *) timer_id;

	if (timer == NULL) {
		return osErrorParameter;
	}

	if (k_is_in_isr()) {
		return osErrorISR;
	}

	if (timer->type == osTimerOnce) {
		k_timer_start(&timer->ztimer, K_USEC(microsec), K_NO_WAIT);
	} else if (timer->type == osTimerPeriodic) {
		k_timer_start(&timer->ztimer, K_USEC(microsec),
			      K_USEC(microsec));
	}

	timer->status = ACTIVE;
	return osOK;
}

/**
 * @brief Stop the Timer
 */
osStatus osTimerStop(osTimerId timer_id)
{
	struct timer_obj *timer = (struct timer_obj *) timer_id;

	if (timer == NULL) {
		return osErrorParameter;
	}

	if (k_is_in_isr()) {
		return osErrorISR;
	}

	if (timer->status == NOT_ACTIVE) {
		return osErrorResource;
	}

	k_timer_stop(&timer->ztimer);
	timer->status = NOT_ACTIVE;
	return osOK;
}

/**
 * @brief Delete the timer that was created by osTimerCreate
 */
osStatus osTimerDelete(osTimerId timer_id)
{
	struct timer_obj *timer = (struct timer_obj *) timer_id;

	if (timer == NULL) {
		return osErrorParameter;
	}

	if (k_is_in_isr()) {
		return osErrorISR;
	}

	if (timer->status == ACTIVE) {
		k_timer_stop(&timer->ztimer);
		timer->status = NOT_ACTIVE;
	}

	k_mem_slab_free(&cmsis_timer_slab, (void *) &timer);
	return osOK;
}
Thanks and regards
Ajit S J
  • Hi Ajit

    Can you let me know which SDK version you are using?

    The packets are transmitted at 992HZ and received at 4HZ. We have modified the "cmsis_timer.c" file to create a microsecond timer.

    The payload for transmit is 21bytes and for receive is 9bytes respectively.

    We enable the receive initially and we have setup a timer for 992Hz timing. Inside the timer callback function we stop the receive, start the transmit and then start the receive functions respectively.

    Have you considered using the ACK payload mechanism to achieve bidirectional communication rather than switching between PRX and PTX mode? 

    By doing this you should be able to simply transmit your packets at 992Hz, and then upload an ACK payload at a 4Hz frequency on the PRX side, making for a more streamlined implementation. 

    We have modified the PTX "main.c" and "esb.c" file

    Before I dig into the code would you be able to summarize the changes you made to the esb.c file, and the reasoning behind them? 

    We would want to get transmit and receive working together without this print statement.

    I expect the timer callback to run in interrupt context, and in general it is a bit risky to run a lot of code in interrupt context directly. 

    Could you try to simply set a flag in the timer callback, and check this flag in you while loop? 

    Alternatively you could do this the 'Zephyr way' and use a work item to schedule your code to be run from thread context rather than interrupt context (more info here). 

    Finally, I see that you commented out the call to k_sleep(..) at the end of your while loop. This is a bit risky as it will make the main thread run continuously, not yielding to other threads that might want to run. I would recommend re-introducing this delay, but you don't need the delay to be very long.

    Best regards
    Torbjørn

  • Hi  ,

    Thanks for your reply. Please find my answers below commented in bold letters.

    Can you let me know which SDK version you are using?
    Ajit:2.1.0

    Have you considered using the ACK payload mechanism to achieve bidirectional communication rather than switching between PRX and PTX mode?
    By doing this you should be able to simply transmit your packets at 992Hz, and then upload an ACK payload at a 4Hz frequency on the PRX side, making for a more streamlined implementation.
    Ajit:The ACK payload mechanism does not work with our protocol. The patient monitor that we have cannot have the ACK mechanism in the protocol.


    We have modified the PTX "main.c" and "esb.c" file
    Before I dig into the code would you be able to summarize the changes you made to the esb.c file, and the reasoning behind them?
    Ajit: I have created a patch with all the differences between the original "esb.c" file and the "esb.c" file with our changes. I have summarized the changes below.

    • Reduced the tx and rx payload buffer length's by 2 as we are not using ACK.
    • The "S0", "S1" and "LF" length values are made zero in the PCNF0 register.
    • The CRCPOLY value changed to "0x1021UL"
    • Updated the payload copying code to get rid of the ACK data fields.
    • Created new PPI channel configuration for rx functionality.
    • Removed the ACK related handler in start_tx_transaction() function with the help of below mentioned code change.
      on_radio_disabled = on_radio_disabled_tx_noack;
      esb_state = ESB_STATE_PTX_TX;
    • Created separate "esb_init_rx" and "esb_init_tx" functions from the "esb_init" function to initialize tx and rx separately.
    • Created a separate mband_frequency_set() function to set the operating radio frequency to 2360MHz.
    • Added changes to FREQUENCY register assignment to update only the frequency bits with the help of "RADIO_FREQUENCY_FREQUENCY_Msk"

    We would want to get transmit and receive working together without this print statement.
    I expect the timer callback to run in interrupt context, and in general it is a bit risky to run a lot of code in interrupt context directly.


    Could you try to simply set a flag in the timer callback, and check this flag in you while loop?
    Ajit: Yes, I tried this change. But the behavior is still the same even after the change. 

    Alternatively you could do this the 'Zephyr way' and use a work item to schedule your code to be run from thread context rather than interrupt context (more info here).
    Ajit: We ideally do not want much of the zephyr RTOS to be run in our code. We want it to be as much standalone as it can.

    Finally, I see that you commented out the call to k_sleep(..) at the end of your while loop. This is a bit risky as it will make the main thread run continuously, not yielding to other threads that might want to run. I would recommend re-introducing this delay, but you don't need the delay to be very long.

    Ajit: Yes, I added k_sleep(K_USEC(1)); at the end of while loop. But the behavior is still the same even after the change. 

    I am attaching the patch file which has differences in the esb.c file and the main.c file which has the changes done as per your suggestions. However the changes did not help us. Still the tx and rx works when the printk("\n  \n"); statement is enabled after esb_write_payload(&tx_payload); function call.

    esb_difference.patch

    /*
     * Copyright (c) 2018 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
     */
    #include <zephyr/drivers/clock_control.h>
    #include <zephyr/drivers/clock_control/nrf_clock_control.h>
    #include <zephyr/drivers/gpio.h>
    #include <zephyr/irq.h>
    #include <zephyr/logging/log.h>
    #include <nrf.h>
    #include <esb.h>
    #include <zephyr/device.h>
    #include <zephyr/devicetree.h>
    #include <zephyr/kernel.h>
    #include <zephyr/types.h>
    #include <zephyr/zephyr.h>
    #include <cmsis_os.h>
    #include <sys/printk.h>
    // #include <sys/unistd.h>
    // #include <zephyr/posix/unistd.h>
    
    /* specify delay between greetings (in us); compute equivalent in ticks */
    // #define TIMER_TICKS  1008
    #define TIMER_TICKS 978
    #define DELAY_TIMER_TICKS 250
    #define TIMER_SEC_TICKS  1000000
    #define ECG_FW_CH_LENTYPE 0x5A // 5A for MR400. 59 for Expression
    #define ECG_FW_CH_PREAMBLE 0xAA
    #define TOT_CMD_DATA_BYTES 4
    #define TOT_SPARE_BYTES 3
    #define TOT_ADDRESS_BYTES 4
    #define TOT_ECG_DATA_BYTES 18
    #define TOT_FWC_BYTES 26
    
    #define NELEMS(x) (sizeof(x) / sizeof((x)[0]))
    
    extern int dbg_events[];
    extern int dbg_events_idx;
    extern bool end_event;
    extern bool tx_start_event;
    void timer_callback(void const *arg);
    void delay_function(void);
    void delay_timer_callback(void const *arg);
    osTimerDef(myTimer, timer_callback);
    osTimerDef(myTimer_delay, delay_timer_callback);
    
    //One second timer for debug print of total messages transmitted and received over past second
    void sec_timer_callback(void const *arg);
    osTimerDef(my_sec_timer, sec_timer_callback);
    
    //Back channel message received for channel selection (commands 0x04 and 0x05)
    unsigned char channel1_filter = 0x03;
    unsigned char channel2_filter = 0x03;
    int filter_recvd;
    bool transmit_data_flag = false;
    
    //Functions to set LED's 3 and 4 to visually indicate filter selection
    int channel1_filter_led_set(void);
    int channel2_filter_led_set(void);
    void decimalToBinary(int num, int *val1, int *val2);
    
    //Initialize ECG Packet for Forward Channel Transmission at 992 Hz
    void initFwdChData(void);
    void transmit_data(void);
    void create_fwc_packet(void);
    
    //Channel 4 setting for Primary frequency of 2.440 GHz and Secondary frequency of 2.448 GHz
    typedef enum hop_frequency
    {
    	primary_hop = 40,
    	secondary_hop = 48
    } hop_values;
    
    int frequency_hop;
    int network;
    int networkGroup;
    unsigned int networkAddress;
    int counter;
    bool packet_tx_done = true;
    bool packet_ready = true;
    bool delay_timer_flag = false;
    
    //Counters for numer of TX messages and RX messages since last reset (1 second)
    int				second_rx_cnt=0;
    int				second_tx_cnt=0;
    
    //ECG data sample variables for 2 Leads and 3 time slices (T0, T1, T2)
    short int ch1DataA;
    short int ch1DataB;
    short int ch1DataC;
    short int ch2DataA;
    short int ch2DataB;
    short int ch2DataC;
    
    int rawLeadDataCh1;
    int rawLeadDataCh2;
    int led_count;
    
    int led_value = 0;
    osTimerId delay_timer_id;
    bool tx_delay_done = false;
    bool			print_metrics = false;
    
    //ECG Waveform Simulation Array from MR400 divided by 10
    static const short ECG_DAT[] = {
    	-34, -32, -23, -23, -18, -18, -18, -12, -15, -20,
    	-11, -18, -29, -32, -34, -29, -25, -28, -32, -19,
    	-15, -6, -13, -16, -21, -21, -20, -14, -25, -28,
    	-38, -36, -30, -28, -37, -25, -20, -13, -11, -9,
    	-14, -18, -13, -17, -27, -28, -35, -39, -35, -31,
    	-33, -36, -32, -25, -13, -17, -20, -13, -14, -15,
    	-24, -25, -30, -29, -41, -35, -32, -39, -25, -19,
    	-20, -16, -14, -18, -10, -7, -14, -15, -31, -27,
    	-33, -29, -35, -23, -24, -19, -9, -8, -10, -12,
    	-5, -7, -10, -9, -24, -31, -32, -33, -40, -36, // 100
    	-29, -26, -17, -17, -11, -8, -12, -5, -3, -11,
    	-13, -19, -29, -35, -32, -26, -26, -25, -18, -19,
    	-15, -5, -6, -12, -14, -18, -18, -23, -32, -35,
    	-25, -32, -28, -33, -27, -17, -14, -7, -14, -5,
    	-10, -8, -18, -10, -18, -31, -27, -37, -31, -30,
    	-28, -19, -6, -1, -1, -1, 6, 3, 10, 8,
    	12, 1, 9, 6, 10, 14, 23, 18, 31, 36,
    	46, 52, 49, 56, 56, 56, 50, 52, 49, 39,
    	40, 46, 48, 51, 51, 55, 63, 65, 66, 73,
    	69, 73, 68, 58, 57, 50, 46, 50, 43, 42, // 200
    	52, 55, 50, 61, 57, 54, 60, 47, 45, 37,
    	36, 19, 19, 20, 13, 16, 9, 11, 18, 16,
    	20, 22, 17, 13, 4, -2, -14, -18, -26, -32,
    	-29, -36, -25, -27, -22, -13, -12, -14, -15, -8,
    	-9, -12, -10, -13, -32, -33, -33, -28, -25, -31,
    	-28, -20, -19, -14, -10, -14, -6, -4, -13, -14,
    	-20, -31, -37, -34, -28, -28, -28, -20, -21, -18,
    	-19, -19, -12, -15, -8, -9, -27, -35, -38, -27,
    	-34, -30, -34, -28, -17, -15, -7, -15, -6, -12,
    	-10, -8, -13, -21, -22, -30, -28, -34, -32, -29, // 300
    	-19, -18, -12, -12, -12, -17, -9, -15, -18, -25,
    	-36, -29, -32, -39, -34, -37, -41, -39, -34, -35,
    	-41, -43, -49, -49, -61, -68, -79, -82, -81, -81,
    	-53, -41, -28, 6, 32, 62, 99, 123, 154, 187,
    	217, 249, 277, 301, 331, 363, 391, 431, 452, 484,
    	522, 540, 563, 572, 571, 557, 548, 539, 511, 490,
    	452, 417, 382, 350, 313, 279, 240, 218, 176, 153,
    	117, 88, 60, 28, 0, -34, -60, -79, -85, -96,
    	-106, -110, -116, -103, -98, -99, -91, -80, -73, -72,
    	-59, -54, -54, -46, -45, -45, -40, -38, -45, -43, // 400
    	-36, -37, -32, -29, -34, -38, -34, -29, -30, -47,
    	-44, -50, -47, -42, -43, -43, -37, -38, -35, -24,
    	-37, -30, -32, -24, -24, -41, -49, -51, -41, -48,
    	-44, -48, -43, -33, -31, -24, -31, -23, -28, -26,
    	-23, -27, -35, -36, -44, -41, -36, -35, -45, -35,
    	-21, -28, -15, -27, -20, -23, -17, -20, -28, -27,
    	-32, -35, -30, -38, -28, -32, -31, -25, -15, -9,
    	-12, -6, -7, -7, -15, -25, -28, -25, -24, -30,
    	-15, -23, -23, -6, 2, 4, 5, -1, 7, 0,
    	-5, -3, -17, -11, -15, -11, -18, -7, -10, -6, // 500
    	1, 13, 8, 6, 13, 11, 9, 12, -1, -6,
    	-5, -5, -11, -8, -2, 0, 7, 17, 20, 22,
    	17, 25, 16, 21, 9, 5, 9, 3, 7, 12,
    	0, 11, 17, 26, 28, 25, 35, 30, 40, 36,
    	37, 21, 26, 25, 24, 17, 22, 17, 22, 31,
    	44, 37, 41, 48, 42, 43, 46, 43, 36, 37,
    	30, 33, 39, 41, 42, 51, 51, 56, 67, 65,
    	71, 67, 74, 71, 65, 55, 52, 62, 56, 61,
    	70, 64, 76, 79, 87, 92, 88, 94, 93, 94,
    	88, 79, 78, 69, 72, 78, 80, 83, 82, 85, // 600
    	91, 92, 104, 97, 93, 98, 82, 74, 74, 68,
    	65, 70, 63, 61, 69, 71, 77, 75, 81, 77,
    	71, 71, 70, 62, 51, 48, 37, 39, 44, 35,
    	39, 39, 44, 41, 44, 34, 29, 25, 29, 12,
    	13, -2, -10, -15, -23, -30, -19, -22, -29, -21,
    	-21, -12, -15, -21, -22, -24, -33, -35, -53, -52,
    	-52, -59, -55, -50, -48, -41, -42, -37, -34, -39,
    	-31, -29, -36, -37, -53, -50, -55, -52, -58, -46,
    	-47, -41, -43, -28, -31, -32, -37, -39, -30, -42,
    	-45, -53, -55, -56, -51, -48, -53, -48, -51, -49, // 700
    	-41, -49, -40, -45, -31, -41, -45, -52, -52, -49,
    	-58, -53, -51, -49, -40, -39, -33, -33, -32, -25,
    	-29, -22, -25, -33, -43, -48, -50, -45, -52, -43,
    	-36, -35, -31, -22, -28, -19, -24, -24, -24, -30,
    	-40, -42, -51, -49, -43, -53, -49, -50, -34, -39,
    	-25, -25, -31, -23, -30, -34, -43, -43, -49, -52,
    	-48, -43, -44, -48, -45, -26, -28, -21, -24, -29,
    	-30, -31, -27, -39, -43, -42, -53, -47, -44, -51,
    	-37, -32, -34, -31, -29, -22, -27, -23, -29, -29,
    	-44, -51, -56, -39, -46, -47, -36, -32, -23, -23, // 800
    	-26, -28, -21, -22, -25, -23, -37, -43, -44, -44,
    	-50, -47, -40, -38, -30, -31, -25, -22, -27, -19,
    	-17, -25, -26, -43, -40, -46, -43, -37, -37, -38,
    	-31, -20, -18, -20, -21, -14, -16, -20, -19, -35,
    	-43, -45, -46, -41, -37, -43, -38, -41, -27, -20,
    	-28, -20, -25, -23, -20, -23, -30, -30, -38, -35,
    	-42, -40, -38, -29, -28, -23, -24, -24, -17, -21,
    	-15, -17, -24, -35, -39, -40, -47, -41, -44, -36,
    	-24, -21, -12, -20, -23, -17, -17, -17, -23, -32,
    	-33, -42, -39, -33, -43, -39, -28, -25, -18, -17, // 900
    	-17, -23, -15, -22, -26, -23, -35, -41, -43, -38,
    	-33, -35, -27, -24, -18, -20, -13, -16, -21, -21,
    	-22, -18, -30, -34, -33, -32, -39, -36, -31, -30,
    	-24, -15, -11, -9, -14, -18, -14, -20, -19, -34,
    	-30, -35, -32, -39, -40, -29, -24, -16, -15, -6,
    	-8, -14, -15, -17, -14, -28, -34, -35, -35, -42,
    	-39, -33, -31, -23, -24, -19, -16, -20, -12, -9,
    	-17, -18, -35, -32, -38, -35, -30, -30, -30, -24,
    	-25, -22, -12, -13, -18, -20, -12, -12, -29, -37,
    	-39, -28, -32768};
    
    int total_items_ecg_dat = NELEMS(ECG_DAT);
    
    //Structure used to set up Nordic Radio Packet and settings
    typedef struct NetTable_t
    {
    	unsigned int addr;
    	char cfgHi;
    	char cfgLo1;
    	char cfgLo2;
    } NetTable;
    
    //Table of Address Bytes, CFGHi, CFGLo1, and CFGLo2 for Channels 1-10
    NetTable NetworkTable[] =
    	{
    		{0xBB44BBB5, 0xAF, 138, 154},
    		{0x9B449B95, 0xAF, 72, 88},
    		{0xBA44BAB5, 0xAF, 74, 90},
    		{0x99449996, 0xAF, 80, 96},
    		{0xA944A9A5, 0xAF, 70, 86},
    		{0xA6565656, 0xAF, 144, 160},
    		{0xC5556666, 0xAF, 110, 126},
    		{0xA6669999, 0xAF, 108, 124},
    		{0x96969696, 0xAF, 116, 132},
    		{0xCCCC5555, 0xAF, 106, 122},
    		{0xBBBBBBBB, 0xAF, 4, 20},
    		{0x9B9B9B9B, 0xAF, 6, 22},
    		{0xBABABABA, 0xAF, 12, 28},
    		{0x99999999, 0xAF, 14, 30},
    		{0xA9A9A9A9, 0xAF, 36, 52}
    	};
    
    // Structure for ECG Forward Channel Packet
    typedef struct
    {
    	//	char 	wPreamble;
    	//	char 	wAddress[TOT_ADDRESS_BYTES];
    	char wLenType;
    	char wECGData[TOT_ECG_DATA_BYTES];
    	char wEcgSeqNumber;
    	char wEcgStatusData;
    } EcgForwardChannelPacket;
    
    static EcgForwardChannelPacket EcgFWCPckt = {
    	//		 0x00,
    	//	    {0x00,0x00,0x00,0x00},
    	0x00,
    	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
    	0x00,
    	0x00};
    
    LOG_MODULE_REGISTER(esb_ptx, CONFIG_ESB_PTX_APP_LOG_LEVEL);
    #if 0
    static const struct gpio_dt_spec leds[] = {
    	GPIO_DT_SPEC_GET(DT_ALIAS(led0), gpios),
    	GPIO_DT_SPEC_GET(DT_ALIAS(led1), gpios),
    	GPIO_DT_SPEC_GET(DT_ALIAS(led2), gpios),
    	GPIO_DT_SPEC_GET(DT_ALIAS(led3), gpios),
    };
    
    BUILD_ASSERT(DT_SAME_NODE(DT_GPIO_CTLR(DT_ALIAS(led0), gpios),
    			  DT_GPIO_CTLR(DT_ALIAS(led1), gpios)) &&
    	     DT_SAME_NODE(DT_GPIO_CTLR(DT_ALIAS(led0), gpios),
    			  DT_GPIO_CTLR(DT_ALIAS(led2), gpios)) &&
    	     DT_SAME_NODE(DT_GPIO_CTLR(DT_ALIAS(led0), gpios),
    			  DT_GPIO_CTLR(DT_ALIAS(led3), gpios)),
    	     "All LEDs must be on the same port");
    #endif
    
    /* The devicetree node identifier for the "led3" alias. */
    #define LED0_NODE DT_ALIAS(led0)
    static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios);
    #define LED1_NODE DT_ALIAS(led1)
    static const struct gpio_dt_spec led_1 = GPIO_DT_SPEC_GET(LED1_NODE, gpios);
    #define LED2_NODE DT_ALIAS(led2)
    static const struct gpio_dt_spec led_3 = GPIO_DT_SPEC_GET(LED2_NODE, gpios);
    #define LED3_NODE DT_ALIAS(led3)
    static const struct gpio_dt_spec led_4 = GPIO_DT_SPEC_GET(LED3_NODE, gpios);
    int led_count;
    
    static bool ready = false;
    static struct esb_payload rx_payload;
    
    static struct esb_payload tx_payload = ESB_CREATE_PAYLOAD(0,
    														  0x00,
    														  0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    														  0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    														  0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    														  0x00,
    														  0x00);
    
    #define _RADIO_SHORTS_COMMON                                       \
    	(RADIO_SHORTS_READY_START_Msk | RADIO_SHORTS_END_DISABLE_Msk | \
    	 RADIO_SHORTS_ADDRESS_RSSISTART_Msk |                          \
    	 RADIO_SHORTS_DISABLED_RSSISTOP_Msk)
    
    //Function to Process Nordic Events
    void event_handler(struct esb_evt const *event)
    {
    	ready = true;
    
    	switch (event->evt_id)
    	{
    	case ESB_EVENT_TX_SUCCESS:
    		// LOG_DBG("TX SUCCESS EVENT");
    		break;
    	case ESB_EVENT_TX_FAILED:
    		LOG_DBG("TX FAILED EVENT");
    		break;
    	case ESB_EVENT_RX_RECEIVED:
    		if (esb_read_rx_payload(&rx_payload) == 0)
    		{
    #if 0
    			LOG_DBG("Packet received, len %d, data: "
    				"0x%02x, 0x%02x, 0x%02x, 0x%02x, "
    				"0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x ",
    				rx_payload.length, rx_payload.data[0],
    				rx_payload.data[1], rx_payload.data[2],
    				rx_payload.data[3], rx_payload.data[4],
    				rx_payload.data[5], rx_payload.data[6],
    				rx_payload.data[7],rx_payload.data[8]);
    #endif
    #if 0
    				if(rx_payload.data[1] == 0x04)
    				{
    					printk("Filter data 0x04 : 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x \r\n",rx_payload.data[1], rx_payload.data[2],
    				rx_payload.data[3], rx_payload.data[4], rx_payload.data[5]);
    					channel1_filter = rx_payload.data[2];
    					//filter_recvd = 1;
    
    				}
    #endif
    			//if ((rx_payload.data[1] == 0x05) && (channel2_filter != rx_payload.data[2]))
    			if (rx_payload.data[1] == 0x05)
    			{
    
    				printk("Filter data 0x05 : 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x \r\n", rx_payload.data[1], rx_payload.data[2],
    					   rx_payload.data[3], rx_payload.data[4], rx_payload.data[5]);
    				
    				if (channel2_filter != rx_payload.data[2])
    				{
    					channel2_filter = rx_payload.data[2];
    					filter_recvd = 2;
    				}
    			}
    			second_rx_cnt++;	
    
    		}
    		break;
    	}
    }
    
    //Function to start system clocks
    int clocks_start(void)
    {
    	int err;
    	int res;
    	struct onoff_manager *clk_mgr;
    	struct onoff_client clk_cli;
    
    	clk_mgr = z_nrf_clock_control_get_onoff(CLOCK_CONTROL_NRF_SUBSYS_HF);
    	if (!clk_mgr)
    	{
    		LOG_ERR("Unable to get the Clock manager");
    		return -ENXIO;
    	}
    
    	sys_notify_init_spinwait(&clk_cli.notify);
    
    	err = onoff_request(clk_mgr, &clk_cli);
    	if (err < 0)
    	{
    		LOG_ERR("Clock request failed: %d", err);
    		return err;
    	}
    
    	do
    	{
    		err = sys_notify_fetch_result(&clk_cli.notify, &res);
    		if (!err && res)
    		{
    			LOG_ERR("Clock could not be started: %d", res);
    			return res;
    		}
    	} while (err);
    
    	LOG_DBG("HF clock started");
    	return 0;
    }
    
    //Function to initialize Nordic Radio at Start Up for RX
    int esb_initialize(void)
    {
    	int err;
    	 
    	//Nordic radio can have 8 Address Bytes.  MR400 implementation uses 4 Address Bytes in base_addr_0
    	uint8_t base_addr_0[4] = {0x99, 0x44, 0x99, 0x96};
    	uint8_t base_addr_1[4] = {0x00, 0x00, 0x00, 0x00};
    
    	//Nordic address prefix MR400 uses 1 and it is set to LS Byte of Address Bytes
    	uint8_t addr_prefix[8] = {0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
    
    	struct esb_config config = ESB_DEFAULT_CONFIG;
    
    	config.protocol = ESB_PROTOCOL_ESB;
    	config.retransmit_delay = 600;
    	config.bitrate = ESB_BITRATE_1MBPS;
    	config.event_handler = event_handler;
    	config.mode = ESB_MODE_PRX;
    	config.selective_auto_ack = true;
    	config.payload_length = 9;
    
    	err = esb_init(&config);
    
    	if (err)
    	{
    		printk("esb_init failed \r\n");
    		return err;
    	}
    
    	err = esb_set_base_address_0(base_addr_0);
    	if (err)
    	{
    		return err;
    	}
    
    	err = esb_set_base_address_1(base_addr_1);
    	if (err)
    	{
    		return err;
    	}
    
    	err = esb_set_prefixes(addr_prefix, ARRAY_SIZE(addr_prefix));
    	if (err)
    	{
    		return err;
    	}
    	tx_payload.noack = 1;
    	rx_payload.noack = 1;
    
    	return 0;
    }
    
    //Function to set Nordic Radio in TX mode
    int esb_initialize_tx(void)
    {
    	int err;
    
    
    	struct esb_config config = ESB_DEFAULT_CONFIG;
    
    	config.protocol = ESB_PROTOCOL_ESB;
    	config.retransmit_delay = 600;
    	config.bitrate = ESB_BITRATE_1MBPS;
    	config.event_handler = event_handler;
    	config.mode = ESB_MODE_PTX;
    	config.selective_auto_ack = true;
    	config.payload_length = 21;
    
    	err = esb_init_tx(&config);
    
    	if (err)
    	{
    		return err;
    	}
    
    	return 0;
    }
    
    //Function to set Nordic Radio in RX mode
    int esb_initialize_rx(void)
    {
    	int err;
    
    
    	struct esb_config config = ESB_DEFAULT_CONFIG;
    
    	config.protocol = ESB_PROTOCOL_ESB;
    	config.retransmit_delay = 600;
    	config.bitrate = ESB_BITRATE_1MBPS;
    	config.event_handler = event_handler;
    	config.mode = ESB_MODE_PRX;
    	config.selective_auto_ack = true;
    	config.payload_length = 9;
    
    	err = esb_init_rx(&config);
    	if (err)
    	{
    		return err;
    	}
    
    	return 0;
    }
    
    //Function to initialize LED's 1, 3, 4
    static int leds_init(void)
    {
    	int ret = 0;
    
    	if (!device_is_ready(led.port))
    	{
    		printk(" error device_is_ready \r\n");
    		return -ENODEV;
    	}
    
    	ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
    	if (ret < 0)
    	{
    		printk(" error gpio_pin_configure_dt \r\n");
    		return -2;
    	}
    
    	if (!device_is_ready(led_1.port))
    	{
    		printk(" error device_is_ready \r\n");
    		return -ENODEV;
    	}
    
    	ret = gpio_pin_configure_dt(&led_1, GPIO_OUTPUT_ACTIVE);
    	if (ret < 0)
    	{
    		printk(" error gpio_pin_configure_dt \r\n");
    		return -2;
    	}
    
    	if (!device_is_ready(led_3.port))
    	{
    		printk(" error device_is_ready \r\n");
    		return -ENODEV;
    	}
    
    	ret = gpio_pin_configure_dt(&led_3, GPIO_OUTPUT_ACTIVE);
    	if (ret < 0)
    	{
    		printk(" error gpio_pin_configure_dt \r\n");
    		return -2;
    	}
    
    	if (!device_is_ready(led_4.port))
    	{
    		printk(" error device_is_ready \r\n");
    		return -ENODEV;
    	}
    
    	ret = gpio_pin_configure_dt(&led_4, GPIO_OUTPUT_ACTIVE);
    	if (ret < 0)
    	{
    		printk(" error gpio_pin_configure_dt \r\n");
    		return -2;
    	}
    
    	return 0;
    }
    
    //Function to initialize the Forward Channel Message.
    void initFwdChData(void)
    {
    	int ret = 0;
    	// Each FWC packet consists of 28 bytes (26 data bytes + 2 CRC bytes) which is transmitted at a rate of 992 Hz (1.008065 ms)
    	// 1. Header - Preamble (8 Bits) + Address (32 Bits) + Length (4 Bits) + Type (4 Bits)
    	// 2. ECG DATA "A" - Data1 (16 bits) + Data2 (16 Bits) + Data3 (16 bits)
    	// 3. ECG DATA "B" - Data1 (16 bits) + Data2 (16 Bits) + Data3 (16 bits)
    	// 4. ECG DATA "C" - Data1 (16 bits) + Data2 (16 Bits) + Data3 (16 bits)
    	// 5. Status Information - Status Code (8 bits) + Status Data (8 bits)
    	// 6. CRC - CRC data (16 bits). The CRC bytes are calculated by the Radio firmware block and not calculated here.
    
    	// EcgFWCPckt.wPreamble = ECG_FW_CH_PREAMBLE; // Preamble
    	EcgFWCPckt.wLenType = ECG_FW_CH_LENTYPE; // Length/type
    	EcgFWCPckt.wEcgSeqNumber = 0x00;
    	EcgFWCPckt.wEcgStatusData = 0x00;
    
    	network = 4;
    	// Get the Network Address from the network table
    	networkAddress = NetworkTable[network - 1].addr;
    
    	// EcgFWCPckt.wAddress[0] = (networkAddress >> 24) & 0xFF;
    	// EcgFWCPckt.wAddress[1] = (networkAddress >> 16) & 0xFF;
    	// EcgFWCPckt.wAddress[2] = (networkAddress >> 8) & 0xFF;
    	// EcgFWCPckt.wAddress[3] = networkAddress & 0xFF;
    
    	ch1DataA = 0;
    	ch1DataB = 0;
    	ch1DataC = 0;
    	ch2DataA = 0;
    	ch2DataB = 0;
    	ch2DataC = 0;
    
    	// ECG DATA "A"
    	// DATA 1
    	EcgFWCPckt.wECGData[0] = ch1DataA & 0xFF;
    	EcgFWCPckt.wECGData[1] = (ch1DataA & 0xFF00) >> 8;
    
    	// DATA 2
    	EcgFWCPckt.wECGData[2] = ch2DataA & 0xFF;
    	EcgFWCPckt.wECGData[3] = (ch2DataA & 0xFF00) >> 8;
    
    	// DATA 3
    	// The 0x55 value for Data A-3 prevents a long series of 0 bit values
    	// in the packet transmission
    	EcgFWCPckt.wECGData[4] = 0x55;
    	EcgFWCPckt.wECGData[5] = 0x55;
    
    	// ECG DATA "B"
    	// DATA 1
    	EcgFWCPckt.wECGData[6] = ch1DataB & 0xFF;
    	EcgFWCPckt.wECGData[7] = (ch1DataB & 0xFF00) >> 8;
    
    	// DATA 2
    	EcgFWCPckt.wECGData[8] = ch2DataB & 0xFF;
    	EcgFWCPckt.wECGData[9] = (ch2DataB & 0xFF00) >> 8;
    
    	// DATA 3
    	// The 0x55 value for Data B-3 prevents a long series of 0 bit values
    	// in the packet transmission
    	EcgFWCPckt.wECGData[10] = 0x55;
    	EcgFWCPckt.wECGData[11] = 0x55;
    
    	// ECG DATA "C"
    	// DATA 1
    	EcgFWCPckt.wECGData[12] = ch1DataC & 0xFF;
    	EcgFWCPckt.wECGData[13] = (ch1DataC & 0xFF00) >> 8;
    
    	// DATA 2
    	EcgFWCPckt.wECGData[14] = ch2DataC & 0xFF;
    	EcgFWCPckt.wECGData[15] = (ch2DataC & 0xFF00) >> 8;
    
    	// DATA 3
    	// The 0x55 value for Data C-3 prevents a long series of 0 bit values
    	// in the packet transmission
    	EcgFWCPckt.wECGData[16] = 0x55;
    	EcgFWCPckt.wECGData[17] = 0x55;
    
    	// Status Code/ Sequence #
    	EcgFWCPckt.wEcgSeqNumber++;
    	EcgFWCPckt.wEcgSeqNumber = EcgFWCPckt.wEcgSeqNumber & 0xFF;
    	bool packet_tx_done = true;
    	bool packet_ready = false;
    
    	channel2_filter = 0x03;
    	channel1_filter = 0x03;
    
    	// Set the radio frequency and start rx
    	frequency_hop = primary_hop;
    	esb_set_rf_channel(frequency_hop);
    	esb_start_rx();
    	frequency_hop = secondary_hop;
    
    	ret = gpio_pin_set(led_3.port, led_3.pin, 0);
    	if (ret)
    	{
    		LOG_ERR("LED3 set 1 error: %d", ret);
    	}
    	ret = gpio_pin_set(led_4.port, led_4.pin, 1);
    	if (ret)
    	{
    		LOG_ERR("LED4 set 1 error: %d", ret);
    	}
    }
    
    void delay_function(void)
    {
    	delay_timer_flag = true;
    	while (delay_timer_flag == false);
    }
    
    void delay_timer_callback(void const *arg)
    {
    	tx_delay_done = true;
    }
    
    void sec_timer_callback(void const *arg)
    {
    	print_metrics = true;
    }
    
    void decimalToBinary(int num, int *val1, int *val2) {
    	// Stores binary representation of number.
    	int binaryNum[3] = {0, 0, 0}; // Assuming 32 bit integer.
    	int i = 0;
    
    	for (; num > 0;)
    	{
    		binaryNum[i++] = num % 2;
    		num /= 2;
    	}
    
    	*val1 = binaryNum[1];
    	*val2 = binaryNum[0];
    }
    
    int channel1_filter_led_set(void)
    {
    
    	int ret = 0, value_led2 = 0, value_led4 = 0;
    
    	decimalToBinary((channel1_filter - 2), &value_led2, &value_led4);
    
    	ret = gpio_pin_set(led_3.port, led_3.pin, value_led2);
    	if (ret)
    	{
    		LOG_ERR("LED3 set 1 error: %d", ret);
    	}
    
    	ret = gpio_pin_set(led_4.port, led_4.pin, value_led4);
    	if (ret)
    	{
    		LOG_ERR("LED4 set 1 error: %d", ret);
    	}
    }
    
    int channel2_filter_led_set(void)
    {
    
    	int ret = 0, value_led2 = 0, value_led4 = 0;
    	decimalToBinary((channel2_filter - 2), &value_led2, &value_led4);
    
    	ret = gpio_pin_set(led_3.port, led_3.pin, value_led2);
    	if (ret)
    	{
    		LOG_ERR("LED3 set 1 error: %d", ret);
    	}
    
    	ret = gpio_pin_set(led_4.port, led_4.pin, value_led4);
    	if (ret)
    	{
    		LOG_ERR("LED4 set 1 error: %d", ret);
    	}
    	filter_recvd = 0;
    }
    
    void transmit_data(void)
    {
    	int ret = 0, err = 0;
    		esb_stop_rx();
    
    		// delay_function();
    		esb_set_rf_channel(frequency_hop);
    
    		esb_initialize_tx();
    
    		// delay_function();
    
    		esb_flush_tx();
    
    
    		err = esb_write_payload(&tx_payload);
    		if (err)
    		{
    			LOG_ERR("Payload write failed, err %d", err);
    		}
    
    		second_tx_cnt++;
    
    		esb_flush_tx();
    		// delay_function();
    		// turn off/on led
    		// usleep(10);
    		// k_sleep(K_USEC(10));
    		// printk("\r\n Inside timer handler, after write payload \r\n");
    		printk("\n  \n");
    		//if (esb_is_idle() != true)
    		//{
    		//	printk("ESB not idle \r\n");
    		//}
    		//printk("\r     \r");
    		//printk("\r\r\r\r\r\r\r\r\r\r\n");
    		packet_tx_done = true;
    		//printk("BEfore while \r\n");
    		//while((tx_start_event == true)&&(end_event == false))
    		//{
    			
    			
    		//}
    		//printk("tx complete\r\n");
    		//tx_start_event = false;
    		//end_event = false;
    		//esb_stop_tx();
    
    #if 0
    	led_value = !led_value;
    	printk("led_value : %d \r\n",led_value);
    	ret = gpio_pin_set(&led_1.port, led_1.pin, led_value);
    	if (ret) {
    		LOG_ERR("LED1 set 0 error: %d", ret);
    	}
    
    #endif
    		ret = gpio_pin_toggle_dt(&led_1);
    		if (ret < 0)
    		{
    			return;
    		}
    
    		esb_set_rf_channel(primary_hop);
    		esb_initialize_rx();
    		// delay_function();
    		esb_start_rx();
    
    }
    
    void create_fwc_packet(void)
    {
    
    		int err, i = 0, ret = 0;
    			//********************* Tasks to do *************
    			//	1. Set a frequency variable to Primary or Secondary frequency for next transmission based on hopping pattern/network
    			//************************************************
    
    			if (frequency_hop == primary_hop)
    			{
    				frequency_hop = secondary_hop;
    			}
    			else if (frequency_hop == secondary_hop)
    			{
    				frequency_hop = primary_hop;
    			}
    			else
    			{
    				frequency_hop = primary_hop;
    			}
    
    			// At Max QRS value, set LED 4 ON
    			if (ECG_DAT[counter] == -572)
    			{
    				// turn on led
    				ret = gpio_pin_set(&led, led.pin, 1);
    				if (ret)
    				{
    					LOG_ERR("LED3 set 1 error: %d", ret);
    				}
    				led_count = 1;
    			}
    
    			// Move T-1 Data to T-2 Data and T Data to T-1 Data
    			ch1DataC = ch1DataB;
    			ch2DataC = ch2DataB;
    			ch1DataB = ch1DataA;
    			ch2DataB = ch2DataA;
    
    			ch1DataA = ECG_DAT[counter];
    			ch2DataA = ECG_DAT[counter];
    
    			// ECG DATA "A"
    			// DATA 1
    			EcgFWCPckt.wECGData[0] = ch1DataA & 0xFF;
    			EcgFWCPckt.wECGData[1] = (ch1DataA & 0xFF00) >> 8;
    
    			// DATA 2
    			EcgFWCPckt.wECGData[2] = ch2DataA & 0xFF;
    			EcgFWCPckt.wECGData[3] = (ch2DataA & 0xFF00) >> 8;
    
    			// DATA 3
    			// The 0x55 value for Data A-3 prevents a long series of 0 bit values
    			// in the packet transmission
    			EcgFWCPckt.wECGData[4] = 0x55;
    			EcgFWCPckt.wECGData[5] = 0x55;
    
    			// ECG DATA "B"
    			// DATA 1
    			EcgFWCPckt.wECGData[6] = ch1DataB & 0xFF;
    			EcgFWCPckt.wECGData[7] = (ch1DataB & 0xFF00) >> 8;
    
    			// DATA 2
    			EcgFWCPckt.wECGData[8] = ch2DataB & 0xFF;
    			EcgFWCPckt.wECGData[9] = (ch2DataB & 0xFF00) >> 8;
    
    			// DATA 3
    			// The 0x55 value for Data B-3 prevents a long series of 0 bit values
    			// in the packet transmission
    			EcgFWCPckt.wECGData[10] = 0x55;
    			EcgFWCPckt.wECGData[11] = 0x55;
    
    			// ECG DATA "C"
    			// DATA 1
    			EcgFWCPckt.wECGData[12] = ch1DataC & 0xFF;
    			EcgFWCPckt.wECGData[13] = (ch1DataC & 0xFF00) >> 8;
    
    			// DATA 2
    			EcgFWCPckt.wECGData[14] = ch2DataC & 0xFF;
    			EcgFWCPckt.wECGData[15] = (ch2DataC & 0xFF00) >> 8;
    
    			// DATA 3
    			// The 0x55 value for Data C-3 prevents a long series of 0 bit values
    			// in the packet transmission
    			EcgFWCPckt.wECGData[16] = 0x55;
    			EcgFWCPckt.wECGData[17] = 0x55;
    
    			// Set sequence number for next packet transmission
    			EcgFWCPckt.wEcgSeqNumber++;
    			EcgFWCPckt.wEcgSeqNumber = EcgFWCPckt.wEcgSeqNumber & 0xFF;
    
    			//*************** Tasks to do ******************
    			//	1. Write EcgFWCPckt.wEcgStatusData = New Structure[EcgFWCPckt.wEcgSeqNumber & 0x3F]
    			//**********************************************
    
    			// Copy ECG packet data into transmit payload
    			memcpy(tx_payload.data, &EcgFWCPckt, 21);
    
    			// Set counter index for ECG simulated data
    			if (counter < total_items_ecg_dat)
    			{
    				counter = counter + 1;
    			}
    			else
    			{
    				counter = 0;
    			}
    
    			if (led_count > 0)
    			{
    				led_count++;
    			}
    			if (led_count > 250)
    			{
    				// turn off led
    				ret = gpio_pin_set(&led, led.pin, 0);
    				if (ret)
    				{
    					LOG_ERR("LED3 set 0 error: %d", ret);
    				}
    				led_count = 0;
    			}
    
    			esb_flush_tx();
    
    }
    void timer_callback(void const *arg)
    {
    
    
    
    	//*************** Tasks to do here ****************
    	//	1. In init(), set radio for RX
    	//	2. Set radio Frequency Register with frequency variable
    	//	3. Set Radio for TX (TX_EN) (There may be a sequence required and a wait for READY event)
    	//*************************************************
    
    	if ((packet_ready == true) && (packet_tx_done == false))
    	{
    		transmit_data_flag = true;
    
    	}
    	//**************** After TX Success ***************
    	//	4. Set Radio for RX (RX_EN) (There may be  a sequence required and a wait for READY event)
    	//*************************************************
    }
    
    void main(void)
    {
    	int err, i = 0, ret = 0;
    
    	osTimerId timer_id;
    	osTimerId timer_sec_id;
    
    	LOG_INF("Enhanced ShockBurst ptx sample");
    	printk(" \r\n ** total_items_ecg_dat: %d **\r\n", total_items_ecg_dat);
    
    	err = clocks_start();
    	if (err)
    	{
    		return;
    	}
    
    	err = leds_init();
    	if (err)
    	{
    		return;
    	}
    
    	err = esb_initialize();
    	if (err)
    	{
    		LOG_ERR("ESB initialization failed, err %d", err);
    		return;
    	}
    
    	initFwdChData();
    
    	LOG_INF("Initialization complete");
    	LOG_INF("Sending test packet");
    	delay_timer_id = osTimerCreate_US(osTimer(myTimer_delay), osTimerOnce, NULL);
    	timer_id = osTimerCreate_US(osTimer(myTimer), osTimerPeriodic, NULL);
    	osTimerStart_US(timer_id, TIMER_TICKS);
    
    	timer_sec_id = osTimerCreate_US(osTimer(my_sec_timer), osTimerPeriodic, NULL);
    	osTimerStart_US(timer_sec_id, TIMER_SEC_TICKS);
    	while (1)
    	{
    		if(transmit_data_flag == true)
    		{
    			transmit_data();
    			transmit_data_flag = false;
    		}
    
    		if (packet_tx_done == true)
    		{
    			packet_ready == false;
    			create_fwc_packet();
    
    			packet_ready == true;
    			packet_tx_done = false;
    		}
    		else
    		{ // packet_tx_done = false
    
    #if 0
    			if(filter_recvd == 1)
    			{	
    				channel1_filter_led_set();
    			}
    #endif
    			if (filter_recvd == 2)
    			{
    				channel2_filter_led_set();
    			}
    
    			if (delay_timer_flag == true)
    			{
    				osTimerStart_US(delay_timer_id, DELAY_TIMER_TICKS);
    				while (tx_delay_done == false);
    				tx_delay_done = false;
    				osTimerStop(delay_timer_id);
    				delay_timer_flag = false;
    			}
    
    			if( print_metrics == true )
    			{
    				printk("second_tx_cnt: %d     second_rx_cnt: %d \r\n", second_tx_cnt, second_rx_cnt);
    				second_rx_cnt = 0;
    				second_tx_cnt = 0;
    				print_metrics = false;
    			}
    			
    			//*************** Tasks to do ***********************
    			//	1. Set up a structure of 64 chars to hold status data
    			//	2. In init() function initialize structure with current value sent as data.
    			//	3. Based on index (SequenceNumber & 0x3F), fill in designated RX data
    			//		a. Plan is to fill in Filter setting with data received from MR400
    			//		b. Based on Filter Setting, set battery remaining time to designated value
    			//	4. Process any received data into Status Data
    			//***************************************************
    		}
    		k_sleep(K_USEC(1));
    	}
    }
    

    Thanks and regards

    Ajit S J

  • Hi Ajit

    I don't see any flow control in your RX -> TX -> transmit a payload -> back to RX routine.

    You are basically changing the radio to RX, uploading a new payload, and then changing back to RX without knowing whether or not the transmission is complete. 

    Possibly the reason it works with the printk() call is that this adds sufficient delay for the TX transmission to complete before you switch back to RX. 

    What if you add 250us or so of delay, will this not fix it? 

    A common way of handling this is to set a flag in the event_handler on ESB_EVENT_TX_SUCCESS, and only proceed to enable the RX mode once this flag is set. 

    Depending on the priority of the timer interrupt this might block the ESB event_handler though, so this is something to consider (and another reason to run this code from thread context). 

    Best regards
    Torbjørn

  • Hi  ,

    Thanks a lot for the suggestions. 

     Setting a flag in the event_handler on ESB_EVENT_TX_SUCCESS and setting a flag in the timer callback, and checking this flag in the while loop did make it to work as expected.

    The RX and TX is working now as expected.

    But we have got one minor issue.

    We are calling the esb_initialize_tx and esb_initialize_rx before transmitting and receiving respectively. We need to do this as we have different payload lengths for tx and rx. We would want to cut short these functions to reduce the code as much as possible inside the while loop. We would call a common "esb_initialize" function in the main only once. Then call the esb_initialize_tx and esb_initialize_rx functions inside the while loop.

    So we modified the functions as below.


    //Function to initialize Nordic Radio at Start Up for RX
    int esb_initialize(void)
    {
        int err;
         
        //Nordic radio can have 8 Address Bytes.  MR400 implementation uses 4 Address Bytes in base_addr_0
        uint8_t base_addr_0[4] = {0x99, 0x44, 0x99, 0x96};
        uint8_t base_addr_1[4] = {0x00, 0x00, 0x00, 0x00};

        //Nordic address prefix MR400 uses 1 and it is set to LS Byte of Address Bytes
        uint8_t addr_prefix[8] = {0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

        struct esb_config config = ESB_DEFAULT_CONFIG;

        config.protocol = ESB_PROTOCOL_ESB;
        config.retransmit_delay = 600;
        config.bitrate = ESB_BITRATE_1MBPS;
        config.event_handler = event_handler;
        config.mode = ESB_MODE_PRX;
        config.selective_auto_ack = true;
        config.payload_length = 9;

        err = esb_init(&config);

        if (err)
        {
            printk("esb_init failed \r\n");
            return err;
        }

        err = esb_set_base_address_0(base_addr_0);
        if (err)
        {
            return err;
        }

        err = esb_set_base_address_1(base_addr_1);
        if (err)
        {
            return err;
        }

        err = esb_set_prefixes(addr_prefix, ARRAY_SIZE(addr_prefix));
        if (err)
        {
            return err;
        }
        tx_payload.noack = 1;
        rx_payload.noack = 1;

        return 0;
    }

    //Function to set Nordic Radio in TX mode
    int esb_initialize_tx(void)
    {
        int err;


        struct esb_config config = ESB_DEFAULT_CONFIG;

        config.protocol = ESB_PROTOCOL_ESB;
        config.retransmit_delay = 600;
        config.bitrate = ESB_BITRATE_1MBPS;
        config.event_handler = event_handler;
        config.mode = ESB_MODE_PTX;
        config.selective_auto_ack = true;
        config.payload_length = 21;

        err = esb_init_tx(&config);

        if (err)
        {
            return err;
        }

        return 0;
    }

    //Function to set Nordic Radio in RX mode
    int esb_initialize_rx(void)
    {
        int err;


        struct esb_config config = ESB_DEFAULT_CONFIG;

        config.protocol = ESB_PROTOCOL_ESB;
        config.retransmit_delay = 600;
        config.bitrate = ESB_BITRATE_1MBPS;
        config.event_handler = event_handler;
        config.mode = ESB_MODE_PRX;
        config.selective_auto_ack = true;
        config.payload_length = 9;

        err = esb_init_rx(&config);
        if (err)
        {
            return err;
        }

        return 0;
    }

    And inside the esb.c we have created "esb_init_tx" and "esb_init_rx" functions respectively which are trimmed versions of "esb_init" function. Please find its code below as well.



    int esb_init_tx(const struct esb_config *config)
    {
        if (config == NULL) {
            return -EINVAL;
        }

        memcpy(&esb_cfg, config, sizeof(esb_cfg)); //separate

        update_radio_parameters(); //separate

        esb_state = ESB_STATE_IDLE; //separate

        return 0;
    }



    int esb_init_rx(const struct esb_config *config)
    {
        if (config == NULL) {
            return -EINVAL;
        }

        memcpy(&esb_cfg, config, sizeof(esb_cfg)); //separate

        update_radio_parameters(); //separate

        esb_state = ESB_STATE_IDLE; //separate

        return 0;
    }
    We also have set the operating frequency to 2.360MHz by using the below mentioned function.
    void mband_frequency_set(void)
    {
        NRF_RADIO->FREQUENCY = (RADIO_FREQUENCY_MAP_Low << RADIO_FREQUENCY_MAP_Pos);
    }
     
    But after these changes, the transmit is working fine but the receive is not able to receive all the packets. We have logged prints every one second. Ideally we should receive 4 packets (reception happens at 4Hz) in one second but we are not receiving them.
    Please let me know if we have optimized the esb_initialize_tx, esb_initialize_rx, esb_init_tx and esb_init_rx functions correctly. Please let us know if we have removed anything that should have been there.

    Thanks and regards

    Ajit S J

  • Hi Ajit

    Are you just sending each of the 4Hz packets once, or do you retransmit them in order to ensure that you can handle some packet loss? 

    Is the transmission of these packets somehow synchronized with the reception of the faster packets?

    When you say you don't receive them you mean you don't receive any packets at all, or that you just receive some of them? 

    How do you disable the ESB protocol before switching modes? 

    It seems like your init functions have omitted quite a lot of the original init functionality, such as the PPI configuration and the system timer init, but possibly you don't disable these? 

    Best regards
    Torbjørn

Related