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

Central and Peripheral: BLE_NUS in parallel with BLE_HRS_C

Hi, 

would like to run several (8) BLE_HRS_C in parallel to one BLE_NUS on a nRF5. Can that work?

In general, is it there any sample code showing how to implement peripheral role (BLE_NUS)  in parallel with central role (BLE_HRS_C)? 

The problem I am encountering (on nRF52840 DK, nRF5_SDK_15.2.0_9412b96) is with BLE_NUS, when sending data (ble_nus_data_send()) it hangs in ble_link_ctx_manager.c:70:

```

70 if (conn_id >= p_link_ctx_storage->max_links_cnt)

71 {
72 return NRF_ERROR_NO_MEM;
73 }

```

as the connection id of the peripheral (BLE_NUS) conn_id==8 and there is only 1 BLE_LINK_CTX_MANAGER_DEF defined (in ble_nus.c), therefore p_link_ctx_storage->max_links_cnt==1. What is the right way to solve this?

Thanks,

Andrea

Parents
  • Hi,

    We don't have an example for combining hrs_c and nus unfortunately. But you can try adding filtering of the BLE events in the NUS services so only connections with GAP peripheral role will be processed by the event handler. 

    You can use the connection state module to keep track GAP roles for each active connections. E.g., 

    diff --git a/components/ble/ble_services/ble_nus/ble_nus.c b/components/ble/ble_services/ble_nus/ble_nus.c
    index 1c32b52..631f1c4 100644
    --- a/components/ble/ble_services/ble_nus/ble_nus.c
    +++ b/components/ble/ble_services/ble_nus/ble_nus.c
    @@ -217,7 +217,8 @@ static void on_hvx_tx_complete(ble_nus_t * p_nus, ble_evt_t const * p_ble_evt)
    
     void ble_nus_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
     {
    -    if ((p_context == NULL) || (p_ble_evt == NULL))
    +    if ((p_context == NULL) || (p_ble_evt == NULL) ||
    +        (BLE_GAP_ROLE_PERIPH != ble_conn_state_role(p_ble_evt->evt.common_evt.conn_handle)))
         {
             return;
         }
    

  • Hi, 

    ok, thanks and noted about not available sample. 

    Do you mean that i need anyhow to modify ble_nus.c? And you modification is the one to take, not the one I actually made (see below)?

    diff --git a/components/ble/ble_link_ctx_manager/ble_link_ctx_manager.c b/components/ble/ble_link_ctx_manager/ble_link_ctx_manager.c
    index 2a139f4..11ae062 100644
    --- a/components/ble/ble_link_ctx_manager/ble_link_ctx_manager.c
    +++ b/components/ble/ble_link_ctx_manager/ble_link_ctx_manager.c
    @@ -67,10 +67,10 @@ ret_code_t blcm_link_ctx_get(blcm_link_ctx_storage_t const * const p_link_ctx_st
             return NRF_ERROR_NOT_FOUND;
         }
     
    -    if (conn_id >= p_link_ctx_storage->max_links_cnt)
    -    {
    -        return NRF_ERROR_NO_MEM;
    -    }
    +    //if (conn_id >= p_link_ctx_storage->max_links_cnt)^M
    +    //{^M
    +    //    return NRF_ERROR_NO_MEM;^M
    +    //}^M
     
         *pp_ctx_data = (void *) ((uint8_t *) p_link_ctx_storage->p_ctx_data_pool + 
                                  conn_id * p_link_ctx_storage->link_ctx_size);
    

    Regards,

    Andrea

  • Hi Andrea,

    Yes, that's what I meant. My proposed change should prevent the "BLE_HRS_C" connections from being processed by the NUS service. 

  • Hi, 

    does not work. conn_id==8 still reaches components/ble/ble_link_ctx_manager/ble_link_ctx_manager.c as above and generates same error above. 

    (gdb) p conn_handle
    $2 = 8
    (gdb) s
    nrf_atflags_get (p_flags=p_flags@entry=0x2000bf90 <m_bcs+4>, flag_index=flag_index@entry=8)
        at ../../../../../../components/libraries/atomic_flags/nrf_atflags.c:95
    95          return (p_flags[FLAG_BASE(flag_index)] & FLAG_MASK(flag_index)) != 0;
    (gdb) s
    blcm_link_ctx_get (p_link_ctx_storage=0x2000ad74 <m_nus_link_ctx_storage>,
        conn_handle=conn_handle@entry=8, pp_ctx_data=pp_ctx_data@entry=0x2000fba4)
        at ../../../../../../components/ble/ble_link_ctx_manager/ble_link_ctx_manager.c:65
    65          if (conn_id == BLE_CONN_STATE_MAX_CONNECTIONS)
    (gdb) bt
    #0  blcm_link_ctx_get (p_link_ctx_storage=0x2000ad74 <m_nus_link_ctx_storage>, conn_handle=conn_handle@entry=8, pp_ctx_data=pp_ctx_data@entry=0x2000fba4)
        at ../../../../../../components/ble/ble_link_ctx_manager/ble_link_ctx_manager.c:65
    #1  0x000342d8 in ble_nus_data_send (p_nus=p_nus@entry=0x2000ad58 <m_nus>, p_data=p_data@entry=0x2000b83c <data_array> "<removed text>\r", p_length=0x2000fbd2, 
        p_length@entry=0x2000fbb2, conn_handle=<optimized out>) at ../../../../../../components/ble/ble_services/ble_nus/ble_nus.c:325
    #2  0x0002c268 in send_to_nus (fmt=0x35a38 "blished, starting DB discovery.") at ../../../main.c:185
    #3  0x0002c69e in ble_evt_handler (p_ble_evt=0x2000fc84, p_context=<optimized out>) at ../../../main.c:433
    #4  0x0002d0aa in nrf_sdh_ble_evts_poll (p_context=<optimized out>) at ../../../../../../components/softdevice/common/nrf_sdh_ble.c:307
    #5  0x0002d056 in nrf_sdh_evts_poll () at ../../../../../../components/softdevice/common/nrf_sdh.c:358
    #6  SWI2_EGU2_IRQHandler () at ../../../../../../components/softdevice/common/nrf_sdh.c:367
    #7  <signal handler called>
    #8  0x00015c7e in ?? ()
    #9  0x00015c7c in ?? ()
    Backtrace stopped: previous frame identical to this frame (corrupt stack?)
    

    Anything I am doing wrong?

  • Hi,

    Sorry, you're right, the link context manager uses the connection handle value to determine if it has enough buffer for the connection even though it's only used for the NUS connection in this case. Does it work if you also comment out the error check in  ble_link_ctx_manager? 

  • Yes, sure. The below is sufficient. But I did not wanna modify SDK files. Just wondering what is the right way to do it. 

    diff --git a/components/ble/ble_link_ctx_manager/ble_link_ctx_manager.c b/components/ble/ble_link_ctx_manager/ble_link_ctx_manager.c
    index 2a139f4..11ae062 100644
    --- a/components/ble/ble_link_ctx_manager/ble_link_ctx_manager.c
    +++ b/components/ble/ble_link_ctx_manager/ble_link_ctx_manager.c
    @@ -67,10 +67,10 @@ ret_code_t blcm_link_ctx_get(blcm_link_ctx_storage_t const * const p_link_ctx_st
             return NRF_ERROR_NOT_FOUND;
         }
     
    -    if (conn_id >= p_link_ctx_storage->max_links_cnt)
    -    {
    -        return NRF_ERROR_NO_MEM;
    -    }
    +    //if (conn_id >= p_link_ctx_storage->max_links_cnt)^M
    +    //{^M
    +    //    return NRF_ERROR_NO_MEM;^M
    +    //}^M
     
         *pp_ctx_data = (void *) ((uint8_t *) p_link_ctx_storage->p_ctx_data_pool + 
                                  conn_id * p_link_ctx_storage->link_ctx_size);
    

  • With the current implementation, the more correct way would probably be to use the link context manager for all links and not just the NUS connection. But I think it's ok to modify the SDK module as you did.

Reply Children
  • This issue is a pain for me as well. Having central and peripheral connections doesn't work very well with the link ctx mgr. It's a bit wasteful having  sizeof(ble_nus_client_context_t) * num_central_connections unused bytes allocated for the ctx manager. Especially when you've got a lot of connection which use up a lot ofRAM already. 

    I know it's not ideal but I use my own blcm_link_ctx_get function to handle this

    static uint32_t get_link_ctx(ble_gm_device_t * p_gm_device, uint16_t conn_handle, ble_gm_device_client_context_t ** const p_client)
    {
        if (p_client == NULL)
        {
            return NRF_ERROR_NULL;
        }
        else
        {
            *p_client = NULL;
        }
        
        VERIFY_PARAM_NOT_NULL(p_gm_device->p_link_ctx_storage);
        VERIFY_PARAM_NOT_NULL(p_gm_device->p_link_ctx_storage->p_ctx_data_pool);
        VERIFY_TRUE((p_gm_device->p_link_ctx_storage->link_ctx_size % BYTES_PER_WORD) == 0, NRF_ERROR_INVALID_PARAM);
        
        uint16_t link_ctx_index = 0;
        for(link_ctx_index = 0; link_ctx_index < p_gm_device->p_link_ctx_storage->max_links_cnt; link_ctx_index++)
        {
            if(p_gm_device->conn_handles[link_ctx_index] == conn_handle )
            {
                *p_client = (void *) ((uint8_t *) p_gm_device->p_link_ctx_storage->p_ctx_data_pool + 
                                 link_ctx_index * p_gm_device->p_link_ctx_storage->link_ctx_size);
                return NRF_SUCCESS;
            }
        }
        return NRF_ERROR_NOT_FOUND;
        
    }

Related