Bluetooth Low Energy: Programul Server
Bluetooth Low Energy: Programul Server
GATT
GATT înseamnă Generic Attributes și definește o structură de date ierarhică pe care o văd dispozitivele conectate.
Această structură se personalizează în aplicațiile client/server pentru a permite transferul de date.
În cadrul GATT, așa cum se vede pe figura de mai jos, elementelor structurii le corespund UUID-uri (Universally
Unique Identifier) care sînt numere unice de 128 biți (16 octeți). Se pot folosi UUID-uri random dar există multe
UUID-uri predefinite pentru profile și servicii uzuale folosite de diferite device-uri BLE: valoarea tensiunii arteriale, a
tensiunii bateriei, a datei și orei curente etc etc etc.
În general, schimbul de date în BLE se face prin definirea în GATT a unor „caracteristici” care în esență sînt variabilele
de program folosite pentru transmiterea/recepția datelor. Caracteristicile au o „valoare”, au „proprietăți” care
descriu modul de interacțiune, de exemplu „Read”, „Write”, „Notify” etc, și pot avea opțional un „descriptor” care să
definească în mod suplimentar metadatele folosite în cadrul caracteristicii. De exemplu txValue, rxValue sînt
variabilele folosite în programele noastre: txValue este trimis de la server către client, rxValue este trimis de la client
către server (deci este recepționat pe server; numele rx, tx sînt dpdv al serverului). Proprietatea de „Notify” nu este
folosită în acest exemplu.
În continuare aveți un exemplu de pereche client-server minimală care ilustrează folosirea unei caracteristici atît pt
scriere cît și citire.
Programul server:
/*
Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-
snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleNotify.cpp
Ported to Arduino ESP32 by Evandro Copercini
updated by chegewara and MoThunderz
*/
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
String txValue;
void setup() {
Serial.begin(115200);
// Start advertising
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
pAdvertising->addServiceUUID(SERVICE_UUID);
pAdvertising->setScanResponse(false);
pAdvertising->setMinPreferred(0x0); // set value to 0x00 to not advertise this
parameter
BLEDevice::startAdvertising();
Serial.println("Waiting a client connection...");
}
case SM_INIT:
txValue = String(1);
// Here the value is written to the Client using setValue();
pCharacteristic_2->setValue(txValue.c_str());
Serial.println("Characteristic (setValue): " + txValue);
SM_state = SM_SEND;
delay(1000);
break;
case SM_SEND:
// pCharacteristic_2 is a std::string (NOT a String). In the code below we
read the current value
// write this to the Serial interface and send a different value back to the
Client
// Here the current value is read using getValue()
std::string rxValue = pCharacteristic_2->getValue();
Serial.print("Characteristic (getValue): ");
Programul client:
/**
* A BLE client example that is rich in capabilities.
* There is a lot new capabilities implemented.
* author unknown
* updated by chegewara and MoThunderz
*/
#include "BLEDevice.h"
//#include "BLEScan.h"
// Define UUIDs:
static BLEUUID serviceUUID("6E400001-B5A3-F393-E0A9-E50E24DCCA9E");
static BLEUUID charUUID_2("6E400003-B5A3-F393-E0A9-E50E24DCCA9E");
pClient->setClientCallbacks(new MyClientCallback());
// Obtain a reference to the service we are after in the remote BLE server.
BLERemoteService* pRemoteService = pClient->getService(serviceUUID);
if (pRemoteService == nullptr) {
Serial.print("Failed to find our service UUID: ");
Serial.println(serviceUUID.toString().c_str());
pClient->disconnect();
return false;
}
Serial.println(" - Found our service");
connected = true;
pRemoteChar_2 = pRemoteService->getCharacteristic(charUUID_2);
if(connectCharacteristic(pRemoteService, pRemoteChar_2) == false) {
connected = false;
pClient-> disconnect();
Serial.println("Characteristic UUID not found");
return false;
}
return true;
}
if(l_BLERemoteChar->canNotify())
l_BLERemoteChar->registerForNotify(notifyCallback);
return true;
}
// Scan for BLE servers and find the first one that advertises the service we are
looking for.
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
//Called for each advertising BLE server.
void onResult(BLEAdvertisedDevice advertisedDevice) {
Serial.print("BLE Advertised Device found: ");
Serial.println(advertisedDevice.toString().c_str());
// We have found a device, let us now see if it contains the service we are
looking for.
if (advertisedDevice.haveServiceUUID() &&
advertisedDevice.isAdvertisingService(serviceUUID)) {
BLEDevice::getScan()->stop();
myDevice = new BLEAdvertisedDevice(advertisedDevice);
doConnect = true;
doScan = true;
void setup() {
Serial.begin(115200);
Serial.println("Starting Arduino BLE Client application...");
BLEDevice::init("");
// Retrieve a Scanner and set the callback we want to use to be informed when we
// have detected a new device. Specify that we want active scanning and start the
// scan to run for 5 seconds.
BLEScan* pBLEScan = BLEDevice::getScan();
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
pBLEScan->setInterval(1349);
pBLEScan->setWindow(449);
pBLEScan->setActiveScan(true);
pBLEScan->start(5, false);
} // End of setup.
void loop() {
// If the flag "doConnect" is true then we have scanned for and found the desired
// BLE Server with which we wish to connect. Now we connect to it. Once we are
// connected we set the connected flag to be true.
if (doConnect == true) {
if (connectToServer()) {
Serial.println("We are now connected to the BLE Server.");
} else {
Serial.println("We have failed to connect to the server");
}
doConnect = false;
}
if (connected) {
std::string rxValue = pRemoteChar_2->readValue();
Serial.print("Characteristic (readValue): ");
Serial.println(rxValue.c_str());
}else if(doScan){
BLEDevice::getScan()->start(0); // this is just example to start scan after
disconnect, most likely there is better way to do it in arduino
}
// In this example "delay" is used to delay with one second. This is of course a
very basic
// implementation to keep things simple. I recommend to use millis() for any
production code
delay(1000);
}
Liniile marcate cu galben sînt cele în care are loc transmisia și recepția propriu-zisă.
Pentru PIA Hunt, baliza este serverul, deci programul vostru trebuie să aibă funcțiile unui client.