Introduction
The existing Timer library written by Simon Monk has a drawback that you cannot use it with your classes directly. You can only pass standard function pointer as timer callback, or you have to make some part of your classes public, and I don't like to do such things. There is no way to pass a member function of a class as callback in this library. With Scheduler
, you can do this, and some other cool properties.
Background
There are some good articles on function pointers, one of them is the following, written by Don Clugston:
I won't get into deeps about the subject, but to state simply, you cannot use standard function pointers and member function pointers interchangeably.
Let's test it:
First of all, we need a class with a member function to be used as callback for Timer
.
class TimerClient {
public:
void timerClientCallback() {
Serial.println("timerClientCallback");
};
};
And the test application where you use this class with a Timer
.
#include <Arduino.h>
#include <Timer.h>
#include "TimerClient.h"
Timer t;
TimerClient c;
void setup() {
t.after(1000, c.timerClientCallback); }
void loop() {
t.update();
}
And this makes the compiler angry with your code.
Quote:
test1.ino: In function 'void setup()':
test1:10: error: no matching function for call to 'Timer::after(int, <unresolved overloaded function type>)'
D:\projects\arduino\libraries\Timer/Timer.h:39: note: candidates are: int8_t Timer::after(long unsigned int, void (*)())
Because "void (*fptr)()
" is different from "void (AnyClass::*fptr)()
".
Overview
Basically, Scheduler
manages Event
s and Event
s informs SchedulerClient
s. When you set SchedulerClient
as a base for your class, you can register it in Scheduler
by using every
function. Simplified class diagram is the following:
Figure 1: Classes
What You Can Do With Scheduler
- You can register a client with
every
function in order to be informed at the end of each period
. - You can do this
repeatCount
times. - You may want an ordinary function (
int (*f)(void)
) as callback. Then you can use SchedulerClient
as a wrapper by constructing it with SchedulerClient(f)
. - You can provide a member function by overriding
schedulerCallback
virtual function. - You may want to be informed at the end of the last period, which means that your
SchedulerClient
is informed repeatCount
times. You can do this by overriding schedulerEnded
virtual function. - You can oscillate a pin (set
HIGH
to LOW
, or LOW
to HIGH
). - You can use
Scheduler
without constructing an instance. Static getInstance
function provides one for you.
Pros
- You can use member functions as good as ordinary functions.
- Dynamic allocation of events: An event is created when it is needed.
- Recycled usage of events: When an event ends, it is used instead of creating a new one for the next request.
- Global access to a
Scheduler
instance: Scheduler
holds a static
instance of itself for instant usage. Therefore, you don't need instantiate one when you need it.
Cons
- There can exist at most 10 active
Event
per Scheduler
. When a call (every or oscillate) returns -1
, it means that you have to wait or create another instance. This applies to static
instance, too. - You cannot pass ordinary functions directly as callback. You have to wrap it with a
SchedulerClient
.
Using Code
I don't want to bother you with many lines of code here, therefore I will only show you the basic usage.
SchedulerClient2 *cl2 = new SchedulerClient2();
SchedulerClient cl1(cb1);
Scheduler s;
void setup() {
Serial.begin(9600);
if(s.every(&cl1, 1000)<0)
printFail("--1");
if(s.every(cl2, 3000)<0)
printFail("--2");
if(s.every(cl2, 2000, 3)<0)
printFail("--3");
if(s.oscillate(LED_PIN, 1000, HIGH)<0)
printFail("--4");
for(int i=0; i<10; i++) {
if(s.every(cl2, 1000, 2)<0) {
printFail("");
Serial.println(i);
}
}
}
And SchedulerClient2
:
class SchedulerClient2: public SchedulerClient {
public:
void schedulerCallback(int eventId) {
Serial.print("Callback from event(SchedulerClient2): ");
Serial.println(eventId);
};
void schedulerEnded(int eventId) {
Serial.print("Event end(SchedulerClient2): ");
Serial.println(eventId);
};
};
As you see in the sample codes, the only thing to do in a client is to override schedulerCallback
virtual function and schedulerEnded
virtual function if you like.
I have provided all sources at the download section. It is simple, but useful, I think. What you should do to use in your Arduino project is to extract the file in a folder under your Arduino libraries directory, as always.