Is the code developed for nRF5340 backward compatible with nRF52840 ?

#include <zephyr/logging/log.h>
#include <zephyr/drivers/uart.h>
#include <include/BLEAdvScanner.h>
#include <bluetooth/scan.h>
#include <zephyr/sys/ring_buffer.h>

const struct device *uart= DEVICE_DT_GET(DT_NODELABEL(uart0));

K_THREAD_STACK_DEFINE(scan_thread_stack, 2048);
struct k_thread scan_thread_data;

K_THREAD_STACK_DEFINE(transceiver_thread_stack, 2048);
struct k_thread transceiver_thread_data;


LOG_MODULE_REGISTER(LOG_MODULE_NAME, LOG_LEVEL_DBG);

static uint32_t g_pktcount=0;

// UART RX primary buffers
uint8_t uart_double_buffer[2][UART_BUF_SIZE];
uint8_t *uart_buf_next = uart_double_buffer[1];

K_SEM_DEFINE(tx_done, 1, 1);
K_SEM_DEFINE(rx_disabled, 0, 1);


static uint8_t rx_buf[128];  // Adjust buffer size if needed
static uint8_t rx_index = 0;
static uint8_t size_expected = 0;

// UART TX fifo
RING_BUF_DECLARE(app_tx_fifo, UART_TX_BUF_SIZE);
volatile int bytes_claimed;

// SCAN message queue
K_MSGQ_DEFINE(scan_msgq, sizeof(scan_msg_queue_item), SCAN_MSG_QUEUE_SIZE, 8);

// UART RX message queue
K_MSGQ_DEFINE(uart_rx_msgq, sizeof(uart_msg_queue_item), UART_RX_MSG_QUEUE_SIZE, 4);


// Callback function called by BLE driver upom receiving a packet during Scanning
// Keep this function short, like an ISR

static void ble_scan_cb(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,struct net_buf_simple *ad) 
{

	static scan_msg_queue_item new_message;
	new_message.rxdpktindex = g_pktcount++;
	new_message.rssi = rssi;
	new_message.rxtime = k_uptime_get_32();
	new_message.advdata_len = ad->len;
	bt_addr_le_to_str(addr,new_message.advr_addr, sizeof(new_message.advr_addr));

	memcpy(&new_message.advdata, ad->data, ad->len);
	if (k_msgq_put(&scan_msgq, &new_message, K_NO_WAIT) != 0) {
		LOG_ERR("Error: SCAN  message queue full!\n");
	}
}


// Callback function called by BLE driver upom receiving a packet during Scanning
// Keep this function short, like an ISR
static void scan_filter_match(struct bt_scan_device_info *device_info,
			      struct bt_scan_filter_match *filter_match,
			      bool connectable)
{
	
	static scan_msg_queue_item new_message;
	new_message.rxdpktindex = g_pktcount++;
	new_message.rssi = device_info->recv_info->rssi;
	new_message.rxtime = k_uptime_get_32();
	new_message.advdata_len = device_info->adv_data->len;
	bt_addr_le_to_str(device_info->recv_info->addr,new_message.advr_addr, sizeof(new_message.advr_addr));
	memcpy(&new_message.advdata, device_info->adv_data->data, device_info->adv_data->len);
	if (k_msgq_put(&scan_msgq, &new_message, K_NO_WAIT) != 0) {
		LOG_ERR("Error: SCAN  message queue full!\n");
	}

}

BT_SCAN_CB_INIT(scan_cb, scan_filter_match, NULL,
		NULL, NULL);


static int scan_init(void)
{
	int err;
	struct bt_le_scan_param scan_param = {
		.type       = BT_LE_SCAN_TYPE_PASSIVE,
		.options    = BT_LE_SCAN_OPT_NONE,
		.interval   = SCAN_INTERVAL_TICKS,
		.window     = SCAN_WINDOW_TICKS,
	};
	struct bt_scan_init_param scan_init = {
		.scan_param = &scan_param,
	};

	bt_addr_t addr ={ { 0x11, 0x93, 0xD3, 0x34, 0x22, 0x77 }};
	bt_addr_le_t filter_addr = {
		.a = addr,
		.type = BT_ADDR_LE_RANDOM,
	};
	struct bt_uuid_16 uuid_to_filter = BT_UUID_INIT_16(0x1234);
	

	bt_scan_init(&scan_init);
	bt_scan_cb_register(&scan_cb);

	err = bt_scan_filter_add(BT_SCAN_FILTER_TYPE_ADDR, &filter_addr);
	err = bt_scan_filter_add(BT_SCAN_FILTER_TYPE_UUID, &uuid_to_filter);
	if (err) {
		LOG_ERR("Scanning filters cannot be set (err %d)", err);
		return err;
	}

	err = bt_scan_filter_enable(BT_SCAN_ADDR_FILTER | BT_SCAN_UUID_FILTER, false);
	if (err) {
		LOG_ERR("Filters cannot be turned on (err %d)", err);
		return err;
	}

	LOG_INF("Scan module initialized");
	return err;
}

static int uart_tx_get_from_queue(void)
{
	uint8_t *data_ptr;
	// Try to claim any available bytes in the FIFO
	bytes_claimed = ring_buf_get_claim(&app_tx_fifo, &data_ptr, UART_TX_BUF_SIZE);

	if(bytes_claimed > 0) {
		// Start a UART transmission based on the number of available bytes
		uart_tx(uart, data_ptr, bytes_claimed, SYS_FOREVER_MS);
	}
	return bytes_claimed;
}

void receive_complete_message(uart_msg_queue_item new_message)
{
	if (new_message.length > 0) {

		if (size_expected > 0) {
			for (int i=0; i<new_message.length; i++) {
				if (new_message.bytes[i] != '\n' && new_message.bytes[i] != '\r') {
					rx_buf[rx_index] = new_message.bytes[i];
					rx_index++;
				}
			}
			LOG_INF("size expected = %u",size_expected); 
			LOG_INF("rx_index = %u",rx_index); 

			if (size_expected == rx_index ){
				rx_buf[rx_index] = 0;
				rx_index = 0;
				size_expected =0;
				LOG_INF("received complete message , %s", rx_buf);
			}
			
		}
		else {
			rx_index =0;
			for (int i=4;i<new_message.length; i++) {
				if (new_message.bytes[i] != '\n' && new_message.bytes[i] != '\r') {
					rx_buf[rx_index] = new_message.bytes[i];
					rx_index++;
				}
				
			}

			for (int i = 0; i < 4; i++) {
				int value;
				if (new_message.bytes[i] >= '0' && new_message.bytes[i] <= '9') {
					value = new_message.bytes[i] - '0';
				} else if (new_message.bytes[i] >= 'A' && new_message.bytes[i] <= 'F') {
					value = 10 + new_message.bytes[i] - 'A';
				} else if (new_message.bytes[i] >= 'a' && new_message.bytes[i] <= 'f') {
					value = 10 + new_message.bytes[i] - 'a';
				} else {
					printf("Error: Invalid hex digit at position %d.\n", i);
					return -1; // Indicate error
				}
				size_expected += value * (1 << (4 * i)); // Multiply by 16^i
   			 }
			//size_expected += new_message.bytes[0] - '0';
			LOG_INF("size expected = %u", size_expected);

			if (size_expected == rx_index ) {
				rx_buf[rx_index] = 0;
				LOG_INF("received complete message , %s", rx_buf);
				size_expected =0;
				rx_index =0;
			}
		}
	}

}

void app_uart_async_callback(const struct device *uart_dev,
							 struct uart_event *evt, void *user_data)
{
 static uart_msg_queue_item new_message;
	switch (evt->type) {
		case UART_TX_DONE:
			// Free up the written bytes in the TX FIFO
			ring_buf_get_finish(&app_tx_fifo, bytes_claimed);

			// If there is more data in the TX fifo, start the transmission
			if(uart_tx_get_from_queue() == 0) {
				// Or release the semaphore if the TX fifo is empty
				k_sem_give(&tx_done);
			}
			break;
		case UART_RX_RDY:
			memcpy(new_message.bytes, evt->data.rx.buf + evt->data.rx.offset, evt->data.rx.len);
			new_message.length = evt->data.rx.len;
			receive_complete_message(new_message);
			break;

		case UART_RX_BUF_REQUEST:
			uart_rx_buf_rsp(uart, uart_buf_next, UART_BUF_SIZE);
			break;

		case UART_RX_BUF_RELEASED:
			uart_buf_next = evt->data.rx_buf.buf;
			break;
		case UART_RX_DISABLED:
			k_sem_give(&rx_disabled);
			break;
		
		default:
			break;
	}
}

static int tx_message_over_uart(const uint8_t * data_ptr, uint32_t data_len)
{
	while(1) {
		// Try to move the data into the TX ring buffer
		uint32_t written_to_buf = ring_buf_put(&app_tx_fifo, data_ptr, data_len);
		data_len -= written_to_buf;
		
		// In case the UART TX is idle, start transmission
		if(k_sem_take(&tx_done, K_NO_WAIT) == 0) {
			uart_tx_get_from_queue();
		}	
		
		// In case all the data was written, exit the loop
		if(data_len == 0) break;

		// In case some data is still to be written, sleep for some time and run the loop one more time
		k_msleep(10);
		data_ptr += written_to_buf;
	}

	return 0;
}

int main(void) {

	int 	err;
	err = bt_enable(NULL);
	if (err) {
		LOG_ERR("Bluetooth init failed (err %d)", err);
		return 0;
	}
	LOG_DBG("Bluetooth Initiated!!");
	
	if (!device_is_ready(uart)){
		LOG_ERR("UART device not ready!!");
	}
	uart_callback_set(uart, app_uart_async_callback, NULL);
	uart_rx_enable(uart, uart_double_buffer[0], UART_BUF_SIZE, UART_RX_TIMEOUT_MS);

	LOG_DBG("UART Initiated!!");

	#ifdef CONFIG_SCANFILTER
		err = scan_init();
		if (err != 0) {
			LOG_ERR("scan_init failed (err %d)", err);
			return 0;
		}
		err = bt_scan_start(BT_SCAN_TYPE_SCAN_PASSIVE);
		if (err) {
			LOG_ERR("Start scanning failed (err %d)", err);
			return;
		}
	#else

		struct bt_le_scan_param scan_param = {
			.type = BT_LE_SCAN_TYPE_PASSIVE,
			.options = BT_LE_SCAN_OPT_FILTER_DUPLICATE,
			.interval = SCAN_INTERVAL_TICKS,
			.window = SCAN_WINDOW_TICKS,
		};
		err = bt_le_scan_start(&scan_param, ble_scan_cb);
		if (err) {
			LOG_ERR("Start scanning failed (err %d)", err);
			return;
		}
		
	#endif

	scan_msg_queue_item incoming_message;

	while (1) {
		k_msgq_get(&scan_msgq, &incoming_message, K_FOREVER);

		// Process the message here.

		static uint8_t addr_buffer[BT_ADDR_LE_STR_LEN + 1], data_buffer[MAX_ADVDATA_LEN+1];

		static uint8_t uart_tx_data[150];
		memcpy(addr_buffer, incoming_message.advr_addr, strlen(incoming_message.advr_addr));
		memcpy(data_buffer, incoming_message.advdata, incoming_message.advdata_len);
		memset(uart_tx_data, 0, 150);
		snprintf(uart_tx_data, sizeof(uart_tx_data), "RX %i: %i: %i: %s: %s\r\n", incoming_message.rxdpktindex, incoming_message.rssi,
								 incoming_message.rxtime, addr_buffer, data_buffer);
		tx_message_over_uart(uart_tx_data, strlen(uart_tx_data));
	}
	return 0;
}

I have this code developed for nRF5340.

Basically it scans for BLE advertisements based on the filters added and transmits the packets through UART.

Now for certain reasons, I wanted to go with nRF52840 and i am doing a study to check if all these features can be supported in lower version SoC?

Questions:

1) Does nRF52840 supports all filter types(whitelist) that has been supported by 5340 ?

2) How efficient is nRF52840 wrt BLE Scanning ? Do we have performance metrics for BLE on this SoC?

3) I have used nRF Connect SDK for 5340 development ? Is that SDK support available for 52840 ? I think it does have zephyr RTOS support ! will there be any limitation ? 

4) Is there any performance benchmark captured to show comparison between nRF5340 and 52840 ?

Related