0% found this document useful (0 votes)
36 views10 pages

Bluetooth Low Energy: Programul Server

The document explains Bluetooth Low Energy (BLE) and the Generic Attributes (GATT) structure used for data transfer between connected devices. It details how GATT defines characteristics with unique UUIDs and properties for reading, writing, and notifying data. Additionally, it provides example server and client code for implementing BLE communication, demonstrating the exchange of values between devices.

Uploaded by

Stefan Miron
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
36 views10 pages

Bluetooth Low Energy: Programul Server

The document explains Bluetooth Low Energy (BLE) and the Generic Attributes (GATT) structure used for data transfer between connected devices. It details how GATT defines characteristics with unique UUIDs and properties for reading, writing, and notifying data. Additionally, it provides example server and client code for implementing BLE communication, demonstrating the exchange of values between devices.

Uploaded by

Stefan Miron
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 10

Bluetooth Low Energy

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>

// Initialize all pointers


BLEServer* pServer = NULL; // Pointer to the server
BLECharacteristic* pCharacteristic_2 = NULL; // Pointer to Characteristic 2

BLE2902 *pBLE2902_2; // Pointer to BLE2902 of


Characteristic 2

// Some variables to keep track on device connected


bool deviceConnected = false;
bool oldDeviceConnected = false;

#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"


#define CHARACTERISTIC_UUID_2 "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"

uint8_t SM_state; // state machine


#define SM_INIT 0
#define SM_SEND 1

String txValue;

// Callback function that is called whenever a client is connected or disconnected


class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
deviceConnected = true;
};

void onDisconnect(BLEServer* pServer) {


deviceConnected = false;
}
};

void setup() {
Serial.begin(115200);

// Create the BLE Device


BLEDevice::init("PHNT1");
// Create the BLE Server
pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());

// Create the BLE Service


BLEService *pService = pServer->createService(SERVICE_UUID);

// Create a BLE Characteristic


pCharacteristic_2 = pService->createCharacteristic(
CHARACTERISTIC_UUID_2,
BLECharacteristic::PROPERTY_READ |
BLECharacteristic::PROPERTY_WRITE |
BLECharacteristic::PROPERTY_NOTIFY
);

// Create a BLE Descriptor


pBLE2902_2 = new BLE2902();
pBLE2902_2->setNotifications(true);
pCharacteristic_2->addDescriptor(pBLE2902_2);

// Start the service


pService->start();

// 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...");
}

/******************* MAIN LOOP *******************/


void loop() {
if (deviceConnected) {
switch(SM_state) {

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): ");

Serial.println(rxValue.c_str()); // c.str returns a standard C character


array string

txValue = String(std::stoi(rxValue) +1 ); // stoi is string to integer


// Here the value is written to the Client using setValue();
pCharacteristic_2->setValue(txValue.c_str());
Serial.println("Characteristic (setValue): " + txValue);
delay(1000);
break;
} //switch
} //if
// The code below keeps the connection status up to date:
// Disconnecting
if (!deviceConnected && oldDeviceConnected) {
delay(500); // give the bluetooth stack the chance to get things ready
pServer->startAdvertising(); // restart advertising
Serial.println("Start advertising");
oldDeviceConnected = deviceConnected;
}
// Connecting
if (deviceConnected && !oldDeviceConnected) {
// do stuff here on connecting
oldDeviceConnected = deviceConnected;
}
}

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");

// Some variables to keep track on device connected


static boolean doConnect = false;
static boolean connected = false;
static boolean doScan = false;

// Define pointer for the BLE connection


static BLEAdvertisedDevice* myDevice;
BLERemoteCharacteristic* pRemoteChar_2;
// Callback function for Notify function
static void notifyCallback(BLERemoteCharacteristic* pBLERemoteCharacteristic,
uint8_t* pData,
size_t length,
bool isNotify) {
} // empty

// Callback function that is called whenever a client is connected or disconnected


class MyClientCallback : public BLEClientCallbacks {
void onConnect(BLEClient* pclient) {
}

void onDisconnect(BLEClient* pclient) {


connected = false;
Serial.println("onDisconnect");
}
};

// Function that is run whenever the server is connected


bool connectToServer() {
Serial.print("Forming a connection to ");
Serial.println(myDevice->getAddress().toString().c_str());

BLEClient* pClient = BLEDevice::createClient();


Serial.println(" - Created client");

pClient->setClientCallbacks(new MyClientCallback());

// Connect to the remote BLE Server.


pClient->connect(myDevice); // if you pass BLEAdvertisedDevice instead of address,
it will be recognized type of peer device address (public or private)
Serial.println(" - Connected to server");

// 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;
}

// Function to chech Characteristic

bool connectCharacteristic(BLERemoteService* pRemoteService, BLERemoteCharacteristic*


l_BLERemoteChar) {
// Obtain a reference to the characteristic in the service of the remote BLE server.
if (l_BLERemoteChar == nullptr) {
Serial.print("Failed to find one of the characteristics");
Serial.print(l_BLERemoteChar->getUUID().toString().c_str());
return false;
}
Serial.println(" - Found characteristic: " + String(l_BLERemoteChar-
>getUUID().toString().c_str()));

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;

} // Found our server


} // onResult
}; // MyAdvertisedDeviceCallbacks

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());

// stoi = string to integer


String txValue = String(std::stoi(rxValue) +1 );
Serial.println("Characteristic (writeValue): " + txValue);

// Set the characteristic's value to be the array of bytes that is actually a


string.
pRemoteChar_2->writeValue(txValue.c_str(), txValue.length());

}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.

You might also like