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

Meaning of context argument in event handlers

Dear Nordic Team, 

I was trying to understand event handlers from SDK5 examples. I understood that by using following macro we can register our event handlers, and afterwards receive BLE events and take appropriate actions either by using switch statements directly or by forwarding event data to other custom event handlers. 

NRF_SDH_BLE_OBSERVER(_name ## _obs, BLE_NUS_C_BLE_OBSERVER_PRIO, ble_nus_c_on_ble_evt, &_name)

In NUS Central example, I came across following code snippet : 

void ble_nus_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
{
    ble_nus_c_t * p_ble_nus_c = (ble_nus_c_t *)p_context; 
    ...

I can't understand meaning of "p_context" argument. How do we know that p_context variable holds NUS client instance? How does event handler link events with the object? Is it possible that generic softdevice event handler below is also receiving NUS client pointer?

 

static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)

I would appreciate if you can explain logic behind the context variable and how does it work. 

  •  From main.c NUS client:

    BLE_NUS_C_DEF(m_ble_nus_c);                                             /**< BLE Nordic UART Service (NUS) client instance. */

    From ble_nus_c.h:

    /**@brief   Macro for defining a ble_nus_c instance.
     *
     * @param   _name   Name of the instance.
     * @hideinitializer
     */
    #define BLE_NUS_C_DEF(_name)                                                                        \
    static ble_nus_c_t _name;                                                                           \
    NRF_SDH_BLE_OBSERVER(_name ## _obs,                                                                 \
                         BLE_NUS_C_BLE_OBSERVER_PRIO,                                                   \
                         ble_nus_c_on_ble_evt, &_name)

    From nrf_sdh_ble.h:

    /**@brief   Macro for registering @ref nrf_sdh_soc_evt_observer_t. Modules that want to be
     *          notified about SoC events must register the handler using this macro.
     *
     * @details This macro places the observer in a section named "sdh_soc_observers".
     *
     * @param[in]   _name       Observer name.
     * @param[in]   _prio       Priority of the observer event handler.
     *                          The smaller the number, the higher the priority.
     * @param[in]   _handler    BLE event handler.
     * @param[in]   _context    Parameter to the event handler.
     * @hideinitializer
     */
    #define NRF_SDH_BLE_OBSERVER(_name, _prio, _handler, _context)                                      \
    STATIC_ASSERT(NRF_SDH_BLE_ENABLED, "NRF_SDH_BLE_ENABLED not set!");                                 \
    STATIC_ASSERT(_prio < NRF_SDH_BLE_OBSERVER_PRIO_LEVELS, "Priority level unavailable.");             \
    NRF_SECTION_SET_ITEM_REGISTER(sdh_ble_observers, _prio, static nrf_sdh_ble_evt_observer_t _name) =  \
    {                                                                                                   \
        .handler   = _handler,                                                                          \
        .p_context = _context                                                                           \
    }

    BLE_NUS_C_DEF declares a ble_nus_c_t called m_ble_nus_c that is then passed to NRF_SDH_BLE_OBSERVER as both the name of the 'observer' and the address of the context pointer.

    Each time the context pointer in ble_nus_c_on_ble_evt is dereferenced as a ble_nus_c_t it is the m_ble_nus_c struct in main that is dereferenced. 

Related