ARMmbed / mbed-os

Arm Mbed OS is a platform operating system designed for the internet of things
https://mbed.com
Other
4.67k stars 2.98k forks source link

BLE Notify loses Values at certain update frequency #13178

Closed pavitter-bluestone closed 4 years ago

pavitter-bluestone commented 4 years ago

Description of defect

When sending multiple values with notify to a client at around 20ms, that is scheduled with an event queue, the client doesnt receive a significant amount of the notifies. If more data is send, the time needed to not lose values increases. I noticed it with 4 characterisitics with each 20 bytes and 20 ms. On a 10 Second run, instead of the expected 500 Values i received around 170 Values on the arduino and around 200 Values on the nucleo. I can get the 500 Values, if it is a single charactersitic with 20 bytes.

There should be enough headroom for the bluetooth le stack to handle it. According to this webside, the limit with GATT should be around 226 kb/s. With 4 characteritics with each 20 bytes and 50 Updates the second its around 4000 Bytes/s.

I'm aware, that a BLE Notify is a write without acknowledgement, but i find the amount of lost notifys weird.

An increase of the event queue size did not help.

Target(s) affected by this defect ?

Arduino Nano 33 BLE using Arduino IDE NUCLEO_WB55RG using Mbed Studio

Toolchain(s) (name and version) displaying this defect ?

For Arduino, the Arduino nRF528x Boards (Mbed OS) Version 1.1.4 NUCLEO_WB55RG, that what Mbed Studio uses for this target.

What version of Mbed-os are you using (tag or sha) ?

I reproduced the issue with the following versions on the nucleo: mbed-os-5.15.4 mbed-os-5.14.2

The arduino used the following version: mbed-os-5.14.0

What version(s) of tools are you using. List all that apply (E.g. mbed-cli)

Mbed Studio: 1.0.0 for the Nucleo ArduinoIDE: 1.8.13 (Windows Store 1.8.39.0)

How is this defect reproduced ?

4 Charactersitics, that are around 20 Bytes each and updating them every 20 ms with the event queue. In the attachment the source file produces the error. If needed I can provide the complete project.

I hope it helps. main.zip

ciarmcom commented 4 years ago

Thank you for raising this detailed GitHub issue. I am now notifying our internal issue triagers. Internal Jira reference: https://jira.arm.com/browse/MBOTRIAGE-2737

hellowtisch commented 4 years ago

I experienced the same. Seems the BLE throughput for notifications is way slower than it could theoretically be. Using an ESP32 with Arduino-ble libs, I receive 4x the data with notifications, reading an IMU sensor, than with mbed os. I could not find the reason so far. Maybe someone can help?

0xc0170 commented 4 years ago

cc @ARMmbed/mbed-os-pan

pavitter-bluestone commented 4 years ago

Hey guys, any updates on this?

pan- commented 4 years ago

Few observations here, throughput will wildly vary depending on the connection parameter and BT controller performance. The connection interval the time at which the central and peripheral exchange data. For instance, if the connection interval is 50ms, every 50ms a connection event between the central and the peripheral happens.

During a connection event, a single GATT request/response is transferred or multiple not acknowledged GATT packets (notification or write without response). How many unacknowledged packets can be transferred is up to the BT controller but usually with iOS/Android devices it is between 4 and 6 GATT packets depending on the mobile phone used.

To avoid dropping notifications, I recommend to register a callback in GattServer::onDataSent to schedule the next packet to send. This callback is invoked when the previous GATT packet has been passed to the local Bluetooth controller. It should allow saturation of the local controller buffers while avoiding overflows. It is also not dependent on the connection parameters.

@pavitter-bluestone Could you post in this thread what are the connection parameters being used ?

pavitter-bluestone commented 4 years ago

@pan- I haven't touched the connection parameters, so it should be on default values. I only specified the Advertisment parameters, but that shouldn't effect the connection itself.

Few observations here, throughput will wildly vary depending on the connection parameter and BT controller performance. The connection interval the time at which the central and peripheral exchange data. For instance, if the connection interval is 50ms, every 50ms a connection event between the central and the peripheral happens. During a connection event, a single GATT request/response is transferred or multiple not acknowledged GATT packets (notification or write without response). How many unacknowledged packets can be transferred is up to the BT controller but usually with iOS/Android devices it is between 4 and 6 GATT packets depending on the mobile phone used.

So it can be a configuration problem on my side? I'm quite sure that my app can handle the update rate. I've build a prototype with an ESP32 and i got the value count I expected. On the otherhand the ESP and mbed os are quite different so they may not be comparable.

To avoid dropping notifications, I recommend to register a callback in GattServer::onDataSent to schedule the next packet to send. This callback is invoked when the previous GATT packet has been passed to the local Bluetooth controller. It should allow saturation of the local controller buffers while avoiding overflows. It is also not dependent on the connection parameters.

So i tried this, but when i call my data send function only when gets still called roughly 1000 Times and the devices only gets around 200. I seem to have even more updates, when calling the function instead of dispatching it via the event queue. What i noticed is, that the update count is always 1.

Hope it helps.

pan- commented 4 years ago

@pavitter-bluestone You cannot assume radio capabilities are the same between two different BLE controllers. It would be interesting to print out what the connection parameters are so we can establish a theoretical throughput.

So i tried this, but when i call my data send function only when gets still called roughly 1000 Times and the devices only gets around 200.

Can you share code like you did previously ? I've been doing that and it works well for me independently of the controller used or the device the peripheral is connected to.

What i noticed is, that the update count is always 1.

That's expected, the callback is called when the packet has been queued onto the controller.

pmancele commented 4 years ago

As @pan- said, connection parameters are very important. Depending on the software stack used you may not have the same results that's why you don't have the same performances (+ the fact that hardware controllers are not the same as explained).

Once connected, you can change those parameters with the Mbed API and if you lower it to the min : 7.5 ms, performance will be greatly increased ! (Some phones like iPhone doesn't support such low parameters so try other configuration and verify that the new parameters you asked from your embedded device are accepted.

pavitter-bluestone commented 4 years ago

Ok, i try to provide the connection parameters and code by tomorrow. Thanks for the useful information and for your help!

pavitter-bluestone commented 4 years ago

So I first tried again with sending the values when the On Data Send callback was called. This is the code I used to archive it: main_update_when_data_send_every_4_values.zip. I still had a difference between updates and what i recieved.

Then I checked for the connection parameters. I used the Gap Callback onConnectionComplete and printed the default values, that the microcontrollers used: Arduino(Mbed OS 5.14.0): 48 ms Connection Length Nucleo(Mbed OS 5.15.3): 48 ms Connection Length

I used then the ble.gap().updateConnectionParameters() function and set the min and max connection length to the min value,that the microcontroller supported. This fixed the issue for me. My code for this: main_fixed.zip

I clearly underestimated the importance of the connection parameter. Any hint where I can find such information in the documentation next time?

pan- commented 4 years ago

@pavitter-bluestone Glad it was solved, we haven't a detailed guide about connection parameters and the relation to throughput in our documentation however the following links are valuable resources:

pavitter-bluestone commented 4 years ago

Thanks for the links