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

NRF_SDH_BLE_OBSERVER and other questions, including macro clarification

Folks,

This is probably a C question as much as Nordic, so I might be told this is off topic. That's fine if so, I can try Stack Overflow.

I never use macros in my C code other than things like #define BUFFER_SIZE 10 as I like the least obfuscated code possible.

I've written a custom service/characteristic by following a third-party guide and have it recognised by my phone and I can write to/.read from the characteristic. So, far so good. 

However, I want to understand and tidy up the code a bit. I've got rid of most of the typedefs - in my code, not all the rest of it - (I'm in Linus' gang when it comes to them) and I would like to get rid of the macros.

There's this that I got from the third party tutorial that I modified to be more suitable for my code:

#define BLE_MK_TEST_DEF(_name)                                                                         \
static struct ble_mk_test_service_s _name;                                                                    \
NRF_SDH_BLE_OBSERVER(_name ## _obs,                                                                 \
                     BLE_MK_TEST_BLE_OBSERVER_PRIO,                                                  \
                     ble_mk_test_service_on_ble_evt, &_name)

That I "call" from main.c with this:

BLE_MK_TEST_DEF(m_mk_test_service); 

I say call; I appreciate it's not a function and I'm not really calling it, but don't know what the proper term is.

I can manually expand this out to this:

#define BLE_MK_TEST_DEF(_name)                                                                         \
static struct ble_mk_test_service_s m_mk_test_service;                                                                    \
NRF_SDH_BLE_OBSERVER(m_mk_test_service_obs,                                                                 \
                     BLE_MK_TEST_BLE_OBSERVER_PRIO,                                                  \
                     ble_mk_test_service_on_ble_evt, &m_mk_test_service)

Which makes it more readable, but I still don't get what it's doing and still have to "call" it from main.

If I get rid of the "call" to it and get rid of the #define BLE_MK_TEST_DEF(_name) , of course as it's static it doesn't compile. If I stop it being static, it tells me, in main, m_mk_test_service is not declared when I try to use it, even though the header is included.

I guess this macro is somehow magically allowing a static struct to be seen outside of its scope, ie main can see something that is declared local to MkTest. However, I don't like it, because:

a. I don't understand it

b. It's ugly code. IMO.

I know a lot of people will vehemently disagree with me as people love typedefs, macros etc to save on typing, but I hate the obfuscation of them. So please don't flame me telling me I'm an idiot, that may be true, but it's not helpful in understanding what's going on and getting rid of these obstacles to clear code (or clear in my mind - I accept some people think they make code clearer and that's fine). If you disagree with me, and don't know how to explain to me, please don't tell me how dim I am. I know this already.

So the other question is: what, exactly, is this observer thing please? What is this macro setting up?

Oh and one more thing, I see this "soft device" term used, what is that please?

If you've got to the end of this and don't think I'm an idiot, well done you! ;)

Parents
  • what, exactly, is this observer thing please?

    I can't tell you exactly what it is because I don't understand it fully myself, but -in a nutshell- it declares a function that will be called whenever a BLE event happens. The linker file specifies some memory sections and the softdevice somehow refers to these sections internally.

    This macro:

    NRF_SDH_BLE_OBSERVER(m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);

    expands to this:

    static_assert(1, "NRF_SDH_BLE_ENABLED not set!");                                 \
    static_assert(3 < 4, "Priority level unavailable.");             \
    static nrf_sdh_ble_evt_observer_t m_ble_observer __attribute__ ((section("." "sdh_ble_observers3"))) __attribute__((used)) =  \
    {                                                                                                   \
        .handler   = ble_evt_handler,                                                                          \
        .p_context = ((void *)0)                                                                           \
    }

    Which as far as I understand it just puts a struct in a specific section in memory.


    Oh and one more thing, I see this "soft device" term used, what is that please?

    The softdevice is just how Nordic calls its radio stack. It comes as a precompiled hex file and needs to be flashed together with the application if you want to use any radio functionality.


    So the other question is

    What was the other question?

Reply
  • what, exactly, is this observer thing please?

    I can't tell you exactly what it is because I don't understand it fully myself, but -in a nutshell- it declares a function that will be called whenever a BLE event happens. The linker file specifies some memory sections and the softdevice somehow refers to these sections internally.

    This macro:

    NRF_SDH_BLE_OBSERVER(m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);

    expands to this:

    static_assert(1, "NRF_SDH_BLE_ENABLED not set!");                                 \
    static_assert(3 < 4, "Priority level unavailable.");             \
    static nrf_sdh_ble_evt_observer_t m_ble_observer __attribute__ ((section("." "sdh_ble_observers3"))) __attribute__((used)) =  \
    {                                                                                                   \
        .handler   = ble_evt_handler,                                                                          \
        .p_context = ((void *)0)                                                                           \
    }

    Which as far as I understand it just puts a struct in a specific section in memory.


    Oh and one more thing, I see this "soft device" term used, what is that please?

    The softdevice is just how Nordic calls its radio stack. It comes as a precompiled hex file and needs to be flashed together with the application if you want to use any radio functionality.


    So the other question is

    What was the other question?

Children
Related