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

Data lost after disable and enable the notification

Hi,

I am working on a project of throughput data from sensors to my central via nrf52805 through a notifying service (SDK16.0.0).

Symptom description

We have app from mobile phone which is ble central.

nRF52805 is ble peripheral and there are many pieces of data to be sent (e.g., 100 pieces of data) after we enable the notification from the mobile app. Each piece of data is 20 byte.

After we enable the notification from mobile app, the system starts to send out the data sequentially.

If we disable the notification in the middle of the transition, for example, it stops at 50th piece of data.

And then we enable the notification.

The mobile app begins to receive the 52nd piece of data (sometimes is 54th piece of data but never is 51st one) so there are some data lost after we disable and enable notification.

Expected behavior

The expected behavior is the app receives the consecutive piece of data (which is 51st one) after we disable and enable the notification.

Current design

Here is the function to handle the notification.

Current design is to check the returned value(ret_code) of sd_ble_gatts_hvx_notification.

if ret_code is NRF_SUCCESS, then the system keeps sending out the data by notification

if ret_code is not NRF_SUCCESS, then the system stops sending.

The returned value is mostly is NRF_SUCCESS but rarely is NRF_ERROR_INVALID_STATE.

uint32_t sd_ble_gatts_hvx_notification(uint16_t conn_handle,
                                           uint16_t value_handle,
                                           uint16_t cccd_handle,
                                           void *p_arg,
                                           uint16_t arg_size)

{
    uint32_t err_code;
    uint8_t  cccd_value_buf[BLE_CCCD_VALUE_LEN];
    ble_gatts_value_t gatts_value;

    memset(&gatts_value, 0, sizeof(gatts_value));
    gatts_value.len     = BLE_CCCD_VALUE_LEN;
    gatts_value.offset  = 0;
    gatts_value.p_value = cccd_value_buf;
    err_code = sd_ble_gatts_value_get(conn_handle,
                                      cccd_handle,
                                      &gatts_value);
    if (err_code == NRF_SUCCESS)
    {
        if (ble_srv_is_notification_enabled(cccd_value_buf))
        {
            ble_gatts_hvx_params_t params;

            memset(&params, 0, sizeof(params));
            params.type   = BLE_GATT_HVX_NOTIFICATION;
            params.handle = value_handle;
            params.p_data = p_arg;
            params.p_len  = &arg_size;
            return sd_ble_gatts_hvx(conn_handle, &params);
        }
        else
        {
            NRF_LOG_INFO("%s(). notification not enabled", __func__);
            err_code = NRF_ERROR_INVALID_STATE;
        }
    }
    else
    {
        NRF_LOG_INFO("%s(). sd_ble_gatts_value_get err_code=0x%x", __func__, err_code);
    }


    return err_code;
}

Maybe I have misunderstood the way notifications work, so I will appreciate any help.

  • Hi,

    It is not common to enable and disable notification dynamically. Typically notification are enabled on initial connection, and then it's enabled for the remaining life time, this allow the peripheral device to send notification as it see fit to the central device. If you want to control the amount of data received on the central device, it is more common to add a characteristic that the central can write commands to, this may be commands to indicate to the application on the peripheral device to please send X notifications and/or start/stop sending notifications.

    The problem with enabling and disabling notifications dynamically is that you quickly end up in race conditions between buffering of notifications on lower level in the stack and exactly when a notification is enabled/disabled on lower level compared to the state of the application.

    Best regards,
    Kenneth

  • Hi, Kenneth

    Thanks for your reply.

    If we enable and disable notification dynamically, this problem happens.

    The solution is to provide another characteristic that the central can write commands to acknowledge. After nRF52805 (ble peripheral) receives the characteristic with correct value/acknowledge, then sends the next piece of data.

    Hope my understanding is correct. Thanks.

  • Yes, that was what I meant yes.

    Best regards,
    Kenneth

Related