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.
Related
I have this piece of code
#ifndef STATION_H
#define STATION_H
#include <vector>
#include "Dispenser.h"
#include "Cashier.h"
//class Cashier;
class Station
{
private:
int price;
int dispenser_count;
int cashier_count;
std::vector<Dispenser> dispensers;
std::vector<Cashier> cashiers;
public:
Station(int, int, int);
int GetPrice() const { return price; }
Dispenser *LookForUnoccupiedDispenser(int &id);
Dispenser *GetDispenserByID(int id);
Cashier *LookForUnoccupiedCashier();
};
#endif // STATION_H
When I have the class Cashier line commented, the compiler fails with a 'Cashier' was not declared in this scope error even though Cashier.h was included. Uncommenting it makes it possible to compile but I'm concerned that it shouldn't be happening.
Cashier.h
#ifndef CASHIER_H
#define CASHIER_H
#include "Station.h"
class Station;
class Cashier
{
private:
bool busy;
Station *at_station;
public:
Cashier(Station *employer);
bool IsBusy() const { return busy; }
};
#endif // CASHIER_H
How is it possible? It's clearly declared in the header file and as far as I know, #include does nothing more than pasting the content of a file into another one.
Thank you for the answers in advance!
Your station.h includes cachier.h. This is an example of cyclic dependency. Given that you only have a pointer to Station in Cachier I'd suggest removing the dependency of station.h and forward declare it.
An #include is literally nothing more than verbatim copy and paste of that file into the current compilation unit. The guards protect you from the effect of an infinite include cycle, but due to the guards one of the #includes does nothing, i.e. does NOT suck in the declaration (nor definition) of the respective class. This results in the error you get. In station.h the compiler has never seen any mention of the Cachier type when it sees the Station type.
(Not sure whether this is exclusively a C/C++ issue)
I’m currently fragmenting elements of a large Arduino project into reusable libraries - so far soo good.
However, a number of methods in the libraries return special structs which are declared in a data-types.h file contained in each library. The problem I have now is I'm unable to import/utilise these structs in my main sketch. I've tried declaring a variable of the DataTypes class in the main library header file and accessing the structs through it, but I get error error: invalid use of 'struct DataTypes::_theStructNameHere_t'
How would I go about accessing these structs from the library in my main sketch to declare as a variable type? I don't want to have to copy the header file which contains the structs from the library into my sketch, and I also don't want to have to create a separate library just for this single header file of structs!
Here's a quick example of what I mean:
Main.cpp:
#include <Arduino.h>
#include <MyLibrary.h>
MyLibrary myLib;
void setup() {
(This is declared in the library) myLib.dataTypes._theStructNameHere_t response = myLib.getASpecialValueWhichIsOfType_theStructNameHere_t()// Gives "error: invalid use of 'struct DataTypes::_theStructNameHere_t'""
// Example usage of the struct:
Serial.print("\n Loop Card Status: ");Serial.print(response.loop_status, HEX);
if (response.number_allocated > 0) {
Serial.print("\n Devices Allocated: ");Serial.print(response.number_allocated, HEX);
} else {
if (response.loop_status != 0x123) {
// Some condition
} else {
// Something else
}
}
}
void loop() {
...
}
Library Structure:
src/
- /data-types/
- - data-types.h
- MyLibrary.cpp
- MyLibrary.h
Library Header MyLibrary.h:
#ifndef _MYLIBRARY_H_
#define _MYLIBRARY_H_
#include <Arduino.h>
#include "./helpers/helpers.h"
...
#include "./data-types/data-types.h"
class MyLibrary {
public:
Uart *_commPort;
Helpers helpers;
...
DataTypes dataTypes;
DataTypes::_theStructNameHere_t getASpecialValueWhichIsOfType_theStructNameHere_t();
...
protected:
private:
};
#endif // _MYLIBRARY_H_
DataTypes Class data-types.h:
#ifndef _RESPONSE_TYPES_H
#define _RESPONSE_TYPES_H
class DataTypes
{
public:
struct _theStructNameHere_t
{
bool successful;
uint8_t loop_status;
uint8_t number_allocated;
uint8_t highest_address;
uint8_t number_inputs;
uint8_t number_outputs;
}
..even more..
private:
}
#endif // _RESPONSE_TYPES_H
I was able to obtain a MCVE from your example:
class DataTypes
{
public:
struct _theStructNameHere_t
{
};
};
class Library
{
public:
DataTypes dataTypes;
DataTypes::_theStructNameHere_t getMyDataType();
};
int main(int argc, char *argv[])
{
Library myLib;
myLib.dataTypes._theStructNameHere_t response;
}
which gives a similar error as your code:
~$ g++ test.cpp
test.cpp: In function 'int main(int, char**)':
test.cpp:20:21: error: invalid use of 'struct DataTypes::_theStructNameHere_t'
myLib.dataTypes._theStructNameHere_t response;
The problem is that you use an instance to access the struct type/name. To fix it, replace
myLib.dataTypes._theStructNameHere_t response = ...;
with
DataTypes::_theStructNameHere_t response = ...;
Notes:
Instead of using classes to create separate namespaces, please consider using namespaces directly. This is a feature of C++ which is available under Arduino.
namespace Library {
namespace DataTypes {
struct _theStructNameHere_t
{
...
};
...
} /*** namespace Library::DataTypes ***/
} /*** namespace Library ***/
Please read StackOverflow guidelines concerning how to ask a good question, in particular the section about Mininimal, Complete and Verifiable Example.
Sooner or later someone will tell you that there is no such thing as C/C++; C is C and C++ is C++; Arduino lives in its own world, even if is based on C++. Thus, you might want to remove C and C++ tags from your question.
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...
I'm currently trying to make a game in C++. In my code I'm trying to nest my variables so that my main doesn't have a lot of includes. My problem right now though is that the value of my variables in my class aren't changing. Stepping through the code it shows it setting the value, but it doesn't work. Anyone know what's going on? Thank you in advance.
This is what I have so far:
Location.h
#ifndef LOCATION_H
#define LOCATION_H
#include <string>
class Location
{
public:
Location(void);
Location(std::string name);
~Location(void);
std::string GetName();
void SetName(std::string value);
private:
std::string m_Name
};
#endif
Location.cpp
#include "Location.h"
Location::Location(void): m_Name("") {}
Location::Location(std::string name): m_Name(name) {}
Location::~Location(void)
{
}
std::string Location::GetName()
{return m_Name;}
void Location::SetName(std::string value){m_Name = value;}
PlayerStats.h
#ifndef PLAYERSTATS_H
#define PLAYERSTATS_H
#include "Location.h"
class PlayerStats
{
public:
PlayerStats(void);
~PlayerStats(void);
Location GetLocation();
void SetLocation(Location location);
private:
Location m_Location;
};
#endif
PlayerStats.cpp
#include "PlayerStats.h"
PlayerStats::PlayerStats(void): m_Location(Location()) {}
PlayerStats::~PlayerStats(void)
{
}
Location PlayerStats::GetLocation(){return m_Location;}
void PlayerStats::SetLocation(Location location){m_Location = location;}
main.cpp
#include <iostream>
#include "PlayerStats.h"
using namespace std;
PlayerStats playerStats = PlayerStats();
int main()
{
playerStats.GetLocation().SetName("Test");
cout<< playerStats.GetLocation().GetName()<<endl;
return 0;
}
Your immediate issue is that
Location GetLocation();
returns a copy of the location, so when you call SetName here:
playerStats.GetLocation().SetName("Test");
You're changing the name of the temporary copy, and the change is lost as soon as the semicolon is hit.
More broadly, this kind of design (nesting classes and nesting includes so that main doesn't have a lot of includes, and using a.b.c() style code to access nested members) isn't great C++ style:
Having a bunch of source files that (transitively) include a bunch of header files means that changing a single header file will trigger recompilations of a bunch of source files. Compile times can be a significant issue in larger C++ projects, so reducing compile times by controlling #include's is important. Read up on "forward declarations" for more information.
Writing code like a.b.c() is considered bad object-oriented design, because it reduces encapsulation: not only does the caller have to know about a's details, it has to know about b's also. Sometimes this is the most expedient way to write code, but it's not something to be blindly done just to reduce #include's. Read up on "Law of Demeter" for more information.
If you want to set the result of playerStats.GetLocation(), you could make GetLocation() pass-by-reference (use ampersand, &, on the return argument). Otherwise you are just setting values in a temporary copy of PlayerStats::m_Location.
Alternatively, you could use the SetLocation() function.
I am programming on linux using g++ and I often encounter the problem that I need to use a class or data type in a header file which I define later, either at a later point in the header or in another header file.
For instance look at this header file:
class example
{
mydatatype blabla;
};
struct mydatatype
{
int blablainteger;
char blablachar;
};
This will give error because mydatatype is used before its defined
so usually I change it like this:
struct mydatatype; // <-- class prototype
class example
{
mydatatype *blabla; // <-- now a pointer to the data type
// I will allocate the data during runtime with the new operator
};
struct mydatatype
{
int blablainteger;
char blablachar;
};
Now it works. I could often just put the definition above, or include the header which is needed, but I don't want to include headers in a header or juggle with the definition order, it always gets messy.
The solution I showed usually works, but now I have encountered a new phenomenon. This time the datatype is not a class but a typedef, I cant use prototypes for a typedef and I don't want to use the actual datatype which the typedef incorporates.. it's messy too.
Is there any solution to this?
Firstly, the solution you've thought of (prototype and pointer), is unneeded, and slower than just implementing it without the pointer.
The "proper" solution for this, would be creating seperate headers for each type, and then include them in your other header. That way it will always be defined! You can even make them so that they include eachother.
However, if you've ever opened a .h file provided by g++, you've most likely seen this at the start of the header:
#ifndef SOMETHING_H
#define SOMETHING_H
// Code
#endif /* SOMETHING_H */
This is to solve the issue of types redefining themselves.
If they weren't there, and you included the header file multiple times, the types would be redefined, and an error would be thrown. This makes it so that the types are always present, but never included twice.
I hope that helps!
Place each class/type in it's own header file, and then include the relevant header file in other headers where you need it. Use an inclusion guard in each header e.g.:
// SomeHeaderFile.h
#ifndef SOME_HEADER_FILE_H
#define SOME_HEADER_FILE_H
// code
#endif
I disagree that this is messy - it allows you have an organised structure to you project, it allows each class to operate independently of others and without worrying about order, and it's a good idea to place each class in it's own file anyway.
You could just define the class inside the other class like
template<class T>
class vertex {
private:
class edge {
public:
vertex<T> *to;
double weight;
edge() {
weight = INFINITY;
to = NULL;
};
} *paths;
T data;
unsigned nof_paths;
public:
vertex(T val) {
data = val;
paths = NULL;
nof_paths = 0;
}
void addPathTo(vertex<T>*&);
edge* getAllPaths() {
return paths;
};
};
Obviously this works for small classes... if your class is ENORMOUS you'll be better using separate header files like the other guys said.