Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs

Using NRF_SDH_BLE_OBSERVER in a nonstatic C++ Class

These days I have the following problems using NRF_SDH_BLE_OBSERVER. I have a CPP project and try to initialize the BLE-Stack in the following way:

void CBLEStackModule::init(BYTE a_nMaxNumberOfPeripheralLinks, BYTE a_nMaxNumberOfCentralLinks, BYTE a_nMaxNumberOfSecurityManagerProtocolInstances)
{
	DWORD nRamStart = 0;
	APP_ERROR_CHECK(nrf_sdh_ble_app_ram_start_get(&nRamStart));

	APP_ERROR_CHECK(nrf_sdh_enable_request());

	ble_cfg_t bleConfiguration;

	memset(&bleConfiguration, 0x00, sizeof(bleConfiguration));

	APP_ERROR_CHECK(nrf_sdh_ble_default_cfg_set(APPLICATION_BLE_CONNECTION_CONFIG_TAG, &nRamStart));

	APP_ERROR_CHECK(nrf_sdh_ble_enable(&nRamStart));
	
	NRF_SDH_BLE_OBSERVER(m_ble_observer, APPLICATION_BLE_OBSERVER_PRIORITY, CBLEStackModule::eventHandler, NULL);
}

The Project is running but the last line

NRF_SDH_BLE_OBSERVER(m_ble_observer, APPLICATION_BLE_OBSERVER_PRIORITY, CBLEStackModule::eventHandler, NULL);

didn't work. For the notification charakteristic I need the event-handler CBLEStackModule::eventHandler but because the Macro didn't work in C++ it's not possible. Does anybody have an idea how to get that line run in a nonstatic CPP project? Or is there any other way to get it run?

  • Hi 

    The observer mechanism has no concept of instances, and requires a static function to work. 

    I think the best workaround here is to use a static member function as the observer callback, and then you can maintain a static instance pointer (or list of instance pointers) to the specific class or classes that you want to process the events, and call the non static handler method from the static one. 

    Hopefully that description made sense. If not let me know, and I will try to explain it better ;)

    Best regards
    Torbjørn

  • Hello Torbjorn,

    thank you very much for your answer. That helped me a lot in understanding how the observer works and it is running now. I also found another mistake which I have done. But I still don't understand why my solution not works. The problem is the following:

    If you add an callback to the observer you use the following line:

    NRF_SDH_BLE_OBSERVER(m_ble_observer, APPLICATION_BLE_OBSERVER_PRIORITY, eventHandler, NULL);

    You have to give the observer priority to the Makro. If I define the Priority like that:

    static const INT32 APPLICATION_BLE_OBSERVER_PRIORITY = 3;

    The observer isn't createt and I have the following output in the *.map-File of the compilation:

    sdh_ble_observers3$$Base
                                    0x0           --   Gb  - Linker created -
    sdh_ble_observers3$$Limit
                                    0x0           --   Gb  - Linker created -
    

    The memory address of the observer is 0x0 and there is no callback added. If I use

    #define APPLICATION_BLE_OBSERVER_PRIORITY 3

    the output in the *.map-File is

    sdh_ble_observers3$$Base
                               0x3'55d8           --   Gb  - Linker created -
    sdh_ble_observers3$$Limit
                               0x3'55e0           --   Gb  - Linker created -

    and a linking to the class of the Callback is added. The callback is also working in this case.

    Now I have the question, why the static const INT32 definition of the priority didn't work? What is the difference the #define definition of the priority?

    Thank you in advance

    Thomas

  • Hi Thomas

    Setting up the observers happens entirely at compile time, not at run time, so you are not able to use normal variables as input to these macros. 

    For instance if you look at the definition of the NRF_SDH_BLE_OBSERVER macro you will see it runs a STATIC_ASSERT to verify the priority. Most likely this is the one that is failing in your case:

    **@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                                                                           \
    }

    Best regards
    Torbjørn

Related