Renaming connected device

Hello Nordic

I am developing a sensor application using nRF52833. The user must be able to connect to the nRF52833 and give it a new name. I have a name characteristic that the user will write the new name to. When the nRF52833 receives the new name, it should disconnect and start advertising the new name. Then the user will reconnect using the new name.

I have read a lot of post on this subject. But none of them seems to work for me. I get the general idea about how to do it:

  • Set the new name using sd_ble_gap_device_name_set
  • Restart the advertising, several ways to do it are described in posts

I am using: SDK 17.1.0

Code starting point: examples\ble_peripheral\ble_app_template

I can rename the nRF52833, but nothing happens until a power cycling takes place.

This is my code:

In the main file I check whether the user has requested a new name. Then I set the new name and run the advertisement initialization again (suggested in this forum)

 if (is_new_device_name_requested()) // if the user has requested a new name for this sensor, then go ahead and set it

    {

        NRF_LOG_INFO("setting new device name");

        set_device_name(DEVICE_NAME);

        advertising_init();

  }

The set_device_name function is shown below:

void set_device_name(uint8_t* first_name)
{
ret_code_t err_code;
ble_gap_conn_sec_mode_t sec_mode;

BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);

memset(full_device_name, 0, sizeof full_device_name);
strcpy(full_device_name, first_name);
strcat(full_device_name, general_par.last_device_name);

err_code = sd_ble_gap_device_name_set(&sec_mode,
(const uint8_t *)full_device_name,
strlen(full_device_name));
APP_ERROR_CHECK(err_code);
general_par.is_new_device_name_wanted = false;
}

The advertising_init function is shown below:

static void advertising_init(void)
{
ret_code_t err_code;
ble_advertising_init_t init;

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

init.advdata.name_type = BLE_ADVDATA_FULL_NAME;
init.advdata.include_appearance = true;
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;

init.config.ble_adv_fast_enabled = true;
init.config.ble_adv_fast_interval = APP_ADV_INTERVAL;
init.config.ble_adv_fast_timeout = APP_ADV_DURATION;

init.evt_handler = on_adv_evt;

err_code = ble_advertising_init(&m_advertising, &init);
APP_ERROR_CHECK(err_code);

ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG);
}

Parents
  • Hi Thomas,

    Are you changing the name while advertising? I take a look at the design of the ble_advertising module and it seems it isn't intended for the "start > stop > update > start again" update method.

    The module does come with a function that is intended to help updating advertising data. It is ble_advertising_advdata_update().

    I have tested using your code, adjusting the bit that use advertising_init() to use that function instead, and I can successfully get the advertising device name to update.

    One of our colleagues, Karl, also wrote a great blog on updating advertising data, which include a sample code using that function in nRF5 SDK v17.1.0. You can find it here:  How to update advertising data dynamically using BLE Advertising library 

    Could you please tweak things to use that function instead, and let me know if it works/does not work?

  • Hi Hieu

    I am changing the name while being in connected mode. I am now using: ble_advertising_advdata_update(). 

    From Karls example I have used and modified the timer handler: static void adv_data_update_timer_handler(void * p_context). I have converted it to a normal function because i do not need timers to trigger it. I have deleted the manufacturer specific data, because I solely want to change the device name. The modified code is shown below:

    static ble_advdata_t new_advdata;
    
    static void adv_data_update(void)
    {
        ret_code_t                  err_code;
    
        NRF_LOG_INFO("Updating advertising data!");
        
        err_code = ble_advertising_advdata_update(&m_advertising, &new_advdata, NULL);
        APP_ERROR_CHECK(err_code);  
        
        NRF_LOG_INFO("Advertising data updated!");
    }

    While the NRF52833 is connected a new name is given by the user and the function below is called:

    void set_device_name(uint8_t* first_name)
    {
        ret_code_t              err_code;
        ble_gap_conn_sec_mode_t sec_mode;
    
        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);
        
        memset(full_device_name, 0, sizeof full_device_name);
        strcpy(full_device_name, first_name);
        strcat(full_device_name, general_par.last_device_name);
    
        err_code = sd_ble_gap_device_name_set(&sec_mode,
                                              (const uint8_t *)full_device_name,
                                              strlen(full_device_name));
        APP_ERROR_CHECK(err_code);
        general_par.is_new_device_name_wanted = false;
    }

    Then I proceed to call the adv_data_update function. I have tried calling it from two code locations:

    1. Subsequent to the device name change

    2. After disconnection has occurred

    Below i 2 code snippets showing where I have called adv_data_udpate.

        if (is_new_device_name_requested()) // if the user has requested a new name for this sensor, then go ahead and set it
        {
            NRF_LOG_INFO("setting new device name");
            set_device_name(DEVICE_NAME);
            adv_data_update();

    /**@brief Function for handling BLE events.
     *
     * @param[in]   p_ble_evt   Bluetooth stack event.
     * @param[in]   p_context   Unused.
     */
    static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
    {
        ret_code_t err_code = NRF_SUCCESS;
    
        switch (p_ble_evt->header.evt_id)
        {
            case BLE_GAP_EVT_DISCONNECTED:
                NRF_LOG_INFO("Disconnected.");
                adv_data_update();
                // LED indication will be changed when advertising starts.
                break;
    

    The result is the same. When I disconnect the NRF52833 will not advertise. A power cycle is needed before i start advertising again. Thank you for your help.

  • Hi Thomas,

    Sorry for my misunderstanding. I thought you meant that the name was not changed when you said nothing happens.

    Have you explicitly called a function to start advertising when disconnection happen?

    For reference, this is the code doing so in the ble_app_blinky example:

    /**@brief Function for handling BLE events.
     *
     * @param[in]   p_ble_evt   Bluetooth stack event.
     * @param[in]   p_context   Unused.
     */
    static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
    {
        ret_code_t err_code;
    
        switch (p_ble_evt->header.evt_id)
        {
            case BLE_GAP_EVT_CONNECTED:
                // ... omitted ...
                break;
    
            case BLE_GAP_EVT_DISCONNECTED:
                NRF_LOG_INFO("Disconnected");
                bsp_board_led_off(CONNECTED_LED);
                m_conn_handle = BLE_CONN_HANDLE_INVALID;
                err_code = app_button_disable();
                APP_ERROR_CHECK(err_code);
                advertising_start();
                break;
            
            // ... omitted ...
            
            default:
                // No implementation needed.
                break;
        }
    }

Reply
  • Hi Thomas,

    Sorry for my misunderstanding. I thought you meant that the name was not changed when you said nothing happens.

    Have you explicitly called a function to start advertising when disconnection happen?

    For reference, this is the code doing so in the ble_app_blinky example:

    /**@brief Function for handling BLE events.
     *
     * @param[in]   p_ble_evt   Bluetooth stack event.
     * @param[in]   p_context   Unused.
     */
    static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
    {
        ret_code_t err_code;
    
        switch (p_ble_evt->header.evt_id)
        {
            case BLE_GAP_EVT_CONNECTED:
                // ... omitted ...
                break;
    
            case BLE_GAP_EVT_DISCONNECTED:
                NRF_LOG_INFO("Disconnected");
                bsp_board_led_off(CONNECTED_LED);
                m_conn_handle = BLE_CONN_HANDLE_INVALID;
                err_code = app_button_disable();
                APP_ERROR_CHECK(err_code);
                advertising_start();
                break;
            
            // ... omitted ...
            
            default:
                // No implementation needed.
                break;
        }
    }

Children
  • Hi Hieu

    Thank you for answering me so fast. I have tried to follow your example from ble_app_blinky. In connected mode the user requests a new name. I set the new name using set_device_name and I call the adv_data_update() function, that contains ble_advertising_advdata_update.

        if (is_new_device_name_requested()) // if the user has requested a new name for this sensor, then go ahead and set it
        {
            NRF_LOG_INFO("setting new device name");
            set_device_name(DEVICE_NAME);
            adv_data_update();
        }

    Then my codes receive an event from the bluetooth stack. I try to follow the blinky example:

    /**@brief Function for handling BLE events.
     *
     * @param[in]   p_ble_evt   Bluetooth stack event.
     * @param[in]   p_context   Unused.
     */
    static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
    {
        ret_code_t err_code = NRF_SUCCESS;
    
        switch (p_ble_evt->header.evt_id)
        {
            case BLE_GAP_EVT_DISCONNECTED:
                NRF_LOG_INFO("Disconnected.");
                m_conn_handle = BLE_CONN_HANDLE_INVALID;
                advertising_start(false);
                break;
    

    The NRF52833 crashes with NRF_ERROR_INVALID_STATE error. 

    <info> app: setting new device name
    <info> app: Updating advertising data!
    <info> app: Advertising data updated!
    <info> app: Fast advertising.
    <info> app: Disconnected.
    <error> app: ERROR 8 [NRF_ERROR_INVALID_STATE] at R:\Produkter\HBCLS\4.Produktion\Software\Release\Git control\nRF5_SDK_17.1.0_ddde560\cal_sw\cal_sw\cal_sw\main.c:1449
    PC at: 0x0002BCFD
    <error> app: End of error report
    <info> app: Setting vector table to bootloader: 0x00077000

    Before this crash, there is a log saying: "Fast advertising" and "Disconnected". Maybe the advertising has somehow restarted already when I try to restart it. I have tried to comment out the advertising_start function call, but then there is no advertising following a device rename.

  • Hi Thomas,

    Sorry, it seems I am unable to keep the fast response going Disappointed

    Could you let me know what the function that outputs "Fast advertising" look like?

    And what function returns NRF_ERROR_INVALID_STATE? Was it ble_advertising_advdata_update()?
    If so, the possible causes are documented here: ble_advertising_advdata_update().

    Please notice that it also returns any error code that the functions it uses return. For NRF_ERROR_INVALID_STATE, sd_ble_gap_adv_set_configure() is also relevant; and the possible causes are documented here: sd_ble_gap_adv_set_configure().

    Hieu

  • Hi Hieu

    The "Fast advertising" message comes from the following function:

    /**@brief Function for handling advertising events.
     *
     * @details This function will be called for advertising events which are passed to the application.
     *
     * @param[in] ble_adv_evt  Advertising event.
     */
    static void on_adv_evt(ble_adv_evt_t ble_adv_evt)
    {
        ret_code_t err_code;
    
        switch (ble_adv_evt)
        {
            case BLE_ADV_EVT_FAST:
                NRF_LOG_INFO("Fast advertising..");
                err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING);
                APP_ERROR_CHECK(err_code);
                break;
    
            case BLE_ADV_EVT_IDLE:
                sleep_mode_enter();
                break;
    
            default:
                break;
        }
    }

    The function that returns NRF_ERROR_INVALID_STATE is shown below. The error is generated by the call to "ble_advertising_start"

    /**@brief Function for starting advertising.
     */
    static void advertising_start(bool erase_bonds)
    {
        if (erase_bonds == true)
        {
            delete_bonds();
            // Advertising is started by PM_EVT_PEERS_DELETED_SUCEEDED event
        }
        else
        {
            ret_code_t err_code = ble_advertising_start(&m_advertising, BLE_ADV_MODE_FAST);
            APP_ERROR_CHECK(err_code);
        }
    }

  • Hi Thomas,

    I looked at the Advertising Module more closely and see that adding a call to ble_advertising_start() like I previously advised is not necessary. The module itself already done that, and you can see by looking at its on_disconnected() function. ble_app_blinky() does not use the Advertising Module and thus need that setup.

    My apology about this.

    However, now I am confused why you initially don't have advertising data then...

    Could you please use debug, put a breakpoint at the line that calls ble_advertising_start() in on_disconnected() in ble_advertising.c?

    If you could, it would be better to use breakpoint in ble_advertising_start() itself to check exactly where the error was reported.
    But in doing this, you need to pay attention to only enable the breakpoint right before a disconnection. In an BLE application, a breakpoint cannot be recovered from (because a halt in execution breaks BLE timing). Therefore, if you enable the breakpoint from the beginning, you will run into it at the initial advertising start, before the connection is established.

  • Hi Hieu, I really appreciate your help. Nice discovery that "ble_advertising_start()" is called by the module itself. The error that I received must be generated by calling "ble_advertising_start()" two times. When I delete the call to "ble_advertising_start()", there is no error, but the NRF52833 goes into a silent disconnected state without advertising. That is, if I do not change the device name, then the advertising works fine, but after a device name change and a disconnect the silent state occurs. 

     

    I am using DFU and setting a breakpoint is not so easy. But searching this forum I see that it is possible.

     

    I am at a small Christmas vacation right now. I will be back in the office Tuesday. Then I can set breakpoints and continue solving this mysteryBlush

Related