WIP: somethings wrong.. #19

Closed
muellerr wants to merge 808 commits from source/master into master
2 changed files with 269 additions and 271 deletions
Showing only changes of commit fd42d8cd46 - Show all commits

View File

@ -1,143 +1,143 @@
#include "PeriodicTask.h" #include "PeriodicTask.h"
#include "../../serviceinterface/ServiceInterfaceStream.h" #include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../tasks/ExecutableObjectIF.h" #include "../../tasks/ExecutableObjectIF.h"
PeriodicTask::PeriodicTask(const char *name, TaskPriority setPriority, PeriodicTask::PeriodicTask(const char *name, TaskPriority setPriority,
TaskStackSize setStack, TaskPeriod setPeriod, TaskStackSize setStack, TaskPeriod setPeriod,
TaskDeadlineMissedFunction deadlineMissedFunc) : TaskDeadlineMissedFunction deadlineMissedFunc) :
started(false), handle(NULL), period(setPeriod), deadlineMissedFunc( started(false), handle(NULL), period(setPeriod), deadlineMissedFunc(
deadlineMissedFunc) deadlineMissedFunc)
{ {
configSTACK_DEPTH_TYPE stackSize = setStack / sizeof(configSTACK_DEPTH_TYPE); configSTACK_DEPTH_TYPE stackSize = setStack / sizeof(configSTACK_DEPTH_TYPE);
BaseType_t status = xTaskCreate(taskEntryPoint, name, BaseType_t status = xTaskCreate(taskEntryPoint, name,
stackSize, this, setPriority, &handle); stackSize, this, setPriority, &handle);
if(status != pdPASS){ if(status != pdPASS){
sif::debug << "PeriodicTask Insufficient heap memory remaining. " sif::debug << "PeriodicTask Insufficient heap memory remaining. "
"Status: " << status << std::endl; "Status: " << status << std::endl;
} }
} }
PeriodicTask::~PeriodicTask(void) { PeriodicTask::~PeriodicTask(void) {
//Do not delete objects, we were responsible for ptrs only. //Do not delete objects, we were responsible for ptrs only.
} }
void PeriodicTask::taskEntryPoint(void* argument) { void PeriodicTask::taskEntryPoint(void* argument) {
// The argument is re-interpreted as PeriodicTask. The Task object is // The argument is re-interpreted as PeriodicTask. The Task object is
// global, so it is found from any place. // global, so it is found from any place.
PeriodicTask *originalTask(reinterpret_cast<PeriodicTask*>(argument)); PeriodicTask *originalTask(reinterpret_cast<PeriodicTask*>(argument));
/* Task should not start until explicitly requested, /* Task should not start until explicitly requested,
* but in FreeRTOS, tasks start as soon as they are created if the scheduler * but in FreeRTOS, tasks start as soon as they are created if the scheduler
* is running but not if the scheduler is not running. * is running but not if the scheduler is not running.
* To be able to accommodate both cases we check a member which is set in * To be able to accommodate both cases we check a member which is set in
* #startTask(). If it is not set and we get here, the scheduler was started * #startTask(). If it is not set and we get here, the scheduler was started
* before #startTask() was called and we need to suspend if it is set, * before #startTask() was called and we need to suspend if it is set,
* the scheduler was not running before #startTask() was called and we * the scheduler was not running before #startTask() was called and we
* can continue */ * can continue */
if (not originalTask->started) { if (not originalTask->started) {
vTaskSuspend(NULL); vTaskSuspend(NULL);
} }
originalTask->taskFunctionality(); originalTask->taskFunctionality();
sif::debug << "Polling task " << originalTask->handle sif::debug << "Polling task " << originalTask->handle
<< " returned from taskFunctionality." << std::endl; << " returned from taskFunctionality." << std::endl;
} }
ReturnValue_t PeriodicTask::startTask() { ReturnValue_t PeriodicTask::startTask() {
started = true; started = true;
// We must not call resume if scheduler is not started yet // We must not call resume if scheduler is not started yet
if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) { if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) {
vTaskResume(handle); vTaskResume(handle);
} }
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t PeriodicTask::sleepFor(uint32_t ms) { ReturnValue_t PeriodicTask::sleepFor(uint32_t ms) {
vTaskDelay(pdMS_TO_TICKS(ms)); vTaskDelay(pdMS_TO_TICKS(ms));
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
void PeriodicTask::taskFunctionality() { void PeriodicTask::taskFunctionality() {
TickType_t xLastWakeTime; TickType_t xLastWakeTime;
const TickType_t xPeriod = pdMS_TO_TICKS(this->period * 1000.); const TickType_t xPeriod = pdMS_TO_TICKS(this->period * 1000.);
for (auto const& object: objectList) { for (auto const &object: objectList) {
object->initializeAfterTaskCreation(); object->initializeAfterTaskCreation();
} }
/* The xLastWakeTime variable needs to be initialized with the current tick /* The xLastWakeTime variable needs to be initialized with the current tick
count. Note that this is the only time the variable is written to count. Note that this is the only time the variable is written to
explicitly. After this assignment, xLastWakeTime is updated automatically explicitly. After this assignment, xLastWakeTime is updated automatically
internally within vTaskDelayUntil(). */ internally within vTaskDelayUntil(). */
xLastWakeTime = xTaskGetTickCount(); xLastWakeTime = xTaskGetTickCount();
/* Enter the loop that defines the task behavior. */ /* Enter the loop that defines the task behavior. */
for (;;) { for (;;) {
for (auto const& object: objectList) { for (auto const& object: objectList) {
object->performOperation(); object->performOperation();
} }
checkMissedDeadline(xLastWakeTime, xPeriod); checkMissedDeadline(xLastWakeTime, xPeriod);
vTaskDelayUntil(&xLastWakeTime, xPeriod); vTaskDelayUntil(&xLastWakeTime, xPeriod);
} }
} }
ReturnValue_t PeriodicTask::addComponent(object_id_t object) { ReturnValue_t PeriodicTask::addComponent(object_id_t object) {
ExecutableObjectIF* newObject = objectManager->get<ExecutableObjectIF>( ExecutableObjectIF* newObject = objectManager->get<ExecutableObjectIF>(
object); object);
if (newObject == nullptr) { if (newObject == nullptr) {
sif::error << "PeriodicTask::addComponent: Invalid object. Make sure" sif::error << "PeriodicTask::addComponent: Invalid object. Make sure"
"it implement ExecutableObjectIF" << std::endl; "it implement ExecutableObjectIF" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
objectList.push_back(newObject); objectList.push_back(newObject);
newObject->setTaskIF(this); newObject->setTaskIF(this);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
uint32_t PeriodicTask::getPeriodMs() const { uint32_t PeriodicTask::getPeriodMs() const {
return period * 1000; return period * 1000;
} }
void PeriodicTask::checkMissedDeadline(const TickType_t xLastWakeTime, void PeriodicTask::checkMissedDeadline(const TickType_t xLastWakeTime,
const TickType_t interval) { const TickType_t interval) {
/* Check whether deadline was missed while also taking overflows /* Check whether deadline was missed while also taking overflows
* into account. Drawing this on paper with a timeline helps to understand * into account. Drawing this on paper with a timeline helps to understand
* it. */ * it. */
TickType_t currentTickCount = xTaskGetTickCount(); TickType_t currentTickCount = xTaskGetTickCount();
TickType_t timeToWake = xLastWakeTime + interval; TickType_t timeToWake = xLastWakeTime + interval;
// Time to wake has not overflown. // Time to wake has not overflown.
if(timeToWake > xLastWakeTime) { if(timeToWake > xLastWakeTime) {
/* If the current time has overflown exclusively or the current /* If the current time has overflown exclusively or the current
* tick count is simply larger than the time to wake, a deadline was * tick count is simply larger than the time to wake, a deadline was
* missed */ * missed */
if((currentTickCount < xLastWakeTime) or (currentTickCount > timeToWake)) { if((currentTickCount < xLastWakeTime) or (currentTickCount > timeToWake)) {
handleMissedDeadline(); handleMissedDeadline();
} }
} }
/* Time to wake has overflown. A deadline was missed if the current time /* Time to wake has overflown. A deadline was missed if the current time
* is larger than the time to wake */ * is larger than the time to wake */
else if((timeToWake < xLastWakeTime) and (currentTickCount > timeToWake)) { else if((timeToWake < xLastWakeTime) and (currentTickCount > timeToWake)) {
handleMissedDeadline(); handleMissedDeadline();
} }
} }
TaskHandle_t PeriodicTask::getTaskHandle() { TaskHandle_t PeriodicTask::getTaskHandle() {
return handle; return handle;
} }
void PeriodicTask::handleMissedDeadline() { void PeriodicTask::handleMissedDeadline() {
#ifdef DEBUG #ifdef DEBUG
sif::warning << "PeriodicTask: " << pcTaskGetName(NULL) << sif::warning << "PeriodicTask: " << pcTaskGetName(NULL) <<
" missed deadline!\n" << std::flush; " missed deadline!\n" << std::flush;
#endif #endif
if(deadlineMissedFunc != nullptr) { if(deadlineMissedFunc != nullptr) {
this->deadlineMissedFunc(); this->deadlineMissedFunc();
} }
} }

View File

@ -1,128 +1,126 @@
#ifndef FRAMEWORK_OSAL_FREERTOS_PERIODICTASK_H_ #ifndef FSFW_OSAL_FREERTOS_PERIODICTASK_H_
#define FRAMEWORK_OSAL_FREERTOS_PERIODICTASK_H_ #define FSFW_OSAL_FREERTOS_PERIODICTASK_H_
#include "../../osal/FreeRTOS/FreeRTOSTaskIF.h" #include "FreeRTOSTaskIF.h"
#include "../../objectmanager/ObjectManagerIF.h" #include "../../objectmanager/ObjectManagerIF.h"
#include "../../tasks/PeriodicTaskIF.h" #include "../../tasks/PeriodicTaskIF.h"
#include "../../tasks/Typedef.h" #include "../../tasks/Typedef.h"
#include <freertos/FreeRTOS.h>
#include <freertos/FreeRTOS.h> #include <freertos/task.h>
#include <freertos/task.h>
#include <vector>
#include <vector>
class ExecutableObjectIF;
class ExecutableObjectIF;
/**
/** * @brief This class represents a specialized task for
* @brief This class represents a specialized task for * periodic activities of multiple objects.
* periodic activities of multiple objects. * @ingroup task_handling
* @ingroup task_handling */
*/ class PeriodicTask: public PeriodicTaskIF, public FreeRTOSTaskIF {
class PeriodicTask: public PeriodicTaskIF, public FreeRTOSTaskIF { public:
public: /**
/** * Keep in Mind that you need to call before this vTaskStartScheduler()!
* Keep in Mind that you need to call before this vTaskStartScheduler()! * A lot of task parameters are set in "FreeRTOSConfig.h".
* A lot of task parameters are set in "FreeRTOSConfig.h". * @details
* TODO: why does this need to be called before vTaskStartScheduler? * The class is initialized without allocated objects.
* @details * These need to be added with #addComponent.
* The class is initialized without allocated objects. * @param priority
* These need to be added with #addComponent. * Sets the priority of a task. Values depend on freeRTOS configuration,
* @param priority * high number means high priority.
* Sets the priority of a task. Values depend on freeRTOS configuration, * @param stack_size
* high number means high priority. * The stack size reserved by the operating system for the task.
* @param stack_size * @param setPeriod
* The stack size reserved by the operating system for the task. * The length of the period with which the task's
* @param setPeriod * functionality will be executed. It is expressed in clock ticks.
* The length of the period with which the task's * @param setDeadlineMissedFunc
* functionality will be executed. It is expressed in clock ticks. * The function pointer to the deadline missed function that shall
* @param setDeadlineMissedFunc * be assigned.
* The function pointer to the deadline missed function that shall */
* be assigned. PeriodicTask(TaskName name, TaskPriority setPriority,
*/ TaskStackSize setStack, TaskPeriod setPeriod,
PeriodicTask(TaskName name, TaskPriority setPriority, TaskDeadlineMissedFunction deadlineMissedFunc);
TaskStackSize setStack, TaskPeriod setPeriod, /**
TaskDeadlineMissedFunction deadlineMissedFunc); * @brief Currently, the executed object's lifetime is not coupled with
/** * the task object's lifetime, so the destructor is empty.
* @brief Currently, the executed object's lifetime is not coupled with */
* the task object's lifetime, so the destructor is empty. virtual ~PeriodicTask(void);
*/
virtual ~PeriodicTask(void); /**
* @brief The method to start the task.
/** * @details The method starts the task with the respective system call.
* @brief The method to start the task. * Entry point is the taskEntryPoint method described below.
* @details The method starts the task with the respective system call. * The address of the task object is passed as an argument
* Entry point is the taskEntryPoint method described below. * to the system call.
* The address of the task object is passed as an argument */
* to the system call. ReturnValue_t startTask() override;
*/ /**
ReturnValue_t startTask() override; * Adds an object to the list of objects to be executed.
/** * The objects are executed in the order added.
* Adds an object to the list of objects to be executed. * @param object Id of the object to add.
* The objects are executed in the order added. * @return
* @param object Id of the object to add. * -@c RETURN_OK on success
* @return * -@c RETURN_FAILED if the object could not be added.
* -@c RETURN_OK on success */
* -@c RETURN_FAILED if the object could not be added. ReturnValue_t addComponent(object_id_t object) override;
*/
ReturnValue_t addComponent(object_id_t object) override; uint32_t getPeriodMs() const override;
uint32_t getPeriodMs() const override; ReturnValue_t sleepFor(uint32_t ms) override;
ReturnValue_t sleepFor(uint32_t ms) override; TaskHandle_t getTaskHandle() override;
protected:
TaskHandle_t getTaskHandle() override; bool started;
protected: TaskHandle_t handle;
bool started;
TaskHandle_t handle; //! Typedef for the List of objects.
typedef std::vector<ExecutableObjectIF*> ObjectList;
//! Typedef for the List of objects. /**
typedef std::vector<ExecutableObjectIF*> ObjectList; * @brief This attribute holds a list of objects to be executed.
/** */
* @brief This attribute holds a list of objects to be executed. ObjectList objectList;
*/ /**
ObjectList objectList; * @brief The period of the task.
/** * @details
* @brief The period of the task. * The period determines the frequency of the task's execution.
* @details * It is expressed in clock ticks.
* The period determines the frequency of the task's execution. */
* It is expressed in clock ticks. TaskPeriod period;
*/ /**
TaskPeriod period; * @brief The pointer to the deadline-missed function.
/** * @details
* @brief The pointer to the deadline-missed function. * This pointer stores the function that is executed if the task's deadline
* @details * is missed so each may react individually on a timing failure.
* This pointer stores the function that is executed if the task's deadline * The pointer may be NULL, then nothing happens on missing the deadline.
* is missed so each may react individually on a timing failure. * The deadline is equal to the next execution of the periodic task.
* The pointer may be NULL, then nothing happens on missing the deadline. */
* The deadline is equal to the next execution of the periodic task. void (*deadlineMissedFunc)(void);
*/ /**
void (*deadlineMissedFunc)(void); * @brief This is the function executed in the new task's context.
/** * @details
* @brief This is the function executed in the new task's context. * It converts the argument back to the thread object type and copies the
* @details * class instance to the task context. The taskFunctionality method is
* It converts the argument back to the thread object type and copies the * called afterwards.
* class instance to the task context. The taskFunctionality method is * @param A pointer to the task object itself is passed as argument.
* called afterwards. */
* @param A pointer to the task object itself is passed as argument.
*/ static void taskEntryPoint(void* argument);
/**
static void taskEntryPoint(void* argument); * @brief The function containing the actual functionality of the task.
/** * @details
* @brief The function containing the actual functionality of the task. * The method sets and starts the task's period, then enters a loop that is
* @details * repeated as long as the isRunning attribute is true. Within the loop,
* The method sets and starts the task's period, then enters a loop that is * all performOperation methods of the added objects are called.
* repeated as long as the isRunning attribute is true. Within the loop, * Afterwards the checkAndRestartPeriod system call blocks the task until
* all performOperation methods of the added objects are called. * the next period.
* Afterwards the checkAndRestartPeriod system call blocks the task until * On missing the deadline, the deadlineMissedFunction is executed.
* the next period. */
* On missing the deadline, the deadlineMissedFunction is executed. void taskFunctionality(void);
*/
void taskFunctionality(void); void checkMissedDeadline(const TickType_t xLastWakeTime,
const TickType_t interval);
void checkMissedDeadline(const TickType_t xLastWakeTime, void handleMissedDeadline();
const TickType_t interval); };
void handleMissedDeadline();
}; #endif /* FSFW_OSAL_FREERTOS_PERIODICTASK_H_ */
#endif /* PERIODICTASK_H_ */