-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSimpleTaskScheduler.h
More file actions
235 lines (211 loc) · 8.19 KB
/
SimpleTaskScheduler.h
File metadata and controls
235 lines (211 loc) · 8.19 KB
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
225
226
227
228
229
230
231
232
233
234
235
/*
* Simple Task Scheduler - Create repetitive tasks to call in your Arduino project.
* Created by: Ryan Nazaretian - ryannazaretian@gmail.com
* Copyright (C) 2018 - Ryan Nazaretian
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdint.h>
#include <Arduino.h>
#ifndef SIMPLE_TASK_SCHEDULER
#define SIMPLE_TASK_SCHEDULER
#define TS_MILLIS 0
#define TS_MICROS 1
#define ONE_SHOT false
#define REPEATING true
//provide a typedef for a void function pointer
typedef void (*FuncPtr)(void);
// This is a task object, which includes everything the SimpleTaskScheduler needs to know about a specific task.
typedef struct {
FuncPtr fptr_callback; // Function pointer to the callback
bool b_enabled; // Whether or not the task is enabled
unsigned long ul_period; // The period, in milliseconds
unsigned long ul_timer_start;
bool b_autoreset;
} TaskObject;
class SimpleTaskScheduler {
public:
SimpleTaskScheduler(uint8_t, uint8_t);
uint8_t addTask(FuncPtr, uint16_t, bool, bool);
void loop(void);
void disableTask(uint8_t);
void enableTask(uint8_t, bool);
bool isEnabled(uint8_t);
void callTask(uint8_t);
void changeTaskPeriod(uint8_t, unsigned long);
private:
TaskObject *st_tasks;
uint8_t u8_numOfTasks;
uint8_t u8_timerType;
void resetTimer(uint8_t);
void checkTask(uint8_t);
unsigned long getCurrentTime(void);
};
SimpleTaskScheduler::SimpleTaskScheduler(uint8_t u8_maxNumOfTasks, uint8_t u8_timerType) {
/* Class: SimpleTaskScheduler
* Description: The SimpleTaskScheduler class is designed to allow the user to setup multiple
* tasks on a time schedule based on millis() or micros().
*
* This is a cooperative task scheduler. Each callback is blocking, so keep your tasks
* as short as possible.
*
* This is also a pretty poorly written task scheduler. This could be made better using
* timers. Don't use this for any real-time tasks. This should be used as a loosly-timed
* task scheduler, i.e. tasks that don't need strict time constraints.
*
* If you have tasks that will likely block, add them last.
*
* Place the SimpleTaskScheduler::loop() inside your Arduino void loop(void) {} function.
* Add tasks using SimpleTaskScheduler::addTask(your callback function, period, enabled)
*
* Arguments:
* uint8_t u8_maxNumOfTasks - The maximum number of tasks to allocate at program start.
* The maximum maximum number of tasks supported is 256. (Seriously though, this is
* an Arduino, don't ask too much of it!)
* uint8_t u8_timerType - The type of timer to use for the schedule. Available options:
* - TS_MILLIS - Uses the millis() function, so you have millisecond resolution
* - TS_MICROS - Uses the micros() function, so you have microsecond resolution
*/
this->u8_numOfTasks = 0;
this->st_tasks = new TaskObject[u8_maxNumOfTasks];
this->u8_timerType = u8_timerType;
}
uint8_t SimpleTaskScheduler::addTask(FuncPtr fptr_callback, uint16_t ul_period, bool b_enable, bool b_autoreset) {
/* Function: addTasks
* Description: Adds a task to the task schedler.
*
* Arguments:
* fptr_callback - Function pointer callback, your void<name>(void) function callback.
* Remember this is a cooperative scheduler which requires your functions to finish
* as quickly as possible. Don't use sleeps or while-loops that wait on a condition.
* ul_period - The period at which to call your callback function. This could be
* milliseconds or microseconds depending on what you setup.
* b_enable - Whether or not this task is enabled at startup
*
* Returns:
* taskId - This is the tasks unique ID. If you want to go back and change any
* parameters of your task after adding it, save this ID.
*
*/
uint8_t u8_taskId = this->u8_numOfTasks++;
this->st_tasks[u8_taskId].fptr_callback = fptr_callback;
this->st_tasks[u8_taskId].ul_period = ul_period;
this->st_tasks[u8_taskId].b_enabled = b_enable;
this->st_tasks[u8_taskId].ul_timer_start = 0;
this->st_tasks[u8_taskId].b_autoreset = b_autoreset;
return u8_taskId;
}
void SimpleTaskScheduler::loop(void) {
/* Function: loop
* Description: Loop should be called as often as possible, preferrably in your Arduino loop function.
* This is what checks what tasks are scheduled to run and runs them.
*/
uint8_t u8_taskId;
for(u8_taskId = 0; u8_taskId < this->u8_numOfTasks; u8_taskId++)
this->checkTask(u8_taskId);
}
void SimpleTaskScheduler::disableTask(uint8_t u8_taskId) {
/* Function disableTask
* Descriptions: Disables the given task from auto-running on a schedule.
*
* Arguments:
* u8_taskId - The unique task ID of the task you want to disable.
*/
this->st_tasks[u8_taskId].b_enabled = false;
}
void SimpleTaskScheduler::enableTask(uint8_t u8_taskId, bool b_trigger_now) {
/* Function enableTask
* Descriptions: Enables the given task from auto-running on a schedule.
*
* Arguments:
* u8_taskId - The unique task ID of the task you want to enable.
* b_trigger_now - Call the task right now and reset its timer.
* Otherwise, the task timer will reset to the current time + the period.
*/
if (!this->st_tasks[u8_taskId].b_enabled) {
this->st_tasks[u8_taskId].b_enabled = true;
if (b_trigger_now)
this->callTask(u8_taskId);
else
this->resetTimer(u8_taskId);
}
}
bool SimpleTaskScheduler::isEnabled(uint8_t u8_taskId){
/* Public Function: isEnabled
* Description: Returns true if the given unique task ID is enabled.
*
* Arguments:
* u8_taskId - The unique task ID of the task you want to check.
*/
return this->st_tasks[u8_taskId].b_enabled;
}
void SimpleTaskScheduler::callTask(uint8_t u8_taskId) {
/* Function: callTask
* Description: Calls the task by the given unique task ID and resets its timer
*
* Arguments:
* u8_taskId - The unique task ID of the task you want to call.
*/
if (this->st_tasks[u8_taskId].b_autoreset)
this->resetTimer(u8_taskId);
else
this->disableTask(u8_taskId);
this->st_tasks[u8_taskId].fptr_callback();
}
void SimpleTaskScheduler::resetTimer(uint8_t u8_taskId) {
/* Private Function: resetTimer
* Description: Resets the timer to begin again at its next period.
*
* Arguments:
* u8_taskId - The unique task ID for the task to reset the tiemr
*/
if (this->st_tasks[u8_taskId].ul_period)
this->st_tasks[u8_taskId].ul_timer_start = this->getCurrentTime();
}
void SimpleTaskScheduler::checkTask(uint8_t u8_taskId) {
/* Private Function: checkTask
* Description: Checks the given unique task ID to see if it's time to call it.
*
* Arguments:
* u8_taskId - The unique task ID of the task you want to check.
*/
// If enabled and (Timer Disabled or Time Now - Time Start > Period
if ( (this->st_tasks[u8_taskId].b_enabled) &&
( (this->st_tasks[u8_taskId].ul_period == 0) ||
(this->getCurrentTime() - this->st_tasks[u8_taskId].ul_timer_start > this->st_tasks[u8_taskId].ul_period)
)
)
this->callTask(u8_taskId);
}
unsigned long SimpleTaskScheduler::getCurrentTime(void) {
/* Private Function: getCurrentTime
* Description: Returns the current time based on which time basis
* the task scheduler is using.
*
* Returns:
* The current time used by the task scheduler.
*/
switch(this->u8_timerType) {
case TS_MICROS:
return micros();
break;
case TS_MILLIS:
return millis();
break;
default:
return millis();
}
}
#endif