I am using the arduinoWebSockets library in my own Arduino library. I'm having trouble with trying to assign a class member as the websocket library onEvent
callback function.
MyClass.cpp:
#include <WebSocketsClient.h>
#include "Arduino.h"
#include "MyClass.h"
void MyClass::connect(String host, int port) {
webSocket.begin(host, port, "/");
webSocket.setReconnectInterval(5000);
// tried all these variations
// webSocket.onEvent(incomingEventHandler);
// webSocket.onEvent(MyClass::incomingEventHandler);
webSocket.onEvent(this->incomingEventHandler);
}
void MyClass::loop() {
webSocket.loop();
}
void MyClass::incomingEventHandler(WStype_t type, uint8_t *payload, size_t length) {
// do stuff with incoming data
// need to access other member functions and class variables
}
MyClass.h:
#ifndef MyClass_h
#define MyClass_h
#include <WebSocketsClient.h>
#include "Arduino.h"
class MyClass {
public:
void connect(String host, int port);
void loop();
void incomingEventHandler(WStype_t type, uint8_t *payload, size_t length);
private:
WebSocketsClient webSocket;
};
#endif
The error returned is:
sketch/MyClass.cpp: In member function 'void MyClass::connect(String, int)': MyClass.cpp:14:47: error: no matching function for call to 'WebSocketsClient::onEvent()'
webSocket.onEvent(this->incomingEventHandler);
From what I understand it seems like I need to create a pointer to the class member, I have tried a few different ways, this one seemed the most promising, but still failed:
typedef void (MyClass::*MyClassMemFn)(WStype_t type, uint8_t *payload, size_t length);
void MyClass::connect(String host, int port) {
webSocket.begin(host, port, "/");
webSocket.setReconnectInterval(5000);
MyClassMemFn onEventCallback = &MyClass::incomingEventHandler;
webSocket.onEvent(MyClassMemFn onEventCallback);
}
The above returns this error:
sketch/MyClass.cpp: In member function 'void MyClass::connect(String, int)': MyClass.cpp:15:34: error: expected primary-expression before 'onEventCallback' webSocket.onEvent(MyClassMemFn onEventCallback);
I have also tried to use std::bind
:
void MyClass::connect(String host, int port) {
webSocket.begin(host, port, "/");
webSocket.setReconnectInterval(5000);
webSocket.onEvent(std::bind(&MyClass::incomingEventHandler, this));
}
Error:
sketch/MyClass.cpp: In member function 'void MyClass::connect(String, int)': MyClass.cpp:12:47: error: no matching function for call to 'WebSocketsClient::onEvent()'
webSocket.onEvent(this->incomingEventHandler);
If I move the incomingEventHandler
function outside the class definition, it works as expected, however then I can't call other class members or access class properties in the same scope.
In arduino c++ how can I pass non-static class member properties as a callback? Is there a better way to approach this?
1 Answer 1
Yes, a callback can be a member function. The error in your std::bind
call is that while you do bind the first hidden this
paramater to an object instance, in this case this
object, you must also use placeholders for all your other function parameters.
Since you declared
void incomingEventHandler(WStype_t type, uint8_t *payload, size_t length)
You must bind as
webSocket.onEvent(std::bind(&MyClass::incomingEventHandler, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
Note that this webSocket.onEvent
call only works if you are on a non-AVR platform, because the library defines
void WebSocketsClient::onEvent(WebSocketClientEvent cbEvent) {
_cbEvent = cbEvent;
}
with
#ifdef __AVR__
typedef void (*WebSocketClientEvent)(WStype_t type, uint8_t * payload, size_t length);
#else
typedef std::function<void (WStype_t type, uint8_t * payload, size_t length)> WebSocketClientEvent;
#endif
i.e., it is a raw function pointer in __AVR__
but a std::function
on non-AVR platforms -- std::bind
will give you a std::function
. Since you're on an ESP8266, this should work fine.
Refer to https://en.cppreference.com/w/cpp/utility/functional/bind (and maybe my old question)
this
. Member functions have a "hidden" parameter.This
is necessary to allow access to the member data and virtual function table. The short answer to your question is therefore - a callback cannot be a member function.