Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Request of setting notify_callback as class instance. #342

Open
asukiaaa opened this issue Jan 29, 2022 · 5 comments
Open

Request of setting notify_callback as class instance. #342

asukiaaa opened this issue Jan 29, 2022 · 5 comments

Comments

@asukiaaa
Copy link
Contributor

asukiaaa commented Jan 29, 2022

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.

@sivar2311
Copy link

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

@asukiaaa
Copy link
Contributor Author

@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

@asukiaaa
Copy link
Contributor Author

I found the reason because scanCompleteCB is not defined with std::function.
https://github.com/h2zero/NimBLE-Arduino/pull/343/files

@sivar2311
Copy link

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.

@asukiaaa
Copy link
Contributor Author

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants