I've running Mosquitto on my RPI4. But right know I only can set static callback functions. Is there a way to use class members?
I've tried to use std::bind to pass a class member function as callback:
main.cpp
#include <stdio.h>
#include <mosquitto.h>
#include "mqtt.h"
#include <string>
int main(int argc, char **argv)
{
MqttConnector * mqtt = new MqttConnector("piClient", "send", "rc", 1883, "localhost", 60);
mqtt->startClient();
return 0;
}
mqtt.h (only important parts
#include <mosquitto.h>
#include <string>
#include <stdio.h>
class MqttConnector
{
public:
MqttConnector(std::string id,
std::string sendTopic,
std::string receiveTopic,
int port,
std::string host,
int keepalive);
~MqttConnector();
void startClient();
private:
void messageCallback(struct mosquitto *mosq,
void *userdata,
const struct mosquitto_message *message);
struct mosquitto *mosqClient = NULL;
int keepalive;
int port;
std::string id;
std::string host;
std::string sendTopic;
std::string receiveTopic;
};
mqtt.cpp
#include "mqtt.h"
#include <stdio.h>
#include <string>
#include <string.h>
#include <mosquitto.h>
#include <functional>
using namespace std::placeholders;
MqttConnector::MqttConnector(std::string id, std::string sendTopic, std::string receiveTopic, int port, std::string host, int keepalive)
{
mosquitto_lib_init();
mosqClient = mosquitto_new(NULL, true, NULL);
if(!mosqClient){
fprintf(stderr, "Error: Out of memory.\n");
}
this->keepalive = keepalive;
this->id = id;
this->host = host;
this->port = port;
this->sendTopic = sendTopic;
this->receiveTopic = receiveTopic;
}
MqttConnector::~MqttConnector()
{
mosquitto_destroy(mosqClient);
mosquitto_lib_cleanup();
}
void MqttConnector::messageCallback(struct mosquitto *mosq, void *userdata, const struct mosquitto_message *message)
{
// I want to access class members like sendTopic / receiveTopic here
}
void MqttConnector::startClient()
{
// try to bind class members function
mosquitto_message_callback_set(mosqClient, std::bind(&MqttConnector::messageCallback, this, _1, _2, _3));
//other stuff
}
This gives me the following error while compiling:
cannot convert 'std::_Bind_helper<false, void (MqttConnector::*)(mosquitto*, void*, const mosquitto_message*), MqttConnector*, const std::_Placeholder<1>&, const std::_Placeholder<2>&, const std::_Placeholder<3>&>::type' {aka 'std::_Bind<void (MqttConnector::*(MqttConnector*, std::_Placeholder<1>, std::_Placeholder<2>, std::_Placeholder<3>))(mosquitto*, void*, const mosquitto_message*)>'} to 'void (*)(mosquitto*, void*, const mosquitto_message*)'
83 | mosquitto_message_callback_set(mosqClient, std::bind(&MqttConnector::messageCallback, this, _1, _2, _3));
Why doesn't it work?
Thanks!
This is a problem of using C-api from C++. What is the difference between a member function and a free function? When you provide a pointer to a member function a pointer to the class object is implicitly passed as the first parameter. Since C-api doesn't do that, but the problem is well known, the solution was introduced and it is called passing a context. Usually it is done through a void pointer. Functions that register callbacks usually take the pointer to the free function and a pointer to context. Then this pointer will be passed as one of the callback parameters.
In mosquitto case this context pointer is passed beforehand at the creation of a mosquitto object with mosquitto_new.
In order to make the callback function behave like a C function, we declare it static.
Inside the callback function we use static_cast to cast the void pointer to the object that we have provided.
mqtt.h
#include <mosquitto.h>
#include <string>
#include <stdio.h>
class MqttConnector
{
public:
MqttConnector(std::string id,
std::string sendTopic,
std::string receiveTopic,
int port,
std::string host,
int keepalive);
~MqttConnector();
void startClient();
private:
// make this function static
---->
static void messageCallback(struct mosquitto *mosq,
void *userdata,
const struct mosquitto_message *message);
struct mosquitto *mosqClient = NULL;
int keepalive;
int port;
std::string id;
std::string host;
std::string sendTopic;
std::string receiveTopic;
};
mqtt.cpp
#include "mqtt.h"
#include <stdio.h>
#include <string>
#include <string.h>
#include <mosquitto.h>
#include <functional>
using namespace std::placeholders;
MqttConnector::MqttConnector(std::string id, std::string sendTopic, std::string receiveTopic, int port, std::string host, int keepalive)
{
mosquitto_lib_init();
// provide apointer to this as user data
mosqClient = mosquitto_new(NULL, true, this);
---->
if(!mosqClient){
fprintf(stderr, "Error: Out of memory.\n");
}
this->keepalive = keepalive;
this->id = id;
this->host = host;
this->port = port;
this->sendTopic = sendTopic;
this->receiveTopic = receiveTopic;
}
MqttConnector::~MqttConnector()
{
mosquitto_destroy(mosqClient);
mosquitto_lib_cleanup();
}
void MqttConnector::messageCallback(struct mosquitto *mosq, void *userdata, const struct mosquitto_message *message)
{
// Use static cast to get pointer to your class object from userdata
MqttConnector *connector = static_cast<MqttConnector>(userdata);
connector->sendTopic;
}
void MqttConnector::startClient()
{
// static callback
mosquitto_message_callback_set(mosqClient, &MqttConnector::messageCallback);
// lambda callback
// beware, you can't use capture here
mosquitto_message_callback_set(&m, [/*no capture possible*/] (struct mosquitto *, void *userdata, const struct mosquitto_message *)
{
MqttConnector *connector = static_cast<MqttConnector>(userdata);
connector->sendTopic;
});
}
Related
I'm trying to create a class that stores pointers to member functions of other classes and that can be executed from a text command (like a game console).
I did something functional, based on an example found here, that stores members with string-like input. Below is my implementation.
file: Command.hpp
#include <string>
#include <functional>
#include <unordered_map>
#include <string>
#include <iostream>
using namespace std;
class Command
{
public:
Command();
virtual ~Command();
void RegisterCommand(string command, function<void(const string&)> fun);
void Run(const string& command, const string& arg);
private:
unordered_map<string, function<void(const string&)>> functions;
};
file: Command.cpp
Command::Command()
{
}
Command::~Command()
{
}
void Command::RegisterCommand(string command, function<void(const string&)> fun)
{
functions[command] = fun;
}
void Command::Run(const string& command, const string& arg)
{
functions[command](arg);
}
file: main.cpp
#include "Command.hpp"
// function to register
void xyz_fun(const string& commandLine)
{
cout << "console output: " << commandLine << endl;
}
int main(int argc, char* argv[])
{
Command m_Cmd;
// Register function
m_Cmd.RegisterCommand("xyz_fun", xyz_fun);
// Run registered function
m_Cmd.Run("xyz_fun", "hello world.");
return EXIT_SUCCESS;
}
My question is how to implement a generic class to store members with unknown input arguments (Booleans, integers, doubles, strings, etc.).
For example, I could do:
m_Cmd.RegisterCommand("xyz_fun2", xyz_function2);
and call
m_Cmd.Run("xyz_fun2", false)
which has a boolean argument instead of a string.
Thanks in advance for your attention and any help is welcome.
Instead of
unordered_map<string, function<void(const string&)>> functions;
you could do
union acceptable_types { int i; char c; bool b; std::string* s; ... };
unordered_map<string, function<void(acceptable_types)>> functions;
Then when calling functions, just place the value wanted by the function into a variable of type acceptable_types.
If a function is wants to use a specific value, it should just use a specific member of the acceptable_types union.
Here's an example:
#include "Command.hpp"
void
my_bool_func (acceptable_types union_param)
{
bool bool_var = union_param.b;
// ...
// Use bool_var
// ...
}
void
my_string_func (acceptable_types union_param)
{
std::string string_var = *(union_param.s);
// ...
// Use string_var
// ...
}
int
main(int argc, char* argv[])
{
Command my_command;
acceptable_types union_var;
my_command.RegisterCommand("my_bool_func", my_bool_func);
my_command.RegisterCommand("my_string_func", my_string_func);
union_var.b = true;
my_command.Run("my_bool_func", union_var);
*(union_var.s) = "hello world.";
my_command.Run("my_string_func", union_var);
return 0;
}
We're getting this compile error followed by many more errors showing attempts to match the subscribe parameters to all possible candidate functions when using boost::bind as a callback for subscribe.
error: no matching function for call to ‘ros::NodeHandle::subscribe(const char [18], int, boost::_bi::bind_t<void, void (*)(const geometry_msgs::WrenchStamped_<std::allocator<void> >&, moveit::planning_interface::MoveGroup&), boost::_bi::list2<boost::arg<1>, boost::_bi::value<moveit::planning_interface::MoveGroup*> > >)’
Our code is as follows. The commented lines show the code which works when the MoveGroup context (object pointer) is not passed.
#include <stdio.h>
#include <boost/bind.hpp>
#include <geometry_msgs/WrenchStamped.h>
#include <moveit/move_group_interface/move_group.h>
using namespace Eigen;
using namespace std;
//void contact_callback(const geometry_msgs::WrenchStamped& msg) {
void contact_callback(const geometry_msgs::WrenchStamped& msg, moveit::planning_interface::MoveGroup &group){
//if(msg.wrench.force.z > 5) group.stop();
}
int main(int argc, char **argv) {
ros::init(argc, argv, "get_stiffness");
ros::NodeHandle node_handle;
ros::AsyncSpinner spinner(1);
spinner.start();
moveit::planning_interface::MoveGroup group("manipulator");
ros::Subscriber contact_sub;
//contact_sub = node_handle.subscribe("/finger1/nano17ft",1,contact_callback);
contact_sub = node_handle.subscribe("/finger1/nano17ft",100,boost::bind(contact_callback,_1,&group));
ros::waitForShutdown();
return 0;
}
The handler takes a MoveGroup& but you pass it the address of group.
Instead use ref(group):
boost::bind(contact_callback,_1,boost::ref(group))
Or, indeed
std::bind(contact_callback,std::placeholders::_1,std::ref(group))
UPDATE:
Your callback does not adhere to the required signature:
void contact_callback(const geometry_msgs::WrenchStamped&, moveit::planning_interface::MoveGroup & group) {
must be
void contact_callback(const boost::shared_ptr<geometry_msgs::WrenchStamped const>, moveit::planning_interface::MoveGroup & group) {
At the call site you must either make the message type explicit (it's in non-deducible context):
contact_sub = node_handle.subscribe<geometry_msgs::WrenchStamped>("/finger1/nano17ft", 100,
boost::bind(contact_callback, _1, boost::ref(group)));
OR you could simply explicitly wrap in a function<> first:
boost::function<void(const boost::shared_ptr<geometry_msgs::WrenchStamped const>&)> callback =
boost::bind(contact_callback, _1, boost::ref(group));
contact_sub = node_handle.subscribe("/finger1/nano17ft", 100, callback);
Live Demo
With all roscpp/Eigen stuff stubbed out:
Live On Coliru
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/function.hpp>
#include <iostream>
////////////////// STUBS STUBS STUBS //////
//#include <geometry_msgs/WrenchStamped.h>
namespace Eigen {}
namespace geometry_msgs {
struct WrenchStamped {}; }
namespace moveit { namespace planning_interface { struct MoveGroup { std::string name; MoveGroup(std::string s):name(s){} }; } }
namespace ros {
void init(...) {}
void waitForShutdown(...) {}
struct Subscriber {};
struct NodeHandle {
using VoidConstPtr = void const *;
enum class TransportHints {};
template <typename M>
Subscriber subscribe(const std::string &topic, uint32_t queue_size,
const boost::function<void(const boost::shared_ptr<M const> &)> &callback,
const VoidConstPtr &tracked_object = VoidConstPtr(),
const TransportHints &transport_hints = TransportHints())
{
(void)topic, (void)queue_size, void(tracked_object), void(transport_hints);
callback({});
return {};
}
};
struct AsyncSpinner {
AsyncSpinner(int) {}
void start() {}
};
};
//#include <moveit/move_group_interface/move_group.h>
////////////////// END STUBS END STUBS END STUBS //////
using namespace Eigen;
void contact_callback(const boost::shared_ptr<geometry_msgs::WrenchStamped const>, moveit::planning_interface::MoveGroup & group) {
// if(msg.wrench.force.z > 5) group.stop();
std::cout << "Invoked! " << group.name << "\n";
}
int main(int argc, char **argv) {
ros::init(argc, argv, "get_stiffness");
ros::NodeHandle node_handle;
ros::AsyncSpinner spinner(1);
spinner.start();
moveit::planning_interface::MoveGroup group("manipulator");
ros::Subscriber contact_sub;
contact_sub = node_handle.subscribe<geometry_msgs::WrenchStamped>("/finger1/nano17ft", 100,
boost::bind(contact_callback, _1, boost::ref(group)));
{
boost::function<void(const boost::shared_ptr<geometry_msgs::WrenchStamped const>&)> callback =
boost::bind(contact_callback, _1, boost::ref(group));
contact_sub = node_handle.subscribe("/finger1/nano17ft", 100, callback);
}
ros::waitForShutdown();
}
Prints
Invoked! manipulator
Invoked! manipulator
I already asked about my Problem, now I'm on the next Step. In the code below I have the Problem, that I always have to make the EventHandler (Server::HandleMessage) static. But I need to have it non static to access other Variables in the Server class from within the Handler.
How can I achieve this?
Here my Code:
#include <iostream>
#include <functional>
using namespace std;
class Client{
public:
struct MessageReceiveArgs {
MessageReceiveArgs(int ID, const std::string& Text) : ID(ID), Text(Text) {}
int ID;
std::string Text;
};
std::function<void(MessageReceiveArgs)> onMessageReceive;
Client(){}
void FireEvent(){
this->onMessageReceive(MessageReceiveArgs(16, "SomeText"));
}
};
class Server{
public:
int i;
Server(){
this->client.onMessageReceive = &Server::HandleMessage;
this->i = 5;
}
void FireEvent(){
this->client.FireEvent();
}
Client client;
static void HandleMessage(Client::MessageReceiveArgs args) {
std::cout<<"ID "<<args.ID<<": "<<" "<<args.Text<<std::endl;
//need it non static
//std::cout<<"I: "<<this->i<<std::endl;
}
};
int main() {
Server sv = Server();
sv.FireEvent();
}
As mentioned in my earlier Post, i'm new to Standard C++ (Unix).
I'm fairly sure this is what you're after. You need to bind the implicit this explicitly when invoking a pointer-to-member through std::function in the fashion you seem to desire.
#include <iostream>
#include <functional>
using namespace std;
class Client{
public:
struct MessageReceiveArgs
{
MessageReceiveArgs(int ID, const std::string& Text)
: ID(ID), Text(Text) {}
int ID;
std::string Text;
};
Client(){}
void FireEvent()
{
this->onMessageReceive(MessageReceiveArgs(16, "SomeText"));
}
std::function<void(MessageReceiveArgs)> onMessageReceive;
};
class Server
{
public:
int i;
Server()
{
this->client.onMessageReceive
= std::bind(&Server::HandleMessage, this, std::placeholders::_1);
this->i = 5;
}
void FireEvent()
{
this->client.FireEvent();
}
Client client;
void HandleMessage(Client::MessageReceiveArgs args)
{
std::cout<<"ID "<<args.ID<<": "<<" "<<args.Text<<std::endl;
}
};
int main()
{
Server sv = Server();
sv.FireEvent();
}
Output
ID 16: SomeText
I have tried many times to solve this problem but i got nothing.
The main purpose of this code is saving pair keys (Public and Private) in nested class NslObject::KeyK or NewKeyPair1.
.cpp file
unsigned long int keyLength = 10;
//KeyPair ADD(RSA::GenerateKeyPair(keyLength));
NslObject::KeyK(RSA::GenerateKeyPair(keyLength));
typedef NslObject::KeyK NewKeyPair1;
NewKeyPair1(RSA::GenerateKeyPair(keyLength));
//NslObject::
Key OtmanK(NslObject::Get_PublicKey(NewKeyPair1));
.h file:
#ifndef __NCTUNS_nslobject_h__
#define __NCTUNS_nslobject_h__
#include <stdio.h>
#include <event.h>
//---------------------------------------------------
#include <cstdlib> //srand()
#include <iostream> //cout
#include <ctime> //time()
#include <cstring> //strcmp()
//#include "test.h" //testing functions
#include "RSA.h" //GenerateKeyPair()
#include "PrimeGenerator.h" //Generate()
//#include <stdio.h>
#include <stdlib.h>
#include <sstream>
#include <string>
//---------------------------------------------------
class MBinder;
struct plist {
u_int8_t pid;
struct plist *next;
};
struct MBlist {
u_int8_t portnum;
MBinder *sendt;
struct MBlist *next;
};
/*=========================================================================
Define Macros
=========================================================================*/
#define DISABLED 0x00
#define ENABLED 0x01
/*=========================================================================
Define Class ProtoType
=========================================================================*/
class NslObject {
private:
char *name_; /* Instance name */
const u_int32_t nodeID_; /* Node Id */
const u_int32_t nodeType_; /* Node type, eg: SWITCH, HOST.. */
u_int32_t portid_; /* port Id */
struct plist *MPlist_;
// static KeyPair NewKeyPair;
public :
/* add for new structure engine*/
u_int32_t pdepth;
struct MBlist *BinderList;
u_int8_t PortNum;
//------------------------------------------------
class KeyK {
private :
KeyPair Kk;
public:
KeyK( KeyPair D1): Kk(D1)
{}
const Key &GetPrivateKey() const
{
return Kk.GetPrivateKey();
}
const Key &GetPublicKey() const
{
return Kk.GetPublicKey();
}
//KeyK NewKeyPair ;
};
Key Get_PrivateKey(KeyK &K){
return K.GetPrivateKey();
}
Key Get_PublicKey(KeyK &K){
return K.GetPublicKey();
}
//static KeyPair *KeyPtr1 ;//= new KeyPair;
//------------------------------------------------
u_char s_flowctl; /* flow control for sending pkt */
u_char r_flowctl; /* flow control for receiving pkt */
MBinder *recvtarget_; /* to upper component */
MBinder *sendtarget_; /* to lower component */
NslObject(u_int32_t, u_int32_t, struct plist*, const char *);
NslObject();
virtual ~NslObject();
virtual int init();
virtual int recv(ePacket_ *);
virtual int send(ePacket_ *);
virtual int get(ePacket_ *, MBinder *);
virtual int put(ePacket_ *, MBinder *);
virtual ePacket_ *put1(ePacket_ *, MBinder *);
virtual int command(int argc, const char *argv[]);
virtual int Debugger();
inline void set_port(u_int32_t portid) {
portid_ = portid;
};
inline u_int32_t get_port() const {
return(portid_);
};
inline struct plist* get_portls() const {
return(MPlist_);
};
inline const char * get_name() const {
return(name_);
}
inline u_int32_t get_nid() const {
return(nodeID_);
}
inline u_int32_t get_type() const {
return(nodeType_);
}
//--------------------------------------------------------
};
so, the problem in this line in cpp file :
Key OtmanK(NslObject::Get_PublicKey(NewKeyPair1));
when i tried to compile this project, i got this Error message:
object.cc:87: error: expected primary-expression before ‘)’ token
please, help me.
when i tried to make a directed call for key class, the other problem was appeared such as :
unsigned long int keyLength = 10;
//KeyPair ADD(RSA::GenerateKeyPair(keyLength));
NslObject::KeyK(RSA::GenerateKeyPair(keyLength));
typedef NslObject::KeyK NewKeyPair1;
NewKeyPair1(RSA::GenerateKeyPair(keyLength));
//NslObject::
//Key OtmanK(NewKeyPair1.GetPublicKey());
std::string message = "othman Alkilany";
// NslObject::NewKeyPair.GetPrivateKey()
std::string cypherText = RSA::Encrypt( message, NewKeyPair1.GetPublicKey());
the Error Message is :
error: expected primary-expression before ‘.’ token
I guess your issue is in the second line here:
typedef NslObject::KeyK NewKeyPair1;
NewKeyPair1(RSA::GenerateKeyPair(keyLength));
Resolving the typedef you've essentially written the following:
NslObject::KeyK(RSA::GenerateKeyPair(keyLength));
So you can clearly see you're missing the variable name for this line.
To fix this, name the variable/object:
NewKeyPair1 somekeypair(RSA::GenerateKeyPair(keyLength));
However, I guess you misused the typedef anyway? Did you try to name that NewKeyPair1? Something like this:
NslObject::KeyK NewKeyPair1(RSA::GenerateKeyPair(keyLength));
I am using libxml2 to validate an xml file against an xsd schema.
Using xmlSchemaSetParserErrors function, errors are output to stderr.
I need to get these validation errors, store them in memory and display to the user.
How can I redirect these errors ? Could you provide me some examples ?
Thanks,
Andrea
This example uses the validation callback mechanism of the parser module. The signature of callbacks expected by xmlSchemaSetParserErrors seems to be the same.
#include <iostream>
#include <cstdarg>
#include <cstdio>
#include <vector>
#include <string>
#include <iterator>
#include <libxml/parser.h>
#include <libxml/tree.h>
struct ParserContext
{
ParserContext() : context(xmlNewParserCtxt()) {}
~ParserContext() { xmlFreeParserCtxt(context); }
xmlParserCtxtPtr context;
private:
ParserContext(ParserContext&);
void operator=(ParserContext&);
};
struct ErrorHandler
{
std::vector<std::string> errors;
void RegisterErrorHandling(xmlValidCtxt& validationContext)
{
// Change this to register for schema errors...
validationContext.userData = this;
validationContext.error = &ErrorHandler::Handle;
}
private:
static void Handle(void *handler, const char *format, ...)
{
va_list arguments;
va_start(arguments, format);
std::string message = MakeMessage(format, arguments);
va_end(arguments);
ErrorHandler* errorHandler = static_cast<ErrorHandler*>(handler);
errorHandler->errors.push_back(message);
}
static std::string MakeMessage(const char* format, va_list arguments)
{
const size_t bufferSize = 200;
std::vector<char> buffer(bufferSize, 0);
size_t charactersWritten =
vsnprintf(&buffer.front(), bufferSize, format, arguments);
if (charactersWritten == -1)
buffer.back() = 0; // Message truncated!
return std::string(&buffer.front());
}
};
struct XmlDocument
{
static XmlDocument FromFile(const char* fileName)
{
ParserContext parser;
ErrorHandler errorHandler;
errorHandler.RegisterErrorHandling(parser.context->vctxt);
XmlDocument document(xmlCtxtReadFile(
parser.context, fileName, NULL, XML_PARSE_DTDVALID));
document.errors = move(errorHandler.errors);
return document;
}
XmlDocument(XmlDocument&& other) :
xmlPointer(other.xmlPointer),
errors(move(other.errors))
{
other.xmlPointer = nullptr;
}
~XmlDocument()
{
xmlFreeDoc(xmlPointer);
}
xmlDocPtr xmlPointer;
std::vector<std::string> errors;
private:
XmlDocument(xmlDocPtr pointer) : xmlPointer(pointer) {}
XmlDocument(XmlDocument&);
void operator=(XmlDocument&);
};
void DisplayErrorsToUser(
const XmlDocument& document,
std::ostream& displayStream = std::cout)
{
using namespace std;
copy(begin(document.errors), end(document.errors),
ostream_iterator<string>(displayStream, "\n"));
}
int main()
{
auto xml = XmlDocument::FromFile("test.xml");
DisplayErrorsToUser(xml);
}
Or even more concise:
void err(void *ctx, const char *msg, ...)
{
va_list args;
va_start(args, msg);
char *val = va_arg(args,char*);
va_end(args);
}
val now contains validation errors
As said in the API documentation, xmlSchemaSetParserErrors() Set the callback functions used to handle errors for a validation context.
You need to write two callback functions with respect to defined signature :
xmlSchemaValidityErrorFunc err
xmlSchemaValidityWarningFunc warn
An example could be :
void err(void *ctx, const char *msg, ...)
{
char buf[1024];
va_list args;
va_start(args, msg);
int len = vsnprintf_s(buf, sizeof(buf), sizeof(buf)/sizeof(buf[0]), msg, args);
va_end(args);
if(len==0) // Can't create schema validity error!
else // Do something to store `buf`,
// you may need to use void *ctx to achieve this
return;
}
Then just call
xmlSchemaSetValidErrors(valid_ctxt_ptr, (xmlSchemaValidityErrorFunc) err, (xmlSchemaValidityWarningFunc) warn, ctx);
before calling
xmlSchemaValidateDoc()