I am attempting to develop a "wrapper" Class that integrates multiple peripherals in a controller board including sensors, RGB LEDs an many others.
To achieve this, I am trying to group all connected peripherals in a structure inside the Controller Class and access its members through a struct pointer.
My end goal is to declare a controller and use the peripherals as follows:
Controller sys;
sys.devices -> rgb.setColor(/*color code*/);
since I find it more readable/understandable during development.
I have reduced my code to the bare minimum after several corrections based on other SOVF posts.
Please note that I am testing my code in Codelite using mingw64, however this will be implemented using platformio on a Teensy board. This is just a skimmed version for the forum
Physical pins are declared as a struct, in a pinout.h file:
#ifndef PINOUT_H
#define PINOUT_H
struct Pinout {
int R = 1;
int G = 2;
int B = 3;
};
#endif // PINOUT_H
then, there is an RGBLed class and a main file (I put them together here just for the sake of simplicity)
#include "pinout.h"
#include <iostream>
class RGBLed
{
public:
RGBLed(int pinR, int pinG, int pinB)
{
this->_r = pinR;
this->_g = pinG;
this->_b = pinB;
};
// this is just a dumb example method
bool turnOn()
{
this->_ledState = true;
return _ledState;
}
int* getPinout()
{
static int pinPtr[3];
pinPtr[0] = this->_r;
pinPtr[1] = this->_g;
pinPtr[2] = this->_b;
return pinPtr;
}
private:
int _r, _g, _b;
bool _ledState;
};
/* This is the _wrapper_ Class I am designing */
class Controller
{
public:
// Default Constructor
inline Controller(){};
struct Peripherals {
RGBLed rgb = RGBLed(_pins->R, _pins->G, _pins->B);
// on a previous compilation I used:
// RGBLed rgb = RGBLed(Controller::_pins->R, Controller::_pins->G, Controller::_pins->B);
// however I ran into linker issues
/* In the future many more devices will be declared here */
};
struct Peripherals *devices;
private:
// I want to keep the pins unreachable to the developer (aka myself and colleagues)
static Pinout* _pins; // I initially had a warning of "invalid use of non-static data member"
// after declaring it as static it went away
};
Then, my main() is:
int main()
{
// Controller object instance
Controller sys;
// Testing if we can call methods from the struct member inside the Class
if(sys.devices->rgb.turnOn())
std::cout << "LED is ON" << std::endl;
// Retrieve pinout
int* conn = sys.devices->rgb.getPinout();
std::cout << "RGBLed pins are: " << std::endl;
for(int idx = 0; idx < 3; idx++) {
//std::cout << std::to_string(conn[idx]);
if(idx != 2)
std::cout << ", ";
else
std::cout << " " << std::endl;
}
return 0;
}
If I comment the lines: int* conn = sys.devices->rgb.getPinout();
and std::cout << std::to_string(conn[idx]);
my code compiles just fine and, evidently, I don't get any valuable output.
However, if I call the .getPinout()
method from the rgb object inside the struct, I get the warnings:
"main.cpp...warning: 'sys.Controller::devices' is used uninitialized"
and
"main.cpp...note: sys.Controller::devices was declared here " pointing at the line: `Controller sys;"
I am absolutely certain that I might be butchering the C++ language hence I am asking here for some pointers (pun intended). I have mixed too many solutions I have found here in SOVF without any success.
What is the best way to compartmentalize my peripherals through a struct inside the Class? Is there a possibility that on top of my own mistakes, I am also facing compiler issues due to the mismatch between gcc (using 13) and the Arduino gcc compiler?
EDITS:
Based on the comments from @273K and @KIIV I realised that effectively I was missing the initialization of the struct devices since I was declaring only a pointer with nothing in it.
Now, I am facing another rather minor issue, I guess.
I am unable to access the elements from the pinout struct. Please see above how they are initialised inside of the struct declaration
If I do this inside the Controller class, where the RGBLed receives numerical values
class Controller
{
public:
// Default Constructor
inline Controller(){};
struct Peripherals {
RGBLed rgb = RGBLed(1, 2, 3) ; // <--- pay attention to this line
};
Peripherals devs, *devices = &devs;
// devices = &devs;
// devices = malloc(sizeof(Peripherals)); // = new Peripherals{RGBLed(_pins->R, _pins->G, _pins->B)};
private:
static Pinout* _pins; // I initially had a warning of "invalid use of non-static data member"
};
I can successfully print the pinout:
However I am unable to access the predefined values inside the pinout struct.
If inside the struct Peripherals I do:
RGBLed rgb = RGBLed(Controller::_pins->R, 2, 3);
I get:
_"undefined reference to Controller::pins"
I am attempting to indicate that the scope is from the Class Controller
I have also tried moving the Pinout pointer inside of the Peripherals struct and changing the calling to the pins as:
RGBLed rgb = RGBLed(this->_pins->R, 2, 3);
getting a similar error _"undefined reference to Controller::Peripherals::pins"
Is it even possible to access the private member this way?
Based on @273K and @KIIV's comments, I realised that I was not declaring and initialising the pointer devices to the struct Peripherals.
The corrected Controller Class is the following:
class Controller
{
public:
// Default Constructor
inline Controller(){};
struct Peripherals {
RGBLed rgb = RGBLed(ledPins.R, ledPins.G, ledPins.B);
/* More devices to be added */
} devs;
Peripherals *devices = &devs;
};
where I redeclared the Pinout struct as:
struct Pinout {
int R = 1;
int G = 2;
int B = 3;
} ledPins; // <-- predeclaring the struct object
This way, I avoided unnecessary nesting of structs and I can use the Pinout object in the RGBLed constructor.
I can finally run my code without a problem:
Despite I am not a big fan of having two Peripherals objects accessible in the main() function (devs and the pointer devices), it is fine for now. I really wanted to have only ONE object to get access to all the peripherals - the pointer devices.
Thanks to all who helped!
:Beers: