This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Updating advertising data (manuf. spec. data) in SDK15

Hello guys! And girls Slight smile

My project is working as expected in SDK14.2.
I'm updating adv data (manuf. spec. data) without any problem with this function

static void advertising_data_update(uint8_t adv_manuf_byte)
{
		ret_code_t err_code;

		ble_advertising_init_t 		init;
		ble_advdata_manuf_data_t 	adv_manuf_data;
		uint8_array_t            	adv_manuf_data_array;
		uint8_t                  	adv_manuf_data_data[1];
		adv_manuf_data_data[0] 		= adv_manuf_byte;

		memset(&init, 0, sizeof(init));

		init.advdata.name_type          		 = BLE_ADVDATA_FULL_NAME;
		init.advdata.include_appearance 		 = false;
		init.advdata.flags              		 = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
		init.advdata.uuids_complete.uuid_cnt = sizeof(m_adv_uuids) / sizeof(m_adv_uuids[0]);
		init.advdata.uuids_complete.p_uuids  = m_adv_uuids;

		adv_manuf_data_array.p_data 							 = adv_manuf_data_data;
		adv_manuf_data_array.size 								 = sizeof(adv_manuf_data_data);
		adv_manuf_data.company_identifier 				 = APP_COMPANY_IDENTIFIER;
		adv_manuf_data.data 											 = adv_manuf_data_array;
		init.advdata.p_manuf_specific_data 				 = &adv_manuf_data;

		init.config.ble_adv_whitelist_enabled      = true;
		init.config.ble_adv_directed_enabled       = true;
		init.config.ble_adv_directed_slow_enabled  = false;
		init.config.ble_adv_directed_slow_interval = 0;
		init.config.ble_adv_directed_slow_timeout  = 0;
		init.config.ble_adv_fast_enabled  				 = true;
		init.config.ble_adv_fast_interval 				 = APP_ADV_INTERVAL;
		init.config.ble_adv_fast_timeout  				 = APP_ADV_TIMEOUT_IN_SECONDS;
							
		err_code = ble_advdata_set(&init.advdata, NULL);
		APP_ERROR_CHECK(err_code);	   
}


But in SDK15 the function ble_advdata_set() has been deprecated.
The migration guide is says to use ble_advdata_encode() and sd_ble_gap_adv_set_configure() instead.

So I changed it to something like this

static void advertising_data_update(uint8_t adv_manuf_byte)
{
		ret_code_t err_code;

		ble_advertising_init_t 		init;
		ble_advdata_manuf_data_t 	adv_manuf_data;
		uint8_array_t            	adv_manuf_data_array;
		adv_manuf_data_data[0] 		= adv_manuf_byte;

		memset(&init, 0, sizeof(init));

    init.advdata.name_type          		 = BLE_ADVDATA_FULL_NAME;
    init.advdata.include_appearance 		 = false;
    init.advdata.flags              		 = BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE;
    init.advdata.uuids_complete.uuid_cnt = sizeof(m_adv_uuids) / sizeof(m_adv_uuids[0]);
    init.advdata.uuids_complete.p_uuids  = m_adv_uuids;
			
		adv_manuf_data_array.p_data 							 = adv_manuf_data_data;
		adv_manuf_data_array.size 								 = sizeof(adv_manuf_data_data);
		adv_manuf_data.company_identifier 				 = APP_COMPANY_IDENTIFIER;
		adv_manuf_data.data 											 = adv_manuf_data_array;
		init.advdata.p_manuf_specific_data 				 = &adv_manuf_data;

    init.config.ble_adv_whitelist_enabled      			= true;
		init.config.ble_adv_directed_high_duty_enabled 	= true;
    init.config.ble_adv_directed_enabled       			= false;
    init.config.ble_adv_fast_enabled  				 			= true;
    init.config.ble_adv_fast_interval 				 			= APP_ADV_INTERVAL;
    init.config.ble_adv_fast_timeout  				 			= APP_ADV_FAST_DURATION;

		//err_code = sd_ble_gap_adv_stop(m_advertising.adv_handle);
		//APP_ERROR_CHECK(err_code);
			
		err_code = ble_advdata_encode(&init.advdata, m_adv_data.adv_data.p_data, &m_adv_data.adv_data.len);	
		APP_ERROR_CHECK(err_code);

		err_code = sd_ble_gap_adv_set_configure(&m_advertising.adv_handle, &m_adv_data, NULL);
		APP_ERROR_CHECK(err_code);
		
		//err_code = sd_ble_gap_adv_start(m_advertising.adv_handle, APP_BLE_CONN_CFG_TAG);
		//APP_ERROR_CHECK(err_code);
}


And of course... it's not working. :)
I'm getting a very strange error at sd_ble_gap_adv_set_configure() --> app: ERROR 12801 [Unknown error code]

Any idea why?
What I'm doing wrong?
What I have to change to get this working like in the SDK14.2?

Parents
  • I had same issue with SDK 15. Read thru several forums including this one with no real answer. I too was using the Advertising Module with 

    BLE_ADVERTISING_DEF(advertiseModule);
    I found the answer to my problem by digging into what SDK's ble_advertising_init was using when it calls ble_advdata_encode. It uses the encoded buffer inside advertiseModule. I was mistakenly creating my own buffer and passing it to ble_advdata_encode.
    Once I used the following functions, everything worked fine. Even without restarting advertising.
    static void advertiseInit(void) {
        // Only call once at start of program.
        servicesToAdvertise[0] = someServiceUUID;
    
        static ble_advdata_manuf_data_t advertMfgData;
        memset(&advertMfgData, 0, sizeof(advertMfgData));
        advertMfgData.data.p_data = (uint8_t*)&mfgData;
        advertMfgData.data.size = sizeof(mfgData);
    
        memset(&init, 0, sizeof(init));
        init.advdata.name_type = BLE_ADVDATA_FULL_NAME;
        init.advdata.include_appearance = false;
        init.advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
        init.advdata.uuids_complete.uuid_cnt = NUM_SERVICES_TO_ADVERTISE;
        init.advdata.uuids_complete.p_uuids = servicesToAdvertise;
        init.advdata.p_manuf_specific_data = &advertMfgData;
    
        init.config.ble_adv_fast_enabled = true;
        init.config.ble_adv_fast_interval = APP_ADV_INTERVAL;
        init.config.ble_adv_fast_timeout = BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED;
        init.config.ble_adv_on_disconnect_disabled = true; // true = Let our code handle the restart
    
        init.evt_handler = advertiseEventHandler;
        init.error_handler = advertiseErrorHandler;
    
        ret_code_t err_code = ble_advertising_init(&advertiseModule, &init);
        APP_ERROR_CHECK(err_code);
    
        ble_advertising_conn_cfg_tag_set(&advertiseModule, APP_BLE_CONN_CFG_TAG);
    
        err_code = sd_ble_gap_tx_power_set(BLE_GAP_TX_POWER_ROLE_ADV, advertiseModule.adv_handle, TX_POWER_LEVEL);
        APP_ERROR_CHECK(err_code);
    }
    
    void advertisingUpdateMfgData(void) {
      mfgData.inventoryCount = userData.count;
      ret_code_t err_code = ble_advdata_encode(&init.advdata, advertiseModule.enc_advdata, &advertiseModule.adv_data.adv_data.len);
      APP_ERROR_CHECK(err_code);
    }
    Notes:
      1) that advertiseModule.enc_advdata is not my buffer. It was created by SDK when using BLE_ADVERTISING_DEF(advertiseModule) and  ble_advertising_init.
  • You do NOT have to stop/restart advertising to change the data inside the advert packets. I dynamically update advert payloads on several projects while advertising. The above code I posted is working in one of my projects, but I do have another way that I use in others. The other way deals with being able to change the data on every radio transmit. Posting the code below.

    1) In main.c
    Note: I keep my main.c to a bare minimum (< 200 lines or so) and put other functionality in associated .c/.h files. KEEP IT CLEAN! :) Below is just an example of initialization flow and how to update adverts without restarting advertising and on every radio tx (which you can just keep send the same data and/or change as needed).

    int main(void) {
    	logInit();
    	timersInit();
    	gpioInit();
    	... other peripheral inits, like TWI/SPI/buttons/etc ...
    	schedulerInit();
    	printBanner();
    	bleStackInit();
    	flashInit_Internal();	// Internal FDS
    	gpioInit();
    	... other inits for data handlers/external flash (if any)/ etc ...
    	bleInit();	// See below
    
    	advertisingStart(); // Start advertising last. This prevents other centrals from initiating a connection before everything is ready and no conflicts with other GATT processes.
    
    	for (;;) {
    		app_sched_execute();
    
    		if (!NRF_LOG_PROCESS()) {
    			powerManage();
    		}
    	}
    }


    2) In bleInitialize.c:

    typedef PACKED_STRUCT {
    	uint8_t advertisingCounter;
    	uint8_t someByte02;
    	uint16_t someOtherValue01;
    	uint16_t someOtherValue02;
    	uint16_t someOtherValue03;
    	uint16_t someOtherValue04;
    } MfgData_t;
    
    static MfgData_t mfgData = {
    	.advertisingCounter = 0,
    	.someByte02 = 0,
    	.someOtherValue01 = 0,
    	.someOtherValue02 = 0,
    	.someOtherValue03 = 0,
    	.someOtherValue04 = 0,
    };
    
    
    BLE_ADVERTISING_DEF(advertiseModule);
    ble_advertising_init_t bleAdvertInit;
    #define NUM_SERVICES_TO_ADVERTISE 1
    static ble_uuid_t servicesToAdvertise[NUM_SERVICES_TO_ADVERTISE];
    
    void bleInit(void) {
    	gapParamsInit();	// sd_ble_gap_ppcp_set
    	bleInfoInit();		// sd_ble_gap_addr_get (optional)
    	gattInit();		// nrf_ble_gatt_init
    	servicesInit();		// services & characteristics init
    	advertiseInit();	// advert init
    	connParamsInit();	// ble_conn_params_init
    }
    
    static void advertiseInit(void) {
    	// Only call once at start of program.
    
    	// Set handler so payloads can be changed between radio transmits.
    	ret_code_t err_code = ble_radio_notification_init(APP_IRQ_PRIORITY_LOW, NRF_RADIO_NOTIFICATION_DISTANCE_2680US, advertiseUpdate);
    
    	servicesToAdvertise[0] = yourServiceUUID;
    
    	static ble_advdata_manuf_data_t advertMfgData;
    	memset(&advertMfgData, 0, sizeof(advertMfgData));
    	advertMfgData.data.p_data = (uint8_t*)&mfgData;
    	advertMfgData.data.size = sizeof(mfgData);
    
    	memset(&bleAdvertInit, 0, sizeof(bleAdvertInit));
    	bleAdvertInit.advdata.name_type = BLE_ADVDATA_FULL_NAME;
    	bleAdvertInit.advdata.include_appearance = false;
    	bleAdvertInit.advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
    	bleAdvertInit.advdata.uuids_complete.uuid_cnt = NUM_SERVICES_TO_ADVERTISE;
    	bleAdvertInit.advdata.uuids_complete.p_uuids = servicesToAdvertise;
    	bleAdvertInit.advdata.p_manuf_specific_data = &advertMfgData;
    
    	bleAdvertInit.config.ble_adv_fast_enabled = true;
    	bleAdvertInit.config.ble_adv_fast_interval = ADV_INTERVAL_ACTIVE;
    	bleAdvertInit.config.ble_adv_fast_timeout = BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED;
    	bleAdvertInit.config.ble_adv_on_disconnect_disabled = true; // true = Let our code handle the restart
    
    	bleAdvertInit.evt_handler = advertiseEventHandler;
    	bleAdvertInit.error_handler = advertiseErrorHandler;
    
    	err_code = ble_advertising_init(&advertiseModule, &bleAdvertInit);
    	APP_ERROR_CHECK(err_code);
    
    	ble_advertising_conn_cfg_tag_set(&advertiseModule, APP_BLE_CONN_CFG_TAG);
    
    	err_code = sd_ble_gap_tx_power_set(BLE_GAP_TX_POWER_ROLE_ADV, advertiseModule.adv_handle, TX_POWER_LEVEL);
    	APP_ERROR_CHECK(err_code);
    }
    
    static void advertiseUpdate(bool radio_active) {
    	// This is called after EVERY radio tx, ie during advertising and tx-ing during connection.
    	if (radio_active) {
    		// Increment advert counter (optional based on your project, you can change the data in mfgData anywhere in your code and it will go to advert packet because inside advertiseInit we set the advertMfgData.data.p_data = (uint8_t*)&mfgData;, which was sent to ble_advertising_init() via bleAdvertInit struct.
    		mfgData.advertisingCounter++;
    
    		ret_code_t err_code = ble_advdata_encode(&bleAdvertInit.advdata, advertiseModule.enc_advdata, &advertiseModule.adv_data.adv_data.len);
    		APP_ERROR_CHECK(err_code);
    	}
    }

  • That is only true, as long as you don't want to change the size of the advertised data.

  • This has not been my experience. I switch advert packet size every TX of the radio. I have a set of different advert packets (each diff data and size) and cycle thru the list changing each time.

    As long as you do the following it should work fine.

    1) Set the characteristics max_len to the largest possible during initialization.

    2) Inside advertiseUpdate (above function) you set ble_advdata_encode'p_len (3rd parameter) to the size of the new advert data.

Reply
  • This has not been my experience. I switch advert packet size every TX of the radio. I have a set of different advert packets (each diff data and size) and cycle thru the list changing each time.

    As long as you do the following it should work fine.

    1) Set the characteristics max_len to the largest possible during initialization.

    2) Inside advertiseUpdate (above function) you set ble_advdata_encode'p_len (3rd parameter) to the size of the new advert data.

Children
  • Have you verified this over the air? Does the advertising really change length, or just using dummy (or old) data behind the length you specified.

    We tested this once, but i admit only with using longer data then previously, which caused the softdevice to cut the data after the length of the initial advertising.

    Since you give the softdevice a pointer and a length during initialization I don't see how changing the data behind the pointer would change the length, that the softdevice assumes.

    The encode function doesn't call the softdevice, so this shouldn't change it.

Related