I am programming in arduino land. using a library AccelStepper.h with a class AccelStepper
I created an instance as follows:
AccelStepper panStepper(AccelStepper::DRIVER, PAN_STEP_PIN, PAN_DIR_PIN);
AccelStepper tiltStepper(AccelStepper::DRIVER, TILT_STEP_PIN, TILT_DIR_PIN);
AccelStepper dollyStepper(AccelStepper::DRIVER, DOLLY_STEP_PIN, DOLLY_DIR_PIN);
I want to be able to pass a reference to one of the instances and be able to change the parameters of that instance.
I am using the following to create a function to work on one of the instances as follows:
void CalibrateAxis(AccelStepper& stepper, int min_pin, int max_pin) {
this is screwing up the arduino compiler, causing it to put forward declarations for this function and others in the middle of a pragma in the main ino file as follows:
// RemoteXY configurate
#pragma pack(push, 1)
//
//
void CalibrateAxis(AccelStepper& stepper, int min_pin, int max_pin);
void CalibrateAll();
void StepperSetup();
void StepperLoop();
void writeProgram();
boolean readProgram();
void stepPan(int d);
void stepTilt(int d);
void stepDolly(int d);
void Run(int s);
void dumpProgram();
void dumpTest();
void PTDSetup();
void PTDLoop();
void StateMachineLoop();
#line 38 "C:\\Users\\chris\\OneDrive\\Documents\\Arduino\\RemoteXY Stuff\\PanTiltDollyVersion2\\PanTiltDollyVersion2.ino"
uint8_t RemoteXY_CONF[] =
{ 255,16,0,27,0,89,1,10,16,0,
130,1,8,1,84,7,29,130,1,8,
44,84,17,29,130,1,46,23,46,19,
not sure what I am doing wrong.....
Not sure how to accept an answer, but Delta_G gave a good solution. Thanks!
Have you tried just giving it your own forward declaration in a more appropriate place and see if that stops Arduino from trying to put it in for you? – Delta_G 1
Putting my own forward declarations fixed the issue.
fixed what the Arduino compiler could not do.
Related
I have noticed the following code, which is obviously invalid C++, compiles in Arduino IDE (using AVR-GCC):
// The program compiles even when the following
// line is commented.
// void someRandomFunction();
void setup() {
// put your setup code here, to run once:
someRandomFunction();
}
void loop() {
// put your main code here, to run repeatedly:
}
void someRandomFunction() {
}
What is going on here? C++ requires functions to be declared before they are used. When the compiler comes to the line someRandomFunction() in the setup() function, how does it know it will be declared?
This is what we call Forward declaration and in C++ it only requires you to declare the prototype of the function before attempting to use it, instead of defining the whole function.:
Taking as example the following two pieces of code:
CODE A:
#include <Arduino.h>
void setup(){}
void AA(){
// any code here
}
void loop(){
AA();
}
CODE B:
#include <Arduino.h>
void setup(){}
void loop(){
BB();
}
void BB(){
// any code here
}
Strictly speaking C requires that functions be forward declared for the compiler to compile and link them. So in CODE A we do not have declared the function but it defined, which makes it legal for proper C code. But the CODE B has the function definition after the loop, which would be illegal for plain C. A solution would be the following one:
#include <Arduino.h>
void BB();
void setup(){}
void loop(){
BB();
}
void BB(){
// any code here
}
This, however, to fit the Arduino script format of having a void setup() following from a void loop(), required Arduino to include a script on its IDE that automatically looks for functions and generate prototypes up top for you so you do not need to worry about it. So despite being written in C++, you will NOT see Arduino sketches using Forward declaration often in their sketches, as it works out fine and it is often easier to read having first setup() and loop().
Your file is .ino not .cpp. .ino is 'Arduino language'.
The main ino file with additional ino files are processed by the Arduino builder to C++ source and only then processed as C++ (preprocessor, compilation).
Is there a way to avoid the Graph:: repetition in the implementation file, yet still split the class into header + implementation? Such as in:
Header File:
#ifndef Graph_H
#define Graph_H
class Graph {
public:
Graph(int n);
void printGraph();
void addEdge();
void removeEdge();
};
#endif
Implementation File:
Graph::Graph(int n){}
void Graph::printGraph(){}
void Graph::addEdge(){}
void Graph::removeEdge(){}
I'm guessing this is to avoid lots of "unnecessary typing". Sadly there's no way to get rid of the scope (as many other answers have told you) however what I do personally is get the class defined with all my function prototypes in nice rows, then copy/paste into the implementation file then ctrl-c your ClassName:: on the clip board and run up the line with ctrl-v.
If you want to avoid typing the "Graph::" in front of the printGraph, addEdge etc., then the answer is "no", unfortunately. The "partial class" feature similar to C# is not accessible in C++ and the name of any class (like "Graph") is not a namespace, it's a scope.
No there's not. Not directly at least. You could go for preprocessor tricks, but don't do it.
#define IMPL Graph::
IMPL Graph(int n){}
void IMPL printGraph(){}
void IMPL addEdge(){}
void IMPL removeEdge(){}
Also, you shouldn't even want to do it. What's the point. Besides it being a C++ rule, it lets you know you're actually implementing a member function.
One option is using. If you have method definitions which are in a cpp file that never gets #included, then using is safe (doesn't affect other files):
foo.h:
class FooLongNameSpecialisationsParamaters
{
int x_;
public:
int Get () const;
void Set (int);
};
foo.cpp:
#include "foo.h"
using Foo = FooLongNameSpecialisationsParamaters;
int Foo::Get () const
{
return x_;
}
void Foo::Set (int x)
{
x_ = x;
}
main.cpp:
#include "foo.h"
int main ()
{
//Foo foo; <-- error
FooLongNameSpecialisationsParamaters foo;
return 0;
}
No, there is no way to avoid it. Otherwise, how would you know if a given function definition is for a class function or for a static function?
If you are asking if you can define a member function such as Graph::printGraph without specifying the class name qualification, then the answer is no, not the way that you want. This is not possible in C++:
implementation file:
void printEdge(){};
The above will compile just fine, but it won't do what you want. It won't define the member function by the same name within the Graph class. Rather, it will declare and define a new free function called printEdge.
This is good and proper, if by your point of view a bit of a pain, because you just might want two functions with the same name but in different scopes. Consider:
// Header File
class A
{
void foo();
};
class B
{
void foo();
};
void foo();
// Implementation File
void foo()
{
}
Which scope should the definition apply to? C++ does not restrict you from having different functions with the same names in different scopes, so you have to tell the compiler what function you're defining.
//yes it is possible using preprocessor like this:
#define $ ClassName //in .cpp
void $::Method1()
{
}
//or like this: in the header .h:
#undef $
#define $ ClassName'
// but you have to include the class header in last #include in your .cpp:
#include "truc.h"
#include "bidule.h" ...
#include "classname.h"
void $::Method() { }
//i was using also
#define $$ BaseClass
//with single inheritance than i can do this:
void $::Method()
{
$$::Method(); //call base class method
}
//but with a typedef defined into class like this it's better to do this:
class Derived : Base
{
typedef Base $$;
}
EDIT: I misread your question. This would be an answer to the question whether you can split header-files. It doesn't help you to avoid using LongClassName::-syntaxes, sorry.
The simple answer: You can split up c++-file, but you can not split up header-files.
The reason is quite simple. Whenever your compiler needs to compile a constructor, it needs to know exactly how many memory it needs to allocate for such an object.
For example:
class Foo {
double bar; //8 bytes
int goo; //4 bytes
}
new Foo() would require the allocation of 12 bytes memory. But if you were allowed to extend your class definitions over multiple files, and hence split header files, you could easily make a mess of this. Your compiler would never know if you already told it everything about the class, or whether you did not. Different places in your code could have different definitions of your class, leading to either segmentation faults or cryptic compiler errors.
For example:
h1.h:
class Foo {
double bar; // 8 bytes
int goo; // 4 bytes
}
h2.h:
#include "h1.h"
class Foo {
double goo; // 8 bytes
} // we extend foo with a double.
foo1.cpp:
#include "foo1.h"
Foo *makeFoo() {
return new Foo();
}
foo2.cpp:
#include "foo2.h"
void cleanupFoo(Foo *foo) {
delete foo;
}
foo1.h:
#include "h1.h"
Foo *makeFoo();
foo2.h:
#include "h1.h"
#include "h2.h"
void cleanupFoo(Foo *foo)
main.cpp:
#include foo1.h
#include foo2.h
void main() {
Foo *foo = makeFoo();
cleanupFoo(foo);
}
Carefully check what happens if you first compile main.cpp to main.o, then foo1.cpp to foo1.o and foo2.cpp to foo2.o, and finally link all of them together. This should compile, but the makeFoo() allocates something else then the cleanupFoo() deallocated.
So there you have it, feel free to split .cpp-files, but don't split up classes over header files.
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 do not really believe that this question was never asked before, but i really tried to search without success, if you got a link to an already answered similar question, please share it.
I am porting a C++/Win32 program to C++/CLI, and, of course, I am trying to make the fewer number of modifications possible to the code in order to speed-up the re-testing phase.
I am having some trouble due to global functions having objects as parameters, here a short example:
Class header file
namespace MyNamespace {
public ref class MyClass {
public:
void test();
};
}
Class cpp file
using MyNamespace;
void myFunction(MyClass ^obj);
void MyClass::test() {
myFunction(this);
}
And here comes the problem: if I leave out myFunction from MyNamspace, it cannot use MyClass as a parameter's type. If I include myFunction in MyNamespace, every cpp file will compile correctly, but i will get a linker error "LNK2028 unresolved token".
An idea is to define a new class and include myFunction as a public static method, but to do this will be a long job, because myFunction, in the real project, is not alone... Any other idea?
If MyClass is in MyNamespace and myFunction is not, you could use MyClass with full name qualification:
void myFunction(MyNamespace::MyClass ^obj);
Of course your myFunction should be implemented somewhere.
I made some tests following Nikita's suggestion, and the final, working, code looks like this:
Class header file
namespace MyNamespace {
public ref class MyClass {
public:
void test();
};
}
Class cpp file
void myFunction(MyClass ^obj);
using MyNamespace;
void MyClass::test() {
myFunction(this);
}
Global function cpp file
using namespace MyNamespace;
void myFunction(MyClass ^obj) {
//do something
}
Using this approach in global function's cpp file is possible to use MyClass while myFunction remains (or pretend to remain) global, and MyClass::test can access myFunction even if not in the same namespace, just using a prototype declaration as in "old" c++.
I can't get method overriding to work. Right now I have a class called Sprite, and two subclasses; Let's call them Goomba and Koopa. Instances of Koopas and Goombas are stored in an std::list of sprites called spriteList, and an iterator goes through this list and calls each sprite's behave() function.
I can get this to work with Goombas alone, by defining the behavior function as Sprite::behave(). But if I try to do the same thing with Koopas, the compiler gets mad because Sprite::behave() is already defined in Goomba. What am I doing wrong? I get the feeling that the answer is an extremely simple syntax issue, but looking online yielded no examples that looked quite like my code.
I'll paste some code, hopefully it'll help. This isn't my exact source code, so I apologize for any typos.
//Sprite.h:
#ifndef SPRITE_H
#define SPRITE_H
class Sprite {
private:
float xPosition; float yPosition;
public:
Sprite(float xp, float yp);
void move(float x, float y); //this one is defined in Sprite.cpp
void behave(); //this one is NOT defined in Sprite.cpp
};
#endif
//Goomba.h:
#ifndef GOOMBA_H
#define GOOMBA_H
#include "Sprite.h"
class Goomba : public Sprite {
public:
Goomba(float xp, float yp);
void behave();
};
#endif
//Goomba.cpp:
#include "Goomba.h"
Goomba::Goomba(float xp, float yp): Enemy(xp, yp) {}
void Sprite::behave(){
Sprite::move(1, 0);
}
//Koopa.h looks just like Goomba.h
//Koopa.cpp
#include "Koopa.h"
Koopa::Koopa(float xp, float yp): Enemy(xp, yp) {}
void Sprite::behave(){
Sprite::move(-2, 1);
}
In Sprite you have to declare the function as virtual
virtual void behave();
Then in Goomba you should state that you are going to override that function
virtual void behave() override;
Note: The override keyword is new as of C++11
In both Koopa.cpp and Goomba.cpp you are defining Sprite::behave. This results in two definitions, as your toolchain told you. You want to define Koopa::behave and Goomba::behave, respectively, in those files.
You also want to define Sprite::behave in Sprite.cpp (you said you currently do not define it anywhere).
You will also want to make Sprite::behave a virtual function in order to get the polymorphic behavior you are after working the way you likely expect it to:
class Sprite {
// ...
// You can either define Sprite::behave in Sprite.cpp or change the declaration to:
// virtual void behave() = 0;
// to make it "pure virtual," indicating that subclasses must provide an implementation.
virtual void behave();
};
In Goomba.cpp, for example:
#include "Goomba.h"
Goomba::Goomba(float xp, float yp): Enemy(xp, yp) {}
void Goomba::behave(){
...
}