This scenario presents how to extend the Bluetooth Low Energy server and client devices with a notification or indication mechanism for sending data automatically. If enabled, notifications or indications are sent at any time while the data in the server is updated. A difference between them is that a notification is an unacknowledged message while an indication is an acknowledged message. While one of them is enabled by the client, the server decides on the time of the message sent.
It is necessary to understand the principles of the Bluetooth Low Energy protocol with concepts of services, characteristics and descriptors. We will use in this scenario the knowledge of the advertising process so making the STM_IoT_6: BLE Communication with characteristics exercise is recommended.
This scenario is intended to be implemented using two BLE laboratory nodes. One of them is a server, while the second is a client. Here we will present the extension of the scenario implemented in STM_IoT_6: BLE Communication with characteristics
Task 1. Implement a program that operates as the BLE server which advertises itself and allows us to connect to. We should be able to subscribe to indications of the characteristic.
Task 2. Implement a client device, capable of subscribing to the characteristic and reading the exemplary data from a server with a indication mechanism.
It is advised to use the server and client programs from STM_IoT_6: BLE Communication with characteristics as the starting point.
We will pass through the lab in a few steps. We will add the second characteristic to the example from lab STM_IoT_6: BLE Communication with characteristics. We will configure this characteristic as capable of transmitting data with indication. It allows us to establish a connection and, if successfully connected, enable the indication feature. With this feature enabled, the peripheral device initiates data transmission. It can be used for periodic measurement reading or updating information on value change.
We start with the program written during the laboratory STM_IoT_6: BLE Communication with characteristics by adding another characteristic to the service and variable required to hold the pointer to the characteristic class. We need to define the UUID for this characteristic.
#define INDICATE_CHARACTERISTIC_UUID "6e9b7b28-ca96-4774-b056-8ec5b759fd86" // BLE Characteristic - custom 128-bit UUID, read and notify enabled BLEByteCharacteristic pIndicateCharacteristic(INDICATE_CHARACTERISTIC_UUID, BLERead | BLEWrite | BLEIndicate);
In the setup() function we add a new characteristic to the service and set its initial value.
// add the characteristic to the service pService.addCharacteristic(pIndicateCharacteristic); // set the initial value for the characteristic: pIndicateCharacteristic.setValue(1);
After these modifications, it would be possible to observe an additional characteristic in the service with the possibility of reading, writing, and enabling notifications.
At this step, we implement periodical data sending. We add the counter variable, an integer for holding the value incremented every loop pass. We will increment this counter with use of millis() function to do not block the loop() with delay();
int counter = 1; int delay_millis;
In the main loop() we implement the incrementation of the counter and updating of the characteristic.
void loop() { // listen for BLE peripherals to connect: BLE.central(); if (millis() > delay_millis +1000){ delay_millis = millis(); pIndicateCharacteristic.setValue(counter); counter++; } }
In this step, we will analyse the behaviour of the client. The client software is much more complex than the server. It is because the server, called also the central device, in many circumstances is a more powerful device than the peripheral. Some parts of the software are implemented as callback functions because they handle reactions on the data coming asynchronously from the server. The diagram presents the algorithm of the client and data coming from the server.
While we have analysed the client's behaviour we can start implementation. Let's begin with modifying the remote characteristic for receiving notifications. Notice its UUID they must match the one defined in the server.
#define REMOTE_NOTIFY_CHARACTERISTIC_UUID "6e9b7b28-ca96-4774-b056-8ec5b759fd86"
In a loop() function we check if a peripheral with UUID we are interested in was discovered. If so we check its name. If the remote device's name is as we expect we print its name, stop scanning, and call the function which reads and displays the value of the characteristic. This function uses the polling method of reading the updated characteristic value. While the function returns, we restart scanning.
We will present the full code of the function to subscribe and receive the indications. The function reads the characteristic value in some steps:
void display_characteristic(BLEDevice peripheral) { // connect to the peripheral if (peripheral.connect()) { // discover peripheral attributes if (peripheral.discoverAttributes()) { // retrieve the remote characteristic to read remoteCharacteristic = peripheral.characteristic(REMOTE_NOTIFY_CHARACTERISTIC_UUID); if (remoteCharacteristic) { // check if the characteristic can be read if (remoteCharacteristic.canSubscribe()){ remoteCharacteristic.subscribe(); // if the peripheral is connected display the value while (peripheral.connected()) { // check if the value was updated if (remoteCharacteristic.valueUpdated()) { // yes, get the value, characteristic is 1 byte so use byte value byte value = 0; remoteCharacteristic.readValue(value); lcd.setCursor(0,1); lcd.print(value); } // if (remoteCharacteristic.valueUpdated()) } // while (peripheral.connected()) } // if (remoteCharacteristic.canSubscribe()) } // if (remoteCharacteristic) peripheral.disconnect(); } // if (peripheral.discoverAttributes()) } // if (peripheral.connect()) }
You should be able to read the name of the remote device in the first line of the LCD. After establishing the connection, the characteristic value should appear on the display's second line.
What is the difference between notification and indication?: As it was mentioned in the beginning the notification is an unacknowledged message while an indication is an acknowledged message. It means that if the indication message remains unacknowledged, the peripheral device won't send another message for this characteristic.
Is the notification/indication mechanism similar to interrupts?: You are right. They work in a similar manner as interrupts in the microprocessor. They allow sending the data asynchronously, and the peripheral decides about the time of the message sent like the peripheral decides on the time of signalling interrupt. Data transmission when the central device sends the packet with a characteristic read command is similar to the polling method used in microprocessors.