diff --git a/osal/FreeRTOS/PeriodicTask.cpp b/osal/FreeRTOS/PeriodicTask.cpp index 31867639..170eb0a4 100644 --- a/osal/FreeRTOS/PeriodicTask.cpp +++ b/osal/FreeRTOS/PeriodicTask.cpp @@ -70,39 +70,67 @@ void PeriodicTask::taskFunctionality() { xLastWakeTime = xTaskGetTickCount(); /* Enter the loop that defines the task behavior. */ for (;;) { - for (ObjectList::iterator it = objectList.begin(); - it != objectList.end(); ++it) { - (*it)->performOperation(); + for (auto const& object: objectList) { + object->performOperation(); } - /* If all operations are finished and the difference of the - * current time minus the last wake time is larger than the - * wait period, a deadline was missed. */ - if(xTaskGetTickCount() - xLastWakeTime >= xPeriod) { -#ifdef DEBUG - sif::warning << "PeriodicTask: " << pcTaskGetName(NULL) << - " missed deadline!\n" << std::flush; -#endif - if(deadlineMissedFunc != nullptr) { - this->deadlineMissedFunc(); - } - } + checkMissedDeadline(xLastWakeTime, xPeriod); vTaskDelayUntil(&xLastWakeTime, xPeriod); } } -ReturnValue_t PeriodicTask::addComponent(object_id_t object) { +ReturnValue_t PeriodicTask::addComponent(object_id_t object, bool setTaskIF) { ExecutableObjectIF* newObject = objectManager->get( object); - if (newObject == NULL) { + if (newObject == nullptr) { + sif::error << "PeriodicTask::addComponent: Invalid object. Make sure" + "it implement ExecutableObjectIF" << std::endl; return HasReturnvaluesIF::RETURN_FAILED; } objectList.push_back(newObject); + + if(setTaskIF) { + 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; + // Tick count has overflown + if(currentTickCount < xLastWakeTime) { + // Time to wake has overflown as well. If the tick count + // is larger than the time to wake, a deadline was missed. + if(timeToWake < xLastWakeTime and + currentTickCount > timeToWake) { + handleMissedDeadline(); + } + } + // No tick count overflow. If the timeToWake has not overflown + // and the current tick count is larger than the time to wake, + // a deadline was missed. + else if(timeToWake > xLastWakeTime and currentTickCount > timeToWake) { + handleMissedDeadline(); + } +} + +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 b9930a73..09aa6bc7 100644 --- a/osal/FreeRTOS/PeriodicTask.h +++ b/osal/FreeRTOS/PeriodicTask.h @@ -54,7 +54,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. @@ -63,11 +63,12 @@ public: * -@c RETURN_OK on success * -@c RETURN_FAILED if the object could not be added. */ - ReturnValue_t addComponent(object_id_t object); + ReturnValue_t addComponent(object_id_t object, + bool setTaskIF = true) override; - uint32_t getPeriodMs() const; + uint32_t getPeriodMs() const override; - ReturnValue_t sleepFor(uint32_t ms); + ReturnValue_t sleepFor(uint32_t ms) override; protected: bool started; TaskHandle_t handle; @@ -115,6 +116,10 @@ protected: * 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_ */ diff --git a/osal/linux/PeriodicPosixTask.cpp b/osal/linux/PeriodicPosixTask.cpp index b754c3f4..1a06a8bf 100644 --- a/osal/linux/PeriodicPosixTask.cpp +++ b/osal/linux/PeriodicPosixTask.cpp @@ -20,13 +20,18 @@ void* PeriodicPosixTask::taskEntryPoint(void* arg) { return NULL; } -ReturnValue_t PeriodicPosixTask::addComponent(object_id_t object) { +ReturnValue_t PeriodicPosixTask::addComponent(object_id_t object, + bool addTaskIF) { ExecutableObjectIF* newObject = objectManager->get( object); - if (newObject == NULL) { + if (newObject == nullptr) { return HasReturnvaluesIF::RETURN_FAILED; } objectList.push_back(newObject); + + if(setTaskIF) { + newObject->setTaskIF(this); + } return HasReturnvaluesIF::RETURN_OK; } diff --git a/osal/linux/PeriodicPosixTask.h b/osal/linux/PeriodicPosixTask.h index 43647eda..e994898a 100644 --- a/osal/linux/PeriodicPosixTask.h +++ b/osal/linux/PeriodicPosixTask.h @@ -26,11 +26,12 @@ public: * @param object Id of the object to add. * @return RETURN_OK on success, RETURN_FAILED if the object could not be added. */ - ReturnValue_t addComponent(object_id_t object); + ReturnValue_t addComponent(object_id_t object, + bool addTaskIF = true) override; - uint32_t getPeriodMs() const; + uint32_t getPeriodMs() const override; - ReturnValue_t sleepFor(uint32_t ms); + ReturnValue_t sleepFor(uint32_t ms) override; private: typedef std::vector ObjectList; //!< Typedef for the List of objects. diff --git a/tasks/PeriodicTaskIF.h b/tasks/PeriodicTaskIF.h index 304a7de6..6f490977 100644 --- a/tasks/PeriodicTaskIF.h +++ b/tasks/PeriodicTaskIF.h @@ -1,9 +1,11 @@ -#ifndef PERIODICTASKIF_H_ -#define PERIODICTASKIF_H_ +#ifndef FRAMEWORK_TASK_PERIODICTASKIF_H_ +#define FRAMEWORK_TASK_PERIODICTASKIF_H_ #include +#include #include class ExecutableObjectIF; + /** * New version of TaskIF * Follows RAII principles, i.e. there's no create or delete method. @@ -17,11 +19,27 @@ public: */ virtual ~PeriodicTaskIF() { } /** - * @brief With the startTask method, a created task can be started for the first time. + * @brief With the startTask method, a created task can be started + * for the first time. */ virtual ReturnValue_t startTask() = 0; - virtual ReturnValue_t addComponent(object_id_t object) {return HasReturnvaluesIF::RETURN_FAILED;}; + /** + * Add a component (object) to a periodic task. The pointer to the + * task can be set optionally + * @param object + * Add an object to the task. The most important case is to add an + * executable object with a function which will be called regularly + * (see ExecutableObjectIF) + * @param setTaskIF + * Can be used to specify whether the task object pointer is passed + * to the component. + * @return + */ + virtual ReturnValue_t addComponent(object_id_t object, + bool setTaskIF = true) { + return HasReturnvaluesIF::RETURN_FAILED; + }; virtual ReturnValue_t sleepFor(uint32_t ms) = 0;