sending CTE at different frequencies

Hey, 

I am trying to calculate distance between 2 BLE devices with nrf5340 by myself. i would have an initiator and a reflector. so my question is how can i configure my device as a reflector and how can i send CTE at different frequencies?

Thanke you 

Parents
  • Hi

    I asked our expert on channel sounding/distance measurement (Carsten which was also the advisor on one of the papers you linked to), and he does not think this will be very viable on an nRF5340 I'm afraid. What you're asking for is not public I'm afraid, so I can't help you. It should be possible to do MCPD by sending CTE packets, but the results will not be very good either. Sorry that I'm being the bearer of bad news.

    Best regards,

    Simon

  • Hi, 

    The result is not a problem, I just want to understand it and document it in my thesis. Can you tell me how I can configure a device as a Rx and Tx to get a "reflektor"?  

    * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
     */
    
    #include <stddef.h>
    #include <errno.h>
    #include <zephyr/kernel.h>
    #include "zephyr/bluetooth/hci_types.h"
    #include <zephyr/bluetooth/bluetooth.h>
    #include <zephyr/bluetooth/direction.h>
    #include "dk_buttons_and_leds.h"
    #include <zephyr/types.h>
    #include <zephyr/sys/byteorder.h>
    #include <zephyr/sys/util.h>
    #include "radio"
    
    /*++++++++++++TX++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
    
    /* Length of CTE in unit of 8[us] */
    #define CTE_LEN (0x14U)
    /* Number of CTE send in single periodic advertising train */
    #define PER_ADV_EVENT_CTE_COUNT 5
    
    static void adv_sent_cb(struct bt_le_ext_adv *adv,
    			struct bt_le_ext_adv_sent_info *info);
    
    const static struct bt_le_ext_adv_cb adv_callbacks = {
    	.sent = adv_sent_cb,
    };
    
    static struct bt_le_ext_adv *adv_set;
    
    const static struct bt_le_adv_param param =
    		BT_LE_ADV_PARAM_INIT(BT_LE_ADV_OPT_EXT_ADV |
    				     BT_LE_ADV_OPT_USE_NAME,
    				     BT_GAP_ADV_FAST_INT_MIN_2,
    				     BT_GAP_ADV_FAST_INT_MAX_2,
    				     NULL);
    
    static struct bt_le_ext_adv_start_param ext_adv_start_param = {
    	.timeout = 0,
    	.num_events = 0,
    };
    
    const static struct bt_le_per_adv_param per_adv_param = {
    	.interval_min = BT_GAP_ADV_SLOW_INT_MIN,
    	.interval_max = BT_GAP_ADV_SLOW_INT_MAX,
    	.options = BT_LE_ADV_OPT_USE_TX_POWER,
    };
    
    #if defined(CONFIG_BT_DF_CTE_TX_AOD)
    /* Example sequence of antenna switch patterns for antenna matrix designed by
     * Nordic. For more information about antenna switch patterns see README.rst.
     */
    static uint8_t ant_patterns[] = {0x2, 0x0, 0x5, 0x6, 0x1, 0x4, 0xC, 0x9, 0xE,
    				 0xD, 0x8, 0xA};
    #endif /* CONFIG_BT_DF_CTE_TX_AOD */
    
    struct bt_df_adv_cte_tx_param cte_params = { .cte_len = CTE_LEN,
    					     .cte_count = PER_ADV_EVENT_CTE_COUNT,
    #if defined(CONFIG_BT_DF_CTE_TX_AOD)
    					     .cte_type = BT_DF_CTE_TYPE_AOD_2US,
    					     .num_ant_ids = ARRAY_SIZE(ant_patterns),
    					     .ant_ids = ant_patterns
    #else
    					     .cte_type = BT_DF_CTE_TYPE_AOA,
    					     .num_ant_ids = 0,
    					     .ant_ids = NULL
    #endif /* CONFIG_BT_DF_CTE_TX_AOD */
    };
    
    const struct bt_df_per_adv_sync_cte_rx_param cte_rx_params = {
    		.max_cte_count = 5,
    #if defined(CONFIG_BT_DF_CTE_RX_AOA)
    		.cte_types = BT_DF_CTE_TYPE_ALL,
    		.slot_durations = 0x2,
    		.num_ant_ids = ARRAY_SIZE(ant_patterns),
    		.ant_ids = ant_patterns,
    #else
    		.cte_types = BT_DF_CTE_TYPE_AOD_1US | BT_DF_CTE_TYPE_AOD_2US,
    #endif /* CONFIG_BT_DF_CTE_RX_AOA */
    	};
    
    /*++++++++++++RX++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
    #define DEVICE_NAME CONFIG_BT_DEVICE_NAME
    #define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1)
    #define PEER_NAME_LEN_MAX 30
    /* BT Core 5.3 specification allows controller to wait 6 periodic advertising events for
     * synchronization establishment, hence timeout must be longer than that.
     */
    #define SYNC_CREATE_TIMEOUT_INTERVAL_NUM 7
    /* Maximum length of advertising data represented in hexadecimal format */
    #define ADV_DATA_HEX_STR_LEN_MAX (BT_GAP_ADV_MAX_EXT_ADV_DATA_LEN * 2 + 1)
    
    static struct bt_le_per_adv_sync *sync;
    static bt_addr_le_t per_addr;
    static volatile bool per_adv_found;
    static bool scan_enabled;
    static uint8_t per_sid;
    static uint32_t sync_create_timeout_ms;
    static bool bCTE_receved = false;
    static K_SEM_DEFINE(sem_per_adv, 0, 1);
    static K_SEM_DEFINE(sem_per_sync, 0, 1);
    static K_SEM_DEFINE(sem_per_sync_lost, 0, 1);
    
    
    static inline uint32_t adv_interval_to_ms(uint16_t interval)
    {
    	return interval * 5 / 4;
    }
    
    static const char *phy2str(uint8_t phy)
    {
    	switch (phy) {
    	case 0: return "No packets";
    	case BT_GAP_LE_PHY_1M: return "LE 1M";
    	case BT_GAP_LE_PHY_2M: return "LE 2M";
    	case BT_GAP_LE_PHY_CODED: return "LE Coded";
    	default: return "Unknown";
    	}
    }
    
    static const char *cte_type2str(uint8_t type)
    {
    	switch (type) {
    	case BT_DF_CTE_TYPE_AOA: return "AOA";
    	case BT_DF_CTE_TYPE_AOD_1US: return "AOD 1 [us]";
    	case BT_DF_CTE_TYPE_AOD_2US: return "AOD 2 [us]";
    	case BT_DF_CTE_TYPE_NONE: return "";
    	default: return "Unknown";
    	}
    }
    
    static const char *packet_status2str(uint8_t status)
    {
    	switch (status) {
    	case BT_DF_CTE_CRC_OK: return "CRC OK";
    	case BT_DF_CTE_CRC_ERR_CTE_BASED_TIME: return "CRC not OK, CTE Info OK";
    	case BT_DF_CTE_CRC_ERR_CTE_BASED_OTHER: return "CRC not OK, Sampled other way";
    	case BT_DF_CTE_INSUFFICIENT_RESOURCES: return "No resources";
    	default: return "Unknown";
    	}
    }
    
    static bool data_cb(struct bt_data *data, void *user_data)
    {
    	char *name = user_data;
    	uint8_t len;
    
    	switch (data->type) {
    	case BT_DATA_NAME_SHORTENED:
    	case BT_DATA_NAME_COMPLETE:
    		len = MIN(data->data_len, PEER_NAME_LEN_MAX - 1);
    		memcpy(name, data->data, len);
    		name[len] = '\0';
    		return false;
    	default:
    		return true;
    	}
    }
    
    static void sync_cb(struct bt_le_per_adv_sync *sync,
    		    struct bt_le_per_adv_sync_synced_info *info)
    {
    	char le_addr[BT_ADDR_LE_STR_LEN];
    
    	bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr));
    
    	printk("PER_ADV_SYNC[%u]: [DEVICE]: %s synced, "
    	       "Interval 0x%04x (%u ms), PHY %s\n",
    	       bt_le_per_adv_sync_get_index(sync), le_addr, info->interval,
    	       adv_interval_to_ms(info->interval), phy2str(info->phy));
    
    	k_sem_give(&sem_per_sync);
    }
    
    static void term_cb(struct bt_le_per_adv_sync *sync,
    		    const struct bt_le_per_adv_sync_term_info *info)
    {
    	char le_addr[BT_ADDR_LE_STR_LEN];
    
    	bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr));
    
    	printk("PER_ADV_SYNC[%u]: [DEVICE]: %s sync terminated\n",
    	       bt_le_per_adv_sync_get_index(sync), le_addr);
    
    	k_sem_give(&sem_per_sync_lost);
    }
    
    static void recv_cb(struct bt_le_per_adv_sync *sync,
    		    const struct bt_le_per_adv_sync_recv_info *info,
    		    struct net_buf_simple *buf)
    {
    	static char data_str[ADV_DATA_HEX_STR_LEN_MAX];
    	char le_addr[BT_ADDR_LE_STR_LEN];
    
    	bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr));
    	bin2hex(buf->data, buf->len, data_str, sizeof(data_str));
    
    	printk("PER_ADV_SYNC[%u]: [DEVICE]: %s, tx_power %i, "
    	       "RSSI %i, CTE %s, data length %u, data: %s\n",
    	       bt_le_per_adv_sync_get_index(sync), le_addr, info->tx_power,
    	       info->rssi, cte_type2str(info->cte_type), buf->len, data_str);
    }
    
    static void adv_sent_cb(struct bt_le_ext_adv *adv,
    			struct bt_le_ext_adv_sent_info *info)
    {
    	printk("Advertiser[%d] %p sent %d\n", bt_le_ext_adv_get_index(adv),
    	       adv, info->num_sent);
    }
    static void scan_disable(void)
    {
    	int err;
    
    	printk("Scan disable...");
    	err = bt_le_scan_stop();
    	if (err) {
    		printk("failed (err %d)\n", err);
    		return;
    	}
    	printk("Success.\n");
    
    	scan_enabled = false;
    }
    
    
    static int delete_sync(void)
    {
    	int err;
    
    	printk("Deleting Periodic Advertising Sync...");
    	err = bt_le_per_adv_sync_delete(sync);
    	if (err) {
    		printk("failed (err %d)\n", err);
    		return err;
    	}
    	printk("success\n");
    
    	return 0;
    }
    
    static void cte_recv_cb(struct bt_le_per_adv_sync *sync,
    			struct bt_df_per_adv_sync_iq_samples_report const *report)
    { 
    	int err;
    	char addr_s[BT_ADDR_LE_STR_LEN];
    	struct bt_le_oob oob_local;
    
    	printk("CTE[%u]: samples count %d, cte type %s, slot durations: %u [us], "
    	       "packet status %s, RSSI %i\n",
    	       bt_le_per_adv_sync_get_index(sync), report->sample_count,
    	       cte_type2str(report->cte_type), report->slot_durations,
    	       packet_status2str(report->packet_status), report->rssi);
    
    		for (uint8_t idx = 0; idx < report->sample_count; idx++) 
    		{
    			if (report->sample_type == BT_DF_IQ_SAMPLE_8_BITS_INT) 
    			{
    				
    				printk(" idx:%d: I:%d  Q:%d Ch_idx:%d\n", idx, report->sample[idx].i,
    				       report->sample[idx].q, report->chan_idx);
    				
    			} 
    		}
    	
    	printk("Advertising set create...");
    	err = bt_le_ext_adv_create(&param, &adv_callbacks, &adv_set);
    	if (err) {
    		printk("failed bt_le_ext_adv_create (err %d)\n", err);
    	}
    	printk("success\n");
    
    	printk("Update CTE params...");
    	err = bt_df_set_adv_cte_tx_param(adv_set, &cte_params);
    	if (err) {
    		printk("failed bt_df_set_adv_cte_tx_param (err %d)\n", err);
    	}
    	printk("success\n");
    
    	printk("Periodic advertising params set...");
    	err = bt_le_per_adv_set_param(adv_set, &per_adv_param);
    	if (err) {
    		printk("failed bt_le_per_adv_set_param (err %d)\n", err);
    	}
    	printk("success\n");
    
    	printk("Enable CTE...");
    	err = bt_df_adv_cte_tx_enable(adv_set);
    	if (err) {
    		printk("failed bt_df_adv_cte_tx_enable (err %d)\n", err);
    	}
    	printk("success\n");
    
    	printk("Periodic advertising enable...");
    	err = bt_le_per_adv_start(adv_set);
    	if (err) {
    		printk("failed bt_le_per_adv_start (err %d)\n", err);
    	}
    	printk("success\n");
    
    	printk("Extended advertising enable...");
    	err = bt_le_ext_adv_start(adv_set, &ext_adv_start_param);
    	if (err) {
    		printk("failed bt_le_ext_adv_start (err %d)\n", err);
    	}
    	printk("success\n");
    
    	bt_le_ext_adv_oob_get_local(adv_set, &oob_local);
    	bt_addr_le_to_str(&oob_local.addr, addr_s, sizeof(addr_s));
    
    	printk("Started extended advertising as %s\n", addr_s);
    }
    
    
    static struct bt_le_per_adv_sync_cb sync_callbacks = {
    	.synced = sync_cb,
    	.term = term_cb,
    	.recv = recv_cb,
    	.cte_report_cb = cte_recv_cb,
    };
    
    static void scan_recv(const struct bt_le_scan_recv_info *info,
    		      struct net_buf_simple *buf)
    {
    	char le_addr[BT_ADDR_LE_STR_LEN];
    	char name[PEER_NAME_LEN_MAX];
    
    	(void)memset(name, 0, sizeof(name));
    
    	bt_data_parse(buf, data_cb, name);
    
    	bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr));
    
    	printk("[DEVICE]: %s, AD evt type %u, Tx Pwr: %i, RSSI %i %s C:%u S:%u "
    	       "D:%u SR:%u E:%u Prim: %s, Secn: %s, Interval: 0x%04x (%u ms), "
    	       "SID: %u\n",
    	       le_addr, info->adv_type, info->tx_power, info->rssi, name,
    	       (info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) != 0,
    	       (info->adv_props & BT_GAP_ADV_PROP_SCANNABLE) != 0,
    	       (info->adv_props & BT_GAP_ADV_PROP_DIRECTED) != 0,
    	       (info->adv_props & BT_GAP_ADV_PROP_SCAN_RESPONSE) != 0,
    	       (info->adv_props & BT_GAP_ADV_PROP_EXT_ADV) != 0, phy2str(info->primary_phy),
    	       phy2str(info->secondary_phy), info->interval, adv_interval_to_ms(info->interval),
    	       info->sid);
    
    	if (!per_adv_found && info->interval) {
    		sync_create_timeout_ms =
    			adv_interval_to_ms(info->interval) * SYNC_CREATE_TIMEOUT_INTERVAL_NUM;
    		per_adv_found = true;
    		per_sid = info->sid;
    		bt_addr_le_copy(&per_addr, info->addr);
    
    		k_sem_give(&sem_per_adv);
    	}
    }
    
    static struct bt_le_scan_cb scan_callbacks = {
    	.recv = scan_recv,
    };
    
    static void create_sync(void)
    {
    	struct bt_le_per_adv_sync_param sync_create_param;
    	int err;
    
    	printk("Creating Periodic Advertising Sync...");
    	bt_addr_le_copy(&sync_create_param.addr, &per_addr);
    	sync_create_param.options = 0;
    	sync_create_param.sid = per_sid;
    	sync_create_param.skip = 0;
    	sync_create_param.timeout = 0xa;
    	err = bt_le_per_adv_sync_create(&sync_create_param, &sync);
    	if (err) {
    		printk("failed (err %d)\n", err);
    		return;
    	}
    	printk("success.\n");
    }
    
    
    static void enable_cte_rx(void)
    {
    	int err;
    
    	printk("Enable receiving of CTE...\n");
    	err = bt_df_per_adv_sync_cte_rx_enable(sync, &cte_rx_params);
    	if (err) {
    		printk("failed (err %d)\n", err);
    		return;
    	}
    	printk("success. CTE receive enabled.\n");
    }
    
    static int scan_init(void)
    {
    	printk("Scan callbacks register...");
    	bt_le_scan_cb_register(&scan_callbacks);
    	printk("success.\n");
    
    	printk("Periodic Advertising callbacks register...");
    	bt_le_per_adv_sync_cb_register(&sync_callbacks);
    	printk("success.\n");
    
    	return 0;
    }
    
    static int scan_enable(void)
    {
    	struct bt_le_scan_param param = {
    		.type = BT_LE_SCAN_TYPE_ACTIVE,
    		.options = BT_LE_SCAN_OPT_FILTER_DUPLICATE,
    		.interval = BT_GAP_SCAN_FAST_INTERVAL,
    		.window = BT_GAP_SCAN_FAST_WINDOW,
    		.timeout = 0U,
    	};
    	int err;
    
    	if (!scan_enabled) {
    		printk("Start scanning...");
    		err = bt_le_scan_start(&param, NULL);
    		if (err) {
    			printk("failed (err %d)\n", err);
    			return err;
    		}
    		printk("success\n");
    		scan_enabled = true;
    	}
    
    	return 0;
    }
    
    int main(void)
    {
    	int err;
    	char addr_s[BT_ADDR_LE_STR_LEN];
    	struct bt_le_oob oob_local;
    	printk("Starting Connectionless Locator Demo\n");
    
    	printk("Bluetooth initialization...");
    	err = bt_enable(NULL);
    	if (err) {
    		printk("failed (err %d)\n", err);
    	}
    	printk("success\n");
    
    	scan_init();
    
    	scan_enabled = false;
    
    	while (bCTE_receved == false) 
    	{
    		per_adv_found = false;
    		scan_enable();
    
    		printk("Waiting for periodic advertising...\n");
    		err = k_sem_take(&sem_per_adv, K_FOREVER);
    		if (err) {
    			printk("failed (err %d)\n", err);
    			return 0;
    		}
    		printk("success. Found periodic advertising.\n");
    
    		create_sync();
    
    		printk("Waiting for periodic sync...\n");
    		err = k_sem_take(&sem_per_sync, K_MSEC(sync_create_timeout_ms));
    		if (err) {
    			printk("failed (err %d)\n", err);
    			err = delete_sync();
    			if (err) {
    				return 0;
    			}
    			continue;
    		}
    		printk("success. Periodic sync established.\n");
    
    		enable_cte_rx();
    		/* Disable scan to cleanup output */
    		scan_disable();
    
    		printk("Waiting for periodic sync lost...\n");
    		err = k_sem_take(&sem_per_sync_lost, K_FOREVER);
    		if (err) {
    			printk("failed (err %d)\n", err);
    			return 0;
    		}
    		printk("Periodic sync lost.\n");
    	}
    }

    here is my code. i have copy the Code for the example "Direct finding connenctionless tx" and but it in the

    cte_recv_cb but that don't work so what i have to do to switch between Rx and Tx on the same device?
Reply
  • Hi, 

    The result is not a problem, I just want to understand it and document it in my thesis. Can you tell me how I can configure a device as a Rx and Tx to get a "reflektor"?  

    * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
     */
    
    #include <stddef.h>
    #include <errno.h>
    #include <zephyr/kernel.h>
    #include "zephyr/bluetooth/hci_types.h"
    #include <zephyr/bluetooth/bluetooth.h>
    #include <zephyr/bluetooth/direction.h>
    #include "dk_buttons_and_leds.h"
    #include <zephyr/types.h>
    #include <zephyr/sys/byteorder.h>
    #include <zephyr/sys/util.h>
    #include "radio"
    
    /*++++++++++++TX++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
    
    /* Length of CTE in unit of 8[us] */
    #define CTE_LEN (0x14U)
    /* Number of CTE send in single periodic advertising train */
    #define PER_ADV_EVENT_CTE_COUNT 5
    
    static void adv_sent_cb(struct bt_le_ext_adv *adv,
    			struct bt_le_ext_adv_sent_info *info);
    
    const static struct bt_le_ext_adv_cb adv_callbacks = {
    	.sent = adv_sent_cb,
    };
    
    static struct bt_le_ext_adv *adv_set;
    
    const static struct bt_le_adv_param param =
    		BT_LE_ADV_PARAM_INIT(BT_LE_ADV_OPT_EXT_ADV |
    				     BT_LE_ADV_OPT_USE_NAME,
    				     BT_GAP_ADV_FAST_INT_MIN_2,
    				     BT_GAP_ADV_FAST_INT_MAX_2,
    				     NULL);
    
    static struct bt_le_ext_adv_start_param ext_adv_start_param = {
    	.timeout = 0,
    	.num_events = 0,
    };
    
    const static struct bt_le_per_adv_param per_adv_param = {
    	.interval_min = BT_GAP_ADV_SLOW_INT_MIN,
    	.interval_max = BT_GAP_ADV_SLOW_INT_MAX,
    	.options = BT_LE_ADV_OPT_USE_TX_POWER,
    };
    
    #if defined(CONFIG_BT_DF_CTE_TX_AOD)
    /* Example sequence of antenna switch patterns for antenna matrix designed by
     * Nordic. For more information about antenna switch patterns see README.rst.
     */
    static uint8_t ant_patterns[] = {0x2, 0x0, 0x5, 0x6, 0x1, 0x4, 0xC, 0x9, 0xE,
    				 0xD, 0x8, 0xA};
    #endif /* CONFIG_BT_DF_CTE_TX_AOD */
    
    struct bt_df_adv_cte_tx_param cte_params = { .cte_len = CTE_LEN,
    					     .cte_count = PER_ADV_EVENT_CTE_COUNT,
    #if defined(CONFIG_BT_DF_CTE_TX_AOD)
    					     .cte_type = BT_DF_CTE_TYPE_AOD_2US,
    					     .num_ant_ids = ARRAY_SIZE(ant_patterns),
    					     .ant_ids = ant_patterns
    #else
    					     .cte_type = BT_DF_CTE_TYPE_AOA,
    					     .num_ant_ids = 0,
    					     .ant_ids = NULL
    #endif /* CONFIG_BT_DF_CTE_TX_AOD */
    };
    
    const struct bt_df_per_adv_sync_cte_rx_param cte_rx_params = {
    		.max_cte_count = 5,
    #if defined(CONFIG_BT_DF_CTE_RX_AOA)
    		.cte_types = BT_DF_CTE_TYPE_ALL,
    		.slot_durations = 0x2,
    		.num_ant_ids = ARRAY_SIZE(ant_patterns),
    		.ant_ids = ant_patterns,
    #else
    		.cte_types = BT_DF_CTE_TYPE_AOD_1US | BT_DF_CTE_TYPE_AOD_2US,
    #endif /* CONFIG_BT_DF_CTE_RX_AOA */
    	};
    
    /*++++++++++++RX++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
    #define DEVICE_NAME CONFIG_BT_DEVICE_NAME
    #define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1)
    #define PEER_NAME_LEN_MAX 30
    /* BT Core 5.3 specification allows controller to wait 6 periodic advertising events for
     * synchronization establishment, hence timeout must be longer than that.
     */
    #define SYNC_CREATE_TIMEOUT_INTERVAL_NUM 7
    /* Maximum length of advertising data represented in hexadecimal format */
    #define ADV_DATA_HEX_STR_LEN_MAX (BT_GAP_ADV_MAX_EXT_ADV_DATA_LEN * 2 + 1)
    
    static struct bt_le_per_adv_sync *sync;
    static bt_addr_le_t per_addr;
    static volatile bool per_adv_found;
    static bool scan_enabled;
    static uint8_t per_sid;
    static uint32_t sync_create_timeout_ms;
    static bool bCTE_receved = false;
    static K_SEM_DEFINE(sem_per_adv, 0, 1);
    static K_SEM_DEFINE(sem_per_sync, 0, 1);
    static K_SEM_DEFINE(sem_per_sync_lost, 0, 1);
    
    
    static inline uint32_t adv_interval_to_ms(uint16_t interval)
    {
    	return interval * 5 / 4;
    }
    
    static const char *phy2str(uint8_t phy)
    {
    	switch (phy) {
    	case 0: return "No packets";
    	case BT_GAP_LE_PHY_1M: return "LE 1M";
    	case BT_GAP_LE_PHY_2M: return "LE 2M";
    	case BT_GAP_LE_PHY_CODED: return "LE Coded";
    	default: return "Unknown";
    	}
    }
    
    static const char *cte_type2str(uint8_t type)
    {
    	switch (type) {
    	case BT_DF_CTE_TYPE_AOA: return "AOA";
    	case BT_DF_CTE_TYPE_AOD_1US: return "AOD 1 [us]";
    	case BT_DF_CTE_TYPE_AOD_2US: return "AOD 2 [us]";
    	case BT_DF_CTE_TYPE_NONE: return "";
    	default: return "Unknown";
    	}
    }
    
    static const char *packet_status2str(uint8_t status)
    {
    	switch (status) {
    	case BT_DF_CTE_CRC_OK: return "CRC OK";
    	case BT_DF_CTE_CRC_ERR_CTE_BASED_TIME: return "CRC not OK, CTE Info OK";
    	case BT_DF_CTE_CRC_ERR_CTE_BASED_OTHER: return "CRC not OK, Sampled other way";
    	case BT_DF_CTE_INSUFFICIENT_RESOURCES: return "No resources";
    	default: return "Unknown";
    	}
    }
    
    static bool data_cb(struct bt_data *data, void *user_data)
    {
    	char *name = user_data;
    	uint8_t len;
    
    	switch (data->type) {
    	case BT_DATA_NAME_SHORTENED:
    	case BT_DATA_NAME_COMPLETE:
    		len = MIN(data->data_len, PEER_NAME_LEN_MAX - 1);
    		memcpy(name, data->data, len);
    		name[len] = '\0';
    		return false;
    	default:
    		return true;
    	}
    }
    
    static void sync_cb(struct bt_le_per_adv_sync *sync,
    		    struct bt_le_per_adv_sync_synced_info *info)
    {
    	char le_addr[BT_ADDR_LE_STR_LEN];
    
    	bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr));
    
    	printk("PER_ADV_SYNC[%u]: [DEVICE]: %s synced, "
    	       "Interval 0x%04x (%u ms), PHY %s\n",
    	       bt_le_per_adv_sync_get_index(sync), le_addr, info->interval,
    	       adv_interval_to_ms(info->interval), phy2str(info->phy));
    
    	k_sem_give(&sem_per_sync);
    }
    
    static void term_cb(struct bt_le_per_adv_sync *sync,
    		    const struct bt_le_per_adv_sync_term_info *info)
    {
    	char le_addr[BT_ADDR_LE_STR_LEN];
    
    	bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr));
    
    	printk("PER_ADV_SYNC[%u]: [DEVICE]: %s sync terminated\n",
    	       bt_le_per_adv_sync_get_index(sync), le_addr);
    
    	k_sem_give(&sem_per_sync_lost);
    }
    
    static void recv_cb(struct bt_le_per_adv_sync *sync,
    		    const struct bt_le_per_adv_sync_recv_info *info,
    		    struct net_buf_simple *buf)
    {
    	static char data_str[ADV_DATA_HEX_STR_LEN_MAX];
    	char le_addr[BT_ADDR_LE_STR_LEN];
    
    	bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr));
    	bin2hex(buf->data, buf->len, data_str, sizeof(data_str));
    
    	printk("PER_ADV_SYNC[%u]: [DEVICE]: %s, tx_power %i, "
    	       "RSSI %i, CTE %s, data length %u, data: %s\n",
    	       bt_le_per_adv_sync_get_index(sync), le_addr, info->tx_power,
    	       info->rssi, cte_type2str(info->cte_type), buf->len, data_str);
    }
    
    static void adv_sent_cb(struct bt_le_ext_adv *adv,
    			struct bt_le_ext_adv_sent_info *info)
    {
    	printk("Advertiser[%d] %p sent %d\n", bt_le_ext_adv_get_index(adv),
    	       adv, info->num_sent);
    }
    static void scan_disable(void)
    {
    	int err;
    
    	printk("Scan disable...");
    	err = bt_le_scan_stop();
    	if (err) {
    		printk("failed (err %d)\n", err);
    		return;
    	}
    	printk("Success.\n");
    
    	scan_enabled = false;
    }
    
    
    static int delete_sync(void)
    {
    	int err;
    
    	printk("Deleting Periodic Advertising Sync...");
    	err = bt_le_per_adv_sync_delete(sync);
    	if (err) {
    		printk("failed (err %d)\n", err);
    		return err;
    	}
    	printk("success\n");
    
    	return 0;
    }
    
    static void cte_recv_cb(struct bt_le_per_adv_sync *sync,
    			struct bt_df_per_adv_sync_iq_samples_report const *report)
    { 
    	int err;
    	char addr_s[BT_ADDR_LE_STR_LEN];
    	struct bt_le_oob oob_local;
    
    	printk("CTE[%u]: samples count %d, cte type %s, slot durations: %u [us], "
    	       "packet status %s, RSSI %i\n",
    	       bt_le_per_adv_sync_get_index(sync), report->sample_count,
    	       cte_type2str(report->cte_type), report->slot_durations,
    	       packet_status2str(report->packet_status), report->rssi);
    
    		for (uint8_t idx = 0; idx < report->sample_count; idx++) 
    		{
    			if (report->sample_type == BT_DF_IQ_SAMPLE_8_BITS_INT) 
    			{
    				
    				printk(" idx:%d: I:%d  Q:%d Ch_idx:%d\n", idx, report->sample[idx].i,
    				       report->sample[idx].q, report->chan_idx);
    				
    			} 
    		}
    	
    	printk("Advertising set create...");
    	err = bt_le_ext_adv_create(&param, &adv_callbacks, &adv_set);
    	if (err) {
    		printk("failed bt_le_ext_adv_create (err %d)\n", err);
    	}
    	printk("success\n");
    
    	printk("Update CTE params...");
    	err = bt_df_set_adv_cte_tx_param(adv_set, &cte_params);
    	if (err) {
    		printk("failed bt_df_set_adv_cte_tx_param (err %d)\n", err);
    	}
    	printk("success\n");
    
    	printk("Periodic advertising params set...");
    	err = bt_le_per_adv_set_param(adv_set, &per_adv_param);
    	if (err) {
    		printk("failed bt_le_per_adv_set_param (err %d)\n", err);
    	}
    	printk("success\n");
    
    	printk("Enable CTE...");
    	err = bt_df_adv_cte_tx_enable(adv_set);
    	if (err) {
    		printk("failed bt_df_adv_cte_tx_enable (err %d)\n", err);
    	}
    	printk("success\n");
    
    	printk("Periodic advertising enable...");
    	err = bt_le_per_adv_start(adv_set);
    	if (err) {
    		printk("failed bt_le_per_adv_start (err %d)\n", err);
    	}
    	printk("success\n");
    
    	printk("Extended advertising enable...");
    	err = bt_le_ext_adv_start(adv_set, &ext_adv_start_param);
    	if (err) {
    		printk("failed bt_le_ext_adv_start (err %d)\n", err);
    	}
    	printk("success\n");
    
    	bt_le_ext_adv_oob_get_local(adv_set, &oob_local);
    	bt_addr_le_to_str(&oob_local.addr, addr_s, sizeof(addr_s));
    
    	printk("Started extended advertising as %s\n", addr_s);
    }
    
    
    static struct bt_le_per_adv_sync_cb sync_callbacks = {
    	.synced = sync_cb,
    	.term = term_cb,
    	.recv = recv_cb,
    	.cte_report_cb = cte_recv_cb,
    };
    
    static void scan_recv(const struct bt_le_scan_recv_info *info,
    		      struct net_buf_simple *buf)
    {
    	char le_addr[BT_ADDR_LE_STR_LEN];
    	char name[PEER_NAME_LEN_MAX];
    
    	(void)memset(name, 0, sizeof(name));
    
    	bt_data_parse(buf, data_cb, name);
    
    	bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr));
    
    	printk("[DEVICE]: %s, AD evt type %u, Tx Pwr: %i, RSSI %i %s C:%u S:%u "
    	       "D:%u SR:%u E:%u Prim: %s, Secn: %s, Interval: 0x%04x (%u ms), "
    	       "SID: %u\n",
    	       le_addr, info->adv_type, info->tx_power, info->rssi, name,
    	       (info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) != 0,
    	       (info->adv_props & BT_GAP_ADV_PROP_SCANNABLE) != 0,
    	       (info->adv_props & BT_GAP_ADV_PROP_DIRECTED) != 0,
    	       (info->adv_props & BT_GAP_ADV_PROP_SCAN_RESPONSE) != 0,
    	       (info->adv_props & BT_GAP_ADV_PROP_EXT_ADV) != 0, phy2str(info->primary_phy),
    	       phy2str(info->secondary_phy), info->interval, adv_interval_to_ms(info->interval),
    	       info->sid);
    
    	if (!per_adv_found && info->interval) {
    		sync_create_timeout_ms =
    			adv_interval_to_ms(info->interval) * SYNC_CREATE_TIMEOUT_INTERVAL_NUM;
    		per_adv_found = true;
    		per_sid = info->sid;
    		bt_addr_le_copy(&per_addr, info->addr);
    
    		k_sem_give(&sem_per_adv);
    	}
    }
    
    static struct bt_le_scan_cb scan_callbacks = {
    	.recv = scan_recv,
    };
    
    static void create_sync(void)
    {
    	struct bt_le_per_adv_sync_param sync_create_param;
    	int err;
    
    	printk("Creating Periodic Advertising Sync...");
    	bt_addr_le_copy(&sync_create_param.addr, &per_addr);
    	sync_create_param.options = 0;
    	sync_create_param.sid = per_sid;
    	sync_create_param.skip = 0;
    	sync_create_param.timeout = 0xa;
    	err = bt_le_per_adv_sync_create(&sync_create_param, &sync);
    	if (err) {
    		printk("failed (err %d)\n", err);
    		return;
    	}
    	printk("success.\n");
    }
    
    
    static void enable_cte_rx(void)
    {
    	int err;
    
    	printk("Enable receiving of CTE...\n");
    	err = bt_df_per_adv_sync_cte_rx_enable(sync, &cte_rx_params);
    	if (err) {
    		printk("failed (err %d)\n", err);
    		return;
    	}
    	printk("success. CTE receive enabled.\n");
    }
    
    static int scan_init(void)
    {
    	printk("Scan callbacks register...");
    	bt_le_scan_cb_register(&scan_callbacks);
    	printk("success.\n");
    
    	printk("Periodic Advertising callbacks register...");
    	bt_le_per_adv_sync_cb_register(&sync_callbacks);
    	printk("success.\n");
    
    	return 0;
    }
    
    static int scan_enable(void)
    {
    	struct bt_le_scan_param param = {
    		.type = BT_LE_SCAN_TYPE_ACTIVE,
    		.options = BT_LE_SCAN_OPT_FILTER_DUPLICATE,
    		.interval = BT_GAP_SCAN_FAST_INTERVAL,
    		.window = BT_GAP_SCAN_FAST_WINDOW,
    		.timeout = 0U,
    	};
    	int err;
    
    	if (!scan_enabled) {
    		printk("Start scanning...");
    		err = bt_le_scan_start(&param, NULL);
    		if (err) {
    			printk("failed (err %d)\n", err);
    			return err;
    		}
    		printk("success\n");
    		scan_enabled = true;
    	}
    
    	return 0;
    }
    
    int main(void)
    {
    	int err;
    	char addr_s[BT_ADDR_LE_STR_LEN];
    	struct bt_le_oob oob_local;
    	printk("Starting Connectionless Locator Demo\n");
    
    	printk("Bluetooth initialization...");
    	err = bt_enable(NULL);
    	if (err) {
    		printk("failed (err %d)\n", err);
    	}
    	printk("success\n");
    
    	scan_init();
    
    	scan_enabled = false;
    
    	while (bCTE_receved == false) 
    	{
    		per_adv_found = false;
    		scan_enable();
    
    		printk("Waiting for periodic advertising...\n");
    		err = k_sem_take(&sem_per_adv, K_FOREVER);
    		if (err) {
    			printk("failed (err %d)\n", err);
    			return 0;
    		}
    		printk("success. Found periodic advertising.\n");
    
    		create_sync();
    
    		printk("Waiting for periodic sync...\n");
    		err = k_sem_take(&sem_per_sync, K_MSEC(sync_create_timeout_ms));
    		if (err) {
    			printk("failed (err %d)\n", err);
    			err = delete_sync();
    			if (err) {
    				return 0;
    			}
    			continue;
    		}
    		printk("success. Periodic sync established.\n");
    
    		enable_cte_rx();
    		/* Disable scan to cleanup output */
    		scan_disable();
    
    		printk("Waiting for periodic sync lost...\n");
    		err = k_sem_take(&sem_per_sync_lost, K_FOREVER);
    		if (err) {
    			printk("failed (err %d)\n", err);
    			return 0;
    		}
    		printk("Periodic sync lost.\n");
    	}
    }

    here is my code. i have copy the Code for the example "Direct finding connenctionless tx" and but it in the

    cte_recv_cb but that don't work so what i have to do to switch between Rx and Tx on the same device?
Children
No Data
Related