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

Client unable to receive notification after 0x3002 from SoftDevice

Hi,

I am having a problem where the client is unable to receive notification from a peripheral after the softdevice in the peripheral returns 0x3002 after a disconnect. The peripheral is running a modified "ble_app_uart" example with the following modifications/design specs

1. PCA10040

2. SDK_17.0.2

3. SoftDevice 7.2.0

4. Modified Nordic Uart Service: Data Length Extension, MTU SIZE = 247, Connection Length Interval Enabled, HW UART functionality removed, min connection interval = max connection interval = 15 (18.75ms)

5. 32-bit timer set to send a random 244 byte packet every 20ms using the "ble_nus_data_send()" as follows

do
{
    err_code = ble_nus_data_send(&m_nus, (uint8_t*)ble_queue[blerdptr], &nus_data_length, m_conn_handle);
} while (err_code == NRF_ERROR_RESOURCES);

if(err_code != NRF_SUCCESS)
{
    //err_code = sd_ble_gatts_sys_attr_set(m_conn_handle, NULL, 0, 0);
    //NRF_LOG_INFO("BLE_ERROR_GATTS_SYS_ATTR_MISSING_LOOP");

    NRF_LOG_INFO("ERROR_CODE IS %u", err_code);
};

6. Timer does not send packets until it receives a 'b' character from the client from its RX interface. Also, timer stops sending packets when peripheral receives a disconnection event.

7. Client is a modified "ble_app_uart_c" running on another PCA10040 to support the modifications from the peripheral or an Android App using modified NUS services.

The above setup works fine and we are able to transfer our 244 byte payload in the 20ms interval without any issues. The problem arises when there is a disconnection. For the most part, If we suddenly disconnect the client (kill Android App or disconnect usb cable of PCA10040 running "ble_app_uart_c") the SoftDevice returns 0x0005 and when we reconnect back to the peripheral everything is fine and we can continue streaming. In a few cases, SoftDevice returns 0x3002. In this particular case after reconnecting with the peripheral, we cannot receive any notification from the peripheral although the peripheral receives commands from the client. Also, the "ble_nus_data_send()" function returns "NRF_SUCCESS" and the "BLE_NUS_EVT_TX_RDY" event is also triggered. I tried enabling/disabling notifications using the nrfConnect App without success.

My questions are as follows:

1. How do I recover from an 0x3002 error such that when there is a reconnection and we can continue to stream data just like in the 0x0005 error case?

2. Is there a better way to send data from the peripheral such that data is not sent when there is a disconnect so as to avoid error 0x3002?

3. Is there a clean up that needs to be done when there is a disconnect from the client using NUS?

4. Is there a better way to use/modify NUS than what we have done?

Thanks You

Parents
  • Hi,

    I assume 0x3002 means BLE_ERROR_INVALID_CONN_HANDLE.

    That seem to indicate that m_conn_handle has changed between the two connections, which it may do. Can you make sure that m_conn_handle is updated/correct before calling ble_nus_data_send()?

    Typically you want to have a global flag of some sort, that make sure you don't call ble_nus_data_send() unless you are in a connection (with a valid m_conn_handle).

    Kenneth

  • Hi Kenneth,

    Thanks for the suggestion. In our current implementation, we do have a global flag that we use to make sure we have a valid connection. That test is right above the call to "ble_nus_data_send()" in the "do" loop but this is not shown in the code snippet above. 

    We still get the same behavior with or without the test for a valid connection. Most of the time, we are able to recover because the err_code is 0x0005. But in a few times, we get the 0x3002 err_code. Only when this happens that we have problems getting notifications after a reconnect and no errors are generated by the Softdevice.

  • I suggest to add some NRF_LOG() output every time you connect, disconnect and ble_nus_data_send(), to log the connection handle. I suspect that your handle is incorrect, for instance that you may have some race condition in your code where the handle is somehow set wrong between connects and disconnects.

    Kenneth

  • I have added the NRF_LOG()s as suggested. But first, let me give more context about our FW. Below is a snippet of code for sending the packets to the client.

    if(ble_conn_flag == 1)
            {
                if(ble_conn_intvl == 1)
                {
                    do
                    {
                        if(m_conn_handle != BLE_CONN_HANDLE_INVALID)
                          err_code = ble_nus_data_send(&m_nus, (uint8_t*)ble_queue[blerdptr], &nus_data_length, m_conn_handle);
                        else
                          err_code = 0x20;
    
                    } while (err_code == NRF_ERROR_RESOURCES);
    
                    if(err_code != NRF_SUCCESS)
                    {
                        //err_code = sd_ble_gatts_sys_attr_set(m_conn_handle, NULL, 0, 0);
                        //NRF_LOG_INFO("BLE_ERROR_GATTS_SYS_ATTR_MISSING_LOOP");
    
                        NRF_LOG_INFO("ERROR_CODE IS %u", err_code);
                        if(err_code == 0x3002)
                        {
                          /* Reset device */
                          //nrf_pwr_mgmt_shutdown(NRF_PWR_MGMT_SHUTDOWN_RESET);
                        };
                    };
    
                    if(m_conn_handle == BLE_CONN_HANDLE_INVALID)
                        nrf_gpio_pin_write(NRF_GPIO_PIN_MAP(0,19), 1);
                    else
                        nrf_gpio_pin_toggle(NRF_GPIO_PIN_MAP(0,19));
                };                        
            };
    "ble_conn_flag" is set when we receive a command from the client side through "BLE_NUS_EVT_RX_DATA". "ble_conn_interval" is set after responding to the "BLE_GAP_EVT_CONN_PARAM_UPDATE" or "BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST" events from the BLE stack. We also check for the connection handle before calling the function :ble_nus_data_send()".  From my NRF_LOG()s, when connected the connection handle is 0. On disconnect, the connection handle is 0xFFFF.

    When there is a disconnection/reconnection of the BLE link that is recoverable, a snippet of the NRF_LOG() is

    00> <info> app: Disconnected
    00> 
    00> <info> app: Connection handle = 65535
    00> 
    00> <info> app: ERROR_CODE IS 32
    00> 
    00> <info> app: Connected
    00> 
    00> <info> app: Connection handle = 0

    The error code is the 0x20 from the "else" statement from the FW snippet above. This indicates that the trap caught the invalid handle before the call to "ble_nus_data_send()".

    Now, when we have a disconnection/reconnection of the BLE link that is not recoverable, theNRF_LOG()s show

    00> <info> app: Disconnected
    00> 
    00> <info> app: Connection handle = 65535
    00> 
    00> <info> app: ERROR_CODE IS 12290
    00> 
    00> <info> app: Connected
    00> 
    00> <info> app: Connection handle = 0

    I am assuming that BLE stack events have higher priority than my code, and if a disconnect event happens that a change in the connection handle will occur before the "ble_nus_data_send()" is called. There is clearly a race condition happening but it is not clear where/how is it manifesting. As you can see, i trapped the call to "ble_nus_data_send()". Also, I do not call "ble_nus_data_send()" until the BLE link is establish and we receive events from the BLE stack and commands from the client.

Reply
  • I have added the NRF_LOG()s as suggested. But first, let me give more context about our FW. Below is a snippet of code for sending the packets to the client.

    if(ble_conn_flag == 1)
            {
                if(ble_conn_intvl == 1)
                {
                    do
                    {
                        if(m_conn_handle != BLE_CONN_HANDLE_INVALID)
                          err_code = ble_nus_data_send(&m_nus, (uint8_t*)ble_queue[blerdptr], &nus_data_length, m_conn_handle);
                        else
                          err_code = 0x20;
    
                    } while (err_code == NRF_ERROR_RESOURCES);
    
                    if(err_code != NRF_SUCCESS)
                    {
                        //err_code = sd_ble_gatts_sys_attr_set(m_conn_handle, NULL, 0, 0);
                        //NRF_LOG_INFO("BLE_ERROR_GATTS_SYS_ATTR_MISSING_LOOP");
    
                        NRF_LOG_INFO("ERROR_CODE IS %u", err_code);
                        if(err_code == 0x3002)
                        {
                          /* Reset device */
                          //nrf_pwr_mgmt_shutdown(NRF_PWR_MGMT_SHUTDOWN_RESET);
                        };
                    };
    
                    if(m_conn_handle == BLE_CONN_HANDLE_INVALID)
                        nrf_gpio_pin_write(NRF_GPIO_PIN_MAP(0,19), 1);
                    else
                        nrf_gpio_pin_toggle(NRF_GPIO_PIN_MAP(0,19));
                };                        
            };
    "ble_conn_flag" is set when we receive a command from the client side through "BLE_NUS_EVT_RX_DATA". "ble_conn_interval" is set after responding to the "BLE_GAP_EVT_CONN_PARAM_UPDATE" or "BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST" events from the BLE stack. We also check for the connection handle before calling the function :ble_nus_data_send()".  From my NRF_LOG()s, when connected the connection handle is 0. On disconnect, the connection handle is 0xFFFF.

    When there is a disconnection/reconnection of the BLE link that is recoverable, a snippet of the NRF_LOG() is

    00> <info> app: Disconnected
    00> 
    00> <info> app: Connection handle = 65535
    00> 
    00> <info> app: ERROR_CODE IS 32
    00> 
    00> <info> app: Connected
    00> 
    00> <info> app: Connection handle = 0

    The error code is the 0x20 from the "else" statement from the FW snippet above. This indicates that the trap caught the invalid handle before the call to "ble_nus_data_send()".

    Now, when we have a disconnection/reconnection of the BLE link that is not recoverable, theNRF_LOG()s show

    00> <info> app: Disconnected
    00> 
    00> <info> app: Connection handle = 65535
    00> 
    00> <info> app: ERROR_CODE IS 12290
    00> 
    00> <info> app: Connected
    00> 
    00> <info> app: Connection handle = 0

    I am assuming that BLE stack events have higher priority than my code, and if a disconnect event happens that a change in the connection handle will occur before the "ble_nus_data_send()" is called. There is clearly a race condition happening but it is not clear where/how is it manifesting. As you can see, i trapped the call to "ble_nus_data_send()". Also, I do not call "ble_nus_data_send()" until the BLE link is establish and we receive events from the BLE stack and commands from the client.

Children
No Data
Related