-2

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.

Weather Vane
  • 33,872
  • 7
  • 36
  • 56
Feanaro
  • 922
  • 3
  • 19
  • 35

1 Answers1

3

In Timer.h you have:

TimerAction* actions;

At the point in time that the compiler sees that line of code it has not seen what a TimerAction is. As such it does not know what the type is and is giving you an error. What you need to do is forward declare TimerAction before Timer so the compiler knows what it is doing.

#ifndef _TIMER_h
#define _TIMER_h

#if defined(ARDUINO) && ARDUINO >= 100
    #include "arduino.h"
#else
    #include "WProgram.h"
#endif

struct TimerAction;

struct Timer {
//...
Community
  • 1
  • 1
NathanOliver
  • 171,901
  • 28
  • 288
  • 402