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

Notifications disappear on their way

I use two nrf51 chips, one of which works as central and second one as peripheral. After the DM_EVT_LINK_SECURED event is generated on the peripheral side I'm starting the app_timer in single_shot mode with a 15ms period. Inside of this timer, the characteristic is updated (in the same way as in "Bluetooth low energy Characteristics, a beginner's tutorial") with only one byte of data. On the central side I use lbs client profile and after BLE_GATTC_EVT_HVX is generated I change the flag in the program and terminate the connection.

Now, the problem is this notification send by server (peripheral) never reach the client (central). To actually send data I must repeat updates of the characteristic and only after few updates one of the notification come to the client. Could someone explain to me why this happens and how to overcome this? I use SDK 11

  • that can't happen. BLE is reliable at the transport level so if you are sending a packet it will arrive at the other end (or the link will timeout). So you don't have to send it multiple times. So if you think you do, your bug is elsewhere.

    Are you waiting for the callback telling you the packet buffer has been retired, when you have that you know the underlying transport has successfully sent the packet and received the L2CAP level confirmation the client side has received it? If you terminate the connection before that, you may just prevent it actually sending the packet out if the stack hasn't sent it yet, is waiting for the next connection interval or is in the process of retrying it.

  • The connection terminate only by the client when BLE_GATTC_EVT_HVX event arrives. In the described situation (if only one notification is being sent) the connection last forever.

  • Sorry for delay, I wanted to upload compilable files but I figured eventually that it will last too long to clean them up so I upload this:

    Server:

    #define MIN_CONN_INTERVAL                MSEC_TO_UNITS(7.5, UNIT_1_25_MS)          
    #define MAX_CONN_INTERVAL                MSEC_TO_UNITS(4000, UNIT_1_25_MS)         
    #define SLAVE_LATENCY                    0                                      
    #define CONN_SUP_TIMEOUT                 MSEC_TO_UNITS(20000, UNIT_10_MS)            
    
    
    static uint32_t device_manager_evt_handler(dm_handle_t const * p_handle,
                                           dm_event_t const  * p_event,
                                           ret_code_t        event_result)
    {
    	switch (p_event->event_id)
    	{
    		case DM_EVT_DEVICE_CONTEXT_STORED:
    				
    				printf("Status of bonding: BONDED");												
    				printf("\n");
    				printf("\033[80D");
    				
    
    				sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
    				break;
    		
    		case DM_EVT_LINK_SECURED:
    				app_timer_start(test_timer_id, TEST_TIMER_INTERVAL, NULL);
    
    		break;
    		default:
    				break;
    	}
    	
    	#ifdef BLE_DFU_APP_SUPPORT
    	if (p_event->event_id == DM_EVT_LINK_SECURED)
    	{
    		app_context_load(p_handle);
    	}
    	#endif // BLE_DFU_APP_SUPPORT
    	return NRF_SUCCESS;
    }
    
    void test_timeout(void * p_context)
    {
    	if(button_down){our_config_characteristic_update(&m_our_service, BUTTON);}
    	else {}
    	
        printf("Data were sent");
    	printf("\n\033[80D");
    
    }
    

    Client:

    #define MIN_CONNECTION_INTERVAL    MSEC_TO_UNITS(15, UNIT_1_25_MS)   
    #define MAX_CONNECTION_INTERVAL    MSEC_TO_UNITS(15, UNIT_1_25_MS)   
    #define SLAVE_LATENCY              0                                 
    #define SUPERVISION_TIMEOUT        MSEC_TO_UNITS(1000, UNIT_10_MS)    
    
    static void lbs_c_init(void)
    {
         ble_lbs_c_init_t lbs_c_init_obj;
         lbs_c_init_obj.evt_handler = lbs_c_evt_handler;
         ble_lbs_c_init(&m_ble_lbs_c, &lbs_c_init_obj);
    }
    
    
    static void lbs_c_evt_handler(ble_lbs_c_t * p_lbs_c, ble_lbs_c_evt_t * p_lbs_c_evt)
    {
    switch (p_lbs_c_evt->evt_type)
    {
        case BLE_LBS_C_EVT_DISCOVERY_COMPLETE:
        {
            ret_code_t err_code;
            err_code = ble_lbs_c_handles_assign(&m_ble_lbs_c,
                                                p_lbs_c_evt->conn_handle,
                                                &p_lbs_c_evt->params.peer_db);
    
            err_code = ble_lbs_c_button_notif_enable(p_lbs_c);
            APP_ERROR_CHECK(err_code);
        } break; 
    
        case BLE_LBS_C_EVT_BUTTON_NOTIFICATION:
        {
            if (p_lbs_c_evt->params.button.button_state)
            {
    				data_received = true;
    				sd_ble_gap_disconnect(m_conn_handle,  
                                        BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
            }
            else {}
        } break; 
    
        default:
            // No implementation needed.
            break;
    }
    }
    
  • I made following experiment:

    On the server side: After the DM_EVT_LINK_SECURED event was received the test_timer is started. The characteristic is updated inside of timeout handler with the counter value. The counter is incremented after each entry to the timeout handler. When the counter reaches the value of 30 the timer is stopped. The connection is terminated by another timer after 10 seconds since the beginning.

    On the client side: Each time when on_hvx function in ble_lbs_c.c is called, the local counter is incremented. After the connection has been terminated, the value of local counter and value of characteristic (updated by server) are displayed:

    local_counter = 23 
    char_value    = 30
    

    It seems that first few notifications are just lost and I guess that it is kind of mistake in SoftDevice implementation. Am I right or I missed something?

Related