forked from richard-damon/FreeRTOScpp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathTaskCPP.h
395 lines (364 loc) · 14.6 KB
/
TaskCPP.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
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
/**
* @file TaskCPP.h
* @copyright (c) 2007-2015 Richard Damon
* @author Richard Damon <[email protected]>
* @parblock
* MIT License:
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* It is requested (but not required by license) that any bugs found or
* improvements made be shared, preferably to the author.
* @endparblock
*
* @brief FreeRTOS Task Wrapper
*
* This file contains a set of lightweight wrappers for tasks using FreeRTOS
*
* @ingroup FreeRTOSCpp
*/
#ifndef TaskCPP_H
#define TaskCPP_H
#include "FreeRTOS.h"
#include "task.h"
/**
* @brief Names for Base set of Priorities.
*
* Assigns used based names to priority levels, optimized for configMAX_PRIORITIES = 6 for maximal distinctions
* with reasonable collapsing for smaller values. If configMAX_PRIORITIES is >6 then some values won't have names here, but
* values could be created and cast to the enum type.
*
* | configMAX_PRIORITIES: | 1 | 2 | 3 | 4 | 5 | 6 | N>6 | Use |
* | --------------------: | - | - | - | - | - | - | :-: | :------------------------------------------------- |
* | TaskPrio_Idle | 0 | 0 | 0 | 0 | 0 | 0 | 0 | Non-Real Time operations, Tasks that don't block |
* | TaskPrio_Low | 0 | 1 | 1 | 1 | 1 | 1 | 1 | Non-Critical operations |
* | TaskPrio_HMI | 0 | 1 | 1 | 1 | 1 | 2 | 2 | Normal User Interface |
* | TaskPrio_Mid | 0 | 1 | 1 | 2 | 2 | 3 | N/2 | Semi-Critical, Deadlines, not much processing |
* | TaskPrio_High | 0 | 1 | 2 | 3 | 3 | 4 | N-2 | Urgent, Short Deadlines, not much processing |
* | TaskPrio_Highest | 0 | 1 | 2 | 3 | 4 | 5 | N-1 | Critical, do NOW, must be quick (Used by FreeRTOS) |
*
* @ingroup FreeRTOSCpp
*/
enum TaskPriority {
TaskPrio_Idle = 0, ///< Non-Real Time operations. tasks that don't block
TaskPrio_Low = ((configMAX_PRIORITIES)>1), ///< Non-Critical operations
TaskPrio_HMI = (TaskPrio_Low + ((configMAX_PRIORITIES)>5)), ///< Normal User Interface Level
TaskPrio_Mid = ((configMAX_PRIORITIES)/2), ///< Semi-Critical, have deadlines, not a lot of processing
TaskPrio_High = ((configMAX_PRIORITIES)-1-((configMAX_PRIORITIES)>4)), ///< Urgent tasks, short deadlines, not much processing
TaskPrio_Highest = ((configMAX_PRIORITIES)-1) ///< Critical Tasks, Do NOW, must be quick (Used by FreeRTOS)
};
/**
* @brief Lowest Level Wrapper.
* Create the specified task with a provided task function.
*
* If the TaskBase object is destroyed, the FreeRTOS Task will be deleted (if deletion has been enabled)
* @ingroup FreeRTOSCpp
* @todo Fully implement task manipulation functions
*
* @ingroup FreeRTOSCpp
*/
class TaskBase {
protected:
/**
* @brief Constructor
*
* TaskBase is effectively Abstract, so a sub class is needed to create to Task.
*/
TaskBase() : taskHandle(0) {
}
public:
/**
* @brief Destructor.
*
* If deletion is enabled, delete the task.
*/
virtual ~TaskBase() {
#if INCLUDE_vTaskDelete
if(taskHandle){
vTaskDelete(taskHandle);
}
#endif
return;
}
/**
* @brief Get Task Handle.
* @return the task handle.
*/
TaskHandle_t getTaskHandle() const { return taskHandle; }
#if INCLUDE_uxTaskPriorityGet
/**
* @brief Get Task priority
*
* Only available if INCLUDE_vTaskPriorityGet == 1
* @return The priority of the Task.
*/
TaskPriority priority() const { return static_cast<TaskPriority>(uxTaskPriorityGet(taskHandle)); }
#endif
#if INCLUDE_vTaskPrioritySet
/**
* @brief Set Task priority
*
* Only available if INCLUDE_vTaskPrioritySet == 1
* @param priority_ The TaskPriority to give the Task.
*/
void priority(TaskPriority priority_) { vTaskPrioritySet(taskHandle, priority_); }
#endif
#if INCLUDE_vTaskSuspend
/**
* @brief Suspend the Task.
*
* Only available if INCLUDE_vTaskSuspend == 1
*/
void suspend() { vTaskSuspend(taskHandle); }
/**
* @brief Resume the Task.
*
* Only available if INCLUDE_vTaskSuspend == 1
*/
void resume() { vTaskResume(taskHandle); }
# endif
#if INCLUDE_xTaskAbortDelay
/**
* @brief Abort Delay
*
* Only available if INCLUDE_xTaskAbortDelay == 1
*/
void abortDelay() { xTaskAbortDelay(taskHandle); }
#endif
# if INCLUDE_xTaskResumeFromISR
/**
* @brief Resume task from ISR.
*
* Note: Only functions with _ISR should be used inside Interupt service routines.
*
* Only available if INCLUDE_vTaskSuspend == 1 and INCLUDE_vTaskResumeFromISR == 1
* @returns True if ISR should request a context switch.
*/
bool resume_ISR() { return xTaskResumeFromISR(taskHandle); }
#endif
/**
* @brief Notify a Task.
*
* Generic Task Notification operation
*/
bool notify(uint32_t value, eNotifyAction act)
{ return xTaskNotify(taskHandle, value, act); }
bool notify_ISR(uint32_t value, eNotifyAction act, portBASE_TYPE& waswoken)
{ return xTaskNotifyFromISR(taskHandle, value, act, &waswoken);}
bool notify_query(uint32_t value, eNotifyAction act, uint32_t &old)
{return xTaskNotifyAndQuery(taskHandle, value, act, &old); }
bool notify_query_ISR(uint32_t value, eNotifyAction act, uint32_t &old, portBASE_TYPE& waswoken)
{return xTaskNotifyAndQueryFromISR(taskHandle, value, act, &old, &waswoken); }
/**
* @brief Notify a Task as a semaphore
*
* Sends a notification to a task using a semaphore based protocol. Generally the task should we using
* the take() function to receive the notification.
*/
bool give() { return xTaskNotifyGive(taskHandle); }
void give_ISR(portBASE_TYPE& waswoken)
{ vTaskNotifyGiveFromISR(taskHandle, &waswoken); }
protected:
// Protected as only the task itself should use these
/**
* @brief Wait for task notification.
*/
uint32_t wait(uint32_t clearEnter, uint32_t clearExit = 0xFFFFFFFF, uint32_t* value = 0, TickType_t ticks = portMAX_DELAY)
{ return xTaskNotifyWait(clearEnter, clearExit, value, ticks); }
/**
* @brief Wait for a task Give notification
*
* Specialized wait() designed to work with the give()/give_ISR() notifications.
*
* @param clear Flag to indicate if the action on succesful take is to clear (True) or decrement (False) the notification value.
* Effectively decides between a binary (True) or counting (False) semaphore behavior.
*
* @param ticks The time to wait for the semaphore.
*
* @returns Returns the notification word (prior to being adjusted for the take() ), Will be zero if
* the take() timed out.
*/
uint32_t take(bool clear = true, TickType_t ticks = portMAX_DELAY)
{ return ulTaskNotifyTake(clear, ticks); }
TaskHandle_t taskHandle; ///< Handle for the task we are managing.
private:
#if __cplusplus < 201101L
TaskBase(TaskBase const&); ///< We are not copyable.
void operator =(TaskBase const&); ///< We are not assignable.
#else
TaskBase(TaskBase const&) = delete; ///< We are not copyable.
void operator =(TaskBase const&) = delete; ///< We are not assignable.
#endif // __cplusplus
};
/**
* @brief Statically Created Task Wrapper.
* Create the specified task with a provided task function.
*
* @tparam stackDepth Size of the stack to give to the task
*
* If the Task object is destroyed, the class will be deleted (if deletion has been enabled)
* @ingroup FreeRTOSCpp
*/
template<uint32_t stackDepth
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
=0
#endif
> class TaskS : public TaskBase {
public:
/**
* @brief Constructor.
*
* @param name The name of the task.
* @param taskfun The function implementing the task, should have type void (*taskfun)(void *)
* @param priority_ The priority of the task. Use the TaskPriority enum values or a related value converted to a TaskPriority
* @param myParm the parameter passed to taskFun. Defaults to NULL.
*
* Upon construction the task will be created.
*
*/
TaskS(char const*name, void (*taskfun)(void *), TaskPriority priority_, void * myParm = 0) {
taskHandle = xTaskCreateStatic(taskfun, name, stackDepth, myParm, priority_, stack, &tcb);
}
protected:
// used by TaskClassS to avoid needing too much complications
TaskS(char const*name, void (*taskfun)(void *), TaskPriority priority_, unsigned portSHORT stackSize_,
void * myParm) {
(void) stackSize_;
taskHandle = xTaskCreateStatic(taskfun, name, stackDepth, myParm, priority_, stack, &tcb);
}
private:
StaticTask_t tcb;
StackType_t stack[stackDepth];
};
/**
* @brief Dynamically Created Task Wrapper
*/
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
template<> class TaskS<0> : public TaskBase {
public:
/**
* @brief Constructor.
*
* @param name The name of the task.
* @param taskfun The function implementing the task, should have type void (*taskfun)(void *)
* @param priority_ The priority of the task. Use the TaskPriority enum values or a related value converted to a TaskPriority
* @param stackSize Size of the stack to give to the task
* @param myParm the parameter passed to taskFun. Defaults to NULL.
*
* Upon construction the task will be created.
*
*/
TaskS(char const*name, void (*taskfun)(void *), TaskPriority priority_,
unsigned portSHORT stackSize, void * myParm = 0) {
xTaskCreate(taskfun, name, stackSize, myParm, priority_, &taskHandle);
}
};
typedef TaskS<0> Task;
#endif
/**
* @brief Make a class based task.
* Derive from TaskClass and the 'task()' member function will get called as the task based on the class.
*
* @tparam stackDepth Size of the stack to give to the task
*
* If task() returns the task will be deleted if deletion has been enabled.
* @ingroup FreeRTOSCpp
*/
template<uint32_t stackDepth> class TaskClassS : public TaskS<stackDepth> {
public:
/**
* @brief Constructor
*
* @param name The name of the task.
* @param priority_ The priority of the task. Use the TaskPriority enum values or a related value converted to a TaskPriority
* @param stackDepth_ How many words of stack to allocate to the task. Only used if the template parameter stackDepth is 0
*
* Note: At construction time the task will be created, so if the the scheduler has been started, the created task needs to
* have a priority less than the creating task so it can't start until after the class deriving from TaskClass has finished
* its constructor. If this is not true, the task will be created with a lower priority, and when it does get to run,
* it will correct its priority. If the task creating the new task is of IDLE priority, and time-slicing is enabled
* then there is a small chance that if a timer tick happens in the middle of creating the object, the system
* will switch to the incomplete task, so this is not advised.
* If INCLUDE_VTaskPrioritySet is not true, then this can't be done so the caller is responsible to enforce.
*
* This code is sort of ugly due to the conditional compilation. In words:
* * If we don't have vTaskPrioritySet, just create the task as specified, and it is the users job to make it work.
* * If we have vTaskPrioritySet but not uxTaskPriorityGet, tasks created when running start out at TaskPrio_Idle.
* * If we have both vTaskPrioritySet and uxTaskPriorityGet, then if the task is to be created with a priority greater
* than or equal to the creating task priority, then it will be created with a priority 1 less than the creating task
* (but not less than TaskPrio_Idle)
*/
TaskClassS(char const*name, TaskPriority priority_, unsigned portSHORT stackDepth_=0) :
TaskS<stackDepth>(name, &taskfun,
#if INCLUDE_vTaskPrioritySet
((xTaskGetSchedulerState() == taskSCHEDULER_RUNNING)
#if INCLUDE_uxTaskPriorityGet
&& (uxTaskPriorityGet(0) <= priority_)
#endif
) ? (
#if INCLUDE_uxTaskPriorityGet
(uxTaskPriorityGet(0) > TaskPrio_Idle ) ? static_cast<TaskPriority>(uxTaskPriorityGet(0)-1) :
#endif
TaskPrio_Idle) :
#endif
priority_,
stackDepth_, this)
#if INCLUDE_vTaskPrioritySet
, myPriority(priority_)
#endif
{
}
virtual ~TaskClassS() {}
/**
* @brief task function.
* The member function task needs to
*/
virtual void task() = 0;
private:
/**
* Trampoline for task.
*
* @todo Note, is a static function so normally compatible by calling convention
* with an ordinary C function, like FreeRTOS expects. For maximum portability
* we could change this to a free function declared as extern "C", but might need so
* tricks to escape out of template space.
*/
static void taskfun(void* myParm) {
TaskClassS *myTask = static_cast<TaskClassS *>(myParm);
#if INCLUDE_vTaskPrioritySet
myTask->priority(myTask->myPriority);
#endif
myTask->task();
// If we get here, task has returned, delete ourselves or block indefinitely.
#if INCLUDE_vTaskDelete
myTask->taskHandle = 0;
vTaskDelete(0); // Delete ourselves
#else
while(1)
vTaskDelay(portMAX_DELAY);
#endif
}
#if INCLUDE_vTaskPrioritySet
TaskPriority myPriority;
#endif
};
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
typedef TaskClassS<0> TaskClass;
#endif
#endif