bluetooth-lowenergybluetooth-gatt

Does the BLE protocol guarantee write-ordering across multiple characteristics in a service?


If a BLE service contains multiple notification characteristics that a GATT client has expressed interest in, does the BLE protocol make any strong guarantees about the order the GATT clients receive the updated values? Separately, are there any protocol-level requirements about the order in which the GATT client delivers the newly-received data up to the application in?

For example: Say that the application changes the values of two separate characteristics in the GATT server in rapid succession between connection events during the "quiet" period. During the next connection event, assume that there is enough time and bandwidth for the GATT server to fully transmit both updated characteristic values to the GATT client.

Does the BLE protocol require that the GATT server transmit the newly-changed values in the order that the application changed them?

Additionally, does the BLE protocol require that the GATT client preserve the order of these newly-changed values when delivering them up to the application?

The BLE stacks I'm reasoning about all support Bluetooth 5.0, but it would also be nice to know if any of this has changed over previous versions. Any specific citations from the protocol standard itself would be very helpful!


Solution

  • Separately, are there any protocol-level requirements about the order in which the GATT client delivers the newly-received data up to the application in?

    Does the BLE protocol require that the GATT server transmit the newly-changed values in the order that the application changed them?

    Additionally, does the BLE protocol require that the GATT client preserve the order of these newly-changed values when delivering them up to the application?

    The answer to all these questions above are perhaps surprisingly "Not applicable". The whole concept of a software library/sdk/api implementing the "core" part of GATT written by one person and then having a separate application written by another person utilising this library/sdk/api simply does not exist when you read the standard. The Bluetooth standard is just a protocol standard, i.e. dictates the requirements how two devices communicate with each other, not how an application is structured and implemented internally. Please see the protocol stack diagram from the GATT chapter, section 2.1 in the Bluetooth core specification (currently version 5.4):

    GATT PROTOCOL STACK

    As you can see, GATT is the "application" profile and ATT is the protocol your application speaks. If you have a software library that internally manages queues, dispatches commands/notifications to the correct thread etc. to make your job easier, then that is not part of the Bluetooth standard and any dumb design mistake in this library limiting the use of the protocol/profile for the end application developer should rather be seen as a "missing feature" than a protocol breach.

    At a few occasions, the standard however suggests some allowed implementation details. In the ATT chapter, you can e.g. read "On an Unenhanced ATT bearer, notifications that are received but cannot be processed due to buffer overflows shall be discarded. Therefore, those PDUs must be considered to be unreliable".

    If a BLE service contains multiple notification characteristics that a GATT client has expressed interest in, does the BLE protocol make any strong guarantees about the order the GATT clients receive the updated values?

    To answer this question, I will make the same assumptions as the standard does, i.e. that the application has direct access to send GATT notifications as ATT packets whenever it wants to the lower layer (L2CAP) and that the GATT client directly receives ATT notifications in the same order they are received from the lower layer (L2CAP).

    Neither the ATT protocol nor the GATT profile standard mentions anything about ordered delivery when it comes to notifications. Instead, when reasoning about ordered delivery, the underlying protocol is typically what is taken into account.

    In Bluetooth 4.0-5.1, only the "Unenhanced ATT bearer" existed, which is a fixed L2CAP channel that delivers data in-order. Thus, you can at least on the protocol level expect ordered delivery. The HID profile for example, more or less assumes ordered delivery. Otherwise keystrokes might end up in the incorrect order.

    In Bluetooth 5.2, "Enhanced ATT bearers" were introduced, to allow more than one concurrent ATT transaction (one per communication channel), which were meant to speed up situations when multiple "apps" running on the same device talks with the same remote device. Note that only one Read Request or a Write Request could otherwise be performed at a time and the next one must be sent when the response from the previous has been received. If both devices support this feature and you have opened multiple ATT bearers to the same device, you cannot assume any specific order that notifications will be delivered to the other device if they are sent over separate ATT bearers since they have their own flow control. So if you need ordered delivery, simply use the same ATT bearer for these notifications.

    In practice, all software libraries implementing GATT I am aware of never reorders notifications belonging to the same characteristic. On Android for example, the Binder mechanism is used as IPC layer between the Bluetooth daemon and each application. Here, the callback that is invoked when a notification is received for a particular BluetoothGatt object will not be called again until a previous method invocation for the same BluetoothGatt object has returned.

    On Windows however, last time I checked, every time you start listening to notifications, a new thread is spinned up which your event handler will run on whenever a notification is received. Since you can only specify to listen to one characteristic when listening to notifications, you need to set up two separate listeners if you have two characteristics and hence two threads will be started, each handling each characteristic. And with two threads it is impossible to synchronise the order of delivered notifications since both threads can run concurrently on two different CPU cores. This is one of those "dumb" design mistakes in my opinion which limits the use.

    So, as a suggestion, if you need guarantees about the notifications are delivered and processed in the same order they are issued, use one single characteristic and you should usually be fine.