-
Notifications
You must be signed in to change notification settings - Fork 1
/
TISM_TaskManager.c
321 lines (274 loc) · 21.1 KB
/
TISM_TaskManager.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
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
/*
TISM_TaskManager.c
==================
Library with functions to manipulate task properties and system states, when requested via messages.
All manipulation of system and task states are handled via TISM_Taskmanager to prevent two tasks from changing
the state of things at the same time, with unexpected results. As only one instance of TISM_Taskmanager can run at a
time, thread safety is achieved.
Note: Still we're not completely thread-safe as TISM_Taskmanager can write to these variables, but
TISM_Scheduler running on another core can attempt to read the same variable at the same time.
Copyright (c) 2024 Maarten Klarenbeek (https://github.com/mjklaren)
Distributed under the GPLv3 license
*/
#include <stdio.h>
#include <stdint.h>
#include "pico/stdlib.h"
#include "TISM.h"
/*
Description
Set the specified attribute of a task (see attibutes above).
Parameters:
TISM_Task ThisTask - Struct containing all task related information.
uint8_t TargetTaskID - TaskID of the task to change
uint8_t AttributeToChange - Attribute to change (see below)
uint32_t Setting - New setting (see below)
Return value:
ERR_INVALID_OPERATION - Invalid request
ERR_TASK_NOT_FOUND - Specified task not found
OK - Succes
AttributeToChange and corresponding Setting values:
TISM_SET_TASK_STATE - Change the state of a task.
Setting: Custom value or predefined (recommended): DOWN, STOP, RUN or INIT
TISM_SET_TASK_PRIORITY - Set the priority of a specific task to PRIORITY
Setting: PRIORITY_LOW, PRIORITY_NORMAL or PRIORITY_HIGH
TISM_SET_TASK_SLEEP - Set the sleep state of a specific state
Setting: true or false
TISM_SET_TASK_WAKEUPTIME - Set the timestamp of the next wake up (in usec); interpreted as "NOW"+timestamp
Setting: timestamp in usec
TISM_SET_TASK_DEBUG - Set the debug level of a specific task
Setting: DEBUG_NONE, DEBUG_NORMAL or DEBUG_HIGH
TISM_WAKE_ALL_TASKS - Wake all tasks.
Setting: 0
TISM_DEDICATE_TO_TASK - Dedicate the whole system to a specific task (use with caution)
Setting: 0
*/
uint8_t TISM_TaskManagerSetTaskAttribute(struct TISM_Task ThisTask, uint8_t TargetTaskID, uint8_t AttributeToChange, uint32_t Setting)
{
// Check if the specified Task ID is valid and if it's not a TISM-system task.
if(TISM_IsValidTaskID(TargetTaskID))
{
// Some attributes for system-tasks can only be changed by other system tasks. Other tasks are not allowed for system tasks.
switch(AttributeToChange)
{
case TISM_SET_TASK_WAKEUPTIME: // Set the task wakeup timer at utime + the specified usec.
case TISM_SET_TASK_PRIORITY :
case TISM_SET_TASK_SLEEP : // When system tasks; only allowed when requested by other system tasks.
if(TISM_IsSystemTask(TargetTaskID))
{
if(TISM_IsSystemTask(ThisTask.TaskID))
{
// Compose a message to Task Manager to adjust the attributes.
TISM_PostmanWriteMessage(ThisTask,System.TISM_TaskManagerTaskID,AttributeToChange,Setting,TargetTaskID);
}
else
{
// Attempt to change priority or sleep state of a system task by a non-system task.
TISM_EventLoggerLogEvent (ThisTask, TISM_LOG_EVENT_ERROR, "Attempt to change priority, wakeup time or sleep state of system task by non-system task, which is not allowed.");
return(ERR_INVALID_OPERATION);
}
}
else
{
// Target is not a system task. Forward the requested operation.
TISM_PostmanWriteMessage(ThisTask,System.TISM_TaskManagerTaskID,AttributeToChange,Setting,TargetTaskID);
}
break;
case TISM_DEDICATE_TO_TASK : // Not allowed for system tasks
if(TISM_IsSystemTask(TargetTaskID))
{
TISM_EventLoggerLogEvent (ThisTask, TISM_LOG_EVENT_ERROR, "Task dedication requested for a system task, which is not allowed.");
return(ERR_INVALID_OPERATION);
}
else
{
// Compose a message to Task Manager to adjust the attributes.
TISM_PostmanWriteMessage(ThisTask,System.TISM_TaskManagerTaskID,AttributeToChange,Setting,TargetTaskID);
}
break;
case TISM_WAKE_ALL_TASKS :
case TISM_SET_TASK_STATE :
case TISM_SET_TASK_DEBUG : // No checking here.
TISM_PostmanWriteMessage(ThisTask,System.TISM_TaskManagerTaskID,AttributeToChange,Setting,TargetTaskID);
break;
default : // Unknown action requested; generate error message.
TISM_EventLoggerLogEvent (ThisTask, TISM_LOG_EVENT_ERROR, "Unknown attribute change (%d) requested.", AttributeToChange);
return(ERR_INVALID_OPERATION);
break;
}
}
else
return(ERR_TASK_NOT_FOUND);
return(OK);
}
/*
Description
Wrapper for TISM_TaskManagerSetTaskAttribute; set the specified attribute for the requesting task itself.
Parameters:
TISM_Task ThisTask - Struct containing all task related information.
uint8_t AttributeToChange - Attribute to change (see below)
uint32_t Setting - New setting (see below)
Return value:
ERR_INVALID_OPERATION - Invalid request
ERR_TASK_NOT_FOUND - Specified task not found
OK - Succes
AttributeToChange and corresponding Setting values:
TISM_SET_TASK_STATE - Change the state of a task.
Setting: Custom value or predefined (recommended): DOWN, STOP, RUN or INIT
TISM_SET_TASK_PRIORITY - Set the priority of a specific task to PRIORITY
Setting: PRIORITY_LOW, PRIORITY_NORMAL or PRIORITY_HIGH
TISM_SET_TASK_SLEEP - Set the sleep state of a specific state
Setting: true or false
TISM_SET_TASK_WAKEUPTIME - Set the timestamp of the next wake up (in usec); interpreted as "NOW"+timestamp
Setting: timestamp in usec
TISM_SET_TASK_DEBUG - Set the debug level of a specific task
Setting: DEBUG_NONE, DEBUG_NORMAL or DEBUG_HIGH
TISM_WAKE_ALL_TASKS - Wake all tasks.
Setting: 0
TISM_DEDICATE_TO_TASK - Dedicate the whole system to a specific task (use with caution)
Setting: 0
*/
uint8_t TISM_TaskManagerSetMyTaskAttribute(struct TISM_Task ThisTask, uint8_t AttributeToChange, uint32_t Setting)
{
return(TISM_TaskManagerSetTaskAttribute(ThisTask,ThisTask.TaskID,AttributeToChange,Setting));
}
/*
Description
Set the state of the entire TISM system. Any task can alter the system state.
Parameters:
TISM_Task ThisTask - Struct containing all task related information.
uint8_t SystemState - System state (see above)
Return value:
non-zero value - Error sending the request
OK - Succes
*/
uint8_t TISM_TaskManagerSetSystemState(struct TISM_Task ThisTask, uint8_t SystemState)
{
return(TISM_PostmanWriteMessage(ThisTask,System.TISM_TaskManagerTaskID,TISM_SET_SYS_STATE,SystemState,0));
}
/*
Description:
This is the TaskManager-function that is registered in the TISM-system.
This function is called by TISM_Scheduler.
Parameters:
TISM_Task ThisTask - Struct containing all task related information.
Return value:
<non zero value> - Task returned an error when executing.
OK - Run succesfully completed.
*/
uint8_t TISM_TaskManager (TISM_Task ThisTask)
{
if (ThisTask.TaskDebug==DEBUG_HIGH) TISM_EventLoggerLogEvent (ThisTask, TISM_LOG_EVENT_NOTIFY, "Run starting.");
switch(ThisTask.TaskState) // Unknown states are ignored
{
case INIT: // Task required to initialize
if (ThisTask.TaskDebug) TISM_EventLoggerLogEvent (ThisTask, TISM_LOG_EVENT_NOTIFY, "Initializing with priority %d.", ThisTask.TaskPriority);
// Bring tasks TaskManager, Postman, IRQHandler and Watchdog to sleep.
System.Task[System.TISM_TaskManagerTaskID].TaskSleeping=true;
System.Task[System.TISM_PostmanTaskID].TaskSleeping=true;
System.Task[System.TISM_IRQHandlerTaskID].TaskSleeping=true;
break;
case RUN: // Do the work
if (ThisTask.TaskDebug==DEBUG_HIGH) TISM_EventLoggerLogEvent (ThisTask, TISM_LOG_EVENT_NOTIFY, "Doing work with priority %d on core %d.", ThisTask.TaskPriority, ThisTask.RunningOnCoreID);
/*
Mapping between messaging structure and TaskManager fields:
MessageToProcess->MessageType = AttributeToChange
MessageToProcess->Message = Setting
MessageToProcess->TargetTaskID = Specification
*/
int MessageCounter=0;
TISM_Message *MessageToProcess;
while((TISM_PostmanMessagesWaiting(ThisTask)>0) && (MessageCounter<MAX_MESSAGES))
{
MessageToProcess=TISM_PostmanReadMessage(ThisTask);
// We received a message; figure out what we need to do.
switch(MessageToProcess->MessageType)
{
case TISM_PING: // Check if this process is still alive. Reply with a ECHO message type; return same message payload.
TISM_PostmanWriteMessage(ThisTask,MessageToProcess->SenderTaskID,TISM_ECHO,MessageToProcess->Message,0);
break;
case TISM_SET_TASK_SLEEP: // Change the sleep state of the specified task.
if(ThisTask.TaskDebug) TISM_EventLoggerLogEvent (ThisTask, TISM_LOG_EVENT_NOTIFY, "AttributeToChange %d (TISM_SET_TASK_SLEEP) for TargetTaskID %d (%s) with setting %ld received from TaskID %d (%s).", MessageToProcess->MessageType, MessageToProcess->Specification, System.Task[MessageToProcess->Specification].TaskName, MessageToProcess->Message, MessageToProcess->SenderTaskID, System.Task[MessageToProcess->SenderTaskID].TaskName);
if(MessageToProcess->Message==0)
{
// Task needs to be awake. Check if this is not already the case.
if(System.Task[(uint8_t)MessageToProcess->Specification].TaskSleeping==true)
{
System.Task[(uint8_t)MessageToProcess->Specification].TaskSleeping=false;
System.Task[(uint8_t)MessageToProcess->Specification].TaskWakeUpTimer=time_us_64();
}
}
else
System.Task[(uint8_t)MessageToProcess->Specification].TaskSleeping=true;
break;
case TISM_SET_TASK_WAKEUPTIME: // Change the wake up time for the specified task, in "Now¨ + specified usec.
if(ThisTask.TaskDebug) TISM_EventLoggerLogEvent (ThisTask, TISM_LOG_EVENT_NOTIFY, "AttributeToChange %d (TISM_SET_WAKEUP_TIME) for TargetTaskID %d (%s) with setting utime + %ld received from TaskID %d (%s).", MessageToProcess->MessageType, MessageToProcess->Specification, System.Task[MessageToProcess->Specification].TaskName, MessageToProcess->Message, MessageToProcess->SenderTaskID, System.Task[MessageToProcess->SenderTaskID].TaskName);
System.Task[(uint8_t)MessageToProcess->Specification].TaskWakeUpTimer=time_us_64()+MessageToProcess->Message;
break;
case TISM_SET_SYS_STATE: // Change the state of the whole system (aka runlevel).
if(ThisTask.TaskDebug) TISM_EventLoggerLogEvent (ThisTask, TISM_LOG_EVENT_NOTIFY, "Set system state (TISM_SET_SYS_STATE) to %d received from TaskID %d (%s).", MessageToProcess->Message, MessageToProcess->SenderTaskID, System.Task[MessageToProcess->SenderTaskID].TaskName);
System.State=(uint8_t)MessageToProcess->Message;
if(System.SystemDebug) TISM_EventLoggerLogEvent (ThisTask, TISM_LOG_EVENT_NOTIFY, "System state changed to %d.", System.State);
break;
case TISM_SET_TASK_STATE: // Change the state of the specified task. These can be custom values.
if(ThisTask.TaskDebug) TISM_EventLoggerLogEvent (ThisTask, TISM_LOG_EVENT_NOTIFY, "AttributeToChange %d (TISM_SET_TASK_STATE) for TargetTaskID %d (%s) with setting %ld received from TaskID %d (%s).", MessageToProcess->MessageType, MessageToProcess->Specification, System.Task[MessageToProcess->Specification].TaskName, MessageToProcess->Message, MessageToProcess->SenderTaskID, System.Task[MessageToProcess->SenderTaskID].TaskName);
System.Task[(uint8_t)MessageToProcess->Specification].TaskState=(uint8_t)MessageToProcess->Message;
break;
case TISM_SET_TASK_PRIORITY: // Set the priority of a specific task to the specified priority level.
if(ThisTask.TaskDebug) TISM_EventLoggerLogEvent (ThisTask, TISM_LOG_EVENT_NOTIFY, "AttributeToChange %d (TISM_SET_TASK_PRIORITY) for TargetTaskID %d (%s) with setting %ld received from TaskID %d (%s).", MessageToProcess->MessageType, MessageToProcess->Specification, System.Task[MessageToProcess->Specification].TaskName, MessageToProcess->Message, MessageToProcess->SenderTaskID, System.Task[MessageToProcess->SenderTaskID].TaskName);
System.Task[(uint8_t)MessageToProcess->Specification].TaskPriority=MessageToProcess->Message;
break;
case TISM_WAKE_ALL_TASKS: // Wake all tasks.
if(ThisTask.TaskDebug) TISM_EventLoggerLogEvent (ThisTask, TISM_LOG_EVENT_NOTIFY, "Wake all tasks (TISM_WAKE_ALL_TASKS) received from TaskID %d (%s).", MessageToProcess->SenderTaskID, System.Task[MessageToProcess->SenderTaskID].TaskName);
for(uint8_t TaskCounter=0;TaskCounter<System.NumberOfTasks;TaskCounter++)
{
// Only wake tasks that are currently sleeping; do not interfere with existing time schedules.
if(System.Task[TaskCounter].TaskSleeping==true)
{
System.Task[TaskCounter].TaskWakeUpTimer=time_us_64();
System.Task[TaskCounter].TaskSleeping=false;
}
}
if(ThisTask.TaskDebug) TISM_EventLoggerLogEvent (ThisTask, TISM_LOG_EVENT_NOTIFY, "All tasks have been woken up.");
break;
case TISM_DEDICATE_TO_TASK: // Dedicate the whole system to a specific task - use with caution.
// Check first if the target task is not sleeping.
if(ThisTask.TaskDebug) TISM_EventLoggerLogEvent (ThisTask, TISM_LOG_EVENT_NOTIFY, "Dedicate to task (TISM_DEDICATE_TO_TASK) requested for %d (%s) by TaskID %d (%s).", (int)MessageToProcess->Message, System.Task[(int)MessageToProcess->Message].TaskName, MessageToProcess->SenderTaskID, System.Task[MessageToProcess->SenderTaskID].TaskName);
if(!System.Task[(uint8_t)MessageToProcess->Message].TaskSleeping)
{
// Yes, put all other tasks to sleep.
for(uint8_t TaskIDCounter=0;TaskIDCounter<System.NumberOfTasks;TaskIDCounter++)
{
// Only non-system tasks are put to sleep.
if((TaskIDCounter!=MessageToProcess->Message) && (!TISM_IsSystemTask(TaskIDCounter)))
System.Task[TaskIDCounter].TaskSleeping=true;
}
if(ThisTask.TaskDebug) TISM_EventLoggerLogEvent (ThisTask, TISM_LOG_EVENT_NOTIFY, "Warning - system now dedicated to task ID %d (%s).", (int)MessageToProcess->Message, System.Task[(int)MessageToProcess->Message].TaskName);
}
else
TISM_EventLoggerLogEvent (ThisTask, TISM_LOG_EVENT_ERROR, "Task to dedicate to (%s,ID %d) is sleeping. Aborting.", System.Task[(int)MessageToProcess->Message].TaskName, (int)MessageToProcess->Message);
break;
case TISM_SET_TASK_DEBUG: // Set the debug level for a task to the specified value.
if(ThisTask.TaskDebug) TISM_EventLoggerLogEvent (ThisTask, TISM_LOG_EVENT_NOTIFY, "AttributeToChange %d (TISM_SET_TASK_DEBUG) for TargetTaskID %d (%s) with setting %ld received from TaskID %d (%s).", MessageToProcess->MessageType, MessageToProcess->Specification, System.Task[MessageToProcess->Specification].TaskName, MessageToProcess->Message, MessageToProcess->SenderTaskID, System.Task[MessageToProcess->SenderTaskID].TaskName);
System.Task[(uint8_t)MessageToProcess->Specification].TaskDebug=(uint8_t)MessageToProcess->Message;
break;
default: // Invalid or not yet implemented message type - ignore.
break;
}
// Processed the message; delete it.
TISM_PostmanDeleteMessage(ThisTask);
MessageCounter++;
}
// Go to sleep; we only wake on incoming messages (only TaskManager can do this directly).
System.Task[ThisTask.TaskID].TaskSleeping=true;
break;
case STOP: // Tasks required to stop
if (ThisTask.TaskDebug) TISM_EventLoggerLogEvent (ThisTask, TISM_LOG_EVENT_NOTIFY, "Stopping.");
// Tasks for stopping
// Set the task state to DOWN (only TaskManager can do this directly).
System.Task[ThisTask.TaskID].TaskState=DOWN;
break;
}
// All done.
if (ThisTask.TaskDebug==DEBUG_HIGH) TISM_EventLoggerLogEvent (ThisTask, TISM_LOG_EVENT_NOTIFY, "Run completed.");
return (OK);
}