nRF5 SDK v15.2.0
SoftDevice Handler library
This information applies to the following SoftDevices: S132, S140

This library is used for enabling and disabling the SoftDevice and for propagating SoftDevice events to the application.

This library has the following functionalities.

The API exposed by this module can be found in <InstallFolder>\components\softdevice\common in the files nrf_sdh.h, nrf_sdh_soc.h, nrf_sdh_ant.h, and nrf_sdh_ble.h.

For API documentation of this module, see SoftDevice Handler.

Library components

The SoftDevice Handler library consists of four main modules.

nrf_sdh component

This is the core of the SoftDevice Handler library. It handles requests for enabling or disabling the SoftDevice, and notifies about SoftDevice state changes (such as: about to be enabled, enabled, about to be disabled, disabled). This component also fetches stack events and dispatches them to the correct nrf_sdh_* library, where stands for soc, ant, or ble. To view and modify the configuration options of this module, refer to SoftDevice handler configuration.

nrf_sdh_soc component

This part of the library receives SoC events from the SoftDevice Handler library. Applications and other libraries can register with nrf_sdh_soc to receive these events by using the macro NRF_SDH_SOC_OBSERVER. To view and modify the configuration options of this module, refer to SoftDevice SoC event handler configuration.

nrf_sdh_ant component

This part of the library receives ANT events from the SoftDevice Handler library. Applications and other libraries can register with nrf_sdh_ant to receive these events by using the macro NRF_SDH_ANT_OBSERVER. To view and modify the configuration options of this module, refer to SoftDevice ANT event handler configuration.

nrf_sdh_ble component

This part of the library receives BLE events from the SoftDevice Handler library. Applications and other libraries can register with nrf_sdh_ble to receive these events by using the macro NRF_SDH_BLE_OBSERVER. To view and modify the configuration options of this module, refer to SoftDevice BLE event handler configuration.

Functions of the library components

The three nrf_sdh_* components have a similar role of sending a particular kind of stack events to their registered observers.

These three modules register with the core nrf_sdh module using macros defined in the SoftDevice Handler library, in a similar way as their observers register to them. The nrf_sdh core component then sends the specific stack events (SoC, ANT, or BLE) to the respective modules.

Apart from propagating stack events to the submodules, nrf_sdh sends two other types of messages.

Registering with the nrf_sdh_* components

Each part of an application that wants to receive events from the different components of the SoftDevice Handler library must register itself by using the macros specified in the Library components section. The registering happens at compile time, even though the events themselves are sent out to the observers at runtime. A registered part of an application becomes an observer.

Observers and their priorities

An observer is essentially a piece of code that listens for events. It consists of a handler function and its associated parameter - a context. Every handler function has a certain priority.

The priority of a handler is a number that specifies the order in which it receives events with respect to other handlers (of the same type of events - BLE, ANT, or SoC). Priority zero is the highest. It is possible to have several observers registered with the same priority, but then the order in which they receive events depends on the order in which the linker encounters the handlers during the linking process. Therefore, to be certain that a particular observer is the first one to receive an event, you must assign higher priority to it.

Example: Module A registers itself an observer of BLE events with (a handler) priority 1. Then, module B registers itself as an observer of BLE events with a handler of priority 0. When an event is pulled from the stack by the SoftDevice Handler library, it is dispatched to nrf_sdh_ble, and from there, it is first sent to all observers that have a handler with priority zero, and then to all observers with a handler with priority 1. In consequence, module B receives the event before module A.

These priorities may be crucial when the modules depend on each other. In the example above, module A might depend on module B to be up to date when module A is processing an event from the stack. For that to happen, module B must receive the event first.

Priorities can be configured by passing a parameter to the macro.

Assigning priorities

It is not recommended to modify the priority of any library that is included in this SDK. This may lead to unexpected problems.

However, when you create a new custom library and want to register it as an observer, you will have to assign a priority to it. In such case, a best practice is to assign to it a priority level that is lower than that for all other libraries. In this way, the rest of the application will have received the event and updated its state by the time the event reaches your library.

The default priority levels are already used by the existing libraries, so you must allocate an additional priority level and assign it to your library. To increase the number of priority levels, open the sdk_config file and look for the NRF_SDH_*_PRIO_LEVELS configuration parameter (* represents the type of events - SoC, BLE, or ANT). The value of this parameter is the number of available priority levels and the lowest priority is that number minus one. Change the value to a higher number and then assign the newly created priority level to your custom library.

It might also happen that you will need your piece of code to run before that of other libraries. In such case, check what priority is used in that library, by opening its header or .c file. Do not modify the priority of this library, but try to adjust the priority of yours. If this solution does not fit your requirements, you can increase the total number of priority levels.

Example of enabling the SoftDevice and BLE stack

The following code snippet demonstrates how to enable the SoftDevice and the BLE stack.

ret_code_t err_code;
// Attempt to enable the SoftDevice
APP_ERROR_CHECK(err_code);
{
// The status change has been deferred. Handle as appropriate.
}
// Fetch the start address of the application RAM.
uint32_t ram_start = 0;
err_code = nrf_sdh_ble_app_ram_start_get(&ram_start);
APP_ERROR_CHECK(err_code);
// Enable BLE stack.
err_code = nrf_sdh_ble_enable(&ram_start);
APP_ERROR_CHECK(err_code);

Example of registering a BLE observer

The following code snippet demonstrates how to register a piece of code as an observer of BLE events.

#include "nrf_sdh_ble.h"
void ble_evt_handler(ble_evt_t const * p_evt, void * p_context)
{
// process events here
}
NRF_SDH_BLE_OBSERVER(m_ble_observer, OBSERVER_PRIO, ble_evt_handler, NULL);

Example of registering a SoftDevice state observer

The following code snippet demonstrates how to register a piece of code as an observer of SoftDevice state change events.

#include "nrf_sdh.h"
void state_evt_handler(nrf_sdh_state_evt_t state, void * p_context);
{
switch (state)
{
// SoftDevice is about to be enabled.
break;
// SoftDevice is now enabled.
break;
// SoftDevice is about to be disabled.
break;
// SoftDevice is now disabled.
break;
}
}
NRF_SDH_STATE_OBSERVER(m_state_observer, OBSERVER_PRIO) =
{
.handler = state_evt_handler,
.p_context = NULL
};

Delaying a SoftDevice's state change

Using the SoftDevice state requests, a part of an application can prevent the SoftDevice from being disabled or enabled. For example, if the flash library has scheduled some flash operations, disabling the SoftDevice will make them fail. In such case, the flash library can use a dedicated macro to register itself with nrf_sdh as a request observer. When another part of the application issues the nrf_sdh_disable_request() call, the flash library event handler for the SoftDevice Handler library will respond to this request.

The handler can then return FALSE and abort the state change.

If it does so, it must afterwards call nrf_sdh_continue() when the SoftDevice can be disabled safely, for example after the flash operation has been completed. This call restarts the state change procedure, which involves resending state requests to all observers. If they all return TRUE, then the SoftDevice begins to change its state and the state events are sent.

Example of registering a SoftDevice state request observer

The following code snippet demonstrates how to register a state request observer.

#include "nrf_sdh.h"
// This functions must return either 'true' or 'false'.
// If you return false, be sure to call nrf_sdh_continue()
// when ready for the SoftDevice to change state.
bool request_evt_handler(nrf_sdh_req_evt_t request, void * p_context);
{
switch (request)
{
break;
break;
}
}
NRF_SDH_REQUEST_OBSERVER(m_req_observer, OBSERVER_PRIO) =
{
.handler = request_evt_handler,
.p_context = NULL
};


Message sequence chart for SoftDevice state requests

In the MSC below, a library requests to disable the SoftDevice. A request observer defers the state change to complete pending operations, and then it restarts the procedure. Finally, the SoftDevice changes its state and the library (a state observer) is notified of this.

msc_inline_mscgraph_1


Preprocessor defines

This module uses conditional compilation. It expects certain preprocessor macros to be defined as follows.


Documentation feedback | Developer Zone | Subscribe | Updated