Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
en:iot-open:practical:hardware:sut:stm32:iot_7 [2024/05/04 09:20] ktokarzen:iot-open:practical:hardware:sut:stm32:iot_7 [2024/05/04 11:03] (current) – [STM_IoT_7: BLE Communication with notifications] ktokarz
Line 1: Line 1:
-====== STM_IoT_7: BLE Communication with notifications =====+====== STM_IoT_7: BLE Communication with indications =====
 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. 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.
  
Line 17: Line 17:
  
 ==== Task to be implemented ==== ==== Task to be implemented ====
-**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 notifications of the characteristic.+**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 notification mechanism.+**Task 2.** Implement a client device, capable of subscribing to the characteristic and reading the exemplary data from a server with a indication mechanism.
  
 ==== Start ==== ==== Start ====
Line 25: Line 25:
  
 ==== Steps ==== ==== Steps ====
-We will pass through the lab in a few steps. We will add the second characteristic to the example from lab [[en:iot-open:practical:hardware:sut:stm32:IoT_6]]. We will configure this characteristic as notify/indicate capable. It allows us to establish a connection and, if successfully connected, enable the indication or notification 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 will pass through the lab in a few steps. We will add the second characteristic to the example from lab [[en:iot-open:practical:hardware:sut:stm32:IoT_6]]. 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.
  
 === Step 1 === === Step 1 ===
 We start with the program written during the laboratory [[en:iot-open:practical:hardware:sut:stm32:IoT_6]] 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. We start with the program written during the laboratory [[en:iot-open:practical:hardware:sut:stm32:IoT_6]] 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.
 <code c> <code c>
-#define NOTIFY_CHARACTERISTIC_UUID "6e9b7b28-ca96-4774-b056-8ec5b759fd86"+#define INDICATE_CHARACTERISTIC_UUID "6e9b7b28-ca96-4774-b056-8ec5b759fd86" 
 // BLE Characteristic - custom 128-bit UUID, read and notify enabled // BLE Characteristic - custom 128-bit UUID, read and notify enabled
-BLEByteCharacteristic pNotifyCharacteristic(NOTIFY_CHARACTERISTIC_UUID, BLERead | BLEWrite | BLENotify);+BLEByteCharacteristic pIndicateCharacteristic(INDICATE_CHARACTERISTIC_UUID, BLERead | BLEWrite | BLEIndicate);
 </code> </code>
  
Line 38: Line 39:
 <code> <code>
 // add the characteristic to the service // add the characteristic to the service
-pService.addCharacteristic(pNotifyCharacteristic);+pService.addCharacteristic(pIndicateCharacteristic);
  
 // set the initial value for the characteristic: // set the initial value for the characteristic:
-pNotifyCharacteristic.setValue(1);+pIndicateCharacteristic.setValue(1);
 </code> </code>
  
Line 47: Line 48:
  
 === Step 2 === === Step 2 ===
-At this step, we implement periodical data sending. We add the counter variable, an integer for holding the value incremented every loop pass.+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(); 
 <code c> <code c>
 int counter = 1; int counter = 1;
 +int delay_millis;
 </code> </code>
  
 In the main loop() we implement the incrementation of the counter and updating of the characteristic. In the main loop() we implement the incrementation of the counter and updating of the characteristic.
 <code c> <code c>
-pCharacteristic.setValue(counter); +void loop() { 
-counter++; +  // listen for BLE peripherals to connect: 
-delay(1000);+  BLE.central(); 
 +  if (millis() > delay_millis +1000){ 
 +    delay_millis = millis(); 
 +    pIndicateCharacteristic.setValue(counter); 
 +    counter++; 
 +  } 
 +}
 </code> </code>
  
Line 63: Line 72:
 {{ en:iot-open:practical:hardware:sut:esp32:ble_client.drawio.svg?500 |The client algorithm}} {{ en:iot-open:practical:hardware:sut:esp32:ble_client.drawio.svg?500 |The client algorithm}}
  
-=== Step === +=== Step === 
-While we have analysed the client's behaviour we can start implementation. Let's begin with the libraries needed. +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.
-Add the libraries to the platformio.ini.  +
-<code c> +
-lib_deps =  +
-  stm32duino/STM32duinoBLE @ 1.2.6 +
-  arduino-libraries/LiquidCrystal@^1.0.7 +
-</code>  +
-And import libraries into the cpp file. +
-<code c> +
-#include "Arduino.h" +
-#include "STM32duinoBLE.h" +
-#include "LiquidCrystal.h" +
-</code> +
-Next, we define the UUIDs for remote service and a characteristic. Notice they must match the ones defined in the server.+
 <code c> <code c>
-// The remote service we wish to connect to. +#define REMOTE_NOTIFY_CHARACTERISTIC_UUID "6e9b7b28-ca96-4774-b056-8ec5b759fd86"
-#define REMOTE_SERVICE_UUID "6e9b7b26-ca96-4774-b056-8ec5b759fd86" +
-// The characteristic of the remote service we are interested in. +
-#define REMOTE_CHARACTERISTIC_UUID "6e9b7b27-ca96-4774-b056-8ec5b759fd86"+
 </code> </code>
 <note> <note>
 We intentionally specified here the same UUIDs as in ESP32 BLE scenarios. If both platforms are physically available in the same laboratory, you can try to connect different hardware platforms with BLE. We intentionally specified here the same UUIDs as in ESP32 BLE scenarios. If both platforms are physically available in the same laboratory, you can try to connect different hardware platforms with BLE.
 </note> </note>
-Some global class objects and variables will be needed for our software. 
-<code c> 
-// Variables 
-HCISharedMemTransportClass HCISharedMemTransport; 
-BLELocalDevice BLEObj(&HCISharedMemTransport); 
-BLELocalDevice& BLE = BLEObj; 
-BLECharacteristic remoteCharacteristic; 
-</code> 
-We need to add and configure the LCD to be able to observe the results. 
-<code c> 
-// LCD class (Constructor uses STM port numbering) 
-const int rs = PC5, en = PB11, d4 = PB12, d5 = PB13, d6 = PB14, d7 = PB15; 
-LiquidCrystal lcd(rs, en, d4, d5, d6, d7); 
-</code> 
  
-In the setup() function we initialise LCD and Bluetooth and start scanning for the device having the service UUID we want to connect. +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. 
- +<note
-<code c> +At the time of writing this book the mechanism available for automatic update of the characteristic value was indication onlyNotifications couldn't be subscribed
-void setup() { +</note
-  // initialise LCD +We will present the full code of the function to subscribe and receive the indications. The function reads the characteristic value in some steps:
-  lcd.begin(16, 2); +
-  lcd.clear(); +
-   +
-  // initialise the BLE hardware +
-  BLE.begin(); +
- +
-  // start scanning for peripherals +
-  int ret = 1; +
-  do +
-  { +
-    ret = BLE.scanForUuid(REMOTE_SERVICE_UUID); +
-    if (ret == 0) +
-    { +
-      BLE.end(); +
-      BLE.begin(); +
-    } +
-  } while(ret == 0); +
-+
-</code> +
- +
-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. While the function returns, we restart scanning. +
- +
-<code c+
-void loop() { +
-  // check if a peripheral has been discovered +
-  BLEDevice peripheral = BLE.available(); +
- +
-  if (peripheral) { +
-    if (peripheral.localName() == "SUT STM BLE") { +
- +
-      // display remote name   +
-      lcd.setCursor(0,0); +
-      lcd.print(peripheral.localName()); +
- +
-      // stop scanning +
-      int ret = 1; +
-      do +
-      { +
-        ret = BLE.stopScan(); +
-        if (ret == 0) +
-        { +
-          BLE.end(); +
-          BLE.begin(); +
-        } +
-      } while(ret == 0); +
- +
-      // display the characteristic value +
-      display_characteristic(peripheral); +
-    } +
- +
-    // peripheral disconnected, start scanning again +
-    int ret = 1; +
-    do +
-    { +
-      ret = BLE.scanForUuid(REMOTE_SERVICE_UUID); +
-      if (ret == 0) +
-      { +
-        BLE.end(); +
-        BLE.begin(); +
-      } +
-    } while(ret == 0); +
-  } +
-} +
-</code+
- +
-The function reads the characteristic value in some steps:+
   - Connects to the remote device.   - Connects to the remote device.
   - Discovers attributes of the remote service.   - Discovers attributes of the remote service.
   - Retrieves the characteristic with specified UUID.   - Retrieves the characteristic with specified UUID.
   - Checks if the remote device is properly connected.   - Checks if the remote device is properly connected.
-  - Checks if the remote characteristic can be read+  - Checks if the remote characteristic can be subscribed. 
-  - Reads the text and displays it on LCD+  - Subscribes to the characteristic with indication mechanism. 
-  - Disconnects from the remote server.+  - Waits for the characteristic value update
 +  - Reads the value and displays it on LCD.
  
 <code c> <code c>
Line 186: Line 100:
   // connect to the peripheral   // connect to the peripheral
   if (peripheral.connect()) {   if (peripheral.connect()) {
-    +        
     // discover peripheral attributes     // discover peripheral attributes
     if (peripheral.discoverAttributes()) {     if (peripheral.discoverAttributes()) {
-          +              
       // retrieve the remote characteristic to read       // retrieve the remote characteristic to read
-      remoteCharacteristic = peripheral.characteristic(REMOTE_CHARACTERISTIC_UUID);+      remoteCharacteristic = peripheral.characteristic(REMOTE_NOTIFY_CHARACTERISTIC_UUID);
       if (remoteCharacteristic) {       if (remoteCharacteristic) {
-    +        // check if the characteristic can be read 
-      // if the peripheral is connected display the value +        if (remoteCharacteristic.canSubscribe()){ 
-        if (peripheral.connected()) { +          remoteCharacteristic.subscribe(); 
- +     
-          // check if the characteristic can be read +          // if the peripheral is connected display the value 
-          if (remoteCharacteristic.canRead()){ +          while (peripheral.connected()) { 
-            char char_text[16]; +             
-            remoteCharacteristic.readValue(char_text,16); +            // check if the value was updated 
-            int i=remoteCharacteristic.valueLength(); +            if (remoteCharacteristic.valueUpdated()) { 
-            lcd.setCursor(0,1); +   
-            lcd.write(char_text,i); +              // yesget the value, characteristic is 1 byte so use byte value 
-          } // if (remoteCharacteristic.canRead()) +              byte value 0; 
-        } // if (peripheral.connected())+              remoteCharacteristic.readValue(value); 
 +              lcd.setCursor(0,1); 
 +              lcd.print(value); 
 +              
 +            } // if (remoteCharacteristic.valueUpdated())  
 +          } // while (peripheral.connected()) 
 +        } // if (remoteCharacteristic.canSubscribe())
       } // if (remoteCharacteristic)       } // if (remoteCharacteristic)
       peripheral.disconnect();       peripheral.disconnect();
Line 216: Line 136:
 ==== Result validation ==== ==== Result validation ====
 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. 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.
 +
 ===== FAQ ===== ===== FAQ =====
- +**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 messageIt means that if the indication message remains unacknowledged, the peripheral device won'send another message for this characteristic.
-**What types of data can be sent with the characteristics?**: The BLE characteristics can send any value as a single byte or a sequence of bytes. BLE does not interpret the data in characteristic in any way. Interpretation lies on the side of the application. +
-\\ +
-**What if I need to read or write more data than a single text?**: It is possible to implement many services in one device and add many characteristics to one service. Theoretically, the maximum number of characteristics in one service is 512but the implementation and the memory available for the BLE library limit it. +
-\\ +
-**What is the maximum length of the data in the characteristics?**: The maximum length of the data in the characteristics in the BLE specification is 512 bytes. +
-\\ +
-**Can I send data between SoCs coming from different vendors?**: That's what the specifications of the network protocols are defined for. If devices are in their transmission range (i.e. in one physical laboratory site) you can implement a BLE server on one type of SoC and a BLE client on another.+
 \\ \\
 +**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.
  
 <WRAP noprint> <WRAP noprint>
en/iot-open/practical/hardware/sut/stm32/iot_7.1714814449.txt.gz · Last modified: 2024/05/04 09:20 by ktokarz
CC Attribution-Share Alike 4.0 International
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0