I'm totally new to C/C++. I've done some higher languages like Java and C# but that's something else I must say. I'm trying to build a timer module for the Arduino so that I can easily queue work that has to be executed after a certain amount of time without the use of delay()
. I would like to create it as intuitively as possible so that I can easily re-use it.
So far I've tried a lot of different approaches. What I did is mostly read tutorials on how to achieve a certain thing in C/C++ and created my little project out of that.
Main .ino file:
#include "Timer.h"
Timer timer;
void setup()
{
// Init the timer
timer.init();
pinMode(13, OUTPUT);
// Define the state
int state = 1;
// Create the action
TimerAction action;
action.create(1000, &timerElapsed, 1 -1);
action.state = &state;
}
void loop()
{
timer.run();
}
void timerElapsed(TimerAction action) {
int *state = (int*)action.state;
if (state == 0) {
digitalWrite(13, HIGH);
*state = 1;
}
else
{
digitalWrite(13, LOW);
*state = 0;
}
}
It's very simple. I'm trying to blink the onboard led as a proof of concept.
This is the Timer.h
file:
#ifndef _TIMER_h
#define _TIMER_h
#if defined(ARDUINO) && ARDUINO >= 100
#include "arduino.h"
#else
#include "WProgram.h"
#endif
struct Timer {
TimerAction* actions;
uint8_t size;
void init();
void queue(TimerAction action);
void dequeue(TimerAction action);
void dequeueIdx(int idx);
void run();
};
struct TimerAction {
// Sets whether to repeat the action
uint8_t repetitive;
// Sets how many times to repeat the action, -1 for infinite
// Will only be used when repetitive == 1
long finite;
void (*callback)(TimerAction sender);
void *state;
unsigned long last;
unsigned long interval;
void create(long interval, void(*callback)(TimerAction sender), uint8_t repetitive = 0U, long finite = -1L);
};
#endif
This is the Timer.ino
file:
#include "Timer.h"
void Timer::init() {
size = 0;
actions = new TimerAction[10];
}
void Timer::queue(TimerAction action) {
action.last = millis();
actions[size - 1] = action;
size++;
}
void Timer::dequeue(TimerAction action) {
for (int i = 0; i < size; i++)
if (&(actions[i]) == &action) {
memmove(actions + i, actions + i + 1, (size - (i + 1)) * sizeof(TimerAction));
break;
}
}
void Timer::dequeueIdx(int idx) {
memmove(actions + idx, actions + idx + 1, (size - (idx + 1)) * sizeof(TimerAction));
}
void Timer::run() {
for (int i = 0; i < size; i++)
if ((actions[i].last + actions[i].interval) >= millis()) {
TimerAction action = actions[i];
action.callback(action);
if (action.repetitive == 1) {
if (action.finite > 0)
action.finite--;
else
if (action.finite == 0)
dequeueIdx(i);
}
else
dequeueIdx(i);
}
}
void TimerAction::create(long _interval, void(*_callback)(TimerAction sender),
uint8_t _repetitive = 0U, long _finite = -1L) {
interval = _interval;
callback = _callback;
repetitive = _repetitive;
finite = _finite;
}
These are the errors the compiler spewed out:
Arduino: 1.6.1 (Windows 8.1), Board: "Arduino Uno"
In file included from Stoplicht.ino:1:0:
Timer.h:13:2: error: 'TimerAction' does not name a type
TimerAction* actions;
^
Timer.h:17:13: error: 'TimerAction' has not been declared
void queue(TimerAction action);
^
Timer.h:18:15: error: 'TimerAction' has not been declared
void dequeue(TimerAction action);
^
Timer.ino: In member function 'void Timer::init()':
Timer.ino:5:2: error: 'actions' was not declared in this scope
Timer.ino: At global scope:
Timer.ino:8:6: error: prototype for 'void Timer::queue(TimerAction)' does not match any in class 'Timer'
In file included from Stoplicht.ino:1:0:
Timer.h:17:7: error: candidate is: void Timer::queue(int)
void queue(TimerAction action);
^
Timer.ino:15:6: error: prototype for 'void Timer::dequeue(TimerAction)' does not match any in class 'Timer'
In file included from Stoplicht.ino:1:0:
Timer.h:18:7: error: candidate is: void Timer::dequeue(int)
void dequeue(TimerAction action);
^
Timer.ino: In member function 'void Timer::dequeueIdx(int)':
Timer.ino:24:10: error: 'actions' was not declared in this scope
Timer.ino: In member function 'void Timer::run()':
Timer.ino:29:8: error: 'actions' was not declared in this scope
Timer.ino: At global scope:
Timer.ino:45:52: error: default argument given for parameter 3 of 'void TimerAction::create(long int, void (*)(TimerAction), uint8_t, long int)' [-fpermissive]
In file included from Stoplicht.ino:1:0:
Timer.h:36:7: error: after previous specification in 'void TimerAction::create(long int, void (*)(TimerAction), uint8_t, long int)' [-fpermissive]
void create(long interval, void(*callback)(TimerAction sender), uint8_t repetitive = 0U, long finite = -1L);
^
Timer.ino:45:52: error: default argument given for parameter 4 of 'void TimerAction::create(long int, void (*)(TimerAction), uint8_t, long int)' [-fpermissive]
In file included from Stoplicht.ino:1:0:
Timer.h:36:7: error: after previous specification in 'void TimerAction::create(long int, void (*)(TimerAction), uint8_t, long int)' [-fpermissive]
void create(long interval, void(*callback)(TimerAction sender), uint8_t repetitive = 0U, long finite = -1L);
^
Let me explain why I'm using Array
over a std::vector
. My chain of thought was this: the Arduino is quite weak and actions
is going to be accessed a lot. So I thought it's a bit more work to implement it initially but it will make sure the timer doesn't use too much of the Arduino's resources.
I've tried a lot of things but I don't really understand where the problem lies. So that's why I'm asking an expert to look at my code and maybe put me on the right track.