I'm a C++ newbie and so far have written my code mostly in an not OO way. Since this is getting confusing I'd like to start creating libraries for some of the functionalities that I've implemented. The following program basically issues callback functions depending on a counter. It's made to detect the duration of a button press in a microcontroller project and issues certain functions accordingly.
What I'd like to achieve is that I can define an array or list of key values somewhere in the program and call the stateEval
function from within main().
const action action_table[] =
{
{ 4, state1 },
{ 8, state4 },
{ 11, state8 },
};
So far I've tried to wrap the stateEval
function into a class but then I simply don't know how to pass the action_table data into the class. The code below is the current working implementation without my desperate try to refactor it. I can't use STL libraries due to the uC environment that I am using. cout
would be replaced.
#include <iostream>
struct action
{
int counter_limit;
void (*transition)(void);
};
void state1() {
std::cout << __func__;
}
void state4() {
std::cout << __func__;
}
void state8() {
std::cout << __func__;
}
const action action_table[] =
{
{ 4, state1 },
{ 8, state4 },
{ 11, state8 },
};
int STATE =0;
void stateEval(int counter)
{
size_t size = sizeof(action_table) / sizeof(action_table[0]);
for (size_t i=0; i < size; i++)
{
const action &a = action_table[i];
if (counter < a.counter_limit)
{
a.transition();
return;
}
}
}
int main()
{
for (int counter = 0 ; counter < 11; ++counter)
stateEval(counter);
return 0;
}
This is how I would like to use my class:
const action action_table[] =
{
{ 4, state1 },
{ 8, state4 },
{ 11, state8 },
};
int main()
{
State_Caller sc;
sc.attach(action_table);
for (int counter = 0 ; counter < 11; ++counter)
sc.stateEval(counter);
return 0;
}
This is the mentioned (in the comment) "ticker" logic that shall go into the class as well which I initially left out to keep it simpler:
Ticker ticker;
InterruptIn pb(p17);
// Global count variable
int volatile counter = 0;
int volatile STATE = 0;
void countCallback(void) {
counter = counter + 1;
}
// pb Interrupt routine - is interrupt activated by a falling edge of pb input
void pb_hit_interrupt (void) {
ticker.attach(countCallback, 1);
counter = 0;
}
void pb_release_interrupt (void) {
ticker.detach();
stateEval();
counter = 0;
STATE = 0;
// pc.printf("Counter: %d \n", counter);
}
int main() {
// Use internal pullup for pushbutton
pb.mode(PullUp);
// Delay for initial pullup to take effect
wait(.01);
// Attach the address of the interrupt handler routine for pushbutton
pb.rise(&pb_release_interrupt);
pb.fall(&pb_hit_interrupt);
}
This is the code merging the sections "If you can't use C++11" and "working with interrupts"
#include "mbed.h"
Serial pc(USBTX, USBRX);
struct action
{
int counter_limit;
void (*transition)(void);
};
struct action_list
{
size_t size;
const action *table;
};
class ButtonHandler {
public:
/* ButtonHandler(PinName pin, float seconds, std::initializer_list<action> table)
: counter{0},
buttonPin{pin},
intervalInSeconds{seconds},
mTable{table.size(), table.begin()},
ticker{}
{ }
*/
ButtonHandler(std::size_t table_size, const action* begin, PinName pin, float seconds ) {
mTable.size = table_size;
mTable.table = begin;
buttonPin = pin;
intervalInSeconds = seconds;
}
void react(int counter) const {
const action *a = mTable.table;
for (std::size_t i=mTable.size; i; --i, ++a) {
if (counter < a->counter_limit) {
a->transition();
return;
}
}
}
void enable() {
buttonPin.mode(PullUp);
wait(0.01);
buttonPin.rise(this, &ButtonHandler::release);
buttonPin.fall(this, &ButtonHandler::press);
buttonPin.enable_irq();
}
void disable() {
buttonPin.disable_irq();
ticker.detach();
}
virtual ~ButtonHandler() {
disable();
}
protected:
void press() {
counter = 0;
ticker.attach(this, &ButtonHandler::secondsCount, intervalInSeconds);
}
void secondsCount() {
++counter;
}
void release() {
ticker.detach();
react(counter);
counter = 0;
}
private:
volatile unsigned counter;
InterruptIn buttonPin;
float intervalInSeconds;
action_list mTable;
Ticker ticker;
};
void state1() {
//std::cout << __func__;
pc.printf("state1");
}
void state4() {
//std::cout << __func__;
pc.printf("state4");
}
void state8() {
//std::cout << __func__;
pc.printf("state8");
}
PinName pin(p17);
//const int pb17 = 17;
//Action Table specifiying push duration and callback function
const action action_table[] =
{
{ 4, state1 },
{ 8, state4 },
{ 11, state8 },
};
int main()
{
const ButtonHandler green(
sizeof(action_table)/sizeof(action_table[0]),
action_table,
pin,
1
);
green.enable();
}
There're still two compiler errors:
Error: No default constructor exists for class "mbed::InterruptIn" in "main.cpp", Line: 32, Col: 94
Error: The object has type qualifiers that are not compatible with the member function in "main.cpp", Line: 117, Col: 6
action_table
dynamically created or is always in ROM? Also, could you show how you'd like to be able to use a class for this? That is, ideally what would code look like that uses it? \$\endgroup\$ – Edward Mar 24 '16 at 21:13