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

What is the reason of making nRF APIs that complicated?

As an example, let's see this function from app_hrm (heart rate monitor):

static void conn_params_init(void)
{
    uint32_t               err_code;
    ble_conn_params_init_t cp_init;

    memset(&cp_init, 0, sizeof(cp_init));

    cp_init.p_conn_params                  = NULL;
    cp_init.first_conn_params_update_delay = FIRST_CONN_PARAMS_UPDATE_DELAY;
    cp_init.next_conn_params_update_delay  = NEXT_CONN_PARAMS_UPDATE_DELAY;
    cp_init.max_conn_params_update_count   = MAX_CONN_PARAMS_UPDATE_COUNT;
    cp_init.start_on_notify_cccd_handle    = m_hrs.hrm_handles.cccd_handle;
    cp_init.disconnect_on_fail             = true;
    cp_init.evt_handler                    = NULL;
    cp_init.error_handler                  = conn_params_error_handler;

    err_code = ble_conn_params_init(&cp_init);
    APP_ERROR_CHECK(err_code);
}

Quickly looking, it seems that there's a lot of code doing lots of things. However, after reading out the lines it turns out that the information is mostly redundant (like "cp_init.first_conn_params_update_delay = FIRST_CONN_PARAMS_UPDATE_DELAY"), and the function just bypasses parameters forward to another function. I used to see this type of coding at the beginning of 1990's, but it was quite soon replaced with much more comfortable way, using function parameters. With that style, the above code would shrink as follows:

ble_conn_params_init(
    NULL, FIRST_CONN_PARAMS_UPDATE_DELAY, NEXT_CONN_PARAMS_UPDATE_DELAY,
    MAX_CONN_PARAMS_UPDATE_COUNT, m_hrs.hrm_handles.cccd_handle, true, NULL,
    conn_params_error_handler);

And actually, the extra function definition conn_params_init() would no more be needed at all. This type of coding would make application much much more readable, yet it would save code lines and probably even flash space.

I have to say that your code looks much more complicated that it would need to be. I know this is a kind of "school of thought" issue, and maybe related to "linux-style" -coding. But still, your coding style doesn't make the APIs too easy for customers. Sorry to say, but it has been a horrendous experience to get familiar with nRF51822 SDK (and the DFU OTA is still not working, but that's another story).

Parents
  • Well then you are probably referring to some example and depending on what exactly your app is doing you either use parts of that code or not. Bare in mind that your are using SDK which basically sits on "bare metal" so you are writing the OS not just the app sitting on top of it. If you demand another layer of abstraction then there is reason why no such "OS + API" exists on these systems: they are so restricted in terms of resources (single threaded not powerful CPU, power restrictions, NVM and RAM in the rang of few dozens of kB) that you never fit some "general" layer there which would serve perfectly to all apps. You actually need to be touching so many low level points if you want to make efficient production FW on this kind of chip that predict all use cases by any smarter API is impossible. And if you are dissatisfied with the examples then you can be sure that most of "high rolling" production FWs are not using that, just derived their better and more efficient templates from it. For the newcomer it might be quite a "hit" to work in such complicated SDK but embedded programming isn't PC "Hello World" programming through win32 API, it's actually quite hard;)

    Cheers Jan

    Edit 2015-12-15

    Sorry but I still don't get the point. Are you mad at having some "standard" sequence of function calls in the main which you will copy from project to project? Something like

    int main(void) {
        // Initiate HW.
        board_configure();
    
        // Initiate application timer.
        rtc1_init();
    
        // Initiate your specific applicative configuration.
        config_init();
    
        // Initiate BT stack in Soft Device.
        ble_stack_init();
    
        // Do all application logic (inside the infinite loop).
        do_work();
    }
    

    Or are you saying that there are studies that instead of initiating parameters into the structure like this

    // Prepare Write parameters.
    write_params.write_op = BLE_GATT_OP_WRITE_CMD;
    write_params.handle = m_central_cccd_handle;
    write_params.offset = 0;
    write_params.len = sizeof(write_value);
    write_params.p_value = (uint8_t *)&write_value;
    
    // Central writes to CCCD of peripheral to receive indications.
    err_code = sd_ble_gattc_write(m_central_conn_handle, &write_params);
    

    they should be passed in the parameters (e.g. like this):

    // Central writes to CCCD of peripheral to receive indications.
    err_code = sd_ble_gattc_write(m_central_conn_handle, BLE_GATT_OP_WRITE_CMD, m_central_cccd_handle, 0, sizeof(write_value), (uint8_t *)&write_value);
    

    to better trigger humans' (specifically programmers') cognitive functions? Could you please give me some references? Because I start to doubt I'm OK...;)

    Thx Jan

Reply
  • Well then you are probably referring to some example and depending on what exactly your app is doing you either use parts of that code or not. Bare in mind that your are using SDK which basically sits on "bare metal" so you are writing the OS not just the app sitting on top of it. If you demand another layer of abstraction then there is reason why no such "OS + API" exists on these systems: they are so restricted in terms of resources (single threaded not powerful CPU, power restrictions, NVM and RAM in the rang of few dozens of kB) that you never fit some "general" layer there which would serve perfectly to all apps. You actually need to be touching so many low level points if you want to make efficient production FW on this kind of chip that predict all use cases by any smarter API is impossible. And if you are dissatisfied with the examples then you can be sure that most of "high rolling" production FWs are not using that, just derived their better and more efficient templates from it. For the newcomer it might be quite a "hit" to work in such complicated SDK but embedded programming isn't PC "Hello World" programming through win32 API, it's actually quite hard;)

    Cheers Jan

    Edit 2015-12-15

    Sorry but I still don't get the point. Are you mad at having some "standard" sequence of function calls in the main which you will copy from project to project? Something like

    int main(void) {
        // Initiate HW.
        board_configure();
    
        // Initiate application timer.
        rtc1_init();
    
        // Initiate your specific applicative configuration.
        config_init();
    
        // Initiate BT stack in Soft Device.
        ble_stack_init();
    
        // Do all application logic (inside the infinite loop).
        do_work();
    }
    

    Or are you saying that there are studies that instead of initiating parameters into the structure like this

    // Prepare Write parameters.
    write_params.write_op = BLE_GATT_OP_WRITE_CMD;
    write_params.handle = m_central_cccd_handle;
    write_params.offset = 0;
    write_params.len = sizeof(write_value);
    write_params.p_value = (uint8_t *)&write_value;
    
    // Central writes to CCCD of peripheral to receive indications.
    err_code = sd_ble_gattc_write(m_central_conn_handle, &write_params);
    

    they should be passed in the parameters (e.g. like this):

    // Central writes to CCCD of peripheral to receive indications.
    err_code = sd_ble_gattc_write(m_central_conn_handle, BLE_GATT_OP_WRITE_CMD, m_central_cccd_handle, 0, sizeof(write_value), (uint8_t *)&write_value);
    

    to better trigger humans' (specifically programmers') cognitive functions? Could you please give me some references? Because I start to doubt I'm OK...;)

    Thx Jan

Children
Related