Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Dynamically updating Advertising data in SDK 15

(side note : it would have been handy if the migration guide mentioned that the advertising timeout configs have changed from seconds to 10's of ms)

It seems to have become harder to dynamically update the advertising packet in SDK15. In SDK14, using ble_advertising, I could just update the manufacturer data used by my instance of ble_advertising_t and call ble_advdata_set and be done. Then whenever ble_advertising did something later, it would continue with the latest data (eg auto restart advertising, change speed etc). Advertising would not be restarted and if you use fast and slow advertising, then that timing and transition would not be affected if you changed the manufacturer data.

Now, we need to use sd_ble_gap_adv_set_configure instead of ble_advdata_set, but the new call wont allow changing the encoded data contents and using the same buffer. You need to provide a new buffer if its busy advertising. Providing a new long lived buffer for each update causes many other issues. One way to deal with this is to stop and restart advertising with the same but updated buffer. But that affects the fast to slow advertising timing and transitions : say you update the data every 1 minute, and your fast advertising goes slow after 2 minutes, then you'll always be in fast mode.

Is there an easy and minimally impactful way to update just the manufacturer data in SDK15 ?

Parents
  • I was beginning to have the same sentiments as you, regarding the need to provide a new buffer to update the advertising data while advertising, until I read through the s140_nrf52_6.0.0_migration_document.pdf. You should be able to find this in your <sdk>/components/softdevice/s140/doc folder.

    It seems that you are to be expected to have 2 sets of buffers allocated in order to update your advertising data on-the-fly.

    Here is the code snippet from the migration doc...

    static uint8_t raw_adv_data_buffer1[BLE_GAP_ADV_SET_DATA_SIZE_MAX];
    static uint8_t raw_scan_rsp_data_buffer1[BLE_GAP_ADV_SET_DATA_SIZE_MAX];
    static ble_gap_adv_data_t adv_data1 = {
        .adv_data.p_data = raw_adv_data_buffer1,
        .adv_data.len = sizeof(raw_adv_data_buffer1),
        .scan_rsp_data.p_data = raw_scan_rsp_data_buffer1,
        .scan_rsp_data.len = sizeof(raw_scan_rsp_data_buffer1)
    };
    
    /* A second advertising data buffer for later updating advertising data while advertising */
    static uint8_t raw_adv_data_buffer2[BLE_GAP_ADV_SET_DATA_SIZE_MAX];
    static uint8_t raw_scan_rsp_data_buffer2[BLE_GAP_ADV_SET_DATA_SIZE_MAX];
    static ble_gap_adv_data_t adv_data2 = {
        .adv_data.p_data = raw_adv_data_buffer2,
        .adv_data.len = sizeof(raw_adv_data_buffer2),
        .scan_rsp_data.p_data = raw_scan_rsp_data_buffer2,
        .scan_rsp_data.len = sizeof(raw_scan_rsp_data_buffer2)
    };
    
    int main(void)
    {
        uint8_t adv_handle = BLE_GAP_ADV_SET_HANDLE_NOT_SET;
        ble_gap_adv_params_t adv_params = {
            .properties = {
                .type = BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED
            },
            .interval = BLE_GAP_ADV_INTERVAL_MAX,
            .duration = BLE_GAP_ADV_TIMEOUT_LIMITED_MAX,
            .channel_mask = {0}, /* Advertising on all the primary channels */
            .max_adv_evts = 0,
            .filter_policy = BLE_GAP_ADV_FP_ANY,
            .primary_phy = BLE_GAP_PHY_AUTO,
            .scan_req_notification = 1
        };
        /* Enable the BLE Stack */
        sd_ble_enable(...);
        [...]
        sd_ble_gap_adv_set_configure(&adv_handle, &adv_data1, &adv_params);
        /* Start advertising */
        sd_ble_gap_adv_start(adv_handle, BLE_CONN_CFG_TAG_DEFAULT);
        [...]
        /* Update advertising data while advertising */
        sd_ble_gap_adv_set_configure(&adv_handle, &adv_data2, NULL);
        [...]
        /* Stop advertising */
        sd_ble_gap_adv_stop(adv_handle);
        [...]
    }

    I am still in the middle of migrating so I have not had a chance to implement this solution and try it out.

Reply
  • I was beginning to have the same sentiments as you, regarding the need to provide a new buffer to update the advertising data while advertising, until I read through the s140_nrf52_6.0.0_migration_document.pdf. You should be able to find this in your <sdk>/components/softdevice/s140/doc folder.

    It seems that you are to be expected to have 2 sets of buffers allocated in order to update your advertising data on-the-fly.

    Here is the code snippet from the migration doc...

    static uint8_t raw_adv_data_buffer1[BLE_GAP_ADV_SET_DATA_SIZE_MAX];
    static uint8_t raw_scan_rsp_data_buffer1[BLE_GAP_ADV_SET_DATA_SIZE_MAX];
    static ble_gap_adv_data_t adv_data1 = {
        .adv_data.p_data = raw_adv_data_buffer1,
        .adv_data.len = sizeof(raw_adv_data_buffer1),
        .scan_rsp_data.p_data = raw_scan_rsp_data_buffer1,
        .scan_rsp_data.len = sizeof(raw_scan_rsp_data_buffer1)
    };
    
    /* A second advertising data buffer for later updating advertising data while advertising */
    static uint8_t raw_adv_data_buffer2[BLE_GAP_ADV_SET_DATA_SIZE_MAX];
    static uint8_t raw_scan_rsp_data_buffer2[BLE_GAP_ADV_SET_DATA_SIZE_MAX];
    static ble_gap_adv_data_t adv_data2 = {
        .adv_data.p_data = raw_adv_data_buffer2,
        .adv_data.len = sizeof(raw_adv_data_buffer2),
        .scan_rsp_data.p_data = raw_scan_rsp_data_buffer2,
        .scan_rsp_data.len = sizeof(raw_scan_rsp_data_buffer2)
    };
    
    int main(void)
    {
        uint8_t adv_handle = BLE_GAP_ADV_SET_HANDLE_NOT_SET;
        ble_gap_adv_params_t adv_params = {
            .properties = {
                .type = BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED
            },
            .interval = BLE_GAP_ADV_INTERVAL_MAX,
            .duration = BLE_GAP_ADV_TIMEOUT_LIMITED_MAX,
            .channel_mask = {0}, /* Advertising on all the primary channels */
            .max_adv_evts = 0,
            .filter_policy = BLE_GAP_ADV_FP_ANY,
            .primary_phy = BLE_GAP_PHY_AUTO,
            .scan_req_notification = 1
        };
        /* Enable the BLE Stack */
        sd_ble_enable(...);
        [...]
        sd_ble_gap_adv_set_configure(&adv_handle, &adv_data1, &adv_params);
        /* Start advertising */
        sd_ble_gap_adv_start(adv_handle, BLE_CONN_CFG_TAG_DEFAULT);
        [...]
        /* Update advertising data while advertising */
        sd_ble_gap_adv_set_configure(&adv_handle, &adv_data2, NULL);
        [...]
        /* Stop advertising */
        sd_ble_gap_adv_stop(adv_handle);
        [...]
    }

    I am still in the middle of migrating so I have not had a chance to implement this solution and try it out.

Children
  • I have not seen that doc before (only the online version). That is somewhat helpful but that approach wont work well if you are using the ble_advertising module.

    Switching buffers yourself means that when ble_advertising gets to do the next thing (like changing from fast to slow advertising), it will use its own buffer which will be old and out of sync of your new buffer.

    Also, I suspect when you switch buffers, you'll get a BLE_GAP_EVT_ADV_SET_TERMINATED event for the previous buffer thats now released, and that event will cause ble_advertising to go to the next mode.

    Basically, where before you could easily use ble_advertising and update the packet, now thats not possible. You'll need to remove the use of ble_advertising and roll your own. 

  • that approach wont work well if you are using the ble_advertising module.

    I believe you are correct - I found this out myself when trying to implement the dual buffers. You would have to write your own callback handler and perform the necessary actions. I'm plodding forward with my migration and implementation of this still and will provide some more feedback when I get around to testing it.

    Any Nordic people able to chime in with some words of wisdom?

  • Hi,

    You can consider adding following function to the ble_advertising module:

    static ret_code_t ble_adv_data_update(ble_advertising_t   * const p_advertising,
                                          ble_gap_adv_data_t  * const p_new_advdata_buf,
                                          bool                        permanent)
    {
        if (permanent)
        {
            memcpy(&p_advertising->adv_data, p_new_advdata_buf, sizeof(p_advertising->adv_data));
            p_advertising->p_adv_data = &p_advertising->adv_data;
        }
        else
        {
            p_advertising->p_adv_data = p_new_advdata_buf;
        }
    
        return sd_ble_gap_adv_set_configure(&p_advertising->adv_handle,
                                            p_advertising->p_adv_data,
                                            NULL);
    }

    It should help with your issue. If you set permanent parameter to true, the advertising data will be permanently updated inside the ble_advertising module. Otherwise, the old data will be restored when you get next BLE_GAP_EVT_ADV_SET_TERMINATED event.

  • Updating the same init buffer in S132V6.0 works fine. The same code did not work for updating the init structure in S140V6.0. Your solution of having a second buffer works for the S140. There are still a couple more test I have to run.

Related