How to send data via a characteristic as fast as possible / detect lost information
Discussed in https://github.com/h2zero/NimBLE-Arduino/discussions/707
Originally posted by Tirus42 August 11, 2024 Hello together,
I am working on a BLE remote control interface with a flexible web interface (web bluetooth) to allow to control actions on the ESP via a browser. See https://github.com/Tirus42/Arduino-BLE-Remote for details, the send operation is located there: https://github.com/Tirus42/Arduino-BLE-Remote/blob/6832e6bfcbdc5fab2857ab38abc1bb5b38dc6e3b/arduino-library/src/BLELedController.cpp#L489.
For this, i send some data (in my example about 1,5kb) to the connected client by using characteristic.notify() inside a loop with 128 byte chunks.
This works, as long as the whole data block is not too large, but for example 5kb of data, there are many packets lost. Also i got problems, when multiple clients are connected.
I assume that the BLE stack contains a send queue which will be overloaded by to many packets. Is there a way to detect this and to handle it properly?
I saw in a example (https://github.com/h2zero/NimBLE-Arduino/blob/master/examples/Refactored_original_examples/BLE_server_multiconnect/BLE_server_multiconnect.ino Line 139) that a simple delay is used. But this seems not to be a reliable solution.
Maybe this is already implemented.
User code may implement a NimBLECharacteristicCallbacks::onRead() callback (on the proper characteristic) to perform flow control using semaphores. Before doing so, user code must also keep track of how many clients are actually using the characteristic thanks to the onSubscribe() callback. You can have many different services in a GATT server, but clients are not forced to use all of them. As a result, the count of connected clients is not reliable for this purpose.
https://github.com/puzrin/reflow_micro/blob/master/firmware/src/lib/ble_chunker.hpp
On upper level, the optimal approach is to use sparse confirmations and message/chunk incremental counters to detect gaps. Sending data to server can be done with existing Write with/without confirm. The reverse direction requires combination of Notify + Indicate.
For easy implementation of fast transfers from server to client 2 things are necessary:
- Possibility to send notify/indicate individually to client (now only broadcasts available for arduino).
- Callbacks like onRead/onWrite, for notify/indicate, to add next data chunk.
It's possible to implement such approach via existing broadcasts, but code can be ugly.