From 02be87aa03f0919d7f8ba629d6afc7fb9bd02076 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Thu, 27 Aug 2020 15:57:47 +0200 Subject: [PATCH 1/5] init after task creation moved to task functionality --- osal/FreeRTOS/PeriodicTask.cpp | 281 +++++++++++++++++---------------- osal/FreeRTOS/PeriodicTask.h | 256 +++++++++++++++--------------- 2 files changed, 271 insertions(+), 266 deletions(-) diff --git a/osal/FreeRTOS/PeriodicTask.cpp b/osal/FreeRTOS/PeriodicTask.cpp index ce981877f..f99e8a4ed 100644 --- a/osal/FreeRTOS/PeriodicTask.cpp +++ b/osal/FreeRTOS/PeriodicTask.cpp @@ -1,138 +1,143 @@ -#include "PeriodicTask.h" - -#include "../../serviceinterface/ServiceInterfaceStream.h" -#include "../../tasks/ExecutableObjectIF.h" - -PeriodicTask::PeriodicTask(const char *name, TaskPriority setPriority, - TaskStackSize setStack, TaskPeriod setPeriod, - TaskDeadlineMissedFunction deadlineMissedFunc) : - started(false), handle(NULL), period(setPeriod), deadlineMissedFunc( - deadlineMissedFunc) -{ - configSTACK_DEPTH_TYPE stackSize = setStack / sizeof(configSTACK_DEPTH_TYPE); - BaseType_t status = xTaskCreate(taskEntryPoint, name, - stackSize, this, setPriority, &handle); - if(status != pdPASS){ - sif::debug << "PeriodicTask Insufficient heap memory remaining. " - "Status: " << status << std::endl; - } - -} - -PeriodicTask::~PeriodicTask(void) { - //Do not delete objects, we were responsible for ptrs only. -} - -void PeriodicTask::taskEntryPoint(void* argument) { - // The argument is re-interpreted as PeriodicTask. The Task object is - // global, so it is found from any place. - PeriodicTask *originalTask(reinterpret_cast(argument)); - /* Task should not start until explicitly requested, - * but in FreeRTOS, tasks start as soon as they are created if the scheduler - * 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 - * #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, - * the scheduler was not running before #startTask() was called and we - * can continue */ - - if (not originalTask->started) { - vTaskSuspend(NULL); - } - - originalTask->taskFunctionality(); - sif::debug << "Polling task " << originalTask->handle - << " returned from taskFunctionality." << std::endl; -} - -ReturnValue_t PeriodicTask::startTask() { - started = true; - - // We must not call resume if scheduler is not started yet - if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) { - vTaskResume(handle); - } - - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t PeriodicTask::sleepFor(uint32_t ms) { - vTaskDelay(pdMS_TO_TICKS(ms)); - return HasReturnvaluesIF::RETURN_OK; -} - -void PeriodicTask::taskFunctionality() { - TickType_t xLastWakeTime; - 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 - explicitly. After this assignment, xLastWakeTime is updated automatically - internally within vTaskDelayUntil(). */ - xLastWakeTime = xTaskGetTickCount(); - /* Enter the loop that defines the task behavior. */ - for (;;) { - for (auto const& object: objectList) { - object->performOperation(); - } - - checkMissedDeadline(xLastWakeTime, xPeriod); - - vTaskDelayUntil(&xLastWakeTime, xPeriod); - - } -} - -ReturnValue_t PeriodicTask::addComponent(object_id_t object) { - ExecutableObjectIF* newObject = objectManager->get( - object); - if (newObject == nullptr) { - sif::error << "PeriodicTask::addComponent: Invalid object. Make sure" - "it implement ExecutableObjectIF" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - objectList.push_back(newObject); - newObject->setTaskIF(this); - - return HasReturnvaluesIF::RETURN_OK; -} - -uint32_t PeriodicTask::getPeriodMs() const { - return period * 1000; -} - -void PeriodicTask::checkMissedDeadline(const TickType_t xLastWakeTime, - const TickType_t interval) { - /* Check whether deadline was missed while also taking overflows - * into account. Drawing this on paper with a timeline helps to understand - * it. */ - TickType_t currentTickCount = xTaskGetTickCount(); - TickType_t timeToWake = xLastWakeTime + interval; - // Time to wake has not overflown. - 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 - * missed */ - if((currentTickCount < xLastWakeTime) or (currentTickCount > timeToWake)) { - handleMissedDeadline(); - } - } - /* Time to wake has overflown. A deadline was missed if the current time - * is larger than the time to wake */ - else if((timeToWake < xLastWakeTime) and (currentTickCount > timeToWake)) { - handleMissedDeadline(); - } -} - -TaskHandle_t PeriodicTask::getTaskHandle() { - return handle; -} - -void PeriodicTask::handleMissedDeadline() { -#ifdef DEBUG - sif::warning << "PeriodicTask: " << pcTaskGetName(NULL) << - " missed deadline!\n" << std::flush; -#endif - if(deadlineMissedFunc != nullptr) { - this->deadlineMissedFunc(); - } -} +#include "PeriodicTask.h" + +#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "../../tasks/ExecutableObjectIF.h" + +PeriodicTask::PeriodicTask(const char *name, TaskPriority setPriority, + TaskStackSize setStack, TaskPeriod setPeriod, + TaskDeadlineMissedFunction deadlineMissedFunc) : + started(false), handle(NULL), period(setPeriod), deadlineMissedFunc( + deadlineMissedFunc) +{ + configSTACK_DEPTH_TYPE stackSize = setStack / sizeof(configSTACK_DEPTH_TYPE); + BaseType_t status = xTaskCreate(taskEntryPoint, name, + stackSize, this, setPriority, &handle); + if(status != pdPASS){ + sif::debug << "PeriodicTask Insufficient heap memory remaining. " + "Status: " << status << std::endl; + } + +} + +PeriodicTask::~PeriodicTask(void) { + //Do not delete objects, we were responsible for ptrs only. +} + +void PeriodicTask::taskEntryPoint(void* argument) { + // The argument is re-interpreted as PeriodicTask. The Task object is + // global, so it is found from any place. + PeriodicTask *originalTask(reinterpret_cast(argument)); + /* Task should not start until explicitly requested, + * but in FreeRTOS, tasks start as soon as they are created if the scheduler + * 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 + * #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, + * the scheduler was not running before #startTask() was called and we + * can continue */ + + if (not originalTask->started) { + vTaskSuspend(NULL); + } + + originalTask->taskFunctionality(); + sif::debug << "Polling task " << originalTask->handle + << " returned from taskFunctionality." << std::endl; +} + +ReturnValue_t PeriodicTask::startTask() { + started = true; + + // We must not call resume if scheduler is not started yet + if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) { + vTaskResume(handle); + } + + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t PeriodicTask::sleepFor(uint32_t ms) { + vTaskDelay(pdMS_TO_TICKS(ms)); + return HasReturnvaluesIF::RETURN_OK; +} + +void PeriodicTask::taskFunctionality() { + TickType_t xLastWakeTime; + const TickType_t xPeriod = pdMS_TO_TICKS(this->period * 1000.); + + for (auto const& object: objectList) { + object->initializeAfterTaskCreation(); + } + + /* The xLastWakeTime variable needs to be initialized with the current tick + count. Note that this is the only time the variable is written to + explicitly. After this assignment, xLastWakeTime is updated automatically + internally within vTaskDelayUntil(). */ + xLastWakeTime = xTaskGetTickCount(); + /* Enter the loop that defines the task behavior. */ + for (;;) { + for (auto const& object: objectList) { + object->performOperation(); + } + + checkMissedDeadline(xLastWakeTime, xPeriod); + + vTaskDelayUntil(&xLastWakeTime, xPeriod); + + } +} + +ReturnValue_t PeriodicTask::addComponent(object_id_t object) { + ExecutableObjectIF* newObject = objectManager->get( + object); + if (newObject == nullptr) { + sif::error << "PeriodicTask::addComponent: Invalid object. Make sure" + "it implement ExecutableObjectIF" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + objectList.push_back(newObject); + newObject->setTaskIF(this); + + return HasReturnvaluesIF::RETURN_OK; +} + +uint32_t PeriodicTask::getPeriodMs() const { + return period * 1000; +} + +void PeriodicTask::checkMissedDeadline(const TickType_t xLastWakeTime, + const TickType_t interval) { + /* Check whether deadline was missed while also taking overflows + * into account. Drawing this on paper with a timeline helps to understand + * it. */ + TickType_t currentTickCount = xTaskGetTickCount(); + TickType_t timeToWake = xLastWakeTime + interval; + // Time to wake has not overflown. + 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 + * missed */ + if((currentTickCount < xLastWakeTime) or (currentTickCount > timeToWake)) { + handleMissedDeadline(); + } + } + /* Time to wake has overflown. A deadline was missed if the current time + * is larger than the time to wake */ + else if((timeToWake < xLastWakeTime) and (currentTickCount > timeToWake)) { + handleMissedDeadline(); + } +} + +TaskHandle_t PeriodicTask::getTaskHandle() { + return handle; +} + +void PeriodicTask::handleMissedDeadline() { +#ifdef DEBUG + sif::warning << "PeriodicTask: " << pcTaskGetName(NULL) << + " missed deadline!\n" << std::flush; +#endif + if(deadlineMissedFunc != nullptr) { + this->deadlineMissedFunc(); + } +} diff --git a/osal/FreeRTOS/PeriodicTask.h b/osal/FreeRTOS/PeriodicTask.h index ea170aba8..1cdc3df70 100644 --- a/osal/FreeRTOS/PeriodicTask.h +++ b/osal/FreeRTOS/PeriodicTask.h @@ -1,128 +1,128 @@ -#ifndef FRAMEWORK_OSAL_FREERTOS_PERIODICTASK_H_ -#define FRAMEWORK_OSAL_FREERTOS_PERIODICTASK_H_ - -#include "../../objectmanager/ObjectManagerIF.h" -#include "../../tasks/PeriodicTaskIF.h" -#include "../../tasks/Typedef.h" -#include "FreeRTOSTaskIF.h" - - -#include -#include - -#include - -class ExecutableObjectIF; - -/** - * @brief This class represents a specialized task for - * periodic activities of multiple objects. - * @ingroup task_handling - */ -class PeriodicTask: public PeriodicTaskIF, public FreeRTOSTaskIF { -public: - /** - * Keep in Mind that you need to call before this vTaskStartScheduler()! - * A lot of task parameters are set in "FreeRTOSConfig.h". - * TODO: why does this need to be called before vTaskStartScheduler? - * @details - * The class is initialized without allocated objects. - * These need to be added with #addComponent. - * @param priority - * Sets the priority of a task. Values depend on freeRTOS configuration, - * high number means high priority. - * @param stack_size - * The stack size reserved by the operating system for the task. - * @param setPeriod - * The length of the period with which the task's - * functionality will be executed. It is expressed in clock ticks. - * @param setDeadlineMissedFunc - * The function pointer to the deadline missed function that shall - * be assigned. - */ - PeriodicTask(TaskName name, TaskPriority setPriority, - 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. - */ - virtual ~PeriodicTask(void); - - /** - * @brief The method to start the task. - * @details The method starts the task with the respective system call. - * Entry point is the taskEntryPoint method described below. - * The address of the task object is passed as an argument - * to the system call. - */ - ReturnValue_t startTask() override; - /** - * Adds an object to the list of objects to be executed. - * The objects are executed in the order added. - * @param object Id of the object to add. - * @return - * -@c RETURN_OK on success - * -@c RETURN_FAILED if the object could not be added. - */ - ReturnValue_t addComponent(object_id_t object) override; - - uint32_t getPeriodMs() const override; - - ReturnValue_t sleepFor(uint32_t ms) override; - - TaskHandle_t getTaskHandle() override; -protected: - bool started; - TaskHandle_t handle; - - //! Typedef for the List of objects. - typedef std::vector ObjectList; - /** - * @brief This attribute holds a list of objects to be executed. - */ - ObjectList objectList; - /** - * @brief The period of the task. - * @details - * The period determines the frequency of the task's execution. - * It is expressed in clock ticks. - */ - TaskPeriod period; - /** - * @brief The pointer to the deadline-missed function. - * @details - * This pointer stores the function that is executed if the task's deadline - * is missed so each may react individually on a timing failure. - * 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); - /** - * @brief This is the function executed in the new task's context. - * @details - * It converts the argument back to the thread object type and copies the - * class instance to the task context. The taskFunctionality method is - * called afterwards. - * @param A pointer to the task object itself is passed as argument. - */ - - static void taskEntryPoint(void* argument); - /** - * @brief The function containing the actual functionality of the task. - * @details - * 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, - * all performOperation methods of the added objects are called. - * Afterwards the checkAndRestartPeriod system call blocks the task until - * the next period. - * On missing the deadline, the deadlineMissedFunction is executed. - */ - void taskFunctionality(void); - - void checkMissedDeadline(const TickType_t xLastWakeTime, - const TickType_t interval); - void handleMissedDeadline(); -}; - -#endif /* PERIODICTASK_H_ */ +#ifndef FRAMEWORK_OSAL_FREERTOS_PERIODICTASK_H_ +#define FRAMEWORK_OSAL_FREERTOS_PERIODICTASK_H_ + +#include "../../osal/FreeRTOS/FreeRTOSTaskIF.h" +#include "../../objectmanager/ObjectManagerIF.h" +#include "../../tasks/PeriodicTaskIF.h" +#include "../../tasks/Typedef.h" + + +#include +#include + +#include + +class ExecutableObjectIF; + +/** + * @brief This class represents a specialized task for + * periodic activities of multiple objects. + * @ingroup task_handling + */ +class PeriodicTask: public PeriodicTaskIF, public FreeRTOSTaskIF { +public: + /** + * Keep in Mind that you need to call before this vTaskStartScheduler()! + * A lot of task parameters are set in "FreeRTOSConfig.h". + * TODO: why does this need to be called before vTaskStartScheduler? + * @details + * The class is initialized without allocated objects. + * These need to be added with #addComponent. + * @param priority + * Sets the priority of a task. Values depend on freeRTOS configuration, + * high number means high priority. + * @param stack_size + * The stack size reserved by the operating system for the task. + * @param setPeriod + * The length of the period with which the task's + * functionality will be executed. It is expressed in clock ticks. + * @param setDeadlineMissedFunc + * The function pointer to the deadline missed function that shall + * be assigned. + */ + PeriodicTask(TaskName name, TaskPriority setPriority, + 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. + */ + virtual ~PeriodicTask(void); + + /** + * @brief The method to start the task. + * @details The method starts the task with the respective system call. + * Entry point is the taskEntryPoint method described below. + * The address of the task object is passed as an argument + * to the system call. + */ + ReturnValue_t startTask() override; + /** + * Adds an object to the list of objects to be executed. + * The objects are executed in the order added. + * @param object Id of the object to add. + * @return + * -@c RETURN_OK on success + * -@c RETURN_FAILED if the object could not be added. + */ + ReturnValue_t addComponent(object_id_t object) override; + + uint32_t getPeriodMs() const override; + + ReturnValue_t sleepFor(uint32_t ms) override; + + TaskHandle_t getTaskHandle() override; +protected: + bool started; + TaskHandle_t handle; + + //! Typedef for the List of objects. + typedef std::vector ObjectList; + /** + * @brief This attribute holds a list of objects to be executed. + */ + ObjectList objectList; + /** + * @brief The period of the task. + * @details + * The period determines the frequency of the task's execution. + * It is expressed in clock ticks. + */ + TaskPeriod period; + /** + * @brief The pointer to the deadline-missed function. + * @details + * This pointer stores the function that is executed if the task's deadline + * is missed so each may react individually on a timing failure. + * 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); + /** + * @brief This is the function executed in the new task's context. + * @details + * It converts the argument back to the thread object type and copies the + * class instance to the task context. The taskFunctionality method is + * called afterwards. + * @param A pointer to the task object itself is passed as argument. + */ + + static void taskEntryPoint(void* argument); + /** + * @brief The function containing the actual functionality of the task. + * @details + * 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, + * all performOperation methods of the added objects are called. + * Afterwards the checkAndRestartPeriod system call blocks the task until + * the next period. + * On missing the deadline, the deadlineMissedFunction is executed. + */ + void taskFunctionality(void); + + void checkMissedDeadline(const TickType_t xLastWakeTime, + const TickType_t interval); + void handleMissedDeadline(); +}; + +#endif /* PERIODICTASK_H_ */ From 89d3fe509504382980aff1bbeaf9be1ffd508136 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Thu, 27 Aug 2020 16:11:40 +0200 Subject: [PATCH 2/5] integrated change manually --- osal/FreeRTOS/PeriodicTask.cpp | 286 ++++++++++++++++----------------- 1 file changed, 143 insertions(+), 143 deletions(-) diff --git a/osal/FreeRTOS/PeriodicTask.cpp b/osal/FreeRTOS/PeriodicTask.cpp index f99e8a4ed..990d38d67 100644 --- a/osal/FreeRTOS/PeriodicTask.cpp +++ b/osal/FreeRTOS/PeriodicTask.cpp @@ -1,143 +1,143 @@ -#include "PeriodicTask.h" - -#include "../../serviceinterface/ServiceInterfaceStream.h" -#include "../../tasks/ExecutableObjectIF.h" - -PeriodicTask::PeriodicTask(const char *name, TaskPriority setPriority, - TaskStackSize setStack, TaskPeriod setPeriod, - TaskDeadlineMissedFunction deadlineMissedFunc) : - started(false), handle(NULL), period(setPeriod), deadlineMissedFunc( - deadlineMissedFunc) -{ - configSTACK_DEPTH_TYPE stackSize = setStack / sizeof(configSTACK_DEPTH_TYPE); - BaseType_t status = xTaskCreate(taskEntryPoint, name, - stackSize, this, setPriority, &handle); - if(status != pdPASS){ - sif::debug << "PeriodicTask Insufficient heap memory remaining. " - "Status: " << status << std::endl; - } - -} - -PeriodicTask::~PeriodicTask(void) { - //Do not delete objects, we were responsible for ptrs only. -} - -void PeriodicTask::taskEntryPoint(void* argument) { - // The argument is re-interpreted as PeriodicTask. The Task object is - // global, so it is found from any place. - PeriodicTask *originalTask(reinterpret_cast(argument)); - /* Task should not start until explicitly requested, - * but in FreeRTOS, tasks start as soon as they are created if the scheduler - * 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 - * #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, - * the scheduler was not running before #startTask() was called and we - * can continue */ - - if (not originalTask->started) { - vTaskSuspend(NULL); - } - - originalTask->taskFunctionality(); - sif::debug << "Polling task " << originalTask->handle - << " returned from taskFunctionality." << std::endl; -} - -ReturnValue_t PeriodicTask::startTask() { - started = true; - - // We must not call resume if scheduler is not started yet - if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) { - vTaskResume(handle); - } - - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t PeriodicTask::sleepFor(uint32_t ms) { - vTaskDelay(pdMS_TO_TICKS(ms)); - return HasReturnvaluesIF::RETURN_OK; -} - -void PeriodicTask::taskFunctionality() { - TickType_t xLastWakeTime; - const TickType_t xPeriod = pdMS_TO_TICKS(this->period * 1000.); - - for (auto const& object: objectList) { - object->initializeAfterTaskCreation(); - } - - /* The xLastWakeTime variable needs to be initialized with the current tick - count. Note that this is the only time the variable is written to - explicitly. After this assignment, xLastWakeTime is updated automatically - internally within vTaskDelayUntil(). */ - xLastWakeTime = xTaskGetTickCount(); - /* Enter the loop that defines the task behavior. */ - for (;;) { - for (auto const& object: objectList) { - object->performOperation(); - } - - checkMissedDeadline(xLastWakeTime, xPeriod); - - vTaskDelayUntil(&xLastWakeTime, xPeriod); - - } -} - -ReturnValue_t PeriodicTask::addComponent(object_id_t object) { - ExecutableObjectIF* newObject = objectManager->get( - object); - if (newObject == nullptr) { - sif::error << "PeriodicTask::addComponent: Invalid object. Make sure" - "it implement ExecutableObjectIF" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - objectList.push_back(newObject); - newObject->setTaskIF(this); - - return HasReturnvaluesIF::RETURN_OK; -} - -uint32_t PeriodicTask::getPeriodMs() const { - return period * 1000; -} - -void PeriodicTask::checkMissedDeadline(const TickType_t xLastWakeTime, - const TickType_t interval) { - /* Check whether deadline was missed while also taking overflows - * into account. Drawing this on paper with a timeline helps to understand - * it. */ - TickType_t currentTickCount = xTaskGetTickCount(); - TickType_t timeToWake = xLastWakeTime + interval; - // Time to wake has not overflown. - 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 - * missed */ - if((currentTickCount < xLastWakeTime) or (currentTickCount > timeToWake)) { - handleMissedDeadline(); - } - } - /* Time to wake has overflown. A deadline was missed if the current time - * is larger than the time to wake */ - else if((timeToWake < xLastWakeTime) and (currentTickCount > timeToWake)) { - handleMissedDeadline(); - } -} - -TaskHandle_t PeriodicTask::getTaskHandle() { - return handle; -} - -void PeriodicTask::handleMissedDeadline() { -#ifdef DEBUG - sif::warning << "PeriodicTask: " << pcTaskGetName(NULL) << - " missed deadline!\n" << std::flush; -#endif - if(deadlineMissedFunc != nullptr) { - this->deadlineMissedFunc(); - } -} +#include "PeriodicTask.h" + +#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "../../tasks/ExecutableObjectIF.h" + +PeriodicTask::PeriodicTask(const char *name, TaskPriority setPriority, + TaskStackSize setStack, TaskPeriod setPeriod, + TaskDeadlineMissedFunction deadlineMissedFunc) : + started(false), handle(NULL), period(setPeriod), deadlineMissedFunc( + deadlineMissedFunc) +{ + configSTACK_DEPTH_TYPE stackSize = setStack / sizeof(configSTACK_DEPTH_TYPE); + BaseType_t status = xTaskCreate(taskEntryPoint, name, + stackSize, this, setPriority, &handle); + if(status != pdPASS){ + sif::debug << "PeriodicTask Insufficient heap memory remaining. " + "Status: " << status << std::endl; + } + +} + +PeriodicTask::~PeriodicTask(void) { + //Do not delete objects, we were responsible for ptrs only. +} + +void PeriodicTask::taskEntryPoint(void* argument) { + // The argument is re-interpreted as PeriodicTask. The Task object is + // global, so it is found from any place. + PeriodicTask *originalTask(reinterpret_cast(argument)); + /* Task should not start until explicitly requested, + * but in FreeRTOS, tasks start as soon as they are created if the scheduler + * 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 + * #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, + * the scheduler was not running before #startTask() was called and we + * can continue */ + + if (not originalTask->started) { + vTaskSuspend(NULL); + } + + originalTask->taskFunctionality(); + sif::debug << "Polling task " << originalTask->handle + << " returned from taskFunctionality." << std::endl; +} + +ReturnValue_t PeriodicTask::startTask() { + started = true; + + // We must not call resume if scheduler is not started yet + if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) { + vTaskResume(handle); + } + + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t PeriodicTask::sleepFor(uint32_t ms) { + vTaskDelay(pdMS_TO_TICKS(ms)); + return HasReturnvaluesIF::RETURN_OK; +} + +void PeriodicTask::taskFunctionality() { + TickType_t xLastWakeTime; + const TickType_t xPeriod = pdMS_TO_TICKS(this->period * 1000.); + + for (auto const &object: objectList) { + object->initializeAfterTaskCreation(); + } + + /* The xLastWakeTime variable needs to be initialized with the current tick + count. Note that this is the only time the variable is written to + explicitly. After this assignment, xLastWakeTime is updated automatically + internally within vTaskDelayUntil(). */ + xLastWakeTime = xTaskGetTickCount(); + /* Enter the loop that defines the task behavior. */ + for (;;) { + for (auto const& object: objectList) { + object->performOperation(); + } + + checkMissedDeadline(xLastWakeTime, xPeriod); + + vTaskDelayUntil(&xLastWakeTime, xPeriod); + + } +} + +ReturnValue_t PeriodicTask::addComponent(object_id_t object) { + ExecutableObjectIF* newObject = objectManager->get( + object); + if (newObject == nullptr) { + sif::error << "PeriodicTask::addComponent: Invalid object. Make sure" + "it implement ExecutableObjectIF" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + objectList.push_back(newObject); + newObject->setTaskIF(this); + + return HasReturnvaluesIF::RETURN_OK; +} + +uint32_t PeriodicTask::getPeriodMs() const { + return period * 1000; +} + +void PeriodicTask::checkMissedDeadline(const TickType_t xLastWakeTime, + const TickType_t interval) { + /* Check whether deadline was missed while also taking overflows + * into account. Drawing this on paper with a timeline helps to understand + * it. */ + TickType_t currentTickCount = xTaskGetTickCount(); + TickType_t timeToWake = xLastWakeTime + interval; + // Time to wake has not overflown. + 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 + * missed */ + if((currentTickCount < xLastWakeTime) or (currentTickCount > timeToWake)) { + handleMissedDeadline(); + } + } + /* Time to wake has overflown. A deadline was missed if the current time + * is larger than the time to wake */ + else if((timeToWake < xLastWakeTime) and (currentTickCount > timeToWake)) { + handleMissedDeadline(); + } +} + +TaskHandle_t PeriodicTask::getTaskHandle() { + return handle; +} + +void PeriodicTask::handleMissedDeadline() { +#ifdef DEBUG + sif::warning << "PeriodicTask: " << pcTaskGetName(NULL) << + " missed deadline!\n" << std::flush; +#endif + if(deadlineMissedFunc != nullptr) { + this->deadlineMissedFunc(); + } +} From 4530b1954811727d0f32eea4fd25b8378a153db0 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Thu, 27 Aug 2020 16:13:36 +0200 Subject: [PATCH 3/5] header update --- osal/FreeRTOS/PeriodicTask.h | 254 +++++++++++++++++------------------ 1 file changed, 126 insertions(+), 128 deletions(-) diff --git a/osal/FreeRTOS/PeriodicTask.h b/osal/FreeRTOS/PeriodicTask.h index 1cdc3df70..87b8b6d2f 100644 --- a/osal/FreeRTOS/PeriodicTask.h +++ b/osal/FreeRTOS/PeriodicTask.h @@ -1,128 +1,126 @@ -#ifndef FRAMEWORK_OSAL_FREERTOS_PERIODICTASK_H_ -#define FRAMEWORK_OSAL_FREERTOS_PERIODICTASK_H_ - -#include "../../osal/FreeRTOS/FreeRTOSTaskIF.h" -#include "../../objectmanager/ObjectManagerIF.h" -#include "../../tasks/PeriodicTaskIF.h" -#include "../../tasks/Typedef.h" - - -#include -#include - -#include - -class ExecutableObjectIF; - -/** - * @brief This class represents a specialized task for - * periodic activities of multiple objects. - * @ingroup task_handling - */ -class PeriodicTask: public PeriodicTaskIF, public FreeRTOSTaskIF { -public: - /** - * Keep in Mind that you need to call before this vTaskStartScheduler()! - * A lot of task parameters are set in "FreeRTOSConfig.h". - * TODO: why does this need to be called before vTaskStartScheduler? - * @details - * The class is initialized without allocated objects. - * These need to be added with #addComponent. - * @param priority - * Sets the priority of a task. Values depend on freeRTOS configuration, - * high number means high priority. - * @param stack_size - * The stack size reserved by the operating system for the task. - * @param setPeriod - * The length of the period with which the task's - * functionality will be executed. It is expressed in clock ticks. - * @param setDeadlineMissedFunc - * The function pointer to the deadline missed function that shall - * be assigned. - */ - PeriodicTask(TaskName name, TaskPriority setPriority, - 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. - */ - virtual ~PeriodicTask(void); - - /** - * @brief The method to start the task. - * @details The method starts the task with the respective system call. - * Entry point is the taskEntryPoint method described below. - * The address of the task object is passed as an argument - * to the system call. - */ - ReturnValue_t startTask() override; - /** - * Adds an object to the list of objects to be executed. - * The objects are executed in the order added. - * @param object Id of the object to add. - * @return - * -@c RETURN_OK on success - * -@c RETURN_FAILED if the object could not be added. - */ - ReturnValue_t addComponent(object_id_t object) override; - - uint32_t getPeriodMs() const override; - - ReturnValue_t sleepFor(uint32_t ms) override; - - TaskHandle_t getTaskHandle() override; -protected: - bool started; - TaskHandle_t handle; - - //! Typedef for the List of objects. - typedef std::vector ObjectList; - /** - * @brief This attribute holds a list of objects to be executed. - */ - ObjectList objectList; - /** - * @brief The period of the task. - * @details - * The period determines the frequency of the task's execution. - * It is expressed in clock ticks. - */ - TaskPeriod period; - /** - * @brief The pointer to the deadline-missed function. - * @details - * This pointer stores the function that is executed if the task's deadline - * is missed so each may react individually on a timing failure. - * 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); - /** - * @brief This is the function executed in the new task's context. - * @details - * It converts the argument back to the thread object type and copies the - * class instance to the task context. The taskFunctionality method is - * called afterwards. - * @param A pointer to the task object itself is passed as argument. - */ - - static void taskEntryPoint(void* argument); - /** - * @brief The function containing the actual functionality of the task. - * @details - * 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, - * all performOperation methods of the added objects are called. - * Afterwards the checkAndRestartPeriod system call blocks the task until - * the next period. - * On missing the deadline, the deadlineMissedFunction is executed. - */ - void taskFunctionality(void); - - void checkMissedDeadline(const TickType_t xLastWakeTime, - const TickType_t interval); - void handleMissedDeadline(); -}; - -#endif /* PERIODICTASK_H_ */ +#ifndef FSFW_OSAL_FREERTOS_PERIODICTASK_H_ +#define FSFW_OSAL_FREERTOS_PERIODICTASK_H_ + +#include "FreeRTOSTaskIF.h" +#include "../../objectmanager/ObjectManagerIF.h" +#include "../../tasks/PeriodicTaskIF.h" +#include "../../tasks/Typedef.h" + +#include +#include + +#include + +class ExecutableObjectIF; + +/** + * @brief This class represents a specialized task for + * periodic activities of multiple objects. + * @ingroup task_handling + */ +class PeriodicTask: public PeriodicTaskIF, public FreeRTOSTaskIF { +public: + /** + * Keep in Mind that you need to call before this vTaskStartScheduler()! + * A lot of task parameters are set in "FreeRTOSConfig.h". + * @details + * The class is initialized without allocated objects. + * These need to be added with #addComponent. + * @param priority + * Sets the priority of a task. Values depend on freeRTOS configuration, + * high number means high priority. + * @param stack_size + * The stack size reserved by the operating system for the task. + * @param setPeriod + * The length of the period with which the task's + * functionality will be executed. It is expressed in clock ticks. + * @param setDeadlineMissedFunc + * The function pointer to the deadline missed function that shall + * be assigned. + */ + PeriodicTask(TaskName name, TaskPriority setPriority, + 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. + */ + virtual ~PeriodicTask(void); + + /** + * @brief The method to start the task. + * @details The method starts the task with the respective system call. + * Entry point is the taskEntryPoint method described below. + * The address of the task object is passed as an argument + * to the system call. + */ + ReturnValue_t startTask() override; + /** + * Adds an object to the list of objects to be executed. + * The objects are executed in the order added. + * @param object Id of the object to add. + * @return + * -@c RETURN_OK on success + * -@c RETURN_FAILED if the object could not be added. + */ + ReturnValue_t addComponent(object_id_t object) override; + + uint32_t getPeriodMs() const override; + + ReturnValue_t sleepFor(uint32_t ms) override; + + TaskHandle_t getTaskHandle() override; +protected: + bool started; + TaskHandle_t handle; + + //! Typedef for the List of objects. + typedef std::vector ObjectList; + /** + * @brief This attribute holds a list of objects to be executed. + */ + ObjectList objectList; + /** + * @brief The period of the task. + * @details + * The period determines the frequency of the task's execution. + * It is expressed in clock ticks. + */ + TaskPeriod period; + /** + * @brief The pointer to the deadline-missed function. + * @details + * This pointer stores the function that is executed if the task's deadline + * is missed so each may react individually on a timing failure. + * 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); + /** + * @brief This is the function executed in the new task's context. + * @details + * It converts the argument back to the thread object type and copies the + * class instance to the task context. The taskFunctionality method is + * called afterwards. + * @param A pointer to the task object itself is passed as argument. + */ + + static void taskEntryPoint(void* argument); + /** + * @brief The function containing the actual functionality of the task. + * @details + * 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, + * all performOperation methods of the added objects are called. + * Afterwards the checkAndRestartPeriod system call blocks the task until + * the next period. + * On missing the deadline, the deadlineMissedFunction is executed. + */ + void taskFunctionality(void); + + void checkMissedDeadline(const TickType_t xLastWakeTime, + const TickType_t interval); + void handleMissedDeadline(); +}; + +#endif /* FSFW_OSAL_FREERTOS_PERIODICTASK_H_ */ From 381914886dd445b9af9669af658ac1b00c035e86 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 4 Sep 2020 14:43:53 +0200 Subject: [PATCH 4/5] initAfterTaskCreation added for linux --- osal/linux/PeriodicPosixTask.cpp | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/osal/linux/PeriodicPosixTask.cpp b/osal/linux/PeriodicPosixTask.cpp index df3694ef0..69dbb6191 100644 --- a/osal/linux/PeriodicPosixTask.cpp +++ b/osal/linux/PeriodicPosixTask.cpp @@ -46,27 +46,33 @@ ReturnValue_t PeriodicPosixTask::startTask(void){ } void PeriodicPosixTask::taskFunctionality(void){ - if(!started){ + if(not started){ suspend(); } + + for (auto const &object: objectList) { + object->initializeAfterTaskCreation(); + } + uint64_t lastWakeTime = getCurrentMonotonicTimeMs(); //The task's "infinite" inner loop is entered. while (1) { - for (ObjectList::iterator it = objectList.begin(); - it != objectList.end(); ++it) { - (*it)->performOperation(); + for (auto const &object: objectList) { + object->performOperation(); } - if(!PosixThread::delayUntil(&lastWakeTime,periodMs)){ + + if(not PosixThread::delayUntil(&lastWakeTime, periodMs)){ char name[20] = {0}; - int status = pthread_getname_np(pthread_self(),name,sizeof(name)); - if(status==0){ + int status = pthread_getname_np(pthread_self(), name, sizeof(name)); + if(status == 0) { sif::error << "PeriodicPosixTask " << name << ": Deadline " "missed." << std::endl; - }else{ + } + else { sif::error << "PeriodicPosixTask X: Deadline missed. " << status << std::endl; } - if (this->deadlineMissedFunc != NULL) { + if (this->deadlineMissedFunc != nullptr) { this->deadlineMissedFunc(); } } From 4bdac1e0179191c67f559233d8fdebcfedada654 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 4 Sep 2020 14:49:59 +0200 Subject: [PATCH 5/5] changed from mueller/master taken over --- osal/linux/PeriodicPosixTask.cpp | 12 +++++++----- osal/linux/PeriodicPosixTask.h | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/osal/linux/PeriodicPosixTask.cpp b/osal/linux/PeriodicPosixTask.cpp index 69dbb6191..3c1df6bb1 100644 --- a/osal/linux/PeriodicPosixTask.cpp +++ b/osal/linux/PeriodicPosixTask.cpp @@ -5,8 +5,8 @@ PeriodicPosixTask::PeriodicPosixTask(const char* name_, int priority_, size_t stackSize_, uint32_t period_, void(deadlineMissedFunc_)()): - PosixThread(name_,priority_,stackSize_),objectList(),started(false), - periodMs(period_),deadlineMissedFunc(deadlineMissedFunc_) { + PosixThread(name_, priority_, stackSize_), objectList(), started(false), + periodMs(period_), deadlineMissedFunc(deadlineMissedFunc_) { } PeriodicPosixTask::~PeriodicPosixTask() { @@ -25,6 +25,8 @@ ReturnValue_t PeriodicPosixTask::addComponent(object_id_t object) { ExecutableObjectIF* newObject = objectManager->get( object); if (newObject == nullptr) { + sif::error << "PeriodicTask::addComponent: Invalid object. Make sure" + << " it implements ExecutableObjectIF!" << std::endl; return HasReturnvaluesIF::RETURN_FAILED; } objectList.push_back(newObject); @@ -38,15 +40,15 @@ ReturnValue_t PeriodicPosixTask::sleepFor(uint32_t ms) { } -ReturnValue_t PeriodicPosixTask::startTask(void){ +ReturnValue_t PeriodicPosixTask::startTask(void) { started = true; //sif::info << stackSize << std::endl; PosixThread::createTask(&taskEntryPoint,this); return HasReturnvaluesIF::RETURN_OK; } -void PeriodicPosixTask::taskFunctionality(void){ - if(not started){ +void PeriodicPosixTask::taskFunctionality(void) { + if(not started) { suspend(); } diff --git a/osal/linux/PeriodicPosixTask.h b/osal/linux/PeriodicPosixTask.h index f23adf4d8..ffee236bc 100644 --- a/osal/linux/PeriodicPosixTask.h +++ b/osal/linux/PeriodicPosixTask.h @@ -32,7 +32,7 @@ public: * The address of the task object is passed as an argument * to the system call. */ - ReturnValue_t startTask(void); + ReturnValue_t startTask() override; /** * Adds an object to the list of objects to be executed. * The objects are executed in the order added.