Differences

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

Link to this comparison view

Next revision
Previous revision
en:iot-open:practical:hardware:sut:stm32:iot_5 [2024/05/04 00:29] – created ktokarzen:iot-open:practical:hardware:sut:stm32:iot_5 [2024/05/04 08:41] (current) – [Steps] ktokarz
Line 6: Line 6:
 </note> </note>
 <note important> <note important>
-To do this scenario two stations are needed, one for the beacon and one for the client device.+To do this scenario two stations are needed, one for the beacon and one for the client device. At the time of writing this book the Bluetooth Low Energy library for STM32WB55 didn't support reading the remote advertising raw data. That's why we can implement the Eddystone beacon device and simple reader which confirms the presence of the device with Eddystone UUID. You can use the beacon receiver build with ESP32 if both SoCs are available in the same physical laboratory you work with.
 </note> </note>
 ===== Prerequisites ===== ===== Prerequisites =====
Line 21: Line 21:
 ==== Task to be implemented ==== ==== Task to be implemented ====
 **Task 1** Implement a program that operates as the BLE beacon which advertises itself with the link to the website. This can be done with the Eddystone beacon format. **Task 1** Implement a program that operates as the BLE beacon which advertises itself with the link to the website. This can be done with the Eddystone beacon format.
-**Task 2** Implement the receiver of advertising frames broadcasted by the beacon device capable of displaying information on the LCD screen.+**Task 2** Implement the receiver of advertising frames broadcasted by the beacon device capable of displaying simple information on the LCD screen.
  
 ==== Start ==== ==== Start ====
-We need to implement both parts of the software to be able to observe the results (steps 1-4). **The Task 1** we implement in steps 1 and 2. **The Task 2** we implement in steps and 4. At the end, we return to **Task 1** with step 5 +We need to implement both parts of the software to be able to observe the results (steps 1-3). **The Task 1** we implement in steps 1 and 2. **The Task 2** we implement in step 3.
 ==== Steps ==== ==== Steps ====
 We can go through the lab in a few steps. In the beginning, we will write a simple program which advertises the device with the default parameters set in the BLE library. As the payload of the advertising frame, we will use the Eddystone format to send the chosen URL address. We can go through the lab in a few steps. In the beginning, we will write a simple program which advertises the device with the default parameters set in the BLE library. As the payload of the advertising frame, we will use the Eddystone format to send the chosen URL address.
Line 147: Line 146:
 <code c> <code c>
 #include "Arduino.h" #include "Arduino.h"
-#include "BLEDevice.h" +#include "STM32duinoBLE.h" 
-#include "Adafruit_LiquidCrystal.h"+#include "LiquidCrystal.h"
 </code> </code>
 There can be a lot of BLE devices in the range of our receiver. We should find the one that we are interested in so we define the UUID of the Eddystone service. There can be a lot of BLE devices in the range of our receiver. We should find the one that we are interested in so we define the UUID of the Eddystone service.
 <code c> <code c>
-#define SERVICE_UUID "feaa"+#define REMOTE_SERVICE_UUID "feaa"
 </code> </code>
  
 Our program will use objects of two classes and some variables: Our program will use objects of two classes and some variables:
 <code c> <code c>
-static BLEAdvertisedDevice* myDevice// Class for remote BLE device +HCISharedMemTransportClass HCISharedMemTransport
-BLEScan* pBLEScan                   // Class for local scanner device +BLELocalDevice BLEObj(&HCISharedMemTransport)
- +BLELocalDevice& BLE = BLEObj;
-uint8_t * advPayload;     // Pointer to the payload of incoming adv packet +
-char eddystoneUrl[20];    // Buffer for text to display +
-String advName;           // Remote device name +
-int advLength;            // Length of payload of adv. packet +
-int advIndex;             // Index of the byte we proceed +
-int advEddystoneLength;   // Length of the Eddystone field +
-int i;+
 </code> </code>
  
 The received information will be displayed on the LCD, so we need to configure it (similar to the scenario EMB5) The received information will be displayed on the LCD, so we need to configure it (similar to the scenario EMB5)
 <code c> <code c>
-// LCD display pins and class declaration +// LCD class (Constructor uses STM port numbering) 
-#define LCD_RS 2 +const int rs = PC5, en = PB11, d4 = PB12, d5 = PB13, d6 = PB14, d7 = PB15; 
-#define LCD_ENABLE 1 +LiquidCrystal lcd(rsend4d5d6d7);
-#define LCD_D4 39 +
-#define LCD_D5 40 +
-#define LCD_D6 41 +
-#define LCD_D7 42 +
-static Adafruit_LiquidCrystal lcd(LCD_RSLCD_ENABLELCD_D4LCD_D5LCD_D6LCD_D7);+
 </code> </code>
  
Line 184: Line 171:
 <code c> <code c>
 void setup() { void setup() {
-  // Initialise LCD 
   lcd.begin(16, 2);   lcd.begin(16, 2);
-  delay(1000); +  lcd.clear(); 
-  lcd.print("BLE CLient");+  lcd.setCursor(0,0); 
 +  lcd.print("Searching for"); 
 +  lcd.setCursor(0,1); 
 +  lcd.print("Beacon device");
      
-  // Initialise the Bluetooth +  // initialize the BLE hardware 
-  BLEDevice::init(""); +  BLE.begin(); 
-   + 
-  // Retrieve the pointer to the scan module +  // start first scanning for peripherals 
-  pBLEScan BLEDevice::getScan()+  int ret 1
-   +  do 
-  // Register callback for incoming advertising +  { 
-  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks()); +    ret = BLE.scanForUuid(REMOTE_SERVICE_UUID); 
-   +    if (ret == 0
-  // Start scan parameters with active scan mode +    { 
-  pBLEScan->setInterval(1349); +      BLE.end(); 
-  pBLEScan->setWindow(449); +      BLE.begin(); 
-  pBLEScan->setActiveScan(true); +    } 
-   +  } while(ret == 0);
-  // Start the scan for 5 seconds +
-  pBLEScan->start(5, false);+
 } }
 </code> </code>
  
-In the loop function, we restart scanning every 5 seconds with 1 second delay.+In the loop function, we wait for the scanned device and display info if the Eddystone device is present.
 <note> <note>
-The start function of the BLEScan class is blockingso it stops program execution for the time of scanning.+Using STM32WB55 SoC you can't see the detailed content of Eddystone advertising frame. You can use either SoC (like ESP32)if available in the same physical laboratory.
 </note> </note>
 <code c> <code c>
 void loop() { void loop() {
-  delay(1000); +  // check if a peripheral has been discovered 
-  // Repeat scanning +  BLEDevice peripheral = BLE.available(); 
-  pBLEScan->start(5,false); + 
- +  if (peripheral) { 
-</code> +    lcd.clear(); 
-=== Step 4 === +    if (peripheral.localName() == "STM32 Beacon") {
-The callback function checks if the device which sent the advertising frame implements the Eddystone service. This is how we filter out all other BLE devices available in the range+
-<note> +
-if we have more than one Eddystone device nearby we would have to implement additional filtering. +
-</note>+
  
-After a successful search for a device with Eddystone service, we can display its name and proceed with displaying the content of the Eddystone field. Because the code is quite complex we present the whole callback function below. Notice that we decode chosen compressed fields only (prefix = 0x00, suffice = 0x07). You would need to decode other values for compatibility with the Eddystone format. +      // display remote name  
-<code c> +
-class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks { +
-  void onResult(BLEAdvertisedDevice advertisedDevice) { +
-    // We have found a device, let's see if it contains the service we are looking for. +
-    if (advertisedDevice.haveServiceUUID() && advertisedDevice.isAdvertisingService(BLEUUID(SERVICE_UUID))) { +
-     +
-      // Display the name of the remote device+
       lcd.setCursor(0,0);       lcd.setCursor(0,0);
-      lcd.print(advertisedDevice.getName().c_str()); +      lcd.print(peripheral.localName()); 
-     +    } 
-      // Get the length of the payload and the pointer to it +    if (peripheral.advertisedServiceUuid() == REMOTE_SERVICE_UUID){ 
-      advLength = advertisedDevice.getPayloadLength(); +      lcd.setCursor(0,1); 
-      advPayload = advertisedDevice.getPayload()+      lcd.print(REMOTE_SERVICE_UUID); 
-     +    }
-      // Search for the Eddystone field (field ID 0x16) +
-      advIndex = 0; +
-      while (advIndex<=advLength+
-      +
-        if (advPayload[advIndex+1]==0x16) { +
-         +
-          // Eddystone field found, get the length of it +
-          advEddystoneLength = advPayload[advIndex]; +
-     +
-          // Display the Eddystone field +
-          lcd.setCursor(0,1); +
- +
-          // Prefix decoding +
-          if (advPayload[advIndex+6]==0x00) { +
-            lcd.print("http://www."); +
-          } +
- +
-          // ULR name +
-          for(i=0; i<advEddystoneLength-7; i++){ +
-            eddystoneUrl[i]=(char)advPayload[advIndex+7+i]; +
-          } +
-          eddystoneUrl[i]=(char)NULL; // Terminate the string +
-          lcd.print(eddystoneUrl); +
- +
-          // Suffix decoding +
-          if (advPayload[advIndex+advEddystoneLength]==0x07){ +
-            lcd.print(".com"); +
-          } +
-        } // Eddystone field found +
-        advIndex ++; +
-      } // Search for Eddystone +
-    } // Found our server +
-  } // onResult +
-}; // MyAdvertisedDeviceCallbacks +
-</code> +
-Additional filtering of remote devices can be done with their names. We can add in the "MyAdvertisedDeviceCallbacks()" function the comparison of the remote device name with the constant string. It should be done if the Eddystone service was found. +
-<code c> +
-String name; +
-name = advertisedDevice.getName().c_str(); +
-if (name.equals("SUT BLE device")) +
-  { +
-    // here the internal code of the MyAdvertisedDeviceCallbacks()+
   }   }
-</code> +}
- +
-=== Step 5 === +
-Let's return to the beacon device. The advertisement frame is quite short so normally additional information is sent upon Scan Request with Scan Response frame. It can contain the device name which can differ from the name we specified in step 1 (in the case of normal operation we can read it as the value of the Generic Access Service). To specify different names in advertising frame and service characteristics we can use the setScanResponseData() function from BLEAdvertising class. +
-<code c> +
-oScanResponseData.setName("SUT Beacon"); +
-pAdvertising->setScanResponseData(oScanResponseData);+
 </code> </code>
  
 ==== Result validation ==== ==== Result validation ====
-After the implementation of steps 1-4, you should be able to see the name of the beacon device in the first line of LCD and the URL from the Eddystone field in the second line of LCD. Implementation of step 5 should result in a change of the device name. +After the implementation of steps 1-3, you should be able to see the name of the beacon device on the first line of LCD and the Eddystone UUID on the second line of LCD. 
 ==== Further work ==== ==== Further work ====
 You can try to implement the beacon device compatible with iBeacon. The description can be found on the website ((https://www.silabs.com/whitepapers/developing-beacons-with-bluetooth-low-energy-technology)). You can try to implement the beacon device compatible with iBeacon. The description can be found on the website ((https://www.silabs.com/whitepapers/developing-beacons-with-bluetooth-low-energy-technology)).
en/iot-open/practical/hardware/sut/stm32/iot_5.1714782590.txt.gz · Last modified: 2024/05/04 00:29 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