refactored and tested hosted and linux task IF

This commit is contained in:
Robin Müller 2022-05-19 00:44:34 +02:00
parent 08f1ebf9fc
commit 3a16290707
No known key found for this signature in database
GPG Key ID: 11D4952C8CCEF814
21 changed files with 160 additions and 147 deletions

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"
@ -23,11 +21,7 @@
FixedTimeslotTask::FixedTimeslotTask(const char* name, TaskPriority setPriority, FixedTimeslotTask::FixedTimeslotTask(const char* name, TaskPriority setPriority,
TaskStackSize setStack, TaskPeriod setPeriod, TaskStackSize setStack, TaskPeriod setPeriod,
TaskDeadlineMissedFunction dlmFunc_) TaskDeadlineMissedFunction dlmFunc_)
: started(false), : FixedTimeslotTaskBase(setPeriod, dlmFunc_), started(false), taskName(name) {
pollingSeqTable(static_cast<uint32_t>(setPeriod * 1000)),
taskName(name),
period(setPeriod),
dlmFunc(dlmFunc_) {
// 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);
@ -80,7 +74,7 @@ ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) {
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
void FixedTimeslotTask::taskFunctionality() { [[noreturn]] void FixedTimeslotTask::taskFunctionality() {
pollingSeqTable.intializeSequenceAfterTaskCreation(); pollingSeqTable.intializeSequenceAfterTaskCreation();
// A local iterator for the Polling Sequence Table is created to // A local iterator for the Polling Sequence Table is created to
@ -106,8 +100,11 @@ 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();
}
}
} }
} }
} }
@ -132,10 +129,6 @@ ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, uint32_t slotT
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
ReturnValue_t FixedTimeslotTask::checkSequence() { return pollingSeqTable.checkSequence(); }
uint32_t FixedTimeslotTask::getPeriodMs() const { return static_cast<uint32_t>(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
@ -175,5 +168,3 @@ bool FixedTimeslotTask::delayForInterval(chron_ms* previousWakeTimeMs, const chr
(*previousWakeTimeMs) = currentStartTime; (*previousWakeTimeMs) = currentStartTime;
return false; return false;
} }
bool FixedTimeslotTask::isEmpty() const { return pollingSeqTable.isEmpty(); }

View File

@ -8,7 +8,7 @@
#include "fsfw/objectmanager/ObjectManagerIF.h" #include "fsfw/objectmanager/ObjectManagerIF.h"
#include "fsfw/tasks/FixedSlotSequence.h" #include "fsfw/tasks/FixedSlotSequence.h"
#include "fsfw/tasks/FixedTimeslotTaskIF.h" #include "fsfw/tasks/FixedTimeslotTaskBase.h"
#include "fsfw/tasks/definitions.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.
@ -57,14 +57,10 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF {
* @param executionStep * @param executionStep
* @return * @return
*/ */
ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs, int8_t executionStep) override; ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs,
int8_t executionStep) override;
ReturnValue_t checkSequence() override;
ReturnValue_t sleepFor(uint32_t ms) override; ReturnValue_t sleepFor(uint32_t ms) override;
uint32_t getPeriodMs() const override;
bool isEmpty() const override;
protected: protected:
using chron_ms = std::chrono::milliseconds; using chron_ms = std::chrono::milliseconds;
@ -74,21 +70,10 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF {
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;
TaskDeadlineMissedFunction dlmFunc = nullptr;
/** /**
* @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
@ -108,7 +93,7 @@ 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(); [[noreturn]] void taskFunctionality();
static bool delayForInterval(chron_ms* previousWakeTimeMs, chron_ms interval); static bool delayForInterval(chron_ms* previousWakeTimeMs, chron_ms interval);
}; };

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>
@ -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.
@ -80,8 +77,6 @@ void PeriodicTask::taskFunctionality() {
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()) {

View File

@ -39,7 +39,7 @@ class PeriodicTask : public PeriodicTaskBase {
* @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,9 +48,9 @@ class PeriodicTask : public PeriodicTaskBase {
* 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); ReturnValue_t sleepFor(uint32_t ms) override;
protected: protected:
using chron_ms = std::chrono::milliseconds; using chron_ms = std::chrono::milliseconds;
@ -81,9 +81,9 @@ class PeriodicTask : public PeriodicTaskBase {
* 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,26 +1,21 @@
#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; 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_,
TaskPeriod periodSeconds_) TaskPeriod periodSeconds_, TaskDeadlineMissedFunction dlmFunc_)
: posixThread(name_, priority_, stackSize_), : FixedTimeslotTaskBase(periodSeconds_, dlmFunc_),
pst(static_cast<uint32_t>(periodSeconds_ * 1000)), posixThread(name_, priority_, stackSize_),
started(false) {} started(false) {}
FixedTimeslotTask::~FixedTimeslotTask() {}
bool FixedTimeslotTask::isEmpty() const { return pst.isEmpty(); }
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;
@ -36,45 +31,25 @@ 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() { 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) {
posixThread.suspend(); posixThread.suspend();
} }
pst.intializeSequenceAfterTaskCreation(); pollingSeqTable.intializeSequenceAfterTaskCreation();
// The start time for the first entry is read. // The start time for the first entry is read.
uint64_t lastWakeTime = posixThread.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)) {
@ -83,7 +58,7 @@ void FixedTimeslotTask::taskFunctionality() {
} }
} }
// 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();
} }
} }

View File

@ -5,10 +5,10 @@
#include "PosixThread.h" #include "PosixThread.h"
#include "fsfw/tasks/FixedSlotSequence.h" #include "fsfw/tasks/FixedSlotSequence.h"
#include "fsfw/tasks/FixedTimeslotTaskIF.h" #include "fsfw/tasks/FixedTimeslotTaskBase.h"
#include "fsfw/tasks/definitions.h" #include "fsfw/tasks/definitions.h"
class FixedTimeslotTask : public FixedTimeslotTaskIF { class FixedTimeslotTask : public FixedTimeslotTaskBase {
public: public:
/** /**
* Create a generic periodic task. * Create a generic periodic task.
@ -22,22 +22,14 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF {
* @param period_ * @param period_
* @param deadlineMissedFunc_ * @param deadlineMissedFunc_
*/ */
FixedTimeslotTask(const char* name_, int priority_, size_t stackSize_, TaskPeriod periodSeconds_); FixedTimeslotTask(const char* name_, TaskPriority priority_, size_t stackSize_,
virtual ~FixedTimeslotTask(); TaskPeriod periodSeconds_, TaskDeadlineMissedFunction dlmFunc_);
~FixedTimeslotTask() override = default;
ReturnValue_t startTask() override; ReturnValue_t startTask() override;
ReturnValue_t sleepFor(uint32_t ms) override; ReturnValue_t sleepFor(uint32_t ms) override;
uint32_t getPeriodMs() const override;
ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs,
int8_t executionStep) override;
ReturnValue_t checkSequence() override;
bool isEmpty() const override;
/** /**
* This static function can be used as #deadlineMissedFunc. * This static function can be used as #deadlineMissedFunc.
* It counts missedDeadlines and prints the number of missed deadlines every 10th time. * It counts missedDeadlines and prints the number of missed deadlines every 10th time.
@ -57,10 +49,11 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF {
* 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; PosixThread posixThread;
bool started;
/** /**
* @brief This is the entry point in a new thread. * @brief This is the entry point in a new thread.
@ -74,9 +67,6 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF {
* 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,35 +1,27 @@
#include "fsfw/osal/linux/PeriodicPosixTask.h" #include "PeriodicPosixTask.h"
#include <cerrno> #include "fsfw/serviceinterface.h"
#include <set>
#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_,
TaskPeriod period_, TaskDeadlineMissedFunction dlMissedFunc_) TaskPeriod period_, TaskDeadlineMissedFunction dlmFunc_)
: PeriodicTaskBase(period_, dlMissedFunc_), : PeriodicTaskBase(period_, dlmFunc_),
posixThread(name_, priority_, stackSize_), posixThread(name_, priority_, stackSize_),
started(false) {} started(false) {}
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 nullptr; return nullptr;
} }
ReturnValue_t PeriodicPosixTask::sleepFor(uint32_t ms) { ReturnValue_t PeriodicPosixTask::sleepFor(uint32_t ms) {
return PosixThread::sleep(static_cast<uint64_t>(ms * 1000000)); return PosixThread::sleep(static_cast<uint64_t>(ms) * 1000000);
} }
ReturnValue_t PeriodicPosixTask::startTask(void) { ReturnValue_t PeriodicPosixTask::startTask() {
if (isEmpty()) { if (isEmpty()) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
@ -38,24 +30,24 @@ ReturnValue_t PeriodicPosixTask::startTask(void) {
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
void PeriodicPosixTask::taskFunctionality(void) { [[noreturn]] void PeriodicPosixTask::taskFunctionality() {
if (not started) { if (not started) {
posixThread.suspend(); posixThread.suspend();
} }
initObjsAfterTaskCreation(); initObjsAfterTaskCreation();
uint64_t lastWakeTime = posixThread.getCurrentMonotonicTimeMs(); uint64_t lastWakeTime = PosixThread::getCurrentMonotonicTimeMs();
uint64_t periodMs = getPeriodMs(); 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& objOpCodePair : objectList) { for (auto const& objOpCodePair : objectList) {
objOpCodePair.first->performOperation(objOpCodePair.second); 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();
} }
} }
} }

View File

@ -24,8 +24,8 @@ class PeriodicPosixTask : public PeriodicTaskBase {
* @param deadlineMissedFunc_ * @param deadlineMissedFunc_
*/ */
PeriodicPosixTask(const char* name_, int priority_, size_t stackSize_, TaskPeriod 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.
@ -54,7 +54,7 @@ class PeriodicPosixTask : public PeriodicTaskBase {
* 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.
* *

View File

@ -8,7 +8,7 @@
// 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; }
@ -22,7 +22,8 @@ PeriodicTaskIF* TaskFactory::createPeriodicTask(
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_); return new FixedTimeslotTask(name_, taskPriority_, stackSize_, periodInSeconds_,
deadLineMissedFunction_);
} }
ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) { ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) {

View File

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

View File

@ -35,7 +35,7 @@ class FixedSlotSequence {
* @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.

View File

@ -0,0 +1,29 @@
#include "FixedTimeslotTaskBase.h"
#include "fsfw/objectmanager/ObjectManager.h"
FixedTimeslotTaskBase::FixedTimeslotTaskBase(TaskPeriod period_,
TaskDeadlineMissedFunction dlmFunc_)
: pollingSeqTable(getPeriodMs()), period(period_), 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 componentId, uint32_t slotTimeMs,
int8_t executionStep) {
auto* 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 0x" << std::hex << std::setw(8) << std::setfill('0') << componentId
<< 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;
}

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:
//! Polling sequence table which contains the object to execute
//! and information like the timeslots and the passed execution step.
FixedSlotSequence pollingSeqTable;
/**
* @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;
ReturnValue_t checkSequence() override;
[[nodiscard]] uint32_t getPeriodMs() const override;
[[nodiscard]] bool isEmpty() const override;
ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs,
int8_t executionStep) override;
};
#endif // FSFW_EXAMPLE_HOSTED_FIXEDTIMESLOTTASKBASE_H

View File

@ -11,7 +11,7 @@
*/ */
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);

View File

@ -1,11 +1,21 @@
#include "PeriodicTaskBase.h" #include "PeriodicTaskBase.h"
#include <fsfw/objectmanager/ObjectManager.h>
#include <set> #include <set>
#include "fsfw/objectmanager/ObjectManager.h"
#include "fsfw/serviceinterface.h"
PeriodicTaskBase::PeriodicTaskBase(TaskPeriod period_, TaskDeadlineMissedFunction dlmFunc_) PeriodicTaskBase::PeriodicTaskBase(TaskPeriod period_, TaskDeadlineMissedFunction dlmFunc_)
: period(period), dlmFunc(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); } uint32_t PeriodicTaskBase::getPeriodMs() const { return static_cast<uint32_t>(period * 1000); }
@ -32,7 +42,7 @@ ReturnValue_t PeriodicTaskBase::initObjsAfterTaskCreation() {
} }
ReturnValue_t PeriodicTaskBase::addComponent(object_id_t object, uint8_t opCode) { ReturnValue_t PeriodicTaskBase::addComponent(object_id_t object, uint8_t opCode) {
ExecutableObjectIF* newObject = ObjectManager::instance()->get<ExecutableObjectIF>(object); auto* newObject = ObjectManager::instance()->get<ExecutableObjectIF>(object);
return addComponent(newObject, opCode); return addComponent(newObject, opCode);
} }

View File

@ -11,14 +11,15 @@ class ExecutableObjectIF;
class PeriodicTaskBase : public PeriodicTaskIF { class PeriodicTaskBase : public PeriodicTaskIF {
public: public:
PeriodicTaskBase(TaskPeriod period, TaskDeadlineMissedFunction deadlineMissedFunc = nullptr); explicit PeriodicTaskBase(TaskPeriod period,
TaskDeadlineMissedFunction deadlineMissedFunc = nullptr);
ReturnValue_t addComponent(object_id_t object, uint8_t opCode) override; ReturnValue_t addComponent(object_id_t object, uint8_t opCode) override;
ReturnValue_t addComponent(ExecutableObjectIF* object, uint8_t opCode) override; ReturnValue_t addComponent(ExecutableObjectIF* object, uint8_t opCode) override;
uint32_t getPeriodMs() const override; [[nodiscard]] uint32_t getPeriodMs() const override;
bool isEmpty() const override; [[nodiscard]] bool isEmpty() const override;
ReturnValue_t initObjsAfterTaskCreation(); ReturnValue_t initObjsAfterTaskCreation();

View File

@ -17,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.

View File

@ -5,7 +5,7 @@
#include <cstdint> #include <cstdint>
using TaskName = const char*; using TaskName = const char*;
using TaskPriority = uint32_t; using TaskPriority = int;
using TaskStackSize = size_t; using TaskStackSize = size_t;
using TaskPeriod = double; using TaskPeriod = double;
using TaskDeadlineMissedFunction = void (*)(); using TaskDeadlineMissedFunction = void (*)();