1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2024-12-01 09:24:10 +01:00

updated in code documentation, use of some enums in callbackscheduler.h

This commit is contained in:
Corvus Corax 2013-04-19 17:25:42 +02:00
parent 28ac515064
commit 6cb2d2b39d
4 changed files with 218 additions and 16 deletions

View File

@ -37,7 +37,7 @@
// Private constants
#define STACK_SIZE configMINIMAL_STACK_SIZE
#define CALLBACK_PRIORITY CALLBACK_PRIORITY_LOW
#define TASK_PRIORITY (tskIDLE_PRIORITY+1)
#define TASK_PRIORITY CALLBACK_TASKPRIORITY_AUXILIARY
// Private types
//#define DEBUGPRINT(...) fprintf (stderr, __VA_ARGS__)

View File

@ -0,0 +1,140 @@
/**
******************************************************************************
*
* @file examplemodcallback.c
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @brief Example module to be used as a template for actual modules.
* Event callback version.
*
* @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
*/
/**
* Input objects: ExampleObject1, ExampleSettings
* Output object: ExampleObject2
*
* This module executes in response to ExampleObject1 updates. When the
* module is triggered it will update the data of ExampleObject2.
*
* No threads are used in this example.
*
* UAVObjects are automatically generated by the UAVObjectGenerator from
* the object definition XML file.
*
* Modules have no API, all communication to other modules is done through UAVObjects.
* However modules may use the API exposed by shared libraries.
* See the OpenPilot wiki for more details.
* http://www.openpilot.org/OpenPilot_Application_Architecture
*
*/
#include "openpilot.h"
#include "exampleobject1.h" // object the module will listen for updates (input)
#include "exampleobject2.h" // object the module will update (output)
#include "examplesettings.h" // object holding module settings (input)
// Private constants
#define STACK_SIZE configMINIMAL_STACK_SIZE
#define CALLBACK_PRIORITY CALLBACK_PRIORITY_LOW
#define CBTASK_PRIORITY CALLBACK_TASKPRIORITY_AUXILIARY
// Private types
// Private variables
static DelayedCallbackInfo *cbinfo;
// Private functions
static void ObjectUpdatedCb(UAVObjEvent *ev);
static void DelayedCb();
/**
* Initialise the module, called on startup.
* \returns 0 on success or -1 if initialisation failed
*/
int32_t ExampleModCallbackInitialize()
{
// Listen for ExampleObject1 updates, connect a callback function
ExampleObject1ConnectCallback(&ObjectUpdatedCb);
cbinfo = DelayedCallbackCreate(&DelayedCb, CALLBACK_PRIORITY, CBTASK_PRIORITY, STACK_SIZE);
return 0;
}
/**
* This function is called each time ExampleObject1 is updated, this could be
* a local update or a remote update from the GCS. In this example the module
* does not have its own thread, the callbacks are executed from within the
* event thread. Because of that the callback execution time must be kept to
* a minimum.
*/
static void ObjectUpdatedCb(UAVObjEvent * ev)
{
DelayedCallbackDispatch(cbinfo);
}
/**
* This function is called by the DelayedCallbackScheduler when its execution
* has been requested. Callbacks scheduled for execution are executed in the
* same thread in a round robin fashion. The Dispatch function to reschedule
* execution can be called from within the Callback itself, in which case the
* re-run will be scheduled after all other callback with equal or higher
* priority have been executed. Like event callbacks, delayed callbacks are
* executed in the same thread context one at a time, therefore blocking IO
* functions or very long lasting calculations are prohibited. Unlike Event
* callbacks these callbacks run with a standard (IDLE+1) thread priority and
* do not block regular threads. They are therefore saver to use.
*/
static void DelayedCb();
ExampleSettingsData settings;
ExampleObject1Data data1;
ExampleObject2Data data2;
int32_t step;
// Update settings with latest value
ExampleSettingsGet(&settings);
// Get the input object
ExampleObject1Get(&data1);
// Determine how to update the output object
if (settings.StepDirection == EXAMPLESETTINGS_STEPDIRECTION_UP) {
step = settings.StepSize;
} else {
step = -settings.StepSize;
}
// Update data
data2.Field1 = data1.Field1 + step;
data2.Field2 = data1.Field2 + step;
data2.Field3 = data1.Field3 + step;
data2.Field4[0] = data1.Field4[0] + step;
data2.Field4[1] = data1.Field4[1] + step;
// Update the ExampleObject2, after this function is called
// notifications to any other modules listening to that object
// will be sent and the GCS object will be updated through the
// telemetry link. All operations will take place asynchronously
// and the following call will return immediately.
ExampleObject2Set(&data2);
//call the module again 10 seconds later,
//even if the exampleobject has not been updated
DelayedCallbackSchedule(cbinfo, 10*1000, CALLBACK_UPDATEMODE_NONE);
}

View File

@ -40,7 +40,7 @@ struct DelayedCallbackTaskStruct {
xTaskHandle callbackSchedulerTaskHandle;
signed char name[3];
uint32_t stackSize;
long taskPriority;
DelayedCallbackPriorityTask priorityTask;
xSemaphoreHandle signal;
struct DelayedCallbackTaskStruct *next;
};
@ -114,7 +114,7 @@ int32_t CallbackSchedulerStart()
cursor->name,
cursor->stackSize/4,
cursor,
cursor->taskPriority,
cursor->priorityTask,
&cursor->callbackSchedulerTaskHandle
);
if (TASKINFO_RUNNING_CALLBACKSCHEDULER0+t <= TASKINFO_RUNNING_CALLBACKSCHEDULER3) {
@ -227,33 +227,35 @@ int32_t DelayedCallbackDispatchFromISR(DelayedCallbackInfo *cbinfo, long *pxHigh
}
/**
* Register a new callback to be called by a delayed callback scheduler task
* 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 called by the same delayed callback scheduler task.
* \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.
* \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.
* \return CallbackInfo Pointer on success, NULL if failed.
*/
DelayedCallbackInfo *DelayedCallbackCreate(
DelayedCallback cb,
DelayedCallbackPriority priority,
long taskPriority,
DelayedCallbackPriorityTask priorityTask,
uint32_t stacksize
)
{
xSemaphoreTakeRecursive(mutex, portMAX_DELAY);
// find appropriate scheduler task matching taskPriority
// find appropriate scheduler task matching priorityTask
struct DelayedCallbackTaskStruct *task = NULL;
int t = 0;
LL_FOREACH(schedulerTasks, task) {
if (task->taskPriority == taskPriority) {
if (task->priorityTask == priorityTask) {
break; // found
}
t++;
}
// if scheduler task for given taskPriority does not exist, create it
// if given priorityTask does not exist, create it
if (!task) {
// allocate memory if possible
task = (struct DelayedCallbackTaskStruct*)pvPortMalloc(sizeof(struct DelayedCallbackTaskStruct));
@ -271,7 +273,7 @@ DelayedCallbackInfo *DelayedCallbackCreate(
task->name[1] = 'a'+t;
task->name[2] = 0;
task->stackSize = ((STACK_SIZE>stacksize)?STACK_SIZE:stacksize);
task->taskPriority = taskPriority;
task->priorityTask = priorityTask;
task->next = NULL;
// create the signaling semaphore
@ -292,7 +294,7 @@ DelayedCallbackInfo *DelayedCallbackCreate(
task->name,
task->stackSize/4,
task,
task->taskPriority,
task->priorityTask,
&task->callbackSchedulerTaskHandle
);
if (TASKINFO_RUNNING_CALLBACKSCHEDULER0 + t <= TASKINFO_RUNNING_CALLBACKSCHEDULER3) {

View File

@ -32,6 +32,51 @@ typedef enum{
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 onlz 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,
@ -39,11 +84,26 @@ typedef enum{
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
//
@ -69,18 +129,18 @@ int32_t CallbackSchedulerStart();
/**
* Register a new callback to be called by a delayed callback scheduler task.
* If a scheduler task with the specified taskPriority does not exist yet, it
* 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 called by the same delayed callback scheduler task.
* \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.
* \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.
* \return CallbackInfo Pointer on success, NULL if failed.
*/
DelayedCallbackInfo *DelayedCallbackCreate(
DelayedCallback cb,
DelayedCallbackPriority priority,
long taskPriority,
DelayedCallbackPriorityTask priorityTask,
uint32_t stacksize
);