diff --git a/SimpleTimer/SimpleTimer.cpp b/SimpleTimer/SimpleTimer.cpp old mode 100644 new mode 100755 index e0a3858..1e92a19 --- a/SimpleTimer/SimpleTimer.cpp +++ b/SimpleTimer/SimpleTimer.cpp @@ -5,6 +5,9 @@ * Author: mromani@ottotecnica.com * Copyright (c) 2010 OTTOTECNICA Italy * + * Callback function parameters added & compiler warnings + * removed by Bill Knight 20March2017 + * * This library is free software; you can redistribute it * and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software @@ -36,10 +39,8 @@ SimpleTimer::SimpleTimer() { unsigned long current_millis = elapsed(); for (int i = 0; i < MAX_TIMERS; i++) { - enabled[i] = false; - callbacks[i] = 0; // if the callback pointer is zero, the slot is free, i.e. doesn't "contain" any timer - prev_millis[i] = current_millis; - numRuns[i] = 0; + memset(&timer[i], 0, sizeof (timer_t)); + timer[i].prev_millis = current_millis; } numTimers = 0; @@ -55,35 +56,34 @@ void SimpleTimer::run() { for (i = 0; i < MAX_TIMERS; i++) { - toBeCalled[i] = DEFCALL_DONTRUN; + timer[i].toBeCalled = DEFCALL_DONTRUN; // no callback == no timer, i.e. jump over empty slots - if (callbacks[i]) { + if (timer[i].callback != NULL) { // is it time to process this timer ? // see http://arduino.cc/forum/index.php/topic,124048.msg932592.html#msg932592 - if (current_millis - prev_millis[i] >= delays[i]) { + if ((current_millis - timer[i].prev_millis) >= timer[i].delay) { // update time - //prev_millis[i] = current_millis; - prev_millis[i] += delays[i]; + timer[i].prev_millis += timer[i].delay; // check if the timer callback has to be executed - if (enabled[i]) { + if (timer[i].enabled) { // "run forever" timers must always be executed - if (maxNumRuns[i] == RUN_FOREVER) { - toBeCalled[i] = DEFCALL_RUNONLY; + if (timer[i].maxNumRuns == RUN_FOREVER) { + timer[i].toBeCalled = DEFCALL_RUNONLY; } // other timers get executed the specified number of times - else if (numRuns[i] < maxNumRuns[i]) { - toBeCalled[i] = DEFCALL_RUNONLY; - numRuns[i]++; + else if (timer[i].numRuns < timer[i].maxNumRuns) { + timer[i].toBeCalled = DEFCALL_RUNONLY; + timer[i].numRuns++; // after the last run, delete the timer - if (numRuns[i] >= maxNumRuns[i]) { - toBeCalled[i] = DEFCALL_RUNANDDEL; + if (timer[i].numRuns >= timer[i].maxNumRuns) { + timer[i].toBeCalled = DEFCALL_RUNANDDEL; } } } @@ -92,19 +92,16 @@ void SimpleTimer::run() { } for (i = 0; i < MAX_TIMERS; i++) { - switch(toBeCalled[i]) { - case DEFCALL_DONTRUN: - break; - - case DEFCALL_RUNONLY: - (*callbacks[i])(); - break; - - case DEFCALL_RUNANDDEL: - (*callbacks[i])(); - deleteTimer(i); - break; - } + if (timer[i].toBeCalled == DEFCALL_DONTRUN) + continue; + + if (timer[i].hasParam) + (*(timer_callback_p)timer[i].callback)(timer[i].param); + else + (*(timer_callback)timer[i].callback)(); + + if (timer[i].toBeCalled == DEFCALL_RUNANDDEL) + deleteTimer(i); } } @@ -112,16 +109,14 @@ void SimpleTimer::run() { // find the first available slot // return -1 if none found int SimpleTimer::findFirstFreeSlot() { - int i; - // all slots are used if (numTimers >= MAX_TIMERS) { return -1; } // return the first slot with no callback (i.e. free) - for (i = 0; i < MAX_TIMERS; i++) { - if (callbacks[i] == 0) { + for (int i = 0; i < MAX_TIMERS; i++) { + if (timer[i].callback == NULL) { return i; } } @@ -131,7 +126,7 @@ int SimpleTimer::findFirstFreeSlot() { } -int SimpleTimer::setTimer(long d, timer_callback f, int n) { +int SimpleTimer::setupTimer(unsigned long d, void* f, void* p, boolean h, unsigned n) { int freeTimer; freeTimer = findFirstFreeSlot(); @@ -143,11 +138,13 @@ int SimpleTimer::setTimer(long d, timer_callback f, int n) { return -1; } - delays[freeTimer] = d; - callbacks[freeTimer] = f; - maxNumRuns[freeTimer] = n; - enabled[freeTimer] = true; - prev_millis[freeTimer] = elapsed(); + timer[freeTimer].delay = d; + timer[freeTimer].callback = f; + timer[freeTimer].param = p; + timer[freeTimer].hasParam = h; + timer[freeTimer].maxNumRuns = n; + timer[freeTimer].enabled = true; + timer[freeTimer].prev_millis = elapsed(); numTimers++; @@ -155,18 +152,32 @@ int SimpleTimer::setTimer(long d, timer_callback f, int n) { } -int SimpleTimer::setInterval(long d, timer_callback f) { - return setTimer(d, f, RUN_FOREVER); +int SimpleTimer::setTimer(unsigned long d, timer_callback f, unsigned n) { + return setupTimer(d, (void *)f, NULL, false, n); } +int SimpleTimer::setTimer(unsigned long d, timer_callback_p f, void* p, unsigned n) { + return setupTimer(d, (void *)f, p, true, n); +} + +int SimpleTimer::setInterval(unsigned long d, timer_callback f) { + return setupTimer(d, (void *)f, NULL, false, RUN_FOREVER); +} + +int SimpleTimer::setInterval(unsigned long d, timer_callback_p f, void* p) { + return setupTimer(d, (void *)f, p, true, RUN_FOREVER); +} + +int SimpleTimer::setTimeout(unsigned long d, timer_callback f) { + return setupTimer(d, (void *)f, NULL, false, RUN_ONCE); +} -int SimpleTimer::setTimeout(long d, timer_callback f) { - return setTimer(d, f, RUN_ONCE); +int SimpleTimer::setTimeout(unsigned long d, timer_callback_p f, void* p) { + return setupTimer(d, (void *)f, p, true, RUN_ONCE); } -void SimpleTimer::deleteTimer(int timerId) { - // ignore invalid argument +void SimpleTimer::deleteTimer(unsigned timerId) { if (timerId >= MAX_TIMERS) { return; } @@ -178,12 +189,9 @@ void SimpleTimer::deleteTimer(int timerId) { // don't decrease the number of timers if the // specified slot is already empty - if (callbacks[timerId] != NULL) { - callbacks[timerId] = 0; - enabled[timerId] = false; - toBeCalled[timerId] = DEFCALL_DONTRUN; - delays[timerId] = 0; - numRuns[timerId] = 0; + if (timer[timerId].callback != NULL) { + memset(&timer[timerId], 0, sizeof (timer_t)); + timer[timerId].prev_millis = elapsed(); // update number of timers numTimers--; @@ -192,55 +200,51 @@ void SimpleTimer::deleteTimer(int timerId) { // function contributed by code@rowansimms.com -void SimpleTimer::restartTimer(int numTimer) { - // ignore invalid argument +void SimpleTimer::restartTimer(unsigned numTimer) { if (numTimer >= MAX_TIMERS) { return; } - prev_millis[numTimer] = elapsed(); + timer[numTimer].prev_millis = elapsed(); } -boolean SimpleTimer::isEnabled(int numTimer) { +boolean SimpleTimer::isEnabled(unsigned numTimer) { if (numTimer >= MAX_TIMERS) { return false; } - return enabled[numTimer]; + return timer[numTimer].enabled; } -void SimpleTimer::enable(int numTimer) { - // ignore invalid argument +void SimpleTimer::enable(unsigned numTimer) { if (numTimer >= MAX_TIMERS) { return; } - enabled[numTimer] = true; + timer[numTimer].enabled = true; } -void SimpleTimer::disable(int numTimer) { - // ignore invalid argument +void SimpleTimer::disable(unsigned numTimer) { if (numTimer >= MAX_TIMERS) { return; } - enabled[numTimer] = false; + timer[numTimer].enabled = false; } -void SimpleTimer::toggle(int numTimer) { - // ignore invalid argument +void SimpleTimer::toggle(unsigned numTimer) { if (numTimer >= MAX_TIMERS) { return; } - enabled[numTimer] = !enabled[numTimer]; + timer[numTimer].enabled = !timer[numTimer].enabled; } -int SimpleTimer::getNumTimers() { +unsigned SimpleTimer::getNumTimers() { return numTimers; } diff --git a/SimpleTimer/SimpleTimer.h b/SimpleTimer/SimpleTimer.h old mode 100644 new mode 100755 index 2cc0b95..4d02379 --- a/SimpleTimer/SimpleTimer.h +++ b/SimpleTimer/SimpleTimer.h @@ -5,6 +5,8 @@ * Author: mromani@ottotecnica.com * Copyright (c) 2010 OTTOTECNICA Italy * + * Modifications by Bill Knight 18March2017 + * * This library is free software; you can redistribute it * and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software @@ -35,6 +37,7 @@ #endif typedef void (*timer_callback)(void); +typedef void (*timer_callback_p)(void *); class SimpleTimer { @@ -52,39 +55,60 @@ class SimpleTimer { // this function must be called inside loop() void run(); - // call function f every d milliseconds - int setInterval(long d, timer_callback f); + // Timer will call function 'f' every 'd' milliseconds forever + // returns the timer number (numTimer) on success or + // -1 on failure (f == NULL) or no free timers + int setInterval(unsigned long d, timer_callback f); + + // Timer will call function 'f' with parameter 'p' every 'd' milliseconds forever + // returns the timer number (numTimer) on success or + // -1 on failure (f == NULL) or no free timers + int setInterval(unsigned long d, timer_callback_p f, void* p); + + // Timer will call function 'f' after 'd' milliseconds one time + // returns the timer number (numTimer) on success or + // -1 on failure (f == NULL) or no free timers + int setTimeout(unsigned long d, timer_callback f); - // call function f once after d milliseconds - int setTimeout(long d, timer_callback f); + // Timer will call function 'f' with parameter 'p' after 'd' milliseconds one time + // returns the timer number (numTimer) on success or + // -1 on failure (f == NULL) or no free timers + int setTimeout(unsigned long d, timer_callback_p f, void* p); - // call function f every d milliseconds for n times - int setTimer(long d, timer_callback f, int n); + // Timer will call function 'f' every 'd' milliseconds 'n' times + // returns the timer number (numTimer) on success or + // -1 on failure (f == NULL) or no free timers + int setTimer(unsigned long d, timer_callback f, unsigned n); + + // Timer will call function 'f' with parameter 'p' every 'd' milliseconds 'n' times + // returns the timer number (numTimer) on success or + // -1 on failure (f == NULL) or no free timers + int setTimer(unsigned long d, timer_callback_p f, void* p, unsigned n); // destroy the specified timer - void deleteTimer(int numTimer); + void deleteTimer(unsigned numTimer); // restart the specified timer - void restartTimer(int numTimer); + void restartTimer(unsigned numTimer); // returns true if the specified timer is enabled - boolean isEnabled(int numTimer); + boolean isEnabled(unsigned numTimer); // enables the specified timer - void enable(int numTimer); + void enable(unsigned numTimer); // disables the specified timer - void disable(int numTimer); + void disable(unsigned numTimer); // enables the specified timer if it's currently disabled, // and vice-versa - void toggle(int numTimer); + void toggle(unsigned numTimer); // returns the number of used timers - int getNumTimers(); + unsigned getNumTimers(); // returns the number of available timers - int getNumAvailableTimers() { return MAX_TIMERS - numTimers; }; + unsigned getNumAvailableTimers() { return MAX_TIMERS - numTimers; }; private: // deferred call constants @@ -92,33 +116,30 @@ class SimpleTimer { const static int DEFCALL_RUNONLY = 1; // call the callback function but don't delete the timer const static int DEFCALL_RUNANDDEL = 2; // call the callback function and delete the timer + // low level function to initialize and enable a new timer + // returns the timer number (numTimer) on success or + // -1 on failure (f == NULL) or no free timers + int setupTimer(unsigned long d, void* f, void* p, boolean h, unsigned n); + // find the first available slot int findFirstFreeSlot(); - // value returned by the millis() function - // in the previous run() call - unsigned long prev_millis[MAX_TIMERS]; - - // pointers to the callback functions - timer_callback callbacks[MAX_TIMERS]; - - // delay values - unsigned long delays[MAX_TIMERS]; - - // number of runs to be executed for each timer - int maxNumRuns[MAX_TIMERS]; - - // number of executed runs for each timer - int numRuns[MAX_TIMERS]; - - // which timers are enabled - boolean enabled[MAX_TIMERS]; + typedef struct { + unsigned long prev_millis; // value returned by the millis() function in the previous run() call + void* callback; // pointer to the callback function + void* param; // function parameter + boolean hasParam; // true if callback takes a parameter + unsigned long delay; // delay value + unsigned maxNumRuns; // number of runs to be executed + unsigned numRuns; // number of executed runs + boolean enabled; // true if enabled + unsigned toBeCalled; // deferred function call (sort of) - N.B.: only used in run() + } timer_t; - // deferred function call (sort of) - N.B.: this array is only used in run() - int toBeCalled[MAX_TIMERS]; + timer_t timer[MAX_TIMERS]; // actual number of timers in use - int numTimers; + unsigned numTimers; }; #endif diff --git a/SimpleTimer/example/SimpleTimerPlus/SimpleTimerPlus.ino b/SimpleTimer/example/SimpleTimerPlus/SimpleTimerPlus.ino new file mode 100644 index 0000000..2a42991 --- /dev/null +++ b/SimpleTimer/example/SimpleTimerPlus/SimpleTimerPlus.ino @@ -0,0 +1,118 @@ +/* + * SimpleTimerAlarmExample.ino + * + * Based on usage example for Time + TimeAlarm + SimpleTimer libraries + * + * A timer is called every 15 seconds + * Another timer is called once only after 10 seconds + * A third timer is called 10 times. + * Toggle an IO pin 100mSec LOW, 900mSec HIGH + * + */ + +#include + +// There must be one global SimpleTimer object. +// More SimpleTimer objects can be created and run, +// although there is little point in doing so. +SimpleTimer timer; + +// Pin to toggle +const unsigned int PIN = 13; + +// function to be called repeatedly +void RepeatTask(void) { + Serial.println("15 second timer"); +} + +// function to be called just once +void OnceOnlyTask(void) { + Serial.println("This timer only triggers once"); +} + +// function to be called exactly 10 times +void TenTimesTask(void) { + static int k = 0; + k++; + Serial.print("called "); + Serial.print(k); + Serial.println(" / 10 times."); +} + +// print current arduino "uptime" on the serial port +void DigitalClockDisplay(void) { + int h,m,s; + s = millis() / 1000; + m = s / 60; + h = s / 3600; + s = s - m * 60; + m = m - h * 60; + Serial.print(h); + printDigits(m); + printDigits(s); + Serial.println(); +} + +// +// utility function for digital clock display: +// prints preceding colon and leading 0 +// +void printDigits(int digits) { + Serial.print(":"); + if(digits < 10) + Serial.print('0'); + Serial.print(digits); +} + +// This callback function takes an arg. The arg can be cast to a value +// as in this example or cast to a pointer to a structure or even a +// function. If a structure, it must be present in memory when the +// callback fuction is called. In other words it must be a global or +// declared 'static' and not a structure local to the function that +// created the timer such as setup() or loop(). +void setPin(void* args) +{ + int state = (int)args; + unsigned long duration; + + if (state == LOW) + { + digitalWrite(PIN, LOW); + state = HIGH; // set the pin high + duration = 100; // after 100 mSec + } + else + { + digitalWrite(PIN, HIGH); + state = LOW; // set the pin low + duration = 900; // after 900 mSec + } + + timer.setTimeout(duration, setPin, (void *)state); +} + +void setup() { + Serial.begin(9600); + + // welcome message + Serial.println("SimpleTimer Example"); + Serial.println("One timer is triggered every 15 seconds"); + Serial.println("Another timer is set to trigger only once after 10 seconds"); + Serial.println("Another timer is set to trigger 10 times"); + Serial.println(); + + // timed actions setup + timer.setInterval(15000, RepeatTask); + timer.setTimeout(10000, OnceOnlyTask); + timer.setInterval(1000, DigitalClockDisplay); + timer.setTimer(1200, TenTimesTask, 10); + pinMode(PIN, OUTPUT); + digitalWrite(PIN, LOW); + // Set the pin HIGH after 100 mSec + timer.setTimeout(100, setPin, (void *)HIGH); +} + +void loop() { + // this is where the "polling" occurs + timer.run(); +} diff --git a/SimpleTimer/tests/SetInterval/SetInterval.ino b/SimpleTimer/tests/SetInterval/SetInterval.ino new file mode 100644 index 0000000..ec08e23 --- /dev/null +++ b/SimpleTimer/tests/SetInterval/SetInterval.ino @@ -0,0 +1,56 @@ +#include + +// the timer object +SimpleTimer timer; + +unsigned int counter = 0; + +boolean pass = true; + +// a function to be executed periodically +void repeatMe() { + counter++; + Serial.print("Uptime (s): "); + Serial.println(millis() / 1000); +} + +void checkResult(void* param) { + unsigned int expected = (unsigned int)param; + + Serial.print("Checking param = "); + Serial.println(expected); + Serial.print("counter = "); + Serial.println(counter); + + if (expected == counter) { + Serial.println("OK"); + } + else { + Serial.println("ERROR"); + pass = false; + } +} + +void start() { + Serial.println("Test start"); +} + +void stopSketch() { + Serial.println("Test stop"); + Serial.println(pass ? "PASS" : "FAIL"); + while(true); +} + +void setup() { + Serial.begin(9600); + timer.setTimeout(100, start); + timer.setInterval(500, repeatMe); + timer.setTimeout(550, checkResult, 1); + timer.setTimeout(1050, checkResult, 2); + timer.setTimeout(1550, checkResult, 3); + timer.setTimeout(2000, stopSketch); +} + +void loop() { + timer.run(); +}