-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathRTOS_prg.c
402 lines (368 loc) · 19.6 KB
/
RTOS_prg.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
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
396
397
398
399
400
401
402
/*
* RTOS_prg.c
*
* Created on: 14 Sep 2019
* Author: Yahia
*/
#include "std_types.h"
#include "common_macros.h"
#include "SysTick_interface.h"
#include "SysTick_config.h"
//#include "SysTick_private.h"
#include "RTOS_interface.h"
#include "RTOS_config.h"
#include "RTOS_private.h"
volatile uint32 OS_Tick = 0; // Counter for timer ticks.
TCB PeriodicQueue[MaxTaskNum]; // Task Control Block(TCB) for tasks.
volatile uint8 Periodic_Task_index; // The index(number) of the created tasks in the TCB.
volatile uint8 RunningTask; // The running task on the processor(if there is no running task then RunningTask will be the value of the lowest priority task +1).
volatile uint8 NonCompleted_Task_index = 0; // The index(number) of the interrupted tasks(non-completed tasks).
uint8 NonCompletedTasks[MaxTaskNum]; // Array of the interrupted tasks(non-completed tasks).
volatile uint8 EnterSchedulerState = NewTick; // Variable that indicate which state that made processor enter the scheduler.
void(*RunTask)(void) = STUB; // Pointer to the task that must be running on the processor.
void(*RunPreemptiveTask)(void) = STUB; // Pointer to the task that halted the processor and must run on it.
volatile uint8 IDLE_Flag = 1; // Variable that indicates that processor has no task to run and should enter idle state.
volatile uint8 TaskIsAlreadyRunning = 1; // Variable that tells the processor that the task that must run is already running.
volatile uint8 SchedulerState;
/* OS_Handler */
/* Function that is called when the the timer fires an interrupt. */
void OS_Handler(void){
OS_Tick++; /* Increase OS_Tick by 1 */
if(SchedulerState == SchedulerOn){ /* Check if the Scheduler if on */
EnterSchedulerState = NewTick; /* Define state of entering scheduler by NewTick state */
Scheduler(); /* Call scheduler */
}
else if(SchedulerState == SchedulerOff){ /* Check if the Scheduler if on */
}
}
/* OSSchedulerOn */
/* Function that turn the scheduler on */
/* Scheduler is on by default */
void OSSchedulerOn(void){
SchedulerState = SchedulerOn;
}
/* OSSchedulerOff */
/* Function that turn the scheduler off */
void OSSchedulerOff(void){
SchedulerState = SchedulerOff;
}
/* Start_OS */
/* Function that starts running OS. */
void Start_OS(void){
CheckPendingTasks(); /* Call CheckPendingTasks to check if there a pending
task and not defined what that is pending on. */
Set_CallBack(OS_Handler); /* Set timer handler to call OS_Handler */
SysTick_Init(OS_TickLength); /* Initialise timer to generate an interrupt every OS_TickLength */
SchedulerState = SchedulerOn; /* Turn the scheduler on */
while(1){
Scheduler(); /* Call scheduler */
if(ThereWasARunningTask){ /* Check if there is ready task to run */
RunTask(); /* Start executing the next task */
PeriodicQueue[RunningTask].state = OSTaskStateReady; /* The task is finished so we put it in the ready state */
NoRunningTask; /* Tell the processor that there is no task to run */
EnterSchedulerState = TaskIsOver; /* Define state of entering scheduler by TaskIsOver state */
}
else{
IDLE_Flag = 1; /* If there is no task to run then the processor must enter an idle state */
RunTask = STUB; /* Make the pointer points to an empty function */
}
while(IDLE_Flag); /* Enter an idle state */
}
}
/* RTOS_Init */
/* Function that initiates OS. */
void RTOS_Init(void){
Periodic_Task_index = 0; /* Initiate the index of TCB by 0 */
InitiatePeriodicQueue(); /* Initiate TCB */
InitiateMutex(); /* Initiate mutex */
}
/* ChangePriority */
/* Function for user to change the priority of task using its name. */
void ChangePriority(void(*Task_name)(void), uint8 Prior){
TCB TempStruct; /* Create local TCB structure */
TCB* Periodic_Task = &TempStruct; /* Create a pointer to the local TCB structure */
uint8 count = 0; /* Create and initiate counter */
if(CheckPriority(Prior)){ /* Check if the task exists in the TCB */
return; /* Exit */
}
while(count < Periodic_Task_index){ /* Loop on the task in the TCB */
if(PeriodicQueue[count].task_name == Task_name){ /* Check if the task's name exists in the TCB */
TempStruct = PeriodicQueue[count]; /* Assign the task that should be deleted to local TCB structure */
TempStruct.priority = Prior; /* Change priority */
DeleteFromPeriodicQueue(count); /* Delete the original task from TCB */
AddTaskToPeriodicQueue(Periodic_Task); /* Add the task with new priority to TCB */
return; /* Exit */
}
count++; /* Increase count by 1 */
}
//Error message: task not found
}
/* BlockTask */
/* Function for user to block task using its name. */
void BlockTask(void(*Task_name)(void), uint8 BlockerID){
uint8 count = 0; /* Create and initiate counter */
while(count < Periodic_Task_index){ /* Loop on the task in the TCB */
if(PeriodicQueue[count].task_name == Task_name){ /* Check if the task's name exists in the TCB */
PeriodicQueue[count].state = OSTaskStateBlocked; /* Change the task's state to Blocked state */
PeriodicQueue[count].Blocker = BlockerID; /* Change the task's Blocker ID to the new one */
return; /* Exit */
}
count++; /* Increase count by 1 */
}
//Error message: task not found
}
/* UnblockTask */
/* Function for user to unblock task using its name. */
void UnblockTask(void(*Task_name)(void)){
uint8 count = 0; /* Create and initiate counter */
while(count < Periodic_Task_index){ /* Loop on the task in the TCB */
if(PeriodicQueue[count].task_name == Task_name){ /* Check if the task's name exists in the TCB */
PeriodicQueue[count].state = OSTaskStateReady; /* Change the task's state to Ready state */
PeriodicQueue[count].Blocker = BLOCKER_NoBlocker; /* Change the task's Blocker ID to No Blocker */
return; /* Exit */
}
count++; /* Increase count by 1 */
}
//Error message: task not found
}
/* OSTaskCreatePending */
/* Function for user to tell what the function is pending on. */
void OSTaskCreatePending(void(*Task_name)(void), uint8* PTRtoService){
uint8 count = 0; /* Create and initiate counter */
while(count < Periodic_Task_index){ /* Loop on the task in the TCB */
if(PeriodicQueue[count].task_name == Task_name){ /* Check if the task's name exists in the TCB */
PeriodicQueue[count].state = OSTaskStatePending; /* Change the task's state to Pending state */
if(*PTRtoService == MutServiceID){ /* Check if the task is pending on mutex */
if(((MutexStruct*)PTRtoService) -> MutStatus == MutTaken){ /* Check if the mutex is taken */
PeriodicQueue[count].PendOn = OSTaskPendOnMutex |\
((((MutexStruct*)PTRtoService) -> MutID) << 4); /* Change the pend on value in the TCB to mutex */
}
else{
//Error message: the mutex you want to pend on is already ready.
PeriodicQueue[count].state = OSTaskStateReady; /* Change the task's state to Ready state */
PeriodicQueue[count].PendOn = OSTaskPendOnNothing; /* The task is pending on nothing */
return; /* Exit */
}
}
else if(*PTRtoService == EventServiceID){ /* Check if the task is pending on event */
}
else{
//Error message: unknown Service ID.
}
return; /* Exit */
}
count++; /* Increase count by 1 */
}
//Error message: task not found
}
/* CreatePeriodicTask */
/* Function for user create a periodic task. */
void CreatePeriodicTask(void(*Task_name)(void),\
uint32 Task_period,\
uint8 Task_priority,\
uint8 Task_state,\
sint32 Task_release_time){
TCB TempStruct; /* Create local TCB structure */
TCB* Periodic_Task = &TempStruct; /* Create a pointer to the local TCB structure */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Assigning the value of the task to the local TCB *
* * * * * * * * * * * * * * * * * * * * * * * * * * * */
Periodic_Task -> period = Task_period;
Periodic_Task -> priority = Task_priority;
Periodic_Task -> state = Task_state;
Periodic_Task -> task_name = Task_name;
Periodic_Task -> release_time = Task_release_time;
Periodic_Task -> Blocker = BLOCKER_NoBlocker;
Periodic_Task -> PendOn = OSTaskPendOnNothing;
if(CheckPriority(Task_priority)){ /* Check if the task exists in the TCB */
//Error message: The priority you choose for task is not valid.
return; /* Exit */
}
else if((Periodic_Task -> state) == OSTaskStatePending){ /* Check if the task in the Pending state */
Periodic_Task -> PendOn = OSTaskPendOnWaiting; /* Change the pend on value in the task's TCB to waiting state */
AddTaskToPeriodicQueue(Periodic_Task); /* Add task to TCB blocks */
}
else if((Periodic_Task -> state) == OSTaskStateReady){ /* Check if the task in the Ready state */
AddTaskToPeriodicQueue(Periodic_Task); /* Add task to TCB blocks */
}
else if((Periodic_Task -> state) == OSTaskStateBlocked){ /* Check if the task in the Blocked state */
Periodic_Task -> Blocker = BLOCKER_USER; /* Change the value of the Blocker in TCB to USER */
AddTaskToPeriodicQueue(Periodic_Task); /* Add task to TCB blocks */
}
else if((Periodic_Task -> state) == OSTaskStateRunning){ /* Check if the task in the Running state */
//Error message: it is not allowed to enter task state as Running.
}
else{
//Error message: Invalid value of task state.
}
}
/* OS_DelayMS */
/* Function to make delay */
void OS_DelayMS(uint32 milliseconds){
volatile uint32 Tick; /* Create a variable of timer ticks */
Tick = OS_Tick + (uint32)(milliseconds/OS_TickLength); /* Tick = the value of the ticks when the function exit */
while(OS_Tick < Tick); /* Loop until the time is out */
}
/* AddTaskToPeriodicQueue */
/* Function to add a task's TCB to TCB block. */
static void AddTaskToPeriodicQueue(TCB* PtrToTaskStruct){
uint8 count = 0; /* Create and initiate counter */
TCB temp_struct; /* Create local TCB structure */
PeriodicQueue[Periodic_Task_index] = *PtrToTaskStruct; /* Move the received TCB to TCB block */
while(count != Periodic_Task_index){ /* Loop on the TCB array */
if((PeriodicQueue[Periodic_Task_index].priority) <\
(PeriodicQueue[count].priority)){ /* Check if there is any higher priority task */
/* * * * * * * * * * * * *
* Swap between tasks *
* * * * * * * * * * * * */
temp_struct = PeriodicQueue[count];
PeriodicQueue[count] = PeriodicQueue[Periodic_Task_index];
PeriodicQueue[Periodic_Task_index] = temp_struct;
}
count++; /* Increase count by 1 */
}
Periodic_Task_index++; /* Increment index of TCB block */
}
/* SaveContext */
/* Function to save the context of the interrupted task. */
static void SaveContext(void){
volatile uint8 NonCompletedTask = RunningTask; /* Create a variable of the running task */
PeriodicQueue[NonCompletedTask].state = OSTaskStateReady; /* Change the state of the running task to ready state */
NonCompletedTasks[NonCompleted_Task_index] = NonCompletedTask; /* Put the index of the task in an array that holds the non completed tasks */
NonCompleted_Task_index++; /* Increment index of the array on non completed tasks */
}
/* RestoreContext */
/* Function to restore the context of the interrupted task. */
static void RestoreContext(void){
uint8 index = NonCompletedTasks[NonCompleted_Task_index - 1]; /* Create a variable that holds the value of the running task */
PeriodicQueue[index].state = OSTaskStateReady; /* Change the state of the running task to ready state */
NonCompleted_Task_index--; /* Decrement index of the array on non completed tasks */
PeriodicQueue[index].state = OSTaskStateRunning; /* Change the state of the interrupted task to running state */
RunTask = PeriodicQueue[index].task_name; /* Make the pointer points to the interrupted task */
RunningTask = index; /* Change running task variable to the interrupted task */
}
/* UpdateReleaseTime */
/* Function to update the release time for tasks in TCB */
static void UpdateReleaseTime(void){
uint8 count = 0; /* Create and initiate counter */
while(count != Periodic_Task_index){ /* Loop on the TCB array */
PeriodicQueue[count].release_time -= OS_TickLength; /* Update release time */
count++; /* Increase count by 1 */
}
}
/* StartScheduling */
/* Function to schedule on tasks */
static void StartScheduling(void){
uint8 count = 0; /* Create and initiate counter */
while(count != Periodic_Task_index){ /* Loop on the TCB array */
if((PeriodicQueue[count].release_time < 1) &&\
((PeriodicQueue[count].state == OSTaskStateReady) ||\
(PeriodicQueue[count].state == OSTaskStateRunning))){ /* Check if there is ready task to execute */
if(PeriodicQueue[count].state == OSTaskStateReady){ /* Check if the task is ready or if it is already running */
PeriodicQueue[count].state = OSTaskStateRunning; /* Change the state of the state of task to running state */
PeriodicQueue[count].release_time += PeriodicQueue[count].period; /* reset release time */
if(ThereWasARunningTask){ /* Check if there was a running task */
SaveContext(); /* Save the context of the interrupted task */
RunPreemptiveTask = PeriodicQueue[count].task_name; /* Make the pointer points to the new task */
}
else{
RunTask = PeriodicQueue[count].task_name; /* Make the pointer points to the ready task */
}
}
else if(PeriodicQueue[count].state == OSTaskStateRunning){ /* Check if the task was already running */
if(TaskSwitching) /* Check if there was a task switching */
TaskIsAlreadyRunning = 1; /* Tell the processor that the new task is already running */
}
RunningTask = PeriodicQueue[count].priority; /* Change running task variable to the new task */
return; /* Exit */
}
count++; /* Increase count by 1 */
}
}
/* HandleTaskSwitching */
/* Function to handle task switching on tasks */
static void HandleTaskSwitching(void){
RunPreemptiveTask(); /* Run the new task */
RestoreContext(); /* Restore the context of the interrupted task */
}
/* Scheduler */
/* Function to schedule on task */
void Scheduler(void){
IDLE_Flag = 0; /* Reset IDLE_Flag */
if(EnterSchedulerState == NewTick){ /* Check if the scheduler is entered by new timer tick */
UpdateReleaseTime(); /* Update release time of Tasks*/
StartScheduling(); /* Start scheduling */
if(TaskSwitching && (TaskIsAlreadyRunning != 1)){ /* Check if there is task switching */
HandleTaskSwitching(); /* Handle task switching and run the new task */
EnterSchedulerState = TaskIsOver; /* Update the state of entering the scheduler by TaskIsOver state */
TaskIsAlreadyRunning = 0; /* Reset the flag */
}
}
else if(EnterSchedulerState == TaskIsOver){ /* Check if the scheduler is entered after finishing previous task */
StartScheduling(); /* Start scheduling */
}
else if(EnterSchedulerState == MutexReleased){ /* Check if the scheduler is entered after releasing mutex */
StartScheduling(); /* Start scheduling */
if(TaskSwitching && (TaskIsAlreadyRunning != 1)){ /* Check if there is task switching */
HandleTaskSwitching(); /* Handle task switching and run the new task */
EnterSchedulerState = TaskIsOver; /* Update the state of entering the scheduler by TaskIsOver state */
TaskIsAlreadyRunning = 0; /* Reset the flag */
}
}
}
/* CheckPendingTasks */
/* Function that checks if the task in the pending state. */
static void CheckPendingTasks(void){
uint8 count = 0; /* Create and initiate counter */
while(count < Periodic_Task_index){ /* Loop on the task in the TCB */
if((PeriodicQueue[count].state == OSTaskStatePending) &&\
(PeriodicQueue[count].PendOn == OSTaskPendOnWaiting)){ /* Check if the state of the task is pending and if it has nothing to pend on */
//Error Message; you didn't define the value that the task is pending on.
return; /* Exit from the function */
}
count++; /* Increase count by 1 */
}
}
/* InitiatePeriodicQueue */
/* Function that initiates the TCB. */
static void InitiatePeriodicQueue(void){
uint8 count = 0; /* Create and initiate counter */
while(count < MaxTaskNum){ /* Loop on all possible places for task in TCB */
PeriodicQueue[count].state = OSTaskStateNoTask; /* Put all tasks in NoTask state */
count++; /* Increase count by 1 */
}
}
/* CheckPriority */
/* Function to check the priority of tasks. */
static uint8 CheckPriority(uint8 Prior){
uint8 count = 0; /* Create and initiate counter */
while(count < Periodic_Task_index){ /* Loop on the task in the TCB */
if(Prior == PeriodicQueue[count].priority) /* Check if the priority of the task exists in the TCB */
return 1; /* Return 1 that indicate that that function with this specified priority exists */
count++; /* Increase count by 1 */
}
return 0; /* Return 0 that indicate that that function with this specified priority doesn't exist */
}
/* DeleteFromPeriodicQueue */
/* Function to delete a task from TCB. */
static void DeleteFromPeriodicQueue(uint8 Index){
uint8 count = Index; /* Create and initiate counter by the index of function that should be deleted */
while(count < Periodic_Task_index){ /* Loop on the above tasks in the TCB */
PeriodicQueue[count] = PeriodicQueue[count +1]; /* Replace each task by the function above it in the TCB */
count++; /* Increase count by 1 */
}
Periodic_Task_index--; /* Decrement index of TCB by 1 */
}
/* DeleteTask */
/* Function for user to delete a task using its name. */
void DeleteTask(void(*Task_name)(void)){
uint8 count = 0; /* Create and initiate counter */
while(count < Periodic_Task_index){ /* Loop on the task in the TCB */
if(PeriodicQueue[count].task_name == Task_name){ /* Check if the task's name exists in the TCB */
DeleteFromPeriodicQueue(PeriodicQueue[count].priority); /* Delete the Task */
return; /* Exit */
}
count++; /* Increase count by 1 */
}
//Error message: task not found
}