Merge pull request 'Task IF refactoring' (#636) from mueller/task-if-refactoring into development

Reviewed-on: fsfw/fsfw#636
This commit is contained in:
Steffen Gaisser 2022-06-20 16:08:03 +02:00
commit c3aaab4b93
46 changed files with 583 additions and 799 deletions

View File

@ -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 the message queue. Also streamlined and simplified `MessageQueue` implementation for all OSALs
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/583 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
- HAL Linux Uart: Baudrate and bits per word are enums now, avoiding misconfigurations - HAL Linux Uart: Baudrate and bits per word are enums now, avoiding misconfigurations

View File

@ -185,7 +185,7 @@ endif()
message(STATUS "${MSG_PREFIX} Finding and/or providing ETL library") message(STATUS "${MSG_PREFIX} Finding and/or providing ETL library")
# Check whether the user has already installed ETL first # 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 # Not installed, so use FetchContent to download and provide etl
if(NOT ${FSFW_ETL_LIB_NAME}_FOUND) if(NOT ${FSFW_ETL_LIB_NAME}_FOUND)
message( message(

View File

@ -10,6 +10,10 @@
#include "stm32h7xx_hal.h" #include "stm32h7xx_hal.h"
#include "stm32h7xx_hal_spi.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 }; enum class TransferStates { IDLE, WAIT, SUCCESS, FAILURE };
class GyroL3GD20H { class GyroL3GD20H {

View File

@ -1,27 +1,23 @@
#include "fsfw/osal/freertos/FixedTimeslotTask.h" #include "fsfw/osal/freertos/FixedTimeslotTask.h"
#include "fsfw/objectmanager/ObjectManager.h" #include "fsfw/serviceinterface.h"
#include "fsfw/serviceinterface/ServiceInterface.h"
uint32_t FixedTimeslotTask::deadlineMissedCount = 0;
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = configMINIMAL_STACK_SIZE; const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = configMINIMAL_STACK_SIZE;
FixedTimeslotTask::FixedTimeslotTask(TaskName name, TaskPriority setPriority, FixedTimeslotTask::FixedTimeslotTask(TaskName name, TaskPriority setPriority,
TaskStackSize setStack, TaskPeriod overallPeriod, TaskStackSize setStack, TaskPeriod period,
void (*setDeadlineMissedFunc)()) TaskDeadlineMissedFunction dlmFunc_)
: started(false), handle(nullptr), pst(overallPeriod * 1000) { : FixedTimeslotTaskBase(period, dlmFunc_), started(false), handle(nullptr) {
configSTACK_DEPTH_TYPE stackSize = setStack / sizeof(configSTACK_DEPTH_TYPE); configSTACK_DEPTH_TYPE stackSize = setStack / sizeof(configSTACK_DEPTH_TYPE);
xTaskCreate(taskEntryPoint, name, stackSize, this, setPriority, &handle); 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) { void FixedTimeslotTask::taskEntryPoint(void* argument) {
// The argument is re-interpreted as FixedTimeslotTask. The Task object is // The argument is re-interpreted as FixedTimeslotTask. The Task object is
// global, so it is found from any place. // global, so it is found from any place.
FixedTimeslotTask* originalTask(reinterpret_cast<FixedTimeslotTask*>(argument)); auto* originalTask(reinterpret_cast<FixedTimeslotTask*>(argument));
/* Task should not start until explicitly requested, /* Task should not start until explicitly requested,
* but in FreeRTOS, tasks start as soon as they are created if the scheduler * but in FreeRTOS, tasks start as soon as they are created if the scheduler
* is running but not if the scheduler is not running. * is running but not if the scheduler is not running.
@ -32,26 +28,18 @@ void FixedTimeslotTask::taskEntryPoint(void* argument) {
* can continue */ * can continue */
if (not originalTask->started) { if (not originalTask->started) {
vTaskSuspend(NULL); vTaskSuspend(nullptr);
} }
originalTask->taskFunctionality(); originalTask->taskFunctionality();
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "Polling task " << originalTask->handle << " returned from taskFunctionality." sif::debug << "Polling task " << originalTask->handle << " returned from taskFunctionality."
<< std::endl; << std::endl;
#else
sif::printDebug("Polling task returned from taskFunctionality\n");
#endif #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() { ReturnValue_t FixedTimeslotTask::startTask() {
started = true; started = true;
@ -63,31 +51,12 @@ ReturnValue_t FixedTimeslotTask::startTask() {
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, uint32_t slotTimeMs, [[noreturn]] void FixedTimeslotTask::taskFunctionality() {
int8_t executionStep) {
ExecutableObjectIF* handler = ObjectManager::instance()->get<ExecutableObjectIF>(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() {
// A local iterator for the Polling Sequence Table is created to find the // A local iterator for the Polling Sequence Table is created to find the
// start time for the first entry. // 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. // The start time for the first entry is read.
uint32_t intervalMs = slotListIter->pollingTimeMs; uint32_t intervalMs = slotListIter->pollingTimeMs;
@ -108,10 +77,10 @@ void FixedTimeslotTask::taskFunctionality() {
/* Enter the loop that defines the task behavior. */ /* Enter the loop that defines the task behavior. */
for (;;) { for (;;) {
// The component for this slot is executed and the next one is chosen. // The component for this slot is executed and the next one is chosen.
this->pst.executeAndAdvance(); this->pollingSeqTable.executeAndAdvance();
if (not pst.slotFollowsImmediately()) { if (not pollingSeqTable.slotFollowsImmediately()) {
// Get the interval till execution of the next slot. // Get the interval till execution of the next slot.
intervalMs = this->pst.getIntervalToPreviousSlotMs(); intervalMs = this->pollingSeqTable.getIntervalToPreviousSlotMs();
interval = pdMS_TO_TICKS(intervalMs); interval = pdMS_TO_TICKS(intervalMs);
#if (tskKERNEL_VERSION_MAJOR == 10 && tskKERNEL_VERSION_MINOR >= 4) || tskKERNEL_VERSION_MAJOR > 10 #if (tskKERNEL_VERSION_MAJOR == 10 && tskKERNEL_VERSION_MINOR >= 4) || tskKERNEL_VERSION_MAJOR > 10
@ -132,8 +101,8 @@ void FixedTimeslotTask::taskFunctionality() {
} }
void FixedTimeslotTask::handleMissedDeadline() { void FixedTimeslotTask::handleMissedDeadline() {
if (deadlineMissedFunc != nullptr) { if (dlmFunc != nullptr) {
this->deadlineMissedFunc(); dlmFunc();
} }
} }

View File

@ -4,11 +4,11 @@
#include "FreeRTOS.h" #include "FreeRTOS.h"
#include "FreeRTOSTaskIF.h" #include "FreeRTOSTaskIF.h"
#include "fsfw/tasks/FixedSlotSequence.h" #include "fsfw/tasks/FixedSlotSequence.h"
#include "fsfw/tasks/FixedTimeslotTaskIF.h" #include "fsfw/tasks/FixedTimeslotTaskBase.h"
#include "fsfw/tasks/Typedef.h" #include "fsfw/tasks/definitions.h"
#include "task.h" #include "task.h"
class FixedTimeslotTask : public FixedTimeslotTaskIF, public FreeRTOSTaskIF { class FixedTimeslotTask : public FixedTimeslotTaskBase, public FreeRTOSTaskIF {
public: public:
/** /**
* Keep in mind that you need to call before vTaskStartScheduler()! * 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. * @return Pointer to the newly created task.
*/ */
FixedTimeslotTask(TaskName name, TaskPriority setPriority, TaskStackSize setStack, FixedTimeslotTask(TaskName name, TaskPriority setPriority, TaskStackSize setStack,
TaskPeriod overallPeriod, void (*setDeadlineMissedFunc)()); TaskPeriod overallPeriod, TaskDeadlineMissedFunction dlmFunc);
/** /**
* @brief The destructor of the class. * @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 * initialization for the PST and the device handlers. This is done by
* calling the PST's destructor. * calling the PST's destructor.
*/ */
virtual ~FixedTimeslotTask(void); ~FixedTimeslotTask() override;
ReturnValue_t startTask(void); ReturnValue_t startTask() override;
/**
* 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 sleepFor(uint32_t ms) override; ReturnValue_t sleepFor(uint32_t ms) override;
@ -61,17 +44,6 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF, public FreeRTOSTaskIF {
bool started; bool started;
TaskHandle_t handle; 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. * @brief This is the entry point for a new task.
* @details * @details
@ -88,7 +60,7 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF, public FreeRTOSTaskIF {
* It links the functionalities provided by FixedSlotSequence with the * It links the functionalities provided by FixedSlotSequence with the
* OS's System Calls to keep the timing of the periods. * OS's System Calls to keep the timing of the periods.
*/ */
void taskFunctionality(void); [[noreturn]] void taskFunctionality();
void handleMissedDeadline(); void handleMissedDeadline();
}; };

View File

@ -6,11 +6,11 @@
class FreeRTOSTaskIF { class FreeRTOSTaskIF {
public: public:
virtual ~FreeRTOSTaskIF() {} virtual ~FreeRTOSTaskIF() = default;
virtual TaskHandle_t getTaskHandle() = 0; virtual TaskHandle_t getTaskHandle() = 0;
protected: 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 /* Check whether deadline was missed while also taking overflows
* into account. Drawing this on paper with a timeline helps to understand * into account. Drawing this on paper with a timeline helps to understand
* it. */ * it. */

View File

@ -5,27 +5,28 @@
#include "fsfw/tasks/ExecutableObjectIF.h" #include "fsfw/tasks/ExecutableObjectIF.h"
PeriodicTask::PeriodicTask(const char* name, TaskPriority setPriority, TaskStackSize setStack, PeriodicTask::PeriodicTask(const char* name, TaskPriority setPriority, TaskStackSize setStack,
TaskPeriod setPeriod, TaskDeadlineMissedFunction deadlineMissedFunc) TaskPeriod setPeriod, TaskDeadlineMissedFunction dlmFunc_)
: started(false), handle(NULL), period(setPeriod), deadlineMissedFunc(deadlineMissedFunc) { : PeriodicTaskBase(setPeriod, dlmFunc_), started(false), handle(nullptr) {
configSTACK_DEPTH_TYPE stackSize = setStack / sizeof(configSTACK_DEPTH_TYPE); configSTACK_DEPTH_TYPE stackSize = setStack / sizeof(configSTACK_DEPTH_TYPE);
BaseType_t status = xTaskCreate(taskEntryPoint, name, stackSize, this, setPriority, &handle); BaseType_t status = xTaskCreate(taskEntryPoint, name, stackSize, this, setPriority, &handle);
if (status != pdPASS) { if (status != pdPASS) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "PeriodicTask Insufficient heap memory remaining. " sif::debug << "PeriodicTask::PeriodicTask Insufficient heap memory remaining. Status: "
"Status: "
<< status << std::endl; << status << std::endl;
#else
sif::printDebug("PeriodicTask::PeriodicTask: Insufficient heap memory remaining. Status: %d\n",
status);
#endif #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) { void PeriodicTask::taskEntryPoint(void* argument) {
// The argument is re-interpreted as PeriodicTask. The Task object is // The argument is re-interpreted as PeriodicTask. The Task object is
// global, so it is found from any place. // global, so it is found from any place.
PeriodicTask* originalTask(reinterpret_cast<PeriodicTask*>(argument)); auto* originalTask(reinterpret_cast<PeriodicTask*>(argument));
/* Task should not start until explicitly requested, /* Task should not start until explicitly requested,
* but in FreeRTOS, tasks start as soon as they are created if the scheduler * but in FreeRTOS, tasks start as soon as they are created if the scheduler
* is running but not if the scheduler is not running. * is running but not if the scheduler is not running.
@ -36,7 +37,7 @@ void PeriodicTask::taskEntryPoint(void* argument) {
* can continue */ * can continue */
if (not originalTask->started) { if (not originalTask->started) {
vTaskSuspend(NULL); vTaskSuspend(nullptr);
} }
originalTask->taskFunctionality(); originalTask->taskFunctionality();
@ -62,13 +63,11 @@ ReturnValue_t PeriodicTask::sleepFor(uint32_t ms) {
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
void PeriodicTask::taskFunctionality() { [[noreturn]] void PeriodicTask::taskFunctionality() {
TickType_t xLastWakeTime; TickType_t xLastWakeTime;
const TickType_t xPeriod = pdMS_TO_TICKS(this->period * 1000.); const TickType_t xPeriod = pdMS_TO_TICKS(this->period * 1000.);
for (auto const& object : objectList) { initObjsAfterTaskCreation();
object->initializeAfterTaskCreation();
}
/* The xLastWakeTime variable needs to be initialized with the current tick /* The xLastWakeTime variable needs to be initialized with the current tick
count. Note that this is the only time the variable is written to count. Note that this is the only time the variable is written to
@ -77,8 +76,8 @@ void PeriodicTask::taskFunctionality() {
xLastWakeTime = xTaskGetTickCount(); xLastWakeTime = xTaskGetTickCount();
/* Enter the loop that defines the task behavior. */ /* Enter the loop that defines the task behavior. */
for (;;) { for (;;) {
for (auto const& object : objectList) { for (auto const& objectPair : objectList) {
object->performOperation(); objectPair.first->performOperation(objectPair.second);
} }
#if (tskKERNEL_VERSION_MAJOR == 10 && tskKERNEL_VERSION_MINOR >= 4) || tskKERNEL_VERSION_MAJOR > 10 #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<ExecutableObjectIF>(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; } TaskHandle_t PeriodicTask::getTaskHandle() { return handle; }
void PeriodicTask::handleMissedDeadline() { void PeriodicTask::handleMissedDeadline() {
if (deadlineMissedFunc != nullptr) { if (dlmFunc != nullptr) {
this->deadlineMissedFunc(); dlmFunc();
} }
} }

View File

@ -6,8 +6,8 @@
#include "FreeRTOS.h" #include "FreeRTOS.h"
#include "FreeRTOSTaskIF.h" #include "FreeRTOSTaskIF.h"
#include "fsfw/objectmanager/ObjectManagerIF.h" #include "fsfw/objectmanager/ObjectManagerIF.h"
#include "fsfw/tasks/PeriodicTaskIF.h" #include "fsfw/tasks/PeriodicTaskBase.h"
#include "fsfw/tasks/Typedef.h" #include "fsfw/tasks/definitions.h"
#include "task.h" #include "task.h"
class ExecutableObjectIF; class ExecutableObjectIF;
@ -17,7 +17,7 @@ class ExecutableObjectIF;
* periodic activities of multiple objects. * periodic activities of multiple objects.
* @ingroup task_handling * @ingroup task_handling
*/ */
class PeriodicTask : public PeriodicTaskIF, public FreeRTOSTaskIF { class PeriodicTask : public PeriodicTaskBase, public FreeRTOSTaskIF {
public: public:
/** /**
* Keep in Mind that you need to call before this vTaskStartScheduler()! * Keep in Mind that you need to call before this vTaskStartScheduler()!
@ -43,7 +43,7 @@ class PeriodicTask : public PeriodicTaskIF, public FreeRTOSTaskIF {
* @brief Currently, the executed object's lifetime is not coupled with * @brief Currently, the executed object's lifetime is not coupled with
* the task object's lifetime, so the destructor is empty. * the task object's lifetime, so the destructor is empty.
*/ */
virtual ~PeriodicTask(void); ~PeriodicTask() override;
/** /**
* @brief The method to start the task. * @brief The method to start the task.
@ -53,27 +53,6 @@ class PeriodicTask : public PeriodicTaskIF, public FreeRTOSTaskIF {
* to the system call. * to the system call.
*/ */
ReturnValue_t startTask() override; ReturnValue_t startTask() override;
/**
* Adds an object to the list of objects to be executed.
* 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; ReturnValue_t sleepFor(uint32_t ms) override;
@ -83,28 +62,6 @@ class PeriodicTask : public PeriodicTaskIF, public FreeRTOSTaskIF {
bool started; bool started;
TaskHandle_t handle; TaskHandle_t handle;
//! Typedef for the List of objects.
typedef std::vector<ExecutableObjectIF*> 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. * @brief This is the function executed in the new task's context.
* @details * @details
@ -125,7 +82,7 @@ class PeriodicTask : public PeriodicTaskIF, public FreeRTOSTaskIF {
* the next period. * the next period.
* On missing the deadline, the deadlineMissedFunction is executed. * On missing the deadline, the deadlineMissedFunction is executed.
*/ */
void taskFunctionality(void); [[noreturn]] void taskFunctionality();
void handleMissedDeadline(); void handleMissedDeadline();
}; };

View File

@ -3,9 +3,7 @@
#include <chrono> #include <chrono>
#include <thread> #include <thread>
#include "fsfw/ipc/MutexFactory.h"
#include "fsfw/objectmanager/ObjectManager.h" #include "fsfw/objectmanager/ObjectManager.h"
#include "fsfw/osal/host/FixedTimeslotTask.h"
#include "fsfw/osal/host/Mutex.h" #include "fsfw/osal/host/Mutex.h"
#include "fsfw/osal/host/taskHelpers.h" #include "fsfw/osal/host/taskHelpers.h"
#include "fsfw/platform.h" #include "fsfw/platform.h"
@ -22,12 +20,8 @@
FixedTimeslotTask::FixedTimeslotTask(const char* name, TaskPriority setPriority, FixedTimeslotTask::FixedTimeslotTask(const char* name, TaskPriority setPriority,
TaskStackSize setStack, TaskPeriod setPeriod, TaskStackSize setStack, TaskPeriod setPeriod,
void (*setDeadlineMissedFunc)()) TaskDeadlineMissedFunction dlmFunc_)
: started(false), : FixedTimeslotTaskBase(setPeriod, dlmFunc_), started(false), taskName(name) {
pollingSeqTable(setPeriod * 1000),
taskName(name),
period(setPeriod),
deadlineMissedFunc(setDeadlineMissedFunc) {
// It is propably possible to set task priorities by using the native // It is propably possible to set task priorities by using the native
// task handles for Windows / Linux // task handles for Windows / Linux
mainThread = std::thread(&FixedTimeslotTask::taskEntryPoint, this, this); mainThread = std::thread(&FixedTimeslotTask::taskEntryPoint, this, this);
@ -39,7 +33,7 @@ FixedTimeslotTask::FixedTimeslotTask(const char* name, TaskPriority setPriority,
tasks::insertTaskName(mainThread.get_id(), taskName); tasks::insertTaskName(mainThread.get_id(), taskName);
} }
FixedTimeslotTask::~FixedTimeslotTask(void) { FixedTimeslotTask::~FixedTimeslotTask() {
// Do not delete objects, we were responsible for ptrs only. // Do not delete objects, we were responsible for ptrs only.
terminateThread = true; terminateThread = true;
if (mainThread.joinable()) { if (mainThread.joinable()) {
@ -48,7 +42,7 @@ FixedTimeslotTask::~FixedTimeslotTask(void) {
} }
void FixedTimeslotTask::taskEntryPoint(void* argument) { void FixedTimeslotTask::taskEntryPoint(void* argument) {
FixedTimeslotTask* originalTask(reinterpret_cast<FixedTimeslotTask*>(argument)); auto* originalTask(reinterpret_cast<FixedTimeslotTask*>(argument));
if (not originalTask->started) { if (not originalTask->started) {
// we have to suspend/block here until the task is 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() { void FixedTimeslotTask::taskFunctionality() {
pollingSeqTable.intializeSequenceAfterTaskCreation(); ReturnValue_t result = pollingSeqTable.intializeSequenceAfterTaskCreation();
// Ignore returnvalue for now
static_cast<void>(result);
// A local iterator for the Polling Sequence Table is created to // A local iterator for the Polling Sequence Table is created to
// find the start time for the first entry. // find the start time for the first entry.
@ -106,37 +102,15 @@ void FixedTimeslotTask::taskFunctionality() {
// we need to wait before executing the current slot // we need to wait before executing the current slot
// this gives us the time to wait: // this gives us the time to wait:
interval = chron_ms(this->pollingSeqTable.getIntervalToPreviousSlotMs()); interval = chron_ms(this->pollingSeqTable.getIntervalToPreviousSlotMs());
delayForInterval(&currentStartTime, interval); if (not delayForInterval(&currentStartTime, interval)) {
// TODO deadline missed check if (dlmFunc != nullptr) {
dlmFunc();
}
}
} }
} }
} }
ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, uint32_t slotTimeMs,
int8_t executionStep) {
ExecutableObjectIF* executableObject =
ObjectManager::instance()->get<ExecutableObjectIF>(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<unsigned int>(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 FixedTimeslotTask::delayForInterval(chron_ms* previousWakeTimeMs, const chron_ms interval) {
bool shouldDelay = false; bool shouldDelay = false;
// Get current wakeup time // Get current wakeup time

View File

@ -6,10 +6,10 @@
#include <thread> #include <thread>
#include <vector> #include <vector>
#include "../../objectmanager/ObjectManagerIF.h" #include "fsfw/objectmanager/ObjectManagerIF.h"
#include "../../tasks/FixedSlotSequence.h" #include "fsfw/tasks/FixedSlotSequence.h"
#include "../../tasks/FixedTimeslotTaskIF.h" #include "fsfw/tasks/FixedTimeslotTaskBase.h"
#include "../../tasks/Typedef.h" #include "fsfw/tasks/definitions.h"
class ExecutableObjectIF; class ExecutableObjectIF;
@ -19,7 +19,7 @@ class ExecutableObjectIF;
* @details * @details
* @ingroup task_handling * @ingroup task_handling
*/ */
class FixedTimeslotTask : public FixedTimeslotTaskIF { class FixedTimeslotTask : public FixedTimeslotTaskBase {
public: public:
/** /**
* @brief Standard constructor of the class. * @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 * @brief Currently, the executed object's lifetime is not coupled with
* the task object's lifetime, so the destructor is empty. * the task object's lifetime, so the destructor is empty.
*/ */
virtual ~FixedTimeslotTask(void); ~FixedTimeslotTask() override;
/** /**
* @brief The method to start the task. * @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 * The address of the task object is passed as an argument
* to the system call. * to the system call.
*/ */
ReturnValue_t startTask(void); ReturnValue_t startTask() override;
/** ReturnValue_t sleepFor(uint32_t ms) 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);
protected: protected:
using chron_ms = std::chrono::milliseconds; using chron_ms = std::chrono::milliseconds;
bool started; bool started;
//!< Typedef for the List of objects.
typedef std::vector<ExecutableObjectIF*> ObjectList;
std::thread mainThread; std::thread mainThread;
std::atomic<bool> terminateThread{false}; std::atomic<bool> 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::condition_variable initCondition;
std::mutex initMutex; std::mutex initMutex;
std::string taskName; 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. * @brief This is the function executed in the new task's context.
* @details * @details
@ -117,9 +83,9 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF {
* the checkAndRestartPeriod system call blocks the task until the next * the checkAndRestartPeriod system call blocks the task until the next
* period. On missing the deadline, the deadlineMissedFunction is executed. * 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_ */ #endif /* FRAMEWORK_OSAL_HOST_FIXEDTIMESLOTTASK_H_ */

View File

@ -3,13 +3,10 @@
#include <chrono> #include <chrono>
#include <thread> #include <thread>
#include "fsfw/ipc/MutexFactory.h"
#include "fsfw/objectmanager/ObjectManager.h"
#include "fsfw/osal/host/Mutex.h" #include "fsfw/osal/host/Mutex.h"
#include "fsfw/osal/host/taskHelpers.h" #include "fsfw/osal/host/taskHelpers.h"
#include "fsfw/platform.h" #include "fsfw/platform.h"
#include "fsfw/serviceinterface/ServiceInterface.h" #include "fsfw/serviceinterface/ServiceInterface.h"
#include "fsfw/tasks/ExecutableObjectIF.h"
#if defined(PLATFORM_WIN) #if defined(PLATFORM_WIN)
#include <processthreadsapi.h> #include <processthreadsapi.h>
@ -20,8 +17,8 @@
#endif #endif
PeriodicTask::PeriodicTask(const char* name, TaskPriority setPriority, TaskStackSize setStack, PeriodicTask::PeriodicTask(const char* name, TaskPriority setPriority, TaskStackSize setStack,
TaskPeriod setPeriod, void (*setDeadlineMissedFunc)()) TaskPeriod setPeriod, TaskDeadlineMissedFunction dlmFunc_)
: started(false), taskName(name), period(setPeriod), deadlineMissedFunc(setDeadlineMissedFunc) { : PeriodicTaskBase(setPeriod, dlmFunc_), started(false), taskName(name) {
// It is probably possible to set task priorities by using the native // It is probably possible to set task priorities by using the native
// task handles for Windows / Linux // task handles for Windows / Linux
mainThread = std::thread(&PeriodicTask::taskEntryPoint, this, this); 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); tasks::insertTaskName(mainThread.get_id(), taskName);
} }
PeriodicTask::~PeriodicTask(void) { PeriodicTask::~PeriodicTask() {
// Do not delete objects, we were responsible for ptrs only. // Do not delete objects, we were responsible for ptrs only.
terminateThread = true; terminateThread = true;
if (mainThread.joinable()) { if (mainThread.joinable()) {
@ -42,7 +39,7 @@ PeriodicTask::~PeriodicTask(void) {
} }
void PeriodicTask::taskEntryPoint(void* argument) { void PeriodicTask::taskEntryPoint(void* argument) {
PeriodicTask* originalTask(reinterpret_cast<PeriodicTask*>(argument)); auto* originalTask(reinterpret_cast<PeriodicTask*>(argument));
if (not originalTask->started) { if (not originalTask->started) {
// we have to suspend/block here until the task is 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() { void PeriodicTask::taskFunctionality() {
for (const auto& object : objectList) { initObjsAfterTaskCreation();
object->initializeAfterTaskCreation();
}
std::chrono::milliseconds periodChrono(static_cast<uint32_t>(period * 1000)); std::chrono::milliseconds periodChrono(static_cast<uint32_t>(period * 1000));
auto currentStartTime{std::chrono::duration_cast<std::chrono::milliseconds>( auto currentStartTime{std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch())}; std::chrono::system_clock::now().time_since_epoch())};
auto nextStartTime{currentStartTime};
/* Enter the loop that defines the task behavior. */ /* Enter the loop that defines the task behavior. */
for (;;) { for (;;) {
if (terminateThread.load()) { if (terminateThread.load()) {
break; break;
} }
for (const auto& object : objectList) { for (const auto& objectPair : objectList) {
object->performOperation(); objectPair.first->performOperation(objectPair.second);
} }
if (not delayForInterval(&currentStartTime, periodChrono)) { if (not delayForInterval(&currentStartTime, periodChrono)) {
if (deadlineMissedFunc != nullptr) { if (dlmFunc != nullptr) {
this->deadlineMissedFunc(); this->dlmFunc();
} }
} }
} }
} }
ReturnValue_t PeriodicTask::addComponent(object_id_t object) {
ExecutableObjectIF* newObject = ObjectManager::instance()->get<ExecutableObjectIF>(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 PeriodicTask::delayForInterval(chron_ms* previousWakeTimeMs, const chron_ms interval) {
bool shouldDelay = false; bool shouldDelay = false;
// Get current wakeup time // Get current wakeup time

View File

@ -6,9 +6,9 @@
#include <thread> #include <thread>
#include <vector> #include <vector>
#include "../../objectmanager/ObjectManagerIF.h" #include "fsfw/objectmanager/ObjectManagerIF.h"
#include "../../tasks/PeriodicTaskIF.h" #include "fsfw/tasks/PeriodicTaskBase.h"
#include "../../tasks/Typedef.h" #include "fsfw/tasks/definitions.h"
class ExecutableObjectIF; class ExecutableObjectIF;
@ -19,7 +19,7 @@ class ExecutableObjectIF;
* *
* @ingroup task_handling * @ingroup task_handling
*/ */
class PeriodicTask : public PeriodicTaskIF { class PeriodicTask : public PeriodicTaskBase {
public: public:
/** /**
* @brief Standard constructor of the class. * @brief Standard constructor of the class.
@ -34,12 +34,12 @@ class PeriodicTask : public PeriodicTaskIF {
* assigned. * assigned.
*/ */
PeriodicTask(const char* name, TaskPriority setPriority, TaskStackSize setStack, 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 * @brief Currently, the executed object's lifetime is not coupled with
* the task object's lifetime, so the destructor is empty. * the task object's lifetime, so the destructor is empty.
*/ */
virtual ~PeriodicTask(void); ~PeriodicTask() override;
/** /**
* @brief The method to start the task. * @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 * The address of the task object is passed as an argument
* to the system call. * to the system call.
*/ */
ReturnValue_t startTask(void); ReturnValue_t startTask() override;
/**
* Adds an object to the list of objects to be executed.
* The objects are executed in the order added.
* @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 sleepFor(uint32_t ms) 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);
protected: protected:
using chron_ms = std::chrono::milliseconds; using chron_ms = std::chrono::milliseconds;
bool started; bool started;
//!< Typedef for the List of objects.
typedef std::vector<ExecutableObjectIF*> ObjectList;
std::thread mainThread; std::thread mainThread;
std::atomic<bool> terminateThread{false}; std::atomic<bool> terminateThread{false};
/**
* @brief This attribute holds a list of objects to be executed.
*/
ObjectList objectList;
std::condition_variable initCondition; std::condition_variable initCondition;
std::mutex initMutex; std::mutex initMutex;
std::string taskName; 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. * @brief This is the function executed in the new task's context.
* @details * @details
@ -124,9 +81,9 @@ class PeriodicTask : public PeriodicTaskIF {
* the checkAndRestartPeriod system call blocks the task until the next * the checkAndRestartPeriod system call blocks the task until the next
* period. On missing the deadline, the deadlineMissedFunction is executed. * 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_ */

View File

@ -14,9 +14,9 @@ TaskFactory* TaskFactory::factoryInstance = new TaskFactory();
// Not used for the host implementation for now because C++ thread abstraction is used // Not used for the host implementation for now because C++ thread abstraction is used
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = 0; const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = 0;
TaskFactory::TaskFactory() {} TaskFactory::TaskFactory() = default;
TaskFactory::~TaskFactory() {} TaskFactory::~TaskFactory() = default;
TaskFactory* TaskFactory::instance() { return TaskFactory::factoryInstance; } TaskFactory* TaskFactory::instance() { return TaskFactory::factoryInstance; }

View File

@ -6,7 +6,7 @@
std::mutex nameMapLock; std::mutex nameMapLock;
std::map<std::thread::id, std::string> taskNameMap; std::map<std::thread::id, std::string> 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<std::mutex> lg(nameMapLock); std::lock_guard<std::mutex> lg(nameMapLock);
auto returnPair = taskNameMap.emplace(threadId, taskName); auto returnPair = taskNameMap.emplace(threadId, taskName);
if (not returnPair.second) { if (not returnPair.second) {

View File

@ -7,7 +7,7 @@
namespace tasks { 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); std::string getTaskName(std::thread::id threadId);
} // namespace tasks } // namespace tasks

View File

@ -1,22 +1,20 @@
#include "fsfw/osal/linux/FixedTimeslotTask.h" #include "fsfw/osal/linux/FixedTimeslotTask.h"
#include <limits.h> #include <climits>
#include "fsfw/objectmanager/ObjectManager.h"
#include "fsfw/serviceinterface/ServiceInterface.h" #include "fsfw/serviceinterface/ServiceInterface.h"
uint32_t FixedTimeslotTask::deadlineMissedCount = 0;
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = PTHREAD_STACK_MIN; const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = PTHREAD_STACK_MIN;
FixedTimeslotTask::FixedTimeslotTask(const char* name_, int priority_, size_t stackSize_, FixedTimeslotTask::FixedTimeslotTask(const char* name_, TaskPriority priority_, size_t stackSize_,
uint32_t periodMs_) TaskPeriod periodSeconds_, TaskDeadlineMissedFunction dlmFunc_)
: PosixThread(name_, priority_, stackSize_), pst(periodMs_), started(false) {} : FixedTimeslotTaskBase(periodSeconds_, dlmFunc_),
posixThread(name_, priority_, stackSize_),
FixedTimeslotTask::~FixedTimeslotTask() {} started(false) {}
void* FixedTimeslotTask::taskEntryPoint(void* arg) { void* FixedTimeslotTask::taskEntryPoint(void* arg) {
// The argument is re-interpreted as PollingTask. // The argument is re-interpreted as PollingTask.
FixedTimeslotTask* originalTask(reinterpret_cast<FixedTimeslotTask*>(arg)); auto* originalTask(reinterpret_cast<FixedTimeslotTask*>(arg));
// The task's functionality is called. // The task's functionality is called.
originalTask->taskFunctionality(); originalTask->taskFunctionality();
return nullptr; return nullptr;
@ -24,7 +22,7 @@ void* FixedTimeslotTask::taskEntryPoint(void* arg) {
ReturnValue_t FixedTimeslotTask::startTask() { ReturnValue_t FixedTimeslotTask::startTask() {
started = true; started = true;
createTask(&taskEntryPoint, this); posixThread.createTask(&taskEntryPoint, this);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
@ -32,63 +30,36 @@ ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) {
return PosixThread::sleep((uint64_t)ms * 1000000); return PosixThread::sleep((uint64_t)ms * 1000000);
} }
uint32_t FixedTimeslotTask::getPeriodMs() const { return pst.getLengthMs(); } [[noreturn]] void FixedTimeslotTask::taskFunctionality() {
ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, uint32_t slotTimeMs,
int8_t executionStep) {
ExecutableObjectIF* executableObject =
ObjectManager::instance()->get<ExecutableObjectIF>(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() {
// Like FreeRTOS pthreads are running as soon as they are created // Like FreeRTOS pthreads are running as soon as they are created
if (!started) { if (!started) {
suspend(); posixThread.suspend();
} }
pst.intializeSequenceAfterTaskCreation(); // Returnvalue ignored for now
static_cast<void>(pollingSeqTable.intializeSequenceAfterTaskCreation());
// The start time for the first entry is read. // The start time for the first entry is read.
uint64_t lastWakeTime = getCurrentMonotonicTimeMs(); uint64_t lastWakeTime = PosixThread::getCurrentMonotonicTimeMs();
uint64_t interval = pst.getIntervalToNextSlotMs(); uint32_t interval = 0;
// The task's "infinite" inner loop is entered. // The task's "infinite" inner loop is entered.
while (1) { while (true) {
if (pst.slotFollowsImmediately()) { if (pollingSeqTable.slotFollowsImmediately()) {
// Do nothing // Do nothing
} else { } else {
// The interval for the next polling slot is selected. // 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. // The period is checked and restarted with the new interval.
// If the deadline was missed, the deadlineMissedFunc is called. // If the deadline was missed, the deadlineMissedFunc is called.
if (!PosixThread::delayUntil(&lastWakeTime, interval)) { if (!PosixThread::delayUntil(&lastWakeTime, interval)) {
// No time left on timer -> we missed the deadline // 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. // The device handler for this slot is executed and the next one is chosen.
this->pst.executeAndAdvance(); pollingSeqTable.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
} }
} }

View File

@ -3,11 +3,12 @@
#include <pthread.h> #include <pthread.h>
#include "../../tasks/FixedSlotSequence.h"
#include "../../tasks/FixedTimeslotTaskIF.h"
#include "PosixThread.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: public:
/** /**
* Create a generic periodic task. * Create a generic periodic task.
@ -21,29 +22,13 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF, public PosixThread {
* @param period_ * @param period_
* @param deadlineMissedFunc_ * @param deadlineMissedFunc_
*/ */
FixedTimeslotTask(const char* name_, int priority_, size_t stackSize_, uint32_t periodMs_); FixedTimeslotTask(const char* name_, TaskPriority priority_, size_t stackSize_,
virtual ~FixedTimeslotTask(); TaskPeriod periodSeconds_, TaskDeadlineMissedFunction dlmFunc_);
~FixedTimeslotTask() override = default;
virtual ReturnValue_t startTask(); ReturnValue_t startTask() override;
virtual ReturnValue_t sleepFor(uint32_t ms); ReturnValue_t sleepFor(uint32_t ms) override;
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;
protected: protected:
/** /**
@ -53,9 +38,12 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF, public PosixThread {
* It links the functionalities provided by FixedSlotSequence with the * It links the functionalities provided by FixedSlotSequence with the
* OS's System Calls to keep the timing of the periods. * OS's System Calls to keep the timing of the periods.
*/ */
virtual void taskFunctionality(); [[noreturn]] virtual void taskFunctionality();
private: private:
PosixThread posixThread;
bool started;
/** /**
* @brief This is the entry point in a new thread. * @brief This is the entry point in a new thread.
* *
@ -68,9 +56,6 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF, public PosixThread {
* arbitrary data. * arbitrary data.
*/ */
static void* taskEntryPoint(void* arg); static void* taskEntryPoint(void* arg);
FixedSlotSequence pst;
bool started;
}; };
#endif /* FSFW_OSAL_LINUX_FIXEDTIMESLOTTASK_H_ */ #endif /* FSFW_OSAL_LINUX_FIXEDTIMESLOTTASK_H_ */

View File

@ -1,86 +1,54 @@
#include "fsfw/osal/linux/PeriodicPosixTask.h" #include "PeriodicPosixTask.h"
#include <errno.h> #include "fsfw/serviceinterface.h"
#include "fsfw/objectmanager/ObjectManager.h"
#include "fsfw/serviceinterface/ServiceInterface.h"
#include "fsfw/tasks/ExecutableObjectIF.h" #include "fsfw/tasks/ExecutableObjectIF.h"
PeriodicPosixTask::PeriodicPosixTask(const char* name_, int priority_, size_t stackSize_, PeriodicPosixTask::PeriodicPosixTask(const char* name_, int priority_, size_t stackSize_,
uint32_t period_, void(deadlineMissedFunc_)()) TaskPeriod period_, TaskDeadlineMissedFunction dlmFunc_)
: PosixThread(name_, priority_, stackSize_), : PeriodicTaskBase(period_, dlmFunc_),
objectList(), posixThread(name_, priority_, stackSize_),
started(false), started(false) {}
periodMs(period_),
deadlineMissedFunc(deadlineMissedFunc_) {}
PeriodicPosixTask::~PeriodicPosixTask() {
// Not Implemented
}
void* PeriodicPosixTask::taskEntryPoint(void* arg) { void* PeriodicPosixTask::taskEntryPoint(void* arg) {
// The argument is re-interpreted as PollingTask. // The argument is re-interpreted as PollingTask.
PeriodicPosixTask* originalTask(reinterpret_cast<PeriodicPosixTask*>(arg)); auto* originalTask(reinterpret_cast<PeriodicPosixTask*>(arg));
// The task's functionality is called. // The task's functionality is called.
originalTask->taskFunctionality(); originalTask->taskFunctionality();
return NULL; return nullptr;
}
ReturnValue_t PeriodicPosixTask::addComponent(object_id_t object) {
ExecutableObjectIF* newObject = ObjectManager::instance()->get<ExecutableObjectIF>(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;
} }
ReturnValue_t PeriodicPosixTask::sleepFor(uint32_t ms) { ReturnValue_t PeriodicPosixTask::sleepFor(uint32_t ms) {
return PosixThread::sleep((uint64_t)ms * 1000000); return PosixThread::sleep(static_cast<uint64_t>(ms) * 1000000);
} }
ReturnValue_t PeriodicPosixTask::startTask(void) { ReturnValue_t PeriodicPosixTask::startTask() {
if (isEmpty()) {
return HasReturnvaluesIF::RETURN_FAILED;
}
started = true; started = true;
PosixThread::createTask(&taskEntryPoint, this); posixThread.createTask(&taskEntryPoint, this);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
void PeriodicPosixTask::taskFunctionality(void) { [[noreturn]] void PeriodicPosixTask::taskFunctionality() {
if (not started) { if (not started) {
suspend(); posixThread.suspend();
} }
for (auto const& object : objectList) { initObjsAfterTaskCreation();
object->initializeAfterTaskCreation();
}
uint64_t lastWakeTime = getCurrentMonotonicTimeMs(); uint64_t lastWakeTime = PosixThread::getCurrentMonotonicTimeMs();
uint64_t periodMs = getPeriodMs();
// The task's "infinite" inner loop is entered. // The task's "infinite" inner loop is entered.
while (1) { while (true) {
for (auto const& object : objectList) { for (auto const& objOpCodePair : objectList) {
object->performOperation(); objOpCodePair.first->performOperation(objOpCodePair.second);
} }
if (not PosixThread::delayUntil(&lastWakeTime, periodMs)) { if (not PosixThread::delayUntil(&lastWakeTime, periodMs)) {
if (this->deadlineMissedFunc != nullptr) { if (dlmFunc != nullptr) {
this->deadlineMissedFunc(); dlmFunc();
} }
} }
} }
} }
uint32_t PeriodicPosixTask::getPeriodMs() const { return periodMs; }

View File

@ -3,12 +3,13 @@
#include <vector> #include <vector>
#include "../../objectmanager/ObjectManagerIF.h"
#include "../../tasks/ExecutableObjectIF.h"
#include "../../tasks/PeriodicTaskIF.h"
#include "PosixThread.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: public:
/** /**
* Create a generic periodic task. * Create a generic periodic task.
@ -22,9 +23,9 @@ class PeriodicPosixTask : public PosixThread, public PeriodicTaskIF {
* @param period_ * @param period_
* @param deadlineMissedFunc_ * @param deadlineMissedFunc_
*/ */
PeriodicPosixTask(const char* name_, int priority_, size_t stackSize_, uint32_t period_, PeriodicPosixTask(const char* name_, int priority_, size_t stackSize_, TaskPeriod period_,
void (*deadlineMissedFunc_)()); TaskDeadlineMissedFunction dlmFunc_);
virtual ~PeriodicPosixTask(); ~PeriodicPosixTask() override = default;
/** /**
* @brief The method to start the task. * @brief The method to start the task.
@ -34,42 +35,17 @@ class PeriodicPosixTask : public PosixThread, public PeriodicTaskIF {
* to the system call. * to the system call.
*/ */
ReturnValue_t startTask() override; ReturnValue_t startTask() override;
/**
* Adds an object to the list of objects to be executed.
* 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; ReturnValue_t sleepFor(uint32_t ms) override;
private: private:
typedef std::vector<ExecutableObjectIF*> ObjectList; //!< Typedef for the List of objects. PosixThread posixThread;
/**
* @brief This attribute holds a list of objects to be executed.
*/
ObjectList objectList;
/** /**
* @brief Flag to indicate that the task was started and is allowed to run * @brief Flag to indicate that the task was started and is allowed to run
*/ */
bool started; bool started;
/**
* @brief Period of the task in milliseconds
*/
uint32_t periodMs;
/** /**
* @brief The function containing the actual functionality of the task. * @brief The function containing the actual functionality of the task.
* @details The method sets and starts * @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 * will be blocked until the next period. On missing the deadline, the deadlineMissedFunction is
* executed. * executed.
*/ */
virtual void taskFunctionality(void); [[noreturn]] virtual void taskFunctionality();
/** /**
* @brief This is the entry point in a new thread. * @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. * of the child class. Needs a valid pointer to the derived class.
*/ */
static void* taskEntryPoint(void* arg); 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_ */ #endif /* FRAMEWORK_OSAL_LINUX_PERIODICPOSIXTASK_H_ */

View File

@ -35,6 +35,21 @@ class PosixThread {
*/ */
void resume(); 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 * Delay function similar to FreeRtos delayUntil function
* *
@ -55,21 +70,6 @@ class PosixThread {
protected: protected:
pthread_t thread; 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: private:
char name[PTHREAD_MAX_NAMELEN]; char name[PTHREAD_MAX_NAMELEN];
int priority; int priority;

View File

@ -8,21 +8,22 @@
// TODO: Different variant than the lazy loading in QueueFactory. What's better and why? // TODO: Different variant than the lazy loading in QueueFactory. What's better and why?
TaskFactory* TaskFactory::factoryInstance = new TaskFactory(); TaskFactory* TaskFactory::factoryInstance = new TaskFactory();
TaskFactory::~TaskFactory() {} TaskFactory::~TaskFactory() = default;
TaskFactory* TaskFactory::instance() { return TaskFactory::factoryInstance; } TaskFactory* TaskFactory::instance() { return TaskFactory::factoryInstance; }
PeriodicTaskIF* TaskFactory::createPeriodicTask( PeriodicTaskIF* TaskFactory::createPeriodicTask(
TaskName name_, TaskPriority taskPriority_, TaskStackSize stackSize_, TaskName name_, TaskPriority taskPriority_, TaskStackSize stackSize_,
TaskPeriod periodInSeconds_, TaskDeadlineMissedFunction deadLineMissedFunction_) { TaskPeriod periodInSeconds_, TaskDeadlineMissedFunction deadLineMissedFunction_) {
return new PeriodicPosixTask(name_, taskPriority_, stackSize_, periodInSeconds_ * 1000, return new PeriodicPosixTask(name_, taskPriority_, stackSize_, periodInSeconds_,
deadLineMissedFunction_); deadLineMissedFunction_);
} }
FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask( FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask(
TaskName name_, TaskPriority taskPriority_, TaskStackSize stackSize_, TaskName name_, TaskPriority taskPriority_, TaskStackSize stackSize_,
TaskPeriod periodInSeconds_, TaskDeadlineMissedFunction deadLineMissedFunction_) { 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) { ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) {

View File

@ -1,42 +1,32 @@
#include "fsfw/osal/rtems/FixedTimeslotTask.h" #include "fsfw/osal/rtems/FixedTimeslotTask.h"
#include <rtems/bspIo.h>
#include <rtems/io.h> #include <rtems/io.h>
#include <rtems/rtems/ratemon.h>
#include <rtems/rtems/status.h> #include <rtems/rtems/status.h>
#include <rtems/rtems/tasks.h> #include <rtems/rtems/tasks.h>
#include <rtems/rtems/types.h> #include <rtems/rtems/types.h>
#include <sys/_stdint.h>
#include "fsfw/objectmanager/ObjectManager.h"
#include "fsfw/objectmanager/SystemObjectIF.h"
#include "fsfw/osal/rtems/RtemsBasic.h" #include "fsfw/osal/rtems/RtemsBasic.h"
#include "fsfw/returnvalues/HasReturnvaluesIF.h" #include "fsfw/returnvalues/HasReturnvaluesIF.h"
#include "fsfw/serviceinterface/ServiceInterface.h" #include "fsfw/serviceinterface/ServiceInterface.h"
#include "fsfw/tasks/FixedSequenceSlot.h"
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
#include <iostream> #include <iostream>
#endif #endif
#include <cstddef> #include <cstddef>
#include <list>
uint32_t FixedTimeslotTask::deadlineMissedCount = 0;
FixedTimeslotTask::FixedTimeslotTask(const char *name, rtems_task_priority setPriority, FixedTimeslotTask::FixedTimeslotTask(const char *name, rtems_task_priority setPriority,
size_t setStack, uint32_t setOverallPeriod, size_t setStack, TaskPeriod setOverallPeriod,
void (*setDeadlineMissedFunc)(void)) TaskDeadlineMissedFunction dlmFunc_)
: RTEMSTaskBase(setPriority, setStack, name), periodId(0), pst(setOverallPeriod) { : FixedTimeslotTaskBase(setOverallPeriod, dlmFunc_),
// All additional attributes are applied to the object. RTEMSTaskBase(setPriority, setStack, name),
this->deadlineMissedFunc = setDeadlineMissedFunc; periodId(0) {}
}
FixedTimeslotTask::~FixedTimeslotTask() {} FixedTimeslotTask::~FixedTimeslotTask() = default;
rtems_task FixedTimeslotTask::taskEntryPoint(rtems_task_argument argument) { rtems_task FixedTimeslotTask::taskEntryPoint(rtems_task_argument argument) {
/* The argument is re-interpreted as a FixedTimeslotTask */ /* The argument is re-interpreted as a FixedTimeslotTask */
FixedTimeslotTask *originalTask(reinterpret_cast<FixedTimeslotTask *>(argument)); auto *originalTask(reinterpret_cast<FixedTimeslotTask *>(argument));
/* The task's functionality is called. */ /* The task's functionality is called. */
return originalTask->taskFunctionality(); return originalTask->taskFunctionality();
/* Should never be reached */ /* Should never be reached */
@ -46,16 +36,6 @@ rtems_task FixedTimeslotTask::taskEntryPoint(rtems_task_argument argument) {
#endif #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() { ReturnValue_t FixedTimeslotTask::startTask() {
rtems_status_code status = rtems_status_code status =
rtems_task_start(id, FixedTimeslotTask::taskEntryPoint, rtems_task_argument((void *)this)); 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, [[noreturn]] void FixedTimeslotTask::taskFunctionality() {
int8_t executionStep) {
ExecutableObjectIF *object = ObjectManager::instance()->get<ExecutableObjectIF>(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() {
/* A local iterator for the Polling Sequence Table is created to find the start time for /* A local iterator for the Polling Sequence Table is created to find the start time for
the first entry. */ the first entry. */
FixedSlotSequence::SlotListIter it = pst.current; auto it = pollingSeqTable.current;
/* Initialize the PST with the correct calling task */ /* Initialize the PST with the correct calling task */
pst.intializeSequenceAfterTaskCreation(); pollingSeqTable.intializeSequenceAfterTaskCreation();
/* The start time for the first entry is read. */ /* The start time for the first entry is read. */
rtems_interval interval = RtemsBasic::convertMsToTicks(it->pollingTimeMs); rtems_interval interval = RtemsBasic::convertMsToTicks(it->pollingTimeMs);
RTEMSTaskBase::setAndStartPeriod(interval, &periodId); RTEMSTaskBase::setAndStartPeriod(interval, &periodId);
// The task's "infinite" inner loop is entered. // The task's "infinite" inner loop is entered.
while (1) { while (true) {
if (pst.slotFollowsImmediately()) { if (pollingSeqTable.slotFollowsImmediately()) {
/* Do nothing */ /* Do nothing */
} else { } else {
/* The interval for the next polling slot is selected. */ /* 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. /* The period is checked and restarted with the new interval.
If the deadline was missed, the deadlineMissedFunc is called. */ If the deadline was missed, the deadlineMissedFunc is called. */
rtems_status_code status = RTEMSTaskBase::restartPeriod(interval, periodId); rtems_status_code status = RTEMSTaskBase::restartPeriod(interval, periodId);
if (status == RTEMS_TIMEOUT) { if (status == RTEMS_TIMEOUT) {
if (this->deadlineMissedFunc != nullptr) { if (dlmFunc != nullptr) {
this->deadlineMissedFunc(); dlmFunc();
} }
} }
} }
/* The device handler for this slot is executed and the next one is chosen. */ /* The device handler for this slot is executed and the next one is chosen. */
this->pst.executeAndAdvance(); this->pollingSeqTable.executeAndAdvance();
} }
} }

View File

@ -1,11 +1,11 @@
#ifndef FSFW_OSAL_RTEMS_FIXEDTIMESLOTTASK_H_ #ifndef FSFW_OSAL_RTEMS_FIXEDTIMESLOTTASK_H_
#define FSFW_OSAL_RTEMS_FIXEDTIMESLOTTASK_H_ #define FSFW_OSAL_RTEMS_FIXEDTIMESLOTTASK_H_
#include "../../tasks/FixedSlotSequence.h"
#include "../../tasks/FixedTimeslotTaskIF.h"
#include "RTEMSTaskBase.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: public:
/** /**
* @brief The standard constructor of the class. * @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. * @param getPst The object id of the completely initialized polling sequence.
*/ */
FixedTimeslotTask(const char *name, rtems_task_priority setPriority, size_t setStackSize, 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. * @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 * 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. * for the PST andthe device handlers. This is done by calling the PST's destructor.
*/ */
virtual ~FixedTimeslotTask(void); ~FixedTimeslotTask() override;
ReturnValue_t startTask(void); 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); ReturnValue_t sleepFor(uint32_t ms) override;
uint32_t getPeriodMs() const;
ReturnValue_t checkSequence() const;
ReturnValue_t sleepFor(uint32_t ms);
protected: protected:
/** /**
* @brief id of the associated OS period * @brief id of the associated OS period
*/ */
rtems_id periodId; 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. * @brief This is the entry point in a new polling thread.
* @details This method is the entry point in the new 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 * It links the functionalities provided by FixedSlotSequence with the OS's system calls to
* keep the timing of the periods. * keep the timing of the periods.
*/ */
void taskFunctionality(void); [[noreturn]] void taskFunctionality();
}; };
#endif /* FSFW_OSAL_RTEMS_FIXEDTIMESLOTTASK_H_ */ #endif /* FSFW_OSAL_RTEMS_FIXEDTIMESLOTTASK_H_ */

View File

@ -59,8 +59,8 @@ class MessageQueue : public MessageQueueBase {
private: private:
/** /**
* \brief This attribute stores a reference to the internal error reporter for reporting full * @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 * queues. @details In the event of a full destination queue, the reporter will be notified. The
* reference is set by lazy loading * reference is set by lazy loading
*/ */
InternalErrorReporterIF* internalErrorReporter; InternalErrorReporterIF* internalErrorReporter;

View File

@ -5,12 +5,12 @@
#include "fsfw/tasks/ExecutableObjectIF.h" #include "fsfw/tasks/ExecutableObjectIF.h"
PeriodicTask::PeriodicTask(const char* name, rtems_task_priority setPriority, size_t setStack, PeriodicTask::PeriodicTask(const char* name, rtems_task_priority setPriority, size_t setStack,
rtems_interval setPeriod, void (*setDeadlineMissedFunc)()) TaskPeriod setPeriod, TaskDeadlineMissedFunction dlmFunc_)
: RTEMSTaskBase(setPriority, setStack, name), : PeriodicTaskBase(setPeriod, dlmFunc_),
periodTicks(RtemsBasic::convertMsToTicks(setPeriod)), RTEMSTaskBase(setPriority, setStack, name),
deadlineMissedFunc(setDeadlineMissedFunc) {} periodTicks(RtemsBasic::convertMsToTicks(static_cast<uint32_t>(setPeriod * 1000.0))) {}
PeriodicTask::~PeriodicTask(void) { PeriodicTask::~PeriodicTask() {
/* Do not delete objects, we were responsible for pointers only. */ /* Do not delete objects, we were responsible for pointers only. */
rtems_rate_monotonic_delete(periodId); rtems_rate_monotonic_delete(periodId);
} }
@ -18,7 +18,7 @@ PeriodicTask::~PeriodicTask(void) {
rtems_task PeriodicTask::taskEntryPoint(rtems_task_argument argument) { rtems_task PeriodicTask::taskEntryPoint(rtems_task_argument argument) {
/* The argument is re-interpreted as MultiObjectTask. The Task object is global, /* The argument is re-interpreted as MultiObjectTask. The Task object is global,
so it is found from any place. */ so it is found from any place. */
PeriodicTask* originalTask(reinterpret_cast<PeriodicTask*>(argument)); auto* originalTask(reinterpret_cast<PeriodicTask*>(argument));
return originalTask->taskFunctionality(); return originalTask->taskFunctionality();
; ;
} }
@ -28,8 +28,10 @@ ReturnValue_t PeriodicTask::startTask() {
rtems_task_start(id, PeriodicTask::taskEntryPoint, rtems_task_argument((void*)this)); rtems_task_start(id, PeriodicTask::taskEntryPoint, rtems_task_argument((void*)this));
if (status != RTEMS_SUCCESSFUL) { if (status != RTEMS_SUCCESSFUL) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "ObjectTask::startTask for " << std::hex << this->getId() << std::dec sif::error << "PeriodicTask::startTask for " << std::hex << this->getId() << std::dec
<< " failed." << std::endl; << " failed" << std::endl;
#else
sif::printError("PeriodicTask::startTask for 0x%08x failed\n", getId());
#endif #endif
} }
switch (status) { switch (status) {
@ -47,38 +49,20 @@ ReturnValue_t PeriodicTask::startTask() {
ReturnValue_t PeriodicTask::sleepFor(uint32_t ms) { return RTEMSTaskBase::sleepFor(ms); } ReturnValue_t PeriodicTask::sleepFor(uint32_t ms) { return RTEMSTaskBase::sleepFor(ms); }
void PeriodicTask::taskFunctionality() { [[noreturn]] void PeriodicTask::taskFunctionality() {
RTEMSTaskBase::setAndStartPeriod(periodTicks, &periodId); RTEMSTaskBase::setAndStartPeriod(periodTicks, &periodId);
for (const auto& object : objectList) { initObjsAfterTaskCreation();
object->initializeAfterTaskCreation();
}
/* The task's "infinite" inner loop is entered. */ /* The task's "infinite" inner loop is entered. */
while (1) { while (true) {
for (const auto& object : objectList) { for (const auto& objectPair : objectList) {
object->performOperation(); objectPair.first->performOperation(objectPair.second);
} }
rtems_status_code status = RTEMSTaskBase::restartPeriod(periodTicks, periodId); rtems_status_code status = RTEMSTaskBase::restartPeriod(periodTicks, periodId);
if (status == RTEMS_TIMEOUT) { if (status == RTEMS_TIMEOUT) {
if (this->deadlineMissedFunc != nullptr) { if (dlmFunc != nullptr) {
this->deadlineMissedFunc(); dlmFunc();
} }
} }
} }
} }
ReturnValue_t PeriodicTask::addComponent(object_id_t object) {
ExecutableObjectIF* newObject = ObjectManager::instance()->get<ExecutableObjectIF>(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); }

View File

@ -3,9 +3,10 @@
#include <vector> #include <vector>
#include "../../objectmanager/ObjectManagerIF.h"
#include "../../tasks/PeriodicTaskIF.h"
#include "RTEMSTaskBase.h" #include "RTEMSTaskBase.h"
#include "fsfw/objectmanager/ObjectManagerIF.h"
#include "fsfw/tasks/PeriodicTaskBase.h"
#include "fsfw/tasks/PeriodicTaskIF.h"
class ExecutableObjectIF; class ExecutableObjectIF;
@ -18,7 +19,7 @@ class ExecutableObjectIF;
* @author baetz * @author baetz
* @ingroup task_handling * @ingroup task_handling
*/ */
class PeriodicTask : public RTEMSTaskBase, public PeriodicTaskIF { class PeriodicTask : public PeriodicTaskBase, public RTEMSTaskBase {
public: public:
/** /**
* @brief Standard constructor of the class. * @brief Standard constructor of the class.
@ -36,12 +37,12 @@ class PeriodicTask : public RTEMSTaskBase, public PeriodicTaskIF {
* that shall be assigned. * that shall be assigned.
*/ */
PeriodicTask(const char *name, rtems_task_priority setPriority, size_t setStack, 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 * @brief Currently, the executed object's lifetime is not coupled with the task object's
* lifetime, so the destructor is empty. * lifetime, so the destructor is empty.
*/ */
virtual ~PeriodicTask(void); ~PeriodicTask() override;
/** /**
* @brief The method to start the task. * @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 * The address of the task object is passed as an argument
* to the system call. * to the system call.
*/ */
ReturnValue_t startTask(void); ReturnValue_t startTask() override;
/**
* Adds an object to the list of objects to be executed.
* The objects are executed in the order added.
* @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; ReturnValue_t sleepFor(uint32_t ms) override;
protected: protected:
typedef std::vector<ExecutableObjectIF *> 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. * @brief The period of the task.
* @details The period determines the frequency of the task's execution. It is expressed in * @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 * @brief id of the associated OS period
*/ */
rtems_id periodId = 0; 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. * @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 * @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 * are called. Afterwards the checkAndRestartPeriod system call blocks the task until the next
* period. On missing the deadline, the deadlineMissedFunction is executed. * period. On missing the deadline, the deadlineMissedFunction is executed.
*/ */
void taskFunctionality(void); [[noreturn]] void taskFunctionality();
}; };
#endif /* FSFW_OSAL_RTEMS_PERIODICTASK_H_ */ #endif /* FSFW_OSAL_RTEMS_PERIODICTASK_H_ */

View File

@ -32,7 +32,7 @@ RTEMSTaskBase::RTEMSTaskBase(rtems_task_priority set_priority, size_t stack_size
RTEMSTaskBase::~RTEMSTaskBase() { rtems_task_delete(id); } 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) { ReturnValue_t RTEMSTaskBase::sleepFor(uint32_t ms) {
rtems_status_code status = rtems_task_wake_after(RtemsBasic::convertMsToTicks(ms)); rtems_status_code status = rtems_task_wake_after(RtemsBasic::convertMsToTicks(ms));

View File

@ -36,9 +36,9 @@ class RTEMSTaskBase {
/** /**
* @brief This method returns the task id of this class. * @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 ReturnValue_t setAndStartPeriod(rtems_interval period, rtems_id *periodId);
static rtems_status_code restartPeriod(rtems_interval period, rtems_id periodId); static rtems_status_code restartPeriod(rtems_interval period, rtems_id periodId);

View File

@ -1,7 +1,6 @@
#include "fsfw/tasks/TaskFactory.h" #include "fsfw/tasks/TaskFactory.h"
#include "fsfw/osal/rtems/FixedTimeslotTask.h" #include "fsfw/osal/rtems/FixedTimeslotTask.h"
#include "fsfw/osal/rtems/InitTask.h"
#include "fsfw/osal/rtems/PeriodicTask.h" #include "fsfw/osal/rtems/PeriodicTask.h"
#include "fsfw/osal/rtems/RtemsBasic.h" #include "fsfw/osal/rtems/RtemsBasic.h"
#include "fsfw/returnvalues/HasReturnvaluesIF.h" #include "fsfw/returnvalues/HasReturnvaluesIF.h"
@ -9,29 +8,29 @@
// TODO: Different variant than the lazy loading in QueueFactory. What's better and why? // TODO: Different variant than the lazy loading in QueueFactory. What's better and why?
TaskFactory* TaskFactory::factoryInstance = new TaskFactory(); TaskFactory* TaskFactory::factoryInstance = new TaskFactory();
TaskFactory::~TaskFactory() {} TaskFactory::TaskFactory() = default;
TaskFactory::~TaskFactory() = default;
TaskFactory* TaskFactory::instance() { return TaskFactory::factoryInstance; } TaskFactory* TaskFactory::instance() { return TaskFactory::factoryInstance; }
PeriodicTaskIF* TaskFactory::createPeriodicTask( PeriodicTaskIF* TaskFactory::createPeriodicTask(
TaskName name_, TaskPriority taskPriority_, TaskStackSize stackSize_, TaskName name_, TaskPriority taskPriority_, TaskStackSize stackSize_,
TaskPeriod periodInSeconds_, TaskDeadlineMissedFunction deadLineMissedFunction_) { TaskPeriod periodInSeconds_, TaskDeadlineMissedFunction deadLineMissedFunction_) {
rtems_interval taskPeriod = periodInSeconds_ * Clock::getTicksPerSecond(); return static_cast<PeriodicTaskIF*>(new PeriodicTask(name_, taskPriority_, stackSize_,
periodInSeconds_, deadLineMissedFunction_));
return static_cast<PeriodicTaskIF*>(
new PeriodicTask(name_, taskPriority_, stackSize_, taskPeriod, deadLineMissedFunction_));
} }
FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask( FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask(
TaskName name_, TaskPriority taskPriority_, TaskStackSize stackSize_, TaskName name_, TaskPriority taskPriority_, TaskStackSize stackSize_,
TaskPeriod periodInSeconds_, TaskDeadlineMissedFunction deadLineMissedFunction_) { TaskPeriod periodInSeconds_, TaskDeadlineMissedFunction deadLineMissedFunction_) {
rtems_interval taskPeriod = periodInSeconds_ * Clock::getTicksPerSecond(); return static_cast<FixedTimeslotTaskIF*>(new FixedTimeslotTask(
return static_cast<FixedTimeslotTaskIF*>( name_, taskPriority_, stackSize_, periodInSeconds_, deadLineMissedFunction_));
new FixedTimeslotTask(name_, taskPriority_, stackSize_, taskPeriod, deadLineMissedFunction_));
} }
ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) { ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) {
// TODO not implemented // This should call the OS specific destructor
delete (dynamic_cast<PeriodicTask*>(task));
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
@ -45,5 +44,3 @@ void TaskFactory::printMissedDeadline() {
/* TODO: Implement */ /* TODO: Implement */
return; return;
} }
TaskFactory::TaskFactory() {}

View File

@ -1,2 +1,3 @@
target_sources(${LIB_FSFW_NAME} PRIVATE FixedSequenceSlot.cpp target_sources(
FixedSlotSequence.cpp) ${LIB_FSFW_NAME} PRIVATE FixedSequenceSlot.cpp FixedSlotSequence.cpp
PeriodicTaskBase.cpp FixedTimeslotTaskBase.cpp)

View File

@ -29,7 +29,7 @@ void FixedSlotSequence::executeAndAdvance() {
uint32_t FixedSlotSequence::getIntervalToNextSlotMs() { uint32_t FixedSlotSequence::getIntervalToNextSlotMs() {
uint32_t oldTime; uint32_t oldTime;
SlotListIter slotListIter = current; auto slotListIter = current;
// Get the pollingTimeMs of the current slot object. // Get the pollingTimeMs of the current slot object.
oldTime = slotListIter->pollingTimeMs; oldTime = slotListIter->pollingTimeMs;
// Advance to the next object. // Advance to the next object.
@ -51,7 +51,7 @@ uint32_t FixedSlotSequence::getIntervalToNextSlotMs() {
uint32_t FixedSlotSequence::getIntervalToPreviousSlotMs() { uint32_t FixedSlotSequence::getIntervalToPreviousSlotMs() {
uint32_t currentTime; uint32_t currentTime;
SlotListIter slotListIter = current; auto slotListIter = current;
// Get the pollingTimeMs of the current slot object. // Get the pollingTimeMs of the current slot object.
currentTime = slotListIter->pollingTimeMs; currentTime = slotListIter->pollingTimeMs;
@ -67,7 +67,7 @@ uint32_t FixedSlotSequence::getIntervalToPreviousSlotMs() {
bool FixedSlotSequence::slotFollowsImmediately() { bool FixedSlotSequence::slotFollowsImmediately() {
uint32_t currentTime = current->pollingTimeMs; uint32_t currentTime = current->pollingTimeMs;
SlotListIter fixedSequenceIter = this->current; auto fixedSequenceIter = this->current;
// Get the pollingTimeMs of the current slot object. // Get the pollingTimeMs of the current slot object.
if (fixedSequenceIter == slotList.begin()) return false; if (fixedSequenceIter == slotList.begin()) return false;
fixedSequenceIter--; fixedSequenceIter--;
@ -96,8 +96,8 @@ ReturnValue_t FixedSlotSequence::checkSequence() const {
return FixedTimeslotTaskIF::SLOT_LIST_EMPTY; return FixedTimeslotTaskIF::SLOT_LIST_EMPTY;
} }
if (customCheckFunction != nullptr) { if (customChecker != nullptr) {
ReturnValue_t result = customCheckFunction(slotList); ReturnValue_t result = customChecker(slotList, customCheckArgs);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
// Continue for now but print error output. // Continue for now but print error output.
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
@ -161,6 +161,9 @@ ReturnValue_t FixedSlotSequence::intializeSequenceAfterTaskCreation() const {
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
void FixedSlotSequence::addCustomCheck(ReturnValue_t (*customCheckFunction)(const SlotList&)) { void FixedSlotSequence::addCustomCheck(CustomCheckFunc customChecker_, void* checkerArgs_) {
this->customCheckFunction = customCheckFunction; customChecker = customChecker_;
customCheckArgs = checkerArgs_;
} }
bool FixedSlotSequence::isEmpty() const { return slotList.empty(); }

View File

@ -30,12 +30,12 @@ class FixedSlotSequence {
public: public:
using SlotList = std::multiset<FixedSequenceSlot>; using SlotList = std::multiset<FixedSequenceSlot>;
using SlotListIter = std::multiset<FixedSequenceSlot>::iterator; using SlotListIter = std::multiset<FixedSequenceSlot>::iterator;
using CustomCheckFunc = ReturnValue_t (*)(const SlotList&, void* args);
/** /**
* @brief The constructor of the FixedSlotSequence object. * @brief The constructor of the FixedSlotSequence object.
* @param setLength The period length, expressed in ms. * @param setLength The period length, expressed in ms.
*/ */
FixedSlotSequence(uint32_t setLengthMs); explicit FixedSlotSequence(uint32_t setLengthMs);
/** /**
* @brief The destructor of the FixedSlotSequence object. * @brief The destructor of the FixedSlotSequence object.
@ -106,7 +106,7 @@ class FixedSlotSequence {
/** /**
* @brief This method returns the length of this FixedSlotSequence instance. * @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 * @brief The method to execute the device handler entered in the current
@ -137,7 +137,7 @@ class FixedSlotSequence {
* @return * @return
* - SLOT_LIST_EMPTY if the slot list is empty * - 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. * @brief A custom check can be injected for the respective slot list.
@ -149,7 +149,7 @@ class FixedSlotSequence {
* @param customCheckFunction * @param customCheckFunction
* *
*/ */
void addCustomCheck(ReturnValue_t (*customCheckFunction)(const SlotList&)); void addCustomCheck(CustomCheckFunc func, void* userArgs);
/** /**
* @brief Perform any initialization steps required after the executing * @brief Perform any initialization steps required after the executing
@ -157,7 +157,9 @@ class FixedSlotSequence {
* executing task! * executing task!
* @return * @return
*/ */
ReturnValue_t intializeSequenceAfterTaskCreation() const; [[nodiscard]] ReturnValue_t intializeSequenceAfterTaskCreation() const;
[[nodiscard]] bool isEmpty() const;
protected: protected:
/** /**
@ -173,7 +175,8 @@ class FixedSlotSequence {
*/ */
SlotList slotList; SlotList slotList;
ReturnValue_t (*customCheckFunction)(const SlotList&) = nullptr; CustomCheckFunc customChecker = nullptr;
void* customCheckArgs = nullptr;
uint32_t lengthMs; uint32_t lengthMs;
}; };

View File

@ -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<uint32_t>(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;
}

View File

@ -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

View File

@ -2,6 +2,7 @@
#define FRAMEWORK_TASKS_FIXEDTIMESLOTTASKIF_H_ #define FRAMEWORK_TASKS_FIXEDTIMESLOTTASKIF_H_
#include "PeriodicTaskIF.h" #include "PeriodicTaskIF.h"
#include "fsfw/objectmanager/ObjectManager.h"
#include "fsfw/objectmanager/ObjectManagerIF.h" #include "fsfw/objectmanager/ObjectManagerIF.h"
#include "fsfw/returnvalues/FwClassIds.h" #include "fsfw/returnvalues/FwClassIds.h"
@ -11,10 +12,23 @@
*/ */
class FixedTimeslotTaskIF : public PeriodicTaskIF { class FixedTimeslotTaskIF : public PeriodicTaskIF {
public: public:
virtual ~FixedTimeslotTaskIF() {} ~FixedTimeslotTaskIF() override = default;
static constexpr ReturnValue_t SLOT_LIST_EMPTY = static constexpr ReturnValue_t SLOT_LIST_EMPTY =
HasReturnvaluesIF::makeReturnCode(CLASS_ID::FIXED_SLOT_TASK_IF, 0); 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. * 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 * The execution step will be passed to the object (e.g. as an operation
@ -25,12 +39,24 @@ class FixedTimeslotTaskIF : public PeriodicTaskIF {
* @return * @return
*/ */
virtual ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs, virtual ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs,
int8_t executionStep) = 0; int8_t executionStep) {
auto* execObj = ObjectManager::instance()->get<ExecutableObjectIF>(componentId);
return addSlot(componentId, execObj, slotTimeMs, executionStep);
}
/** /**
* Check whether the sequence is valid and perform all other required * Check whether the sequence is valid and perform all other required
* initialization steps which are needed after task creation * 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_ */ #endif /* FRAMEWORK_TASKS_FIXEDTIMESLOTTASKIF_H_ */

View File

@ -0,0 +1,71 @@
#include "PeriodicTaskBase.h"
#include <set>
#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<uint32_t>(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<ExecutableObjectIF*> 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<ExecutableObjectIF>(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;
}

View File

@ -0,0 +1,54 @@
#ifndef FSFW_SRC_FSFW_TASKS_PERIODICTASKBASE_H_
#define FSFW_SRC_FSFW_TASKS_PERIODICTASKBASE_H_
#include <cstdint>
#include <vector>
#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<std::pair<ExecutableObjectIF*, uint8_t>>;
/**
* @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_ */

View File

@ -3,9 +3,8 @@
#include <cstddef> #include <cstddef>
#include "../objectmanager/SystemObjectIF.h" #include "fsfw/objectmanager/SystemObjectIF.h"
#include "../timemanager/Clock.h" #include "fsfw/tasks/ExecutableObjectIF.h"
class ExecutableObjectIF;
/** /**
* New version of TaskIF * New version of TaskIF
@ -18,7 +17,7 @@ class PeriodicTaskIF {
/** /**
* @brief A virtual destructor as it is mandatory for interfaces. * @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 * @brief With the startTask method, a created task can be started
* for the first time. * for the first time.
@ -26,28 +25,29 @@ class PeriodicTaskIF {
virtual ReturnValue_t startTask() = 0; virtual ReturnValue_t startTask() = 0;
/** /**
* Add a component (object) to a periodic task. * Adds an object to the list of objects to be executed.
* @param object * The objects are executed in the order added. The object needs to implement
* Add an object to the task. The object needs to implement ExecutableObjectIF * ExecutableObjectIF
* @return * @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) { virtual ReturnValue_t addComponent(object_id_t object, uint8_t opCode) = 0;
return HasReturnvaluesIF::RETURN_FAILED; virtual ReturnValue_t addComponent(object_id_t object) { return addComponent(object, 0); };
};
/** /**
* Add an object to a periodic task. * Adds an object to the list of objects to be executed.
* @param object * The objects are executed in the order added.
* Add an object to the task. * @param object pointer to the object to add.
* @return * @return RETURN_OK on success, RETURN_FAILED if the object could not be added.
*/ */
virtual ReturnValue_t addComponent(ExecutableObjectIF* object) { virtual ReturnValue_t addComponent(ExecutableObjectIF* object, uint8_t opCode) = 0;
return HasReturnvaluesIF::RETURN_FAILED; virtual ReturnValue_t addComponent(ExecutableObjectIF* object) { return addComponent(object, 0); }
};
virtual ReturnValue_t sleepFor(uint32_t ms) = 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_ */

View File

@ -4,7 +4,7 @@
#include <cstdlib> #include <cstdlib>
#include "FixedTimeslotTaskIF.h" #include "FixedTimeslotTaskIF.h"
#include "Typedef.h" #include "definitions.h"
/** /**
* Singleton Class that produces Tasks. * Singleton Class that produces Tasks.

View File

@ -1,13 +0,0 @@
#ifndef FSFW_TASKS_TYPEDEF_H_
#define FSFW_TASKS_TYPEDEF_H_
#include <cstddef>
#include <cstdint>
typedef const char* TaskName;
typedef uint32_t TaskPriority;
typedef size_t TaskStackSize;
typedef double TaskPeriod;
typedef void (*TaskDeadlineMissedFunction)();
#endif /* FSFW_TASKS_TYPEDEF_H_ */

View File

@ -0,0 +1,13 @@
#ifndef FSFW_TASKS_TYPEDEF_H_
#define FSFW_TASKS_TYPEDEF_H_
#include <cstddef>
#include <cstdint>
using TaskName = const char*;
using TaskPriority = int;
using TaskStackSize = size_t;
using TaskPeriod = double;
using TaskDeadlineMissedFunction = void (*)();
#endif /* FSFW_TASKS_TYPEDEF_H_ */

View File

@ -13,14 +13,14 @@ TestDevice::TestDevice(object_id_t objectId, object_id_t comIF, CookieIF* cookie
dataset(this), dataset(this),
fullInfoPrintout(fullInfoPrintout) {} fullInfoPrintout(fullInfoPrintout) {}
TestDevice::~TestDevice() {} TestDevice::~TestDevice() = default;
void TestDevice::performOperationHook() { void TestDevice::performOperationHook() {
if (periodicPrintout) { if (periodicPrintout) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "TestDevice" << deviceIdx << "::performOperationHook: Alive!" << std::endl; sif::info << "TestDevice" << deviceIdx << "::performOperationHook: Alive!" << std::endl;
#else #else
sif::printInfo("TestDevice%d::performOperationHook: Alive!", deviceIdx); sif::printInfo("TestDevice%d::performOperationHook: Alive!\n", deviceIdx);
#endif #endif
} }

View File

@ -12,7 +12,7 @@ TestTask::TestTask(object_id_t objectId) : SystemObject(objectId), testMode(test
IPCStore = ObjectManager::instance()->get<StorageManagerIF>(objects::IPC_STORE); IPCStore = ObjectManager::instance()->get<StorageManagerIF>(objects::IPC_STORE);
} }
TestTask::~TestTask() {} TestTask::~TestTask() = default;
ReturnValue_t TestTask::performOperation(uint8_t operationCode) { ReturnValue_t TestTask::performOperation(uint8_t operationCode) {
ReturnValue_t result = RETURN_OK; ReturnValue_t result = RETURN_OK;

View File

@ -13,9 +13,9 @@
*/ */
class TestTask : public SystemObject, public ExecutableObjectIF, public HasReturnvaluesIF { class TestTask : public SystemObject, public ExecutableObjectIF, public HasReturnvaluesIF {
public: public:
TestTask(object_id_t objectId); explicit TestTask(object_id_t objectId);
virtual ~TestTask(); ~TestTask() override;
virtual ReturnValue_t performOperation(uint8_t operationCode = 0) override; ReturnValue_t performOperation(uint8_t operationCode) override;
protected: protected:
virtual ReturnValue_t performOneShotAction(); virtual ReturnValue_t performOneShotAction();

View File

@ -16,7 +16,7 @@
#include "fsfw_tests/unit/mocks/PeriodicTaskIFMock.h" #include "fsfw_tests/unit/mocks/PeriodicTaskIFMock.h"
TEST_CASE("Internal Error Reporter", "[TestInternalError]") { TEST_CASE("Internal Error Reporter", "[TestInternalError]") {
PeriodicTaskMock task(10); PeriodicTaskMock task(10, nullptr);
ObjectManagerIF* manager = ObjectManager::instance(); ObjectManagerIF* manager = ObjectManager::instance();
if (manager == nullptr) { if (manager == nullptr) {
FAIL(); FAIL();
@ -27,6 +27,8 @@ TEST_CASE("Internal Error Reporter", "[TestInternalError]") {
FAIL(); FAIL();
} }
task.addComponent(objects::INTERNAL_ERROR_REPORTER); task.addComponent(objects::INTERNAL_ERROR_REPORTER);
// This calls the initializeAfterTaskCreation function
task.startTask();
MessageQueueIF* testQueue = QueueFactory::instance()->createMessageQueue(1); MessageQueueIF* testQueue = QueueFactory::instance()->createMessageQueue(1);
MessageQueueIF* hkQueue = QueueFactory::instance()->createMessageQueue(1); MessageQueueIF* hkQueue = QueueFactory::instance()->createMessageQueue(1);
internalErrorReporter->getSubscriptionInterface()->subscribeForSetUpdateMessage( internalErrorReporter->getSubscriptionInterface()->subscribeForSetUpdateMessage(

View File

@ -2,36 +2,24 @@
#define FSFW_UNITTEST_TESTS_MOCKS_PERIODICTASKMOCK_H_ #define FSFW_UNITTEST_TESTS_MOCKS_PERIODICTASKMOCK_H_
#include <fsfw/tasks/ExecutableObjectIF.h> #include <fsfw/tasks/ExecutableObjectIF.h>
#include <fsfw/tasks/PeriodicTaskIF.h> #include <fsfw/tasks/PeriodicTaskBase.h>
class PeriodicTaskMock : public PeriodicTaskIF { class PeriodicTaskMock : public PeriodicTaskBase {
public: public:
PeriodicTaskMock(uint32_t period = 5) : period(period) {} PeriodicTaskMock(TaskPeriod period, TaskDeadlineMissedFunction dlmFunc)
/** : PeriodicTaskBase(period, dlmFunc) {}
* @brief A virtual destructor as it is mandatory for interfaces.
*/
virtual ~PeriodicTaskMock() {} virtual ~PeriodicTaskMock() {}
/** /**
* @brief With the startTask method, a created task can be started * @brief With the startTask method, a created task can be started
* for the first time. * for the first time.
*/ */
virtual ReturnValue_t startTask() override { return HasReturnvaluesIF::RETURN_OK; }; virtual ReturnValue_t startTask() override {
initObjsAfterTaskCreation();
virtual ReturnValue_t addComponent(object_id_t object) override {
ExecutableObjectIF* executableObject =
ObjectManager::instance()->get<ExecutableObjectIF>(objects::INTERNAL_ERROR_REPORTER);
if (executableObject == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
executableObject->setTaskIF(this);
executableObject->initializeAfterTaskCreation();
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
}; };
virtual ReturnValue_t sleepFor(uint32_t ms) override { 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_ #endif // FSFW_UNITTEST_TESTS_MOCKS_PERIODICTASKMOCK_H_