diff --git a/CHANGELOG.md b/CHANGELOG.md index df3ae8bf..9ba6d754 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,38 @@ and this project adheres to [Semantic Versioning](http://semver.org/). the message queue. Also streamlined and simplified `MessageQueue` implementation for all OSALs PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/583 +### Task Module Refactoring + +PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/636 + +**Refactoring general task code** + +- There was a lot of duplicate/boilerplate code inside the individual task IF OSAL implementations. + Remove it by introducing base classes `PeriodicTaskBase` and `FixedTimeslotTaskBase`. + +**Refactor PeriodicTaskIF** + +- Convert `virtual ReturnValue_t addComponent(object_id_t object)` to + `virtual ReturnValue_t addComponent(object_id_t object, uint8_t opCode = 0)`, allowing to pass + the operation code passed to `performOperation`. Updated API taking + an `ExecutableObjectIF` accordingly + +**Refactor FixedTimeslotTaskIF** + +- Add additional `addSlot` function which takes an `ExecutableObjectIF` pointer and its Object ID + +**Refactor FixedSequenceSlot** + +- Introduce typedef `CustomCheckFunc` for `ReturnValue_t (*customCheckFunction)(const SlotList&)`. +- Convert `ReturnValue_t (*customCheckFunction)(const SlotList&)` to + `ReturnValue_t (*customCheckFunction)(const SlotList&, void*)`, allowing arbitrary user arguments + for the custom checker + +**Linux Task Module** + +- Use composition instead of inheritance for the `PeriodicPosixTask` and make the `PosixTask` a + member of the class + ### HAL - HAL Linux Uart: Baudrate and bits per word are enums now, avoiding misconfigurations diff --git a/CMakeLists.txt b/CMakeLists.txt index c102d445..d8163f3e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -186,7 +186,7 @@ endif() message(STATUS "${MSG_PREFIX} Finding and/or providing ETL library") # Check whether the user has already installed ETL first -find_package(${FSFW_ETL_LIB_NAME} ${FSFW_ETL_LIB_MAJOR_VERSION} CONFIG QUIET) +find_package(${FSFW_ETL_LIB_NAME} ${FSFW_ETL_LIB_MAJOR_VERSION} QUIET) # Not installed, so use FetchContent to download and provide etl if(NOT ${FSFW_ETL_LIB_NAME}_FOUND) message( diff --git a/hal/src/fsfw_hal/stm32h7/devicetest/GyroL3GD20H.h b/hal/src/fsfw_hal/stm32h7/devicetest/GyroL3GD20H.h index a6c3376a..a0c3748a 100644 --- a/hal/src/fsfw_hal/stm32h7/devicetest/GyroL3GD20H.h +++ b/hal/src/fsfw_hal/stm32h7/devicetest/GyroL3GD20H.h @@ -10,6 +10,10 @@ #include "stm32h7xx_hal.h" #include "stm32h7xx_hal_spi.h" +#ifndef STM_USE_PERIPHERAL_TX_BUFFER_MPU_PROTECTION +#define STM_USE_PERIPHERAL_TX_BUFFER_MPU_PROTECTION 1 +#endif + enum class TransferStates { IDLE, WAIT, SUCCESS, FAILURE }; class GyroL3GD20H { diff --git a/src/fsfw/datapoollocal/LocalDataPoolManager.cpp b/src/fsfw/datapoollocal/LocalDataPoolManager.cpp index 781d8f71..215d1753 100644 --- a/src/fsfw/datapoollocal/LocalDataPoolManager.cpp +++ b/src/fsfw/datapoollocal/LocalDataPoolManager.cpp @@ -696,9 +696,9 @@ void LocalDataPoolManager::performPeriodicHkGeneration(HkReceiver& receiver) { if (result != HasReturnvaluesIF::RETURN_OK) { /* Configuration error */ #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "LocalDataPoolManager::performHkOperation: HK generation failed." << std::endl; + sif::warning << "LocalDataPoolManager::performPeriodicHkOperation: HK generation failed." << std::endl; #else - sif::printWarning("LocalDataPoolManager::performHkOperation: HK generation failed.\n"); + sif::printWarning("LocalDataPoolManager::performPeriodicHkOperation: HK generation failed.\n"); #endif } } diff --git a/src/fsfw/osal/freertos/FixedTimeslotTask.cpp b/src/fsfw/osal/freertos/FixedTimeslotTask.cpp index e0e3779e..e86636ab 100644 --- a/src/fsfw/osal/freertos/FixedTimeslotTask.cpp +++ b/src/fsfw/osal/freertos/FixedTimeslotTask.cpp @@ -1,27 +1,23 @@ #include "fsfw/osal/freertos/FixedTimeslotTask.h" -#include "fsfw/objectmanager/ObjectManager.h" -#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/serviceinterface.h" -uint32_t FixedTimeslotTask::deadlineMissedCount = 0; const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = configMINIMAL_STACK_SIZE; FixedTimeslotTask::FixedTimeslotTask(TaskName name, TaskPriority setPriority, - TaskStackSize setStack, TaskPeriod overallPeriod, - void (*setDeadlineMissedFunc)()) - : started(false), handle(nullptr), pst(overallPeriod * 1000) { + TaskStackSize setStack, TaskPeriod period, + TaskDeadlineMissedFunction dlmFunc_) + : FixedTimeslotTaskBase(period, dlmFunc_), started(false), handle(nullptr) { configSTACK_DEPTH_TYPE stackSize = setStack / sizeof(configSTACK_DEPTH_TYPE); xTaskCreate(taskEntryPoint, name, stackSize, this, setPriority, &handle); - // All additional attributes are applied to the object. - this->deadlineMissedFunc = setDeadlineMissedFunc; } -FixedTimeslotTask::~FixedTimeslotTask() {} +FixedTimeslotTask::~FixedTimeslotTask() = default; void FixedTimeslotTask::taskEntryPoint(void* argument) { // The argument is re-interpreted as FixedTimeslotTask. The Task object is // global, so it is found from any place. - FixedTimeslotTask* originalTask(reinterpret_cast(argument)); + auto* 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. @@ -32,26 +28,18 @@ void FixedTimeslotTask::taskEntryPoint(void* argument) { * can continue */ if (not originalTask->started) { - vTaskSuspend(NULL); + vTaskSuspend(nullptr); } originalTask->taskFunctionality(); #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::debug << "Polling task " << originalTask->handle << " returned from taskFunctionality." << std::endl; +#else + sif::printDebug("Polling task returned from taskFunctionality\n"); #endif } -void FixedTimeslotTask::missedDeadlineCounter() { - FixedTimeslotTask::deadlineMissedCount++; - if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "PST missed " << FixedTimeslotTask::deadlineMissedCount << " deadlines." - << std::endl; -#endif - } -} - ReturnValue_t FixedTimeslotTask::startTask() { started = true; @@ -63,31 +51,12 @@ ReturnValue_t FixedTimeslotTask::startTask() { return HasReturnvaluesIF::RETURN_OK; } -ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, uint32_t slotTimeMs, - int8_t executionStep) { - ExecutableObjectIF* handler = ObjectManager::instance()->get(componentId); - if (handler != nullptr) { - pst.addSlot(componentId, slotTimeMs, executionStep, handler, this); - return HasReturnvaluesIF::RETURN_OK; - } - -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "Component " << std::hex << componentId << " not found, not adding it to pst" - << std::endl; -#endif - return HasReturnvaluesIF::RETURN_FAILED; -} - -uint32_t FixedTimeslotTask::getPeriodMs() const { return pst.getLengthMs(); } - -ReturnValue_t FixedTimeslotTask::checkSequence() const { return pst.checkSequence(); } - -void FixedTimeslotTask::taskFunctionality() { +[[noreturn]] void FixedTimeslotTask::taskFunctionality() { // A local iterator for the Polling Sequence Table is created to find the // start time for the first entry. - auto slotListIter = pst.current; + auto slotListIter = pollingSeqTable.current; - pst.intializeSequenceAfterTaskCreation(); + pollingSeqTable.intializeSequenceAfterTaskCreation(); // The start time for the first entry is read. uint32_t intervalMs = slotListIter->pollingTimeMs; @@ -108,10 +77,10 @@ void FixedTimeslotTask::taskFunctionality() { /* Enter the loop that defines the task behavior. */ for (;;) { // The component for this slot is executed and the next one is chosen. - this->pst.executeAndAdvance(); - if (not pst.slotFollowsImmediately()) { + this->pollingSeqTable.executeAndAdvance(); + if (not pollingSeqTable.slotFollowsImmediately()) { // Get the interval till execution of the next slot. - intervalMs = this->pst.getIntervalToPreviousSlotMs(); + intervalMs = this->pollingSeqTable.getIntervalToPreviousSlotMs(); interval = pdMS_TO_TICKS(intervalMs); #if (tskKERNEL_VERSION_MAJOR == 10 && tskKERNEL_VERSION_MINOR >= 4) || tskKERNEL_VERSION_MAJOR > 10 @@ -132,8 +101,8 @@ void FixedTimeslotTask::taskFunctionality() { } void FixedTimeslotTask::handleMissedDeadline() { - if (deadlineMissedFunc != nullptr) { - this->deadlineMissedFunc(); + if (dlmFunc != nullptr) { + dlmFunc(); } } diff --git a/src/fsfw/osal/freertos/FixedTimeslotTask.h b/src/fsfw/osal/freertos/FixedTimeslotTask.h index 77999d71..53c9a11c 100644 --- a/src/fsfw/osal/freertos/FixedTimeslotTask.h +++ b/src/fsfw/osal/freertos/FixedTimeslotTask.h @@ -4,11 +4,11 @@ #include "FreeRTOS.h" #include "FreeRTOSTaskIF.h" #include "fsfw/tasks/FixedSlotSequence.h" -#include "fsfw/tasks/FixedTimeslotTaskIF.h" -#include "fsfw/tasks/Typedef.h" +#include "fsfw/tasks/FixedTimeslotTaskBase.h" +#include "fsfw/tasks/definitions.h" #include "task.h" -class FixedTimeslotTask : public FixedTimeslotTaskIF, public FreeRTOSTaskIF { +class FixedTimeslotTask : public FixedTimeslotTaskBase, public FreeRTOSTaskIF { public: /** * Keep in mind that you need to call before vTaskStartScheduler()! @@ -23,7 +23,7 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF, public FreeRTOSTaskIF { * @return Pointer to the newly created task. */ FixedTimeslotTask(TaskName name, TaskPriority setPriority, TaskStackSize setStack, - TaskPeriod overallPeriod, void (*setDeadlineMissedFunc)()); + TaskPeriod overallPeriod, TaskDeadlineMissedFunction dlmFunc); /** * @brief The destructor of the class. @@ -32,26 +32,9 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF, public FreeRTOSTaskIF { * initialization for the PST and the device handlers. This is done by * calling the PST's destructor. */ - virtual ~FixedTimeslotTask(void); + ~FixedTimeslotTask() override; - ReturnValue_t startTask(void); - /** - * This static function can be used as #deadlineMissedFunc. - * It counts missedDeadlines and prints the number of missed deadlines - * every 10th time. - */ - static void missedDeadlineCounter(); - /** - * A helper variable to count missed deadlines. - */ - static uint32_t deadlineMissedCount; - - ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs, - int8_t executionStep) override; - - uint32_t getPeriodMs() const override; - - ReturnValue_t checkSequence() const override; + ReturnValue_t startTask() override; ReturnValue_t sleepFor(uint32_t ms) override; @@ -61,17 +44,6 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF, public FreeRTOSTaskIF { bool started; TaskHandle_t handle; - FixedSlotSequence pst; - - /** - * @brief This attribute holds a function pointer that is executed when - * a deadline was missed. - * @details - * Another function may be announced to determine the actions to perform - * when a deadline was missed. Currently, only one function for missing - * any deadline is allowed. If not used, it shall be declared NULL. - */ - void (*deadlineMissedFunc)(void); /** * @brief This is the entry point for a new task. * @details @@ -88,7 +60,7 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF, public FreeRTOSTaskIF { * It links the functionalities provided by FixedSlotSequence with the * OS's System Calls to keep the timing of the periods. */ - void taskFunctionality(void); + [[noreturn]] void taskFunctionality(); void handleMissedDeadline(); }; diff --git a/src/fsfw/osal/freertos/FreeRTOSTaskIF.h b/src/fsfw/osal/freertos/FreeRTOSTaskIF.h index ad5c9f7f..dbefc6c1 100644 --- a/src/fsfw/osal/freertos/FreeRTOSTaskIF.h +++ b/src/fsfw/osal/freertos/FreeRTOSTaskIF.h @@ -6,11 +6,11 @@ class FreeRTOSTaskIF { public: - virtual ~FreeRTOSTaskIF() {} + virtual ~FreeRTOSTaskIF() = default; virtual TaskHandle_t getTaskHandle() = 0; protected: - bool checkMissedDeadline(const TickType_t xLastWakeTime, const TickType_t interval) { + static bool 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. */ diff --git a/src/fsfw/osal/freertos/PeriodicTask.cpp b/src/fsfw/osal/freertos/PeriodicTask.cpp index d2c46ea8..665be06c 100644 --- a/src/fsfw/osal/freertos/PeriodicTask.cpp +++ b/src/fsfw/osal/freertos/PeriodicTask.cpp @@ -5,27 +5,28 @@ #include "fsfw/tasks/ExecutableObjectIF.h" PeriodicTask::PeriodicTask(const char* name, TaskPriority setPriority, TaskStackSize setStack, - TaskPeriod setPeriod, TaskDeadlineMissedFunction deadlineMissedFunc) - : started(false), handle(NULL), period(setPeriod), deadlineMissedFunc(deadlineMissedFunc) { + TaskPeriod setPeriod, TaskDeadlineMissedFunction dlmFunc_) + : PeriodicTaskBase(setPeriod, dlmFunc_), started(false), handle(nullptr) { configSTACK_DEPTH_TYPE stackSize = setStack / sizeof(configSTACK_DEPTH_TYPE); BaseType_t status = xTaskCreate(taskEntryPoint, name, stackSize, this, setPriority, &handle); if (status != pdPASS) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::debug << "PeriodicTask Insufficient heap memory remaining. " - "Status: " + sif::debug << "PeriodicTask::PeriodicTask Insufficient heap memory remaining. Status: " << status << std::endl; +#else + sif::printDebug("PeriodicTask::PeriodicTask: Insufficient heap memory remaining. Status: %d\n", + status); #endif } } -PeriodicTask::~PeriodicTask(void) { - // Do not delete objects, we were responsible for ptrs only. -} +// Do not delete objects, we were responsible for ptrs only. +PeriodicTask::~PeriodicTask() = default; 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)); + auto* 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. @@ -36,7 +37,7 @@ void PeriodicTask::taskEntryPoint(void* argument) { * can continue */ if (not originalTask->started) { - vTaskSuspend(NULL); + vTaskSuspend(nullptr); } originalTask->taskFunctionality(); @@ -62,13 +63,11 @@ ReturnValue_t PeriodicTask::sleepFor(uint32_t ms) { return HasReturnvaluesIF::RETURN_OK; } -void PeriodicTask::taskFunctionality() { +[[noreturn]] void PeriodicTask::taskFunctionality() { TickType_t xLastWakeTime; const TickType_t xPeriod = pdMS_TO_TICKS(this->period * 1000.); - for (auto const& object : objectList) { - object->initializeAfterTaskCreation(); - } + initObjsAfterTaskCreation(); /* The xLastWakeTime variable needs to be initialized with the current tick count. Note that this is the only time the variable is written to @@ -77,8 +76,8 @@ void PeriodicTask::taskFunctionality() { xLastWakeTime = xTaskGetTickCount(); /* Enter the loop that defines the task behavior. */ for (;;) { - for (auto const& object : objectList) { - object->performOperation(); + for (auto const& objectPair : objectList) { + objectPair.first->performOperation(objectPair.second); } #if (tskKERNEL_VERSION_MAJOR == 10 && tskKERNEL_VERSION_MINOR >= 4) || tskKERNEL_VERSION_MAJOR > 10 @@ -95,32 +94,10 @@ void PeriodicTask::taskFunctionality() { } } -ReturnValue_t PeriodicTask::addComponent(object_id_t object) { - ExecutableObjectIF* newObject = ObjectManager::instance()->get(object); - return addComponent(newObject); -} - -ReturnValue_t PeriodicTask::addComponent(ExecutableObjectIF* object) { - if (object == nullptr) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "PeriodicTask::addComponent: Invalid object. Make sure" - "it implement ExecutableObjectIF" - << std::endl; -#endif - return HasReturnvaluesIF::RETURN_FAILED; - } - objectList.push_back(object); - object->setTaskIF(this); - - return HasReturnvaluesIF::RETURN_OK; -} - -uint32_t PeriodicTask::getPeriodMs() const { return period * 1000; } - TaskHandle_t PeriodicTask::getTaskHandle() { return handle; } void PeriodicTask::handleMissedDeadline() { - if (deadlineMissedFunc != nullptr) { - this->deadlineMissedFunc(); + if (dlmFunc != nullptr) { + dlmFunc(); } } diff --git a/src/fsfw/osal/freertos/PeriodicTask.h b/src/fsfw/osal/freertos/PeriodicTask.h index fc8e9092..c3fb9d70 100644 --- a/src/fsfw/osal/freertos/PeriodicTask.h +++ b/src/fsfw/osal/freertos/PeriodicTask.h @@ -6,8 +6,8 @@ #include "FreeRTOS.h" #include "FreeRTOSTaskIF.h" #include "fsfw/objectmanager/ObjectManagerIF.h" -#include "fsfw/tasks/PeriodicTaskIF.h" -#include "fsfw/tasks/Typedef.h" +#include "fsfw/tasks/PeriodicTaskBase.h" +#include "fsfw/tasks/definitions.h" #include "task.h" class ExecutableObjectIF; @@ -17,7 +17,7 @@ class ExecutableObjectIF; * periodic activities of multiple objects. * @ingroup task_handling */ -class PeriodicTask : public PeriodicTaskIF, public FreeRTOSTaskIF { +class PeriodicTask : public PeriodicTaskBase, public FreeRTOSTaskIF { public: /** * Keep in Mind that you need to call before this vTaskStartScheduler()! @@ -43,7 +43,7 @@ class PeriodicTask : public PeriodicTaskIF, public FreeRTOSTaskIF { * @brief Currently, the executed object's lifetime is not coupled with * the task object's lifetime, so the destructor is empty. */ - virtual ~PeriodicTask(void); + ~PeriodicTask() override; /** * @brief The method to start the task. @@ -53,27 +53,6 @@ class PeriodicTask : public PeriodicTaskIF, public FreeRTOSTaskIF { * 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; - - /** - * 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(ExecutableObjectIF* object) override; - - uint32_t getPeriodMs() const override; ReturnValue_t sleepFor(uint32_t ms) override; @@ -83,28 +62,6 @@ class PeriodicTask : public PeriodicTaskIF, public FreeRTOSTaskIF { 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 @@ -125,7 +82,7 @@ class PeriodicTask : public PeriodicTaskIF, public FreeRTOSTaskIF { * the next period. * On missing the deadline, the deadlineMissedFunction is executed. */ - void taskFunctionality(void); + [[noreturn]] void taskFunctionality(); void handleMissedDeadline(); }; diff --git a/src/fsfw/osal/host/FixedTimeslotTask.cpp b/src/fsfw/osal/host/FixedTimeslotTask.cpp index 07853938..1d10b8d8 100644 --- a/src/fsfw/osal/host/FixedTimeslotTask.cpp +++ b/src/fsfw/osal/host/FixedTimeslotTask.cpp @@ -3,9 +3,7 @@ #include #include -#include "fsfw/ipc/MutexFactory.h" #include "fsfw/objectmanager/ObjectManager.h" -#include "fsfw/osal/host/FixedTimeslotTask.h" #include "fsfw/osal/host/Mutex.h" #include "fsfw/osal/host/taskHelpers.h" #include "fsfw/platform.h" @@ -22,12 +20,8 @@ FixedTimeslotTask::FixedTimeslotTask(const char* name, TaskPriority setPriority, TaskStackSize setStack, TaskPeriod setPeriod, - void (*setDeadlineMissedFunc)()) - : started(false), - pollingSeqTable(setPeriod * 1000), - taskName(name), - period(setPeriod), - deadlineMissedFunc(setDeadlineMissedFunc) { + TaskDeadlineMissedFunction dlmFunc_) + : FixedTimeslotTaskBase(setPeriod, dlmFunc_), started(false), taskName(name) { // It is propably possible to set task priorities by using the native // task handles for Windows / Linux mainThread = std::thread(&FixedTimeslotTask::taskEntryPoint, this, this); @@ -39,7 +33,7 @@ FixedTimeslotTask::FixedTimeslotTask(const char* name, TaskPriority setPriority, tasks::insertTaskName(mainThread.get_id(), taskName); } -FixedTimeslotTask::~FixedTimeslotTask(void) { +FixedTimeslotTask::~FixedTimeslotTask() { // Do not delete objects, we were responsible for ptrs only. terminateThread = true; if (mainThread.joinable()) { @@ -48,7 +42,7 @@ FixedTimeslotTask::~FixedTimeslotTask(void) { } void FixedTimeslotTask::taskEntryPoint(void* argument) { - FixedTimeslotTask* originalTask(reinterpret_cast(argument)); + auto* originalTask(reinterpret_cast(argument)); if (not originalTask->started) { // we have to suspend/block here until the task is started. @@ -81,7 +75,9 @@ ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) { } void FixedTimeslotTask::taskFunctionality() { - pollingSeqTable.intializeSequenceAfterTaskCreation(); + ReturnValue_t result = pollingSeqTable.intializeSequenceAfterTaskCreation(); + // Ignore returnvalue for now + static_cast(result); // A local iterator for the Polling Sequence Table is created to // find the start time for the first entry. @@ -106,37 +102,15 @@ void FixedTimeslotTask::taskFunctionality() { // we need to wait before executing the current slot // this gives us the time to wait: interval = chron_ms(this->pollingSeqTable.getIntervalToPreviousSlotMs()); - delayForInterval(¤tStartTime, interval); - // TODO deadline missed check + if (not delayForInterval(¤tStartTime, interval)) { + if (dlmFunc != nullptr) { + dlmFunc(); + } + } } } } -ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, uint32_t slotTimeMs, - int8_t executionStep) { - ExecutableObjectIF* executableObject = - ObjectManager::instance()->get(componentId); - if (executableObject != nullptr) { - pollingSeqTable.addSlot(componentId, slotTimeMs, executionStep, executableObject, this); - return HasReturnvaluesIF::RETURN_OK; - } - -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "Component " << std::hex << "0x" << componentId - << "not found, " - "not adding it to PST.." - << std::dec << std::endl; -#else - sif::printError("Component 0x%08x not found, not adding it to PST..\n", - static_cast(componentId)); -#endif - return HasReturnvaluesIF::RETURN_FAILED; -} - -ReturnValue_t FixedTimeslotTask::checkSequence() const { return pollingSeqTable.checkSequence(); } - -uint32_t FixedTimeslotTask::getPeriodMs() const { return period * 1000; } - bool FixedTimeslotTask::delayForInterval(chron_ms* previousWakeTimeMs, const chron_ms interval) { bool shouldDelay = false; // Get current wakeup time diff --git a/src/fsfw/osal/host/FixedTimeslotTask.h b/src/fsfw/osal/host/FixedTimeslotTask.h index cdbc6f23..4e77f8fd 100644 --- a/src/fsfw/osal/host/FixedTimeslotTask.h +++ b/src/fsfw/osal/host/FixedTimeslotTask.h @@ -6,10 +6,10 @@ #include #include -#include "../../objectmanager/ObjectManagerIF.h" -#include "../../tasks/FixedSlotSequence.h" -#include "../../tasks/FixedTimeslotTaskIF.h" -#include "../../tasks/Typedef.h" +#include "fsfw/objectmanager/ObjectManagerIF.h" +#include "fsfw/tasks/FixedSlotSequence.h" +#include "fsfw/tasks/FixedTimeslotTaskBase.h" +#include "fsfw/tasks/definitions.h" class ExecutableObjectIF; @@ -19,7 +19,7 @@ class ExecutableObjectIF; * @details * @ingroup task_handling */ -class FixedTimeslotTask : public FixedTimeslotTaskIF { +class FixedTimeslotTask : public FixedTimeslotTaskBase { public: /** * @brief Standard constructor of the class. @@ -39,7 +39,7 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF { * @brief Currently, the executed object's lifetime is not coupled with * the task object's lifetime, so the destructor is empty. */ - virtual ~FixedTimeslotTask(void); + ~FixedTimeslotTask() override; /** * @brief The method to start the task. @@ -48,56 +48,22 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF { * The address of the task object is passed as an argument * to the system call. */ - ReturnValue_t startTask(void); + ReturnValue_t startTask() override; - /** - * Add timeslot to the polling sequence table. - * @param componentId - * @param slotTimeMs - * @param executionStep - * @return - */ - ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs, int8_t executionStep); - - ReturnValue_t checkSequence() const override; - - uint32_t getPeriodMs() const; - - ReturnValue_t sleepFor(uint32_t ms); + ReturnValue_t sleepFor(uint32_t ms) override; protected: using chron_ms = std::chrono::milliseconds; bool started; - //!< Typedef for the List of objects. - typedef std::vector ObjectList; + std::thread mainThread; std::atomic terminateThread{false}; - //! Polling sequence table which contains the object to execute - //! and information like the timeslots and the passed execution step. - FixedSlotSequence pollingSeqTable; - std::condition_variable initCondition; std::mutex initMutex; std::string taskName; - /** - * @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 @@ -117,9 +83,9 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF { * the checkAndRestartPeriod system call blocks the task until the next * period. On missing the deadline, the deadlineMissedFunction is executed. */ - void taskFunctionality(void); + void taskFunctionality(); - bool delayForInterval(chron_ms* previousWakeTimeMs, const chron_ms interval); + static bool delayForInterval(chron_ms* previousWakeTimeMs, chron_ms interval); }; #endif /* FRAMEWORK_OSAL_HOST_FIXEDTIMESLOTTASK_H_ */ diff --git a/src/fsfw/osal/host/PeriodicTask.cpp b/src/fsfw/osal/host/PeriodicTask.cpp index cdcfafa6..1f18d335 100644 --- a/src/fsfw/osal/host/PeriodicTask.cpp +++ b/src/fsfw/osal/host/PeriodicTask.cpp @@ -3,13 +3,10 @@ #include #include -#include "fsfw/ipc/MutexFactory.h" -#include "fsfw/objectmanager/ObjectManager.h" #include "fsfw/osal/host/Mutex.h" #include "fsfw/osal/host/taskHelpers.h" #include "fsfw/platform.h" #include "fsfw/serviceinterface/ServiceInterface.h" -#include "fsfw/tasks/ExecutableObjectIF.h" #if defined(PLATFORM_WIN) #include @@ -20,8 +17,8 @@ #endif PeriodicTask::PeriodicTask(const char* name, TaskPriority setPriority, TaskStackSize setStack, - TaskPeriod setPeriod, void (*setDeadlineMissedFunc)()) - : started(false), taskName(name), period(setPeriod), deadlineMissedFunc(setDeadlineMissedFunc) { + TaskPeriod setPeriod, TaskDeadlineMissedFunction dlmFunc_) + : PeriodicTaskBase(setPeriod, dlmFunc_), started(false), taskName(name) { // It is probably possible to set task priorities by using the native // task handles for Windows / Linux mainThread = std::thread(&PeriodicTask::taskEntryPoint, this, this); @@ -33,7 +30,7 @@ PeriodicTask::PeriodicTask(const char* name, TaskPriority setPriority, TaskStack tasks::insertTaskName(mainThread.get_id(), taskName); } -PeriodicTask::~PeriodicTask(void) { +PeriodicTask::~PeriodicTask() { // Do not delete objects, we were responsible for ptrs only. terminateThread = true; if (mainThread.joinable()) { @@ -42,7 +39,7 @@ PeriodicTask::~PeriodicTask(void) { } void PeriodicTask::taskEntryPoint(void* argument) { - PeriodicTask* originalTask(reinterpret_cast(argument)); + auto* originalTask(reinterpret_cast(argument)); if (not originalTask->started) { // we have to suspend/block here until the task is started. @@ -75,47 +72,27 @@ ReturnValue_t PeriodicTask::sleepFor(uint32_t ms) { } void PeriodicTask::taskFunctionality() { - for (const auto& object : objectList) { - object->initializeAfterTaskCreation(); - } + initObjsAfterTaskCreation(); std::chrono::milliseconds periodChrono(static_cast(period * 1000)); auto currentStartTime{std::chrono::duration_cast( std::chrono::system_clock::now().time_since_epoch())}; - auto nextStartTime{currentStartTime}; - /* Enter the loop that defines the task behavior. */ for (;;) { if (terminateThread.load()) { break; } - for (const auto& object : objectList) { - object->performOperation(); + for (const auto& objectPair : objectList) { + objectPair.first->performOperation(objectPair.second); } if (not delayForInterval(¤tStartTime, periodChrono)) { - if (deadlineMissedFunc != nullptr) { - this->deadlineMissedFunc(); + if (dlmFunc != nullptr) { + this->dlmFunc(); } } } } -ReturnValue_t PeriodicTask::addComponent(object_id_t object) { - ExecutableObjectIF* newObject = ObjectManager::instance()->get(object); - return addComponent(newObject); -} - -ReturnValue_t PeriodicTask::addComponent(ExecutableObjectIF* object) { - if (object == nullptr) { - return HasReturnvaluesIF::RETURN_FAILED; - } - object->setTaskIF(this); - objectList.push_back(object); - return HasReturnvaluesIF::RETURN_OK; -} - -uint32_t PeriodicTask::getPeriodMs() const { return period * 1000; } - bool PeriodicTask::delayForInterval(chron_ms* previousWakeTimeMs, const chron_ms interval) { bool shouldDelay = false; // Get current wakeup time diff --git a/src/fsfw/osal/host/PeriodicTask.h b/src/fsfw/osal/host/PeriodicTask.h index 6c4d5e8b..6fdaae4e 100644 --- a/src/fsfw/osal/host/PeriodicTask.h +++ b/src/fsfw/osal/host/PeriodicTask.h @@ -6,9 +6,9 @@ #include #include -#include "../../objectmanager/ObjectManagerIF.h" -#include "../../tasks/PeriodicTaskIF.h" -#include "../../tasks/Typedef.h" +#include "fsfw/objectmanager/ObjectManagerIF.h" +#include "fsfw/tasks/PeriodicTaskBase.h" +#include "fsfw/tasks/definitions.h" class ExecutableObjectIF; @@ -19,7 +19,7 @@ class ExecutableObjectIF; * * @ingroup task_handling */ -class PeriodicTask : public PeriodicTaskIF { +class PeriodicTask : public PeriodicTaskBase { public: /** * @brief Standard constructor of the class. @@ -34,12 +34,12 @@ class PeriodicTask : public PeriodicTaskIF { * assigned. */ PeriodicTask(const char* name, TaskPriority setPriority, TaskStackSize setStack, - TaskPeriod setPeriod, void (*setDeadlineMissedFunc)()); + TaskPeriod setPeriod, TaskDeadlineMissedFunction dlmFunc); /** * @brief Currently, the executed object's lifetime is not coupled with * the task object's lifetime, so the destructor is empty. */ - virtual ~PeriodicTask(void); + ~PeriodicTask() override; /** * @brief The method to start the task. @@ -48,63 +48,20 @@ class PeriodicTask : public PeriodicTaskIF { * The address of the task object is passed as an argument * to the system call. */ - ReturnValue_t startTask(void); - /** - * 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); + 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 pointer to the object to add. - * @return - * -@c RETURN_OK on success - * -@c RETURN_FAILED if the object could not be added. - */ - ReturnValue_t addComponent(ExecutableObjectIF* object); - - uint32_t getPeriodMs() const; - - ReturnValue_t sleepFor(uint32_t ms); + ReturnValue_t sleepFor(uint32_t ms) override; protected: using chron_ms = std::chrono::milliseconds; bool started; - //!< Typedef for the List of objects. - typedef std::vector ObjectList; std::thread mainThread; std::atomic terminateThread{false}; - /** - * @brief This attribute holds a list of objects to be executed. - */ - ObjectList objectList; - std::condition_variable initCondition; std::mutex initMutex; std::string taskName; - /** - * @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 @@ -124,9 +81,9 @@ class PeriodicTask : public PeriodicTaskIF { * the checkAndRestartPeriod system call blocks the task until the next * period. On missing the deadline, the deadlineMissedFunction is executed. */ - void taskFunctionality(void); + void taskFunctionality(); - bool delayForInterval(chron_ms* previousWakeTimeMs, const chron_ms interval); + static bool delayForInterval(chron_ms* previousWakeTimeMs, chron_ms interval); }; -#endif /* PERIODICTASK_H_ */ +#endif /* FRAMEWORK_OSAL_HOST_PERIODICTASK_H_ */ diff --git a/src/fsfw/osal/host/TaskFactory.cpp b/src/fsfw/osal/host/TaskFactory.cpp index 6e74fd57..ec4c1554 100644 --- a/src/fsfw/osal/host/TaskFactory.cpp +++ b/src/fsfw/osal/host/TaskFactory.cpp @@ -14,9 +14,9 @@ TaskFactory* TaskFactory::factoryInstance = new TaskFactory(); // Not used for the host implementation for now because C++ thread abstraction is used const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = 0; -TaskFactory::TaskFactory() {} +TaskFactory::TaskFactory() = default; -TaskFactory::~TaskFactory() {} +TaskFactory::~TaskFactory() = default; TaskFactory* TaskFactory::instance() { return TaskFactory::factoryInstance; } diff --git a/src/fsfw/osal/host/taskHelpers.cpp b/src/fsfw/osal/host/taskHelpers.cpp index aba2948a..432cf30c 100644 --- a/src/fsfw/osal/host/taskHelpers.cpp +++ b/src/fsfw/osal/host/taskHelpers.cpp @@ -6,7 +6,7 @@ std::mutex nameMapLock; std::map taskNameMap; -ReturnValue_t tasks::insertTaskName(std::thread::id threadId, std::string taskName) { +ReturnValue_t tasks::insertTaskName(std::thread::id threadId, const std::string& taskName) { std::lock_guard lg(nameMapLock); auto returnPair = taskNameMap.emplace(threadId, taskName); if (not returnPair.second) { diff --git a/src/fsfw/osal/host/taskHelpers.h b/src/fsfw/osal/host/taskHelpers.h index cf553011..13a71d16 100644 --- a/src/fsfw/osal/host/taskHelpers.h +++ b/src/fsfw/osal/host/taskHelpers.h @@ -7,7 +7,7 @@ namespace tasks { -ReturnValue_t insertTaskName(std::thread::id threadId, std::string taskName); +ReturnValue_t insertTaskName(std::thread::id threadId, const std::string& taskName); std::string getTaskName(std::thread::id threadId); } // namespace tasks diff --git a/src/fsfw/osal/linux/FixedTimeslotTask.cpp b/src/fsfw/osal/linux/FixedTimeslotTask.cpp index 1f4d6e23..775acea8 100644 --- a/src/fsfw/osal/linux/FixedTimeslotTask.cpp +++ b/src/fsfw/osal/linux/FixedTimeslotTask.cpp @@ -1,22 +1,20 @@ #include "fsfw/osal/linux/FixedTimeslotTask.h" -#include +#include -#include "fsfw/objectmanager/ObjectManager.h" #include "fsfw/serviceinterface/ServiceInterface.h" -uint32_t FixedTimeslotTask::deadlineMissedCount = 0; const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = PTHREAD_STACK_MIN; -FixedTimeslotTask::FixedTimeslotTask(const char* name_, int priority_, size_t stackSize_, - uint32_t periodMs_) - : PosixThread(name_, priority_, stackSize_), pst(periodMs_), started(false) {} - -FixedTimeslotTask::~FixedTimeslotTask() {} +FixedTimeslotTask::FixedTimeslotTask(const char* name_, TaskPriority priority_, size_t stackSize_, + TaskPeriod periodSeconds_, TaskDeadlineMissedFunction dlmFunc_) + : FixedTimeslotTaskBase(periodSeconds_, dlmFunc_), + posixThread(name_, priority_, stackSize_), + started(false) {} void* FixedTimeslotTask::taskEntryPoint(void* arg) { // The argument is re-interpreted as PollingTask. - FixedTimeslotTask* originalTask(reinterpret_cast(arg)); + auto* originalTask(reinterpret_cast(arg)); // The task's functionality is called. originalTask->taskFunctionality(); return nullptr; @@ -24,7 +22,7 @@ void* FixedTimeslotTask::taskEntryPoint(void* arg) { ReturnValue_t FixedTimeslotTask::startTask() { started = true; - createTask(&taskEntryPoint, this); + posixThread.createTask(&taskEntryPoint, this); return HasReturnvaluesIF::RETURN_OK; } @@ -32,63 +30,36 @@ ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) { return PosixThread::sleep((uint64_t)ms * 1000000); } -uint32_t FixedTimeslotTask::getPeriodMs() const { return pst.getLengthMs(); } - -ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, uint32_t slotTimeMs, - int8_t executionStep) { - ExecutableObjectIF* executableObject = - ObjectManager::instance()->get(componentId); - if (executableObject != nullptr) { - pst.addSlot(componentId, slotTimeMs, executionStep, executableObject, this); - return HasReturnvaluesIF::RETURN_OK; - } - -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "Component " << std::hex << componentId << " not found, not adding it to pst" - << std::dec << std::endl; -#endif - return HasReturnvaluesIF::RETURN_FAILED; -} - -ReturnValue_t FixedTimeslotTask::checkSequence() const { return pst.checkSequence(); } - -void FixedTimeslotTask::taskFunctionality() { +[[noreturn]] void FixedTimeslotTask::taskFunctionality() { // Like FreeRTOS pthreads are running as soon as they are created if (!started) { - suspend(); + posixThread.suspend(); } - pst.intializeSequenceAfterTaskCreation(); + // Returnvalue ignored for now + static_cast(pollingSeqTable.intializeSequenceAfterTaskCreation()); // The start time for the first entry is read. - uint64_t lastWakeTime = getCurrentMonotonicTimeMs(); - uint64_t interval = pst.getIntervalToNextSlotMs(); + uint64_t lastWakeTime = PosixThread::getCurrentMonotonicTimeMs(); + uint32_t interval = 0; // The task's "infinite" inner loop is entered. - while (1) { - if (pst.slotFollowsImmediately()) { + while (true) { + if (pollingSeqTable.slotFollowsImmediately()) { // Do nothing } else { // The interval for the next polling slot is selected. - interval = this->pst.getIntervalToPreviousSlotMs(); + interval = pollingSeqTable.getIntervalToPreviousSlotMs(); // The period is checked and restarted with the new interval. // If the deadline was missed, the deadlineMissedFunc is called. if (!PosixThread::delayUntil(&lastWakeTime, interval)) { // No time left on timer -> we missed the deadline - missedDeadlineCounter(); + if(dlmFunc != nullptr){ + dlmFunc(); + } } } // The device handler for this slot is executed and the next one is chosen. - this->pst.executeAndAdvance(); - } -} - -void FixedTimeslotTask::missedDeadlineCounter() { - FixedTimeslotTask::deadlineMissedCount++; - if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "PST missed " << FixedTimeslotTask::deadlineMissedCount << " deadlines." - << std::endl; -#endif + pollingSeqTable.executeAndAdvance(); } } diff --git a/src/fsfw/osal/linux/FixedTimeslotTask.h b/src/fsfw/osal/linux/FixedTimeslotTask.h index 76b92db3..1f5766a2 100644 --- a/src/fsfw/osal/linux/FixedTimeslotTask.h +++ b/src/fsfw/osal/linux/FixedTimeslotTask.h @@ -3,11 +3,12 @@ #include -#include "../../tasks/FixedSlotSequence.h" -#include "../../tasks/FixedTimeslotTaskIF.h" #include "PosixThread.h" +#include "fsfw/tasks/FixedSlotSequence.h" +#include "fsfw/tasks/FixedTimeslotTaskBase.h" +#include "fsfw/tasks/definitions.h" -class FixedTimeslotTask : public FixedTimeslotTaskIF, public PosixThread { +class FixedTimeslotTask : public FixedTimeslotTaskBase { public: /** * Create a generic periodic task. @@ -21,29 +22,13 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF, public PosixThread { * @param period_ * @param deadlineMissedFunc_ */ - FixedTimeslotTask(const char* name_, int priority_, size_t stackSize_, uint32_t periodMs_); - virtual ~FixedTimeslotTask(); + FixedTimeslotTask(const char* name_, TaskPriority priority_, size_t stackSize_, + TaskPeriod periodSeconds_, TaskDeadlineMissedFunction dlmFunc_); + ~FixedTimeslotTask() override = default; - virtual ReturnValue_t startTask(); + ReturnValue_t startTask() override; - virtual ReturnValue_t sleepFor(uint32_t ms); - - virtual uint32_t getPeriodMs() const; - - virtual ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs, int8_t executionStep); - - virtual ReturnValue_t checkSequence() const; - - /** - * This static function can be used as #deadlineMissedFunc. - * It counts missedDeadlines and prints the number of missed deadlines every 10th time. - */ - static void missedDeadlineCounter(); - - /** - * A helper variable to count missed deadlines. - */ - static uint32_t deadlineMissedCount; + ReturnValue_t sleepFor(uint32_t ms) override; protected: /** @@ -53,9 +38,12 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF, public PosixThread { * It links the functionalities provided by FixedSlotSequence with the * OS's System Calls to keep the timing of the periods. */ - virtual void taskFunctionality(); + [[noreturn]] virtual void taskFunctionality(); private: + PosixThread posixThread; + bool started; + /** * @brief This is the entry point in a new thread. * @@ -68,9 +56,6 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF, public PosixThread { * arbitrary data. */ static void* taskEntryPoint(void* arg); - FixedSlotSequence pst; - - bool started; }; #endif /* FSFW_OSAL_LINUX_FIXEDTIMESLOTTASK_H_ */ diff --git a/src/fsfw/osal/linux/PeriodicPosixTask.cpp b/src/fsfw/osal/linux/PeriodicPosixTask.cpp index e1937df4..09b106ed 100644 --- a/src/fsfw/osal/linux/PeriodicPosixTask.cpp +++ b/src/fsfw/osal/linux/PeriodicPosixTask.cpp @@ -1,86 +1,54 @@ -#include "fsfw/osal/linux/PeriodicPosixTask.h" +#include "PeriodicPosixTask.h" -#include - -#include "fsfw/objectmanager/ObjectManager.h" -#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/serviceinterface.h" #include "fsfw/tasks/ExecutableObjectIF.h" 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_) {} - -PeriodicPosixTask::~PeriodicPosixTask() { - // Not Implemented -} + TaskPeriod period_, TaskDeadlineMissedFunction dlmFunc_) + : PeriodicTaskBase(period_, dlmFunc_), + posixThread(name_, priority_, stackSize_), + started(false) {} void* PeriodicPosixTask::taskEntryPoint(void* arg) { // The argument is re-interpreted as PollingTask. - PeriodicPosixTask* originalTask(reinterpret_cast(arg)); + auto* originalTask(reinterpret_cast(arg)); // The task's functionality is called. originalTask->taskFunctionality(); - return NULL; -} - -ReturnValue_t PeriodicPosixTask::addComponent(object_id_t object) { - ExecutableObjectIF* newObject = ObjectManager::instance()->get(object); - return addComponent(newObject); -} - -ReturnValue_t PeriodicPosixTask::addComponent(ExecutableObjectIF* object) { - if (object == nullptr) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "PeriodicTask::addComponent: Invalid object. Make sure" - << " it implements ExecutableObjectIF!" << std::endl; -#else - sif::printError( - "PeriodicTask::addComponent: Invalid object. Make sure it " - "implements ExecutableObjectIF!\n"); -#endif - return HasReturnvaluesIF::RETURN_FAILED; - } - objectList.push_back(object); - object->setTaskIF(this); - - return HasReturnvaluesIF::RETURN_OK; + return nullptr; } ReturnValue_t PeriodicPosixTask::sleepFor(uint32_t ms) { - return PosixThread::sleep((uint64_t)ms * 1000000); + return PosixThread::sleep(static_cast(ms) * 1000000); } -ReturnValue_t PeriodicPosixTask::startTask(void) { +ReturnValue_t PeriodicPosixTask::startTask() { + if (isEmpty()) { + return HasReturnvaluesIF::RETURN_FAILED; + } started = true; - PosixThread::createTask(&taskEntryPoint, this); + posixThread.createTask(&taskEntryPoint, this); return HasReturnvaluesIF::RETURN_OK; } -void PeriodicPosixTask::taskFunctionality(void) { +[[noreturn]] void PeriodicPosixTask::taskFunctionality() { if (not started) { - suspend(); + posixThread.suspend(); } - for (auto const& object : objectList) { - object->initializeAfterTaskCreation(); - } + initObjsAfterTaskCreation(); - uint64_t lastWakeTime = getCurrentMonotonicTimeMs(); + uint64_t lastWakeTime = PosixThread::getCurrentMonotonicTimeMs(); + uint64_t periodMs = getPeriodMs(); // The task's "infinite" inner loop is entered. - while (1) { - for (auto const& object : objectList) { - object->performOperation(); + while (true) { + for (auto const& objOpCodePair : objectList) { + objOpCodePair.first->performOperation(objOpCodePair.second); } if (not PosixThread::delayUntil(&lastWakeTime, periodMs)) { - if (this->deadlineMissedFunc != nullptr) { - this->deadlineMissedFunc(); + if (dlmFunc != nullptr) { + dlmFunc(); } } } } - -uint32_t PeriodicPosixTask::getPeriodMs() const { return periodMs; } diff --git a/src/fsfw/osal/linux/PeriodicPosixTask.h b/src/fsfw/osal/linux/PeriodicPosixTask.h index 3cd9847a..085c10b9 100644 --- a/src/fsfw/osal/linux/PeriodicPosixTask.h +++ b/src/fsfw/osal/linux/PeriodicPosixTask.h @@ -3,12 +3,13 @@ #include -#include "../../objectmanager/ObjectManagerIF.h" -#include "../../tasks/ExecutableObjectIF.h" -#include "../../tasks/PeriodicTaskIF.h" #include "PosixThread.h" +#include "fsfw/objectmanager/ObjectManagerIF.h" +#include "fsfw/tasks/ExecutableObjectIF.h" +#include "fsfw/tasks/PeriodicTaskBase.h" +#include "fsfw/tasks/PeriodicTaskIF.h" -class PeriodicPosixTask : public PosixThread, public PeriodicTaskIF { +class PeriodicPosixTask : public PeriodicTaskBase { public: /** * Create a generic periodic task. @@ -22,9 +23,9 @@ class PeriodicPosixTask : public PosixThread, public PeriodicTaskIF { * @param period_ * @param deadlineMissedFunc_ */ - PeriodicPosixTask(const char* name_, int priority_, size_t stackSize_, uint32_t period_, - void (*deadlineMissedFunc_)()); - virtual ~PeriodicPosixTask(); + PeriodicPosixTask(const char* name_, int priority_, size_t stackSize_, TaskPeriod period_, + TaskDeadlineMissedFunction dlmFunc_); + ~PeriodicPosixTask() override = default; /** * @brief The method to start the task. @@ -34,42 +35,17 @@ class PeriodicPosixTask : public PosixThread, public PeriodicTaskIF { * 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 RETURN_OK on success, RETURN_FAILED if the object could not be added. - */ - ReturnValue_t addComponent(object_id_t object) override; - - /** - * Adds an object to the list of objects to be executed. - * The objects are executed in the order added. - * @param object pointer to the object to add. - * @return RETURN_OK on success, RETURN_FAILED if the object could not be added. - */ - ReturnValue_t addComponent(ExecutableObjectIF* object) override; - - uint32_t getPeriodMs() const override; ReturnValue_t sleepFor(uint32_t ms) override; private: - typedef std::vector ObjectList; //!< Typedef for the List of objects. - /** - * @brief This attribute holds a list of objects to be executed. - */ - ObjectList objectList; + PosixThread posixThread; /** * @brief Flag to indicate that the task was started and is allowed to run */ bool started; - /** - * @brief Period of the task in milliseconds - */ - uint32_t periodMs; /** * @brief The function containing the actual functionality of the task. * @details The method sets and starts @@ -78,7 +54,7 @@ class PeriodicPosixTask : public PosixThread, public PeriodicTaskIF { * will be blocked until the next period. On missing the deadline, the deadlineMissedFunction is * executed. */ - virtual void taskFunctionality(void); + [[noreturn]] virtual void taskFunctionality(); /** * @brief This is the entry point in a new thread. * @@ -86,14 +62,6 @@ class PeriodicPosixTask : public PosixThread, public PeriodicTaskIF { * of the child class. Needs a valid pointer to the derived class. */ static void* taskEntryPoint(void* arg); - /** - * @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)(); }; #endif /* FRAMEWORK_OSAL_LINUX_PERIODICPOSIXTASK_H_ */ diff --git a/src/fsfw/osal/linux/PosixThread.h b/src/fsfw/osal/linux/PosixThread.h index 69c6c5b7..78fdfa2b 100644 --- a/src/fsfw/osal/linux/PosixThread.h +++ b/src/fsfw/osal/linux/PosixThread.h @@ -35,6 +35,21 @@ class PosixThread { */ void resume(); + /** + * @brief Function that has to be called by derived class because the + * derived class pointer has to be valid as argument. + * @details + * This function creates a pthread with the given parameters. As the + * function requires a pointer to the derived object it has to be called + * after the this pointer of the derived object is valid. + * Sets the taskEntryPoint as function to be called by new a thread. + * @param fnc_ Function which will be executed by the thread. + * @param arg_ + * argument of the taskEntryPoint function, needs to be this pointer + * of derived class + */ + void createTask(void* (*fnc_)(void*), void* arg_); + /** * Delay function similar to FreeRtos delayUntil function * @@ -55,21 +70,6 @@ class PosixThread { protected: pthread_t thread; - /** - * @brief Function that has to be called by derived class because the - * derived class pointer has to be valid as argument. - * @details - * This function creates a pthread with the given parameters. As the - * function requires a pointer to the derived object it has to be called - * after the this pointer of the derived object is valid. - * Sets the taskEntryPoint as function to be called by new a thread. - * @param fnc_ Function which will be executed by the thread. - * @param arg_ - * argument of the taskEntryPoint function, needs to be this pointer - * of derived class - */ - void createTask(void* (*fnc_)(void*), void* arg_); - private: char name[PTHREAD_MAX_NAMELEN]; int priority; diff --git a/src/fsfw/osal/linux/TaskFactory.cpp b/src/fsfw/osal/linux/TaskFactory.cpp index 8503039f..a28e685d 100644 --- a/src/fsfw/osal/linux/TaskFactory.cpp +++ b/src/fsfw/osal/linux/TaskFactory.cpp @@ -8,21 +8,22 @@ // TODO: Different variant than the lazy loading in QueueFactory. What's better and why? TaskFactory* TaskFactory::factoryInstance = new TaskFactory(); -TaskFactory::~TaskFactory() {} +TaskFactory::~TaskFactory() = default; TaskFactory* TaskFactory::instance() { return TaskFactory::factoryInstance; } PeriodicTaskIF* TaskFactory::createPeriodicTask( TaskName name_, TaskPriority taskPriority_, TaskStackSize stackSize_, TaskPeriod periodInSeconds_, TaskDeadlineMissedFunction deadLineMissedFunction_) { - return new PeriodicPosixTask(name_, taskPriority_, stackSize_, periodInSeconds_ * 1000, + return new PeriodicPosixTask(name_, taskPriority_, stackSize_, periodInSeconds_, deadLineMissedFunction_); } FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask( TaskName name_, TaskPriority taskPriority_, TaskStackSize stackSize_, TaskPeriod periodInSeconds_, TaskDeadlineMissedFunction deadLineMissedFunction_) { - return new FixedTimeslotTask(name_, taskPriority_, stackSize_, periodInSeconds_ * 1000); + return new FixedTimeslotTask(name_, taskPriority_, stackSize_, periodInSeconds_, + deadLineMissedFunction_); } ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) { diff --git a/src/fsfw/osal/rtems/FixedTimeslotTask.cpp b/src/fsfw/osal/rtems/FixedTimeslotTask.cpp index 3347739a..f400c213 100644 --- a/src/fsfw/osal/rtems/FixedTimeslotTask.cpp +++ b/src/fsfw/osal/rtems/FixedTimeslotTask.cpp @@ -1,42 +1,32 @@ #include "fsfw/osal/rtems/FixedTimeslotTask.h" -#include #include -#include #include #include #include -#include -#include "fsfw/objectmanager/ObjectManager.h" -#include "fsfw/objectmanager/SystemObjectIF.h" #include "fsfw/osal/rtems/RtemsBasic.h" #include "fsfw/returnvalues/HasReturnvaluesIF.h" #include "fsfw/serviceinterface/ServiceInterface.h" -#include "fsfw/tasks/FixedSequenceSlot.h" #if FSFW_CPP_OSTREAM_ENABLED == 1 #include #endif #include -#include - -uint32_t FixedTimeslotTask::deadlineMissedCount = 0; FixedTimeslotTask::FixedTimeslotTask(const char *name, rtems_task_priority setPriority, - size_t setStack, uint32_t setOverallPeriod, - void (*setDeadlineMissedFunc)(void)) - : RTEMSTaskBase(setPriority, setStack, name), periodId(0), pst(setOverallPeriod) { - // All additional attributes are applied to the object. - this->deadlineMissedFunc = setDeadlineMissedFunc; -} + size_t setStack, TaskPeriod setOverallPeriod, + TaskDeadlineMissedFunction dlmFunc_) + : FixedTimeslotTaskBase(setOverallPeriod, dlmFunc_), + RTEMSTaskBase(setPriority, setStack, name), + periodId(0) {} -FixedTimeslotTask::~FixedTimeslotTask() {} +FixedTimeslotTask::~FixedTimeslotTask() = default; rtems_task FixedTimeslotTask::taskEntryPoint(rtems_task_argument argument) { /* The argument is re-interpreted as a FixedTimeslotTask */ - FixedTimeslotTask *originalTask(reinterpret_cast(argument)); + auto *originalTask(reinterpret_cast(argument)); /* The task's functionality is called. */ return originalTask->taskFunctionality(); /* Should never be reached */ @@ -46,16 +36,6 @@ rtems_task FixedTimeslotTask::taskEntryPoint(rtems_task_argument argument) { #endif } -void FixedTimeslotTask::missedDeadlineCounter() { - FixedTimeslotTask::deadlineMissedCount++; - if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "PST missed " << FixedTimeslotTask::deadlineMissedCount << " deadlines." - << std::endl; -#endif - } -} - ReturnValue_t FixedTimeslotTask::startTask() { rtems_status_code status = rtems_task_start(id, FixedTimeslotTask::taskEntryPoint, rtems_task_argument((void *)this)); @@ -79,54 +59,35 @@ ReturnValue_t FixedTimeslotTask::startTask() { } } -ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, uint32_t slotTimeMs, - int8_t executionStep) { - ExecutableObjectIF *object = ObjectManager::instance()->get(componentId); - if (object != nullptr) { - pst.addSlot(componentId, slotTimeMs, executionStep, object, this); - return HasReturnvaluesIF::RETURN_OK; - } - -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "Component " << std::hex << componentId << " not found, not adding it to pst" - << std::endl; -#endif - return HasReturnvaluesIF::RETURN_FAILED; -} - -uint32_t FixedTimeslotTask::getPeriodMs() const { return pst.getLengthMs(); } - -ReturnValue_t FixedTimeslotTask::checkSequence() const { return pst.checkSequence(); } - -void FixedTimeslotTask::taskFunctionality() { +[[noreturn]] void FixedTimeslotTask::taskFunctionality() { /* A local iterator for the Polling Sequence Table is created to find the start time for the first entry. */ - FixedSlotSequence::SlotListIter it = pst.current; + auto it = pollingSeqTable.current; /* Initialize the PST with the correct calling task */ - pst.intializeSequenceAfterTaskCreation(); + pollingSeqTable.intializeSequenceAfterTaskCreation(); /* The start time for the first entry is read. */ rtems_interval interval = RtemsBasic::convertMsToTicks(it->pollingTimeMs); RTEMSTaskBase::setAndStartPeriod(interval, &periodId); // The task's "infinite" inner loop is entered. - while (1) { - if (pst.slotFollowsImmediately()) { + while (true) { + if (pollingSeqTable.slotFollowsImmediately()) { /* Do nothing */ } else { /* The interval for the next polling slot is selected. */ - interval = RtemsBasic::convertMsToTicks(this->pst.getIntervalToNextSlotMs()); + interval = RtemsBasic::convertMsToTicks(pollingSeqTable.getIntervalToNextSlotMs()); /* The period is checked and restarted with the new interval. If the deadline was missed, the deadlineMissedFunc is called. */ rtems_status_code status = RTEMSTaskBase::restartPeriod(interval, periodId); if (status == RTEMS_TIMEOUT) { - if (this->deadlineMissedFunc != nullptr) { - this->deadlineMissedFunc(); + if (dlmFunc != nullptr) { + dlmFunc(); } } } /* The device handler for this slot is executed and the next one is chosen. */ - this->pst.executeAndAdvance(); + this->pollingSeqTable.executeAndAdvance(); } } diff --git a/src/fsfw/osal/rtems/FixedTimeslotTask.h b/src/fsfw/osal/rtems/FixedTimeslotTask.h index 6dedfa44..781c93db 100644 --- a/src/fsfw/osal/rtems/FixedTimeslotTask.h +++ b/src/fsfw/osal/rtems/FixedTimeslotTask.h @@ -1,11 +1,11 @@ #ifndef FSFW_OSAL_RTEMS_FIXEDTIMESLOTTASK_H_ #define FSFW_OSAL_RTEMS_FIXEDTIMESLOTTASK_H_ -#include "../../tasks/FixedSlotSequence.h" -#include "../../tasks/FixedTimeslotTaskIF.h" #include "RTEMSTaskBase.h" +#include "fsfw/tasks/FixedSlotSequence.h" +#include "fsfw/tasks/FixedTimeslotTaskBase.h" -class FixedTimeslotTask : public RTEMSTaskBase, public FixedTimeslotTaskIF { +class FixedTimeslotTask : public FixedTimeslotTaskBase, public RTEMSTaskBase { public: /** * @brief The standard constructor of the class. @@ -17,7 +17,7 @@ class FixedTimeslotTask : public RTEMSTaskBase, public FixedTimeslotTaskIF { * @param getPst The object id of the completely initialized polling sequence. */ FixedTimeslotTask(const char *name, rtems_task_priority setPriority, size_t setStackSize, - uint32_t overallPeriod, void (*setDeadlineMissedFunc)()); + TaskPeriod overallPeriod, TaskDeadlineMissedFunction dlmFunc); /** * @brief The destructor of the class. @@ -25,44 +25,17 @@ class FixedTimeslotTask : public RTEMSTaskBase, public FixedTimeslotTaskIF { * The destructor frees all heap memory that was allocated on thread initialization * for the PST andthe device handlers. This is done by calling the PST's destructor. */ - virtual ~FixedTimeslotTask(void); + ~FixedTimeslotTask() override; ReturnValue_t startTask(void); - /** - * This static function can be used as #deadlineMissedFunc. - * It counts missedDeadlines and prints the number of missed deadlines every 10th time. - */ - static void missedDeadlineCounter(); - /** - * A helper variable to count missed deadlines. - */ - static uint32_t deadlineMissedCount; - ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs, int8_t executionStep); - - uint32_t getPeriodMs() const; - - ReturnValue_t checkSequence() const; - - ReturnValue_t sleepFor(uint32_t ms); + ReturnValue_t sleepFor(uint32_t ms) override; protected: /** * @brief id of the associated OS period */ rtems_id periodId; - - FixedSlotSequence pst; - - /** - * @brief This attribute holds a function pointer that is executed when a deadline was missed. - * - * @details - * Another function may be announced to determine the actions to perform when a deadline - * was missed. Currently, only one function for missing any deadline is allowed. - * If not used, it shall be declared NULL. - */ - void (*deadlineMissedFunc)(void) = nullptr; /** * @brief This is the entry point in a new polling thread. * @details This method is the entry point in the new thread @@ -76,7 +49,7 @@ class FixedTimeslotTask : public RTEMSTaskBase, public FixedTimeslotTaskIF { * It links the functionalities provided by FixedSlotSequence with the OS's system calls to * keep the timing of the periods. */ - void taskFunctionality(void); + [[noreturn]] void taskFunctionality(); }; #endif /* FSFW_OSAL_RTEMS_FIXEDTIMESLOTTASK_H_ */ diff --git a/src/fsfw/osal/rtems/MessageQueue.h b/src/fsfw/osal/rtems/MessageQueue.h index 2649b880..6f1ce568 100644 --- a/src/fsfw/osal/rtems/MessageQueue.h +++ b/src/fsfw/osal/rtems/MessageQueue.h @@ -59,8 +59,8 @@ class MessageQueue : public MessageQueueBase { private: /** - * \brief This attribute stores a reference to the internal error reporter for reporting full - * queues. \details In the event of a full destination queue, the reporter will be notified. The + * @brief This attribute stores a reference to the internal error reporter for reporting full + * queues. @details In the event of a full destination queue, the reporter will be notified. The * reference is set by lazy loading */ InternalErrorReporterIF* internalErrorReporter; diff --git a/src/fsfw/osal/rtems/PeriodicTask.cpp b/src/fsfw/osal/rtems/PeriodicTask.cpp index ae2ec426..cccf937f 100644 --- a/src/fsfw/osal/rtems/PeriodicTask.cpp +++ b/src/fsfw/osal/rtems/PeriodicTask.cpp @@ -5,12 +5,12 @@ #include "fsfw/tasks/ExecutableObjectIF.h" PeriodicTask::PeriodicTask(const char* name, rtems_task_priority setPriority, size_t setStack, - rtems_interval setPeriod, void (*setDeadlineMissedFunc)()) - : RTEMSTaskBase(setPriority, setStack, name), - periodTicks(RtemsBasic::convertMsToTicks(setPeriod)), - deadlineMissedFunc(setDeadlineMissedFunc) {} + TaskPeriod setPeriod, TaskDeadlineMissedFunction dlmFunc_) + : PeriodicTaskBase(setPeriod, dlmFunc_), + RTEMSTaskBase(setPriority, setStack, name), + periodTicks(RtemsBasic::convertMsToTicks(static_cast(setPeriod * 1000.0))) {} -PeriodicTask::~PeriodicTask(void) { +PeriodicTask::~PeriodicTask() { /* Do not delete objects, we were responsible for pointers only. */ rtems_rate_monotonic_delete(periodId); } @@ -18,7 +18,7 @@ PeriodicTask::~PeriodicTask(void) { rtems_task PeriodicTask::taskEntryPoint(rtems_task_argument argument) { /* The argument is re-interpreted as MultiObjectTask. The Task object is global, so it is found from any place. */ - PeriodicTask* originalTask(reinterpret_cast(argument)); + auto* originalTask(reinterpret_cast(argument)); return originalTask->taskFunctionality(); ; } @@ -28,8 +28,10 @@ ReturnValue_t PeriodicTask::startTask() { rtems_task_start(id, PeriodicTask::taskEntryPoint, rtems_task_argument((void*)this)); if (status != RTEMS_SUCCESSFUL) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "ObjectTask::startTask for " << std::hex << this->getId() << std::dec - << " failed." << std::endl; + sif::error << "PeriodicTask::startTask for " << std::hex << this->getId() << std::dec + << " failed" << std::endl; +#else + sif::printError("PeriodicTask::startTask for 0x%08x failed\n", getId()); #endif } switch (status) { @@ -47,38 +49,20 @@ ReturnValue_t PeriodicTask::startTask() { ReturnValue_t PeriodicTask::sleepFor(uint32_t ms) { return RTEMSTaskBase::sleepFor(ms); } -void PeriodicTask::taskFunctionality() { +[[noreturn]] void PeriodicTask::taskFunctionality() { RTEMSTaskBase::setAndStartPeriod(periodTicks, &periodId); - for (const auto& object : objectList) { - object->initializeAfterTaskCreation(); - } + initObjsAfterTaskCreation(); + /* The task's "infinite" inner loop is entered. */ - while (1) { - for (const auto& object : objectList) { - object->performOperation(); + while (true) { + for (const auto& objectPair : objectList) { + objectPair.first->performOperation(objectPair.second); } rtems_status_code status = RTEMSTaskBase::restartPeriod(periodTicks, periodId); if (status == RTEMS_TIMEOUT) { - if (this->deadlineMissedFunc != nullptr) { - this->deadlineMissedFunc(); + if (dlmFunc != nullptr) { + dlmFunc(); } } } } - -ReturnValue_t PeriodicTask::addComponent(object_id_t object) { - ExecutableObjectIF* newObject = ObjectManager::instance()->get(object); - return addComponent(newObject); -} - -ReturnValue_t PeriodicTask::addComponent(ExecutableObjectIF* object) { - if (object == nullptr) { - return HasReturnvaluesIF::RETURN_FAILED; - } - objectList.push_back(object); - object->setTaskIF(this); - - return HasReturnvaluesIF::RETURN_OK; -} - -uint32_t PeriodicTask::getPeriodMs() const { return RtemsBasic::convertTicksToMs(periodTicks); } diff --git a/src/fsfw/osal/rtems/PeriodicTask.h b/src/fsfw/osal/rtems/PeriodicTask.h index 9f47dfc6..d987a82e 100644 --- a/src/fsfw/osal/rtems/PeriodicTask.h +++ b/src/fsfw/osal/rtems/PeriodicTask.h @@ -3,9 +3,10 @@ #include -#include "../../objectmanager/ObjectManagerIF.h" -#include "../../tasks/PeriodicTaskIF.h" #include "RTEMSTaskBase.h" +#include "fsfw/objectmanager/ObjectManagerIF.h" +#include "fsfw/tasks/PeriodicTaskBase.h" +#include "fsfw/tasks/PeriodicTaskIF.h" class ExecutableObjectIF; @@ -18,7 +19,7 @@ class ExecutableObjectIF; * @author baetz * @ingroup task_handling */ -class PeriodicTask : public RTEMSTaskBase, public PeriodicTaskIF { +class PeriodicTask : public PeriodicTaskBase, public RTEMSTaskBase { public: /** * @brief Standard constructor of the class. @@ -36,12 +37,12 @@ class PeriodicTask : public RTEMSTaskBase, public PeriodicTaskIF { * that shall be assigned. */ PeriodicTask(const char *name, rtems_task_priority setPriority, size_t setStack, - rtems_interval setPeriod, void (*setDeadlineMissedFunc)()); + TaskPeriod setPeriod, TaskDeadlineMissedFunction dlmFunc); /** * @brief Currently, the executed object's lifetime is not coupled with the task object's * lifetime, so the destructor is empty. */ - virtual ~PeriodicTask(void); + ~PeriodicTask() override; /** * @brief The method to start the task. @@ -50,33 +51,11 @@ class PeriodicTask : public RTEMSTaskBase, public PeriodicTaskIF { * The address of the task object is passed as an argument * to the system call. */ - ReturnValue_t startTask(void); - /** - * 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 RETURN_OK on success, RETURN_FAILED if the object could not be added. - */ - ReturnValue_t addComponent(object_id_t object) override; - - /** - * Adds an object to the list of objects to be executed. - * The objects are executed in the order added. - * @param object pointer to the object to add. - * @return RETURN_OK on success, RETURN_FAILED if the object could not be added. - */ - ReturnValue_t addComponent(ExecutableObjectIF *object) override; - - uint32_t getPeriodMs() const override; + ReturnValue_t startTask() override; ReturnValue_t sleepFor(uint32_t ms) override; protected: - typedef std::vector ObjectList; //!< Typedef for the List of objects. - /** - * @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 @@ -87,14 +66,7 @@ class PeriodicTask : public RTEMSTaskBase, public PeriodicTaskIF { * @brief id of the associated OS period */ rtems_id periodId = 0; - /** - * @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 - * nullptr, 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 @@ -110,7 +82,7 @@ class PeriodicTask : public RTEMSTaskBase, public PeriodicTaskIF { * 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); + [[noreturn]] void taskFunctionality(); }; #endif /* FSFW_OSAL_RTEMS_PERIODICTASK_H_ */ diff --git a/src/fsfw/osal/rtems/RTEMSTaskBase.cpp b/src/fsfw/osal/rtems/RTEMSTaskBase.cpp index a01b7802..a306b9e2 100644 --- a/src/fsfw/osal/rtems/RTEMSTaskBase.cpp +++ b/src/fsfw/osal/rtems/RTEMSTaskBase.cpp @@ -32,7 +32,7 @@ RTEMSTaskBase::RTEMSTaskBase(rtems_task_priority set_priority, size_t stack_size RTEMSTaskBase::~RTEMSTaskBase() { rtems_task_delete(id); } -rtems_id RTEMSTaskBase::getId() { return this->id; } +rtems_id RTEMSTaskBase::getId() const { return this->id; } ReturnValue_t RTEMSTaskBase::sleepFor(uint32_t ms) { rtems_status_code status = rtems_task_wake_after(RtemsBasic::convertMsToTicks(ms)); diff --git a/src/fsfw/osal/rtems/RTEMSTaskBase.h b/src/fsfw/osal/rtems/RTEMSTaskBase.h index 9ae9e755..ed9972d3 100644 --- a/src/fsfw/osal/rtems/RTEMSTaskBase.h +++ b/src/fsfw/osal/rtems/RTEMSTaskBase.h @@ -36,9 +36,9 @@ class RTEMSTaskBase { /** * @brief This method returns the task id of this class. */ - rtems_id getId(); + rtems_id getId() const; - ReturnValue_t sleepFor(uint32_t ms); + static ReturnValue_t sleepFor(uint32_t ms); static ReturnValue_t setAndStartPeriod(rtems_interval period, rtems_id *periodId); static rtems_status_code restartPeriod(rtems_interval period, rtems_id periodId); diff --git a/src/fsfw/osal/rtems/TaskFactory.cpp b/src/fsfw/osal/rtems/TaskFactory.cpp index 8bfd53ed..fb52eb0e 100644 --- a/src/fsfw/osal/rtems/TaskFactory.cpp +++ b/src/fsfw/osal/rtems/TaskFactory.cpp @@ -1,7 +1,6 @@ #include "fsfw/tasks/TaskFactory.h" #include "fsfw/osal/rtems/FixedTimeslotTask.h" -#include "fsfw/osal/rtems/InitTask.h" #include "fsfw/osal/rtems/PeriodicTask.h" #include "fsfw/osal/rtems/RtemsBasic.h" #include "fsfw/returnvalues/HasReturnvaluesIF.h" @@ -9,29 +8,29 @@ // TODO: Different variant than the lazy loading in QueueFactory. What's better and why? TaskFactory* TaskFactory::factoryInstance = new TaskFactory(); -TaskFactory::~TaskFactory() {} +TaskFactory::TaskFactory() = default; + +TaskFactory::~TaskFactory() = default; TaskFactory* TaskFactory::instance() { return TaskFactory::factoryInstance; } PeriodicTaskIF* TaskFactory::createPeriodicTask( TaskName name_, TaskPriority taskPriority_, TaskStackSize stackSize_, TaskPeriod periodInSeconds_, TaskDeadlineMissedFunction deadLineMissedFunction_) { - rtems_interval taskPeriod = periodInSeconds_ * Clock::getTicksPerSecond(); - - return static_cast( - new PeriodicTask(name_, taskPriority_, stackSize_, taskPeriod, deadLineMissedFunction_)); + return static_cast(new PeriodicTask(name_, taskPriority_, stackSize_, + periodInSeconds_, deadLineMissedFunction_)); } FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask( TaskName name_, TaskPriority taskPriority_, TaskStackSize stackSize_, TaskPeriod periodInSeconds_, TaskDeadlineMissedFunction deadLineMissedFunction_) { - rtems_interval taskPeriod = periodInSeconds_ * Clock::getTicksPerSecond(); - return static_cast( - new FixedTimeslotTask(name_, taskPriority_, stackSize_, taskPeriod, deadLineMissedFunction_)); + return static_cast(new FixedTimeslotTask( + name_, taskPriority_, stackSize_, periodInSeconds_, deadLineMissedFunction_)); } ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) { - // TODO not implemented + // This should call the OS specific destructor + delete (dynamic_cast(task)); return HasReturnvaluesIF::RETURN_FAILED; } @@ -45,5 +44,3 @@ void TaskFactory::printMissedDeadline() { /* TODO: Implement */ return; } - -TaskFactory::TaskFactory() {} diff --git a/src/fsfw/tasks/CMakeLists.txt b/src/fsfw/tasks/CMakeLists.txt index df69520a..1d4ab4e1 100644 --- a/src/fsfw/tasks/CMakeLists.txt +++ b/src/fsfw/tasks/CMakeLists.txt @@ -1,2 +1,3 @@ -target_sources(${LIB_FSFW_NAME} PRIVATE FixedSequenceSlot.cpp - FixedSlotSequence.cpp) +target_sources( + ${LIB_FSFW_NAME} PRIVATE FixedSequenceSlot.cpp FixedSlotSequence.cpp + PeriodicTaskBase.cpp FixedTimeslotTaskBase.cpp) diff --git a/src/fsfw/tasks/FixedSlotSequence.cpp b/src/fsfw/tasks/FixedSlotSequence.cpp index d4c67b4d..9305b441 100644 --- a/src/fsfw/tasks/FixedSlotSequence.cpp +++ b/src/fsfw/tasks/FixedSlotSequence.cpp @@ -29,7 +29,7 @@ void FixedSlotSequence::executeAndAdvance() { uint32_t FixedSlotSequence::getIntervalToNextSlotMs() { uint32_t oldTime; - SlotListIter slotListIter = current; + auto slotListIter = current; // Get the pollingTimeMs of the current slot object. oldTime = slotListIter->pollingTimeMs; // Advance to the next object. @@ -51,7 +51,7 @@ uint32_t FixedSlotSequence::getIntervalToNextSlotMs() { uint32_t FixedSlotSequence::getIntervalToPreviousSlotMs() { uint32_t currentTime; - SlotListIter slotListIter = current; + auto slotListIter = current; // Get the pollingTimeMs of the current slot object. currentTime = slotListIter->pollingTimeMs; @@ -67,7 +67,7 @@ uint32_t FixedSlotSequence::getIntervalToPreviousSlotMs() { bool FixedSlotSequence::slotFollowsImmediately() { uint32_t currentTime = current->pollingTimeMs; - SlotListIter fixedSequenceIter = this->current; + auto fixedSequenceIter = this->current; // Get the pollingTimeMs of the current slot object. if (fixedSequenceIter == slotList.begin()) return false; fixedSequenceIter--; @@ -96,8 +96,8 @@ ReturnValue_t FixedSlotSequence::checkSequence() const { return FixedTimeslotTaskIF::SLOT_LIST_EMPTY; } - if (customCheckFunction != nullptr) { - ReturnValue_t result = customCheckFunction(slotList); + if (customChecker != nullptr) { + ReturnValue_t result = customChecker(slotList, customCheckArgs); if (result != HasReturnvaluesIF::RETURN_OK) { // Continue for now but print error output. #if FSFW_CPP_OSTREAM_ENABLED == 1 @@ -161,6 +161,9 @@ ReturnValue_t FixedSlotSequence::intializeSequenceAfterTaskCreation() const { return HasReturnvaluesIF::RETURN_OK; } -void FixedSlotSequence::addCustomCheck(ReturnValue_t (*customCheckFunction)(const SlotList&)) { - this->customCheckFunction = customCheckFunction; +void FixedSlotSequence::addCustomCheck(CustomCheckFunc customChecker_, void* checkerArgs_) { + customChecker = customChecker_; + customCheckArgs = checkerArgs_; } + +bool FixedSlotSequence::isEmpty() const { return slotList.empty(); } diff --git a/src/fsfw/tasks/FixedSlotSequence.h b/src/fsfw/tasks/FixedSlotSequence.h index a287c5b2..2e38ee4b 100644 --- a/src/fsfw/tasks/FixedSlotSequence.h +++ b/src/fsfw/tasks/FixedSlotSequence.h @@ -30,12 +30,12 @@ class FixedSlotSequence { public: using SlotList = std::multiset; using SlotListIter = std::multiset::iterator; - + using CustomCheckFunc = ReturnValue_t (*)(const SlotList&, void* args); /** * @brief The constructor of the FixedSlotSequence object. * @param setLength The period length, expressed in ms. */ - FixedSlotSequence(uint32_t setLengthMs); + explicit FixedSlotSequence(uint32_t setLengthMs); /** * @brief The destructor of the FixedSlotSequence object. @@ -106,7 +106,7 @@ class FixedSlotSequence { /** * @brief This method returns the length of this FixedSlotSequence instance. */ - uint32_t getLengthMs() const; + [[nodiscard]] uint32_t getLengthMs() const; /** * @brief The method to execute the device handler entered in the current @@ -137,7 +137,7 @@ class FixedSlotSequence { * @return * - SLOT_LIST_EMPTY if the slot list is empty */ - ReturnValue_t checkSequence() const; + [[nodiscard]] ReturnValue_t checkSequence() const; /** * @brief A custom check can be injected for the respective slot list. @@ -149,7 +149,7 @@ class FixedSlotSequence { * @param customCheckFunction * */ - void addCustomCheck(ReturnValue_t (*customCheckFunction)(const SlotList&)); + void addCustomCheck(CustomCheckFunc func, void* userArgs); /** * @brief Perform any initialization steps required after the executing @@ -157,7 +157,9 @@ class FixedSlotSequence { * executing task! * @return */ - ReturnValue_t intializeSequenceAfterTaskCreation() const; + [[nodiscard]] ReturnValue_t intializeSequenceAfterTaskCreation() const; + + [[nodiscard]] bool isEmpty() const; protected: /** @@ -173,7 +175,8 @@ class FixedSlotSequence { */ SlotList slotList; - ReturnValue_t (*customCheckFunction)(const SlotList&) = nullptr; + CustomCheckFunc customChecker = nullptr; + void* customCheckArgs = nullptr; uint32_t lengthMs; }; diff --git a/src/fsfw/tasks/FixedTimeslotTaskBase.cpp b/src/fsfw/tasks/FixedTimeslotTaskBase.cpp new file mode 100644 index 00000000..5d12d565 --- /dev/null +++ b/src/fsfw/tasks/FixedTimeslotTaskBase.cpp @@ -0,0 +1,27 @@ +#include "FixedTimeslotTaskBase.h" + +#include "fsfw/objectmanager/ObjectManager.h" + +FixedTimeslotTaskBase::FixedTimeslotTaskBase(TaskPeriod period_, + TaskDeadlineMissedFunction dlmFunc_) + : period(period_), pollingSeqTable(getPeriodMs()), dlmFunc(dlmFunc_) {} +uint32_t FixedTimeslotTaskBase::getPeriodMs() const { return static_cast(period * 1000); } + +bool FixedTimeslotTaskBase::isEmpty() const { return pollingSeqTable.isEmpty(); } + +ReturnValue_t FixedTimeslotTaskBase::checkSequence() { return pollingSeqTable.checkSequence(); } + +ReturnValue_t FixedTimeslotTaskBase::addSlot(object_id_t execId, ExecutableObjectIF* execObj, + uint32_t slotTimeMs, int8_t executionStep) { + if (execObj == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "Component 0x" << std::hex << std::setw(8) << std::setfill('0') << execObj + << std::setfill(' ') << " not found, not adding it to PST" << std::dec << std::endl; +#else + sif::printError("Component 0x%08x not found, not adding it to PST\n"); +#endif + return HasReturnvaluesIF::RETURN_FAILED; + } + pollingSeqTable.addSlot(execId, slotTimeMs, executionStep, execObj, this); + return HasReturnvaluesIF::RETURN_OK; +} diff --git a/src/fsfw/tasks/FixedTimeslotTaskBase.h b/src/fsfw/tasks/FixedTimeslotTaskBase.h new file mode 100644 index 00000000..b88b393c --- /dev/null +++ b/src/fsfw/tasks/FixedTimeslotTaskBase.h @@ -0,0 +1,44 @@ +#ifndef FSFW_EXAMPLE_HOSTED_FIXEDTIMESLOTTASKBASE_H +#define FSFW_EXAMPLE_HOSTED_FIXEDTIMESLOTTASKBASE_H + +#include "FixedSlotSequence.h" +#include "FixedTimeslotTaskIF.h" +#include "definitions.h" + +class FixedTimeslotTaskBase : public FixedTimeslotTaskIF { + public: + explicit FixedTimeslotTaskBase(TaskPeriod period, TaskDeadlineMissedFunction dlmFunc = nullptr); + ~FixedTimeslotTaskBase() override = default; + ; + + protected: + /** + * @brief Period of task in floating point seconds + */ + TaskPeriod period; + + //! Polling sequence table which contains the object to execute + //! and information like the timeslots and the passed execution step. + FixedSlotSequence pollingSeqTable; + + /** + * @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. + */ + TaskDeadlineMissedFunction dlmFunc = nullptr; + + ReturnValue_t checkSequence() override; + + [[nodiscard]] uint32_t getPeriodMs() const override; + + [[nodiscard]] bool isEmpty() const override; + + ReturnValue_t addSlot(object_id_t execId, ExecutableObjectIF* componentId, uint32_t slotTimeMs, + int8_t executionStep) override; +}; + +#endif // FSFW_EXAMPLE_HOSTED_FIXEDTIMESLOTTASKBASE_H diff --git a/src/fsfw/tasks/FixedTimeslotTaskIF.h b/src/fsfw/tasks/FixedTimeslotTaskIF.h index 497db245..3f5e30d8 100644 --- a/src/fsfw/tasks/FixedTimeslotTaskIF.h +++ b/src/fsfw/tasks/FixedTimeslotTaskIF.h @@ -2,6 +2,7 @@ #define FRAMEWORK_TASKS_FIXEDTIMESLOTTASKIF_H_ #include "PeriodicTaskIF.h" +#include "fsfw/objectmanager/ObjectManager.h" #include "fsfw/objectmanager/ObjectManagerIF.h" #include "fsfw/returnvalues/FwClassIds.h" @@ -11,10 +12,23 @@ */ class FixedTimeslotTaskIF : public PeriodicTaskIF { public: - virtual ~FixedTimeslotTaskIF() {} + ~FixedTimeslotTaskIF() override = default; static constexpr ReturnValue_t SLOT_LIST_EMPTY = HasReturnvaluesIF::makeReturnCode(CLASS_ID::FIXED_SLOT_TASK_IF, 0); + + /** + * Add an object with a slot time and the execution step to the task. + * The execution step will be passed to the object (e.g. as an operation + * code in #performOperation) + * @param componentId + * @param slotTimeMs + * @param executionStep + * @return + */ + virtual ReturnValue_t addSlot(object_id_t execId, ExecutableObjectIF* obj, uint32_t slotTimeMs, + int8_t executionStep) = 0; + /** * Add an object with a slot time and the execution step to the task. * The execution step will be passed to the object (e.g. as an operation @@ -25,12 +39,24 @@ class FixedTimeslotTaskIF : public PeriodicTaskIF { * @return */ virtual ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs, - int8_t executionStep) = 0; + int8_t executionStep) { + auto* execObj = ObjectManager::instance()->get(componentId); + return addSlot(componentId, execObj, slotTimeMs, executionStep); + } + /** * Check whether the sequence is valid and perform all other required * initialization steps which are needed after task creation */ - virtual ReturnValue_t checkSequence() const = 0; + virtual ReturnValue_t checkSequence() = 0; + + ReturnValue_t addComponent(object_id_t object, uint8_t opCode) override { + return HasReturnvaluesIF::RETURN_FAILED; + } + + ReturnValue_t addComponent(ExecutableObjectIF* object, uint8_t opCode) override { + return HasReturnvaluesIF::RETURN_FAILED; + } }; #endif /* FRAMEWORK_TASKS_FIXEDTIMESLOTTASKIF_H_ */ diff --git a/src/fsfw/tasks/PeriodicTaskBase.cpp b/src/fsfw/tasks/PeriodicTaskBase.cpp new file mode 100644 index 00000000..ce925a45 --- /dev/null +++ b/src/fsfw/tasks/PeriodicTaskBase.cpp @@ -0,0 +1,71 @@ +#include "PeriodicTaskBase.h" + +#include + +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/serviceinterface.h" + +PeriodicTaskBase::PeriodicTaskBase(TaskPeriod period_, TaskDeadlineMissedFunction dlmFunc_) + : period(period_), dlmFunc(dlmFunc_) { + // Hints at configuration error + if (PeriodicTaskBase::getPeriodMs() <= 1) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "Passed task period 0 or smaller than 1 ms" << std::endl; +#else + sif::printWarning("Passed task period 0 or smaller than 1ms\n"); +#endif + } +} + +uint32_t PeriodicTaskBase::getPeriodMs() const { return static_cast(period * 1000); } + +bool PeriodicTaskBase::isEmpty() const { return objectList.empty(); } + +ReturnValue_t PeriodicTaskBase::addComponent(object_id_t object) { return addComponent(object, 0); } + +ReturnValue_t PeriodicTaskBase::addComponent(ExecutableObjectIF* object) { + return addComponent(object, 0); +} + +ReturnValue_t PeriodicTaskBase::initObjsAfterTaskCreation() { + std::set uniqueObjects; + ReturnValue_t status = HasReturnvaluesIF::RETURN_OK; + uint32_t count = 0; + for (const auto& obj : objectList) { + // Ensure that each unique object is initialized once. + if (uniqueObjects.find(obj.first) == uniqueObjects.end()) { + ReturnValue_t result = obj.first->initializeAfterTaskCreation(); + if (result != HasReturnvaluesIF::RETURN_OK) { + count++; + status = result; + } + uniqueObjects.emplace(obj.first); + } + } + if (count > 0) { + } + return status; +} + +ReturnValue_t PeriodicTaskBase::addComponent(object_id_t object, uint8_t opCode) { + auto* newObject = ObjectManager::instance()->get(object); + return addComponent(newObject, opCode); +} + +ReturnValue_t PeriodicTaskBase::addComponent(ExecutableObjectIF* object, uint8_t opCode) { + if (object == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "PeriodicTask::addComponent: Invalid object. Make sure" + << " it implements ExecutableObjectIF!" << std::endl; +#else + sif::printError( + "PeriodicTask::addComponent: Invalid object. Make sure it " + "implements ExecutableObjectIF!\n"); +#endif + return HasReturnvaluesIF::RETURN_FAILED; + } + objectList.push_back({object, opCode}); + object->setTaskIF(this); + + return HasReturnvaluesIF::RETURN_OK; +} diff --git a/src/fsfw/tasks/PeriodicTaskBase.h b/src/fsfw/tasks/PeriodicTaskBase.h new file mode 100644 index 00000000..9023f104 --- /dev/null +++ b/src/fsfw/tasks/PeriodicTaskBase.h @@ -0,0 +1,54 @@ +#ifndef FSFW_SRC_FSFW_TASKS_PERIODICTASKBASE_H_ +#define FSFW_SRC_FSFW_TASKS_PERIODICTASKBASE_H_ + +#include +#include + +#include "fsfw/tasks/PeriodicTaskIF.h" +#include "fsfw/tasks/definitions.h" + +class ExecutableObjectIF; + +class PeriodicTaskBase : public PeriodicTaskIF { + public: + explicit PeriodicTaskBase(TaskPeriod period, + TaskDeadlineMissedFunction deadlineMissedFunc = nullptr); + + ReturnValue_t addComponent(object_id_t object, uint8_t opCode) override; + ReturnValue_t addComponent(ExecutableObjectIF* object, uint8_t opCode) override; + + ReturnValue_t addComponent(object_id_t object) override; + ReturnValue_t addComponent(ExecutableObjectIF* object) override; + + [[nodiscard]] uint32_t getPeriodMs() const override; + + [[nodiscard]] bool isEmpty() const override; + + ReturnValue_t initObjsAfterTaskCreation(); + + protected: + //! Typedef for the List of objects. Will contain the objects to execute and their respective + //! operation codes + using ObjectList = std::vector>; + /** + * @brief This attribute holds a list of objects to be executed. + */ + ObjectList objectList; + + /** + * @brief Period of task in floating point seconds + */ + 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. + */ + TaskDeadlineMissedFunction dlmFunc = nullptr; +}; + +#endif /* FSFW_SRC_FSFW_TASKS_PERIODICTASKBASE_H_ */ diff --git a/src/fsfw/tasks/PeriodicTaskIF.h b/src/fsfw/tasks/PeriodicTaskIF.h index c78a32de..03b709ab 100644 --- a/src/fsfw/tasks/PeriodicTaskIF.h +++ b/src/fsfw/tasks/PeriodicTaskIF.h @@ -3,9 +3,8 @@ #include -#include "../objectmanager/SystemObjectIF.h" -#include "../timemanager/Clock.h" -class ExecutableObjectIF; +#include "fsfw/objectmanager/SystemObjectIF.h" +#include "fsfw/tasks/ExecutableObjectIF.h" /** * New version of TaskIF @@ -18,7 +17,7 @@ class PeriodicTaskIF { /** * @brief A virtual destructor as it is mandatory for interfaces. */ - virtual ~PeriodicTaskIF() {} + virtual ~PeriodicTaskIF() = default; /** * @brief With the startTask method, a created task can be started * for the first time. @@ -26,28 +25,29 @@ class PeriodicTaskIF { virtual ReturnValue_t startTask() = 0; /** - * Add a component (object) to a periodic task. - * @param object - * Add an object to the task. The object needs to implement ExecutableObjectIF - * @return + * Adds an object to the list of objects to be executed. + * The objects are executed in the order added. The object needs to implement + * ExecutableObjectIF + * @param object Id of the object to add. + * @return RETURN_OK on success, RETURN_FAILED if the object could not be added. */ - virtual ReturnValue_t addComponent(object_id_t object) { - return HasReturnvaluesIF::RETURN_FAILED; - }; + virtual ReturnValue_t addComponent(object_id_t object, uint8_t opCode) = 0; + virtual ReturnValue_t addComponent(object_id_t object) { return addComponent(object, 0); }; /** - * Add an object to a periodic task. - * @param object - * Add an object to the task. - * @return + * Adds an object to the list of objects to be executed. + * The objects are executed in the order added. + * @param object pointer to the object to add. + * @return RETURN_OK on success, RETURN_FAILED if the object could not be added. */ - virtual ReturnValue_t addComponent(ExecutableObjectIF* object) { - return HasReturnvaluesIF::RETURN_FAILED; - }; + virtual ReturnValue_t addComponent(ExecutableObjectIF* object, uint8_t opCode) = 0; + virtual ReturnValue_t addComponent(ExecutableObjectIF* object) { return addComponent(object, 0); } virtual ReturnValue_t sleepFor(uint32_t ms) = 0; - virtual uint32_t getPeriodMs() const = 0; + [[nodiscard]] virtual uint32_t getPeriodMs() const = 0; + + [[nodiscard]] virtual bool isEmpty() const = 0; }; -#endif /* PERIODICTASKIF_H_ */ +#endif /* FRAMEWORK_TASK_PERIODICTASKIF_H_ */ diff --git a/src/fsfw/tasks/TaskFactory.h b/src/fsfw/tasks/TaskFactory.h index fcd62678..828c533e 100644 --- a/src/fsfw/tasks/TaskFactory.h +++ b/src/fsfw/tasks/TaskFactory.h @@ -4,7 +4,7 @@ #include #include "FixedTimeslotTaskIF.h" -#include "Typedef.h" +#include "definitions.h" /** * Singleton Class that produces Tasks. diff --git a/src/fsfw/tasks/Typedef.h b/src/fsfw/tasks/Typedef.h deleted file mode 100644 index 1bb75131..00000000 --- a/src/fsfw/tasks/Typedef.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef FSFW_TASKS_TYPEDEF_H_ -#define FSFW_TASKS_TYPEDEF_H_ - -#include -#include - -typedef const char* TaskName; -typedef uint32_t TaskPriority; -typedef size_t TaskStackSize; -typedef double TaskPeriod; -typedef void (*TaskDeadlineMissedFunction)(); - -#endif /* FSFW_TASKS_TYPEDEF_H_ */ diff --git a/src/fsfw/tasks/definitions.h b/src/fsfw/tasks/definitions.h new file mode 100644 index 00000000..586884b6 --- /dev/null +++ b/src/fsfw/tasks/definitions.h @@ -0,0 +1,13 @@ +#ifndef FSFW_TASKS_TYPEDEF_H_ +#define FSFW_TASKS_TYPEDEF_H_ + +#include +#include + +using TaskName = const char*; +using TaskPriority = int; +using TaskStackSize = size_t; +using TaskPeriod = double; +using TaskDeadlineMissedFunction = void (*)(); + +#endif /* FSFW_TASKS_TYPEDEF_H_ */ diff --git a/tests/src/fsfw_tests/integration/devices/TestDeviceHandler.cpp b/tests/src/fsfw_tests/integration/devices/TestDeviceHandler.cpp index cd15d6e0..36f1ea8c 100644 --- a/tests/src/fsfw_tests/integration/devices/TestDeviceHandler.cpp +++ b/tests/src/fsfw_tests/integration/devices/TestDeviceHandler.cpp @@ -13,14 +13,14 @@ TestDevice::TestDevice(object_id_t objectId, object_id_t comIF, CookieIF* cookie dataset(this), fullInfoPrintout(fullInfoPrintout) {} -TestDevice::~TestDevice() {} +TestDevice::~TestDevice() = default; void TestDevice::performOperationHook() { if (periodicPrintout) { #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::info << "TestDevice" << deviceIdx << "::performOperationHook: Alive!" << std::endl; #else - sif::printInfo("TestDevice%d::performOperationHook: Alive!", deviceIdx); + sif::printInfo("TestDevice%d::performOperationHook: Alive!\n", deviceIdx); #endif } diff --git a/tests/src/fsfw_tests/integration/task/TestTask.cpp b/tests/src/fsfw_tests/integration/task/TestTask.cpp index 765f780e..a6a4a30b 100644 --- a/tests/src/fsfw_tests/integration/task/TestTask.cpp +++ b/tests/src/fsfw_tests/integration/task/TestTask.cpp @@ -12,7 +12,7 @@ TestTask::TestTask(object_id_t objectId) : SystemObject(objectId), testMode(test IPCStore = ObjectManager::instance()->get(objects::IPC_STORE); } -TestTask::~TestTask() {} +TestTask::~TestTask() = default; ReturnValue_t TestTask::performOperation(uint8_t operationCode) { ReturnValue_t result = RETURN_OK; diff --git a/tests/src/fsfw_tests/integration/task/TestTask.h b/tests/src/fsfw_tests/integration/task/TestTask.h index cd630ee3..038355c3 100644 --- a/tests/src/fsfw_tests/integration/task/TestTask.h +++ b/tests/src/fsfw_tests/integration/task/TestTask.h @@ -13,9 +13,9 @@ */ class TestTask : public SystemObject, public ExecutableObjectIF, public HasReturnvaluesIF { public: - TestTask(object_id_t objectId); - virtual ~TestTask(); - virtual ReturnValue_t performOperation(uint8_t operationCode = 0) override; + explicit TestTask(object_id_t objectId); + ~TestTask() override; + ReturnValue_t performOperation(uint8_t operationCode) override; protected: virtual ReturnValue_t performOneShotAction(); diff --git a/tests/src/fsfw_tests/unit/internalerror/TestInternalErrorReporter.cpp b/tests/src/fsfw_tests/unit/internalerror/TestInternalErrorReporter.cpp index 92c3ff22..a993fff6 100644 --- a/tests/src/fsfw_tests/unit/internalerror/TestInternalErrorReporter.cpp +++ b/tests/src/fsfw_tests/unit/internalerror/TestInternalErrorReporter.cpp @@ -16,7 +16,7 @@ #include "fsfw_tests/unit/mocks/PeriodicTaskIFMock.h" TEST_CASE("Internal Error Reporter", "[TestInternalError]") { - PeriodicTaskMock task(10); + PeriodicTaskMock task(10, nullptr); ObjectManagerIF* manager = ObjectManager::instance(); if (manager == nullptr) { FAIL(); @@ -27,6 +27,8 @@ TEST_CASE("Internal Error Reporter", "[TestInternalError]") { FAIL(); } task.addComponent(objects::INTERNAL_ERROR_REPORTER); + // This calls the initializeAfterTaskCreation function + task.startTask(); MessageQueueIF* testQueue = QueueFactory::instance()->createMessageQueue(1); MessageQueueIF* hkQueue = QueueFactory::instance()->createMessageQueue(1); internalErrorReporter->getSubscriptionInterface()->subscribeForSetUpdateMessage( @@ -115,4 +117,4 @@ TEST_CASE("Internal Error Reporter", "[TestInternalError]") { } QueueFactory::instance()->deleteMessageQueue(testQueue); QueueFactory::instance()->deleteMessageQueue(hkQueue); -} \ No newline at end of file +} diff --git a/tests/src/fsfw_tests/unit/mocks/PeriodicTaskIFMock.h b/tests/src/fsfw_tests/unit/mocks/PeriodicTaskIFMock.h index ebd9a2e7..dc0ccefc 100644 --- a/tests/src/fsfw_tests/unit/mocks/PeriodicTaskIFMock.h +++ b/tests/src/fsfw_tests/unit/mocks/PeriodicTaskIFMock.h @@ -2,36 +2,24 @@ #define FSFW_UNITTEST_TESTS_MOCKS_PERIODICTASKMOCK_H_ #include -#include +#include -class PeriodicTaskMock : public PeriodicTaskIF { +class PeriodicTaskMock : public PeriodicTaskBase { public: - PeriodicTaskMock(uint32_t period = 5) : period(period) {} - /** - * @brief A virtual destructor as it is mandatory for interfaces. - */ + PeriodicTaskMock(TaskPeriod period, TaskDeadlineMissedFunction dlmFunc) + : PeriodicTaskBase(period, dlmFunc) {} + virtual ~PeriodicTaskMock() {} /** * @brief With the startTask method, a created task can be started * for the first time. */ - virtual ReturnValue_t startTask() override { return HasReturnvaluesIF::RETURN_OK; }; - - virtual ReturnValue_t addComponent(object_id_t object) override { - ExecutableObjectIF* executableObject = - ObjectManager::instance()->get(objects::INTERNAL_ERROR_REPORTER); - if (executableObject == nullptr) { - return HasReturnvaluesIF::RETURN_FAILED; - } - executableObject->setTaskIF(this); - executableObject->initializeAfterTaskCreation(); + virtual ReturnValue_t startTask() override { + initObjsAfterTaskCreation(); return HasReturnvaluesIF::RETURN_OK; }; virtual ReturnValue_t sleepFor(uint32_t ms) override { return HasReturnvaluesIF::RETURN_OK; }; - - virtual uint32_t getPeriodMs() const override { return period; }; - uint32_t period; }; -#endif // FSFW_UNITTEST_TESTS_MOCKS_PERIODICTASKMOCK_H_ \ No newline at end of file +#endif // FSFW_UNITTEST_TESTS_MOCKS_PERIODICTASKMOCK_H_