bt_gatt_notify intermittently not received by phone application

  1. Device Overview

We have developed a smart wearable that sends notifications to our mobile application over BLE. Under normal conditions, the device alternates sensor + battery data and IMU data every second and status updates is sent on event.

  1. GATT Profile

2.1 Services and Characteristics
Battery Service

  • Battery Level characteristic

Debug Service

  • Debug characteristic

Data Service

  • Sensor Data characteristic (20 bytes)

  • Status Data characteristic (2 bytes)

  • IMU Data characteristic (12 bytes)

SMP Service
(Secure Management Protocol for OTA updates)

2.2 MTU
Default MTU size is used: 23 bytes

  1. Notification Schedule

  • Sensor Data and IMU Data notifications alternate once every second

  • Status Data is sent only when an event occurs (not on a timer)

  • Battery Level notifications are sent on demand

  1. Observed Issue

In most cases, all notifications arrive correctly.
Intermittently, Sensor Data, IMU Data and Battery Level notifications fail to arrive, while Status Data continues to be received reliably.
This behavior is seen in the user field; we’re unable to reproduce it in the lab, which makes debugging complex.
One user downloaded nRF Connect and the problem still occurs, so it does not appear related to our app.

  1. Expected Behavior

All characteristics configured for notification should deliver updates without loss, according to the schedule above.

We are really struggling to find the root cause of the issue or just a reproducer, thank you for any pointers or insights!
27317.prj.conf

Parents
  • Hi,

    Bluetooth ensures delivery of notifications and other GATT data. Retransmission will be attempted until successfull, or the link is disconnected due to supervision timeout. That leads to a few questions:

    1. Is there a disconnect seen when you loose data, or not? If yes, we need to follow that path. If not, there are other considerations:

    2. Do you know that the notifications are acually "sent" from the application, by Bluetooth API calls?  Or could it be that the calls are not made for some reason (due to application logic, for instance)?

    3. Do the API calls where you sent the notifications (that typically end up in bt_gatt_notify()) succeed or are errors returned?

    I understand this is tricky as you are not reproducing in your lab, but perhaps you can add some more logging to get information about this in the field? If not, I suspect there is a need to find a way to reproduce this on your end to debug further.

Reply
  • Hi,

    Bluetooth ensures delivery of notifications and other GATT data. Retransmission will be attempted until successfull, or the link is disconnected due to supervision timeout. That leads to a few questions:

    1. Is there a disconnect seen when you loose data, or not? If yes, we need to follow that path. If not, there are other considerations:

    2. Do you know that the notifications are acually "sent" from the application, by Bluetooth API calls?  Or could it be that the calls are not made for some reason (due to application logic, for instance)?

    3. Do the API calls where you sent the notifications (that typically end up in bt_gatt_notify()) succeed or are errors returned?

    I understand this is tricky as you are not reproducing in your lab, but perhaps you can add some more logging to get information about this in the field? If not, I suspect there is a need to find a way to reproduce this on your end to debug further.

Children
  • Hi Einar,
    Thanks for the prompt reply.

    1. No disconnection is seen (status notification still works, these are based on user event)

    2. The call to bt_gatt_notify is conditionned to :

    • phone being connected (seems to be ok cause same check for status)

    • Notify_enable flag (set and unset with ccc callback) (it seems this flag is unecessary, we are going to remove it in the next version.

    But, the difference from the status notify is that all the other call are launched by a timer in another work queue, so that might come from here.

    k_work_queue_init(&sensor_timer_work_q);
    k_work_queue_start(&sensor_timer_work_q,
                       sensor_timer_stack,
                       K_THREAD_STACK_SIZEOF(sensor_timer_stack), 5,
                       NULL);
    
    k_timer_init(&adc_timer, sensor_timer_event, NULL);
    k_timer_start(&adc_timer, K_NO_WAIT, K_MSEC(SAMPLING_ROUND_INTERVAL_MSEC));
    
    void sensor_timer_event(struct k_timer *timer_id)
    {
        ARG_UNUSED(timer_id);
        k_work_submit_to_queue(&sensor_timer_work_q, &on_imu_and_send_gsr_work);
    }
    
    void on_imu_and_send_gsr_handler()
    {
        call to bt_gatt_notify()
    }
    
    K_WORK_DEFINE(on_imu_and_send_gsr_work, on_imu_and_send_gsr_handler);


    3. I have no idea if the call succeed or not unfortunately.
    I'm working to find a reproducer, feel free to share if you have any idea.

Related