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

Check if currently advertising

In my application, a host co-processor controls when to start/stop advertising, connect etc.
I've noticed that soft-device command are state-dependent, e.g. calling ble_advertising_start() while advertising, or calling sd_ble_gap_adv_stop() while not, causes an SD assert which by default soft-resets the device (related question here).

How should I mitigate this? Do I have to keep track of the stack's state (Advertising, Connected, Scanning, etc.), or, better yet, are there API methods to check the state of the stack before issuing a command?

Version: nRF5 SDK 11.0.0, s132, with PCA10040 EVB

Parents
  • Hi,

    First I want to mention that it is not the SD that asserts. It simply returns an error code. The APP_ERROR_CHECK macro is the one that will reset the device, unless you choose to handle it in a different way. You can call any API functions with any parameter, at any time, and as long as you do not lie about the length of any buffers you provide, the SD shall never assert or crash. The functions will return an error code stating what happened.

    And for your question, you are right in your assumption that you have to remember the state in your application. If sd_ble_gap_adv_start() returns NRF_SUCCESS, the device will advertise until

    1. BLE_GAP_EVT_CONNECTED event is received, i.e. a connection is made (in the case of connectable advertisement). If you are trying to use the central to connect at the same time, you need to check the role flag of the connection. If BLE_GAP_ROLE_PERIPH, you are no longer advertising.

    2. BLE_GAP_EVT_TIMEOUT event is received (in the case where you set a timeout, or use high duty-cycle directed advertisements) and the src field is BLE_GAP_TIMEOUT_SRC_ADVERTISING.

    3. sd_ble_gap_adv_stop() has been called.

    There are no commands to check the current state, and it would be prone to race conditions if we had one. Instead, our stack relies on application events to tell you when the internal state changes.

  • The safe way is to create a (possibly volatile) flag like is_advertising, which is set to true whenever adv_start() returns NRF_SUCCESS, and set to false when any of the three conditions above are hit. Never call adv_stop() unless the flag is true, and adv_start() unless it is false. The easier way is to simply handle or ignore the NRF_ERROR_INVALID_STATE return code, accepting that you do not really keep track of the state yourself.

    What I meant about race conditions is in the hypothetical case where you had a function to retrieve state. Then you could look at the state, see that it is advertising, then call adv_stop(). If advertising stops by itself between the two last steps, you would have the same problem as now. There are no such problems in the current implementation, unless you are changing your own application states in higher interrupt levels.

Reply
  • The safe way is to create a (possibly volatile) flag like is_advertising, which is set to true whenever adv_start() returns NRF_SUCCESS, and set to false when any of the three conditions above are hit. Never call adv_stop() unless the flag is true, and adv_start() unless it is false. The easier way is to simply handle or ignore the NRF_ERROR_INVALID_STATE return code, accepting that you do not really keep track of the state yourself.

    What I meant about race conditions is in the hypothetical case where you had a function to retrieve state. Then you could look at the state, see that it is advertising, then call adv_stop(). If advertising stops by itself between the two last steps, you would have the same problem as now. There are no such problems in the current implementation, unless you are changing your own application states in higher interrupt levels.

Children
No Data
Related