Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

BLE indications

As I understand, BLE indications are a reliable communications method. How do you know if your indications was not communicated. I am writing code for the peripheral/server and currently when I send a notifications, I get a manual response from the central. I read that if I use indications, the acknowledges take place in the L2CAP layer automatically and communications is therefore faster, but how does my embedded controller know the Bluetooth module was not successful at getting the packet across the link? We are using the Microchip RN4030 Bluetooth module.

like image 215
user2532067 Avatar asked Oct 12 '25 17:10

user2532067


1 Answers

Let's make things clear.

The BLE stack looks roughly like the following. The stack has these layers in this order:

  • Link Layer
  • HCI (if controller and host are separated)
  • L2CAP
  • ATT
  • GATT
  • Application

The Link Layer is a reliable protocol in the sense that all packets are protected by a CRC and every packet is acknowledged by the receiving device. If a packet is not acknowledged, it is resent until an acknowledge is received. There can also only be one outstanding packet, which means no reordering of packets are possible. Acknowledges are normally not being presented to upper layers.

The HCI layer is the communication protocol between the controller and the host.

The L2CAP layer does almost nothing if you use the standard MTU size of 23. It has a length header and a type code ("channel") which indicates what type of packet is being sent (usually ATT).

On the ATT level, there are two types of packets that are sent from the server that are not sent as a response to a client request. Those are notifications and indications. Sending one notification or indication has the same "performance" since the type is just a tag of a packet that's sent over the lower layers. The differences are listed below:

Indications:

  • When an indication packet is sent to the client, the client must acknowledge the packet by sending a confirmation packet when it has received the indication packet. Even if the indication packet is invalid, a confirmation shall be sent back.
  • Upper layers are not involved sending back the confirmation.
  • The server may not send a new indication until it has received a confirmation from the previous one.
  • The only time you won't receive a confirmation after an indication is if the link is dropped (you should then get a disconnected event), or there is some bug in some of the BLE stacks.
  • After the app has sent an indication, most BLE stacks confirm to the server app that a confirmation has been received from the client as that the indication operation has completed.

Notifications:

  • No ATT layer acknowledges are sent.
  • "Commands and notifications that are received but cannot be processed, due to buffer overflows or other reasons, shall be discarded. Therefore, those PDUs must be considered to be unreliable." However I have never noticed an implementation actually following this rule, i.e. all notifications are delivered to the application. Or I've never hit the max buffer size.

The GATT layer is mostly a definition of how the attribute protocol should be used and defines a DB structure of characteristics.

Implications

According to my opinion, there are several flaws or issues with the BLE standard. There are two things that might make indications useless and unreliable in practice:

  • There are no way to send back an error response instead of a confirmation.
  • The fact that it is typically the ATT layer that sends back the confirmation directly when it has received the indication, and not the app when it has successfully handled the indication.

This means that if for example, some bug or other issue causing that the BLE stack couldn't send the indication to the app, or your app crashed, or your app found your value to be invalid, there is no way your peripheral can aware of that. Since it got the confirmation it thinks everything is fine.

I can't understand why they defined indications this way. Since the app doesn't send the confirmation but a lower layer does, there seems to be no point at all in having an ATT layer acknowledge instead of just using the Link Layer acknowledge. Both are just acknowledges that the packet has been received halfway of its destination.

If we draw a parallel to a HTTP POST and internet, we could consider the Link Layer acknowledge as when the network card of the destination receives the request and the ATT confirmation as a confirmation that the TCP stack received the packet. You have no way of knowing that your web server software actually did receive your request, and it processed it with success.

The fact that notifications are allowed to be dropped by the receiver is also bad. Normally notifications are used if the peripheral wants to stream a lot of data to the central and then you don't want dropped packets. They should have designed the flow control so that the Link Layer stopped acknowledge incoming packets instead until the app are ready to process the next notifications. This is even already implemented at the LL + HCI + Host layers.

Windows

One interesting thing about at least the Windows BLE stack is, if it receives indications faster than the app processes them it starts to drop the indications as well, even though only notifications should be allowed to be dropped due to "buffer overflows or other reasons". It buffers at most 512 indications in my tests.

That said

Just use notifications and if you want some kind of confirmation, let the client send a write packet when it has received your data and successed processing it.

Edit

With some Bluetooth stacks, it is possible that it is the app's responsibility to send the confirmation once it has processed the indication. If the app layer chooses to not send a confirmation within 30 seconds, it will lead to teardown of the ATT connection. Note that the Bluetooth standard does not make any distiction here regarding the ATT/GATT/App layer. It just says the "client" shall respond with a confirmation once it has received the indication, regardless if the value is valid or not.