I would like to implement a workaround to use a non-static class as a call-back function. I am working with Eclipse Paho MQTT code. The following type is implemented and used as callback:
typedef void MQTTAsync_onSuccess(void* context, MQTTAsync_successData* response);
MQTTAsync_onSuccess* onSuccess;
onSuccess = myStaticCallback;
void myStaticCallback (void* context, MQTTAsync_successData* response)
{
//...callback actions...
}
I want to wrap this C API (without modifying the existing MQTT C API) and implement non-static / non-centralized callback function that belongs to an object/class.
typedef void MQTTAsync_onSuccess(void* context, MQTTAsync_successData* response);
class myMQTTClass
{
private:
void myCallback (void* context, MQTTAsync_successData* response);
MQTTAsync_onSuccess* onSuccess;
public:
void foo (void)
{
this->onSuccess = this->myCallback;
}
}
As you might guess, the code above causes the error:
cannot convert myCallback from type 'void (myMQTTClass::) (void*, MQTTAsync_successData*)' to type 'void (*)(void*, MQTTAsync_successData*)'.
Any guidance as to how to address this issue or any workaround is greately appreciated. I would be willing to provide any possible missing information. Thanks in advance.
EDIT: Actual code with some omissions
namespace rover
{
typedef struct
{
char * clientID;
char * topic;
char * payload;
int qos; // 1
long int timeout; // Such as 10000L usec
} RoverMQTT_Configure_t;
class RoverPahoMQTT
{
public:
RoverPahoMQTT (char * host_name, int port, RoverMQTT_Configure_t MQTT_Configure);
private:
/**
* @brief Host name used for connecting to the Eclipse Paho MQTT server
*/
char * HOST_NAME;
/**
* @brief Port used for connecting to the Eclipse Paho MQTT server
*/
int PORT;
RoverMQTT_Configure_t rover_MQTT_configure;
/* Internal attributes */
MQTTAsync client;
/**
* @brief Connect options
*/
MQTTAsync_connectOptions conn_opts;
/**
* @brief Disconnect options
*/
MQTTAsync_disconnectOptions disc_opts;
//...
static void onPublisherConnect (void* context, MQTTAsync_successData* response);
void onPublisherConnect_ (MQTTAsync_successData* response);
//...
}
}
int rover::RoverPahoMQTT::publish (void)
{
this->flushFlags ();
this->conn_opts = MQTTAsync_connectOptions_initializer;
this->client = new MQTTAsync;
int rc;
char my_addr[20];
this->constructAddress (my_addr);
printf ("address: %s", my_addr);
MQTTAsync_create ( &(this->client),
my_addr,
this->rover_MQTT_configure.clientID,
MQTTCLIENT_PERSISTENCE_NONE,
NULL);
MQTTAsync_setCallbacks(this->client, NULL, onConnectionLost, NULL, NULL);
conn_opts.keepAliveInterval = 20;
conn_opts.cleansession = 1;
conn_opts.onSuccess = rover::RoverPahoMQTT::onPublisherConnect;
conn_opts.onFailure = onConnectFailure;
conn_opts.context = this->client;
if ((rc = MQTTAsync_connect(this->client, &(this->conn_opts))) != MQTTASYNC_SUCCESS)
{
printf("Failed to start connect, return code %d\n", rc);
return rc;
}
/*printf("Waiting for publication of %s\n"
"on topic %s for client with ClientID: %s\n",
PAYLOAD, TOPIC, CLIENTID);*/
while (!mqtt_finished)
usleep(this->rover_MQTT_configure.timeout);
MQTTAsync_destroy(&client);
return rc;
}
void rover::RoverPahoMQTT::onPublisherConnect_(MQTTAsync_successData* response)
{
MQTTAsync_responseOptions opts = MQTTAsync_responseOptions_initializer;
MQTTAsync_message pubmsg = MQTTAsync_message_initializer;
int rc;
printf("Successful connection\n");
opts.onSuccess = onPublisherSend;
opts.context = client;
pubmsg.payload = &default_MQTT_configure.payload;
pubmsg.payloadlen = strlen(default_MQTT_configure.payload);
pubmsg.qos = default_MQTT_configure.qos;
pubmsg.retained = 0;
deliveredtoken = 0;
if ((rc = MQTTAsync_sendMessage(client, default_MQTT_configure.topic, &pubmsg, &opts)) != MQTTASYNC_SUCCESS)
{
printf("Failed to start sendMessage, return code %d\n", rc);
exit(EXIT_FAILURE);
}
}
void rover::RoverPahoMQTT::onPublisherConnect (void* context, MQTTAsync_successData* response)
{
rover::RoverPahoMQTT* m = (rover::RoverPahoMQTT*) context;
m->onPublisherConnect_(response);
//((rover::RoverPahoMQTT*)context)->onPublisherConnect_(response);
// ^^^HERE IS THE SEGMENTATION FAULT
}
staticclass member function and providethisas thecontext.extern "C"(since it's clearly a C level callback). If you control thecontextparameter then use that to identify your class instance. If not, then you can either use someMQTTA-specific means of instance identification, or for a small number of possible concurrent instances identify via the callback function address (then using a unique callback function per instance), or for single-threaded execution, a "current instance" global variable, or ditto thread local such variable for multi-threading, or something else.this->onSuccess = myCallback(this)but I know that won't work.