Extended Advertising - reception and data size

Hi,

I recently started with nRF52840-DK, Zephyr and nRF Connect SDK (v. 1.9.1). I want to test extended advertising. Since there is no example of "pure" extended advertising (i.e. no periodic), I modified the periodic_adv example. Modification is quite easy: In prj.conf setting CONFIG_BT_PER_ADV=n, in main.c skipping bt_le_per_adv_set_param() and bt_le_per_adv_start(), usage of bt_le_ext_adv_set_data() instead of bt_le_per_adv_set_data(). Now extended advertising runs well. With a Sodera sniffer, I can see three ADV_EXT_IND frames in channels 37/38/39, followed by an AUX_ADV_IND frame in one of the data channels. The AUX_ADV_IND frame contains two AD elements: One with the data I want to transmit and one with the complete local name as set in prj.conf.

For reception, I use the periodic_sync example, which should support extended advertising without the periodic functionality too.

Now the questions:

My receiver calls the scan_recv function, but always I see only one of the AD elements. The buffer contains only the AD element with the local name, which is the last one in the frame (according to the sniffer raw data). There is no indication of the reception of my data in the second AD element. What have I to do to receive both (or even more) AD elements? What is the intention here - to have several calls of scan_recv for every AD element or to have a list of buffers or something else?

Parents
  • Hi

    So, it seems like using the BT_LE_ADV_PARAM_INIT helper sorts this issue out, as well as some additional prj.conf options on the scanner side. Let me know if you want us to explain more in detail, but these modified main files should be sufficient to solve your issue at least: 

    /*
     * Copyright (c) 2020 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    
    // modified periodic_sync example of ncs to test "pure" extended advertising
    
    #include <device.h>
    #include <devicetree.h>
    #include <drivers/gpio.h>
    #include <bluetooth/bluetooth.h>
    
    /* prj.conf:
     * CONFIG_BT=y
     * CONFIG_BT_EXT_ADV=y
     * CONFIG_BT_OBSERVER=y
     * CONFIG_BT_PER_ADV_SYNC=n
     * CONFIG_BT_DEBUG_LOG=y
     * CONFIG_BT_DEVICE_NAME="Test Reception of Extended Adv"
     * CONFIG_BT_CTLR=y
     * CONFIG_BT_HCI=y
     * CONFIG_BT_CTLR_PHY_2M=y
     * CONFIG_BT_CTLR_PHY_CODED=y
     * CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX=1650
     * CONFIG_BT_EXT_SCAN_BUF_SIZE=1650
     */
    
    static void scan_recv(const struct bt_le_scan_recv_info *info,
    		      struct net_buf_simple *buf)
    {
    	if ((buf->data[3] == 0xff) && (buf->data[5] == 0xbb)){   // i.e. my frames
    		printk("Adv type : %d \n", info->adv_type);
    		printk("net_buf_simple_max_length: %u\n", net_buf_simple_max_len(buf));
    		printk("    %.2X %.2X %.2X\n", buf->data[3], buf->data[4], buf->data[5]);
    		for(int i = 0; i < 254; i++){
    			//Just to check output
    		  	printk("\n %.2X",  buf->data[i]);
    		}
    	}
    }
    
    static struct bt_le_scan_cb scan_callbacks = {
    	.recv = scan_recv,
    };
    
    void main(void)
    {
    	int err;
    
    	printk("Starting Axel's Extended Advertising Reception Demo\n");
    	printk("\n");
    	printk("CONFIG_BT_CTLR_ADV_DATA_LEN_MAX : %d\n", CONFIG_BT_CTLR_ADV_DATA_LEN_MAX);
    	printk("CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX: %d\n", CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX);
    	printk("\n");
    
    
    	/* Initialize the Bluetooth Subsystem */
    	err = bt_enable(NULL);
    	if (err) {
    		printk("Bluetooth init failed (err %d)\n", err);
    		return;
    	}
    
    	printk("Scan callbacks register...");
    	bt_le_scan_cb_register(&scan_callbacks);
    	printk("success.\n");
    
    
    	printk("Start scanning...");
    	err = bt_le_scan_start(BT_LE_SCAN_ACTIVE , NULL);
    	//err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, NULL);
    	if (err) {
    		printk("failed (err %d)\n", err);
    		return;
    	}
    	printk("success.\n");
    
    	do {
    	} while (true);
    }
    

    /*
     * Copyright (c) 2020 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    
    // modified periodic_adv example of ncs to test "pure" extended advertising
    
    #include <bluetooth/bluetooth.h>
    
    /* prj.conf:
     * CONFIG_BT=y
     * CONFIG_BT_EXT_ADV=y
     * CONFIG_BT_PER_ADV=n
     * CONFIG_BT_DEBUG_LOG=y
     * CONFIG_BT_DEVICE_NAME="ABC"
     * CONFIG_BT_CTLR_PHY_2M=y
     * CONFIG_BT_CTLR_PHY_CODED=y
     * CONFIG_BT_CTLR_ADV_DATA_LEN_MAX=1650
     */
    
    // up to 0xde (length 227) possible to receive, up to 0xf4 (length 249) possible to transmit
    static uint8_t mfg_data[] = { 0xff, 0xff, 0x00, 0xbb, 0xDD, 0xDD, 0xDE, 0xDA, 0xDA, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,\
                                                          0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,\
                                                          0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,\
                                                          0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,\
                                                          0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,\
                                                          0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,\
                                                          0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,\
                                                          0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,\
                                                          0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,\
                                                          0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,\
                                                          0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,\
                                                          0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,\
                                                          0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,\
                                                          0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,\
                                                          0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,\
                                                          0xf0, 0xf1, 0xf2, 0xf3, 0xf4};
    
    static const struct bt_data ad[] = {
    	BT_DATA(BT_DATA_MANUFACTURER_DATA,  mfg_data, 249),
    };
    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);
    void main(void)
    {
    	struct bt_le_ext_adv *adv;
    	int err;
    
    	printk("Starting Advertising Timing Demo\n");
    	printk("\n");
    	printk("CONFIG_BT_CTLR_ADV_DATA_LEN_MAX: %d\n", CONFIG_BT_CTLR_ADV_DATA_LEN_MAX);
    	printk("\n");
    
    	/* Initialize the Bluetooth Subsystem */
    	err = bt_enable(NULL);
    	if (err) {
    		printk("Bluetooth init failed (err %d)\n", err);
    		return;
    	}
    
    
    	err = bt_le_ext_adv_create(&param, NULL, &adv);
    	if (err) {
    		printk("Failed to create advertising set (err %d)\n", err);
    		return;
    	}
    
    	printk("Set Advertising Data, length mfg_data[]: %d ...", ARRAY_SIZE(mfg_data));
    	err = bt_le_ext_adv_set_data(adv, ad, ARRAY_SIZE(ad), NULL, 0);
    	if (err) {
    		printk("Failed (err %d)\n", err);
    		return;
    	}
    	printk("done.\n");
    
    	while (true) {
    		printk("Start Extended Advertising...");
    		err = bt_le_ext_adv_start(adv, BT_LE_EXT_ADV_START_DEFAULT);
    		if (err) {
    			printk("Failed to start extended advertising (err %d)\n", err);
    			return;
    		}
    		printk("done.\n");
    
    		k_sleep(K_MSEC(44));  // try to send every data set just once -- mostly ok, in a few cases sending a frame twice, which is ok
    
    		printk("Stop Extended Advertising...");
    		err = bt_le_ext_adv_stop(adv);
    		if (err) {
    			printk("Failed to stop extended advertising (err %d)\n", err);
    			return;
    		}
    		printk("done.\n");
    
    		mfg_data[2]++;
    
    		printk("Set Advertising Data...");
    		err = bt_le_ext_adv_set_data(adv, ad, ARRAY_SIZE(ad), NULL, 0);
    		if (err) {
    			printk("Failed (err %d)\n", err);
    			return;
    		}
    		printk("done.\n");
    
    		k_sleep(K_SECONDS(1));
    	}
    }
    

    Best regards,

    Simon

Reply
  • Hi

    So, it seems like using the BT_LE_ADV_PARAM_INIT helper sorts this issue out, as well as some additional prj.conf options on the scanner side. Let me know if you want us to explain more in detail, but these modified main files should be sufficient to solve your issue at least: 

    /*
     * Copyright (c) 2020 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    
    // modified periodic_sync example of ncs to test "pure" extended advertising
    
    #include <device.h>
    #include <devicetree.h>
    #include <drivers/gpio.h>
    #include <bluetooth/bluetooth.h>
    
    /* prj.conf:
     * CONFIG_BT=y
     * CONFIG_BT_EXT_ADV=y
     * CONFIG_BT_OBSERVER=y
     * CONFIG_BT_PER_ADV_SYNC=n
     * CONFIG_BT_DEBUG_LOG=y
     * CONFIG_BT_DEVICE_NAME="Test Reception of Extended Adv"
     * CONFIG_BT_CTLR=y
     * CONFIG_BT_HCI=y
     * CONFIG_BT_CTLR_PHY_2M=y
     * CONFIG_BT_CTLR_PHY_CODED=y
     * CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX=1650
     * CONFIG_BT_EXT_SCAN_BUF_SIZE=1650
     */
    
    static void scan_recv(const struct bt_le_scan_recv_info *info,
    		      struct net_buf_simple *buf)
    {
    	if ((buf->data[3] == 0xff) && (buf->data[5] == 0xbb)){   // i.e. my frames
    		printk("Adv type : %d \n", info->adv_type);
    		printk("net_buf_simple_max_length: %u\n", net_buf_simple_max_len(buf));
    		printk("    %.2X %.2X %.2X\n", buf->data[3], buf->data[4], buf->data[5]);
    		for(int i = 0; i < 254; i++){
    			//Just to check output
    		  	printk("\n %.2X",  buf->data[i]);
    		}
    	}
    }
    
    static struct bt_le_scan_cb scan_callbacks = {
    	.recv = scan_recv,
    };
    
    void main(void)
    {
    	int err;
    
    	printk("Starting Axel's Extended Advertising Reception Demo\n");
    	printk("\n");
    	printk("CONFIG_BT_CTLR_ADV_DATA_LEN_MAX : %d\n", CONFIG_BT_CTLR_ADV_DATA_LEN_MAX);
    	printk("CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX: %d\n", CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX);
    	printk("\n");
    
    
    	/* Initialize the Bluetooth Subsystem */
    	err = bt_enable(NULL);
    	if (err) {
    		printk("Bluetooth init failed (err %d)\n", err);
    		return;
    	}
    
    	printk("Scan callbacks register...");
    	bt_le_scan_cb_register(&scan_callbacks);
    	printk("success.\n");
    
    
    	printk("Start scanning...");
    	err = bt_le_scan_start(BT_LE_SCAN_ACTIVE , NULL);
    	//err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, NULL);
    	if (err) {
    		printk("failed (err %d)\n", err);
    		return;
    	}
    	printk("success.\n");
    
    	do {
    	} while (true);
    }
    

    /*
     * Copyright (c) 2020 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    
    // modified periodic_adv example of ncs to test "pure" extended advertising
    
    #include <bluetooth/bluetooth.h>
    
    /* prj.conf:
     * CONFIG_BT=y
     * CONFIG_BT_EXT_ADV=y
     * CONFIG_BT_PER_ADV=n
     * CONFIG_BT_DEBUG_LOG=y
     * CONFIG_BT_DEVICE_NAME="ABC"
     * CONFIG_BT_CTLR_PHY_2M=y
     * CONFIG_BT_CTLR_PHY_CODED=y
     * CONFIG_BT_CTLR_ADV_DATA_LEN_MAX=1650
     */
    
    // up to 0xde (length 227) possible to receive, up to 0xf4 (length 249) possible to transmit
    static uint8_t mfg_data[] = { 0xff, 0xff, 0x00, 0xbb, 0xDD, 0xDD, 0xDE, 0xDA, 0xDA, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,\
                                                          0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,\
                                                          0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,\
                                                          0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,\
                                                          0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,\
                                                          0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,\
                                                          0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,\
                                                          0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,\
                                                          0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,\
                                                          0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,\
                                                          0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,\
                                                          0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,\
                                                          0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,\
                                                          0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,\
                                                          0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,\
                                                          0xf0, 0xf1, 0xf2, 0xf3, 0xf4};
    
    static const struct bt_data ad[] = {
    	BT_DATA(BT_DATA_MANUFACTURER_DATA,  mfg_data, 249),
    };
    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);
    void main(void)
    {
    	struct bt_le_ext_adv *adv;
    	int err;
    
    	printk("Starting Advertising Timing Demo\n");
    	printk("\n");
    	printk("CONFIG_BT_CTLR_ADV_DATA_LEN_MAX: %d\n", CONFIG_BT_CTLR_ADV_DATA_LEN_MAX);
    	printk("\n");
    
    	/* Initialize the Bluetooth Subsystem */
    	err = bt_enable(NULL);
    	if (err) {
    		printk("Bluetooth init failed (err %d)\n", err);
    		return;
    	}
    
    
    	err = bt_le_ext_adv_create(&param, NULL, &adv);
    	if (err) {
    		printk("Failed to create advertising set (err %d)\n", err);
    		return;
    	}
    
    	printk("Set Advertising Data, length mfg_data[]: %d ...", ARRAY_SIZE(mfg_data));
    	err = bt_le_ext_adv_set_data(adv, ad, ARRAY_SIZE(ad), NULL, 0);
    	if (err) {
    		printk("Failed (err %d)\n", err);
    		return;
    	}
    	printk("done.\n");
    
    	while (true) {
    		printk("Start Extended Advertising...");
    		err = bt_le_ext_adv_start(adv, BT_LE_EXT_ADV_START_DEFAULT);
    		if (err) {
    			printk("Failed to start extended advertising (err %d)\n", err);
    			return;
    		}
    		printk("done.\n");
    
    		k_sleep(K_MSEC(44));  // try to send every data set just once -- mostly ok, in a few cases sending a frame twice, which is ok
    
    		printk("Stop Extended Advertising...");
    		err = bt_le_ext_adv_stop(adv);
    		if (err) {
    			printk("Failed to stop extended advertising (err %d)\n", err);
    			return;
    		}
    		printk("done.\n");
    
    		mfg_data[2]++;
    
    		printk("Set Advertising Data...");
    		err = bt_le_ext_adv_set_data(adv, ad, ARRAY_SIZE(ad), NULL, 0);
    		if (err) {
    			printk("Failed (err %d)\n", err);
    			return;
    		}
    		printk("done.\n");
    
    		k_sleep(K_SECONDS(1));
    	}
    }
    

    Best regards,

    Simon

Children
  • Hi Simon,

    I had a week off, that's why answering now.

    Thanks for your suggestions. I think the main clue is CONFIG_BT_EXT_SCAN_BUF_SIZE - now I can receive 249 data bytes (probably even more). On advertiser side I still use my old config. A few tests showed that the dev is including data chaining when setting that max size of 1650 and trying to send the 249 bytes I was able to send before - there is an extension of the extended header by an AUX pointer field (3 bytes), reducing the data size a little. Therefore I still use CONFIG_BT_CTLR_ADV_DATA_LEN_MAX=255.

    The main goal was to use the max data size of a single frame, which is running, as far as I see right now. Thanks!

Related