-
Notifications
You must be signed in to change notification settings - Fork 2
/
TaskScheduler.c
127 lines (112 loc) · 4 KB
/
TaskScheduler.c
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
#include "TaskScheduler.h"
#include "TS_Priorities.h"
#include "TS_Timing.h"
// Counter to keep track of the number of tasks created
static uint16_t allocated_tasks = 0;
// This is the pool of tasks that can be assigned
static TS_Task_T task_pool[MAX_NUM_TASKS];
static bool all_tasks_initialized = false;
// The idle function pointer. By default it is null
static TS_Callback_T idle_function;
// local function for executing a task
static void executeTaskAndHandleResults(TS_Task_T * t, TS_Time_T current_time);
// This function initialize internal crap of the scheduler. It must be called at the very beginning of the program
void TS_Initialize(void)
{
int i;
for(i=0; i<MAX_NUM_TASKS; i++)
{
task_pool[i].enabled = false;
task_pool[i].needs_more_time = false;
task_pool[i].init_complete = false;
}
}
// Add a new task to the list of tasks to execute.
// p is the callback function to execute when the task is due
TS_Task_T * TS_AddTask(uint16_t period, uint8_t priority, TS_Callback_T f)
{
// Initialize the task
TS_Task_T * t = &task_pool[allocated_tasks];
t->period_ms = period;
t->callback = f;
t->init_complete = true; // At this point we don't have an init func.
t->needs_more_time = false;
t->enabled = true;
all_tasks_initialized = false;
// Increment the count and return a pointer to the task
allocated_tasks++;
return t;
}
// Every task can have an Init function that is called once after a specific amount of time
// after startup. Use this function to setup the init function for a task.
// Calling this is optional. By defalt there is no init funcion for tasks.
void TS_SetupTaskInitFunc(TS_Task_T * p_task, TS_Callback_T f, TS_TimeSpan_T delay)
{
p_task->init_delay_ms = delay;
p_task->init_func = f;
p_task->init_complete = false;
}
void TS_SetIdleFunc(TS_Callback_T f)
{
idle_function = f;
}
// This is the function that should be called from the main program loop
void TS_Process_Tasks(TS_Time_T current_time)
{
// declare an array of pointers to tasks.
TS_Task_T * pending_tasks[MAX_NUM_TASKS];
// Check for tasks ready to be initialized
if(!all_tasks_initialized)
{
TS_Task_T * task_to_init = TS_GetNextTaskToInit(task_pool);
if(task_to_init != NULL)
{
// Call the tasks init function
task_to_init->init_func();
task_to_init->initialized = true;
// Check if all tasks are initialized
if(TS_GetNumTasksAwatingInit(task_pool) == 0)
all_tasks_initialized = true;
}
}
{
// Check for expired tasks
uint8_t task_cnt = TS_GetExpiredTaskList(task_pool, pending_tasks);
if(task_cnt)
{
// Get the highest priority one if there are multiple
TS_Task_T * t = TS_GetHighestPriorityTask(pending_tasks, task_cnt);
executeTaskAndHandleResults(t, current_time);
}
else
{
// Check for tasks that need more work
task_cnt = TS_GetTasksNeedingMoreWork(pending_tasks);
// Get the highest priority one if there are multiple;
if(task_cnt)
{
// Get the highest priority one if there are multiple
TS_Task_T * t = TS_GetHighestPriorityTask(pending_tasks, task_cnt);
executeTaskAndHandleResults(t, current_time);
}
else
{
// Call the idle function (if it has been defined!)
if(idle_function) idle_function();
}
}
}
}
static void executeTaskAndHandleResults(TS_Task_T * t, TS_Time_T current_time)
{
// Call the task callback
TS_Task_Results r = t->callback();
// Set the next call time
t->next_do_time = TS_GetNextCallTime(t->period, current_time);
// Handle the results
t->needs_more_time = false;
if(r == INCOMPLETE)
t->needs_more_time = true;
else if (r == KILL_TASK)
t->enabled = false;
}