Merge remote-tracking branch 'upstream/development' into mueller/update-cmd-reply-maps-refactoring

This commit is contained in:
2022-07-08 17:29:21 +02:00
91 changed files with 2053 additions and 1089 deletions
+1 -1
View File
@@ -6,6 +6,6 @@ static constexpr int FSFW_VERSION_MAJOR = @FSFW_VERSION@;
static constexpr int FSFW_VERSION_MINOR = @FSFW_SUBVERSION@;
static constexpr int FSFW_VERSION_REVISION = @FSFW_REVISION@;
// Also contains CST (Commits since tag) information
static const char FSFW_VERSION_CST_GIT_SHA1[] = "@FSFW_VERSION_CST_GIT_SHA1@";
static const char FSFW_VCS_INFO[] = "@FSFW_VCS_INFO@";
#endif /* FSFW_VERSION_H_ */
@@ -696,9 +696,9 @@ void LocalDataPoolManager::performPeriodicHkGeneration(HkReceiver& receiver) {
if (result != HasReturnvaluesIF::RETURN_OK) {
/* Configuration error */
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "LocalDataPoolManager::performHkOperation: HK generation failed." << std::endl;
sif::warning << "LocalDataPoolManager::performPeriodicHkOperation: HK generation failed." << std::endl;
#else
sif::printWarning("LocalDataPoolManager::performHkOperation: HK generation failed.\n");
sif::printWarning("LocalDataPoolManager::performPeriodicHkOperation: HK generation failed.\n");
#endif
}
}
+1
View File
@@ -27,6 +27,7 @@ enum : uint8_t {
PUS_SERVICE_6 = 86,
PUS_SERVICE_8 = 88,
PUS_SERVICE_9 = 89,
PUS_SERVICE_11 = 91,
PUS_SERVICE_17 = 97,
PUS_SERVICE_23 = 103,
MGM_LIS3MDL = 106,
@@ -14,6 +14,7 @@ enum framework_objects : object_id_t {
PUS_SERVICE_5_EVENT_REPORTING = 0x53000005,
PUS_SERVICE_8_FUNCTION_MGMT = 0x53000008,
PUS_SERVICE_9_TIME_MGMT = 0x53000009,
PUS_SERVICE_11_TC_SCHEDULER = 0x53000011,
PUS_SERVICE_17_TEST = 0x53000017,
PUS_SERVICE_20_PARAMETERS = 0x53000020,
PUS_SERVICE_200_MODE_MGMT = 0x53000200,
+4 -4
View File
@@ -109,8 +109,8 @@ TcpTmTcServer::~TcpTmTcServer() { closeSocket(listenerTcpSocket); }
using namespace tcpip;
// If a connection is accepted, the corresponding socket will be assigned to the new socket
socket_t connSocket = 0;
// sockaddr clientSockAddr = {};
// socklen_t connectorSockAddrLen = 0;
sockaddr clientSockAddr = {};
socklen_t connectorSockAddrLen = 0;
int retval = 0;
// Listen for connection requests permanently for lifetime of program
@@ -121,8 +121,7 @@ TcpTmTcServer::~TcpTmTcServer() { closeSocket(listenerTcpSocket); }
continue;
}
// connSocket = accept(listenerTcpSocket, &clientSockAddr, &connectorSockAddrLen);
connSocket = accept(listenerTcpSocket, nullptr, nullptr);
connSocket = accept(listenerTcpSocket, &clientSockAddr, &connectorSockAddrLen);
if (connSocket == INVALID_SOCKET) {
handleError(Protocol::TCP, ErrorSources::ACCEPT_CALL, 500);
@@ -137,6 +136,7 @@ TcpTmTcServer::~TcpTmTcServer() { closeSocket(listenerTcpSocket); }
if (retval != 0) {
handleError(Protocol::TCP, ErrorSources::SHUTDOWN_CALL);
}
closeSocket(connSocket);
connSocket = 0;
}
+17 -48
View File
@@ -1,27 +1,23 @@
#include "fsfw/osal/freertos/FixedTimeslotTask.h"
#include "fsfw/objectmanager/ObjectManager.h"
#include "fsfw/serviceinterface/ServiceInterface.h"
#include "fsfw/serviceinterface.h"
uint32_t FixedTimeslotTask::deadlineMissedCount = 0;
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = configMINIMAL_STACK_SIZE;
FixedTimeslotTask::FixedTimeslotTask(TaskName name, TaskPriority setPriority,
TaskStackSize setStack, TaskPeriod overallPeriod,
void (*setDeadlineMissedFunc)())
: started(false), handle(nullptr), pst(overallPeriod * 1000) {
TaskStackSize setStack, TaskPeriod period,
TaskDeadlineMissedFunction dlmFunc_)
: FixedTimeslotTaskBase(period, dlmFunc_), started(false), handle(nullptr) {
configSTACK_DEPTH_TYPE stackSize = setStack / sizeof(configSTACK_DEPTH_TYPE);
xTaskCreate(taskEntryPoint, name, stackSize, this, setPriority, &handle);
// All additional attributes are applied to the object.
this->deadlineMissedFunc = setDeadlineMissedFunc;
}
FixedTimeslotTask::~FixedTimeslotTask() {}
FixedTimeslotTask::~FixedTimeslotTask() = default;
void FixedTimeslotTask::taskEntryPoint(void* argument) {
// The argument is re-interpreted as FixedTimeslotTask. The Task object is
// global, so it is found from any place.
FixedTimeslotTask* originalTask(reinterpret_cast<FixedTimeslotTask*>(argument));
auto* originalTask(reinterpret_cast<FixedTimeslotTask*>(argument));
/* Task should not start until explicitly requested,
* but in FreeRTOS, tasks start as soon as they are created if the scheduler
* is running but not if the scheduler is not running.
@@ -32,26 +28,18 @@ void FixedTimeslotTask::taskEntryPoint(void* argument) {
* can continue */
if (not originalTask->started) {
vTaskSuspend(NULL);
vTaskSuspend(nullptr);
}
originalTask->taskFunctionality();
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "Polling task " << originalTask->handle << " returned from taskFunctionality."
<< std::endl;
#else
sif::printDebug("Polling task returned from taskFunctionality\n");
#endif
}
void FixedTimeslotTask::missedDeadlineCounter() {
FixedTimeslotTask::deadlineMissedCount++;
if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "PST missed " << FixedTimeslotTask::deadlineMissedCount << " deadlines"
<< std::endl;
#endif
}
}
ReturnValue_t FixedTimeslotTask::startTask() {
started = true;
@@ -63,31 +51,12 @@ ReturnValue_t FixedTimeslotTask::startTask() {
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, uint32_t slotTimeMs,
int8_t executionStep) {
ExecutableObjectIF* handler = ObjectManager::instance()->get<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() {
[[noreturn]] void FixedTimeslotTask::taskFunctionality() {
// A local iterator for the Polling Sequence Table is created to find the
// start time for the first entry.
auto slotListIter = pst.current;
auto slotListIter = pollingSeqTable.current;
pst.intializeSequenceAfterTaskCreation();
pollingSeqTable.intializeSequenceAfterTaskCreation();
// The start time for the first entry is read.
uint32_t intervalMs = slotListIter->pollingTimeMs;
@@ -108,10 +77,10 @@ void FixedTimeslotTask::taskFunctionality() {
/* Enter the loop that defines the task behavior. */
for (;;) {
// The component for this slot is executed and the next one is chosen.
this->pst.executeAndAdvance();
if (not pst.slotFollowsImmediately()) {
this->pollingSeqTable.executeAndAdvance();
if (not pollingSeqTable.slotFollowsImmediately()) {
// Get the interval till execution of the next slot.
intervalMs = this->pst.getIntervalToPreviousSlotMs();
intervalMs = this->pollingSeqTable.getIntervalToPreviousSlotMs();
interval = pdMS_TO_TICKS(intervalMs);
#if (tskKERNEL_VERSION_MAJOR == 10 && tskKERNEL_VERSION_MINOR >= 4) || tskKERNEL_VERSION_MAJOR > 10
@@ -132,8 +101,8 @@ void FixedTimeslotTask::taskFunctionality() {
}
void FixedTimeslotTask::handleMissedDeadline() {
if (deadlineMissedFunc != nullptr) {
this->deadlineMissedFunc();
if (dlmFunc != nullptr) {
dlmFunc();
}
}
+7 -35
View File
@@ -4,11 +4,11 @@
#include "FreeRTOS.h"
#include "FreeRTOSTaskIF.h"
#include "fsfw/tasks/FixedSlotSequence.h"
#include "fsfw/tasks/FixedTimeslotTaskIF.h"
#include "fsfw/tasks/Typedef.h"
#include "fsfw/tasks/FixedTimeslotTaskBase.h"
#include "fsfw/tasks/definitions.h"
#include "task.h"
class FixedTimeslotTask : public FixedTimeslotTaskIF, public FreeRTOSTaskIF {
class FixedTimeslotTask : public FixedTimeslotTaskBase, public FreeRTOSTaskIF {
public:
/**
* Keep in mind that you need to call before vTaskStartScheduler()!
@@ -23,7 +23,7 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF, public FreeRTOSTaskIF {
* @return Pointer to the newly created task.
*/
FixedTimeslotTask(TaskName name, TaskPriority setPriority, TaskStackSize setStack,
TaskPeriod overallPeriod, void (*setDeadlineMissedFunc)());
TaskPeriod overallPeriod, TaskDeadlineMissedFunction dlmFunc);
/**
* @brief The destructor of the class.
@@ -32,26 +32,9 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF, public FreeRTOSTaskIF {
* initialization for the PST and the device handlers. This is done by
* calling the PST's destructor.
*/
virtual ~FixedTimeslotTask(void);
~FixedTimeslotTask() override;
ReturnValue_t startTask(void);
/**
* This static function can be used as #deadlineMissedFunc.
* It counts missedDeadlines and prints the number of missed deadlines
* every 10th time.
*/
static void missedDeadlineCounter();
/**
* A helper variable to count missed deadlines.
*/
static uint32_t deadlineMissedCount;
ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs,
int8_t executionStep) override;
uint32_t getPeriodMs() const override;
ReturnValue_t checkSequence() const override;
ReturnValue_t startTask() override;
ReturnValue_t sleepFor(uint32_t ms) override;
@@ -61,17 +44,6 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF, public FreeRTOSTaskIF {
bool started;
TaskHandle_t handle;
FixedSlotSequence pst;
/**
* @brief This attribute holds a function pointer that is executed when
* a deadline was missed.
* @details
* Another function may be announced to determine the actions to perform
* when a deadline was missed. Currently, only one function for missing
* any deadline is allowed. If not used, it shall be declared NULL.
*/
void (*deadlineMissedFunc)(void);
/**
* @brief This is the entry point for a new task.
* @details
@@ -88,7 +60,7 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF, public FreeRTOSTaskIF {
* It links the functionalities provided by FixedSlotSequence with the
* OS's System Calls to keep the timing of the periods.
*/
void taskFunctionality(void);
[[noreturn]] void taskFunctionality();
void handleMissedDeadline();
};
+2 -2
View File
@@ -6,11 +6,11 @@
class FreeRTOSTaskIF {
public:
virtual ~FreeRTOSTaskIF() {}
virtual ~FreeRTOSTaskIF() = default;
virtual TaskHandle_t getTaskHandle() = 0;
protected:
bool checkMissedDeadline(const TickType_t xLastWakeTime, const TickType_t interval) {
static bool checkMissedDeadline(const TickType_t xLastWakeTime, const TickType_t interval) {
/* Check whether deadline was missed while also taking overflows
* into account. Drawing this on paper with a timeline helps to understand
* it. */
+16 -39
View File
@@ -5,27 +5,28 @@
#include "fsfw/tasks/ExecutableObjectIF.h"
PeriodicTask::PeriodicTask(const char* name, TaskPriority setPriority, TaskStackSize setStack,
TaskPeriod setPeriod, TaskDeadlineMissedFunction deadlineMissedFunc)
: started(false), handle(NULL), period(setPeriod), deadlineMissedFunc(deadlineMissedFunc) {
TaskPeriod setPeriod, TaskDeadlineMissedFunction dlmFunc_)
: PeriodicTaskBase(setPeriod, dlmFunc_), started(false), handle(nullptr) {
configSTACK_DEPTH_TYPE stackSize = setStack / sizeof(configSTACK_DEPTH_TYPE);
BaseType_t status = xTaskCreate(taskEntryPoint, name, stackSize, this, setPriority, &handle);
if (status != pdPASS) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "PeriodicTask Insufficient heap memory remaining. "
"Status: "
sif::debug << "PeriodicTask::PeriodicTask Insufficient heap memory remaining. Status: "
<< status << std::endl;
#else
sif::printDebug("PeriodicTask::PeriodicTask: Insufficient heap memory remaining. Status: %d\n",
status);
#endif
}
}
PeriodicTask::~PeriodicTask(void) {
// Do not delete objects, we were responsible for ptrs only.
}
// Do not delete objects, we were responsible for ptrs only.
PeriodicTask::~PeriodicTask() = default;
void PeriodicTask::taskEntryPoint(void* argument) {
// The argument is re-interpreted as PeriodicTask. The Task object is
// global, so it is found from any place.
PeriodicTask* originalTask(reinterpret_cast<PeriodicTask*>(argument));
auto* originalTask(reinterpret_cast<PeriodicTask*>(argument));
/* Task should not start until explicitly requested,
* but in FreeRTOS, tasks start as soon as they are created if the scheduler
* is running but not if the scheduler is not running.
@@ -36,7 +37,7 @@ void PeriodicTask::taskEntryPoint(void* argument) {
* can continue */
if (not originalTask->started) {
vTaskSuspend(NULL);
vTaskSuspend(nullptr);
}
originalTask->taskFunctionality();
@@ -62,13 +63,11 @@ ReturnValue_t PeriodicTask::sleepFor(uint32_t ms) {
return HasReturnvaluesIF::RETURN_OK;
}
void PeriodicTask::taskFunctionality() {
[[noreturn]] void PeriodicTask::taskFunctionality() {
TickType_t xLastWakeTime;
const TickType_t xPeriod = pdMS_TO_TICKS(this->period * 1000.);
for (auto const& object : objectList) {
object->initializeAfterTaskCreation();
}
initObjsAfterTaskCreation();
/* The xLastWakeTime variable needs to be initialized with the current tick
count. Note that this is the only time the variable is written to
@@ -77,8 +76,8 @@ void PeriodicTask::taskFunctionality() {
xLastWakeTime = xTaskGetTickCount();
/* Enter the loop that defines the task behavior. */
for (;;) {
for (auto const& object : objectList) {
object->performOperation();
for (auto const& objectPair : objectList) {
objectPair.first->performOperation(objectPair.second);
}
#if (tskKERNEL_VERSION_MAJOR == 10 && tskKERNEL_VERSION_MINOR >= 4) || tskKERNEL_VERSION_MAJOR > 10
@@ -95,32 +94,10 @@ void PeriodicTask::taskFunctionality() {
}
}
ReturnValue_t PeriodicTask::addComponent(object_id_t object) {
ExecutableObjectIF* newObject = ObjectManager::instance()->get<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; }
void PeriodicTask::handleMissedDeadline() {
if (deadlineMissedFunc != nullptr) {
this->deadlineMissedFunc();
if (dlmFunc != nullptr) {
dlmFunc();
}
}
+5 -48
View File
@@ -6,8 +6,8 @@
#include "FreeRTOS.h"
#include "FreeRTOSTaskIF.h"
#include "fsfw/objectmanager/ObjectManagerIF.h"
#include "fsfw/tasks/PeriodicTaskIF.h"
#include "fsfw/tasks/Typedef.h"
#include "fsfw/tasks/PeriodicTaskBase.h"
#include "fsfw/tasks/definitions.h"
#include "task.h"
class ExecutableObjectIF;
@@ -17,7 +17,7 @@ class ExecutableObjectIF;
* periodic activities of multiple objects.
* @ingroup task_handling
*/
class PeriodicTask : public PeriodicTaskIF, public FreeRTOSTaskIF {
class PeriodicTask : public PeriodicTaskBase, public FreeRTOSTaskIF {
public:
/**
* Keep in Mind that you need to call before this vTaskStartScheduler()!
@@ -43,7 +43,7 @@ class PeriodicTask : public PeriodicTaskIF, public FreeRTOSTaskIF {
* @brief Currently, the executed object's lifetime is not coupled with
* the task object's lifetime, so the destructor is empty.
*/
virtual ~PeriodicTask(void);
~PeriodicTask() override;
/**
* @brief The method to start the task.
@@ -53,27 +53,6 @@ class PeriodicTask : public PeriodicTaskIF, public FreeRTOSTaskIF {
* to the system call.
*/
ReturnValue_t startTask() override;
/**
* Adds an object to the list of objects to be executed.
* The objects are executed in the order added.
* @param object Id of the object to add.
* @return
* -@c RETURN_OK on success
* -@c RETURN_FAILED if the object could not be added.
*/
ReturnValue_t addComponent(object_id_t object) override;
/**
* Adds an object to the list of objects to be executed.
* The objects are executed in the order added.
* @param object Id of the object to add.
* @return
* -@c RETURN_OK on success
* -@c RETURN_FAILED if the object could not be added.
*/
ReturnValue_t addComponent(ExecutableObjectIF* object) override;
uint32_t getPeriodMs() const override;
ReturnValue_t sleepFor(uint32_t ms) override;
@@ -83,28 +62,6 @@ class PeriodicTask : public PeriodicTaskIF, public FreeRTOSTaskIF {
bool started;
TaskHandle_t handle;
//! Typedef for the List of objects.
typedef std::vector<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.
* @details
@@ -125,7 +82,7 @@ class PeriodicTask : public PeriodicTaskIF, public FreeRTOSTaskIF {
* the next period.
* On missing the deadline, the deadlineMissedFunction is executed.
*/
void taskFunctionality(void);
[[noreturn]] void taskFunctionality();
void handleMissedDeadline();
};
+12 -38
View File
@@ -3,9 +3,7 @@
#include <chrono>
#include <thread>
#include "fsfw/ipc/MutexFactory.h"
#include "fsfw/objectmanager/ObjectManager.h"
#include "fsfw/osal/host/FixedTimeslotTask.h"
#include "fsfw/osal/host/Mutex.h"
#include "fsfw/osal/host/taskHelpers.h"
#include "fsfw/platform.h"
@@ -22,12 +20,8 @@
FixedTimeslotTask::FixedTimeslotTask(const char* name, TaskPriority setPriority,
TaskStackSize setStack, TaskPeriod setPeriod,
void (*setDeadlineMissedFunc)())
: started(false),
pollingSeqTable(setPeriod * 1000),
taskName(name),
period(setPeriod),
deadlineMissedFunc(setDeadlineMissedFunc) {
TaskDeadlineMissedFunction dlmFunc_)
: FixedTimeslotTaskBase(setPeriod, dlmFunc_), started(false), taskName(name) {
// It is propably possible to set task priorities by using the native
// task handles for Windows / Linux
mainThread = std::thread(&FixedTimeslotTask::taskEntryPoint, this, this);
@@ -39,7 +33,7 @@ FixedTimeslotTask::FixedTimeslotTask(const char* name, TaskPriority setPriority,
tasks::insertTaskName(mainThread.get_id(), taskName);
}
FixedTimeslotTask::~FixedTimeslotTask(void) {
FixedTimeslotTask::~FixedTimeslotTask() {
// Do not delete objects, we were responsible for ptrs only.
terminateThread = true;
if (mainThread.joinable()) {
@@ -48,7 +42,7 @@ FixedTimeslotTask::~FixedTimeslotTask(void) {
}
void FixedTimeslotTask::taskEntryPoint(void* argument) {
FixedTimeslotTask* originalTask(reinterpret_cast<FixedTimeslotTask*>(argument));
auto* originalTask(reinterpret_cast<FixedTimeslotTask*>(argument));
if (not originalTask->started) {
// we have to suspend/block here until the task is started.
@@ -81,7 +75,9 @@ ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) {
}
void FixedTimeslotTask::taskFunctionality() {
pollingSeqTable.intializeSequenceAfterTaskCreation();
ReturnValue_t result = pollingSeqTable.intializeSequenceAfterTaskCreation();
// Ignore returnvalue for now
static_cast<void>(result);
// A local iterator for the Polling Sequence Table is created to
// find the start time for the first entry.
@@ -106,37 +102,15 @@ void FixedTimeslotTask::taskFunctionality() {
// we need to wait before executing the current slot
// this gives us the time to wait:
interval = chron_ms(this->pollingSeqTable.getIntervalToPreviousSlotMs());
delayForInterval(&currentStartTime, interval);
// TODO deadline missed check
if (not delayForInterval(&currentStartTime, interval)) {
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 shouldDelay = false;
// Get current wakeup time
+11 -45
View File
@@ -6,10 +6,10 @@
#include <thread>
#include <vector>
#include "../../objectmanager/ObjectManagerIF.h"
#include "../../tasks/FixedSlotSequence.h"
#include "../../tasks/FixedTimeslotTaskIF.h"
#include "../../tasks/Typedef.h"
#include "fsfw/objectmanager/ObjectManagerIF.h"
#include "fsfw/tasks/FixedSlotSequence.h"
#include "fsfw/tasks/FixedTimeslotTaskBase.h"
#include "fsfw/tasks/definitions.h"
class ExecutableObjectIF;
@@ -19,7 +19,7 @@ class ExecutableObjectIF;
* @details
* @ingroup task_handling
*/
class FixedTimeslotTask : public FixedTimeslotTaskIF {
class FixedTimeslotTask : public FixedTimeslotTaskBase {
public:
/**
* @brief Standard constructor of the class.
@@ -39,7 +39,7 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF {
* @brief Currently, the executed object's lifetime is not coupled with
* the task object's lifetime, so the destructor is empty.
*/
virtual ~FixedTimeslotTask(void);
~FixedTimeslotTask() override;
/**
* @brief The method to start the task.
@@ -48,56 +48,22 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF {
* The address of the task object is passed as an argument
* to the system call.
*/
ReturnValue_t startTask(void);
ReturnValue_t startTask() override;
/**
* Add timeslot to the polling sequence table.
* @param componentId
* @param slotTimeMs
* @param executionStep
* @return
*/
ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs, int8_t executionStep);
ReturnValue_t checkSequence() const override;
uint32_t getPeriodMs() const;
ReturnValue_t sleepFor(uint32_t ms);
ReturnValue_t sleepFor(uint32_t ms) override;
protected:
using chron_ms = std::chrono::milliseconds;
bool started;
//!< Typedef for the List of objects.
typedef std::vector<ExecutableObjectIF*> ObjectList;
std::thread mainThread;
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::mutex initMutex;
std::string taskName;
/**
* @brief The period of the task.
* @details
* The period determines the frequency of the task's execution.
* It is expressed in clock ticks.
*/
TaskPeriod period;
/**
* @brief The pointer to the deadline-missed function.
* @details
* This pointer stores the function that is executed if the task's deadline
* is missed. So, each may react individually on a timing failure.
* The pointer may be NULL, then nothing happens on missing the deadline.
* The deadline is equal to the next execution of the periodic task.
*/
void (*deadlineMissedFunc)(void);
/**
* @brief This is the function executed in the new task's context.
* @details
@@ -117,9 +83,9 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF {
* the checkAndRestartPeriod system call blocks the task until the next
* period. On missing the deadline, the deadlineMissedFunction is executed.
*/
void taskFunctionality(void);
void taskFunctionality();
bool delayForInterval(chron_ms* previousWakeTimeMs, const chron_ms interval);
static bool delayForInterval(chron_ms* previousWakeTimeMs, chron_ms interval);
};
#endif /* FRAMEWORK_OSAL_HOST_FIXEDTIMESLOTTASK_H_ */
+9 -32
View File
@@ -3,13 +3,10 @@
#include <chrono>
#include <thread>
#include "fsfw/ipc/MutexFactory.h"
#include "fsfw/objectmanager/ObjectManager.h"
#include "fsfw/osal/host/Mutex.h"
#include "fsfw/osal/host/taskHelpers.h"
#include "fsfw/platform.h"
#include "fsfw/serviceinterface/ServiceInterface.h"
#include "fsfw/tasks/ExecutableObjectIF.h"
#if defined(PLATFORM_WIN)
#include <processthreadsapi.h>
@@ -20,8 +17,8 @@
#endif
PeriodicTask::PeriodicTask(const char* name, TaskPriority setPriority, TaskStackSize setStack,
TaskPeriod setPeriod, void (*setDeadlineMissedFunc)())
: started(false), taskName(name), period(setPeriod), deadlineMissedFunc(setDeadlineMissedFunc) {
TaskPeriod setPeriod, TaskDeadlineMissedFunction dlmFunc_)
: PeriodicTaskBase(setPeriod, dlmFunc_), started(false), taskName(name) {
// It is probably possible to set task priorities by using the native
// task handles for Windows / Linux
mainThread = std::thread(&PeriodicTask::taskEntryPoint, this, this);
@@ -33,7 +30,7 @@ PeriodicTask::PeriodicTask(const char* name, TaskPriority setPriority, TaskStack
tasks::insertTaskName(mainThread.get_id(), taskName);
}
PeriodicTask::~PeriodicTask(void) {
PeriodicTask::~PeriodicTask() {
// Do not delete objects, we were responsible for ptrs only.
terminateThread = true;
if (mainThread.joinable()) {
@@ -42,7 +39,7 @@ PeriodicTask::~PeriodicTask(void) {
}
void PeriodicTask::taskEntryPoint(void* argument) {
PeriodicTask* originalTask(reinterpret_cast<PeriodicTask*>(argument));
auto* originalTask(reinterpret_cast<PeriodicTask*>(argument));
if (not originalTask->started) {
// we have to suspend/block here until the task is started.
@@ -75,47 +72,27 @@ ReturnValue_t PeriodicTask::sleepFor(uint32_t ms) {
}
void PeriodicTask::taskFunctionality() {
for (const auto& object : objectList) {
object->initializeAfterTaskCreation();
}
initObjsAfterTaskCreation();
std::chrono::milliseconds periodChrono(static_cast<uint32_t>(period * 1000));
auto currentStartTime{std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch())};
auto nextStartTime{currentStartTime};
/* Enter the loop that defines the task behavior. */
for (;;) {
if (terminateThread.load()) {
break;
}
for (const auto& object : objectList) {
object->performOperation();
for (const auto& objectPair : objectList) {
objectPair.first->performOperation(objectPair.second);
}
if (not delayForInterval(&currentStartTime, periodChrono)) {
if (deadlineMissedFunc != nullptr) {
this->deadlineMissedFunc();
if (dlmFunc != nullptr) {
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 shouldDelay = false;
// Get current wakeup time
+12 -55
View File
@@ -6,9 +6,9 @@
#include <thread>
#include <vector>
#include "../../objectmanager/ObjectManagerIF.h"
#include "../../tasks/PeriodicTaskIF.h"
#include "../../tasks/Typedef.h"
#include "fsfw/objectmanager/ObjectManagerIF.h"
#include "fsfw/tasks/PeriodicTaskBase.h"
#include "fsfw/tasks/definitions.h"
class ExecutableObjectIF;
@@ -19,7 +19,7 @@ class ExecutableObjectIF;
*
* @ingroup task_handling
*/
class PeriodicTask : public PeriodicTaskIF {
class PeriodicTask : public PeriodicTaskBase {
public:
/**
* @brief Standard constructor of the class.
@@ -34,12 +34,12 @@ class PeriodicTask : public PeriodicTaskIF {
* assigned.
*/
PeriodicTask(const char* name, TaskPriority setPriority, TaskStackSize setStack,
TaskPeriod setPeriod, void (*setDeadlineMissedFunc)());
TaskPeriod setPeriod, TaskDeadlineMissedFunction dlmFunc);
/**
* @brief Currently, the executed object's lifetime is not coupled with
* the task object's lifetime, so the destructor is empty.
*/
virtual ~PeriodicTask(void);
~PeriodicTask() override;
/**
* @brief The method to start the task.
@@ -48,63 +48,20 @@ class PeriodicTask : public PeriodicTaskIF {
* The address of the task object is passed as an argument
* to the system call.
*/
ReturnValue_t startTask(void);
/**
* Adds an object to the list of objects to be executed.
* The objects are executed in the order added.
* @param object Id of the object to add.
* @return
* -@c RETURN_OK on success
* -@c RETURN_FAILED if the object could not be added.
*/
ReturnValue_t addComponent(object_id_t object);
ReturnValue_t startTask() override;
/**
* Adds an object to the list of objects to be executed.
* The objects are executed in the order added.
* @param object pointer to the object to add.
* @return
* -@c RETURN_OK on success
* -@c RETURN_FAILED if the object could not be added.
*/
ReturnValue_t addComponent(ExecutableObjectIF* object);
uint32_t getPeriodMs() const;
ReturnValue_t sleepFor(uint32_t ms);
ReturnValue_t sleepFor(uint32_t ms) override;
protected:
using chron_ms = std::chrono::milliseconds;
bool started;
//!< Typedef for the List of objects.
typedef std::vector<ExecutableObjectIF*> ObjectList;
std::thread mainThread;
std::atomic<bool> terminateThread{false};
/**
* @brief This attribute holds a list of objects to be executed.
*/
ObjectList objectList;
std::condition_variable initCondition;
std::mutex initMutex;
std::string taskName;
/**
* @brief The period of the task.
* @details
* The period determines the frequency of the task's execution.
* It is expressed in clock ticks.
*/
TaskPeriod period;
/**
* @brief The pointer to the deadline-missed function.
* @details
* This pointer stores the function that is executed if the task's deadline
* is missed. So, each may react individually on a timing failure.
* The pointer may be NULL, then nothing happens on missing the deadline.
* The deadline is equal to the next execution of the periodic task.
*/
void (*deadlineMissedFunc)(void);
/**
* @brief This is the function executed in the new task's context.
* @details
@@ -124,9 +81,9 @@ class PeriodicTask : public PeriodicTaskIF {
* the checkAndRestartPeriod system call blocks the task until the next
* period. On missing the deadline, the deadlineMissedFunction is executed.
*/
void taskFunctionality(void);
void taskFunctionality();
bool delayForInterval(chron_ms* previousWakeTimeMs, const chron_ms interval);
static bool delayForInterval(chron_ms* previousWakeTimeMs, chron_ms interval);
};
#endif /* PERIODICTASK_H_ */
#endif /* FRAMEWORK_OSAL_HOST_PERIODICTASK_H_ */
+2 -2
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
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = 0;
TaskFactory::TaskFactory() {}
TaskFactory::TaskFactory() = default;
TaskFactory::~TaskFactory() {}
TaskFactory::~TaskFactory() = default;
TaskFactory* TaskFactory::instance() { return TaskFactory::factoryInstance; }
+1 -1
View File
@@ -6,7 +6,7 @@
std::mutex nameMapLock;
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);
auto returnPair = taskNameMap.emplace(threadId, taskName);
if (not returnPair.second) {
+1 -1
View File
@@ -7,7 +7,7 @@
namespace tasks {
ReturnValue_t insertTaskName(std::thread::id threadId, std::string taskName);
ReturnValue_t insertTaskName(std::thread::id threadId, const std::string& taskName);
std::string getTaskName(std::thread::id threadId);
} // namespace tasks
+21 -50
View File
@@ -1,22 +1,20 @@
#include "fsfw/osal/linux/FixedTimeslotTask.h"
#include <limits.h>
#include <climits>
#include "fsfw/objectmanager/ObjectManager.h"
#include "fsfw/serviceinterface/ServiceInterface.h"
uint32_t FixedTimeslotTask::deadlineMissedCount = 0;
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = PTHREAD_STACK_MIN;
FixedTimeslotTask::FixedTimeslotTask(const char* name_, int priority_, size_t stackSize_,
uint32_t periodMs_)
: PosixThread(name_, priority_, stackSize_), pst(periodMs_), started(false) {}
FixedTimeslotTask::~FixedTimeslotTask() {}
FixedTimeslotTask::FixedTimeslotTask(const char* name_, TaskPriority priority_, size_t stackSize_,
TaskPeriod periodSeconds_, TaskDeadlineMissedFunction dlmFunc_)
: FixedTimeslotTaskBase(periodSeconds_, dlmFunc_),
posixThread(name_, priority_, stackSize_),
started(false) {}
void* FixedTimeslotTask::taskEntryPoint(void* arg) {
// The argument is re-interpreted as PollingTask.
FixedTimeslotTask* originalTask(reinterpret_cast<FixedTimeslotTask*>(arg));
auto* originalTask(reinterpret_cast<FixedTimeslotTask*>(arg));
// The task's functionality is called.
originalTask->taskFunctionality();
return nullptr;
@@ -24,7 +22,7 @@ void* FixedTimeslotTask::taskEntryPoint(void* arg) {
ReturnValue_t FixedTimeslotTask::startTask() {
started = true;
createTask(&taskEntryPoint, this);
posixThread.createTask(&taskEntryPoint, this);
return HasReturnvaluesIF::RETURN_OK;
}
@@ -32,63 +30,36 @@ ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) {
return PosixThread::sleep((uint64_t)ms * 1000000);
}
uint32_t FixedTimeslotTask::getPeriodMs() const { return pst.getLengthMs(); }
ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, uint32_t slotTimeMs,
int8_t executionStep) {
ExecutableObjectIF* executableObject =
ObjectManager::instance()->get<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() {
[[noreturn]] void FixedTimeslotTask::taskFunctionality() {
// Like FreeRTOS pthreads are running as soon as they are created
if (!started) {
suspend();
posixThread.suspend();
}
pst.intializeSequenceAfterTaskCreation();
// Returnvalue ignored for now
static_cast<void>(pollingSeqTable.intializeSequenceAfterTaskCreation());
// The start time for the first entry is read.
uint64_t lastWakeTime = getCurrentMonotonicTimeMs();
uint64_t interval = pst.getIntervalToNextSlotMs();
uint64_t lastWakeTime = PosixThread::getCurrentMonotonicTimeMs();
uint32_t interval = 0;
// The task's "infinite" inner loop is entered.
while (1) {
if (pst.slotFollowsImmediately()) {
while (true) {
if (pollingSeqTable.slotFollowsImmediately()) {
// Do nothing
} else {
// The interval for the next polling slot is selected.
interval = this->pst.getIntervalToPreviousSlotMs();
interval = pollingSeqTable.getIntervalToPreviousSlotMs();
// The period is checked and restarted with the new interval.
// If the deadline was missed, the deadlineMissedFunc is called.
if (!PosixThread::delayUntil(&lastWakeTime, interval)) {
// No time left on timer -> we missed the deadline
missedDeadlineCounter();
if(dlmFunc != nullptr){
dlmFunc();
}
}
}
// The device handler for this slot is executed and the next one is chosen.
this->pst.executeAndAdvance();
}
}
void FixedTimeslotTask::missedDeadlineCounter() {
FixedTimeslotTask::deadlineMissedCount++;
if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "PST missed " << FixedTimeslotTask::deadlineMissedCount << " deadlines"
<< std::endl;
#endif
pollingSeqTable.executeAndAdvance();
}
}
+13 -28
View File
@@ -3,11 +3,12 @@
#include <pthread.h>
#include "../../tasks/FixedSlotSequence.h"
#include "../../tasks/FixedTimeslotTaskIF.h"
#include "PosixThread.h"
#include "fsfw/tasks/FixedSlotSequence.h"
#include "fsfw/tasks/FixedTimeslotTaskBase.h"
#include "fsfw/tasks/definitions.h"
class FixedTimeslotTask : public FixedTimeslotTaskIF, public PosixThread {
class FixedTimeslotTask : public FixedTimeslotTaskBase {
public:
/**
* Create a generic periodic task.
@@ -21,29 +22,13 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF, public PosixThread {
* @param period_
* @param deadlineMissedFunc_
*/
FixedTimeslotTask(const char* name_, int priority_, size_t stackSize_, uint32_t periodMs_);
virtual ~FixedTimeslotTask();
FixedTimeslotTask(const char* name_, TaskPriority priority_, size_t stackSize_,
TaskPeriod periodSeconds_, TaskDeadlineMissedFunction dlmFunc_);
~FixedTimeslotTask() override = default;
virtual ReturnValue_t startTask();
ReturnValue_t startTask() override;
virtual ReturnValue_t sleepFor(uint32_t ms);
virtual uint32_t getPeriodMs() const;
virtual ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs, int8_t executionStep);
virtual ReturnValue_t checkSequence() const;
/**
* This static function can be used as #deadlineMissedFunc.
* It counts missedDeadlines and prints the number of missed deadlines every 10th time.
*/
static void missedDeadlineCounter();
/**
* A helper variable to count missed deadlines.
*/
static uint32_t deadlineMissedCount;
ReturnValue_t sleepFor(uint32_t ms) override;
protected:
/**
@@ -53,9 +38,12 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF, public PosixThread {
* It links the functionalities provided by FixedSlotSequence with the
* OS's System Calls to keep the timing of the periods.
*/
virtual void taskFunctionality();
[[noreturn]] virtual void taskFunctionality();
private:
PosixThread posixThread;
bool started;
/**
* @brief This is the entry point in a new thread.
*
@@ -68,9 +56,6 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF, public PosixThread {
* arbitrary data.
*/
static void* taskEntryPoint(void* arg);
FixedSlotSequence pst;
bool started;
};
#endif /* FSFW_OSAL_LINUX_FIXEDTIMESLOTTASK_H_ */
+24 -56
View File
@@ -1,86 +1,54 @@
#include "fsfw/osal/linux/PeriodicPosixTask.h"
#include "PeriodicPosixTask.h"
#include <errno.h>
#include "fsfw/objectmanager/ObjectManager.h"
#include "fsfw/serviceinterface/ServiceInterface.h"
#include "fsfw/serviceinterface.h"
#include "fsfw/tasks/ExecutableObjectIF.h"
PeriodicPosixTask::PeriodicPosixTask(const char* name_, int priority_, size_t stackSize_,
uint32_t period_, void(deadlineMissedFunc_)())
: PosixThread(name_, priority_, stackSize_),
objectList(),
started(false),
periodMs(period_),
deadlineMissedFunc(deadlineMissedFunc_) {}
PeriodicPosixTask::~PeriodicPosixTask() {
// Not Implemented
}
TaskPeriod period_, TaskDeadlineMissedFunction dlmFunc_)
: PeriodicTaskBase(period_, dlmFunc_),
posixThread(name_, priority_, stackSize_),
started(false) {}
void* PeriodicPosixTask::taskEntryPoint(void* arg) {
// The argument is re-interpreted as PollingTask.
PeriodicPosixTask* originalTask(reinterpret_cast<PeriodicPosixTask*>(arg));
auto* originalTask(reinterpret_cast<PeriodicPosixTask*>(arg));
// The task's functionality is called.
originalTask->taskFunctionality();
return NULL;
}
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;
return nullptr;
}
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;
PosixThread::createTask(&taskEntryPoint, this);
posixThread.createTask(&taskEntryPoint, this);
return HasReturnvaluesIF::RETURN_OK;
}
void PeriodicPosixTask::taskFunctionality(void) {
[[noreturn]] void PeriodicPosixTask::taskFunctionality() {
if (not started) {
suspend();
posixThread.suspend();
}
for (auto const& object : objectList) {
object->initializeAfterTaskCreation();
}
initObjsAfterTaskCreation();
uint64_t lastWakeTime = getCurrentMonotonicTimeMs();
uint64_t lastWakeTime = PosixThread::getCurrentMonotonicTimeMs();
uint64_t periodMs = getPeriodMs();
// The task's "infinite" inner loop is entered.
while (1) {
for (auto const& object : objectList) {
object->performOperation();
while (true) {
for (auto const& objOpCodePair : objectList) {
objOpCodePair.first->performOperation(objOpCodePair.second);
}
if (not PosixThread::delayUntil(&lastWakeTime, periodMs)) {
if (this->deadlineMissedFunc != nullptr) {
this->deadlineMissedFunc();
if (dlmFunc != nullptr) {
dlmFunc();
}
}
}
}
uint32_t PeriodicPosixTask::getPeriodMs() const { return periodMs; }
+10 -42
View File
@@ -3,12 +3,13 @@
#include <vector>
#include "../../objectmanager/ObjectManagerIF.h"
#include "../../tasks/ExecutableObjectIF.h"
#include "../../tasks/PeriodicTaskIF.h"
#include "PosixThread.h"
#include "fsfw/objectmanager/ObjectManagerIF.h"
#include "fsfw/tasks/ExecutableObjectIF.h"
#include "fsfw/tasks/PeriodicTaskBase.h"
#include "fsfw/tasks/PeriodicTaskIF.h"
class PeriodicPosixTask : public PosixThread, public PeriodicTaskIF {
class PeriodicPosixTask : public PeriodicTaskBase {
public:
/**
* Create a generic periodic task.
@@ -22,9 +23,9 @@ class PeriodicPosixTask : public PosixThread, public PeriodicTaskIF {
* @param period_
* @param deadlineMissedFunc_
*/
PeriodicPosixTask(const char* name_, int priority_, size_t stackSize_, uint32_t period_,
void (*deadlineMissedFunc_)());
virtual ~PeriodicPosixTask();
PeriodicPosixTask(const char* name_, int priority_, size_t stackSize_, TaskPeriod period_,
TaskDeadlineMissedFunction dlmFunc_);
~PeriodicPosixTask() override = default;
/**
* @brief The method to start the task.
@@ -34,42 +35,17 @@ class PeriodicPosixTask : public PosixThread, public PeriodicTaskIF {
* to the system call.
*/
ReturnValue_t startTask() override;
/**
* Adds an object to the list of objects to be executed.
* The objects are executed in the order added.
* @param object Id of the object to add.
* @return RETURN_OK on success, RETURN_FAILED if the object could not be added.
*/
ReturnValue_t addComponent(object_id_t object) override;
/**
* Adds an object to the list of objects to be executed.
* The objects are executed in the order added.
* @param object pointer to the object to add.
* @return RETURN_OK on success, RETURN_FAILED if the object could not be added.
*/
ReturnValue_t addComponent(ExecutableObjectIF* object) override;
uint32_t getPeriodMs() const override;
ReturnValue_t sleepFor(uint32_t ms) override;
private:
typedef std::vector<ExecutableObjectIF*> ObjectList; //!< Typedef for the List of objects.
/**
* @brief This attribute holds a list of objects to be executed.
*/
ObjectList objectList;
PosixThread posixThread;
/**
* @brief Flag to indicate that the task was started and is allowed to run
*/
bool started;
/**
* @brief Period of the task in milliseconds
*/
uint32_t periodMs;
/**
* @brief The function containing the actual functionality of the task.
* @details The method sets and starts
@@ -78,7 +54,7 @@ class PeriodicPosixTask : public PosixThread, public PeriodicTaskIF {
* will be blocked until the next period. On missing the deadline, the deadlineMissedFunction is
* executed.
*/
virtual void taskFunctionality(void);
[[noreturn]] virtual void taskFunctionality();
/**
* @brief This is the entry point in a new thread.
*
@@ -86,14 +62,6 @@ class PeriodicPosixTask : public PosixThread, public PeriodicTaskIF {
* of the child class. Needs a valid pointer to the derived class.
*/
static void* taskEntryPoint(void* arg);
/**
* @brief The pointer to the deadline-missed function.
* @details This pointer stores the function that is executed if the task's deadline is missed.
* So, each may react individually on a timing failure. The pointer may be
* NULL, then nothing happens on missing the deadline. The deadline is equal to the next execution
* of the periodic task.
*/
void (*deadlineMissedFunc)();
};
#endif /* FRAMEWORK_OSAL_LINUX_PERIODICPOSIXTASK_H_ */
+15 -15
View File
@@ -35,6 +35,21 @@ class PosixThread {
*/
void resume();
/**
* @brief Function that has to be called by derived class because the
* derived class pointer has to be valid as argument.
* @details
* This function creates a pthread with the given parameters. As the
* function requires a pointer to the derived object it has to be called
* after the this pointer of the derived object is valid.
* Sets the taskEntryPoint as function to be called by new a thread.
* @param fnc_ Function which will be executed by the thread.
* @param arg_
* argument of the taskEntryPoint function, needs to be this pointer
* of derived class
*/
void createTask(void* (*fnc_)(void*), void* arg_);
/**
* Delay function similar to FreeRtos delayUntil function
*
@@ -55,21 +70,6 @@ class PosixThread {
protected:
pthread_t thread;
/**
* @brief Function that has to be called by derived class because the
* derived class pointer has to be valid as argument.
* @details
* This function creates a pthread with the given parameters. As the
* function requires a pointer to the derived object it has to be called
* after the this pointer of the derived object is valid.
* Sets the taskEntryPoint as function to be called by new a thread.
* @param fnc_ Function which will be executed by the thread.
* @param arg_
* argument of the taskEntryPoint function, needs to be this pointer
* of derived class
*/
void createTask(void* (*fnc_)(void*), void* arg_);
private:
char name[PTHREAD_MAX_NAMELEN];
int priority;
+4 -3
View File
@@ -8,21 +8,22 @@
// TODO: Different variant than the lazy loading in QueueFactory. What's better and why?
TaskFactory* TaskFactory::factoryInstance = new TaskFactory();
TaskFactory::~TaskFactory() {}
TaskFactory::~TaskFactory() = default;
TaskFactory* TaskFactory::instance() { return TaskFactory::factoryInstance; }
PeriodicTaskIF* TaskFactory::createPeriodicTask(
TaskName name_, TaskPriority taskPriority_, TaskStackSize stackSize_,
TaskPeriod periodInSeconds_, TaskDeadlineMissedFunction deadLineMissedFunction_) {
return new PeriodicPosixTask(name_, taskPriority_, stackSize_, periodInSeconds_ * 1000,
return new PeriodicPosixTask(name_, taskPriority_, stackSize_, periodInSeconds_,
deadLineMissedFunction_);
}
FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask(
TaskName name_, TaskPriority taskPriority_, TaskStackSize stackSize_,
TaskPeriod periodInSeconds_, TaskDeadlineMissedFunction deadLineMissedFunction_) {
return new FixedTimeslotTask(name_, taskPriority_, stackSize_, periodInSeconds_ * 1000);
return new FixedTimeslotTask(name_, taskPriority_, stackSize_, periodInSeconds_,
deadLineMissedFunction_);
}
ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) {
+16 -55
View File
@@ -1,42 +1,32 @@
#include "fsfw/osal/rtems/FixedTimeslotTask.h"
#include <rtems/bspIo.h>
#include <rtems/io.h>
#include <rtems/rtems/ratemon.h>
#include <rtems/rtems/status.h>
#include <rtems/rtems/tasks.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/returnvalues/HasReturnvaluesIF.h"
#include "fsfw/serviceinterface/ServiceInterface.h"
#include "fsfw/tasks/FixedSequenceSlot.h"
#if FSFW_CPP_OSTREAM_ENABLED == 1
#include <iostream>
#endif
#include <cstddef>
#include <list>
uint32_t FixedTimeslotTask::deadlineMissedCount = 0;
FixedTimeslotTask::FixedTimeslotTask(const char *name, rtems_task_priority setPriority,
size_t setStack, uint32_t setOverallPeriod,
void (*setDeadlineMissedFunc)(void))
: RTEMSTaskBase(setPriority, setStack, name), periodId(0), pst(setOverallPeriod) {
// All additional attributes are applied to the object.
this->deadlineMissedFunc = setDeadlineMissedFunc;
}
size_t setStack, TaskPeriod setOverallPeriod,
TaskDeadlineMissedFunction dlmFunc_)
: FixedTimeslotTaskBase(setOverallPeriod, dlmFunc_),
RTEMSTaskBase(setPriority, setStack, name),
periodId(0) {}
FixedTimeslotTask::~FixedTimeslotTask() {}
FixedTimeslotTask::~FixedTimeslotTask() = default;
rtems_task FixedTimeslotTask::taskEntryPoint(rtems_task_argument argument) {
/* The argument is re-interpreted as a FixedTimeslotTask */
FixedTimeslotTask *originalTask(reinterpret_cast<FixedTimeslotTask *>(argument));
auto *originalTask(reinterpret_cast<FixedTimeslotTask *>(argument));
/* The task's functionality is called. */
return originalTask->taskFunctionality();
/* Should never be reached */
@@ -46,16 +36,6 @@ rtems_task FixedTimeslotTask::taskEntryPoint(rtems_task_argument argument) {
#endif
}
void FixedTimeslotTask::missedDeadlineCounter() {
FixedTimeslotTask::deadlineMissedCount++;
if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "PST missed " << FixedTimeslotTask::deadlineMissedCount << " deadlines"
<< std::endl;
#endif
}
}
ReturnValue_t FixedTimeslotTask::startTask() {
rtems_status_code status =
rtems_task_start(id, FixedTimeslotTask::taskEntryPoint, rtems_task_argument((void *)this));
@@ -79,54 +59,35 @@ ReturnValue_t FixedTimeslotTask::startTask() {
}
}
ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, uint32_t slotTimeMs,
int8_t executionStep) {
ExecutableObjectIF *object = ObjectManager::instance()->get<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() {
[[noreturn]] void FixedTimeslotTask::taskFunctionality() {
/* A local iterator for the Polling Sequence Table is created to find the start time for
the first entry. */
FixedSlotSequence::SlotListIter it = pst.current;
auto it = pollingSeqTable.current;
/* Initialize the PST with the correct calling task */
pst.intializeSequenceAfterTaskCreation();
pollingSeqTable.intializeSequenceAfterTaskCreation();
/* The start time for the first entry is read. */
rtems_interval interval = RtemsBasic::convertMsToTicks(it->pollingTimeMs);
RTEMSTaskBase::setAndStartPeriod(interval, &periodId);
// The task's "infinite" inner loop is entered.
while (1) {
if (pst.slotFollowsImmediately()) {
while (true) {
if (pollingSeqTable.slotFollowsImmediately()) {
/* Do nothing */
} else {
/* The interval for the next polling slot is selected. */
interval = RtemsBasic::convertMsToTicks(this->pst.getIntervalToNextSlotMs());
interval = RtemsBasic::convertMsToTicks(pollingSeqTable.getIntervalToNextSlotMs());
/* The period is checked and restarted with the new interval.
If the deadline was missed, the deadlineMissedFunc is called. */
rtems_status_code status = RTEMSTaskBase::restartPeriod(interval, periodId);
if (status == RTEMS_TIMEOUT) {
if (this->deadlineMissedFunc != nullptr) {
this->deadlineMissedFunc();
if (dlmFunc != nullptr) {
dlmFunc();
}
}
}
/* The device handler for this slot is executed and the next one is chosen. */
this->pst.executeAndAdvance();
this->pollingSeqTable.executeAndAdvance();
}
}
+7 -34
View File
@@ -1,11 +1,11 @@
#ifndef FSFW_OSAL_RTEMS_FIXEDTIMESLOTTASK_H_
#define FSFW_OSAL_RTEMS_FIXEDTIMESLOTTASK_H_
#include "../../tasks/FixedSlotSequence.h"
#include "../../tasks/FixedTimeslotTaskIF.h"
#include "RTEMSTaskBase.h"
#include "fsfw/tasks/FixedSlotSequence.h"
#include "fsfw/tasks/FixedTimeslotTaskBase.h"
class FixedTimeslotTask : public RTEMSTaskBase, public FixedTimeslotTaskIF {
class FixedTimeslotTask : public FixedTimeslotTaskBase, public RTEMSTaskBase {
public:
/**
* @brief The standard constructor of the class.
@@ -17,7 +17,7 @@ class FixedTimeslotTask : public RTEMSTaskBase, public FixedTimeslotTaskIF {
* @param getPst The object id of the completely initialized polling sequence.
*/
FixedTimeslotTask(const char *name, rtems_task_priority setPriority, size_t setStackSize,
uint32_t overallPeriod, void (*setDeadlineMissedFunc)());
TaskPeriod overallPeriod, TaskDeadlineMissedFunction dlmFunc);
/**
* @brief The destructor of the class.
@@ -25,44 +25,17 @@ class FixedTimeslotTask : public RTEMSTaskBase, public FixedTimeslotTaskIF {
* The destructor frees all heap memory that was allocated on thread initialization
* for the PST andthe device handlers. This is done by calling the PST's destructor.
*/
virtual ~FixedTimeslotTask(void);
~FixedTimeslotTask() override;
ReturnValue_t startTask(void);
/**
* This static function can be used as #deadlineMissedFunc.
* It counts missedDeadlines and prints the number of missed deadlines every 10th time.
*/
static void missedDeadlineCounter();
/**
* A helper variable to count missed deadlines.
*/
static uint32_t deadlineMissedCount;
ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs, int8_t executionStep);
uint32_t getPeriodMs() const;
ReturnValue_t checkSequence() const;
ReturnValue_t sleepFor(uint32_t ms);
ReturnValue_t sleepFor(uint32_t ms) override;
protected:
/**
* @brief id of the associated OS period
*/
rtems_id periodId;
FixedSlotSequence pst;
/**
* @brief This attribute holds a function pointer that is executed when a deadline was missed.
*
* @details
* Another function may be announced to determine the actions to perform when a deadline
* was missed. Currently, only one function for missing any deadline is allowed.
* If not used, it shall be declared NULL.
*/
void (*deadlineMissedFunc)(void) = nullptr;
/**
* @brief This is the entry point in a new polling thread.
* @details This method is the entry point in the new thread
@@ -76,7 +49,7 @@ class FixedTimeslotTask : public RTEMSTaskBase, public FixedTimeslotTaskIF {
* It links the functionalities provided by FixedSlotSequence with the OS's system calls to
* keep the timing of the periods.
*/
void taskFunctionality(void);
[[noreturn]] void taskFunctionality();
};
#endif /* FSFW_OSAL_RTEMS_FIXEDTIMESLOTTASK_H_ */
+1 -1
View File
@@ -65,7 +65,7 @@ ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, MessageQueu
}
ReturnValue_t returnCode = convertReturnCode(result);
if (result == MessageQueueIF::EMPTY) {
if (returnCode == MessageQueueIF::EMPTY) {
return HasReturnvaluesIF::RETURN_FAILED;
}
+9 -8
View File
@@ -36,9 +36,9 @@ class MessageQueue : public MessageQueueBase {
* @param max_message_size With this parameter, the maximum message size can be adjusted.
* This should be left default.
*/
MessageQueue(size_t message_depth = 3,
size_t max_message_size = MessageQueueMessage::MAX_MESSAGE_SIZE,
MqArgs* args = nullptr);
explicit MessageQueue(size_t message_depth = 3,
size_t max_message_size = MessageQueueMessage::MAX_MESSAGE_SIZE,
MqArgs* args = nullptr);
/** Copying message queues forbidden */
MessageQueue(const MessageQueue&) = delete;
@@ -48,18 +48,19 @@ class MessageQueue : public MessageQueueBase {
* @brief The destructor deletes the formerly created message queue.
* @details This is accomplished by using the delete call provided by the operating system.
*/
virtual ~MessageQueue();
~MessageQueue() override;
// Implement non-generic MessageQueueIF functions not handled by MessageQueueBase
ReturnValue_t flush(uint32_t* count) override;
ReturnValue_t receiveMessage(MessageQueueMessageIF* message) override;
ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
MessageQueueId_t sentFrom = NO_QUEUE,
bool ignoreFault = false) override;
MessageQueueId_t sentFrom, bool ignoreFault) override;
private:
/**
* \brief This attribute stores a reference to the internal error reporter for reporting full
* queues. \details In the event of a full destination queue, the reporter will be notified. The
* @brief This attribute stores a reference to the internal error reporter for reporting full
* queues. @details In the event of a full destination queue, the reporter will be notified. The
* reference is set by lazy loading
*/
InternalErrorReporterIF* internalErrorReporter;
+18 -34
View File
@@ -5,12 +5,12 @@
#include "fsfw/tasks/ExecutableObjectIF.h"
PeriodicTask::PeriodicTask(const char* name, rtems_task_priority setPriority, size_t setStack,
rtems_interval setPeriod, void (*setDeadlineMissedFunc)())
: RTEMSTaskBase(setPriority, setStack, name),
periodTicks(RtemsBasic::convertMsToTicks(setPeriod)),
deadlineMissedFunc(setDeadlineMissedFunc) {}
TaskPeriod setPeriod, TaskDeadlineMissedFunction dlmFunc_)
: PeriodicTaskBase(setPeriod, dlmFunc_),
RTEMSTaskBase(setPriority, setStack, name),
periodTicks(RtemsBasic::convertMsToTicks(static_cast<uint32_t>(setPeriod * 1000.0))) {}
PeriodicTask::~PeriodicTask(void) {
PeriodicTask::~PeriodicTask() {
/* Do not delete objects, we were responsible for pointers only. */
rtems_rate_monotonic_delete(periodId);
}
@@ -18,7 +18,7 @@ PeriodicTask::~PeriodicTask(void) {
rtems_task PeriodicTask::taskEntryPoint(rtems_task_argument argument) {
/* The argument is re-interpreted as MultiObjectTask. The Task object is global,
so it is found from any place. */
PeriodicTask* originalTask(reinterpret_cast<PeriodicTask*>(argument));
auto* originalTask(reinterpret_cast<PeriodicTask*>(argument));
return originalTask->taskFunctionality();
;
}
@@ -28,8 +28,10 @@ ReturnValue_t PeriodicTask::startTask() {
rtems_task_start(id, PeriodicTask::taskEntryPoint, rtems_task_argument((void*)this));
if (status != RTEMS_SUCCESSFUL) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "ObjectTask::startTask for " << std::hex << this->getId() << std::dec
<< " failed." << std::endl;
sif::error << "PeriodicTask::startTask for " << std::hex << this->getId() << std::dec
<< " failed" << std::endl;
#else
sif::printError("PeriodicTask::startTask for 0x%08x failed\n", getId());
#endif
}
switch (status) {
@@ -47,38 +49,20 @@ ReturnValue_t PeriodicTask::startTask() {
ReturnValue_t PeriodicTask::sleepFor(uint32_t ms) { return RTEMSTaskBase::sleepFor(ms); }
void PeriodicTask::taskFunctionality() {
[[noreturn]] void PeriodicTask::taskFunctionality() {
RTEMSTaskBase::setAndStartPeriod(periodTicks, &periodId);
for (const auto& object : objectList) {
object->initializeAfterTaskCreation();
}
initObjsAfterTaskCreation();
/* The task's "infinite" inner loop is entered. */
while (1) {
for (const auto& object : objectList) {
object->performOperation();
while (true) {
for (const auto& objectPair : objectList) {
objectPair.first->performOperation(objectPair.second);
}
rtems_status_code status = RTEMSTaskBase::restartPeriod(periodTicks, periodId);
if (status == RTEMS_TIMEOUT) {
if (this->deadlineMissedFunc != nullptr) {
this->deadlineMissedFunc();
if (dlmFunc != nullptr) {
dlmFunc();
}
}
}
}
ReturnValue_t PeriodicTask::addComponent(object_id_t object) {
ExecutableObjectIF* newObject = ObjectManager::instance()->get<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); }
+9 -37
View File
@@ -3,9 +3,10 @@
#include <vector>
#include "../../objectmanager/ObjectManagerIF.h"
#include "../../tasks/PeriodicTaskIF.h"
#include "RTEMSTaskBase.h"
#include "fsfw/objectmanager/ObjectManagerIF.h"
#include "fsfw/tasks/PeriodicTaskBase.h"
#include "fsfw/tasks/PeriodicTaskIF.h"
class ExecutableObjectIF;
@@ -18,7 +19,7 @@ class ExecutableObjectIF;
* @author baetz
* @ingroup task_handling
*/
class PeriodicTask : public RTEMSTaskBase, public PeriodicTaskIF {
class PeriodicTask : public PeriodicTaskBase, public RTEMSTaskBase {
public:
/**
* @brief Standard constructor of the class.
@@ -36,12 +37,12 @@ class PeriodicTask : public RTEMSTaskBase, public PeriodicTaskIF {
* that shall be assigned.
*/
PeriodicTask(const char *name, rtems_task_priority setPriority, size_t setStack,
rtems_interval setPeriod, void (*setDeadlineMissedFunc)());
TaskPeriod setPeriod, TaskDeadlineMissedFunction dlmFunc);
/**
* @brief Currently, the executed object's lifetime is not coupled with the task object's
* lifetime, so the destructor is empty.
*/
virtual ~PeriodicTask(void);
~PeriodicTask() override;
/**
* @brief The method to start the task.
@@ -50,33 +51,11 @@ class PeriodicTask : public RTEMSTaskBase, public PeriodicTaskIF {
* The address of the task object is passed as an argument
* to the system call.
*/
ReturnValue_t startTask(void);
/**
* Adds an object to the list of objects to be executed.
* The objects are executed in the order added.
* @param object Id of the object to add.
* @return RETURN_OK on success, RETURN_FAILED if the object could not be added.
*/
ReturnValue_t addComponent(object_id_t object) override;
/**
* Adds an object to the list of objects to be executed.
* The objects are executed in the order added.
* @param object pointer to the object to add.
* @return RETURN_OK on success, RETURN_FAILED if the object could not be added.
*/
ReturnValue_t addComponent(ExecutableObjectIF *object) override;
uint32_t getPeriodMs() const override;
ReturnValue_t startTask() override;
ReturnValue_t sleepFor(uint32_t ms) override;
protected:
typedef std::vector<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.
* @details The period determines the frequency of the task's execution. It is expressed in
@@ -87,14 +66,7 @@ class PeriodicTask : public RTEMSTaskBase, public PeriodicTaskIF {
* @brief id of the associated OS period
*/
rtems_id periodId = 0;
/**
* @brief The pointer to the deadline-missed function.
* @details This pointer stores the function that is executed if the task's deadline is missed.
* So, each may react individually on a timing failure. The pointer may be
* nullptr, then nothing happens on missing the deadline. The deadline is equal to the next
* execution of the periodic task.
*/
void (*deadlineMissedFunc)(void);
/**
* @brief This is the function executed in the new task's context.
* @details It converts the argument back to the thread object type and copies the class
@@ -110,7 +82,7 @@ class PeriodicTask : public RTEMSTaskBase, public PeriodicTaskIF {
* are called. Afterwards the checkAndRestartPeriod system call blocks the task until the next
* period. On missing the deadline, the deadlineMissedFunction is executed.
*/
void taskFunctionality(void);
[[noreturn]] void taskFunctionality();
};
#endif /* FSFW_OSAL_RTEMS_PERIODICTASK_H_ */
+2 -2
View File
@@ -45,9 +45,9 @@ QueueFactory* QueueFactory::instance() {
return factoryInstance;
}
QueueFactory::QueueFactory() {}
QueueFactory::QueueFactory() = default;
QueueFactory::~QueueFactory() {}
QueueFactory::~QueueFactory() = default;
MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, size_t maxMessageSize,
MqArgs* args) {
+1 -1
View File
@@ -32,7 +32,7 @@ RTEMSTaskBase::RTEMSTaskBase(rtems_task_priority set_priority, size_t stack_size
RTEMSTaskBase::~RTEMSTaskBase() { rtems_task_delete(id); }
rtems_id RTEMSTaskBase::getId() { return this->id; }
rtems_id RTEMSTaskBase::getId() const { return this->id; }
ReturnValue_t RTEMSTaskBase::sleepFor(uint32_t ms) {
rtems_status_code status = rtems_task_wake_after(RtemsBasic::convertMsToTicks(ms));
+2 -2
View File
@@ -36,9 +36,9 @@ class RTEMSTaskBase {
/**
* @brief This method returns the task id of this class.
*/
rtems_id getId();
rtems_id getId() const;
ReturnValue_t sleepFor(uint32_t ms);
static ReturnValue_t sleepFor(uint32_t ms);
static ReturnValue_t setAndStartPeriod(rtems_interval period, rtems_id *periodId);
static rtems_status_code restartPeriod(rtems_interval period, rtems_id periodId);
+9 -12
View File
@@ -1,7 +1,6 @@
#include "fsfw/tasks/TaskFactory.h"
#include "fsfw/osal/rtems/FixedTimeslotTask.h"
#include "fsfw/osal/rtems/InitTask.h"
#include "fsfw/osal/rtems/PeriodicTask.h"
#include "fsfw/osal/rtems/RtemsBasic.h"
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
@@ -9,29 +8,29 @@
// TODO: Different variant than the lazy loading in QueueFactory. What's better and why?
TaskFactory* TaskFactory::factoryInstance = new TaskFactory();
TaskFactory::~TaskFactory() {}
TaskFactory::TaskFactory() = default;
TaskFactory::~TaskFactory() = default;
TaskFactory* TaskFactory::instance() { return TaskFactory::factoryInstance; }
PeriodicTaskIF* TaskFactory::createPeriodicTask(
TaskName name_, TaskPriority taskPriority_, TaskStackSize stackSize_,
TaskPeriod periodInSeconds_, TaskDeadlineMissedFunction deadLineMissedFunction_) {
rtems_interval taskPeriod = periodInSeconds_ * Clock::getTicksPerSecond();
return static_cast<PeriodicTaskIF*>(
new PeriodicTask(name_, taskPriority_, stackSize_, taskPeriod, deadLineMissedFunction_));
return static_cast<PeriodicTaskIF*>(new PeriodicTask(name_, taskPriority_, stackSize_,
periodInSeconds_, deadLineMissedFunction_));
}
FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask(
TaskName name_, TaskPriority taskPriority_, TaskStackSize stackSize_,
TaskPeriod periodInSeconds_, TaskDeadlineMissedFunction deadLineMissedFunction_) {
rtems_interval taskPeriod = periodInSeconds_ * Clock::getTicksPerSecond();
return static_cast<FixedTimeslotTaskIF*>(
new FixedTimeslotTask(name_, taskPriority_, stackSize_, taskPeriod, deadLineMissedFunction_));
return static_cast<FixedTimeslotTaskIF*>(new FixedTimeslotTask(
name_, taskPriority_, stackSize_, periodInSeconds_, deadLineMissedFunction_));
}
ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) {
// TODO not implemented
// This should call the OS specific destructor
delete (dynamic_cast<PeriodicTask*>(task));
return HasReturnvaluesIF::RETURN_FAILED;
}
@@ -45,5 +44,3 @@ void TaskFactory::printMissedDeadline() {
/* TODO: Implement */
return;
}
TaskFactory::TaskFactory() {}
+4 -4
View File
@@ -17,28 +17,28 @@ void DummyPowerSwitcher::setInitialFusesList(std::vector<ReturnValue_t> fuseList
}
ReturnValue_t DummyPowerSwitcher::sendSwitchCommand(power::Switch_t switchNr, ReturnValue_t onOff) {
if (switchNr < switcherList.capacity()) {
if (switchNr < switcherList.size()) {
switcherList[switchNr] = onOff;
}
return RETURN_FAILED;
}
ReturnValue_t DummyPowerSwitcher::sendFuseOnCommand(uint8_t fuseNr) {
if (fuseNr < fuseList.capacity()) {
if (fuseNr < fuseList.size()) {
fuseList[fuseNr] = FUSE_ON;
}
return RETURN_FAILED;
}
ReturnValue_t DummyPowerSwitcher::getSwitchState(power::Switch_t switchNr) const {
if (switchNr < switcherList.capacity()) {
if (switchNr < switcherList.size()) {
return switcherList[switchNr];
}
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t DummyPowerSwitcher::getFuseState(uint8_t fuseNr) const {
if (fuseNr < fuseList.capacity()) {
if (fuseNr < fuseList.size()) {
return fuseList[fuseNr];
}
return HasReturnvaluesIF::RETURN_FAILED;
@@ -0,0 +1,203 @@
#ifndef MISSION_PUS_SERVICE11TELECOMMANDSCHEDULING_H_
#define MISSION_PUS_SERVICE11TELECOMMANDSCHEDULING_H_
#include <etl/multimap.h>
#include <fsfw/tmtcservices/PusServiceBase.h>
#include <fsfw/tmtcservices/TmTcMessage.h>
#include "fsfw/FSFW.h"
#include "fsfw/returnvalues/FwClassIds.h"
/**
* @brief: PUS-Service 11 - Telecommand scheduling.
* @details:
* PUS-Service 11 - Telecommand scheduling.
* Full documentation: ECSS-E-ST-70-41C, p. 168:
* ST[11] time-based scheduling
*
* This service provides the capability to command pre-loaded
* application processes (telecommands) by releasing them at their
* due-time.
* References to telecommands are stored together with their due-timepoints
* and are released at their corresponding due-time.
*
* Necessary subservice functionalities are implemented.
* Those are:
* TC[11,4] activity insertion
* TC[11,5] activity deletion
* TC[11,6] filter-based activity deletion
* TC[11,7] activity time-shift
* TC[11,8] filter-based activity time-shift
*
* Groups are not supported.
* This service remains always enabled. Sending a disable-request has no effect.
*/
template <size_t MAX_NUM_TCS>
class Service11TelecommandScheduling final : public PusServiceBase {
public:
static constexpr uint8_t CLASS_ID = CLASS_ID::PUS_SERVICE_11;
static constexpr ReturnValue_t INVALID_TYPE_TIME_WINDOW =
HasReturnvaluesIF::makeReturnCode(CLASS_ID, 1);
static constexpr ReturnValue_t TIMESHIFTING_NOT_POSSIBLE =
HasReturnvaluesIF::makeReturnCode(CLASS_ID, 2);
static constexpr ReturnValue_t INVALID_RELATIVE_TIME =
HasReturnvaluesIF::makeReturnCode(CLASS_ID, 3);
static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PUS_SERVICE_11;
//! [EXPORT] : [COMMENT] Deletion of a TC from the map failed.
//! P1: First 32 bit of request ID, P2. Last 32 bit of Request ID
static constexpr Event TC_DELETION_FAILED = event::makeEvent(SUBSYSTEM_ID, 0, severity::MEDIUM);
// The types of PUS-11 subservices
enum Subservice : uint8_t {
ENABLE_SCHEDULING = 1,
DISABLE_SCHEDULING = 2,
RESET_SCHEDULING = 3,
INSERT_ACTIVITY = 4,
DELETE_ACTIVITY = 5,
FILTER_DELETE_ACTIVITY = 6,
TIMESHIFT_ACTIVITY = 7,
FILTER_TIMESHIFT_ACTIVITY = 8,
DETAIL_REPORT = 9,
TIMEBASE_SCHEDULE_DETAIL_REPORT = 10,
TIMESHIFT_ALL_SCHEDULE_ACTIVITIES = 15
};
// The types of time windows for TC[11,6] and TC[11,8], as defined in ECSS-E-ST-70-41C,
// requirement 8.11.3c (p. 507)
enum TypeOfTimeWindow : uint32_t {
SELECT_ALL = 0,
FROM_TIMETAG_TO_TIMETAG = 1,
FROM_TIMETAG = 2,
TO_TIMETAG = 3
};
Service11TelecommandScheduling(object_id_t objectId, uint16_t apid, uint8_t serviceId,
AcceptsTelecommandsIF* tcRecipient,
uint16_t releaseTimeMarginSeconds = DEFAULT_RELEASE_TIME_MARGIN,
bool debugMode = false);
~Service11TelecommandScheduling() override;
void enableExpiredTcDeletion();
void disableExpiredTcDeletion();
/** PusServiceBase overrides */
ReturnValue_t handleRequest(uint8_t subservice) override;
ReturnValue_t performService() override;
ReturnValue_t initialize() override;
private:
struct TelecommandStruct {
uint64_t requestId{};
uint32_t seconds{};
store_address_t storeAddr; // uint16
};
static constexpr uint16_t DEFAULT_RELEASE_TIME_MARGIN = 5;
// minimum release time offset to insert into schedule
const uint16_t RELEASE_TIME_MARGIN_SECONDS = 5;
/**
* By default, the scheduling will be disabled. This is a standard requirement
*/
bool schedulingEnabled = false;
bool deleteExpiredTcWhenDisabled = true;
bool debugMode = false;
StorageManagerIF* tcStore = nullptr;
AcceptsTelecommandsIF* tcRecipient = nullptr;
MessageQueueId_t recipientMsgQueueId = 0;
/**
* The telecommand map uses the exectution time as a Unix time stamp as
* the key. This is mapped to a generic telecommand struct.
*/
using TelecommandMap = etl::multimap<uint32_t, TelecommandStruct, MAX_NUM_TCS>;
using TcMapIter = typename TelecommandMap::iterator;
TelecommandMap telecommandMap;
ReturnValue_t handleResetCommand();
/**
* @brief Logic to be performed on an incoming TC[11,4].
* @return RETURN_OK if successful
*/
ReturnValue_t doInsertActivity(const uint8_t* data, size_t size);
/**
* @brief Logic to be performed on an incoming TC[11,5].
* @return RETURN_OK if successful
*/
ReturnValue_t doDeleteActivity(const uint8_t* data, size_t size);
/**
* @brief Logic to be performed on an incoming TC[11,6].
* @return RETURN_OK if successful
*/
ReturnValue_t doFilterDeleteActivity(const uint8_t* data, size_t size);
/**
* @brief Logic to be performed on an incoming TC[11,7].
* @return RETURN_OK if successful
*/
ReturnValue_t doTimeshiftActivity(const uint8_t* data, size_t size);
/**
* @brief Logic to be performed on an incoming TC[11,8].
* @return RETURN_OK if successful
*/
ReturnValue_t doFilterTimeshiftActivity(const uint8_t* data, size_t size);
/**
* @brief Extracts the Request ID from the Application Data of a TC by utilizing a ctor of the
* class TcPacketPus.
* NOTE: This only works if the payload data is a TC (e.g. not for TC[11,5] which does not
* send a TC as payload)!
* @param data The Application data of the TC (get via getApplicationData()).
* @return requestId
*/
uint64_t getRequestIdFromDataTC(const uint8_t* data) const;
/**
* @brief Extracts the Request ID from the Application Data directly, assuming it is packed
* as follows (acc. to ECSS): | source ID (uint32) | apid (uint32) | ssc (uint32) |.
* @param data Pointer to first byte described data
* @param dataSize Remaining size of data NOTE: non-const, this is modified by the function
* @param [out] requestId Request ID
* @return RETURN_OK if successful
*/
ReturnValue_t getRequestIdFromData(const uint8_t*& data, size_t& dataSize, uint64_t& requestId);
/**
* @brief Builds the Request ID from its three elements.
* @param sourceId Source ID
* @param apid Application Process ID (APID)
* @param ssc Source Sequence Count
* @return Request ID
*/
[[nodiscard]] uint64_t buildRequestId(uint32_t sourceId, uint16_t apid, uint16_t ssc) const;
/**
* @brief Gets the filter range for filter TCs from a data packet
* @param data TC data
* @param dataSize TC data size
* @param [out] itBegin Begin of filter range
* @param [out] itEnd End of filter range
* @return RETURN_OK if successful
*/
ReturnValue_t getMapFilterFromData(const uint8_t*& data, size_t& size, TcMapIter& itBegin,
TcMapIter& itEnd);
ReturnValue_t handleInvalidData(const char* ctx);
/**
* @brief Prints content of multimap. Use for simple debugging only.
*/
void debugPrintMultimapContent() const;
};
#include "Service11TelecommandScheduling.tpp"
#endif /* MISSION_PUS_SERVICE11TELECOMMANDSCHEDULING_H_ */
@@ -0,0 +1,645 @@
#pragma once
#include <cstddef>
#include "fsfw/objectmanager/ObjectManager.h"
#include "fsfw/serialize/SerializeAdapter.h"
#include "fsfw/serviceinterface.h"
#include "fsfw/tmtcservices/AcceptsTelecommandsIF.h"
static constexpr auto DEF_END = SerializeIF::Endianness::BIG;
template <size_t MAX_NUM_TCS>
inline Service11TelecommandScheduling<MAX_NUM_TCS>::Service11TelecommandScheduling(
object_id_t objectId, uint16_t apid, uint8_t serviceId, AcceptsTelecommandsIF *tcRecipient,
uint16_t releaseTimeMarginSeconds, bool debugMode)
: PusServiceBase(objectId, apid, serviceId),
RELEASE_TIME_MARGIN_SECONDS(releaseTimeMarginSeconds),
debugMode(debugMode),
tcRecipient(tcRecipient) {}
template <size_t MAX_NUM_TCS>
inline Service11TelecommandScheduling<MAX_NUM_TCS>::~Service11TelecommandScheduling() = default;
template <size_t MAX_NUM_TCS>
inline ReturnValue_t Service11TelecommandScheduling<MAX_NUM_TCS>::handleRequest(
uint8_t subservice) {
if (debugMode) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "PUS11::handleRequest: Handling request " << static_cast<int>(subservice);
#else
sif::printInfo("PUS11::handleRequest: Handling request %d\n", subservice);
#endif
}
// Get de-serialized Timestamp
const uint8_t *data = currentPacket.getApplicationData();
size_t size = currentPacket.getApplicationDataSize();
if (data == nullptr) {
return handleInvalidData("handleRequest");
}
switch (subservice) {
case Subservice::ENABLE_SCHEDULING: {
schedulingEnabled = true;
break;
}
case Subservice::DISABLE_SCHEDULING: {
schedulingEnabled = false;
break;
}
case Subservice::RESET_SCHEDULING: {
return handleResetCommand();
}
case Subservice::INSERT_ACTIVITY:
return doInsertActivity(data, size);
case Subservice::DELETE_ACTIVITY:
return doDeleteActivity(data, size);
case Subservice::FILTER_DELETE_ACTIVITY:
return doFilterDeleteActivity(data, size);
case Subservice::TIMESHIFT_ACTIVITY:
return doTimeshiftActivity(data, size);
case Subservice::FILTER_TIMESHIFT_ACTIVITY:
return doFilterTimeshiftActivity(data, size);
default:
return AcceptsTelecommandsIF::INVALID_SUBSERVICE;
}
return RETURN_OK;
}
template <size_t MAX_NUM_TCS>
inline ReturnValue_t Service11TelecommandScheduling<MAX_NUM_TCS>::performService() {
if (not schedulingEnabled) {
return RETURN_OK;
}
// get current time as UNIX timestamp
timeval tNow = {};
Clock::getClock_timeval(&tNow);
// TODO: Optionally limit the max number of released TCs per cycle?
// NOTE: The iterator is increased in the loop here. Increasing the iterator as for-loop arg
// does not work in this case as we are deleting the current element here.
for (auto it = telecommandMap.begin(); it != telecommandMap.end();) {
if (it->first <= tNow.tv_sec) {
if (schedulingEnabled) {
// release tc
TmTcMessage releaseMsg(it->second.storeAddr);
auto sendRet = this->requestQueue->sendMessage(recipientMsgQueueId, &releaseMsg, false);
if (sendRet != HasReturnvaluesIF::RETURN_OK) {
return sendRet;
}
if (debugMode) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "Released TC & erased it from TC map" << std::endl;
#else
sif::printInfo("Released TC & erased it from TC map\n");
#endif
}
telecommandMap.erase(it++);
} else if (deleteExpiredTcWhenDisabled) {
telecommandMap.erase(it++);
}
continue;
}
it++;
}
return HasReturnvaluesIF::RETURN_OK;
}
template <size_t MAX_NUM_TCS>
inline ReturnValue_t Service11TelecommandScheduling<MAX_NUM_TCS>::initialize() {
ReturnValue_t res = PusServiceBase::initialize();
if (res != HasReturnvaluesIF::RETURN_OK) {
return res;
}
tcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TC_STORE);
if (!tcStore) {
return ObjectManagerIF::CHILD_INIT_FAILED;
}
if (tcRecipient == nullptr) {
return ObjectManagerIF::CHILD_INIT_FAILED;
}
recipientMsgQueueId = tcRecipient->getRequestQueue();
return res;
}
template <size_t MAX_NUM_TCS>
inline ReturnValue_t Service11TelecommandScheduling<MAX_NUM_TCS>::handleResetCommand() {
for (auto it = telecommandMap.begin(); it != telecommandMap.end(); it++) {
ReturnValue_t result = tcStore->deleteData(it->second.storeAddr);
if (result != RETURN_OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
// This should not happen
sif::warning << "Service11TelecommandScheduling::handleRequestDeleting: Deletion failed"
<< std::endl;
#else
sif::printWarning("Service11TelecommandScheduling::handleRequestDeleting: Deletion failed\n");
#endif
triggerEvent(TC_DELETION_FAILED, (it->second.requestId >> 32) & 0xffffffff,
it->second.requestId & 0xffffffff);
}
}
telecommandMap.clear();
return RETURN_OK;
}
template <size_t MAX_NUM_TCS>
inline ReturnValue_t Service11TelecommandScheduling<MAX_NUM_TCS>::doInsertActivity(
const uint8_t *data, size_t size) {
uint32_t timestamp = 0;
ReturnValue_t result = SerializeAdapter::deSerialize(&timestamp, &data, &size, DEF_END);
if (result != RETURN_OK) {
return result;
}
// Insert possible if sched. time is above margin
// (See requirement for Time margin)
timeval tNow = {};
Clock::getClock_timeval(&tNow);
if (timestamp - tNow.tv_sec <= RELEASE_TIME_MARGIN_SECONDS) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "Service11TelecommandScheduling::doInsertActivity: Release time too close to "
"current time"
<< std::endl;
#else
sif::printWarning(
"Service11TelecommandScheduling::doInsertActivity: Release time too close to current "
"time\n");
#endif
return RETURN_FAILED;
}
// store currentPacket and receive the store address
store_address_t addr{};
if (tcStore->addData(&addr, data, size) != RETURN_OK ||
addr.raw == storeId::INVALID_STORE_ADDRESS) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "Service11TelecommandScheduling::doInsertActivity: Adding data to TC Store failed"
<< std::endl;
#else
sif::printError(
"Service11TelecommandScheduling::doInsertActivity: Adding data to TC Store failed\n");
#endif
return RETURN_FAILED;
}
// insert into multimap with new store address
TelecommandStruct tc;
tc.seconds = timestamp;
tc.storeAddr = addr;
tc.requestId =
getRequestIdFromDataTC(data); // TODO: Missing sanity check of the returned request id
auto it = telecommandMap.insert(std::pair<uint32_t, TelecommandStruct>(timestamp, tc));
if (it == telecommandMap.end()) {
return RETURN_FAILED;
}
if (debugMode) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "PUS11::doInsertActivity: Inserted into Multimap:" << std::endl;
#else
sif::printInfo("PUS11::doInsertActivity: Inserted into Multimap:\n");
#endif
debugPrintMultimapContent();
}
return HasReturnvaluesIF::RETURN_OK;
}
template <size_t MAX_NUM_TCS>
inline ReturnValue_t Service11TelecommandScheduling<MAX_NUM_TCS>::doDeleteActivity(
const uint8_t *data, size_t size) {
// Get request ID
uint64_t requestId;
ReturnValue_t result = getRequestIdFromData(data, size, requestId);
if (result != RETURN_OK) {
return result;
}
// DEBUG
if (debugMode) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "PUS11::doDeleteActivity: requestId: " << requestId << std::endl;
#else
sif::printInfo("PUS11::doDeleteActivity: requestId: %d\n", requestId);
#endif
}
TcMapIter tcToDelete; // handle to the TC to be deleted, can be used if counter is valid
int tcToDeleteCount = 0; // counter of all found TCs. Should be 1.
for (auto it = telecommandMap.begin(); it != telecommandMap.end(); it++) {
if (it->second.requestId == requestId) {
tcToDelete = it;
tcToDeleteCount++;
}
}
// check if 1 explicit TC is found via request ID
if (tcToDeleteCount == 0 || tcToDeleteCount > 1) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "Service11TelecommandScheduling::doDeleteActivity: No or more than 1 TC found. "
"Cannot explicitly delete TC"
<< std::endl;
#else
sif::printWarning(
"Service11TelecommandScheduling::doDeleteActivity: No or more than 1 TC found. "
"Cannot explicitly delete TC");
#endif
return RETURN_FAILED;
}
// delete packet from store
if (tcStore->deleteData(tcToDelete->second.storeAddr) != RETURN_OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "Service11TelecommandScheduling::doDeleteActivity: Could not delete TC from Store"
<< std::endl;
#else
sif::printError(
"Service11TelecommandScheduling::doDeleteActivity: Could not delete TC from Store\n");
#endif
return RETURN_FAILED;
}
telecommandMap.erase(tcToDelete);
if (debugMode) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "PUS11::doDeleteActivity: Deleted TC from map" << std::endl;
#else
sif::printInfo("PUS11::doDeleteActivity: Deleted TC from map\n");
#endif
}
return RETURN_OK;
}
template <size_t MAX_NUM_TCS>
inline ReturnValue_t Service11TelecommandScheduling<MAX_NUM_TCS>::doFilterDeleteActivity(
const uint8_t *data, size_t size) {
TcMapIter itBegin;
TcMapIter itEnd;
ReturnValue_t result = getMapFilterFromData(data, size, itBegin, itEnd);
// get the filter window as map range via dedicated method
if (result != RETURN_OK) {
return result;
}
int deletedTCs = 0;
for (TcMapIter it = itBegin; it != itEnd; it++) {
// delete packet from store
if (tcStore->deleteData(it->second.storeAddr) != RETURN_OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "Service11TelecommandScheduling::doFilterDeleteActivity: Could not delete TC "
"from Store"
<< std::endl;
#else
sif::printError(
"Service11TelecommandScheduling::doFilterDeleteActivity: Could not delete TC from "
"Store\n");
#endif
continue;
}
deletedTCs++;
}
// NOTE: Spec says this function erases all elements including itBegin but not itEnd,
// see here: https://www.cplusplus.com/reference/map/multimap/erase/
// Therefore we need to increase itEnd by 1. (Note that end() returns the "past-the-end" iterator)
if (itEnd != telecommandMap.end()) {
itEnd++;
}
telecommandMap.erase(itBegin, itEnd);
if (debugMode) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "PUS11::doFilterDeleteActivity: Deleted " << deletedTCs << " TCs" << std::endl;
#else
sif::printInfo("PUS11::doFilterDeleteActivity: Deleted %d TCs\n", deletedTCs);
#endif
}
return RETURN_OK;
}
template <size_t MAX_NUM_TCS>
inline ReturnValue_t Service11TelecommandScheduling<MAX_NUM_TCS>::doTimeshiftActivity(
const uint8_t *data, size_t size) {
// Get relative time
uint32_t relativeTime = 0;
ReturnValue_t result = SerializeAdapter::deSerialize(&relativeTime, &data, &size, DEF_END);
if (result != RETURN_OK) {
return result;
}
if (relativeTime == 0) {
return INVALID_RELATIVE_TIME;
}
// TODO further check sanity of the relative time?
// Get request ID
uint64_t requestId;
result = getRequestIdFromData(data, size, requestId);
if (result != RETURN_OK) {
return result;
}
if (debugMode) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "PUS11::doTimeshiftActivity: requestId: " << requestId << std::endl;
#else
sif::printInfo("PUS11::doTimeshiftActivity: requestId: %d\n", requestId);
#endif
}
// NOTE: Despite having C++17 ETL multimap has no member function extract :(
TcMapIter tcToTimeshiftIt;
int tcToTimeshiftCount = 0;
for (auto it = telecommandMap.begin(); it != telecommandMap.end(); it++) {
if (it->second.requestId == requestId) {
tcToTimeshiftIt = it;
tcToTimeshiftCount++;
}
}
if (tcToTimeshiftCount == 0 || tcToTimeshiftCount > 1) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "Service11TelecommandScheduling::doTimeshiftActivity: Either 0 or more than 1 "
"TCs found. No explicit timeshifting "
"possible"
<< std::endl;
#else
sif::printWarning(
"Service11TelecommandScheduling::doTimeshiftActivity: Either 0 or more than 1 TCs found. "
"No explicit timeshifting possible\n");
#endif
return TIMESHIFTING_NOT_POSSIBLE;
}
// temporarily hold the item
TelecommandStruct tempTc(tcToTimeshiftIt->second);
uint32_t tempKey = tcToTimeshiftIt->first + relativeTime;
// delete old entry from the mm
telecommandMap.erase(tcToTimeshiftIt);
// and then insert it again as new entry
telecommandMap.insert(std::make_pair(tempKey, tempTc));
if (debugMode) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "PUS11::doTimeshiftActivity: Shifted TC" << std::endl;
#else
sif::printDebug("PUS11::doTimeshiftActivity: Shifted TC\n");
#endif
debugPrintMultimapContent();
}
return RETURN_OK;
}
template <size_t MAX_NUM_TCS>
inline ReturnValue_t Service11TelecommandScheduling<MAX_NUM_TCS>::doFilterTimeshiftActivity(
const uint8_t *data, size_t size) {
// Get relative time
uint32_t relativeTime = 0;
ReturnValue_t result = SerializeAdapter::deSerialize(&relativeTime, &data, &size, DEF_END);
if (result != RETURN_OK) {
return result;
}
if (relativeTime == 0) {
return INVALID_RELATIVE_TIME;
}
// Do time window
TcMapIter itBegin;
TcMapIter itEnd;
result = getMapFilterFromData(data, size, itBegin, itEnd);
if (result != RETURN_OK) {
return result;
}
int shiftedItemsCount = 0;
for (auto it = itBegin; it != itEnd;) {
// temporarily hold the item
TelecommandStruct tempTc(it->second);
uint32_t tempKey = it->first + relativeTime;
// delete the old entry from the mm
telecommandMap.erase(it++);
// and then insert it again as new entry
telecommandMap.insert(std::make_pair(tempKey, tempTc));
shiftedItemsCount++;
}
if (debugMode) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "PUS11::doFilterTimeshiftActivity: shiftedItemsCount: " << shiftedItemsCount
<< std::endl;
#else
sif::printInfo("PUS11::doFilterTimeshiftActivity: shiftedItemsCount: %d\n", shiftedItemsCount);
#endif
debugPrintMultimapContent();
}
if (shiftedItemsCount > 0) {
return RETURN_OK;
}
return RETURN_FAILED;
}
template <size_t MAX_NUM_TCS>
inline uint64_t Service11TelecommandScheduling<MAX_NUM_TCS>::getRequestIdFromDataTC(
const uint8_t *data) const {
TcPacketPus mask(data);
uint32_t sourceId = mask.getSourceId();
uint16_t apid = mask.getAPID();
uint16_t sequenceCount = mask.getPacketSequenceCount();
return buildRequestId(sourceId, apid, sequenceCount);
}
template <size_t MAX_NUM_TCS>
inline ReturnValue_t Service11TelecommandScheduling<MAX_NUM_TCS>::getRequestIdFromData(
const uint8_t *&data, size_t &dataSize, uint64_t &requestId) {
uint32_t srcId = 0;
uint16_t apid = 0;
uint16_t ssc = 0;
ReturnValue_t result = SerializeAdapter::deSerialize(&srcId, &data, &dataSize, DEF_END);
if (result != RETURN_OK) {
return result;
}
result = SerializeAdapter::deSerialize(&apid, &data, &dataSize, DEF_END);
if (result != RETURN_OK) {
return result;
}
result = SerializeAdapter::deSerialize(&ssc, &data, &dataSize, DEF_END);
if (result != RETURN_OK) {
return result;
}
requestId = buildRequestId(srcId, apid, ssc);
return RETURN_OK;
}
template <size_t MAX_NUM_TCS>
inline uint64_t Service11TelecommandScheduling<MAX_NUM_TCS>::buildRequestId(uint32_t sourceId,
uint16_t apid,
uint16_t ssc) const {
auto sourceId64 = static_cast<uint64_t>(sourceId);
auto apid64 = static_cast<uint64_t>(apid);
auto ssc64 = static_cast<uint64_t>(ssc);
return (sourceId64 << 32) | (apid64 << 16) | ssc64;
}
template <size_t MAX_NUM_TCS>
inline ReturnValue_t Service11TelecommandScheduling<MAX_NUM_TCS>::getMapFilterFromData(
const uint8_t *&data, size_t &dataSize, TcMapIter &itBegin, TcMapIter &itEnd) {
// get filter type first
uint32_t typeRaw = 0;
ReturnValue_t result = SerializeAdapter::deSerialize(&typeRaw, &data, &dataSize, DEF_END);
if (result != RETURN_OK) {
return result;
}
if (typeRaw > 3) {
return INVALID_TYPE_TIME_WINDOW;
}
auto type = static_cast<TypeOfTimeWindow>(typeRaw);
// we now have the type of delete activity - so now we set the range to delete,
// according to the type of time window.
// NOTE: Blocks are used in this switch-case statement so that timestamps can be
// cleanly redefined for each case.
switch (type) {
case TypeOfTimeWindow::SELECT_ALL: {
itBegin = telecommandMap.begin();
itEnd = telecommandMap.end();
break;
}
case TypeOfTimeWindow::FROM_TIMETAG: {
uint32_t fromTimestamp = 0;
result = SerializeAdapter::deSerialize(&fromTimestamp, &data, &dataSize, DEF_END);
if (result != RETURN_OK) {
return result;
}
itBegin = telecommandMap.begin();
while (itBegin->first < fromTimestamp && itBegin != telecommandMap.end()) {
itBegin++;
}
itEnd = telecommandMap.end();
break;
}
case TypeOfTimeWindow::TO_TIMETAG: {
uint32_t toTimestamp;
result = SerializeAdapter::deSerialize(&toTimestamp, &data, &dataSize, DEF_END);
if (result != RETURN_OK) {
return result;
}
itBegin = telecommandMap.begin();
itEnd = telecommandMap.begin();
while (itEnd->first <= toTimestamp && itEnd != telecommandMap.end()) {
itEnd++;
}
break;
}
case TypeOfTimeWindow::FROM_TIMETAG_TO_TIMETAG: {
uint32_t fromTimestamp;
uint32_t toTimestamp;
result = SerializeAdapter::deSerialize(&fromTimestamp, &data, &dataSize,
SerializeIF::Endianness::BIG);
if (result != RETURN_OK) {
return result;
}
result = SerializeAdapter::deSerialize(&toTimestamp, &data, &dataSize,
SerializeIF::Endianness::BIG);
if (result != RETURN_OK) {
return result;
}
itBegin = telecommandMap.begin();
itEnd = telecommandMap.begin();
while (itBegin->first < fromTimestamp && itBegin != telecommandMap.end()) {
itBegin++;
}
while (itEnd->first <= toTimestamp && itEnd != telecommandMap.end()) {
itEnd++;
}
break;
}
default:
return RETURN_FAILED;
}
// additional security check, this should never be true
if (itBegin->first > itEnd->first) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
#else
sif::printError("11::GetMapFilterFromData: itBegin > itEnd\n");
#endif
return RETURN_FAILED;
}
// the map range should now be set according to the sent filter.
return RETURN_OK;
}
template <size_t MAX_NUM_TCS>
inline ReturnValue_t Service11TelecommandScheduling<MAX_NUM_TCS>::handleInvalidData(
const char *ctx) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "Service11TelecommandScheduling:: " << ctx << ": Invalid buffer" << std::endl;
#else
sif::printWarning("Service11TelecommandScheduling::%s: Invalid buffer\n", ctx);
#endif
#endif
return RETURN_FAILED;
}
template <size_t MAX_NUM_TCS>
inline void Service11TelecommandScheduling<MAX_NUM_TCS>::debugPrintMultimapContent() const {
#if FSFW_DISABLE_PRINTOUT == 0
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "Service11TelecommandScheduling::debugPrintMultimapContent: Multimap Content"
<< std::endl;
#else
sif::printDebug("Service11TelecommandScheduling::debugPrintMultimapContent: Multimap Content\n");
#endif
for (const auto &dit : telecommandMap) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "[" << dit.first << "]: Request ID: " << dit.second.requestId << " | "
<< "Store Address: " << dit.second.storeAddr.raw << std::endl;
#else
sif::printDebug("[%d]: Request ID: %d | Store Address: %d\n", dit.first, dit.second.requestId,
dit.second.storeAddr);
#endif
}
#endif
}
template <size_t MAX_NUM_TCS>
inline void Service11TelecommandScheduling<MAX_NUM_TCS>::enableExpiredTcDeletion() {
deleteExpiredTcWhenDisabled = true;
}
template <size_t MAX_NUM_TCS>
inline void Service11TelecommandScheduling<MAX_NUM_TCS>::disableExpiredTcDeletion() {
deleteExpiredTcWhenDisabled = false;
}
+1 -1
View File
@@ -85,7 +85,7 @@ ReturnValue_t Service5EventReporting::handleRequest(uint8_t subservice) {
// In addition to the default PUSServiceBase initialization, this service needs
// to be registered to the event manager to listen for events.
ReturnValue_t Service5EventReporting::initialize() {
EventManagerIF* manager = ObjectManager::instance()->get<EventManagerIF>(objects::EVENT_MANAGER);
auto* manager = ObjectManager::instance()->get<EventManagerIF>(objects::EVENT_MANAGER);
if (manager == nullptr) {
return RETURN_FAILED;
}
+1
View File
@@ -72,6 +72,7 @@ enum : uint8_t {
DLE_ENCODER, // DLEE
PUS_SERVICE_3, // PUS3
PUS_SERVICE_9, // PUS9
PUS_SERVICE_11, // PUS11
FILE_SYSTEM, // FILS
LINUX_OSAL, // UXOS
HAL_SPI, // HSPI
+1 -1
View File
@@ -13,7 +13,7 @@ StorageAccessor::StorageAccessor(store_address_t storeId, StorageManagerIF* stor
StorageAccessor& StorageAccessor::operator=(StorageAccessor&& other) {
// Call the parent move assignment and also assign own member.
dataPointer = other.dataPointer;
StorageAccessor::operator=(std::move(other));
ConstStorageAccessor::operator=(std::move(other));
return *this;
}
+3 -2
View File
@@ -1,2 +1,3 @@
target_sources(${LIB_FSFW_NAME} PRIVATE FixedSequenceSlot.cpp
FixedSlotSequence.cpp)
target_sources(
${LIB_FSFW_NAME} PRIVATE FixedSequenceSlot.cpp FixedSlotSequence.cpp
PeriodicTaskBase.cpp FixedTimeslotTaskBase.cpp)
+10 -7
View File
@@ -29,7 +29,7 @@ void FixedSlotSequence::executeAndAdvance() {
uint32_t FixedSlotSequence::getIntervalToNextSlotMs() {
uint32_t oldTime;
SlotListIter slotListIter = current;
auto slotListIter = current;
// Get the pollingTimeMs of the current slot object.
oldTime = slotListIter->pollingTimeMs;
// Advance to the next object.
@@ -51,7 +51,7 @@ uint32_t FixedSlotSequence::getIntervalToNextSlotMs() {
uint32_t FixedSlotSequence::getIntervalToPreviousSlotMs() {
uint32_t currentTime;
SlotListIter slotListIter = current;
auto slotListIter = current;
// Get the pollingTimeMs of the current slot object.
currentTime = slotListIter->pollingTimeMs;
@@ -67,7 +67,7 @@ uint32_t FixedSlotSequence::getIntervalToPreviousSlotMs() {
bool FixedSlotSequence::slotFollowsImmediately() {
uint32_t currentTime = current->pollingTimeMs;
SlotListIter fixedSequenceIter = this->current;
auto fixedSequenceIter = this->current;
// Get the pollingTimeMs of the current slot object.
if (fixedSequenceIter == slotList.begin()) return false;
fixedSequenceIter--;
@@ -96,8 +96,8 @@ ReturnValue_t FixedSlotSequence::checkSequence() const {
return FixedTimeslotTaskIF::SLOT_LIST_EMPTY;
}
if (customCheckFunction != nullptr) {
ReturnValue_t result = customCheckFunction(slotList);
if (customChecker != nullptr) {
ReturnValue_t result = customChecker(slotList, customCheckArgs);
if (result != HasReturnvaluesIF::RETURN_OK) {
// Continue for now but print error output.
#if FSFW_CPP_OSTREAM_ENABLED == 1
@@ -161,6 +161,9 @@ ReturnValue_t FixedSlotSequence::intializeSequenceAfterTaskCreation() const {
return HasReturnvaluesIF::RETURN_OK;
}
void FixedSlotSequence::addCustomCheck(ReturnValue_t (*customCheckFunction)(const SlotList&)) {
this->customCheckFunction = customCheckFunction;
void FixedSlotSequence::addCustomCheck(CustomCheckFunc customChecker_, void* checkerArgs_) {
customChecker = customChecker_;
customCheckArgs = checkerArgs_;
}
bool FixedSlotSequence::isEmpty() const { return slotList.empty(); }
+10 -7
View File
@@ -30,12 +30,12 @@ class FixedSlotSequence {
public:
using SlotList = std::multiset<FixedSequenceSlot>;
using SlotListIter = std::multiset<FixedSequenceSlot>::iterator;
using CustomCheckFunc = ReturnValue_t (*)(const SlotList&, void* args);
/**
* @brief The constructor of the FixedSlotSequence object.
* @param setLength The period length, expressed in ms.
*/
FixedSlotSequence(uint32_t setLengthMs);
explicit FixedSlotSequence(uint32_t setLengthMs);
/**
* @brief The destructor of the FixedSlotSequence object.
@@ -106,7 +106,7 @@ class FixedSlotSequence {
/**
* @brief This method returns the length of this FixedSlotSequence instance.
*/
uint32_t getLengthMs() const;
[[nodiscard]] uint32_t getLengthMs() const;
/**
* @brief The method to execute the device handler entered in the current
@@ -137,7 +137,7 @@ class FixedSlotSequence {
* @return
* - SLOT_LIST_EMPTY if the slot list is empty
*/
ReturnValue_t checkSequence() const;
[[nodiscard]] ReturnValue_t checkSequence() const;
/**
* @brief A custom check can be injected for the respective slot list.
@@ -149,7 +149,7 @@ class FixedSlotSequence {
* @param customCheckFunction
*
*/
void addCustomCheck(ReturnValue_t (*customCheckFunction)(const SlotList&));
void addCustomCheck(CustomCheckFunc func, void* userArgs);
/**
* @brief Perform any initialization steps required after the executing
@@ -157,7 +157,9 @@ class FixedSlotSequence {
* executing task!
* @return
*/
ReturnValue_t intializeSequenceAfterTaskCreation() const;
[[nodiscard]] ReturnValue_t intializeSequenceAfterTaskCreation() const;
[[nodiscard]] bool isEmpty() const;
protected:
/**
@@ -173,7 +175,8 @@ class FixedSlotSequence {
*/
SlotList slotList;
ReturnValue_t (*customCheckFunction)(const SlotList&) = nullptr;
CustomCheckFunc customChecker = nullptr;
void* customCheckArgs = nullptr;
uint32_t lengthMs;
};
+27
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;
}
+44
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
+29 -3
View File
@@ -2,6 +2,7 @@
#define FRAMEWORK_TASKS_FIXEDTIMESLOTTASKIF_H_
#include "PeriodicTaskIF.h"
#include "fsfw/objectmanager/ObjectManager.h"
#include "fsfw/objectmanager/ObjectManagerIF.h"
#include "fsfw/returnvalues/FwClassIds.h"
@@ -11,10 +12,23 @@
*/
class FixedTimeslotTaskIF : public PeriodicTaskIF {
public:
virtual ~FixedTimeslotTaskIF() {}
~FixedTimeslotTaskIF() override = default;
static constexpr ReturnValue_t SLOT_LIST_EMPTY =
HasReturnvaluesIF::makeReturnCode(CLASS_ID::FIXED_SLOT_TASK_IF, 0);
/**
* Add an object with a slot time and the execution step to the task.
* The execution step will be passed to the object (e.g. as an operation
* code in #performOperation)
* @param componentId
* @param slotTimeMs
* @param executionStep
* @return
*/
virtual ReturnValue_t addSlot(object_id_t execId, ExecutableObjectIF* obj, uint32_t slotTimeMs,
int8_t executionStep) = 0;
/**
* Add an object with a slot time and the execution step to the task.
* The execution step will be passed to the object (e.g. as an operation
@@ -25,12 +39,24 @@ class FixedTimeslotTaskIF : public PeriodicTaskIF {
* @return
*/
virtual ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs,
int8_t executionStep) = 0;
int8_t executionStep) {
auto* execObj = ObjectManager::instance()->get<ExecutableObjectIF>(componentId);
return addSlot(componentId, execObj, slotTimeMs, executionStep);
}
/**
* Check whether the sequence is valid and perform all other required
* initialization steps which are needed after task creation
*/
virtual ReturnValue_t checkSequence() const = 0;
virtual ReturnValue_t checkSequence() = 0;
ReturnValue_t addComponent(object_id_t object, uint8_t opCode) override {
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t addComponent(ExecutableObjectIF* object, uint8_t opCode) override {
return HasReturnvaluesIF::RETURN_FAILED;
}
};
#endif /* FRAMEWORK_TASKS_FIXEDTIMESLOTTASKIF_H_ */
+71
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;
}
+54
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_ */
+20 -20
View File
@@ -3,9 +3,8 @@
#include <cstddef>
#include "../objectmanager/SystemObjectIF.h"
#include "../timemanager/Clock.h"
class ExecutableObjectIF;
#include "fsfw/objectmanager/SystemObjectIF.h"
#include "fsfw/tasks/ExecutableObjectIF.h"
/**
* New version of TaskIF
@@ -18,7 +17,7 @@ class PeriodicTaskIF {
/**
* @brief A virtual destructor as it is mandatory for interfaces.
*/
virtual ~PeriodicTaskIF() {}
virtual ~PeriodicTaskIF() = default;
/**
* @brief With the startTask method, a created task can be started
* for the first time.
@@ -26,28 +25,29 @@ class PeriodicTaskIF {
virtual ReturnValue_t startTask() = 0;
/**
* Add a component (object) to a periodic task.
* @param object
* Add an object to the task. The object needs to implement ExecutableObjectIF
* @return
* Adds an object to the list of objects to be executed.
* The objects are executed in the order added. The object needs to implement
* ExecutableObjectIF
* @param object Id of the object to add.
* @return RETURN_OK on success, RETURN_FAILED if the object could not be added.
*/
virtual ReturnValue_t addComponent(object_id_t object) {
return HasReturnvaluesIF::RETURN_FAILED;
};
virtual ReturnValue_t addComponent(object_id_t object, uint8_t opCode) = 0;
virtual ReturnValue_t addComponent(object_id_t object) { return addComponent(object, 0); };
/**
* Add an object to a periodic task.
* @param object
* Add an object to the task.
* @return
* Adds an object to the list of objects to be executed.
* The objects are executed in the order added.
* @param object pointer to the object to add.
* @return RETURN_OK on success, RETURN_FAILED if the object could not be added.
*/
virtual ReturnValue_t addComponent(ExecutableObjectIF* object) {
return HasReturnvaluesIF::RETURN_FAILED;
};
virtual ReturnValue_t addComponent(ExecutableObjectIF* object, uint8_t opCode) = 0;
virtual ReturnValue_t addComponent(ExecutableObjectIF* object) { return addComponent(object, 0); }
virtual ReturnValue_t sleepFor(uint32_t ms) = 0;
virtual uint32_t getPeriodMs() const = 0;
[[nodiscard]] virtual uint32_t getPeriodMs() const = 0;
[[nodiscard]] virtual bool isEmpty() const = 0;
};
#endif /* PERIODICTASKIF_H_ */
#endif /* FRAMEWORK_TASK_PERIODICTASKIF_H_ */
+1 -1
View File
@@ -4,7 +4,7 @@
#include <cstdlib>
#include "FixedTimeslotTaskIF.h"
#include "Typedef.h"
#include "definitions.h"
/**
* Singleton Class that produces Tasks.
-13
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_ */
+13
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_ */
+3 -2
View File
@@ -9,7 +9,7 @@
CCSDSDistributor::CCSDSDistributor(uint16_t setDefaultApid, object_id_t setObjectId)
: TcDistributor(setObjectId), defaultApid(setDefaultApid) {}
CCSDSDistributor::~CCSDSDistributor() {}
CCSDSDistributor::~CCSDSDistributor() = default;
TcDistributor::TcMqMapIter CCSDSDistributor::selectDestination() {
#if CCSDS_DISTRIBUTOR_DEBUGGING == 1
@@ -38,6 +38,7 @@ TcDistributor::TcMqMapIter CCSDSDistributor::selectDestination() {
" store failed!\n");
#endif
#endif
return queueMap.end();
}
SpacePacketBase currentPacket(packet);
@@ -45,7 +46,7 @@ TcDistributor::TcMqMapIter CCSDSDistributor::selectDestination() {
sif::info << "CCSDSDistributor::selectDestination has packet with APID " << std::hex
<< currentPacket.getAPID() << std::dec << std::endl;
#endif
TcMqMapIter position = this->queueMap.find(currentPacket.getAPID());
auto position = this->queueMap.find(currentPacket.getAPID());
if (position != this->queueMap.end()) {
return position;
} else {
+5 -8
View File
@@ -15,7 +15,7 @@ PUSDistributor::PUSDistributor(uint16_t setApid, object_id_t setObjectId,
tcStatus(RETURN_FAILED),
packetSource(setPacketSource) {}
PUSDistributor::~PUSDistributor() {}
PUSDistributor::~PUSDistributor() = default;
PUSDistributor::TcMqMapIter PUSDistributor::selectDestination() {
#if FSFW_CPP_OSTREAM_ENABLED == 1 && PUS_DISTRIBUTOR_DEBUGGING == 1
@@ -23,7 +23,7 @@ PUSDistributor::TcMqMapIter PUSDistributor::selectDestination() {
sif::debug << "PUSDistributor::handlePacket received: " << storeId.poolIndex << ", "
<< storeId.packetIndex << std::endl;
#endif
TcMqMapIter queueMapIt = this->queueMap.end();
auto queueMapIt = this->queueMap.end();
if (this->currentPacket == nullptr) {
return queueMapIt;
}
@@ -48,10 +48,8 @@ PUSDistributor::TcMqMapIter PUSDistributor::selectDestination() {
sif::warning << "PUSDistributor::handlePacket: Packet format invalid, " << keyword
<< " error" << std::endl;
#else
sif::printWarning(
"PUSDistributor::handlePacket: Packet format invalid, "
"%s error\n",
keyword);
sif::printWarning("PUSDistributor::handlePacket: Packet format invalid, %s error\n",
keyword);
#endif
#endif
}
@@ -133,8 +131,7 @@ ReturnValue_t PUSDistributor::initialize() {
return ObjectManagerIF::CHILD_INIT_FAILED;
}
CCSDSDistributorIF* ccsdsDistributor =
ObjectManager::instance()->get<CCSDSDistributorIF>(packetSource);
auto* ccsdsDistributor = ObjectManager::instance()->get<CCSDSDistributorIF>(packetSource);
if (ccsdsDistributor == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "PUSDistributor::initialize: Packet source invalid" << std::endl;
@@ -6,20 +6,20 @@
#include "fsfw/objectmanager/frameworkObjects.h"
#include "fsfw/serviceinterface/ServiceInterface.h"
StorageManagerIF* TcPacketStoredBase::store = nullptr;
StorageManagerIF* TcPacketStoredBase::STORE = nullptr;
TcPacketStoredBase::TcPacketStoredBase() {
this->storeAddress.raw = StorageManagerIF::INVALID_ADDRESS;
this->checkAndSetStore();
TcPacketStoredBase::checkAndSetStore();
}
TcPacketStoredBase::~TcPacketStoredBase() {}
TcPacketStoredBase::~TcPacketStoredBase() = default;
ReturnValue_t TcPacketStoredBase::getData(const uint8_t** dataPtr, size_t* dataSize) {
auto result = this->store->getData(storeAddress, dataPtr, dataSize);
auto result = TcPacketStoredBase::STORE->getData(storeAddress, dataPtr, dataSize);
if (result != HasReturnvaluesIF::RETURN_OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "TcPacketStoredBase: Could not get data!" << std::endl;
sif::warning << "TcPacketStoredBase: Could not get data" << std::endl;
#else
sif::printWarning("TcPacketStoredBase: Could not get data!\n");
#endif
@@ -28,11 +28,13 @@ ReturnValue_t TcPacketStoredBase::getData(const uint8_t** dataPtr, size_t* dataS
}
bool TcPacketStoredBase::checkAndSetStore() {
if (this->store == nullptr) {
this->store = ObjectManager::instance()->get<StorageManagerIF>(objects::TC_STORE);
if (this->store == nullptr) {
if (TcPacketStoredBase::STORE == nullptr) {
TcPacketStoredBase::STORE = ObjectManager::instance()->get<StorageManagerIF>(objects::TC_STORE);
if (TcPacketStoredBase::STORE == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TcPacketStoredBase::TcPacketStoredBase: TC Store not found!" << std::endl;
sif::error << "TcPacketStoredBase::TcPacketStoredBase: TC Store not found" << std::endl;
#else
sif::printError("TcPacketStoredBase::TcPacketStoredBase: TC Store not found\n");
#endif
return false;
}
@@ -47,7 +49,7 @@ void TcPacketStoredBase::setStoreAddress(store_address_t setAddress,
size_t tempSize;
ReturnValue_t status = StorageManagerIF::RETURN_FAILED;
if (this->checkAndSetStore()) {
status = this->store->getData(this->storeAddress, &tempData, &tempSize);
status = TcPacketStoredBase::STORE->getData(this->storeAddress, &tempData, &tempSize);
}
if (status == StorageManagerIF::RETURN_OK) {
@@ -65,7 +65,7 @@ class TcPacketStoredBase : public TcPacketStoredIF {
* call tries to set it and throws an error message in case of failures.
* The default store is objects::TC_STORE.
*/
static StorageManagerIF* store;
static StorageManagerIF* STORE;
/**
* The address where the packet data of the object instance is stored.
*/
@@ -77,7 +77,7 @@ class TcPacketStoredBase : public TcPacketStoredIF {
* @return @li @c true if the store is linked or could be created.
* @li @c false otherwise.
*/
bool checkAndSetStore();
static bool checkAndSetStore();
};
#endif /* TMTCPACKET_PUS_TcPacketStoredBase_H_ */
#endif /* TMTCPACKET_PUS_TCPACKETSTORED_H_ */
@@ -9,7 +9,8 @@
class TcPacketStoredIF {
public:
virtual ~TcPacketStoredIF(){};
virtual ~TcPacketStoredIF() = default;
;
/**
* With this call, the stored packet can be set to another packet in a store. This is useful
@@ -14,8 +14,8 @@ TcPacketStoredPus::TcPacketStoredPus(uint16_t apid, uint8_t service, uint8_t sub
}
uint8_t* pData = nullptr;
ReturnValue_t returnValue =
this->store->getFreeElement(&this->storeAddress, (TC_PACKET_MIN_SIZE + size), &pData);
if (returnValue != this->store->RETURN_OK) {
this->STORE->getFreeElement(&this->storeAddress, (TC_PACKET_MIN_SIZE + size), &pData);
if (returnValue != this->STORE->RETURN_OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "TcPacketStoredBase: Could not get free element from store!" << std::endl;
#endif
@@ -44,19 +44,19 @@ TcPacketStoredPus::TcPacketStoredPus(const uint8_t* data, size_t size) : TcPacke
return;
}
if (this->checkAndSetStore()) {
ReturnValue_t status = store->addData(&storeAddress, data, size);
ReturnValue_t status = STORE->addData(&storeAddress, data, size);
if (status != HasReturnvaluesIF::RETURN_OK) {
this->setData(nullptr, size);
}
const uint8_t* storePtr = nullptr;
// Repoint base data pointer to the data in the store.
store->getData(storeAddress, &storePtr, &size);
STORE->getData(storeAddress, &storePtr, &size);
this->setData(const_cast<uint8_t*>(storePtr), size);
}
}
ReturnValue_t TcPacketStoredPus::deletePacket() {
ReturnValue_t result = this->store->deleteData(this->storeAddress);
ReturnValue_t result = this->STORE->deleteData(this->storeAddress);
this->storeAddress.raw = StorageManagerIF::INVALID_ADDRESS;
// To circumvent size checks
this->setData(nullptr, -1);
@@ -68,7 +68,7 @@ TcPacketPusBase* TcPacketStoredPus::getPacketBase() { return this; }
bool TcPacketStoredPus::isSizeCorrect() {
const uint8_t* temp_data = nullptr;
size_t temp_size;
ReturnValue_t status = this->store->getData(this->storeAddress, &temp_data, &temp_size);
ReturnValue_t status = this->STORE->getData(this->storeAddress, &temp_data, &temp_size);
if (status == StorageManagerIF::RETURN_OK) {
if (this->getFullSize() == temp_size) {
return true;
@@ -1,7 +1,7 @@
#ifndef FRAMEWORK_TMTCSERVICES_ACCEPTSTELECOMMANDSIF_H_
#define FRAMEWORK_TMTCSERVICES_ACCEPTSTELECOMMANDSIF_H_
#include "../ipc/MessageQueueSenderIF.h"
#include "fsfw/ipc/MessageQueueSenderIF.h"
/**
* @brief This interface is implemented by classes that are sinks for
@@ -20,7 +20,7 @@ class AcceptsTelecommandsIF {
/**
* @brief The virtual destructor as it is mandatory for C++ interfaces.
*/
virtual ~AcceptsTelecommandsIF() {}
virtual ~AcceptsTelecommandsIF() = default;
/**
* @brief Getter for the service id.
* @details Any receiving service (at least any PUS service) shall have a
+8 -4
View File
@@ -12,19 +12,21 @@
#undef minor
#endif
const Version fsfw::FSFW_VERSION = {FSFW_VERSION_MAJOR, FSFW_VERSION_MINOR, FSFW_VERSION_REVISION,
FSFW_VERSION_CST_GIT_SHA1};
const fsfw::Version fsfw::FSFW_VERSION = {FSFW_VERSION_MAJOR, FSFW_VERSION_MINOR,
FSFW_VERSION_REVISION, FSFW_VCS_INFO};
Version::Version(int major, int minor, int revision, const char* addInfo)
fsfw::Version::Version(int major, int minor, int revision, const char* addInfo)
: major(major), minor(minor), revision(revision), addInfo(addInfo) {}
void Version::getVersion(char* str, size_t maxLen) const {
void fsfw::Version::getVersion(char* str, size_t maxLen) const {
size_t len = snprintf(str, maxLen, "%d.%d.%d", major, minor, revision);
if (addInfo != nullptr) {
snprintf(str + len, maxLen - len, "-%s", addInfo);
}
}
namespace fsfw {
#if FSFW_CPP_OSTREAM_ENABLED == 1
std::ostream& operator<<(std::ostream& os, const Version& v) {
os << v.major << "." << v.minor << "." << v.revision;
@@ -34,3 +36,5 @@ std::ostream& operator<<(std::ostream& os, const Version& v) {
return os;
}
#endif
} // namespace fsfw
+2 -2
View File
@@ -8,6 +8,8 @@
#endif
#include <cstdint>
namespace fsfw {
class Version {
public:
Version(int major, int minor, int revision, const char* addInfo = nullptr);
@@ -55,8 +57,6 @@ class Version {
void getVersion(char* str, size_t maxLen) const;
};
namespace fsfw {
extern const Version FSFW_VERSION;
} // namespace fsfw