Added some more code to the scheduler
Added more functionality to the scheduler. It should be able to select the task that should run and soon be able to create tasks. Not fully finished but its not that much left to add
This commit is contained in:
parent
5c09d34c92
commit
8eda8ba66d
@ -2,7 +2,7 @@
|
||||
* NAME: scheduler.h *
|
||||
* PURPOSE: Defining the the scheduler to be used in the system to organize*
|
||||
* the runtime for the tasks in the system based on priority. *
|
||||
* INFORMATION: *
|
||||
* INFORMATION: Many elements and ideas obtained from beta/cleanflight *
|
||||
* GLOBAL VARIABLES: *
|
||||
* Variable Type Description *
|
||||
* -------- ---- ----------- *
|
||||
@ -45,7 +45,13 @@ typedef struct
|
||||
uint32_t lastExecutedAt; /* last time of invocation */
|
||||
uint32_t lastSignaledAt; /* time of invocation event for event-driven tasks */
|
||||
|
||||
/* ToDo: potential statistic values of the task */
|
||||
/* Statistic values of the task */
|
||||
uint32_t averageExecutionTime; // Moving average over 6 samples, used to calculate guard interval
|
||||
uint32_t taskLatestDeltaTime; //
|
||||
#ifndef SKIP_TASK_STATISTICS
|
||||
uint32_t maxExecutionTime;
|
||||
uint32_t totalExecutionTime; // total time consumed by task since boot
|
||||
#endif
|
||||
|
||||
}task_t;
|
||||
|
||||
@ -90,7 +96,9 @@ typedef enum
|
||||
}taskId_t;
|
||||
|
||||
/* Variables --------------------------------------------------------------------------------- */
|
||||
|
||||
extern task_t SystemTasks[TASK_COUNT]; /* All the tasks that exist in the system */
|
||||
extern uint16_t CpuLoad; /* The current load on the cpu Todo */
|
||||
extern uint16_t averageSystemLoadPercent; /* The average load on the system Todo */
|
||||
|
||||
|
||||
/* Functions that operate can operate on the tasks ------------------------------------------- */
|
||||
|
@ -9,16 +9,23 @@
|
||||
***************************************************************************/
|
||||
|
||||
#include "Scheduler/scheduler.h"
|
||||
#include "stm32f4xx_revo.h"
|
||||
|
||||
static uint32_t tasksReadyToRun;
|
||||
|
||||
//Todo: change for several instances where 0 is used as null to the define value NULL
|
||||
|
||||
static task_t *currentTask = 0;
|
||||
|
||||
static uint32_t totalSchedulerPasses; /* Number of times the scheduler has been invoked */
|
||||
static uint32_t totalSchedulerReadyTasks; /* The amount of tasks that totally has been ready in the scheduler */
|
||||
|
||||
uint32_t currentTime = 0;
|
||||
uint16_t averageSystmeLoad = 0;
|
||||
|
||||
static int taskQueuePos = 0;
|
||||
static int taskQueueSize = 0;
|
||||
static int taskReadyQueuePos = 0;
|
||||
static int taskReadyQueueSize = 0;
|
||||
|
||||
static task_t * taskReadyQueue[TASK_COUNT + 1]; /* Array holding all the tasks that are ready to run in the system */
|
||||
static task_t * taskReadyQueue[TASK_COUNT + 1]; /* Array holding all the tasks that are ready to run in the system + 1 for a NULL value at the end*/
|
||||
|
||||
|
||||
/* Functions to operate on the task queue ------------------------------------------------------- */
|
||||
@ -29,7 +36,10 @@ static task_t * taskReadyQueue[TASK_COUNT + 1]; /* Array holding all the tasks
|
||||
**************************************************************************/
|
||||
void taskReadyQueueClear(void)
|
||||
{
|
||||
|
||||
//Empties the queue by settin all the positions to 0(NULL)
|
||||
memset(taskReadyQueue, 0, sizeof(taskReadyQueue));
|
||||
taskReadyQueuePos = 0;
|
||||
taskReadyQueueSize = 0;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
@ -39,7 +49,7 @@ void taskReadyQueueClear(void)
|
||||
bool taskReadyQueueContains(task_t *task)
|
||||
{
|
||||
//Go through the taskReadyQueue to see if the current task is contained
|
||||
for (int i = 0; i < taskQueueSize; i++)
|
||||
for (int i = 0; i < taskReadyQueueSize; i++)
|
||||
{
|
||||
if (taskReadyQueue[i] == task)
|
||||
{
|
||||
@ -56,7 +66,60 @@ bool taskReadyQueueContains(task_t *task)
|
||||
**************************************************************************/
|
||||
bool taskReadyQueueAdd(task_t *task)
|
||||
{
|
||||
int i; /* Iterator */
|
||||
int j; /* Inner iterator used to sort based on desired period */
|
||||
|
||||
//Check if the task is in the queue already
|
||||
if (taskReadyQueueContains(task) || taskReadyQueueSize >= TASK_COUNT)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//Try to add the task to the taskReadyQueue at a good position
|
||||
//Order is: staticPriority > desired period > all else
|
||||
//<= taskReadyQueueSize because if we go through the entire thing we should get a null value
|
||||
//representing the position directly after the last one in the queue.
|
||||
for (i = 0; i < taskReadyQueueSize; i++)
|
||||
{
|
||||
//check if the static prio of the current position in the queue is less than the task we want to add
|
||||
if(taskReadyQueue[i]->staticPriority < task->staticPriority)
|
||||
{
|
||||
//order tasks based on lowest period first, within the ones with the same priority
|
||||
//ToDo: check if setting j to i-1 initially will produce the same result, in that case add another iterator to get item from taskReadyQueue
|
||||
for (j = i; taskReadyQueue[j]->staticPriority == task->staticPriority; j++ )
|
||||
{
|
||||
//If the new task has a shorter period place in front
|
||||
if (task->desiredPeriod <= taskReadyQueue[j]->desiredPeriod)
|
||||
{
|
||||
//remove one increment because otherwise it will be wrong
|
||||
j--;
|
||||
}
|
||||
}
|
||||
//task does not have shorter period than any other with the same priority, add behind them
|
||||
j++;
|
||||
memmove(&taskReadyQueue[j+1], &taskReadyQueue[j], sizeof(task) * (taskReadyQueueSize - j));
|
||||
taskReadyQueue[j] = task;
|
||||
++taskReadyQueueSize;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
//If this is true it needs to be placed at the very back of the queue
|
||||
if (taskReadyQueue[i] == NULL )
|
||||
{
|
||||
//if taskReadyQueueSize > 0 we need to increment the counter i
|
||||
if (taskReadyQueueSize > 0)
|
||||
{
|
||||
i++;
|
||||
}
|
||||
|
||||
taskReadyQueue[i] = task; //ToDo: check if this works correctly, that a new NULL value will exist at i+1
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//Could not add the task in the anywhere in the queue
|
||||
return false;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
@ -65,7 +128,14 @@ bool taskReadyQueueAdd(task_t *task)
|
||||
**************************************************************************/
|
||||
bool taskReadyQueueRemove(task_t *task)
|
||||
{
|
||||
|
||||
for (int i = 0; i < taskReadyQueueSize; ++i) {
|
||||
if (taskReadyQueue[i] == task) {
|
||||
memmove(&taskReadyQueue[i], &taskReadyQueue[i+1], sizeof(task) * (taskReadyQueueSize - i));
|
||||
--taskReadyQueueSize;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -77,7 +147,14 @@ bool taskReadyQueueRemove(task_t *task)
|
||||
**************************************************************************/
|
||||
void enableTask(taskId_t taskId, bool enabled)
|
||||
{
|
||||
|
||||
if (taskId == TASK_SELF || taskId < TASK_COUNT) {
|
||||
task_t *task = taskId == TASK_SELF ? currentTask : &SystemTasks[taskId];
|
||||
if (enabled && task->taskFunction) {
|
||||
taskReadyQueueAdd(task);
|
||||
} else {
|
||||
taskReadyQueueRemove(task);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
@ -86,7 +163,12 @@ void enableTask(taskId_t taskId, bool enabled)
|
||||
**************************************************************************/
|
||||
uint32_t getTaskDeltaTime(taskId_t taskId)
|
||||
{
|
||||
|
||||
if (taskId == TASK_SELF || taskId < TASK_COUNT) {
|
||||
task_t *task = taskId == TASK_SELF ? currentTask : &SystemTasks[taskId];
|
||||
return task->taskLatestDeltaTime;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
@ -104,7 +186,9 @@ void rescheduleTask(taskId_t taskId, uint32_t newPeriodMicros)
|
||||
**************************************************************************/
|
||||
void initScheduler(void)
|
||||
{
|
||||
|
||||
/*Todo: what needs to be init for the scheduler, should all the tasks
|
||||
* be added to the readyTasksqueue here or should it be done at in
|
||||
* another place in the code. */
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
@ -113,6 +197,67 @@ void initScheduler(void)
|
||||
**************************************************************************/
|
||||
void scheduler(void)
|
||||
{
|
||||
/*ToDo: implement the function micros that should give the current
|
||||
* time in microseconds. Not entirely sure how it should be obtained,
|
||||
* needs to be looked into and solved otherwise no time can be gotten */
|
||||
currentTime = micros();
|
||||
task_t * taskToRun;
|
||||
uint32_t currentDynamicPriority = 0;
|
||||
uint32_t currentReadyTasks = 0;
|
||||
float currentAgeCyckleExact = 0;
|
||||
float ageCycleExact = 0;
|
||||
|
||||
/* Check if a task has entered a new period and assign its new dynamic priority */
|
||||
/* Go through all the tasks to check if they should be able to run */
|
||||
for (int i = 0; i < taskReadyQueueSize; i++)
|
||||
{
|
||||
//Get the next task in the queue
|
||||
taskToRun = taskReadyQueue[i];
|
||||
|
||||
/* Check if the task is an event, else its a time controlled task */
|
||||
if (taskToRun->checkEventTriggered != NULL)
|
||||
{
|
||||
//ToDO: Handle event tasks, they should get to operate at a higher priority
|
||||
|
||||
}
|
||||
else //Handle time controlled tasks
|
||||
{
|
||||
//Calculate a new age cycle for the task. It represents if the task is in a new "period" in relation to its last execution
|
||||
//If the value is 0 it is still in the same "period" as the last execution
|
||||
taskToRun->taskAgeCycle = (currentTime - taskToRun->lastExecutedAt) / taskToRun->desiredPeriod;
|
||||
|
||||
//May not be used. Could be used to check what task is closest to its next period instance
|
||||
ageCycleExact = ((float)currentTime - (float)taskToRun->lastExecutedAt) / (float)taskToRun->desiredPeriod;
|
||||
|
||||
//Check if > 0, if it has entered a new "period"
|
||||
if (taskToRun->taskAgeCycle > 0)
|
||||
{
|
||||
//Calculate the new dynamic priority for the task
|
||||
taskToRun->dynamicPriority = 1 + taskToRun->taskAgeCycle * taskToRun->staticPriority;
|
||||
currentReadyTasks ++; //Increase the number of ready tasks
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//If the current task has the largest dynamic priority so far it could be a candidate for execution
|
||||
if(taskToRun->dynamicPriority > currentDynamicPriority)
|
||||
{
|
||||
|
||||
}
|
||||
else if(taskToRun->dynamicPriority == currentDynamicPriority) //The comparing tasks have the same priority
|
||||
{
|
||||
//if the tasks have the same priority check who is closest to its deadline and run that one
|
||||
if (ageCycleExact > currentAgeCyckleExact)
|
||||
{
|
||||
//If the ageCycleExact is larger than the one of the current task we will change the priority of the one to run
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} /* for-loop end */
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user