How to setEventHandler in Custom Class?
Hello I made my custom class I used example code about callback led
#include <ArduinoBLE.h>
const int ledPin = LED_BUILTIN; // pin to use for the LED
class Sample0 {
private:
BLEService _ledService;
BLEByteCharacteristic _switchCharacteristic;
public:
Sample0() : _ledService("19B10000-E8F2-537E-4F6C-D104768A1214"), _switchCharacteristic("19B10001-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite){
Serial.println("init Sample0");
}
void init(){
// begin initialization
if (!BLE.begin()) {
Serial.println("starting BLE failed!");
while (1)
;
}
// set the local name peripheral advertises
BLE.setLocalName("LEDCallback");
// set the UUID for the service this peripheral advertises
BLE.setAdvertisedService(_ledService);
// add the characteristic to the service
_ledService.addCharacteristic(_switchCharacteristic);
// add service
BLE.addService(_ledService);
// assign event handlers for connected, disconnected to peripheral
BLE.setEventHandler(BLEConnected, blePeripheralConnectHandler);
BLE.setEventHandler(BLEDisconnected, blePeripheralDisconnectHandler);
// assign event handlers for characteristic
_switchCharacteristic.setEventHandler(BLEWritten, switchCharacteristicWritten);
// set an initial value for the characteristic
_switchCharacteristic.setValue(0);
// start advertising
BLE.advertise();
Serial.println(("Bluetooth device active, waiting for connections..."));
}
void blePeripheralConnectHandler(BLEDevice central) {
// central connected event handler
Serial.print("Connected event, central: ");
Serial.println(central.address());
}
void blePeripheralDisconnectHandler(BLEDevice central) {
// central disconnected event handler
Serial.print("Disconnected event, central: ");
Serial.println(central.address());
}
void switchCharacteristicWritten(BLEDevice central, BLECharacteristic characteristic) {
// central wrote new value to characteristic, update LED
Serial.print("Characteristic event, written: ");
if (characteristic.value()) {
Serial.println("LED on");
// digitalWrite(ledPin, HIGH);
} else {
Serial.println("LED off");
// digitalWrite(ledPin, LOW);
}
}
};
// BLEService ledService("19B10000-E8F2-537E-4F6C-D104768A1214"); // create service
// BLEByteCharacteristic switchCharacteristic("19B10001-E8F2-537E 4F6C-D104768A1214", BLERead | BLEWrite);
void setup() {
Serial.begin(9600);
while (!Serial);
pinMode(ledPin, OUTPUT); // use the LED pin as an output
Sample0 sample;
sample.init();
}
void loop() {
// poll for BLE events
BLE.poll();
}
Error code
error: invalid use of non-static member function
error: invalid use of non-static member function 'void Sample0 ::blePeripheralConnectHandler(BLEDevice)'
BLE.setEventHandler(BLEConnected, blePeripheralConnectHandler);
Hi @JAICHANGPARK , as the error says, the callback should be a static function
Hi @JAICHANGPARK.
A simple way to solve this is to store the instance of your class in a static variable, and then retrieve it in you static callback.
For example, your class could be:
class Sample0 {
private:
BLEService _ledService;
BLEByteCharacteristic _switchCharacteristic;
public:
Sample0() : _ledService("19B10000-E8F2-537E-4F6C-D104768A1214"), _switchCharacteristic("19B10001-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite){
static Sample0* myInstance = this;
this->_switchCharacteristic.setEventHandler(BLERead, onSwitchRead);
Serial.println("init Sample0");
}
void test(uint8_t* value) {
// whatever
}
}
And the callback would be something like:
static void onSwitchRead(BLECentral central, BLECharacteristic characteristic) {
Sample0::myInstance->test(characteristic.value());
}
Of course, you may need to store a pointer to your instance in some other way, or have a singleton Sample0, etc. But the basic idea will be the same. Since the callback needs to be static, you need a way to statically retrieve your instance.
Hope this helps!
Does the ArduinoBLE plan to extend implementation for multiple Bluetooth modules available on the one Arduino device?
Agree with @mklemarczyk the events going through a static only good for 1 device and necessitates the needs for statics.
In NimBLE32 for the ESP32, they define a NimBLEServerCallbacks that is used as a vehicle to send the devices.
In your implementation, in stead of calling the _eventsHandler make a call to an instance of the NimBLECallback
On the implementation side, override the NimBLEServerCallback class from above and pick up on onConnected or onDisconnected
https://github.com/lathoub/Arduino-BLE-MIDI/blob/8dee1f7d257aa71aeb0e956632da2dd2ae9ed496/src/hardware/BLEMIDI_ESP32_NimBLE.h#L72-L94
Happy to help
Here is a rough implementation: https://github.com/lathoub/ArduinoBLE Changes: https://github.com/arduino-libraries/ArduinoBLE/compare/master...lathoub:master
usage:
template <class _Settings>
class MyServerCallbacks : public BLELocalDeviceCallbacks
{
public:
MyServerCallbacks(BLEMIDI_ArduinoBLE<_Settings> *bluetooth)
: _bluetooth(bluetooth)
{
}
protected:
BLEMIDI_ArduinoBLE<_Settings> *_bluetooth = nullptr;
void onConnect(void *)
{
if (_bluetooth)
_bluetooth->connected();
};
void onDisconnect(void *)
{
if (_bluetooth)
_bluetooth->disconnected();
}
};
BLE.setCallbacks(new MyServerCallbacks<_Settings>(this));
@glsubri @mklemarczyk @lathoub Thanks all!!
Thanks @lathoub What do you think about making a contribution to the library? I think to extend it later by the BLERead and BLEWritten events for BLECharacteristic.
Thanks @lathoub What do you think about making a contribution to the library? I think to extend it later by the BLERead and BLEWritten events for BLECharacteristic.
Not sure what you mean @mklemarczyk
@lathoub The contribution that is presented by you adds a new method setCallbacks for the BLEDevice class. It handles two events that are possible to bind via setEventHandler method. Which is cool and you can bind your instance methods that way to your class instance.
That improvement provide solution only for the onConnect and onDisconnect events of BLEDevice class. There is yet another class congaing events and setEventHandler method. That class is called BLECharacteristic end expose two other events onRead and onWrite when the characteristic is being read or wrote from external. You can not bind your instance methods to it as well. I propose to handle it as well with introduction of the new method setCallbacks in BLECharacteristic class.
Another question, do you plan to create PR with your improvements to the ArduinoBLE repository?
@mklemarczyk ah, I see what you mean now. Let me revisit the code to get back into it. No promisses.
I have implemented the above in https://github.com/lathoub/ArduinoBLE (device and char callbacks). I'll add some callback examples now, to see how it behaves (but i will need help on this, I'm not a BLE expert)
added examples (central and peripheral) , but i don't have the hardware here, so need help testing
@mklemarczyk gentle nudge
@lathoub Thank you, this is exactly what I was looking for. Sorry for the late response, I am stuck on problem with ArduinoBLE and FastLED libraries. I will test the improvements on my side next weekend.
Do you think it can be integrated in the official repo?
Do you think it can be integrated in the official repo?
There is fair chance, the code is incremental with little impact on the rest - and - it makes the event listening more flexible and extendible. @per1234 is listening is, so Arduino is aware .
Looking forward to your testing results @mklemarczyk