I've sort of programmed myself into a corner and in the process, realized that I am really lacking in my understanding of c++ function pointers as well as virtual functions. The goal is to implement a temperature controller on a raspberry pi. I won't go into detail on the other components as they are not relevant. I am currently working on the button controller. This is more of an architecture question.
- TempCtrl is the main class that calls all others. It also calls the ButtonController::addButton() to register buttons, and contains the callbacks.
- ButtonCtrl reads the gpio registers and cycles through the registered buttons stored in a vector of type Button.
- Button class was supposed to be a very simple container which had nothing other than an integer specifying the gpio, and callbacks. This is where the problem is.
I've never really done anything like this before, but I wanted something really clean. Basically, once I finish the button controller I wanted to be able to leave it alone unless I was adding functionality. For this reason, I wanted callback functions to be defined in the TempCtrl Function.
So far this has not worked. I'm sure my syntax is off if it is even possible. I would also be interested in alternative ways of achieving this.
Code below. I only posted the relevant headers, and the buttoncontroller.cpp as there is quite a lot of code. I will be glad to post more code if more information is needed, so please just ask:
button.hpp
#ifndef BUTTON_HPP
#define BUTTON_HPP
#include <ctime>
#include <cstdint>
#define HOLDTIME 500 // milliseconds
class TempCtrl;
enum State_E
{
BP_LOW,
BP_HIGH
};
class Button
{
public:
Button(
uint8_t _gpio,
void(TempCtrl::*)(),
void(TempCtrl::*)(),
void(TempCtrl::*)());
~Button();
void update(State_E newValue);
uint8_t getGpio() const;
private:
void (TempCtrl::*onFallingEdge)();
void (TempCtrl::*onLongHold)();
void (TempCtrl::*onRisingEdge)();
uint8_t gpio;
State_E state;
time_t timeStamp;
};
#endif /* BUTTON_HPP */
buttonprocessor.hpp
#ifndef BUTTONPROCESSOR_HPP
#define BUTTONPROCESSOR_HPP
#include "button.hpp"
#include <cstdint>
#include <vector>
#define GPIO_MAX 53
#define BLOCK_SIZE (4*1024)
#define GPLEV0 13
#define GPLEV1 14
#define SCAN_RATE 100 // milliseconds
class ButtonProcessor
{
public:
ButtonProcessor();
virtual ~ButtonProcessor();
bool init();
bool shutdown();
size_t addButton(Button button);
void startEventLoop(bool &terminate);
private:
int fd;
volatile uint32_t *gpio_base;
std::vector<Button> buttonDb;
};
#endif /* BUTTONPROCESSOR_HPP */
tempctrl.hpp
#ifndef TEMPCTRL_HPP
#define TEMPCTRL_HPP
#include "button.hpp"
#include "lcdscreen.hpp"
#include "buttonprocessor.hpp"
#include <cstdlib>
#include <vector>
#include <string>
#include <time.h>
#include <cstring>
#include <memory>
#define W1_DEV_ROOT "/sys/bus/w1/devices/w1_bus_master1/"
#define W1_SLAVE_COUNT W1_DEV_ROOT "w1_master_slave_count"
#define W1_SLAVES W1_DEV_ROOT "w1_master_slaves"
#define POLL_FREQ 1000
/***********************************************
* A structure for holding a single data point *
* of temperature in degrees celsius, as well *
* as the temp probe ID and a time stamp. *
************************************************/
struct TempStruct
{
time_t ts;
std::string id;
float temp;
};
enum TScale_E
{
CELSIUS,
FARENHEIT,
KELVIN,
RANKINE,
MAX_VALUE_TSCALE
};
#define DEFAULT_TEMP_SCALE FARENHEIT
enum InputMode_E
{
SETPOINT,
LOAD_PROFILE,
PID_TUNE,
MAX_VALUE_INPUT_MODE
};
class TempCtrl
{
public:
TempCtrl();
virtual ~TempCtrl();
/***********************************************
* Fetches the current time from the specified *
* temperature controller, and stores the *
* returned value with time stamp and device *
* id, in the tempStruct array.
************************************************/
void getTemp(int);
void setTempScale(TScale_E);
void lcdToggleEnable(int bits);
void wait(size_t seconds);
void printTemp(enum TScale_E);
std::vector<std::string> slavesArr;
std::vector<TempStruct> tempStruct;
TScale_E tempScaleVal = CELSIUS;
int fd;
// These should not be public
void onFallingEdge();
void onLongHold();
void onRisingEdge();
private:
void lcdInit();
uint8_t tempInit(void);
/***********************************************
* exclusive access to atomic safe lcdscreen *
* manipulation. Logic is completely decoupled *
************************************************/
std::unique_ptr<LcdScreen> mLcdScreen;
/***********************************************
* The responsibility of the button processor *
* is to detect edge changes in for specified *
* GPIO's, determine the type of press and call *
* the relavant callback. *
************************************************/
std::unique_ptr<ButtonProcessor> mButtonProcessor;
};
#endif /* TEMPCTRL_HPP */
buttonprocessor.cpp
#include "button.hpp"
Button::Button(
uint8_t _gpio,
void(TempCtrl::*_onFallingEdge)(),
void(TempCtrl::*_onLongHold)(),
void(TempCtrl::*_onRisingEdge)())
: state(BP_LOW),
timeStamp(time(NULL)),
onFallingEdge(_onFallingEdge),
onLongHold(_onLongHold),
onRisingEdge(_onRisingEdge)
{
}
Button::~Button()
{
}
void Button::update(State_E newValue)
{
if(
newValue != state &&
state == BP_HIGH) // Rising edge
{
timeStamp = time(NULL);
state = newValue;
// ((Button*)this)->Button::onRisingEdge();
}
else if(
state == BP_HIGH &&
newValue == state &&
((time(NULL) - timeStamp) > HOLDTIME)) // Long Hold
{
timeStamp = time(NULL);
state = newValue;
// ((Button*)this)->Button::onLongHold();
}
else if(
newValue != state &&
state == BP_LOW) // Falling edge
{
timeStamp = time(NULL);
state = newValue;
TempCtrl.(*((Button*)this)->Button::onFallingEdge());
//onFallingEdge();
}
}
uint8_t Button::getGpio() const
{
return gpio;
}
Aucun commentaire:
Enregistrer un commentaire