-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathTasker.h
224 lines (183 loc) · 5.85 KB
/
Tasker.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
/*
* Tasker for Arduino - cooperative task scheduler with Javascript like API
* Copyleft (c) 2015-2018 Petr Stehlik petr@pstehlik.cz
* Distributed under the GNU LGPL http://www.gnu.org/licenses/lgpl.txt
*/
#ifndef _tasker_h
#define _tasker_h
#ifndef TASKER_MAX_TASKS
#define TASKER_MAX_TASKS 10 // max 254 entries, one occupies 14 bytes of RAM
#endif
#include "Arduino.h"
typedef void (*TaskCallback0)(void);
typedef void (*TaskCallback1)(int);
class Tasker
{
public:
Tasker(bool prioritized = false);
bool setTimeout(TaskCallback0 func, unsigned long interval, byte prio = TASKER_MAX_TASKS);
bool setTimeout(TaskCallback1 func, unsigned long interval, int param, byte prio = TASKER_MAX_TASKS);
bool setInterval(TaskCallback0 func, unsigned long interval, byte prio = TASKER_MAX_TASKS);
bool setInterval(TaskCallback1 func, unsigned long interval, int param, byte prio = TASKER_MAX_TASKS);
bool setRepeated(TaskCallback0 func, unsigned long interval, unsigned int repeat, byte prio = TASKER_MAX_TASKS);
bool setRepeated(TaskCallback1 func, unsigned long interval, unsigned int repeat, int param, byte prio = TASKER_MAX_TASKS);
bool cancel(TaskCallback0 func);
bool cancel(TaskCallback1 func, int param);
bool clearTimeout(TaskCallback0 func) { return cancel(func); };
bool clearTimeout(TaskCallback1 func, int param) { return cancel(func, param); };
bool clearInterval(TaskCallback0 func) { return cancel(func); };
bool clearInterval(TaskCallback1 func, int param) { return cancel(func, param); };
unsigned long scheduledIn(TaskCallback0 func);
unsigned long scheduledIn(TaskCallback1 func, int param);
void loop(void);
bool isPrioritized() { return t_prioritized; }
void setPrioritized(bool prioritized) { t_prioritized = prioritized; }
private:
struct TASK {
TaskCallback1 call;
int param;
unsigned long interval;
unsigned long lastRun;
unsigned int repeat;
};
int findTask(TaskCallback0 func);
int findTask(TaskCallback1 func, int param);
bool addTask(TaskCallback1 func, unsigned long interval, unsigned int repeat, int param, byte prio);
bool removeTask(int t_idx);
TASK tasks[TASKER_MAX_TASKS];
byte t_count;
bool t_prioritized;
static const int NO_PARAMETER = -1;
};
Tasker::Tasker(bool prioritized)
{
t_count = 0;
t_prioritized = prioritized;
}
bool Tasker::setTimeout(TaskCallback0 func, unsigned long interval, byte prio)
{
return setRepeated(func, interval, 1, prio);
}
bool Tasker::setTimeout(TaskCallback1 func, unsigned long interval, int param, byte prio)
{
return setRepeated(func, interval, 1, param, prio);
}
bool Tasker::setInterval(TaskCallback1 func, unsigned long interval, int param, byte prio)
{
return setRepeated(func, interval, 0, param, prio);
}
bool Tasker::setInterval(TaskCallback0 func, unsigned long interval, byte prio)
{
return setRepeated(func, interval, 0, prio);
}
bool Tasker::setRepeated(TaskCallback0 func, unsigned long interval, unsigned int repeat, byte prio)
{
return addTask((TaskCallback1)func, interval, repeat, NO_PARAMETER, prio);
}
bool Tasker::setRepeated(TaskCallback1 func, unsigned long interval, unsigned int repeat, int param, byte prio)
{
if (param < 0) param = 0; // param can be nonnegative only
return addTask(func, interval, repeat, param, prio);
}
bool Tasker::cancel(TaskCallback0 func)
{
return removeTask(findTask(func));
}
bool Tasker::cancel(TaskCallback1 func, int param)
{
return removeTask(findTask(func, param));
}
unsigned long Tasker::scheduledIn(TaskCallback0 func)
{
return scheduledIn((TaskCallback1)func, NO_PARAMETER);
}
// how long before the given task will be called
// return 0 = task is not scheduled
// return 1 = scheduled to run as soon as possible
// return X = time period in milliseconds
unsigned long Tasker::scheduledIn(TaskCallback1 func, int param)
{
int t_idx = findTask(func, param);
if (t_idx >= 0) {
TASK &t = tasks[t_idx];
unsigned long now = millis();
if (now - t.lastRun >= t.interval)
return 1; // scheduled to run as soon as possible
else
return t.lastRun + t.interval - now;
}
return 0;
}
void Tasker::loop(void)
{
byte t_idx = 0;
unsigned long now = millis();
while(t_idx < t_count) {
bool inc = true;
TASK &t = tasks[t_idx];
if (now - t.lastRun >= t.interval) {
int param = t.param;
TaskCallback1 call = t.call;
t.lastRun += t.interval;
if (t.repeat > 0 && --t.repeat == 0) {
// drop the finished task by removing its slot
removeTask(t_idx);
inc = false;
}
if (param >= 0) // param can be nonnegative only
(*(call))(param);
else
(*(TaskCallback0)(call))();
if (t_prioritized)
break;
now = millis();
}
if (inc)
t_idx++;
}
}
int Tasker::findTask(TaskCallback0 func)
{
return findTask((TaskCallback1)func, NO_PARAMETER);
}
int Tasker::findTask(TaskCallback1 func, int param)
{
for(byte t_idx = 0; t_idx < t_count; t_idx++) {
TASK &t = tasks[t_idx];
if (t.call == func && t.param == param)
return t_idx;
}
return -1;
}
bool Tasker::addTask(TaskCallback1 func, unsigned long interval, unsigned int repeat, int param, byte prio)
{
byte pos = (prio < t_count) ? prio : t_count; // position of newly added task is based on priority
int idx = findTask(func, param);
if (idx >= 0) {
removeTask(idx); // if there's a matching task then remove it first
pos = idx; // new task will replace the original one
}
if (t_count >= TASKER_MAX_TASKS || interval == 0)
return false;
if (pos < t_count)
memmove(tasks+pos+1, tasks+pos, sizeof(TASK)*(t_count-pos));
TASK &t = tasks[pos];
t.call = func;
t.interval = interval;
t.param = param;
t.lastRun = millis();
t.repeat = repeat;
t_count++;
return true;
}
bool Tasker::removeTask(int t_idx)
{
if (t_idx >= 0 && t_idx < t_count) {
memmove(tasks+t_idx, tasks+t_idx+1, sizeof(TASK)*(t_count-t_idx-1));
t_count--;
return true;
}
return false;
}
#endif // _tasker_h
// vim: tabstop=4 shiftwidth=4 noexpandtab cindent