简体   繁体   中英

arduino (esp8266/esp32) ticker callback class member function

Can someone help me with the following code ?
I have a custom class and I want to define a callback for the ticker the function onTickerCallback() .
It compiles and runs on ESP8266 but not on ESP32.
I see that ESP32 Ticker::once has a different declaration but my c++ knowledge does not help me to find a solution.

Test.h

class Test {
  public:
    void start();
    void doSomething();
  private:
    void onTickerCallback();
};

Test.cpp

#include <Arduino.h>
#include <Test.h>
#include <functional>

// for ESP8266: https://github.com/esp8266/Arduino/blob/master/libraries/Ticker/src/Ticker.h
// for ESP32:   https://github.com/espressif/arduino-esp32/blob/master/libraries/Ticker/src/Ticker.h
#include <Ticker.h>

Ticker ticker;

void Test::start(){
  ticker.once(5, std::bind(&Test::onTickerCallback, this) );
}

void Test::onTickerCallback() {
  doSomething();
}

void Test::doSomething() {
  Serial.println("Hello");
}

main.cpp

#include <Arduino.h>
#include <Test.h>

Test t;

void setup() {
  Serial.begin(115200);
  t.start();
}

void loop() {
}

On ESP32 I get the following error:

error: no matching function for call to 'Ticker::once(int, std::_Bind_helper<false, void (Test::*)(), Test*>::type)'  
note: candidate: void Ticker::once(float, Ticker::callback_t)
   void once(float seconds, callback_t callback)  
note:   no known conversion for argument 2 from 'std::_Bind_helper<false, void (Test::*)(), Test*>::type {aka std::_Bind<std::_Mem_fn<void (Test::*)()>(Test*)>}' to 'Ticker::callback_t {aka 
void (*)()}'  
note: candidate: template<class TArg> void Ticker::once(float, void (*)(TArg), TArg)
   void once(float seconds, void (*callback)(TArg), TArg arg)  
note:   mismatched types 'void (*)(TArg)' and 'std::_Bind<std::_Mem_fn<void (Test::*)()>(Test*)>'  

The implementations of the two Ticker.h files are a bit different. On ESP8266, the once method expects type "callback_function_t" where callback_function_t is defined as:

typedef std::function<void(void)> callback_function_t;

On ESP32, it expects type "callback_t" which is defined as:

typedef void (*callback_t)(void);

In your code example, std::bind provides the std::function type that is expected. This is not the case for the ESP32 Ticker.h, it expects a function pointer. You have two options:

  1. Instead of having the onTickerCallback function part of the Test class, just create a free function for the callback. (Note that this is only acceptable if the callback doesn't need to be part of the Test class).
#include <Arduino.h>
#include <Test.h>
#include <functional>

// for ESP8266: https://github.com/esp8266/Arduino/blob/master/libraries/Ticker/src/Ticker.h
// for ESP32:   https://github.com/espressif/arduino-esp32/blob/master/libraries/Ticker/src/Ticker.h
#include <Ticker.h>

Ticker ticker;

void callbackFunction() {
  Serial.println("Hello");
}

void Test::start(){
  ticker.once(5, callbackFunction);
}
  1. Create a free function that takes an instance of test and use this to call your function. (Note this will also require onTickerCallback to be public, no real way around this that I can think of).
#include <Arduino.h>
#include <Test.h>
#include <functional>

// for ESP8266: https://github.com/esp8266/Arduino/blob/master/libraries/Ticker/src/Ticker.h
// for ESP32:   https://github.com/espressif/arduino-esp32/blob/master/libraries/Ticker/src/Ticker.h
#include <Ticker.h>

Ticker ticker;

void callbackFunc(Test* testInstance) {
  testInstance->onTickerCallback();
}

void Test::start(){
  ticker.once(5, callbackFunc, this);
}

void Test::onTickerCallback() {
  doSomething();
}

void Test::doSomething() {
  Serial.println("Hello");
}

Bonus: After thinking about it for a second, you could use a lambda instead of creating the function (note you need to have a + sign before the lambda in order for it to work as a function pointer). This would look like:

#include <Arduino.h>
#include <Test.h>
#include <functional>

// for ESP8266: https://github.com/esp8266/Arduino/blob/master/libraries/Ticker/src/Ticker.h
// for ESP32:   https://github.com/espressif/arduino-esp32/blob/master/libraries/Ticker/src/Ticker.h
#include <Ticker.h>

Ticker ticker;

void Test::start(){
  ticker.once(5, +[](Test* testInstance) { testInstance->onTickerCallback(); }, this);
}

void Test::onTickerCallback() {
  doSomething();
}

void Test::doSomething() {
  Serial.println("Hello");
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM