NimBLE-Arduino
NimBLE-Arduino copied to clipboard
Request of setting notify_callback as class instance.
I tried to set notify_callback with using class member method but could not. (scanCompleteCB also)
Could you support CharacteristicCallbacks class to set notify_callback like AdvertisedDeviceCallbacks or ClientCallbacks?
Is there any way to do that current functions?
My use case:
class Controller() {
public:
bool afterConnect(NimBLEClient* pClient) {
for (auto pService : *pClient->getServices(true)) {
auto sUuid = pService->getUUID();
if (!sUuid.equals(uuidServiceHid)) {
continue; // skip
}
Serial.println(pService->toString().c_str());
for (auto pChara : *pService->getCharacteristics(true)) {
charaRead(pChara);
charaSubscribeNotification(pChara);
}
}
return true;
}
void charaSubscribeNotification(NimBLERemoteCharacteristic* pChara) {
if (pChara->canNotify()) {
charaPrintId(pChara);
Serial.println(" canNotify ");
if (pChara->subscribe(true, notifyCB, true)) { // <<<<<< ========== Here
Serial.println("set notifyCb");
// return true;
} else {
Serial.println("failed to subscribe");
}
}
}
void notifyCB(NimBLERemoteCharacteristic* pRemoteCharacteristic, uint8_t* pData,
size_t length, bool isNotify) {
// update controller state
}
}
Controllelr myController;
Thank you for sharing an useful library.
You can use std::bind to set a class member function as callback function:
void charaSubscribeNotification(NimBLERemoteCharacteristic* pChara) {
if (pChara->canNotify()) {
charaPrintId(pChara);
Serial.println(" canNotify ");
if (pChara->subscribe(true, std::bind(&Controller::notifyCB, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4), true)) {
Serial.println("set notifyCb");
} else {
Serial.println("failed to subscribe");
}
}
@sivar2311 Thank you for the information. I could call!
I tried calling scanEndCB with using the bind function but I cannot pass compilcation. Could you give me some advice?
class Controller {
void startScan() {
scanning = true;
auto pScan = NimBLEDevice::getScan();
pScan->setAdvertisedDeviceCallbacks(advDeviceCBs);
pScan->setInterval(45);
pScan->setWindow(15);
Serial.println("Start scan");
// pScan->start(scanTime, scanEndedCB);
pScan->start(scanTime,
std::bind(&Core::scanEndedCB, this, std::placeholders::_1)); // <<<<<<<<<< ======== Here
}
void scanEndedCB(NimBLEScanResults results) {
Serial.println("Scan Ended");
scanning = false;
}
};
I got the following error.
In file included from src/main.cpp:3:0:
/home/asuki/pio/shared/XboxSeriesXControllerESP32/src/XboxSeriesXControllerESP32.hpp: In member function 'void XboxSeriesXControllerESP32::Core::startScan()':
/home/asuki/pio/shared/XboxSeriesXControllerESP32/src/XboxSeriesXControllerESP32.hpp:203:76: error: no matching function for call to 'NimBLEScan::start(uint32_t&, std::_Bind_helper<false, void (XboxSeriesXControllerESP32::Core::*)(NimBLEScanResults), XboxSeriesXControllerESP32::Core*, const std::_Placeholder<1>&>::type)'
std::bind(&Core::scanEndedCB, this, std::placeholders::_1));
^
In file included from /home/asuki/pio/shared/NimBLE-Arduino/src/NimBLEDevice.h:22:0,
from /home/asuki/pio/shared/XboxSeriesXControllerESP32/src/XboxSeriesXControllerESP32.hpp:3,
from src/main.cpp:3:
/home/asuki/pio/shared/NimBLE-Arduino/src/NimBLEScan.h:65:25: note: candidate: bool NimBLEScan::start(uint32_t, void (*)(NimBLEScanResults), bool)
bool start(uint32_t duration, void (*scanCompleteCB)(NimBLEScanResults), bool is_continue = false);
I triec casting but it did not solve the problem.
pScan->start(scanTime,
(void (*)(NimBLEScanResults))std::bind(
&Core::scanEndedCB, this, std::placeholders::_1));
In file included from src/main.cpp:3:0:
/home/asuki/pio/shared/XboxSeriesXControllerESP32/src/XboxSeriesXControllerESP32.hpp: In member function 'void XboxSeriesXControllerESP32::Core::startScan()':
/home/asuki/pio/shared/XboxSeriesXControllerESP32/src/XboxSeriesXControllerESP32.hpp:204:69: error: invalid cast from type 'std::_Bind_helper<false, void (XboxSeriesXControllerESP32::Core::*)(NimBLEScanResults), XboxSeriesXControllerESP32::Core*, const std::_Placeholder<1>&>::type {aka std::_Bind<std::_Mem_fn<void (XboxSeriesXControllerESP32::Core::*)(NimBLEScanResults)>(XboxSeriesXControllerESP32::Core*, std::_Placeholder<1>)>}' to type 'void (*)(NimBLEScanResults)'
&Core::scanEndedCB, this, std::placeholders::_1));
^
*** [.pio/build/esp32dev/src/main.cpp.o] Error 1
I found the reason because scanCompleteCB is not defined with std::function. https://github.com/h2zero/NimBLE-Arduino/pull/343/files
Sorry, I was away for a few hours.
For a "pure" function pointer std::bind does not work. That's why I prefer to use std::function as a callback parameter. This also allows the use of lambda functions.
Thank you for the information. I also succeeded in compilation with using lambda expression.
if (pChara->subscribe(
true,
[this](NimBLERemoteCharacteristic* pRemoteCharacteristic,
uint8_t* pData, size_t length, bool isNotify) {
notifyCB(pRemoteCharacteristic, pData, length, isNotify);
},
true)) {
Serial.println("set notifyCb");
} else {
Serial.println("failed to subscribe");
}
std::function and std::bind are new for me.
Thank you.