1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2024-12-05 13:24:11 +01:00
LibrePilot/flight/pios/inc/pios_callbackscheduler.h
Corvus Corax 7ec21a8f36 OP-942 duplicated exact API of task_monitor to also monitor callbacks
This allows cleaner and fine grained handling of STACKOVERFLOW alarms
2014-02-07 22:39:16 +01:00

220 lines
10 KiB
C

/**
******************************************************************************
*
* @file pios_callbackscheduler.h
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2014.
* @brief Include files of the PIOS_CALLBACKSCHEDULER
* @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
*/
#ifndef PIOS_CALLBACKSCHEDULER_H
#define PIOS_CALLBACKSCHEDULER_H
// Public types
typedef enum {
CALLBACK_PRIORITY_CRITICAL = 0,
CALLBACK_PRIORITY_REGULAR = 1,
CALLBACK_PRIORITY_LOW = 2
} DelayedCallbackPriority;
// Use the CallbackPriority to define how frequent a callback needs to be
// called in relation to others in the same callback scheduling task.
// The scheduler will call callbacks waiting for execution with the same
// priority in a round robin way. However one slot in this queue is reserved
// for a chosen member of the next lower priority. This member will also be
// chosen in a round robin way.
// Example:
// Assume you have 6 callbacks in the same PriorityTask, all constantly wanting
// to be executed.
// A and B are priority CRITICAL,
// c and d are priority REGULAR,
// x and y are priority LOW.
// Then the execution schedule will look as follows:
// ...ABcABdABxABcABdAByABcABdABxABcABdABy...
// However if only the 3 callbacks, A, c and x want to execute, you will get:
// ...AcAxAcAxAcAxAcAxAcAxAcAxAcAxAcAxAcAx...
// And if only A and y need execution it will be:
// ...AyAyAyAyAyAyAyAyAyAyAyAyAyAyAyAyAyAy...
// despite their different priority they would get treated equally in this case.
//
// WARNING: Callbacks ALWAYS should return as quickly as possible. Otherwise
// a low priority callback can block a critical one from being executed.
// Callbacks MUST NOT block execution!
typedef enum {
CALLBACK_TASK_AUXILIARY = (tskIDLE_PRIORITY + 1),
CALLBACK_TASK_NAVIGATION = (tskIDLE_PRIORITY + 2),
CALLBACK_TASK_FLIGHTCONTROL = (tskIDLE_PRIORITY + 3),
CALLBACK_TASK_DEVICEDRIVER = (tskIDLE_PRIORITY + 4),
} DelayedCallbackPriorityTask;
// Use the PriorityTask to define the global importance of callback execution
// compared to other processes in the system.
// Callbacks dispatched in a higher PriorityTasks will halt the execution of
// any lower priority processes, including callbacks and even callback
// scheduling tasks until they are done!
// Assume you have two callbacks:
// A in priorityTask DEVICEDRIVER,
// b and c in priorityTask AUXILIARY,
// Then the execution schedule can look as follows: (| marks a task switch)
// <b ... /b><c ... |<A ... /A>| ... /c><b ...
// be aware that if A gets constantly dispatched this would look like this:
// <b ... |<A><A><A><A><A><A><A><A><A><A><A><A><A><A><A><A><A><A><A>...
//
// WARNING: Any higher priority task can prevent lower priority code from being
// executed! (This does not only apply to callbacks but to all FreeRTOS tasks!)
typedef enum {
CALLBACK_UPDATEMODE_NONE = 0,
CALLBACK_UPDATEMODE_SOONER = 1,
CALLBACK_UPDATEMODE_LATER = 2,
CALLBACK_UPDATEMODE_OVERRIDE = 3
} DelayedCallbackUpdateMode;
// When scheduling a callback for execution at a time in the future, use the
// update mode to define what should happen if the callback is already
// scheduled.
// With NONE, the schedule will not be updated and the callback will be
// executed at the original time.
// With SOONER, the closer of the two schedules will take precedence
// With LATER, the schedule more distant in the future will be used.
// With OVERRIDE, the original schedule will be discarded.
typedef void (*DelayedCallback)(void);
// Use this type for the callback function.
struct DelayedCallbackInfoStruct;
typedef struct DelayedCallbackInfoStruct DelayedCallbackInfo;
// Use a pointer to DelayedCallbackInfo as a handle to identify registered callbacks.
// be aware that the same callback function can be registered as a callback
// several times, even with different callback priorities and even
// priorityTasks, using different handles and as such different dispatch calls.
// Be aware that using different priorityTasks for the same callback function
// might cause your callback to be executed recursively in different task contexts!
// Public functions
//
/**
* Initialize the scheduler
* must be called before any other functions are called
* \return Success (0), failure (-1)
*/
int32_t PIOS_CALLBACKSCHEDULER_Initialize();
/**
* 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.
* \return Success (0), failure (-1)
*/
int32_t PIOS_CALLBACKSCHEDULER_Start();
/**
* Register a new callback to be called by a delayed callback scheduler task.
* If a scheduler task with the specified task priority does not exist yet, it
* will be created.
* \param[in] cb The callback to be invoked
* \param[in] priority Priority of the callback compared to other callbacks scheduled by the same delayed callback scheduler task.
* \param[in] priorityTask Task priority of the scheduler task. One scheduler task will be spawned for each distinct value specified, further callbacks created with the same priorityTask will all be handled by the same delayed callback scheduler task and scheduled according to their individual callback priorities
* \param[in] stacksize The stack requirements of the callback when called by the scheduler.
* \param[in] callbackID - CallbackInfoRunningElem from CallbackInfo UAVObject, unique identified to collect stats for the callback, -1 to ignore!
* \return CallbackInfo Pointer on success, NULL if failed.
*/
DelayedCallbackInfo *PIOS_CALLBACKSCHEDULER_Create(
DelayedCallback cb,
DelayedCallbackPriority priority,
DelayedCallbackPriorityTask priorityTask,
int16_t callbackID,
uint32_t stacksize);
/**
* Schedule dispatching a callback at some point in the future. The function returns immediately.
* \param[in] *cbinfo the callback handle
* \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
*/
int32_t PIOS_CALLBACKSCHEDULER_Schedule(
DelayedCallbackInfo *cbinfo,
int32_t milliseconds,
DelayedCallbackUpdateMode updatemode);
/**
* Dispatch an event by invoking the supplied callback. The function
* returns immediately, the callback is invoked from the event task.
* \param[in] *cbinfo the callback handle
* \return Success (-1), failure (0)
*/
int32_t PIOS_CALLBACKSCHEDULER_Dispatch(DelayedCallbackInfo *cbinfo);
/**
* Dispatch an event by invoking the supplied callback. The function
* returns immediately, the callback is invoked from the event task.
* \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 PIOS_CALLBACKSCHEDULER_DispatchFromISR(DelayedCallbackInfo *cbinfo, long *pxHigherPriorityTaskWoken);
/**
* Information about a running callback that has been registered
* via a call to PIOS_CALLBACKSCHEDULER_Create().
*/
struct pios_callback_info {
/** Remaining task stack in bytes -1 for detected stack overflow. */
int32_t stack_remaining;
/** Flag indicating whether or not the task is running. */
bool is_running;
/** Count of executions of the callback since system start */
uint32_t running_time_count;
};
/**
* Iterator callback, called for each monitored callback by PIOS_CALLBACKSCHEDULER_ForEachCallback().
*
* @param task_id The id of the task the task_info refers to.
* @param task_info Information about the task identified by task_id.
* @param context Context information optionally provided by the caller to PIOS_TASK_MONITOR_TasksIterate()
*/
typedef void (*CallbackSchedulerCallbackInfoCallback)(int16_t task_id, const struct pios_callback_info *callback_info, void *context);
/**
* Iterator. Iterates over all callbacks and all scheduler tasks and retrieves information
*
* @param[in] callback Callback function to receive the data - will be called in same task context as the callerThe id of the task the task_info refers to.
* @param context Context information optionally provided to the callback.
*/
void PIOS_CALLBACKSCHEDULER_ForEachCallback(CallbackSchedulerCallbackInfoCallback callback, void *context);
#endif // PIOS_CALLBACKSCHEDULER_H