This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts
This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

BLE Multilink example + Throughput example

Hi there,

I'm trying to combine the BLE Multilink example with the Throughput example, with the hope that I can connect 1 Central to 2 Peripherals and get a high throughput.

In creating the AMTS instance, I'm a bit unsure of which ones have to be 2 instances and which one can share the function.

For example:
1) I created 2 instances of m_amts

nrf_ble_amts_t m_amts[2]

2) I only call NRF_SDH_BLE_OBSERVER once, since I assume I can reuse the m_amts_ble_obs and the handler nrf_ble_amts_on_ble_evt for both connection.

NRF_SDH_BLE_OBSERVER(m_amts_ble_obs, BLE_AMTS_BLE_OBSERVER_PRIO, nrf_ble_amts_on_ble_evt, NULL);

--> I'm thinking to put the condition inside nrf_ble_amts_on_ble_evt.  So conn_handle==0 will use m_amts[0] and conn_handle==1 will use m_amts[1]

3) I called nrf_ble_amts_init twice, but with different m_amts
nrf_ble_amts_init(&m_amts[0], amts_evt_handler, ...)

nrf_ble_amts_init(&m_amts[1], amts_evt_handler, ...)

4) I reuse the UUID for both, ie AMT_SERVICE_UUID, AMTS_CHAR_UUID, AMT_RCV_BYTES_CNT_CHAR_UUID are used for both m_amts[0] and m_amts[1]

So far I can connect to 2 Peripherals.  However, it fails in the "on_write" function inside nrf_ble_amts_on_ble_evt.


In this check

if ((p_evt_write->handle == p_ctx->amts_char_handles.cccd_handle) && (p_evt_wirte->len ==2)) {

//CCCD written, call the application event handler...

...

}

The 2nd connection always fails because for the 2nd connection the "p_evt_write->handle" is 13 or 14 and "p_ctx->amts_char_handles.cccd_handle" for the 2nd connection is 19 or 20.


Should I have created new set of services for the 2nd peripheral?  Or other things I can do for workaround this?


Thanks,
Cecylia

Parents
  • Hi again

    It seems like you're only logging the <info> and <error> messages. Please try adding DEBUG to your preprocessor definitions in order to get more information in terms of logging (as explained in the link in my last reply). If you're able to see what error message the sd_ble_gatts_hvx() error returns you can take a look at the description of the possible errors here (from ble_gatts.h) :

    @retval ::NRF_SUCCESS Successfully queued a notification or indication for transmission, and optionally updated the attribute value.
     * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle.
     * @retval ::NRF_ERROR_INVALID_STATE One or more of the following is true:
     *                                   - Invalid Connection State
     *                                   - Notifications and/or indications not enabled in the CCCD
     *                                   - An ATT_MTU exchange is ongoing
     * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
     * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied.
     * @retval ::BLE_ERROR_INVALID_ATTR_HANDLE Invalid attribute handle(s) supplied. Only attributes added directly by the application are available to notify and indicate.
     * @retval ::BLE_ERROR_GATTS_INVALID_ATTR_TYPE Invalid attribute type(s) supplied, only characteristic values may be notified and indicated.
     * @retval ::NRF_ERROR_NOT_FOUND Attribute not found.
     * @retval ::NRF_ERROR_FORBIDDEN The connection's current security level is lower than the one required by the write permissions of the CCCD associated with this characteristic.
     * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied.
     * @retval ::NRF_ERROR_BUSY For @ref BLE_GATT_HVX_INDICATION Procedure already in progress. Wait for a @ref BLE_GATTS_EVT_HVC event and retry.
     * @retval ::BLE_ERROR_GATTS_SYS_ATTR_MISSING System attributes missing, use @ref sd_ble_gatts_sys_attr_set to set them to a known value.
     * @retval ::NRF_ERROR_RESOURCES Too many notifications queued.
     *                               Wait for a @ref BLE_GATTS_EVT_HVN_TX_COMPLETE event and retry.
     * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without reestablishing the connection.
     */

    One thought is that your service (on the central side) doesn't handle the connection handles correctly and isn't able to separate the two notification requests from each other.

    Best regards,

    Simon

  • Hi Simon,

    I added the verbosity level and I got more information.  As you predicted, I didn't seem to initialize the Central's Services properly.

    Here's how I initialized.  I tried to separate the functions for the 2 servers (m_amts) for debugging.

    // NRF_SDH_BLE_CENTRAL_LINK_COUNT is 2
    
    NRF_BLE_QWRS_DEF(m_qwr_array_c, NRF_SDH_BLE_CENTRAL_LINK_COUNT);
    NRF_BLE_GATT_DEF(m_gatt); /**< GATT module instance. */
    BLE_DB_DISCOVERY_ARRAY_DEF(m_ble_db_discovery, NRF_SDH_BLE_CENTRAL_LINK_COUNT); /**< Database discovery module instances. */
    NRF_BLE_SCAN_DEF(m_scan); /**< Scanning Module instance. */
    NRF_BLE_GQ_DEF(m_ble_gatt_queue, /**< BLE GATT Queue instance. */
    NRF_SDH_BLE_CENTRAL_LINK_COUNT,
    NRF_BLE_GQ_QUEUE_SIZE);
    
    // Here's how I initialized m_amts
    nrf_ble_amts_t m_amts[NRF_SDH_BLE_CENTRAL_LINK_COUNT];
    NRF_SDH_BLE_OBSERVER(m_amts_ble_obs, BLE_AMTS_BLE_OBSERVER_PRIO, nrf_ble_amts_on_ble_evt, &m_amts[0]);
    NRF_SDH_BLE_OBSERVER(m_amts_ble_obs1, BLE_AMTS_BLE_OBSERVER_PRIO, nrf_ble_amts_on_ble_evt1, &m_amts[1]);
    
    ...
    
    // And then here's the server init
    static void server_init(void)
    {
        qwr_init();
    
        for (uint8_t qq = 0; qq < NRF_SDH_BLE_CENTRAL_LINK_COUNT; qq++) {
            nrf_ble_amts_init(&m_amts[qq], amts_evt_handler, 244 /*sizeof(client_to_marc_t)*/,
                            sizeof(marc_to_client_t));
            m_amts[qq].conn_handle = BLE_CONN_HANDLE_INVALID;
        }
    }

    When I power on the 1st peripheral board and the first connection happens, both nrf_ble_amts_on_ble_evt and nrf_ble_amts_on_ble_evt1 are called and m_amts[0] and m_amts[1] are updated.  I.e., both conn_handle are now set to 0.

    Then when I power on the 2nd board, both m_amts[0] and m_amts[1]'s connection handles are set to 1. 

    I believe this is wrong.  I think the first connection should only set the conn_handle for the first server, so if done correctly they should end up as:
    m_amts[0].conn_handle = 0
    m_amts[1].conn_handle = 1

    Instead of what I have now, where after the 2nd connection,both are set to 1.


    So, my question is, when an event happen, and both 

    void nrf_ble_amts_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)

    and

    void nrf_ble_amts_on_ble_evt1(ble_evt_t const * p_ble_evt, void * p_context)

    are called, can I put a condition inside these functions so that based on the information inside p_ble_evt I can know if it should be handled by the first or the 2nd connection? 

    Or should the fix be way earlier, ie during the init, such that BLE events for the 1st connection should not even call the 2nd handler?

    PS: I didn't get much information from chasing the "sd_ble_gatts_hvx".  

    Thanks a lot,
    Cecylia

Reply
  • Hi Simon,

    I added the verbosity level and I got more information.  As you predicted, I didn't seem to initialize the Central's Services properly.

    Here's how I initialized.  I tried to separate the functions for the 2 servers (m_amts) for debugging.

    // NRF_SDH_BLE_CENTRAL_LINK_COUNT is 2
    
    NRF_BLE_QWRS_DEF(m_qwr_array_c, NRF_SDH_BLE_CENTRAL_LINK_COUNT);
    NRF_BLE_GATT_DEF(m_gatt); /**< GATT module instance. */
    BLE_DB_DISCOVERY_ARRAY_DEF(m_ble_db_discovery, NRF_SDH_BLE_CENTRAL_LINK_COUNT); /**< Database discovery module instances. */
    NRF_BLE_SCAN_DEF(m_scan); /**< Scanning Module instance. */
    NRF_BLE_GQ_DEF(m_ble_gatt_queue, /**< BLE GATT Queue instance. */
    NRF_SDH_BLE_CENTRAL_LINK_COUNT,
    NRF_BLE_GQ_QUEUE_SIZE);
    
    // Here's how I initialized m_amts
    nrf_ble_amts_t m_amts[NRF_SDH_BLE_CENTRAL_LINK_COUNT];
    NRF_SDH_BLE_OBSERVER(m_amts_ble_obs, BLE_AMTS_BLE_OBSERVER_PRIO, nrf_ble_amts_on_ble_evt, &m_amts[0]);
    NRF_SDH_BLE_OBSERVER(m_amts_ble_obs1, BLE_AMTS_BLE_OBSERVER_PRIO, nrf_ble_amts_on_ble_evt1, &m_amts[1]);
    
    ...
    
    // And then here's the server init
    static void server_init(void)
    {
        qwr_init();
    
        for (uint8_t qq = 0; qq < NRF_SDH_BLE_CENTRAL_LINK_COUNT; qq++) {
            nrf_ble_amts_init(&m_amts[qq], amts_evt_handler, 244 /*sizeof(client_to_marc_t)*/,
                            sizeof(marc_to_client_t));
            m_amts[qq].conn_handle = BLE_CONN_HANDLE_INVALID;
        }
    }

    When I power on the 1st peripheral board and the first connection happens, both nrf_ble_amts_on_ble_evt and nrf_ble_amts_on_ble_evt1 are called and m_amts[0] and m_amts[1] are updated.  I.e., both conn_handle are now set to 0.

    Then when I power on the 2nd board, both m_amts[0] and m_amts[1]'s connection handles are set to 1. 

    I believe this is wrong.  I think the first connection should only set the conn_handle for the first server, so if done correctly they should end up as:
    m_amts[0].conn_handle = 0
    m_amts[1].conn_handle = 1

    Instead of what I have now, where after the 2nd connection,both are set to 1.


    So, my question is, when an event happen, and both 

    void nrf_ble_amts_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)

    and

    void nrf_ble_amts_on_ble_evt1(ble_evt_t const * p_ble_evt, void * p_context)

    are called, can I put a condition inside these functions so that based on the information inside p_ble_evt I can know if it should be handled by the first or the 2nd connection? 

    Or should the fix be way earlier, ie during the init, such that BLE events for the 1st connection should not even call the 2nd handler?

    PS: I didn't get much information from chasing the "sd_ble_gatts_hvx".  

    Thanks a lot,
    Cecylia

Children
Related