init after task creation moved to task functionality

This commit is contained in:
Robin Müller 2020-08-27 15:57:47 +02:00
parent 9465c8f2b2
commit 02be87aa03
2 changed files with 271 additions and 266 deletions

View File

@ -1,138 +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.);
/* The xLastWakeTime variable needs to be initialized with the current tick
count. Note that this is the only time the variable is written to for (auto const& object: objectList) {
explicitly. After this assignment, xLastWakeTime is updated automatically object->initializeAfterTaskCreation();
internally within vTaskDelayUntil(). */ }
xLastWakeTime = xTaskGetTickCount();
/* Enter the loop that defines the task behavior. */ /* The xLastWakeTime variable needs to be initialized with the current tick
for (;;) { count. Note that this is the only time the variable is written to
for (auto const& object: objectList) { explicitly. After this assignment, xLastWakeTime is updated automatically
object->performOperation(); internally within vTaskDelayUntil(). */
} xLastWakeTime = xTaskGetTickCount();
/* Enter the loop that defines the task behavior. */
checkMissedDeadline(xLastWakeTime, xPeriod); for (;;) {
for (auto const& object: objectList) {
vTaskDelayUntil(&xLastWakeTime, xPeriod); object->performOperation();
}
}
} checkMissedDeadline(xLastWakeTime, xPeriod);
ReturnValue_t PeriodicTask::addComponent(object_id_t object) { vTaskDelayUntil(&xLastWakeTime, xPeriod);
ExecutableObjectIF* newObject = objectManager->get<ExecutableObjectIF>(
object); }
if (newObject == nullptr) { }
sif::error << "PeriodicTask::addComponent: Invalid object. Make sure"
"it implement ExecutableObjectIF" << std::endl; ReturnValue_t PeriodicTask::addComponent(object_id_t object) {
return HasReturnvaluesIF::RETURN_FAILED; ExecutableObjectIF* newObject = objectManager->get<ExecutableObjectIF>(
} object);
objectList.push_back(newObject); if (newObject == nullptr) {
newObject->setTaskIF(this); sif::error << "PeriodicTask::addComponent: Invalid object. Make sure"
"it implement ExecutableObjectIF" << std::endl;
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_FAILED;
} }
objectList.push_back(newObject);
uint32_t PeriodicTask::getPeriodMs() const { newObject->setTaskIF(this);
return period * 1000;
} return HasReturnvaluesIF::RETURN_OK;
}
void PeriodicTask::checkMissedDeadline(const TickType_t xLastWakeTime,
const TickType_t interval) { uint32_t PeriodicTask::getPeriodMs() const {
/* Check whether deadline was missed while also taking overflows return period * 1000;
* into account. Drawing this on paper with a timeline helps to understand }
* it. */
TickType_t currentTickCount = xTaskGetTickCount(); void PeriodicTask::checkMissedDeadline(const TickType_t xLastWakeTime,
TickType_t timeToWake = xLastWakeTime + interval; const TickType_t interval) {
// Time to wake has not overflown. /* Check whether deadline was missed while also taking overflows
if(timeToWake > xLastWakeTime) { * into account. Drawing this on paper with a timeline helps to understand
/* If the current time has overflown exclusively or the current * it. */
* tick count is simply larger than the time to wake, a deadline was TickType_t currentTickCount = xTaskGetTickCount();
* missed */ TickType_t timeToWake = xLastWakeTime + interval;
if((currentTickCount < xLastWakeTime) or (currentTickCount > timeToWake)) { // Time to wake has not overflown.
handleMissedDeadline(); if(timeToWake > xLastWakeTime) {
} /* If the current time has overflown exclusively or the current
} * tick count is simply larger than the time to wake, a deadline was
/* Time to wake has overflown. A deadline was missed if the current time * missed */
* is larger than the time to wake */ if((currentTickCount < xLastWakeTime) or (currentTickCount > timeToWake)) {
else if((timeToWake < xLastWakeTime) and (currentTickCount > timeToWake)) { handleMissedDeadline();
handleMissedDeadline(); }
} }
} /* Time to wake has overflown. A deadline was missed if the current time
* is larger than the time to wake */
TaskHandle_t PeriodicTask::getTaskHandle() { else if((timeToWake < xLastWakeTime) and (currentTickCount > timeToWake)) {
return handle; handleMissedDeadline();
} }
}
void PeriodicTask::handleMissedDeadline() {
#ifdef DEBUG TaskHandle_t PeriodicTask::getTaskHandle() {
sif::warning << "PeriodicTask: " << pcTaskGetName(NULL) << return handle;
" missed deadline!\n" << std::flush; }
#endif
if(deadlineMissedFunc != nullptr) { void PeriodicTask::handleMissedDeadline() {
this->deadlineMissedFunc(); #ifdef DEBUG
} sif::warning << "PeriodicTask: " << pcTaskGetName(NULL) <<
} " missed deadline!\n" << std::flush;
#endif
if(deadlineMissedFunc != nullptr) {
this->deadlineMissedFunc();
}
}

View File

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