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

How can I stop a connection and BLE advertisement?

Dear All,

I am using the ble_app_template as my baseline.

I have created a custom service with various characteristics and I am able to broadcast my service, connect and exchange data with it.

My next goal is to be able to break the connection from the host device and shutdown the BLE advertisement.

I understand that the client (my device) is not allowed to break a connection on its own, but I want to be able to do so, in case the battery voltage, for example, drops bellow a certain value.

What would be the beset way to go about it?

I know that there is the APP_ADV_DURATION that I can configure, but I want to make sure that the device will shutdown the BLE radio safely whenever the code needs it. I also need to be able to restart the beaconing and my service as soon as the device's battery recovers.

In order to emulate the 2 events I am using 2 buttons on the nrf52840DK attaching interrupts on them:

My interrupt routine is the following:

/**@brief Function for handling pin interrupts
 *
 * @param[in]   pin   The number of the GPIO pin this interrupt is attached to
 * @param[in]   action  Pin action detected on the pin
 */
void in_pin_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
{
    ret_code_t err_code;
    if (pin == PIN_IN_1) {
        NRF_LOG_INFO("Button 1 pressed");
        if (m_conn_handle != BLE_CONN_HANDLE_INVALID) {
            err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
            APP_ERROR_CHECK(err_code);
        }
        err_code = sd_ble_gap_adv_stop(m_advertising.adv_handle);
        APP_ERROR_CHECK(err_code);
    }
    else if (pin == PIN_IN_2) {
        NRF_LOG_INFO("Button 2 pressed");
        conn_params_init();
        advertising_init();
        advertising_start(erase_bonds);
    }
}

When I press the first button the device should break the connection (here I am cheating as I am indicating that the HOST broke the connection) and stop beaconing.

When I press button 2 the device will start beaconing again expecting new connections.

What I see is the following:

If I run the code and do not connect with a host device, the bluetooth beaconing starts and stops pressing the 2 buttons as expected.

If I connect and then press button 1 the application returns this error: NRF_ERROR_INVALID_STATE when it calls sd_ble_gap_adv_stop.

So I wonder if there is a better way to achieve the functionality I described, or how can I fix my current implementation so that it does not crush anymore at sd_ble_gap_adv_stop

Parents
  • Hi

    If you call sd_ble_gap_adv_stop() when you aren't advertising, for example while you're connected, the function will return the NRF_ERROR_INVALID_STATE. You should not call this function when you aren't advertising, or you have to ignore the invalid state error message. Same goes for the sd_ble_gap_disconnect() function if you call it if a disconnection is already in progress. 

    You can try something like this code snippet to circumvent these errors:

    uint32_t err_code;
    
    if (m_conn_handle != BLE_CONN_HANDLE_INVALID)
    {
        err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
        if (err_code != NRF_ERROR_INVALID_STATE)
        {
            APP_ERROR_CHECK(err_code);
        }
    }
    
    err_code = sd_ble_gap_adv_stop();
    if (err_code != NRF_ERROR_INVALID_STATE)
    {
        APP_ERROR_CHECK(err_code);
    }

    Best regards,

    Simon

Reply
  • Hi

    If you call sd_ble_gap_adv_stop() when you aren't advertising, for example while you're connected, the function will return the NRF_ERROR_INVALID_STATE. You should not call this function when you aren't advertising, or you have to ignore the invalid state error message. Same goes for the sd_ble_gap_disconnect() function if you call it if a disconnection is already in progress. 

    You can try something like this code snippet to circumvent these errors:

    uint32_t err_code;
    
    if (m_conn_handle != BLE_CONN_HANDLE_INVALID)
    {
        err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
        if (err_code != NRF_ERROR_INVALID_STATE)
        {
            APP_ERROR_CHECK(err_code);
        }
    }
    
    err_code = sd_ble_gap_adv_stop();
    if (err_code != NRF_ERROR_INVALID_STATE)
    {
        APP_ERROR_CHECK(err_code);
    }

    Best regards,

    Simon

Children
  • Dear ,

    I have added your snippet, with some small changes:

    if (m_conn_handle != BLE_CONN_HANDLE_INVALID)
            {
                err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
                if (err_code != NRF_ERROR_INVALID_STATE)
                {
                    APP_ERROR_CHECK(err_code);
                }
                m_conn_handle = BLE_CONN_HANDLE_INVALID;
            }
            m_advertising.adv_evt = BLE_ADV_EVT_IDLE;
            err_code = sd_ble_gap_adv_stop(NULL);
    
            if (err_code != NRF_ERROR_INVALID_STATE)
            {
                APP_ERROR_CHECK(err_code);
            }
        }
    because I am using the v16.0.0 SDK.

    The result is similar to what I had before. If there is no connection, everything seems to work fine.

    But when I have established a connection and I press the button, the connection stops as expected, but the device is still beaconing. Why is that? With the above sample I need to press the button twice. Once the device will disconnect and the next time the beaconing will stop.

Related