2013-04-13 21:50:47 +02:00
|
|
|
/**
|
|
|
|
******************************************************************************
|
|
|
|
*
|
|
|
|
* @file callbackscheduler.c
|
2013-04-14 04:16:34 +02:00
|
|
|
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2013.
|
2013-04-13 21:50:47 +02:00
|
|
|
* @brief Scheduler to run callback functions from a shared context with given priorities.
|
|
|
|
*
|
|
|
|
* @see The GNU Public License (GPL) Version 3
|
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
/*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
|
|
* for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "openpilot.h"
|
|
|
|
|
|
|
|
// Private constants
|
|
|
|
#define STACK_SIZE 128
|
2013-04-18 14:17:29 +02:00
|
|
|
#define MAX_SLEEP 1000
|
2013-04-13 21:50:47 +02:00
|
|
|
|
|
|
|
// Private types
|
2013-04-14 04:16:34 +02:00
|
|
|
/**
|
|
|
|
* task information
|
|
|
|
*/
|
|
|
|
struct DelayedCallbackTaskStruct {
|
2013-04-19 09:07:35 +02:00
|
|
|
DelayedCallbackInfo *callbackQueue[CALLBACK_PRIORITY_LOW + 1];
|
|
|
|
DelayedCallbackInfo *queueCursor[CALLBACK_PRIORITY_LOW + 1];
|
2013-04-14 04:16:34 +02:00
|
|
|
xTaskHandle callbackSchedulerTaskHandle;
|
|
|
|
signed char name[3];
|
|
|
|
uint32_t stackSize;
|
|
|
|
long taskPriority;
|
|
|
|
xSemaphoreHandle signal;
|
|
|
|
struct DelayedCallbackTaskStruct *next;
|
|
|
|
};
|
|
|
|
|
2013-04-13 21:50:47 +02:00
|
|
|
/**
|
|
|
|
* callback information
|
|
|
|
*/
|
|
|
|
struct DelayedCallbackInfoStruct {
|
|
|
|
DelayedCallback cb;
|
|
|
|
bool volatile waiting;
|
2013-04-18 14:17:29 +02:00
|
|
|
uint32_t volatile scheduletime;
|
2013-04-14 04:16:34 +02:00
|
|
|
struct DelayedCallbackTaskStruct *task;
|
2013-04-13 21:50:47 +02:00
|
|
|
struct DelayedCallbackInfoStruct *next;
|
|
|
|
};
|
|
|
|
|
2013-04-14 04:16:34 +02:00
|
|
|
|
|
|
|
|
2013-04-13 21:50:47 +02:00
|
|
|
// Private variables
|
2013-04-14 04:16:34 +02:00
|
|
|
static struct DelayedCallbackTaskStruct *schedulerTasks;
|
2013-04-13 21:50:47 +02:00
|
|
|
static xSemaphoreHandle mutex;
|
2013-04-14 04:16:34 +02:00
|
|
|
static bool schedulerStarted;
|
2013-04-13 21:50:47 +02:00
|
|
|
|
|
|
|
// Private functions
|
2013-04-14 04:16:34 +02:00
|
|
|
static void CallbackSchedulerTask(void *task);
|
2013-04-18 14:17:29 +02:00
|
|
|
static int32_t runNextCallback(struct DelayedCallbackTaskStruct *task, DelayedCallbackPriority priority);
|
2013-04-13 21:50:47 +02:00
|
|
|
|
|
|
|
/**
|
2013-04-14 04:16:34 +02:00
|
|
|
* Initialize the scheduler
|
2013-04-19 09:07:35 +02:00
|
|
|
* must be called before any other functions are called
|
2013-04-13 21:50:47 +02:00
|
|
|
* \return Success (0), failure (-1)
|
|
|
|
*/
|
|
|
|
int32_t CallbackSchedulerInitialize()
|
|
|
|
{
|
|
|
|
// Initialize variables
|
2013-04-14 04:16:34 +02:00
|
|
|
schedulerTasks = NULL;
|
|
|
|
schedulerStarted = false;
|
2013-04-13 21:50:47 +02:00
|
|
|
|
|
|
|
// Create mutex
|
|
|
|
mutex = xSemaphoreCreateRecursiveMutex();
|
2013-04-14 04:16:34 +02:00
|
|
|
if (mutex == NULL) {
|
2013-04-13 21:50:47 +02:00
|
|
|
return -1;
|
2013-04-14 04:16:34 +02:00
|
|
|
}
|
2013-04-13 21:50:47 +02:00
|
|
|
|
|
|
|
// Done
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-04-14 04:16:34 +02:00
|
|
|
/**
|
2013-04-19 09:07:35 +02:00
|
|
|
* Start all scheduler tasks
|
|
|
|
* Will instantiate all scheduler tasks registered so far. Although new
|
|
|
|
* callbacks CAN be registered beyond that point, any further scheduling tasks
|
|
|
|
* will be started the moment of instantiation. It is not possible to increase
|
|
|
|
* the STACK requirements of a scheduler task after this function has been
|
|
|
|
* run. No callbacks will be run before this function is called, although
|
|
|
|
* they can be marked for later execution by executing the dispatch function.
|
2013-04-14 04:16:34 +02:00
|
|
|
* \return Success (0), failure (-1)
|
|
|
|
*/
|
2013-04-13 21:50:47 +02:00
|
|
|
int32_t CallbackSchedulerStart()
|
|
|
|
{
|
2013-04-14 04:16:34 +02:00
|
|
|
xSemaphoreTakeRecursive(mutex, portMAX_DELAY);
|
|
|
|
|
|
|
|
// only call once
|
2013-04-19 09:07:35 +02:00
|
|
|
PIOS_Assert(schedulerStarted == false);
|
2013-04-14 04:16:34 +02:00
|
|
|
|
|
|
|
// start tasks
|
2013-04-19 09:07:35 +02:00
|
|
|
struct DelayedCallbackTaskStruct *cursor = NULL;
|
|
|
|
int t = 0;
|
|
|
|
LL_FOREACH(schedulerTasks, cursor) {
|
|
|
|
xTaskCreate(
|
|
|
|
CallbackSchedulerTask,
|
|
|
|
cursor->name,
|
|
|
|
cursor->stackSize/4,
|
|
|
|
cursor,
|
|
|
|
cursor->taskPriority,
|
|
|
|
&cursor->callbackSchedulerTaskHandle
|
|
|
|
);
|
2013-04-14 04:16:34 +02:00
|
|
|
if (TASKINFO_RUNNING_CALLBACKSCHEDULER0+t <= TASKINFO_RUNNING_CALLBACKSCHEDULER3) {
|
|
|
|
TaskMonitorAdd(TASKINFO_RUNNING_CALLBACKSCHEDULER0 + t, cursor->callbackSchedulerTaskHandle);
|
|
|
|
}
|
|
|
|
t++;
|
|
|
|
}
|
2013-04-18 14:17:29 +02:00
|
|
|
|
2013-04-14 04:16:34 +02:00
|
|
|
schedulerStarted = true;
|
|
|
|
|
|
|
|
xSemaphoreGiveRecursive(mutex);
|
2013-04-18 14:17:29 +02:00
|
|
|
|
2013-04-13 21:50:47 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-04-18 14:17:29 +02:00
|
|
|
/**
|
|
|
|
* Schedule dispatching a callback at some point in the future. The function returns immediately.
|
2013-04-19 09:07:35 +02:00
|
|
|
* \param[in] *cbinfo the callback handle
|
2013-04-18 14:17:29 +02:00
|
|
|
* \param[in] milliseconds How far in the future to dispatch the callback
|
|
|
|
* \param[in] updatemode What to do if the callback is already scheduled but not dispatched yet.
|
|
|
|
* The options are:
|
|
|
|
* UPDATEMODE_NONE: An existing schedule will not be touched, the call will have no effect at all if there's an existing schedule.
|
|
|
|
* UPDATEMODE_SOONER: The callback will be rescheduled only if the new schedule triggers before the original one would have triggered.
|
|
|
|
* UPDATEMODE_LATER: The callback will be rescheduled only if the new schedule triggers after the original one would have triggered.
|
|
|
|
* UPDATEMODE_OVERRIDE: The callback will be rescheduled in any case, effectively overriding any previous schedule. (sooner+later=override)
|
|
|
|
* \return 0: not scheduled, previous schedule takes precedence, 1: new schedule, 2: previous schedule overridden
|
|
|
|
*/
|
2013-04-19 09:07:35 +02:00
|
|
|
int32_t DelayedCallbackSchedule(
|
|
|
|
DelayedCallbackInfo *cbinfo,
|
|
|
|
int32_t milliseconds,
|
|
|
|
DelayedCallbackUpdateMode updatemode
|
|
|
|
)
|
2013-04-18 14:17:29 +02:00
|
|
|
{
|
2013-04-19 09:07:35 +02:00
|
|
|
int32_t result = 0;
|
2013-04-18 14:17:29 +02:00
|
|
|
|
|
|
|
PIOS_Assert(cbinfo);
|
|
|
|
|
2013-04-19 09:07:35 +02:00
|
|
|
if (milliseconds <= 0) {
|
|
|
|
milliseconds = 0; // we can and will not schedule in the past since that ruins the wraparound of uint32_t
|
2013-04-18 14:17:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
xSemaphoreTakeRecursive(mutex, portMAX_DELAY);
|
|
|
|
|
|
|
|
uint32_t new = xTaskGetTickCount() + (milliseconds/portTICK_RATE_MS);
|
|
|
|
if (!new) {
|
|
|
|
new = 1; // zero has a special meaning, schedule at time 1 instead
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t diff = new - cbinfo->scheduletime;
|
|
|
|
if ( (!cbinfo->scheduletime)
|
2013-04-19 09:07:35 +02:00
|
|
|
|| ((updatemode & CALLBACK_UPDATEMODE_SOONER) && diff < 0)
|
|
|
|
|| ((updatemode & CALLBACK_UPDATEMODE_LATER ) && diff > 0)
|
2013-04-18 14:17:29 +02:00
|
|
|
) {
|
|
|
|
|
|
|
|
// the scheduletime may be updated
|
|
|
|
if (!cbinfo->scheduletime) {
|
2013-04-19 09:07:35 +02:00
|
|
|
result = 1;
|
2013-04-18 14:17:29 +02:00
|
|
|
} else {
|
2013-04-19 09:07:35 +02:00
|
|
|
result = 2;
|
2013-04-18 14:17:29 +02:00
|
|
|
}
|
|
|
|
cbinfo->scheduletime = new;
|
|
|
|
|
|
|
|
// scheduler needs to be notified to adapt sleep times
|
|
|
|
xSemaphoreGive(cbinfo->task->signal);
|
|
|
|
}
|
|
|
|
|
|
|
|
xSemaphoreGiveRecursive(mutex);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2013-04-13 21:50:47 +02:00
|
|
|
/**
|
|
|
|
* Dispatch an event by invoking the supplied callback. The function
|
2013-04-18 14:17:29 +02:00
|
|
|
* returns immediately, the callback is invoked from the event task.
|
2013-04-13 21:50:47 +02:00
|
|
|
* \param[in] cbinfo the callback handle
|
2013-04-14 04:16:34 +02:00
|
|
|
* \return Success (-1), failure (0)
|
2013-04-13 21:50:47 +02:00
|
|
|
*/
|
|
|
|
int32_t DelayedCallbackDispatch(DelayedCallbackInfo *cbinfo)
|
|
|
|
{
|
2013-04-14 04:16:34 +02:00
|
|
|
PIOS_Assert(cbinfo);
|
|
|
|
|
|
|
|
// no semaphore needed for the callback
|
2013-04-19 09:07:35 +02:00
|
|
|
cbinfo->waiting = true;
|
2013-04-14 04:16:34 +02:00
|
|
|
// but the scheduler as a whole needs to be notified
|
|
|
|
return xSemaphoreGive(cbinfo->task->signal);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Dispatch an event by invoking the supplied callback. The function
|
2013-04-18 14:17:29 +02:00
|
|
|
* returns immediately, the callback is invoked from the event task.
|
2013-04-14 04:16:34 +02:00
|
|
|
* \param[in] cbinfo the callback handle
|
|
|
|
* \param[in] pxHigherPriorityTaskWoken
|
|
|
|
* xSemaphoreGiveFromISR() will set *pxHigherPriorityTaskWoken to pdTRUE if
|
|
|
|
* giving the semaphore caused a task to unblock, and the unblocked task has a
|
|
|
|
* priority higher than the currently running task. If xSemaphoreGiveFromISR()
|
|
|
|
* sets this value to pdTRUE then a context switch should be requested before
|
|
|
|
* the interrupt is exited.
|
|
|
|
* From FreeRTOS Docu: Context switching from an ISR uses port specific syntax.
|
|
|
|
* Check the demo task for your port to find the syntax required.
|
|
|
|
* \return Success (-1), failure (0)
|
|
|
|
*/
|
|
|
|
int32_t DelayedCallbackDispatchFromISR(DelayedCallbackInfo *cbinfo, long *pxHigherPriorityTaskWoken)
|
|
|
|
{
|
|
|
|
PIOS_Assert(cbinfo);
|
|
|
|
|
|
|
|
// no semaphore needed for the callback
|
2013-04-19 09:07:35 +02:00
|
|
|
cbinfo->waiting = true;
|
2013-04-14 04:16:34 +02:00
|
|
|
// but the scheduler as a whole needs to be notified
|
|
|
|
return xSemaphoreGiveFromISR(cbinfo->task->signal, pxHigherPriorityTaskWoken);
|
2013-04-13 21:50:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-04-14 04:16:34 +02:00
|
|
|
* Register a new callback to be called by a delayed callback scheduler task
|
2013-04-13 21:50:47 +02:00
|
|
|
* \param[in] cb The callback to be invoked
|
2013-04-14 04:16:34 +02:00
|
|
|
* \param[in] priority Priority of the callback compared to other callbacks called by the same delayed callback scheduler task.
|
2013-04-19 09:07:35 +02:00
|
|
|
* \param[in] taskPriority Priority of the entire scheduler task. One scheduler task will be spawned for each distinct task priority in use, further callbacks with the same task priority will be handled by the same delayed callback scheduler task, according to their callback priority.
|
2013-04-14 04:16:34 +02:00
|
|
|
* \param[in] stacksize The stack requirements of the callback when called by the scheduler.
|
2013-04-19 09:07:35 +02:00
|
|
|
* \return CallbackInfo Pointer on success, NULL if failed.
|
2013-04-13 21:50:47 +02:00
|
|
|
*/
|
2013-04-19 09:07:35 +02:00
|
|
|
DelayedCallbackInfo *DelayedCallbackCreate(
|
|
|
|
DelayedCallback cb,
|
|
|
|
DelayedCallbackPriority priority,
|
|
|
|
long taskPriority,
|
|
|
|
uint32_t stacksize
|
|
|
|
)
|
2013-04-13 21:50:47 +02:00
|
|
|
{
|
2013-04-18 14:17:29 +02:00
|
|
|
|
2013-04-13 21:50:47 +02:00
|
|
|
xSemaphoreTakeRecursive(mutex, portMAX_DELAY);
|
2013-04-18 14:17:29 +02:00
|
|
|
|
2013-04-14 04:16:34 +02:00
|
|
|
// find appropriate scheduler task matching taskPriority
|
2013-04-19 09:07:35 +02:00
|
|
|
struct DelayedCallbackTaskStruct *task = NULL;
|
|
|
|
int t = 0;
|
2013-04-14 04:16:34 +02:00
|
|
|
LL_FOREACH(schedulerTasks, task) {
|
|
|
|
if (task->taskPriority == taskPriority) {
|
|
|
|
break; // found
|
|
|
|
}
|
|
|
|
t++;
|
|
|
|
}
|
|
|
|
// if scheduler task for given taskPriority does not exist, create it
|
|
|
|
if (!task) {
|
|
|
|
// allocate memory if possible
|
|
|
|
task = (struct DelayedCallbackTaskStruct*)pvPortMalloc(sizeof(struct DelayedCallbackTaskStruct));
|
|
|
|
if (!task) {
|
|
|
|
xSemaphoreGiveRecursive(mutex);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// initialize structure
|
2013-04-19 09:07:35 +02:00
|
|
|
for (DelayedCallbackPriority p = 0; p <= CALLBACK_PRIORITY_LOW; p++) {
|
2013-04-14 04:16:34 +02:00
|
|
|
task->callbackQueue[p] = NULL;
|
2013-04-19 09:07:35 +02:00
|
|
|
task->queueCursor[p] = NULL;
|
2013-04-14 04:16:34 +02:00
|
|
|
}
|
|
|
|
task->name[0] = 'C';
|
|
|
|
task->name[1] = 'a'+t;
|
|
|
|
task->name[2] = 0;
|
2013-04-19 09:07:35 +02:00
|
|
|
task->stackSize = ((STACK_SIZE>stacksize)?STACK_SIZE:stacksize);
|
2013-04-14 04:16:34 +02:00
|
|
|
task->taskPriority = taskPriority;
|
|
|
|
task->next = NULL;
|
|
|
|
|
|
|
|
// create the signaling semaphore
|
|
|
|
vSemaphoreCreateBinary( task->signal );
|
|
|
|
if (!task->signal) {
|
|
|
|
xSemaphoreGiveRecursive(mutex);
|
|
|
|
return NULL;
|
|
|
|
}
|
2013-04-13 21:50:47 +02:00
|
|
|
|
2013-04-14 04:16:34 +02:00
|
|
|
// add to list of scheduler tasks
|
|
|
|
LL_APPEND(schedulerTasks, task);
|
2013-04-13 21:50:47 +02:00
|
|
|
|
2013-04-14 04:16:34 +02:00
|
|
|
// Previously registered tasks are spawned when CallbackSchedulerStart() is called.
|
|
|
|
// Tasks registered afterwards need to spawn upon creation.
|
|
|
|
if (schedulerStarted) {
|
2013-04-19 09:07:35 +02:00
|
|
|
xTaskCreate(
|
|
|
|
CallbackSchedulerTask,
|
|
|
|
task->name,
|
|
|
|
task->stackSize/4,
|
|
|
|
task,
|
|
|
|
task->taskPriority,
|
|
|
|
&task->callbackSchedulerTaskHandle
|
|
|
|
);
|
2013-04-14 04:16:34 +02:00
|
|
|
if (TASKINFO_RUNNING_CALLBACKSCHEDULER0 + t <= TASKINFO_RUNNING_CALLBACKSCHEDULER3) {
|
|
|
|
TaskMonitorAdd(TASKINFO_RUNNING_CALLBACKSCHEDULER0 + t, task->callbackSchedulerTaskHandle);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!schedulerStarted && stacksize > task->stackSize) {
|
|
|
|
task->stackSize = stacksize; // previous to task initialisation we can still adapt to the maximum needed stack
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (stacksize > task->stackSize) {
|
|
|
|
xSemaphoreGiveRecursive(mutex);
|
|
|
|
return NULL; // error - not enough memory
|
|
|
|
}
|
|
|
|
|
|
|
|
// initialize callback scheduling info
|
2013-04-13 21:50:47 +02:00
|
|
|
DelayedCallbackInfo *info = (DelayedCallbackInfo*)pvPortMalloc(sizeof(DelayedCallbackInfo));
|
2013-04-14 04:16:34 +02:00
|
|
|
if (!info) {
|
|
|
|
xSemaphoreGiveRecursive(mutex);
|
|
|
|
return NULL; // error - not enough memory
|
|
|
|
}
|
2013-04-18 14:17:29 +02:00
|
|
|
info->next = NULL;
|
|
|
|
info->waiting = false;
|
|
|
|
info->scheduletime = 0;
|
|
|
|
info->task = task;
|
|
|
|
info->cb = cb;
|
2013-04-13 21:50:47 +02:00
|
|
|
|
|
|
|
// add to scheduling queue
|
2013-04-19 09:07:35 +02:00
|
|
|
LL_APPEND(task->callbackQueue[priority], info);
|
2013-04-18 14:17:29 +02:00
|
|
|
|
2013-04-14 04:16:34 +02:00
|
|
|
xSemaphoreGiveRecursive(mutex);
|
2013-04-13 21:50:47 +02:00
|
|
|
|
|
|
|
return info;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Scheduler subtask
|
2013-04-18 14:17:29 +02:00
|
|
|
* \param[in] task The scheduler task in question
|
2013-04-13 21:50:47 +02:00
|
|
|
* \param[in] priority The scheduling priority of the callback to search for
|
2013-04-18 14:17:29 +02:00
|
|
|
* \return wait time until next scheduled callback is due - 0 if a callback has just been executed
|
2013-04-13 21:50:47 +02:00
|
|
|
*/
|
2013-04-19 09:07:35 +02:00
|
|
|
static int32_t runNextCallback(struct DelayedCallbackTaskStruct *task, DelayedCallbackPriority priority)
|
|
|
|
{
|
2013-04-18 14:17:29 +02:00
|
|
|
|
|
|
|
int32_t result = MAX_SLEEP;
|
2013-04-19 09:07:35 +02:00
|
|
|
int32_t diff = 0;
|
2013-04-18 14:17:29 +02:00
|
|
|
|
2013-04-13 21:50:47 +02:00
|
|
|
// no such queue
|
2013-04-14 04:16:34 +02:00
|
|
|
if (priority > CALLBACK_PRIORITY_LOW) {
|
2013-04-18 14:17:29 +02:00
|
|
|
return result;
|
2013-04-14 04:16:34 +02:00
|
|
|
}
|
2013-04-13 21:50:47 +02:00
|
|
|
|
|
|
|
// queue is empty, search a lower priority queue
|
2013-04-14 04:16:34 +02:00
|
|
|
if (task->callbackQueue[priority] == NULL) {
|
|
|
|
return runNextCallback(task, priority + 1);
|
|
|
|
}
|
2013-04-13 21:50:47 +02:00
|
|
|
|
2013-04-14 04:16:34 +02:00
|
|
|
DelayedCallbackInfo *current = task->queueCursor[priority];
|
2013-04-13 21:50:47 +02:00
|
|
|
DelayedCallbackInfo *next;
|
|
|
|
do {
|
2013-04-19 09:07:35 +02:00
|
|
|
if (current == NULL) {
|
|
|
|
next = task->callbackQueue[priority]; // loop around the end of the list
|
2013-04-13 21:50:47 +02:00
|
|
|
// also attempt to run a callback that has lower priority
|
|
|
|
// every time the queue is completely traversed
|
2013-04-18 14:17:29 +02:00
|
|
|
diff = runNextCallback(task, priority + 1);
|
|
|
|
if (!diff) {
|
|
|
|
task->queueCursor[priority] = next; // the recursive call has executed a callback
|
|
|
|
return 0;
|
|
|
|
}
|
2013-04-19 09:07:35 +02:00
|
|
|
if (diff < result) {
|
2013-04-18 14:17:29 +02:00
|
|
|
result = diff; // adjust sleep time
|
2013-04-13 21:50:47 +02:00
|
|
|
}
|
|
|
|
} else {
|
2013-04-14 04:16:34 +02:00
|
|
|
next = current->next;
|
2013-04-18 14:17:29 +02:00
|
|
|
xSemaphoreTakeRecursive(mutex, portMAX_DELAY); // access to scheduletime should be mutex protected
|
|
|
|
if (current->scheduletime) {
|
2013-04-18 18:35:57 +02:00
|
|
|
diff = current->scheduletime - xTaskGetTickCount();
|
2013-04-19 09:07:35 +02:00
|
|
|
if (diff <= 0) {
|
2013-04-18 14:17:29 +02:00
|
|
|
current->waiting = true;
|
2013-04-19 09:07:35 +02:00
|
|
|
} else if (diff < result) {
|
2013-04-18 14:17:29 +02:00
|
|
|
result = diff; // adjust sleep time
|
|
|
|
}
|
|
|
|
}
|
2013-04-13 21:50:47 +02:00
|
|
|
if (current->waiting) {
|
2013-04-14 04:16:34 +02:00
|
|
|
task->queueCursor[priority] = next;
|
2013-04-18 14:17:29 +02:00
|
|
|
current->scheduletime = 0; // any schedules are reset
|
|
|
|
current->waiting = false; // the flag is reset just before execution.
|
|
|
|
xSemaphoreGiveRecursive(mutex);
|
2013-04-13 21:50:47 +02:00
|
|
|
current->cb(); // call the callback
|
2013-04-18 14:17:29 +02:00
|
|
|
return 0;
|
2013-04-13 21:50:47 +02:00
|
|
|
}
|
2013-04-18 14:17:29 +02:00
|
|
|
xSemaphoreGiveRecursive(mutex);
|
2013-04-13 21:50:47 +02:00
|
|
|
}
|
2013-04-14 04:16:34 +02:00
|
|
|
current = next;
|
|
|
|
} while (current != task->queueCursor[priority]);
|
2013-04-18 14:17:29 +02:00
|
|
|
// once the list has been traversed entirely without finding any to be executed task, abort (nothing to do)
|
|
|
|
return result;
|
2013-04-13 21:50:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Scheduler task, responsible of invoking callbacks.
|
2013-04-14 04:16:34 +02:00
|
|
|
* \param[in] task The scheduling task being run
|
2013-04-13 21:50:47 +02:00
|
|
|
*/
|
2013-04-14 04:16:34 +02:00
|
|
|
static void CallbackSchedulerTask(void *task)
|
2013-04-13 21:50:47 +02:00
|
|
|
{
|
2013-04-19 09:07:35 +02:00
|
|
|
uint32_t delay = 0;
|
|
|
|
|
2013-04-13 21:50:47 +02:00
|
|
|
while (1) {
|
2013-04-18 14:17:29 +02:00
|
|
|
|
2013-04-19 09:07:35 +02:00
|
|
|
delay = runNextCallback((struct DelayedCallbackTaskStruct*)task, CALLBACK_PRIORITY_CRITICAL);
|
2013-04-18 14:17:29 +02:00
|
|
|
if (delay) {
|
|
|
|
// nothing to do but sleep
|
2013-04-19 09:07:35 +02:00
|
|
|
xSemaphoreTake(((struct DelayedCallbackTaskStruct*)task)->signal, delay);
|
2013-04-13 21:50:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|