esp32-snippets
esp32-snippets copied to clipboard
Getting two Services when I only start one
Hello!
Thank you for the ESP32 BLE Arduino library! Huge help! But I have run in to an issue that I can't not seem to solve.
I created a header and CPP files to serve as a wrapper for your library. In my setup() function, I start a freeRTOS task, and before that forever loop, I declare and initialize my BLE wrapper class, then create one server, one service, and one characteristics. Then in my forever loop, I have conditional to handle connecting, disconnecting, and advertising.
The problem is I would like to keep my header and CPP wrapper files compliant with good coding practices, namely the Open-Closed principle, so that those files never need to be changed, and instead all modifications take place in the freeRTOS task.
More than a fix, because I am able to modify my code enough to get only one service, but breaks the Open-Closed principle. I'd love to know why I am seeing two services.
Main sketch:
#include <freertos/stream_buffer.h>
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#include "BLE.h"
#include "ServerCallbacks.h"
#include "CharCallbacks.h"
// See the following for generating UUIDs:
// https://www.uuidgenerator.net/
TaskHandle_t ble_handle;
TickType_t lastReceviedTickCount;
StreamBufferHandle_t rxStreamBuffer;
const size_t xStreamBufferSizeBytes = 100, xTriggerLevel = 10;
void setup() {
Serial.begin(115200);
Serial.println("Starting BLE work!");
rxStreamBuffer = xStreamBufferCreate( xStreamBufferSizeBytes, xTriggerLevel );
xTaskCreatePinnedToCore(ble_task,
"BLE Task",
1024 * 5,
NULL,
20,
&ble_handle,
1);
}
void loop() {
// put your main code here, to run repeatedly:
char rxData[ 100 ];
size_t xReceivedBytes;
const TickType_t xBlockTime = pdMS_TO_TICKS( 20 );
// Receive up to another sizeof( ucRxData ) bytes from the stream buffer.
// Wait in the Blocked state (so not using any CPU processing time) for a
// maximum of 100ms for the full sizeof( ucRxData ) number of bytes to be
// available.
xReceivedBytes = xStreamBufferReceive( rxStreamBuffer,
( void * ) rxData,
50,
xBlockTime );
if( xReceivedBytes > 0 )
{
char incoming[xReceivedBytes+1];
for(int i = 0; i < xReceivedBytes; i++) {
incoming[i] = rxData[i];
}
incoming[xReceivedBytes] = '\0';
std::string rx_message = incoming;
Serial.print("rx_message:");
Serial.println(rx_message.c_str());
}
vTaskDelay( 100 / portTICK_PERIOD_MS );
}
BLE_task
void ble_task(void * parameters) {
Serial.println("Task: ble_task");
BLE ble = BLE();
ble.init("Noon");
ble.getServer()->setCallbacks(new ServerCallbacks(ble.getDeviceConnected()));
BLEService* pService = ble.getServer()->createService(SERVICE_UUID);
BLECharacteristic* pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID,
BLECharacteristic::PROPERTY_READ |
BLECharacteristic::PROPERTY_WRITE
);
pCharacteristic->setCallbacks(new CharCallbacks(&lastReceviedTickCount, &rxStreamBuffer));
//pCharacteristic->setValue("Hello World says Neil");
pService->start();
BLEAdvertising* pAdvertising = BLEDevice::getAdvertising();
pAdvertising->addServiceUUID(SERVICE_UUID);
pAdvertising->setScanResponse(true);
pAdvertising->setMinPreferred(0x06); // functions that help with iPhone connections issue
pAdvertising->setMinPreferred(0x12);
BLEDevice::startAdvertising();
for( ;; ) {
// disconnecting
if (!ble.isDeviceConnected() && ble.isOldDeviceConnected()) {
delay(500); // give the bluetooth stack the chance to get things ready
Serial.println("Device disconnected!");
BLEDevice::startAdvertising();
Serial.println("start advertising");
ble.setOldDeviceConnected(ble.isDeviceConnected());
//oldDeviceConnected = deviceConnected;
}
// connecting
if (ble.isDeviceConnected() && !ble.isOldDeviceConnected()) {
// do stuff here on connecting
Serial.println("Device connected!");
ble.setOldDeviceConnected(ble.isDeviceConnected());
//oldDeviceConnected = deviceConnected;
}
vTaskDelay( 100 / portTICK_PERIOD_MS );
}
}
BLE.h/BLE.cpp:
#ifndef BLE_H_
#define BLE_H_
#include <BLEDevice.h>
#include <BLEServer.h>
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
class BLE {
public:
BLE();
~BLE();
void init(std::string name);
std::string getName();
void setName(std::string n);
BLEServer* getServer();
void setServer(BLEServer* s);
bool* getDeviceConnected();
bool isDeviceConnected();
void setDeviceConnected(bool c);
bool* getOldDeviceConnected();
bool isOldDeviceConnected();
void setOldDeviceConnected(bool c);
private:
std::string bleName;
BLEServer* pServer;
bool deviceConnected;
bool oldDeviceConnected;
};
#endif
BLE::BLE() {
deviceConnected = false;
oldDeviceConnected = false;
}
BLE::~BLE() {
}
void BLE::init(std::string name) {
setName(name);
BLEDevice::init(getName());
setServer(BLEDevice::createServer()); //BLEServer* pServer = BLEDevice::createServer();
}
std::string BLE::getName() {
return bleName;
}
void BLE::setName(std::string n) {
bleName = n;
}
BLEServer* BLE::getServer() {
return pServer;
}
void BLE::setServer(BLEServer* s) {
pServer = s;
}
bool* BLE::getDeviceConnected() {
return &deviceConnected;
}
bool BLE::isDeviceConnected() {
return deviceConnected;
}
void BLE::setDeviceConnected(bool c) {
deviceConnected = c;
}
bool* BLE::getOldDeviceConnected() {
return &oldDeviceConnected;
}
bool BLE::isOldDeviceConnected() {
return oldDeviceConnected;
}
void BLE::setOldDeviceConnected(bool c) {
oldDeviceConnected = c;
}
ServerCallbacks.h/ServerCallbacks.cpp:
#ifndef SERVERCALLBACKS_H_
#define SERVERCALLBACKS_H_
#include <BLEServer.h>
class ServerCallbacks: public BLEServerCallbacks {
public:
ServerCallbacks(bool* connnectionStatus);
virtual ~ServerCallbacks();
void onConnect(BLEServer* pServer);
void onDisconnect(BLEServer* pServer);
private:
bool *bConnected;
};
#endif
ServerCallbacks::ServerCallbacks(bool* connnectionStatus) {
bConnected = connnectionStatus;
}
ServerCallbacks::~ServerCallbacks() {
}
void ServerCallbacks::onConnect(BLEServer* pServer) {
*bConnected = true;
}
void ServerCallbacks::onDisconnect(BLEServer* pServer) {
*bConnected = false;
}
CharCallbacks.h/CharCallbacks.cpp:
#ifndef CHARCALLBACKS_H_
#define CHARCALLBACKS_H_
#include "Arduino.h"
#include <freertos/stream_buffer.h>
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
class CharCallbacks: public BLECharacteristicCallbacks {
public:
CharCallbacks(TickType_t* lastReceivedTick, StreamBufferHandle_t* streamBuffer);
virtual ~CharCallbacks();
void onWrite(BLECharacteristic *pCharacteristic);
void onRead(BLECharacteristic* pCharacteristic);
StreamBufferHandle_t* getStreamBuffer();
void setStreamBuffer(StreamBufferHandle_t* buf);
private:
TickType_t* lastReceviedTickCount;
StreamBufferHandle_t* rxStreamBuffer;
size_t xBytesSent;
TickType_t x100ms;
};
#endif
CharCallbacks::CharCallbacks(TickType_t* lastReceivedTick, StreamBufferHandle_t* streamBuffer) {
lastReceviedTickCount = lastReceivedTick;
x100ms = pdMS_TO_TICKS( 100 );
rxStreamBuffer = streamBuffer;
}
CharCallbacks::~CharCallbacks() {
}
void CharCallbacks::onWrite(BLECharacteristic *pCharacteristic) {
Serial.println("BLE received data!");
std::string rxValue = pCharacteristic->getValue();
// Send the string to the stream buffer. Return immediately if there is not
// enough space in the buffer.
Serial.print("Sending to BLE rx stream buffer: ");Serial.println(rxValue.c_str());
xBytesSent = xStreamBufferSend( *rxStreamBuffer, ( void * ) rxValue.c_str(), strlen( rxValue.c_str() ), 0 );
if( xBytesSent != strlen( rxValue.c_str() ) )
{
// The entire string could not be added to the stream buffer because
// there was not enough free space in the buffer, but xBytesSent bytes
// were sent. Could try again to send the remaining bytes.
Serial.println("The entire string could not be added to the stream buffer.");
}
}
void CharCallbacks::onRead(BLECharacteristic* pCharacteristic) {
}
StreamBufferHandle_t* CharCallbacks::getStreamBuffer() {
return rxStreamBuffer;
}
void CharCallbacks::setStreamBuffer(StreamBufferHandle_t* buf) {
rxStreamBuffer = buf;
}
Ideally, the BLE task would handle all the application specific settings like BLE name, services and their characteristics, connection, disconnection, and advertising. And then a BLE message comes in, it sends it to a Stream Buffer for my application logic to receive and process. (This whole thing came about when I was dropping messages because I was busy processing the previous one)
Thank you in advance and please know I have gotten a single service to work, but any, I mean any, modification creates a random second service.