I'm using the Arduino IDE and the things network arduino library to create a LoRa mote.
I have created a class which should handle all the LoRa related functions. In this class I need to handle a callback if i receive a downlink message.
The ttn library has the onMessage function which I want to setup in my init function and parse another function, which are a class member, called message.
I'm getting the error "invalid use of non-static member function".
// File: LoRa.cpp
#include "Arduino.h"
#include "LoRa.h"
#include <TheThingsNetwork.h>
TheThingsNetwork ttn(loraSerial,debugSerial,freqPlan);
LoRa::LoRa(){
}
void LoRa::init(){
// Set the callback
ttn.onMessage(this->message);
}
// Other functions
void LoRa::message(const uint8_t *payload, size_t size, port_t port)
{
// Stuff to do when reciving a downlink
}
and the header file
// File: LoRa.h
#ifndef LoRa_h
#define LoRa_h
#include "Arduino.h"
#include <TheThingsNetwork.h>
// Define serial interface for communication with LoRa module
#define loraSerial Serial1
#define debugSerial Serial
// define the frequency plan - EU or US. (TTN_FP_EU868 or TTN_FP_US915)
#define freqPlan TTN_FP_EU868
class LoRa{
// const vars
public:
LoRa();
void init();
// other functions
void message(const uint8_t *payload, size_t size, port_t port);
private:
// Private functions
};
#endif
I have tried:
ttn.onMessage(this->message);
ttn.onMessage(LoRa::message);
ttn.onMessage(message);
However none of them worked as I had expected.
You're trying to call a member function (that means, a function belonging to a member of a class type) without using a class member. That means, what you'd usually do is instantiate a member of your class LoRa first, then call it like:
LoRa loraMember;
loraMember.message();
Since you're trying to call that function from inside the class itself, without a member of the class calling the init(), you have to make the function static like:
static void message(const uint8_t *payload, size_t size, port_t port);
Then you can use LoRa::message() from anywhere as long as it's public, but calling it just like that will give you another compiler error, since the interface of message asks for "const uint8_t *payload, size_t size, port_t port". So what you'd have to do is call message like:
LoRa::message(payloadPointer, sizeVar, portVar);`
When you call ttn.onMessage(functionCall) what happens is that the function call gets evaluated, then what is returned by that function gets put into the parentheses and ttn.onMessage is called with that. Since your LoRa::message function returns nothing (void) you'll get another error here.
I suggest a good book on C++ basics to get you started - book list
Good luck!
I Solved the problem by making the message function a normal function outside the class. Not sure if it is good practice - but it works.
// File: LoRa.cpp
#include "Arduino.h"
#include "LoRa.h"
#include <TheThingsNetwork.h>
TheThingsNetwork ttn(loraSerial,debugSerial,freqPlan);
void message(const uint8_t *payload, size_t size, port_t port)
{
// Stuff to do when reciving a downlink
}
LoRa::LoRa(){
}
void LoRa::init(){
// Set the callback
ttn.onMessage(message);
}
You should pass arguments to massage as indicated by its prototype:
void message(const uint8_t *payload, size_t size, port_t port);
Since massage returns void, it should not be used as an argument to other functions.
Related
I'm not an expert with C++ since I come from an electronics background.
I'm trying to make a Arduino program that allows anyone to add a sensors easily to a Arduino device using a standard format.
I thought of making a HAL for each sensor, for that I have created a class named Sensor which is the base class for each sensor. The user has to create a subclass that inherits from the Sensor class. This subclass for example is called Sensor_2 (2 is the ID) and it implements functions like:
uint16_t getID( void );
uint8_t getAvailableChannels( void );
void sampleChannel( uint8_t aChannel, uint8_t *aDataSize, uint8_t aDataBuffer[] );
This class is the one that calls its own sensor library which is dependent of the sensor.
Doing it this way I can sample every sensor in an standard way without having to rewrite each sensor library.
I don't know if that is the way to do it but I can't think of anything better.
I have tried to implement that with the following code:
Sensor.h
#ifndef SENSOR_H
#define SENSOR_H
#include "Arduino.h"
class Sensor
{
public:
Sensor();
virtual uint16_t getID( void );
virtual uint8_t getAvailableChannels( void );
virtual void sampleChannel( uint8_t channel, uint8_t dataSize, uint8_t dataBuffer[]);
};
#endif
Sensor_2.h
#ifndef Sensor_2_H
#define Sensor_2_H
#include "Arduino.h"
#include "../../Sensor.h"
#define ID 2
#define CHANNELS 1
class Sensor_2: public Sensor
{
public:
Sensor_2 ( void );
virtual uint16_t getID( void );
virtual uint8_t getAvailableChannels( void );
virtual void sampleChannel( uint8_t aChannel, uint8_t *aDataSize, uint8_t aDataBuffer[] );
};
#endif
Sensor_2.cpp
#include "Sensor_2.h"
Sensor_2::Sensor_2( void )
{
}
uint16_t Sensor_2::getID( void )
{
return (ID);
}
uint8_t Sensor_2::getAvailableChannels( void )
{
return (CHANNELS);
}
void sampleChannel( uint8_t aChannel, uint8_t *aDataSize, uint8_t aDataBuffer[] )
{
aDataSize = 1;
aDataBuffer[0] = hallRead();
}
main.cpp
#include <Logger.h>
#include "ComHandler.h"
#include "./Sensors/Sensor_2/Sensor_2.h"
ComHandler comHandler;
SensorManager* sensorManager = SensorManager::getInstance();
void setup()
{
Serial.begin(115200);
Logger::setLogLevel(Logger::WARNING);
Sensor_2 sensorHall = new Sensor_2;
sensorManager->addSensor(sensorHall);
}
void loop()
{
uint8_t* datasize;
uint16_t buffer[4];
comHandler.checkForData();
sensorManager.getAvailableSensors()[0].sampleChannel(0,dataSize, buffer);
}
The problem is that when trying to compile I get this error:
conversion from 'Sensor_2*' to non-scalar type 'Sensor_2' requested
Sensor_2 sensorHall = new Sensor_2;
^
If instead of:
Sensor_2 sensorHall = new Sensor_2;
I use:
Sensor_2 sensorHall;
I get:
sketch/Sensor.cpp.o:(.literal._ZN6SensorC2Ev+0x0): undefined reference to `vtable for Sensor'
sketch/Winja.ino.cpp.o:(.literal._Z5setupv+0x10): undefined reference to `Sensor_2::Sensor_2()'
sketch/Winja.ino.cpp.o: In function `setup()':
Do you think this is a good way to implement a solution to my problem? If so, how could I fix my error?
If I understood the problem, here you have two issues (one is blocking, the other not).
As for the simplest problem, Sensor_2 sensorHall = new Sensor_2; is not valid, since the new keyword generates a pointer to the object. You have two ways to generate an object and to pass it to the sensor manager (I assume the sensor manager accepts pointer to sensors):
// Solution 1
Sensor_2 *sensorHall = new Sensor_2;
sensorManager->addSensor(sensorHall);
// Solution 2
Sensor_2 sensorHall;
sensorManager->addSensor(&sensorHall);
Please note, however, that if you use solution 2 you must put the sensor definition outside the function. If, for instance, you write
void setup() {
Sensor_2 sensorHall;
sensorManager->addSensor(&sensorHall);
}
then the sensor object will be destroyed after you exit the setup. In order to avoid this, write
Sensor_2 sensorHall;
void setup() {
sensorManager->addSensor(&sensorHall);
}
As for the main problem, I think that arduino does not compile source files outside the main sketch folder (and it does not recursively, so subfolders are not scanned).
However, what you are trying to do is usually done by implementing libraries. You can find different libraries and resources to understand how a library work (for instance, there is a library tutorial on the arduino website). You will have to create a folder inside the library folder, then put inside the source files (in this case you can use subfolders); the compilation will be successful. This way you won't need to copy these files in future projects: they will already be there.
If you don't want to make them shared, and still want to put them in a separate folder, IIRC you can make a special folder called src and put the source files there (again, not in subfolders). The src folder gets merged with the sketch folder when compiling.
My suggestion: make it a library. Fully reusable, easy to maintain, even a bit of highlighting...
In class Foo I have two methods, assign_handler() and call_handler().
The actual handler code is in the main.cpp which is do_this(). do_this() uses the some global variables in main.cpp,
I think Foo has to have a function pointer as member which will be assigned in assign_handler() which is what I did. However I'm having trouble invoking assign_handler() i.e. calling do_this(), from call_handler().
Note: call_handler() itself is call by a sigaction in Foo.
EDIT: I tried producing a MCVE as suggested in the comments. I've used gedit to create the files and compile it using g++ in command line. The code works. However in my Eclipse project I get the errors shown in inline comments of the code.
MCVE:
//Foo.h
class Foo{
public:
void (*funptr)(void);
void call_handler();
void assign_handler (void(*func1)(void));
Foo(){};
};
//Foo.cpp
#include "Foo.h"
void Foo::assign_handler(void(*func1)(void)){
funptr = func1;
}
void Foo::call_handler(){
funptr();//error: invalid use of member Foo::funptr in static member function; from this location
//or
//this->funptr();//error: 'this' is unavailable for static member functions
}
//main.cpp
#include <iostream>
#include "Foo.h"
using namespace std;
void do_this(void);
int main(void){
Foo foo;
foo.assign_handler(do_this);
foo.call_handler(); //this won't be called explicitly, it is assigned as a handler for a sigaction
int x;
cin>>x;
}
void do_this(void){
cout<<"done"<<endl;
}
I'll divide my answer in two parts. First I'll attempt to answer your question, then I'll attempt to tell you what you actually want to do.
Your question is how to assign a function pointer to a member variable and then call it from a static member function. Since the function pointer is a member of the class you will also require a pointer to the class in order to call the function pointer. A way of achieving this is to add a static member to your class that holds a pointer to the (single) instance of your class. Since you indicated that you will be using this as a signal handler, you won't want to use multiple handlers anyway.
So, something like this:
//Foo.h
class Foo{
public:
static void call_handler();
void assign_handler (void(*func1)(void));
Foo() {
ms_instance = this;
};
private:
void (*funptr)(void);
static Foo *ms_instance;
};
//Foo.cpp
#include "Foo.h"
void Foo::assign_handler(void(*func1)(void)){
funptr = func1;
}
void Foo::call_handler(){
ms_instance->funptr();
}
A more general way would be to store a function object:
//Foo.h
#include <functional>
#include <utility>
class Foo{
public:
static void call_handler();
template<typename func>
void assign_handler (func&& handler)
{
m_handler = std::forward(handler);
}
Foo() {
ms_instance = this;
};
private:
std::function<void(void)> m_handler;
static Foo *ms_instance;
};
//Foo.cpp
#include "Foo.h"
void Foo::call_handler(){
ms_instance->m_handler();
}
This way you can assign lots of different stuff as the handler:
// Function pointers
foo.assign_handler(do_this);
// Lambdas
foo.assign_handler([]() { /* do something */ });
// Binds - you should probably prefer lambdas...
foo.assign_handler(std::bind(&MyClass::member_func, &myObj));
Now what you actually want to do when you are going to handle a signal is a bit more complicated. Remember that signal handlers can only call certain functions (async-signal-safe functions) - otherwise things may get ugly. Therefore there is a common trick that you should perform called the self pipe trick. Essentially you should have a signal handler that receives the signal, but only calls write on a pipe with the signal number as the data to send. Then you have another place in your code that calls select on the pipe and then read to read the signal number. You then call the appropriate handler function which is then allowed to do whatever you like.
An example of this is here: http://man7.org/tlpi/code/online/book/altio/self_pipe.c.html
Be aware that it can be slightly tricky to get this right in a cross-platform manner, especially if multithreaded.
I'm trying to develop a networking part in my basic game engine in C++, but I'm faced with a rather strange problem (it is for me).
I got a Singleton Networker class that handles the set-up of a socket (UDP) and will try to register the username the client provided to the server, returning a bool that represents if the username is already taken by a different player or not. The class itself does not handle the packets itself, I aim to use a Packethandler class for that.
The problem is that I don't want a client to be able to create a PacketHandler directly because the entire point of the Networker class is to provide some kind of interface for handling that. The first idea I had is 'make the constructor of Packethandler private and create a Singleton' but then ofcourse the client can still ask the instance. Then I quickly though 'well protected then' but Networker is not extending PacketHandler. Then I thought 'well let's make Networker a friend of PacketHandler'. All the info I found up till now seems to discourage Friend usage however, so I wonder:
Is my plan for the simple networking part flawed thus facing me with an issue like this or is my problem the reason friend functionality exists in the first place? What is the take of you guys on this, do you have a much better idea?
Edit: code of my idea.
Packethandler.h
#ifndef FANCY_PACKET_HANDLER
#define FANCY_PACKET_HANDLER
#include <SFML/Network.hpp>
namespace fancy {
namespace network {
class PacketHandler
{
friend class Networker;
private:
sf::IpAddress _hostAddress;
sf::UdpSocket _socket;
PacketHandler(std::string hostAdress);
public:
~PacketHandler();
void sendPacket(const char* packet_data, const unsigned int packet_size);
char* receivePacket();
};
}
}
#endif
Networker.h
#ifndef FANCY_NETWORKER
#define FANCY_NETWORKER
#include <SFML/Network.hpp>
#include <Engine/PacketHandler.h>
namespace fancy {
namespace network {
class Networker
{
public:
static Networker* instance();
bool openUdpSocket(unsigned short port);
bool registerUsername(char* username);
char* receiveOnSocket();
protected:
Networker();
private:
static Networker* _instance;
static PacketHandler* _packetHandler;
const char* _username;
sf::IpAddress _hostAddress;
sf::UdpSocket _socket;
};
}
}
#endif
If you wish to provide an interface and hide all the implementation details, you'd better define a pure virtual class (e.g. Networker) which is visible to a user (say in .h-file), and write an implementation in a descendant class (e.g. NetworkerImpl) which is NOT visible to a user. You can then declare in the header file a function (or even a static method of the Networker class) like Networker *CreateNetworker(); (so the declaration is visible to a user), and then implement the function in .cc file along with your NetworkerImpl (so that the implementation is not visible to a user) like return new NetworkerImpl();.
I have some code that I wanted to put into a library which uses another library, SoftwareSerial. Now I added the SoftwareSerial.h and SoftwareSerial.cpp files to the same folder as the library I'm creating.
My header file looks something like this:
#ifndef MyLibrary_h
#define MyLibrary_h
#include "Arduino.h"
#include "SoftwareSerial.h"
#define MyLibrary_VERSION 1 // software version of this library
//DEFINE ALL CLASS VARIABLES
#define DATA_BUFFER_SIZE 50 //soft serial has 63 byte buffer.
class MyLibrary
{
public:
MyLibrary(uint8_t port_in, uint8_t port_out);
float getSomeValue(uint8_t some_index);
private:
SoftwareSerial _serial;
//Not sure if I should add the constructors below to the above declaration.
//(uint8_t in_pin=4, uint8_t out_pin=5, bool logic_reversed = false);
float convertSomeValue(byte upperbyte, byte lowerbyte);
void flushSerialBuffer();
};
#endif
My .cpp file looks like this:
#include "Arduino.h"
#include "MyLibrary.h"
#include "SoftwareSerial.h"
MyLibrary::MyLibrary(uint8_t in_pin, uint8_t out_pin)
{
bool logic_reversed = false;
this->_serial(in_pin*, out_pin*, logic_reversed);
//I tried the declaration below as well.
//SoftwareSerial _serial(in_pin*, out_pin*, logic_reversed);
}
float MyLibrary::getSomeValue(uint8_t sensor_index) {
float someValue = 1.1;
return someValue;
}
float MyLibrary::convertSome(byte upperbyte, byte lowerbyte) {
float someValue = 0.9;
return someValue;
}
void MyLibrary::flushSerialBuffer() {
//Flush serial buffer
while(_serial.available())
char c = _serial.read();
}
I would like SoftwareSerial to be a private field in MyLibrary (preferably static but not necessary) but I've tried many was of declaring it but nothing seems to work. I keep getting errors like no matching function for call to 'SoftwareSerial::SoftwareSerial() or invalid use of qualified-name 'MyLibrary::_serial'.
I got it to compile fine once by declaring static SoftwareSerial _serial; in my .h file, and SoftwareSerial MyLibrary::_serial(4,5,false); at the top of my .cpp file. The thing is, I would like to set the ports of _serial in my constructor for MyLibrary (so I can create a MyLibrary that uses specific in/out pins for SoftwareSerial) and not have them explicitly declared at the top of the .cpp file.
I'm not so familiar with C coding and Arduino so it would be a great help if someone could explain to me how to declare these properly in the .h file and instanciate them with the correct ports in the MyLibrary constructor or a MyLibrary.begin() function (or something of the like).
Thanks in advance for you helpful comments.
What you need is to make your constructor do the initialization as follows:
class MyLibrary{
public:
MyLibrary(uint8_t, uint8_t);
//...
private:
SoftwareSerial _serial;
//...
};
MyLibrary::MyLibrary(uint8_t in, uint8_t out)
: _serial(in, out)
{
//do initialization
}
This syntax might seem strange at first, but although it isn't quite as pretty, it clearly differentiates initialization of variables vs operations on variables, which is something that placing the initialization in the body of the constructor can make slightly fuzzy. As a rule, UNLESS you use this syntax to initialize a member variable, C++ will call the default constructor, which will cause a compile error iff the member does not have a callable default constructor.
Today it's the day of strange things....
Got a stupid hpp file and another stupid cpp file trying to implement a stupid class.
Here they are:
// HPP
#ifndef _WFQUEUE_MANAGER_PROXY_HPP_
#define _WFQUEUE_MANAGER_PROXY_HPP_
#include <iostream>
#include <string>
#include "workflow.hpp"
#include "wfqueue.hpp"
//-----------------------------------------------------------------------------
// Enum, struct, aliases
namespace middleware {
typedef struct {
std::string proxy_ipaddr; /* IP address to manager */
std::string proxy_port; /* Port to manager */
} WFProxyConfig;
}
//-----------------------------------------------------------------------------
// Class definitions
namespace middleware {
/*!
* This class provides network interface to access the workflow queue. It is
* important to notice that constructor is private in order to let a factory
* perform such a work.
*/
class WFQueueManagerProxy : public WFQueue {
/*!
* To let factory build properly this object, we provide access to every
* part of it.
*/
friend class WFQueueProxyFactory;
private:
/*!
* Privately constructs the object. Default configuration with loopback
* address and invalid port.
*/
WFQueueManagerProxy();
public:
/*!
* Destructor
*/
~WFQueueManagerProxy();
/*!
* Enqueues a workflow.
*/
void enqueue(const Workflow& workflow);
/*!
* Dequeues a workflow.
*/
const Workflow& dequeue();
private:
/*!
* Privately constructs the object. Assigning configuration.
*/
void ConfigureProxy(WFProxyConfig conf);
/*!
* Parameters for proxy.
*/
WFProxyConfig _config;
}; /* WFQueueManagerProxy */
} /* middleware */
#endif
Here the other
// CPP
#include "wfqueue_manager_proxy.hpp"
using namespace middleware;
//-----------------------------------------------------------------------------
// Constructors and destructor
/* Private constructor */
WFQueueManagerProxy::WFQueueManagerProxy() {
(this->_config).proxy_ipaddr = "127.0.0.1";
(this->_config).proxy_port = "0";
}
/* Destructor */
WFQueueManagerProxy::~WFQueueManagerProxy() {
}
//-----------------------------------------------------------------------------
// Public members
/* Enqueue */
void WFQueueManagerProxy::enqueue(const Workflow& workflow) {
}
/* Dequeue */
const Workflow& WFQueueManagerProxy::dequeue() {
}
//-----------------------------------------------------------------------------
// Private members
void WFQueueManagerProxy::ConfigureProxy(WFProxyConfig conf) {
}
Somebody please explain me why g++ tells me this:
wfqueue_manager_proxy.cpp: In
constructor
‘middleware::WFQueueManagerProxy::WFQueueManagerProxy()’:
wfqueue_manager_proxy.cpp:32: error:
‘class
middleware::WFQueueManagerProxy’ has
no member named ‘_config’
wfqueue_manager_proxy.cpp:33: error:
‘class
middleware::WFQueueManagerProxy’ has
no member named ‘_config’
wfqueue_manager_proxy.cpp: At global
scope: wfqueue_manager_proxy.cpp:51:
error: variable or field
‘ConfigureProxy’ declared void
wfqueue_manager_proxy.cpp:51: error:
‘WFProxyConfig’ was not declared in
this scope
ABSURD...
It does not recognize that typedef and doesn't recognize a private member too... and, more than everything... why does not g++ recognize a member function trying to see it as a variable?????????
I have tried everything...
PS (to who saw my earlier post): my virtual machine now is not the cause. I checked and got confirm that no virtual hard disk is corrupted or in collision with other virtual mem units.
Just a guess. Shouldn't it be
WFQueueManagerProxy::WFQueueManagerProxy() {
(this->_config).proxy_ipaddr = "127.0.0.1";
(this->_config).proxy_port = "0";
}
I get the error you are getting when I remove the declaration of WFProxyConfig (or change the name declared). Are you sure you posted the exact code that is producing the error?
Identifiers with leading underscores are reserved (include guards as well as _config). I'd be a little surprised if one of these is your problem - but not that surprised.
_config might even be a g++ extension keyword.
OK, this was the error....
I also compiled headers.. many gch were so created.... g++ didn't update those precompiled headers and got an old code... that's why it was indifferent to any change I did... sorry for disturb you guys... thanks a lot for your help