Updating data in chained periodic advertising (1,650 bytes)

Hi team!

I have some doubts regarding updating the advertising data using periodic advertisements. We were able to advertise 1,650 bytes of data using periodic advertisements. But data does not get updated. I have explained everything in the points below. I request you to read through all of them. (Thanks in advance for your patience!)

The zephyr sample periodic_adv was taken as the base code. nRF Connect SDK v2.0.0 was used. The board used was nRF52840 DK. 

  1. Without chaining, the maximum AD Data buffer size that can be provided is 250 bytes. We provided the following buffer:
    static uint8_t mfg_data[] = { 0x59, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 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, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB};
    static const struct bt_data ad[] = {BT_DATA(BT_DATA_MANUFACTURER_DATA, mfg_data, 250),};


    and this was the main function:

    void main(void)
    {
    	struct bt_le_ext_adv *adv;
    	int err;
    
    	printk("Starting Periodic Advertising Demo\n");
    
          printk("Starting Periodic Advertising Demo\n");
          
          /*Function for setting a custom random static address*/
          set_random_static_address();
    
    	/* Initialize the Bluetooth Subsystem */
    	err = bt_enable(NULL);
    	if (err) {
    		printk("Bluetooth init failed (err %d)\n", err);
    		return;
    	}
    
    	
    /* Create a non-connectable non-scannable advertising set */
    	err = bt_le_ext_adv_create(BT_LE_EXT_ADV_NCONN_IDENTITY, NULL, &adv);
    	if (err) {
    		printk("Failed to create advertising set (err %d)\n", err);
    		return;
    	}
    	/* Set periodic advertising parameters */
    	struct bt_le_per_adv_param periodic_param = BT_LE_PER_ADV_PARAM_INIT(0x1f40, 0x1f40, BT_LE_PER_ADV_OPT_NONE); //for 10s
    
    	err = bt_le_per_adv_set_param(adv, &periodic_param);
    	if (err) {
    		printk("Failed to set periodic advertising parameters (err %d)\n", err);
    		return;
    	}
    
    
    	err = bt_le_per_adv_start(adv);
    	if (err) {
    		printk("Failed to enable periodic advertising (err %d)\n", err);
    		return;
    	}
    
    	/* Enable Extended Advertising */
    	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");
    
    	while (true) {
    		
                mfg_data[2]=0;
    		for (int i = 0; i < 5; i++) {
    			k_sleep(K_SECONDS(10));
    
    			mfg_data[2]++;
    
    			printk("Set Periodic Advertising Data...");
    			err = bt_le_per_adv_set_data(adv, ad, ARRAY_SIZE(ad));
    			if (err) {
    				printk("Failed (err %d)\n", err);
    				return;
    			}
    			printk("done.\n");
    		}
    		
    	}
    }
    


    Please notice that the bt_le_per_adv_set_data() has only been called inside the while loop, after calling the bt_le_per_adv_start() function. This is the PuTTY output for this code:



    Clearly, the updated data gets successfully advertised. It was also verified using Wireshark, AUX_SYNC_IND packets with updated data are received at intervals of 10 seconds, which is also the value of periodic advertising interval.

  2. Next, the same code was used to advertise 1,650 bytes (maximum allowed) of advertising data, and the same approach was used as mentioned in one of my previous tickets (link). The following buffer was provided:

    static uint8_t mfg_data[] = { 0x59, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 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, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB};
    
    
    static const struct bt_data ad[] = {BT_DATA(BT_DATA_MANUFACTURER_DATA, mfg_data, 254),
    				    BT_DATA(BT_DATA_MANUFACTURER_DATA, mfg_data, 254),  
    				    BT_DATA(BT_DATA_MANUFACTURER_DATA, mfg_data, 254),  
    				    BT_DATA(BT_DATA_MANUFACTURER_DATA, mfg_data, 254),  
    				    BT_DATA(BT_DATA_MANUFACTURER_DATA, mfg_data, 254),  
    				    BT_DATA(BT_DATA_MANUFACTURER_DATA, mfg_data, 254),  
    				    BT_DATA(BT_DATA_MANUFACTURER_DATA, mfg_data, 112),};


    No changes were made to the main function. It was the same as mentioned in the first point. This was the output at the PuTTY terminal:



    The function bt_le_per_adv_set_data() threw error EINVAL. 

  3. Next, using the same buffer (for 1,650 bytes) we called the bt_le_per_adv_set_data() once before the bt_le_per_adv_start() function, and then again called bt_le_per_adv_set_data() inside the while loop at intervals of 10 seconds for updating the data, as shown in the code below:

    void main(void)
    {
    	struct bt_le_ext_adv *adv;
    	int err;
    
    	printk("Starting Periodic Advertising Demo\n");
    
          printk("Starting Periodic Advertising Demo\n");
          
          /*Function for setting a custom random static address*/
          set_random_static_address();
    
    	/* Initialize the Bluetooth Subsystem */
    	err = bt_enable(NULL);
    	if (err) {
    		printk("Bluetooth init failed (err %d)\n", err);
    		return;
    	}
    
    	
    /* Create a non-connectable non-scannable advertising set */
    	err = bt_le_ext_adv_create(BT_LE_EXT_ADV_NCONN_IDENTITY, NULL, &adv);
    	if (err) {
    		printk("Failed to create advertising set (err %d)\n", err);
    		return;
    	}
    	/* Set periodic advertising parameters */
    	struct bt_le_per_adv_param periodic_param = BT_LE_PER_ADV_PARAM_INIT(0x1f40, 0x1f40, BT_LE_PER_ADV_OPT_NONE); //for 10s
    
    	err = bt_le_per_adv_set_param(adv, &periodic_param);
    	if (err) {
    		printk("Failed to set periodic advertising parameters (err %d)\n", err);
    		return;
    	}
    
    
    	printk("Set Periodic Advertising Data...");
    			err = bt_le_per_adv_set_data(adv, ad, ARRAY_SIZE(ad));
    			if (err) {
    				printk("Failed (err %d)\n", err);
    				return;
    			}
    			printk("done.\n"); 
    
        
        /* Enable Periodic Advertising */
    	err = bt_le_per_adv_start(adv);
    	if (err) {
    		printk("Failed to enable periodic advertising (err %d)\n", err);
    		return;
    	}
    
    	/* Enable Extended Advertising */
    	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");
    
    	while (true) {
    		
                mfg_data[2]=0;
    		for (int i = 0; i < 5; i++) {
    			k_sleep(K_SECONDS(10));
    
    			mfg_data[2]++;
    
    			printk("Set Periodic Advertising Data...");
    			err = bt_le_per_adv_set_data(adv, ad, ARRAY_SIZE(ad));
    			if (err) {
    				printk("Failed (err %d)\n", err);
    				return;
    			}
    			printk("done.\n");
    		}
    		
    	}
    }
    


    This is what we got at the PuTTY terminal:


    In this case, the periodic advertising data was set once, but data updation failed with error -22. We observed the received packets in Wireshark. PDUs with 1,650 bytes of payload were received at intervals of 10 seconds (periodic advertising interval), but all of them contained the same data since data updation failed. 

Now, I have the following concerns:

  • It is clear that it is possible to advertise 1,650 bytes of data in periodic advertisements. But, why does this data not get updated?
  • The bt_le_per_adv_set_data() function fails when called after the bt_le_per_adv_start() function, but works fine if called before bt_le_per_adv_start() function. Why is this happening?
  • If the order of these two functions matters, why are no errors encountered when the bt_le_per_adv_set_data() function is called after bt_le_per_adv_start(), in cases when there is no chaining? (sending up to 250 bytes of AD Data)

I am also attaching the complete code and the prj.conf file for your reference:

/*
 * Copyright (c) 2020 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_vs.h>
#include <sys/byteorder.h>

static uint8_t mfg_data[] = { 0x59, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 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, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB};


static const struct bt_data ad[] = {BT_DATA(BT_DATA_MANUFACTURER_DATA, mfg_data, 254),
				    BT_DATA(BT_DATA_MANUFACTURER_DATA, mfg_data, 254),  
				    BT_DATA(BT_DATA_MANUFACTURER_DATA, mfg_data, 254),  
				    BT_DATA(BT_DATA_MANUFACTURER_DATA, mfg_data, 254),  
				    BT_DATA(BT_DATA_MANUFACTURER_DATA, mfg_data, 254),  
				    BT_DATA(BT_DATA_MANUFACTURER_DATA, mfg_data, 254),  
				    BT_DATA(BT_DATA_MANUFACTURER_DATA, mfg_data, 112),};


static void set_random_static_address(void)
{
int err;
        int err1;
printk("Starting iBeacon Demo\n");
       
bt_addr_le_t addr;

//convert the string into a binary address and stores this address in a buffer whose address is addr.
err=bt_addr_le_from_str("DE:AD:BE:AF:BA:11","random" , &addr);  //Only random static address can be given when the type is set to "random"
                if (err) {
printk("Invalid BT address (err %d)\n", err);
                         }

//create a new Identity address. This must be done before enabling Bluetooth. Addr is the address used for the new identity
err1=bt_id_create(&addr, NULL);
                if (err1 < 0) {
printk("Creating new ID failed (err %d)\n", err1);
}
            printk("Created new address\n");
 }


void main(void)
{
	struct bt_le_ext_adv *adv;
	int err;

	printk("Starting Periodic Advertising Demo\n");

      printk("Starting Periodic Advertising Demo\n");
      set_random_static_address();

	/* Initialize the Bluetooth Subsystem */
	err = bt_enable(NULL);
	if (err) {
		printk("Bluetooth init failed (err %d)\n", err);
		return;
	}


/* Create a non-connectable non-scannable advertising set */
	err = bt_le_ext_adv_create(BT_LE_EXT_ADV_NCONN_IDENTITY, NULL, &adv);
	if (err) {
		printk("Failed to create advertising set (err %d)\n", err);
		return;
	}
	/* Set periodic advertising parameters */
	struct bt_le_per_adv_param periodic_param = BT_LE_PER_ADV_PARAM_INIT(0x1f40, 0x1f40, BT_LE_PER_ADV_OPT_NONE); //for 10s

	err = bt_le_per_adv_set_param(adv, &periodic_param);
	if (err) {
		printk("Failed to set periodic advertising parameters (err %d)\n", err);
		return;
	}

	

	/* Enable Periodic Advertising */
	printk("Set Periodic Advertising Data...");
			err = bt_le_per_adv_set_data(adv, ad, ARRAY_SIZE(ad));
			if (err) {
				printk("Failed (err %d)\n", err);
				return;
			}
			printk("done.\n"); 

	err = bt_le_per_adv_start(adv);
	if (err) {
		printk("Failed to enable periodic advertising (err %d)\n", err);
		return;
	}

	/* Enable Extended Advertising */
	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");

	while (true) {
		
            mfg_data[2]=0;
		for (int i = 0; i < 5; i++) {
			k_sleep(K_SECONDS(10));

			mfg_data[2]++;

			printk("Set Periodic Advertising Data...");
			err = bt_le_per_adv_set_data(adv, ad, ARRAY_SIZE(ad));
			if (err) {
				printk("Failed (err %d)\n", err);
				return;
			}
			printk("done.\n");
		}
		
	}
}

CONFIG_BT=y
CONFIG_BT_EXT_ADV=y
CONFIG_BT_PER_ADV=y
CONFIG_BT_DEBUG_LOG=y
CONFIG_BT_DEVICE_NAME="Test Periodic Advertising"

CONFIG_LOG=y
CONFIG_BT_CTLR_ADV_EXT=y
CONFIG_BT_CTLR_ADV_PERIODIC=y
CONFIG_BT_CTLR_ADV_DATA_LEN_MAX=1650
CONFIG_SENSOR_LOG_LEVEL_DBG=y


I also have another doubt regarding periodic advertisements

Going by the Bluetooth core specification (version 5.3, Page 2768):


When including the ADI field is enabled by the Host and where the periodic advertising data is not changed for every periodic advertising event, the Controller should include the ADI field in the AUX_SYNC_IND PDU.


Does this mean that if the data is changed for every periodic advertising event, ADI field should be included in the AUX_SYNC_IND PDU? I also came across this section in the feature enhancement document of Bluetooth version 5.3:

The ADI field of the Common Extended Advertising Payload Format may now optionally be included in AUX_SYNC_IND periodic advertising PDUs by the controller in a broadcasting device at the request of the host.

and..

AUX_SYNC_IND PDUs may now include the ADI field. The inclusion of the ADI field in this PDU type is optional however and the controller’s link layer implementation will only include ADI in this packet type if the host requests that this be done by sending an HCI LE Set Periodic Advertising Enable command to the controller.

How exactly does the host "request" the inclusion of ADI in AUX_SYNC_IND? By changing advertising data in every periodic advertising event?

In my implementation where I update the advertising data in each periodic advertising event (which I'm currently able to do only when there are no chain PDUs used), Extended advertising header is absent in each AUX_SYNC_IND PDU, which means that ADI field is absent.

Is ADI inclusion not implemented in the SDK yet? Or is there a problem with my understanding?

Parents Reply Children
No Data
Related