How to set a device as a reflector when running the nrf_dm example?

When I was running the dm process of Connect SDK 3.0.2. I wanted to make one device as the initiator and six devices as the reflectors.  I expect that the reflectors will not undergo scanning.I made the modifications based on this post:https://devzone.nordicsemi.com/f/nordic-q-a/99676/customising-distance-measurement-using-ndt/426102?focus=true#permalink=858951*/ for reflector.

I made the following revisions  to the code of the reflector device:: 

In the main, these two positions have been commented out :

and  if (peer_supported_test(info->addr)) {}, Also, modify the method for obtaining the random seed 

At the same time, comment out the following code in the peer file:

After I completed the two code modifications, I downloaded the code to the reflectors side. But at this point, distance measurement is impossible. Could you please tell me where the problem lies?.   

Parents
  • Hi,

    This seems mostly sensibel to me. But in order to understand more I have a few questions:

    • Can you share your modified project or a diff so I see all changes?
    • Are you using the unmodified nrf_dm sample as the initiator?
    • You write that distance measuremetn is impossible. In what way does it not work? Can you share logs?

    PS: For more precise distance measurement you may want to consider Bluetooth Channel Sounding, but this is only supported with nRF54 series devices.

  • nrf_dm_noscan.zipThis is the source code that the reflector does not scan.

  • Hi,

    There are some changes there that I do not understand. Also, there is need for some changes on the initiator side as well to get synchronization working. Please see this modified maiin.c from the nrf_dm sample in nRF Connect SDK 3.0.2:

    /*
     * Copyright (c) 2021 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
     */
    
    /** @file
     *  @brief Nordic Distance Measurement sample
     */
    
    #include <stdint.h>
    #include <zephyr/kernel.h>
    #include <zephyr/sys/printk.h>
    #include <zephyr/sys/byteorder.h>
    
    #include <zephyr/bluetooth/bluetooth.h>
    #include <bluetooth/scan.h>
    #include <bluetooth/services/ddfs.h>
    
    #include <dk_buttons_and_leds.h>
    
    #include <dm.h>
    #include "peer.h"
    #include "service.h"
    
    #define DEVICE_NAME             CONFIG_BT_DEVICE_NAME
    #define DEVICE_NAME_LEN         (sizeof(DEVICE_NAME) - 1)
    
    #define RUN_STATUS_LED          DK_LED2
    #define CON_STATUS_LED          DK_LED3
    #define RUN_LED_BLINK_INTERVAL  1000
    
    #define SUPPORT_DM_CODE         0xFF55AA5A
    
    #define SCAN_ENABLE		0
    
    struct adv_mfg_data {
    	uint16_t company_code;	    /* Company Identifier Code. */
    	uint32_t support_dm_code;   /* To identify the device that supports distance measurement. */
    	uint32_t rng_seed;          /* Random seed used for generating hopping patterns. */
    } __packed;
    
    static struct adv_mfg_data mfg_data;
    struct bt_le_adv_param adv_param_conn =
    	BT_LE_ADV_PARAM_INIT(BT_LE_ADV_OPT_CONN |
    			     BT_LE_ADV_OPT_NOTIFY_SCAN_REQ,
    			     BT_GAP_ADV_FAST_INT_MIN_2,
    			     BT_GAP_ADV_FAST_INT_MAX_2,
    			     NULL);
    
    struct bt_le_adv_param adv_param_noconn =
    	BT_LE_ADV_PARAM_INIT(BT_LE_ADV_OPT_USE_IDENTITY |
    			     BT_LE_ADV_OPT_SCANNABLE |
    			     BT_LE_ADV_OPT_NOTIFY_SCAN_REQ,
    			     BT_GAP_ADV_FAST_INT_MIN_2,
    			     BT_GAP_ADV_FAST_INT_MAX_2,
    			     NULL);
    
    
    struct bt_le_adv_param *adv_param = &adv_param_conn;
    
    static const struct bt_data ad[] = {
    	BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
    	BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN),
    };
    
    static const struct bt_data sd[] = {
    	BT_DATA(BT_DATA_MANUFACTURER_DATA, (unsigned char *)&mfg_data, sizeof(mfg_data)),
    	BT_DATA_BYTES(BT_DATA_UUID128_ALL, BT_UUID_DDFS_VAL),
    };
    
    #if SCAN_ENABLE
    static struct bt_le_scan_param scan_param = {
    	.type     = BT_LE_SCAN_TYPE_ACTIVE,
    	.interval = BT_GAP_SCAN_FAST_INTERVAL,
    	.window   = BT_GAP_SCAN_FAST_WINDOW,
    	.options  = BT_LE_SCAN_OPT_NONE,
    	.timeout  = 0,
    };
    
    static struct bt_scan_init_param scan_init = {
    	.connect_if_match = 0,
    	.scan_param = &scan_param,
    	.conn_param = NULL
    };
    #endif
    
    //static uint32_t scanner_random_share;
    
    static struct bt_le_ext_adv *adv;
    static void adv_work_handle(struct k_work *item);
    static K_WORK_DEFINE(adv_work, adv_work_handle);
    static void adv_update_data(void);
    //static uint32_t scanner_addr_to_random_share(const bt_addr_t *p_scanner_addr);
    //static uint32_t get_id_addr_random_share(void);
    
    #if SCAN_ENABLE
    static struct bt_scan_manufacturer_data scan_mfg_data = {
    	.data = (unsigned char *)&mfg_data,
    	.data_len = sizeof(mfg_data.company_code) + sizeof(mfg_data.support_dm_code),
    };
    
    
    static bool data_cb(struct bt_data *data, void *user_data)
    {
    	struct adv_mfg_data *recv_mfg_data;
    	struct dm_request req;
    
    	switch (data->type) {
    	case BT_DATA_MANUFACTURER_DATA:
    		if (sizeof(struct adv_mfg_data) == data->data_len) {
    			recv_mfg_data = (struct adv_mfg_data *)data->data;
    
    			bt_addr_le_copy(&req.bt_addr, user_data);
    			req.role = DM_ROLE_INITIATOR;
    			req.ranging_mode = peer_ranging_mode_get();
    			/* We need to make sure that we only initiate a ranging to a single peer.
    			 * A scan response that is received by this device can be received by
    			 * multiple other devices which can all start a ranging at the same time
    			 * as a consequence. To prevent this, we need to make sure that we set a
    			 * per-peer random as the random seed. This helps the ranging library to
    			 * avoid interference from other devices trying to range at the same time.
    			 *
    			 * This means that the initiator and the reflector need to set the same
    			 * value for the random seed.
    			 */
    			req.rng_seed =
    				sys_le32_to_cpu(recv_mfg_data->rng_seed);// + scanner_random_share;
    			req.start_delay_us = 0;
    			req.extra_window_time_us = 0;
    
    			dm_request_add(&req);
    		}
    		return false;
    	default:
    		return true;
    	}
    }
    #endif
    #if 0
    static uint32_t get_id_addr_random_share(void)
    {
    	bt_addr_le_t addrs[CONFIG_BT_ID_MAX];
    	size_t count = CONFIG_BT_ID_MAX;
    
    	bt_id_get(addrs, &count);
    
    	__ASSERT(count == 1, "The sample assumes a single ID addr");
    
    	return scanner_addr_to_random_share(&addrs[0].a);
    }
    
    static uint32_t scanner_addr_to_random_share(const bt_addr_t *p_scanner_addr)
    {
    	return (p_scanner_addr->val[0] | p_scanner_addr->val[1] << 8 |
    		p_scanner_addr->val[2] << 16 | p_scanner_addr->val[3] << 24) +
    	       (p_scanner_addr->val[4] | p_scanner_addr->val[5] << 8);
    }
    #endif
    
    #if SCAN_ENABLE
    static void scan_filter_match(struct bt_scan_device_info *device_info,
    			      struct bt_scan_filter_match *filter_match,
    			      bool connectable)
    {
    	bt_addr_le_t addr;
    
    	bt_addr_le_copy(&addr, device_info->recv_info->addr);
    	peer_supported_add(device_info->recv_info->addr);
    	bt_data_parse(device_info->adv_data, data_cb, &addr);
    }
    
    BT_SCAN_CB_INIT(scan_cb, scan_filter_match, NULL, NULL, NULL);
    #endif
    
    static void adv_scanned_cb(struct bt_le_ext_adv *adv,
    			struct bt_le_ext_adv_scanned_info *info)
    {
    	struct dm_request req;
    #if SCAN_ENABLE
    	if (peer_supported_test(info->addr)) {
    #endif
    		bt_addr_le_copy(&req.bt_addr, info->addr);
    		req.role = DM_ROLE_REFLECTOR;
    		req.ranging_mode = peer_ranging_mode_get();
    
    		/* We need to make sure that we only initiate a ranging to a single peer.
    		 * A scan response from this device can be received by multiple peers which can
    		 * all start a ranging at the same time as a consequence. To prevent this,
    		 * we need to make sure that we set a per-peer random as the random seed.
    		 * This helps the ranging library to avoid interference from other devices
    		 * trying to range at the same time.
    		 *
    		 * This means that the initiator and the reflector need to set the same value
    		 * for the random seed.
    		 */
    		req.rng_seed = peer_rng_seed_get();// + scanner_addr_to_random_share(&info->addr->a);
    		req.start_delay_us = 0;
    		req.extra_window_time_us = 0;
    
    		dm_request_add(&req);
    		adv_update_data();
    #if SCAN_ENABLE
    	}
    #endif
    }
    
    const static struct bt_le_ext_adv_cb adv_cb = {
    	.scanned = adv_scanned_cb,
    };
    
    static void adv_update_data(void)
    {
    	int err;
    
    	if (!adv) {
    		return;
    	}
    	mfg_data.rng_seed = peer_rng_seed_prepare();
    	err = bt_le_ext_adv_set_data(adv, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd));
    	if (err) {
    		printk("Failed setting adv data (err %d)\n", err);
    	}
    }
    
    static int adv_start(void)
    {
    	int err;
    	struct bt_le_ext_adv_start_param ext_adv_start_param = {0};
    
    	if (adv) {
    		err = bt_le_ext_adv_stop(adv);
    		if (err) {
    			printk("Failed to stop extended advertising  (err %d)\n", err);
    			return err;
    		}
    			err = bt_le_ext_adv_delete(adv);
    		if (err) {
    			printk("Failed to delete advertising set  (err %d)\n", err);
    			return err;
    		}
    	}
    
    	err = bt_le_ext_adv_create(adv_param, &adv_cb, &adv);
    	if (err) {
    		printk("Failed to create advertising set (err %d)\n", err);
    		return err;
    	}
    
    	err = bt_le_ext_adv_set_data(adv, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd));
    	if (err) {
    		printk("Failed setting adv data (err %d)\n", err);
    		return err;
    	}
    
    	err = bt_le_ext_adv_start(adv, &ext_adv_start_param);
    	if (err) {
    		printk("Failed to start extended advertising  (err %d)\n", err);
    		return err;
    	}
    
    	return err;
    }
    
    #if SCAN_ENABLE
    static int scan_start(void)
    {
    	int err;
    
    	bt_scan_init(&scan_init);
    	bt_scan_cb_register(&scan_cb);
    
    	err = bt_scan_filter_add(BT_SCAN_FILTER_TYPE_MANUFACTURER_DATA, &scan_mfg_data);
    	if (err) {
    		printk("Scanning filters cannot be set (err %d)\n", err);
    		return err;
    	}
    
    	err = bt_scan_filter_enable(BT_SCAN_MANUFACTURER_DATA_FILTER, false);
    	if (err) {
    		printk("Filters cannot be turned on (err %d)\n", err);
    		return err;
    	}
    
    	//scanner_random_share = get_id_addr_random_share();
    
    	err = bt_scan_start(BT_SCAN_TYPE_SCAN_ACTIVE);
    	if (err) {
    		printk("Scanning failed to start (err %d)\n", err);
    		return err;
    	}
    
    	return err;
    }
    #endif
    
    static void adv_work_handle(struct k_work *item)
    {
    	adv_start();
    }
    
    static void connected(struct bt_conn *conn, uint8_t conn_err)
    {
    	adv_param = &adv_param_noconn;
    	k_work_submit(&adv_work);
    
    	dk_set_led_on(CON_STATUS_LED);
    }
    
    static void disconnected(struct bt_conn *conn, uint8_t reason)
    {
    	adv_param = &adv_param_conn;
    	k_work_submit(&adv_work);
    
    	dk_set_led_off(CON_STATUS_LED);
    }
    
    BT_CONN_CB_DEFINE(conn_callbacks) = {
    	.connected = connected,
    	.disconnected = disconnected,
    };
    
    static int bt_sync_init(void)
    {
    	/* Synchronisation is based on advertising and scanning modes.
    	 * It occurs when SCAN_REQ and SCAN_RESP packets are exchanged.
    	 */
    
    	int err;
    
    	printk("DM Bluetooth LE Synchronization initialization\n");
    
    	mfg_data.company_code = sys_cpu_to_le16(CONFIG_BT_COMPANY_ID_NORDIC);
    	mfg_data.support_dm_code = sys_cpu_to_le32(SUPPORT_DM_CODE);
    	mfg_data.rng_seed = sys_cpu_to_le32(peer_rng_seed_prepare());
    
    	err = adv_start();
    	if (err) {
    		printk("Failed to start advertising (err %d)\n", err);
    		return err;
    	}
    
    #if SCAN_ENABLE
    	err = scan_start();
    	if (err) {
    		printk("Failed to start scanning (err %d)\n", err);
    	}
    #endif
    
    	return err;
    }
    
    static void data_ready(struct dm_result *result)
    {
    	if (result->status) {
    		peer_update(result);
    	}
    }
    
    static struct dm_cb dm_cb = {
    	.data_ready = data_ready,
    };
    
    int main(void)
    {
    	int err;
    	uint32_t blink_status = 0;
    	struct dm_init_param init_param;
    
    	printk("Starting Distance Measurement sample\n");
    
    	err = dk_leds_init();
    	if (err) {
    		printk("LEDs init failed (err %d)\n", err);
    		return 0;
    	}
    
    	err = peer_init();
    	if (err) {
    		printk("Peer init failed (err %d)\n", err);
    		return 0;
    	}
    
    	init_param.cb = &dm_cb;
    
    	err = dm_init(&init_param);
    	if (err) {
    		printk("Distance measurement init failed (err %d)\n", err);
    		return 0;
    	}
    
    	err = service_ddfs_init();
    	if (err) {
    		printk("DDF Service init failed (err %d)\n", err);
    		return 0;
    	}
    
    	err = bt_enable(NULL);
    	if (err) {
    		printk("Bluetooth init failed (err %d)\n", err);
    		return 0;
    	}
    
    	err = bt_sync_init();
    	if (err) {
    		printk("Synchronisation init failed (err %d)\n", err);
    		return 0;
    	}
    
    	for (;;) {
    		dk_set_led(RUN_STATUS_LED, (++blink_status) % 2);
    		k_sleep(K_MSEC(RUN_LED_BLINK_INTERVAL));
    		service_azimuth_elevation_simulation();
    	}
    }
    

    Also just the diff for simplicity:

    diff --git a/samples/bluetooth/nrf_dm/src/main.c b/samples/bluetooth/nrf_dm/src/main.c
    index ccb650a8e9..67305d8c0e 100644
    --- a/samples/bluetooth/nrf_dm/src/main.c
    +++ b/samples/bluetooth/nrf_dm/src/main.c
    @@ -32,6 +32,8 @@
     
     #define SUPPORT_DM_CODE         0xFF55AA5A
     
    +#define SCAN_ENABLE		0
    +
     struct adv_mfg_data {
     	uint16_t company_code;	    /* Company Identifier Code. */
     	uint32_t support_dm_code;   /* To identify the device that supports distance measurement. */
    @@ -67,6 +69,7 @@ static const struct bt_data sd[] = {
     	BT_DATA_BYTES(BT_DATA_UUID128_ALL, BT_UUID_DDFS_VAL),
     };
     
    +#if SCAN_ENABLE
     static struct bt_le_scan_param scan_param = {
     	.type     = BT_LE_SCAN_TYPE_ACTIVE,
     	.interval = BT_GAP_SCAN_FAST_INTERVAL,
    @@ -80,21 +83,24 @@ static struct bt_scan_init_param scan_init = {
     	.scan_param = &scan_param,
     	.conn_param = NULL
     };
    +#endif
     
    -static uint32_t scanner_random_share;
    +//static uint32_t scanner_random_share;
     
     static struct bt_le_ext_adv *adv;
     static void adv_work_handle(struct k_work *item);
     static K_WORK_DEFINE(adv_work, adv_work_handle);
     static void adv_update_data(void);
    -static uint32_t scanner_addr_to_random_share(const bt_addr_t *p_scanner_addr);
    -static uint32_t get_id_addr_random_share(void);
    +//static uint32_t scanner_addr_to_random_share(const bt_addr_t *p_scanner_addr);
    +//static uint32_t get_id_addr_random_share(void);
     
    +#if SCAN_ENABLE
     static struct bt_scan_manufacturer_data scan_mfg_data = {
     	.data = (unsigned char *)&mfg_data,
     	.data_len = sizeof(mfg_data.company_code) + sizeof(mfg_data.support_dm_code),
     };
     
    +
     static bool data_cb(struct bt_data *data, void *user_data)
     {
     	struct adv_mfg_data *recv_mfg_data;
    @@ -119,7 +125,7 @@ static bool data_cb(struct bt_data *data, void *user_data)
     			 * value for the random seed.
     			 */
     			req.rng_seed =
    -				sys_le32_to_cpu(recv_mfg_data->rng_seed) + scanner_random_share;
    +				sys_le32_to_cpu(recv_mfg_data->rng_seed);// + scanner_random_share;
     			req.start_delay_us = 0;
     			req.extra_window_time_us = 0;
     
    @@ -130,7 +136,8 @@ static bool data_cb(struct bt_data *data, void *user_data)
     		return true;
     	}
     }
    -
    +#endif
    +#if 0
     static uint32_t get_id_addr_random_share(void)
     {
     	bt_addr_le_t addrs[CONFIG_BT_ID_MAX];
    @@ -149,7 +156,9 @@ static uint32_t scanner_addr_to_random_share(const bt_addr_t *p_scanner_addr)
     		p_scanner_addr->val[2] << 16 | p_scanner_addr->val[3] << 24) +
     	       (p_scanner_addr->val[4] | p_scanner_addr->val[5] << 8);
     }
    +#endif
     
    +#if SCAN_ENABLE
     static void scan_filter_match(struct bt_scan_device_info *device_info,
     			      struct bt_scan_filter_match *filter_match,
     			      bool connectable)
    @@ -162,13 +171,15 @@ static void scan_filter_match(struct bt_scan_device_info *device_info,
     }
     
     BT_SCAN_CB_INIT(scan_cb, scan_filter_match, NULL, NULL, NULL);
    +#endif
     
     static void adv_scanned_cb(struct bt_le_ext_adv *adv,
     			struct bt_le_ext_adv_scanned_info *info)
     {
     	struct dm_request req;
    -
    +#if SCAN_ENABLE
     	if (peer_supported_test(info->addr)) {
    +#endif
     		bt_addr_le_copy(&req.bt_addr, info->addr);
     		req.role = DM_ROLE_REFLECTOR;
     		req.ranging_mode = peer_ranging_mode_get();
    @@ -183,13 +194,15 @@ static void adv_scanned_cb(struct bt_le_ext_adv *adv,
     		 * This means that the initiator and the reflector need to set the same value
     		 * for the random seed.
     		 */
    -		req.rng_seed = peer_rng_seed_get() + scanner_addr_to_random_share(&info->addr->a);
    +		req.rng_seed = peer_rng_seed_get();// + scanner_addr_to_random_share(&info->addr->a);
     		req.start_delay_us = 0;
     		req.extra_window_time_us = 0;
     
     		dm_request_add(&req);
     		adv_update_data();
    +#if SCAN_ENABLE
     	}
    +#endif
     }
     
     const static struct bt_le_ext_adv_cb adv_cb = {
    @@ -249,6 +262,7 @@ static int adv_start(void)
     	return err;
     }
     
    +#if SCAN_ENABLE
     static int scan_start(void)
     {
     	int err;
    @@ -268,7 +282,7 @@ static int scan_start(void)
     		return err;
     	}
     
    -	scanner_random_share = get_id_addr_random_share();
    +	//scanner_random_share = get_id_addr_random_share();
     
     	err = bt_scan_start(BT_SCAN_TYPE_SCAN_ACTIVE);
     	if (err) {
    @@ -278,6 +292,7 @@ static int scan_start(void)
     
     	return err;
     }
    +#endif
     
     static void adv_work_handle(struct k_work *item)
     {
    @@ -325,10 +340,12 @@ static int bt_sync_init(void)
     		return err;
     	}
     
    +#if SCAN_ENABLE
     	err = scan_start();
     	if (err) {
     		printk("Failed to start scanning (err %d)\n", err);
     	}
    +#endif
     
     	return err;
     }
    

    With this, make sure you build with SCAN_ENABLE set to 1 for the firmware to run on the initiator, and set it to 0 for the firmware to run on the reflector where you do not want scanning. Note that with SCAN_ENABLE set to 1 the device is still multirole as in the sample and will work in the same way except for not using a per-peer random seed.

  • Thank you for your help. Now I would like to further increase the speed of the distance measurement output. Which parameters can be adjusted?

  • Hi,

    I am sorry for the delay. The distance measurement by nature takes quite some time, but you can adjust scan and advertising parameters to affect it. More rapid advertising packets, and long and frequent scan windows increase the speed. Howwever, it also causes higher current consumption as described under Power consumption.

    The measurments are quite frequent if you use the sample as is or the modified sample with only one scanner, though. How high frequency do you want? And for my understanding, can you share why you need it faster (particularily at the cost of power consumption)?

Reply
  • Hi,

    I am sorry for the delay. The distance measurement by nature takes quite some time, but you can adjust scan and advertising parameters to affect it. More rapid advertising packets, and long and frequent scan windows increase the speed. Howwever, it also causes higher current consumption as described under Power consumption.

    The measurments are quite frequent if you use the sample as is or the modified sample with only one scanner, though. How high frequency do you want? And for my understanding, can you share why you need it faster (particularily at the cost of power consumption)?

Children
No Data
Related