Merge pull request 'Update FSFW from upstream' (#102) from mueller/update-from-upstream into develop
Reviewed-on: #102 Reviewed-by: Jakob Meier <meierj@irs.uni-stuttgart.de>
This commit is contained in:
commit
6a62cf7f1e
8
.gitignore
vendored
8
.gitignore
vendored
@ -1,6 +1,14 @@
|
||||
# PyCharm and CLion
|
||||
/.idea/*
|
||||
!/.idea/runConfigurations
|
||||
!/.idea/cmake.xml
|
||||
!/.idea/codeStyles
|
||||
|
||||
# Eclipse
|
||||
.cproject
|
||||
.project
|
||||
.settings
|
||||
.metadata
|
||||
|
||||
/build*
|
||||
/cmake-build*
|
||||
|
14
.idea/codeStyles/Project.xml
Normal file
14
.idea/codeStyles/Project.xml
Normal file
@ -0,0 +1,14 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<clangFormatSettings>
|
||||
<option name="ENABLED" value="true" />
|
||||
</clangFormatSettings>
|
||||
<codeStyleSettings language="CMake">
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="2" />
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="0" />
|
||||
<option name="TAB_SIZE" value="2" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
||||
</component>
|
5
.idea/codeStyles/codeStyleConfig.xml
Normal file
5
.idea/codeStyles/codeStyleConfig.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||
</state>
|
||||
</component>
|
41
CHANGELOG.md
41
CHANGELOG.md
@ -12,6 +12,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## Changes
|
||||
|
||||
- Renamed auto-formatting script to `auto-formatter.sh` and made it more robust.
|
||||
If `cmake-format` is installed, it will also auto-format the `CMakeLists.txt` files now.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/625
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/626
|
||||
- Bump C++ required version to C++17. Every project which uses the FSFW and every modern
|
||||
compiler supports it
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/622
|
||||
@ -43,6 +47,38 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
the message queue. Also streamlined and simplified `MessageQueue` implementation for all OSALs
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/583
|
||||
|
||||
### Task Module Refactoring
|
||||
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/636
|
||||
|
||||
**Refactoring general task code**
|
||||
|
||||
- There was a lot of duplicate/boilerplate code inside the individual task IF OSAL implementations.
|
||||
Remove it by introducing base classes `PeriodicTaskBase` and `FixedTimeslotTaskBase`.
|
||||
|
||||
**Refactor PeriodicTaskIF**
|
||||
|
||||
- Convert `virtual ReturnValue_t addComponent(object_id_t object)` to
|
||||
`virtual ReturnValue_t addComponent(object_id_t object, uint8_t opCode = 0)`, allowing to pass
|
||||
the operation code passed to `performOperation`. Updated API taking
|
||||
an `ExecutableObjectIF` accordingly
|
||||
|
||||
**Refactor FixedTimeslotTaskIF**
|
||||
|
||||
- Add additional `addSlot` function which takes an `ExecutableObjectIF` pointer and its Object ID
|
||||
|
||||
**Refactor FixedSequenceSlot**
|
||||
|
||||
- Introduce typedef `CustomCheckFunc` for `ReturnValue_t (*customCheckFunction)(const SlotList&)`.
|
||||
- Convert `ReturnValue_t (*customCheckFunction)(const SlotList&)` to
|
||||
`ReturnValue_t (*customCheckFunction)(const SlotList&, void*)`, allowing arbitrary user arguments
|
||||
for the custom checker
|
||||
|
||||
**Linux Task Module**
|
||||
|
||||
- Use composition instead of inheritance for the `PeriodicPosixTask` and make the `PosixTask` a
|
||||
member of the class
|
||||
|
||||
### HAL
|
||||
|
||||
- HAL Linux Uart: Baudrate and bits per word are enums now, avoiding misconfigurations
|
||||
@ -84,6 +120,11 @@ https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/593
|
||||
|
||||
## Additions
|
||||
|
||||
- Added options for CI/CD builds: `FSFW_CICD_BUILD`. This allows the source code to know
|
||||
whether it is running in CI/CD
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/623
|
||||
- Basic `clion` support: Update `.gitignore` and add some basic run configurations
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/625
|
||||
- LTO support: Allow using LTO/IPO by setting `FSFW_ENABLE_LTO=1`. CMake is able to detect whether
|
||||
the user compiler supports IPO/LPO. LTO is on by default now. Most modern compilers support it,
|
||||
can make good use of it and it usually makes the code faster and/or smaller.
|
||||
|
@ -71,7 +71,7 @@ set(FSFW_ETL_LIB_MAJOR_VERSION
|
||||
20
|
||||
CACHE STRING "ETL library major version requirement")
|
||||
set(FSFW_ETL_LIB_VERSION
|
||||
${FSFW_ETL_LIB_MAJOR_VERSION}.27.3
|
||||
${FSFW_ETL_LIB_MAJOR_VERSION}.28.0
|
||||
CACHE STRING "ETL library exact version requirement")
|
||||
set(FSFW_ETL_LINK_TARGET etl::etl)
|
||||
|
||||
@ -105,6 +105,7 @@ endif()
|
||||
|
||||
option(FSFW_BUILD_UNITTESTS
|
||||
"Build unittest binary in addition to static library" OFF)
|
||||
option(FSFW_CICD_BUILD "Build for CI/CD. This can disable problematic test" OFF)
|
||||
option(FSFW_BUILD_DOCS "Build documentation with Sphinx and Doxygen" OFF)
|
||||
if(FSFW_BUILD_UNITTESTS)
|
||||
option(FSFW_TESTS_GEN_COV "Generate coverage data for unittests" ON)
|
||||
|
@ -99,7 +99,7 @@ add and link against the FSFW library in general.
|
||||
|
||||
4. Link against the FSFW library
|
||||
|
||||
```cmake
|
||||
```sh
|
||||
target_link_libraries(${YourProjectName} PRIVATE fsfw)
|
||||
```
|
||||
|
||||
@ -131,7 +131,7 @@ default. This can be disabled by setting the `FSFW_TESTS_COV_GEN` option to `OFF
|
||||
You can use the following commands inside the `fsfw` folder to set up the build system
|
||||
|
||||
```sh
|
||||
mkdir build-Unittest && cd build-Unittest
|
||||
mkdir build-tests && cd build-tests
|
||||
cmake -DFSFW_BUILD_UNITTESTS=ON -DFSFW_OSAL=host -DCMAKE_BUILD_TYPE=Debug ..
|
||||
```
|
||||
|
||||
|
2
automation/Jenkinsfile
vendored
2
automation/Jenkinsfile
vendored
@ -14,7 +14,7 @@ pipeline {
|
||||
stage('Configure') {
|
||||
steps {
|
||||
dir(BUILDDIR) {
|
||||
sh 'cmake -DFSFW_OSAL=host -DFSFW_BUILD_UNITTESTS=ON ..'
|
||||
sh 'cmake -DFSFW_OSAL=host -DFSFW_BUILD_UNITTESTS=ON -DFSFW_CICD_BUILD=ON ..'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -215,7 +215,7 @@ ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie* spiCookie, const
|
||||
return result;
|
||||
}
|
||||
updateLinePolarity(fileDescriptor);
|
||||
ReturnValue_t result = gpioComIF->pullLow(gpioId);
|
||||
result = gpioComIF->pullLow(gpioId);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
|
@ -10,6 +10,10 @@
|
||||
#include "stm32h7xx_hal.h"
|
||||
#include "stm32h7xx_hal_spi.h"
|
||||
|
||||
#ifndef STM_USE_PERIPHERAL_TX_BUFFER_MPU_PROTECTION
|
||||
#define STM_USE_PERIPHERAL_TX_BUFFER_MPU_PROTECTION 1
|
||||
#endif
|
||||
|
||||
enum class TransferStates { IDLE, WAIT, SUCCESS, FAILURE };
|
||||
|
||||
class GyroL3GD20H {
|
||||
|
@ -700,8 +700,7 @@ void LocalDataPoolManager::performPeriodicHkGeneration(HkReceiver& receiver) {
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
/* Configuration error */
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "LocalDataPoolManager::performPeriodicHkOperation: HK generation failed."
|
||||
<< std::endl;
|
||||
sif::warning << "LocalDataPoolManager::performPeriodicHkOperation: HK generation failed." << std::endl;
|
||||
#else
|
||||
sif::printWarning("LocalDataPoolManager::performPeriodicHkOperation: HK generation failed.\n");
|
||||
#endif
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
};
|
||||
|
@ -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. */
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
};
|
||||
|
@ -74,8 +74,10 @@ ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) {
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
[[noreturn]] void FixedTimeslotTask::taskFunctionality() {
|
||||
pollingSeqTable.intializeSequenceAfterTaskCreation();
|
||||
void FixedTimeslotTask::taskFunctionality() {
|
||||
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.
|
||||
@ -109,26 +111,6 @@ ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) {
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, uint32_t slotTimeMs,
|
||||
int8_t executionStep) {
|
||||
auto* executableObject = ObjectManager::instance()->get<ExecutableObjectIF>(componentId);
|
||||
if (executableObject != nullptr) {
|
||||
pollingSeqTable.addSlot(componentId, slotTimeMs, executionStep, executableObject, this);
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "Component " << 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;
|
||||
}
|
||||
|
||||
bool FixedTimeslotTask::delayForInterval(chron_ms* previousWakeTimeMs, const chron_ms interval) {
|
||||
bool shouldDelay = false;
|
||||
// Get current wakeup time
|
||||
|
@ -50,16 +50,6 @@ class FixedTimeslotTask : public FixedTimeslotTaskBase {
|
||||
*/
|
||||
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) override;
|
||||
|
||||
ReturnValue_t sleepFor(uint32_t ms) override;
|
||||
|
||||
protected:
|
||||
@ -93,7 +83,7 @@ class FixedTimeslotTask : public FixedTimeslotTaskBase {
|
||||
* the checkAndRestartPeriod system call blocks the task until the next
|
||||
* period. On missing the deadline, the deadlineMissedFunction is executed.
|
||||
*/
|
||||
[[noreturn]] void taskFunctionality();
|
||||
void taskFunctionality();
|
||||
|
||||
static bool delayForInterval(chron_ms* previousWakeTimeMs, chron_ms interval);
|
||||
};
|
||||
|
@ -133,5 +133,3 @@ bool PeriodicTask::delayForInterval(chron_ms* previousWakeTimeMs, const chron_ms
|
||||
(*previousWakeTimeMs) = currentStartTime;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PeriodicTask::isEmpty() const { return objectList.empty(); }
|
||||
|
@ -52,8 +52,6 @@ class PeriodicTask : public PeriodicTaskBase {
|
||||
|
||||
ReturnValue_t sleepFor(uint32_t ms) override;
|
||||
|
||||
bool isEmpty() const override;
|
||||
|
||||
protected:
|
||||
using chron_ms = std::chrono::milliseconds;
|
||||
bool started;
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
#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_, TaskPriority priority_, size_t stackSize_,
|
||||
@ -37,7 +36,8 @@ ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) {
|
||||
posixThread.suspend();
|
||||
}
|
||||
|
||||
pollingSeqTable.intializeSequenceAfterTaskCreation();
|
||||
// Returnvalue ignored for now
|
||||
static_cast<void>(pollingSeqTable.intializeSequenceAfterTaskCreation());
|
||||
|
||||
// The start time for the first entry is read.
|
||||
uint64_t lastWakeTime = PosixThread::getCurrentMonotonicTimeMs();
|
||||
@ -54,20 +54,12 @@ ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) {
|
||||
// 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.
|
||||
pollingSeqTable.executeAndAdvance();
|
||||
}
|
||||
}
|
||||
|
||||
void FixedTimeslotTask::missedDeadlineCounter() {
|
||||
FixedTimeslotTask::deadlineMissedCount++;
|
||||
if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "PST missed " << FixedTimeslotTask::deadlineMissedCount << " deadlines."
|
||||
<< std::endl;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -30,17 +30,6 @@ class FixedTimeslotTask : public FixedTimeslotTaskBase {
|
||||
|
||||
ReturnValue_t sleepFor(uint32_t ms) override;
|
||||
|
||||
/**
|
||||
* This static function can be used as #deadlineMissedFunc.
|
||||
* It counts missedDeadlines and prints the number of missed deadlines every 10th time.
|
||||
*/
|
||||
static void missedDeadlineCounter();
|
||||
|
||||
/**
|
||||
* A helper variable to count missed deadlines.
|
||||
*/
|
||||
static uint32_t deadlineMissedCount;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief This function holds the main functionality of the thread.
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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_ */
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,7 @@ 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,
|
||||
explicit MessageQueue(size_t message_depth = 3,
|
||||
size_t max_message_size = MessageQueueMessage::MAX_MESSAGE_SIZE,
|
||||
MqArgs* args = nullptr);
|
||||
|
||||
@ -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;
|
||||
|
@ -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); }
|
||||
|
@ -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_ */
|
||||
|
@ -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) {
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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() {}
|
||||
|
@ -615,23 +615,23 @@ inline ReturnValue_t Service11TelecommandScheduling<MAX_NUM_TCS>::handleInvalidD
|
||||
|
||||
template <size_t MAX_NUM_TCS>
|
||||
inline void Service11TelecommandScheduling<MAX_NUM_TCS>::debugPrintMultimapContent() const {
|
||||
for ([[maybe_unused]] const auto &dit : telecommandMap) {
|
||||
#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(
|
||||
"Service11TelecommandScheduling::debugPrintMultimapContent: Multimap Content\n");
|
||||
for (auto dit = telecommandMap.begin(); dit != telecommandMap.end(); ++dit) {
|
||||
sif::printDebug("[%d]: Request ID: %d | Store Address: %d\n", dit->first,
|
||||
dit->second.requestId, dit->second.storeAddr);
|
||||
}
|
||||
#endif
|
||||
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>
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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,8 +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(); }
|
||||
|
@ -30,7 +30,7 @@ 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.
|
||||
@ -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,9 +157,9 @@ class FixedSlotSequence {
|
||||
* executing task!
|
||||
* @return
|
||||
*/
|
||||
ReturnValue_t intializeSequenceAfterTaskCreation() const;
|
||||
[[nodiscard]] ReturnValue_t intializeSequenceAfterTaskCreation() const;
|
||||
|
||||
bool isEmpty() const;
|
||||
[[nodiscard]] bool isEmpty() const;
|
||||
|
||||
protected:
|
||||
/**
|
||||
@ -175,7 +175,8 @@ class FixedSlotSequence {
|
||||
*/
|
||||
SlotList slotList;
|
||||
|
||||
ReturnValue_t (*customCheckFunction)(const SlotList&) = nullptr;
|
||||
CustomCheckFunc customChecker = nullptr;
|
||||
void* customCheckArgs = nullptr;
|
||||
|
||||
uint32_t lengthMs;
|
||||
};
|
||||
|
@ -11,19 +11,17 @@ bool FixedTimeslotTaskBase::isEmpty() const { return pollingSeqTable.isEmpty();
|
||||
|
||||
ReturnValue_t FixedTimeslotTaskBase::checkSequence() { return pollingSeqTable.checkSequence(); }
|
||||
|
||||
ReturnValue_t FixedTimeslotTaskBase::addSlot(object_id_t componentId, uint32_t slotTimeMs,
|
||||
int8_t executionStep) {
|
||||
auto* executableObject = ObjectManager::instance()->get<ExecutableObjectIF>(componentId);
|
||||
if (executableObject != nullptr) {
|
||||
pollingSeqTable.addSlot(componentId, slotTimeMs, executionStep, executableObject, this);
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
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') << componentId
|
||||
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;
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ class FixedTimeslotTaskBase : public FixedTimeslotTaskIF {
|
||||
|
||||
[[nodiscard]] bool isEmpty() const override;
|
||||
|
||||
ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs,
|
||||
ReturnValue_t addSlot(object_id_t execId, ExecutableObjectIF* componentId, uint32_t slotTimeMs,
|
||||
int8_t executionStep) override;
|
||||
};
|
||||
|
||||
|
@ -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"
|
||||
|
||||
@ -15,6 +16,19 @@ class FixedTimeslotTaskIF : public PeriodicTaskIF {
|
||||
|
||||
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() = 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_ */
|
||||
|
@ -21,8 +21,14 @@ uint32_t PeriodicTaskBase::getPeriodMs() const { return static_cast<uint32_t>(pe
|
||||
|
||||
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::multiset<ExecutableObjectIF*> uniqueObjects;
|
||||
std::set<ExecutableObjectIF*> uniqueObjects;
|
||||
ReturnValue_t status = HasReturnvaluesIF::RETURN_OK;
|
||||
uint32_t count = 0;
|
||||
for (const auto& obj : objectList) {
|
||||
|
@ -17,6 +17,9 @@ class PeriodicTaskBase : public PeriodicTaskIF {
|
||||
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;
|
||||
|
@ -31,9 +31,8 @@ class PeriodicTaskIF {
|
||||
* @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, uint8_t opCode = 0) {
|
||||
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); };
|
||||
|
||||
/**
|
||||
* Adds an object to the list of objects to be executed.
|
||||
@ -41,15 +40,14 @@ class PeriodicTaskIF {
|
||||
* @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, uint8_t opCode = 0) {
|
||||
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;
|
||||
|
||||
virtual bool isEmpty() const = 0;
|
||||
[[nodiscard]] virtual bool isEmpty() const = 0;
|
||||
};
|
||||
|
||||
#endif /* PERIODICTASKIF_H_ */
|
||||
#endif /* FRAMEWORK_TASK_PERIODICTASKIF_H_ */
|
||||
|
@ -13,14 +13,14 @@ TestDevice::TestDevice(object_id_t objectId, object_id_t comIF, CookieIF* cookie
|
||||
dataset(this),
|
||||
fullInfoPrintout(fullInfoPrintout) {}
|
||||
|
||||
TestDevice::~TestDevice() {}
|
||||
TestDevice::~TestDevice() = default;
|
||||
|
||||
void TestDevice::performOperationHook() {
|
||||
if (periodicPrintout) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::info << "TestDevice" << deviceIdx << "::performOperationHook: Alive!" << std::endl;
|
||||
#else
|
||||
sif::printInfo("TestDevice%d::performOperationHook: Alive!", deviceIdx);
|
||||
sif::printInfo("TestDevice%d::performOperationHook: Alive!\n", deviceIdx);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@ TestTask::TestTask(object_id_t objectId) : SystemObject(objectId), testMode(test
|
||||
IPCStore = ObjectManager::instance()->get<StorageManagerIF>(objects::IPC_STORE);
|
||||
}
|
||||
|
||||
TestTask::~TestTask() {}
|
||||
TestTask::~TestTask() = default;
|
||||
|
||||
ReturnValue_t TestTask::performOperation(uint8_t operationCode) {
|
||||
ReturnValue_t result = RETURN_OK;
|
||||
|
@ -13,9 +13,9 @@
|
||||
*/
|
||||
class TestTask : public SystemObject, public ExecutableObjectIF, public HasReturnvaluesIF {
|
||||
public:
|
||||
TestTask(object_id_t objectId);
|
||||
virtual ~TestTask();
|
||||
virtual ReturnValue_t performOperation(uint8_t operationCode = 0) override;
|
||||
explicit TestTask(object_id_t objectId);
|
||||
~TestTask() override;
|
||||
ReturnValue_t performOperation(uint8_t operationCode) override;
|
||||
|
||||
protected:
|
||||
virtual ReturnValue_t performOneShotAction();
|
||||
|
@ -2,7 +2,9 @@
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#include "tests/TestsConfig.h"
|
||||
#include "fsfw/container/DynamicFIFO.h"
|
||||
#include "fsfw/container/SimpleRingBuffer.h"
|
||||
#include "fsfw/platform.h"
|
||||
@ -61,6 +63,9 @@ TEST_CASE("Command Executor", "[cmd-exec]") {
|
||||
std::string cmpString = "Hello World\n";
|
||||
CHECK(readString == cmpString);
|
||||
outputBuffer.deleteData(12, true);
|
||||
|
||||
// Issues with CI/CD
|
||||
#if FSFW_CICD_BUILD == 0
|
||||
// Test more complex command
|
||||
result = cmdExecutor.load("ping -c 1 localhost", false, false);
|
||||
REQUIRE(cmdExecutor.getCurrentState() == CommandExecutor::States::COMMAND_LOADED);
|
||||
@ -81,16 +86,27 @@ TEST_CASE("Command Executor", "[cmd-exec]") {
|
||||
REQUIRE(cmdExecutor.getCurrentState() == CommandExecutor::States::IDLE);
|
||||
readBytes = 0;
|
||||
sizesFifo.retrieve(&readBytes);
|
||||
// That's about the size of the reply
|
||||
bool beTrue = (readBytes > 200) and (readBytes < 300);
|
||||
REQUIRE(beTrue);
|
||||
uint8_t largerReadBuffer[1024] = {};
|
||||
// That's about the size of the reply
|
||||
bool beTrue = (readBytes > 100) and (readBytes < 400);
|
||||
if (not beTrue) {
|
||||
size_t readLen = outputBuffer.getAvailableReadData();
|
||||
if (readLen > sizeof(largerReadBuffer) - 1) {
|
||||
readLen = sizeof(largerReadBuffer) - 1;
|
||||
}
|
||||
outputBuffer.readData(largerReadBuffer, readLen);
|
||||
std::string readString(reinterpret_cast<char*>(largerReadBuffer));
|
||||
std::cerr << "Catch2 tag cmd-exec: Read " << readBytes << ": " << std::endl;
|
||||
std::cerr << readString << std::endl;
|
||||
}
|
||||
REQUIRE(beTrue);
|
||||
outputBuffer.readData(largerReadBuffer, readBytes);
|
||||
// You can also check this output in the debugger
|
||||
std::string allTheReply(reinterpret_cast<char*>(largerReadBuffer));
|
||||
// I am just going to assume that this string is the same across ping implementations
|
||||
// of different Linux systems
|
||||
REQUIRE(allTheReply.find("PING localhost") != std::string::npos);
|
||||
#endif
|
||||
|
||||
// Now check failing command
|
||||
result = cmdExecutor.load("false", false, false);
|
||||
|
@ -16,7 +16,7 @@
|
||||
#include "fsfw_tests/unit/mocks/PeriodicTaskIFMock.h"
|
||||
|
||||
TEST_CASE("Internal Error Reporter", "[TestInternalError]") {
|
||||
PeriodicTaskMock task(10);
|
||||
PeriodicTaskMock task(10, nullptr);
|
||||
ObjectManagerIF* manager = ObjectManager::instance();
|
||||
if (manager == nullptr) {
|
||||
FAIL();
|
||||
@ -27,6 +27,8 @@ TEST_CASE("Internal Error Reporter", "[TestInternalError]") {
|
||||
FAIL();
|
||||
}
|
||||
task.addComponent(objects::INTERNAL_ERROR_REPORTER);
|
||||
// This calls the initializeAfterTaskCreation function
|
||||
task.startTask();
|
||||
MessageQueueIF* testQueue = QueueFactory::instance()->createMessageQueue(1);
|
||||
MessageQueueIF* hkQueue = QueueFactory::instance()->createMessageQueue(1);
|
||||
internalErrorReporter->getSubscriptionInterface()->subscribeForSetUpdateMessage(
|
||||
|
@ -2,36 +2,24 @@
|
||||
#define FSFW_UNITTEST_TESTS_MOCKS_PERIODICTASKMOCK_H_
|
||||
|
||||
#include <fsfw/tasks/ExecutableObjectIF.h>
|
||||
#include <fsfw/tasks/PeriodicTaskIF.h>
|
||||
#include <fsfw/tasks/PeriodicTaskBase.h>
|
||||
|
||||
class PeriodicTaskMock : public PeriodicTaskIF {
|
||||
class PeriodicTaskMock : public PeriodicTaskBase {
|
||||
public:
|
||||
PeriodicTaskMock(uint32_t period = 5) : period(period) {}
|
||||
/**
|
||||
* @brief A virtual destructor as it is mandatory for interfaces.
|
||||
*/
|
||||
PeriodicTaskMock(TaskPeriod period, TaskDeadlineMissedFunction dlmFunc)
|
||||
: PeriodicTaskBase(period, dlmFunc) {}
|
||||
|
||||
virtual ~PeriodicTaskMock() {}
|
||||
/**
|
||||
* @brief With the startTask method, a created task can be started
|
||||
* for the first time.
|
||||
*/
|
||||
virtual ReturnValue_t startTask() override { return HasReturnvaluesIF::RETURN_OK; };
|
||||
|
||||
virtual ReturnValue_t addComponent(object_id_t object) override {
|
||||
ExecutableObjectIF* executableObject =
|
||||
ObjectManager::instance()->get<ExecutableObjectIF>(objects::INTERNAL_ERROR_REPORTER);
|
||||
if (executableObject == nullptr) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
executableObject->setTaskIF(this);
|
||||
executableObject->initializeAfterTaskCreation();
|
||||
virtual ReturnValue_t startTask() override {
|
||||
initObjsAfterTaskCreation();
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
};
|
||||
|
||||
virtual ReturnValue_t sleepFor(uint32_t ms) override { return HasReturnvaluesIF::RETURN_OK; };
|
||||
|
||||
virtual uint32_t getPeriodMs() const override { return period; };
|
||||
uint32_t period;
|
||||
};
|
||||
|
||||
#endif // FSFW_UNITTEST_TESTS_MOCKS_PERIODICTASKMOCK_H_
|
@ -156,4 +156,31 @@ TEST_CASE("New Accessor", "[NewAccessor]") {
|
||||
CHECK(receptionArray[i] == 42);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Operators"){
|
||||
result = SimplePool.addData(&testStoreId, testDataArray.data(), size);
|
||||
REQUIRE(result == retval::CATCH_OK);
|
||||
{
|
||||
StorageAccessor accessor(testStoreId);
|
||||
StorageAccessor accessor2(0);
|
||||
accessor2 = std::move(accessor);
|
||||
REQUIRE(accessor.data() == nullptr);
|
||||
std::array<uint8_t, 6> data;
|
||||
size_t size = 6;
|
||||
result = accessor.write(data.data(), data.size());
|
||||
REQUIRE(result == HasReturnvaluesIF::RETURN_FAILED);
|
||||
result = SimplePool.modifyData(testStoreId, accessor2);
|
||||
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
|
||||
CHECK(accessor2.getId() == testStoreId);
|
||||
CHECK(accessor2.size() == 10);
|
||||
|
||||
std::array<uint8_t, 10> newData;
|
||||
// Expect data to be invalid so this must return RETURN_FAILED
|
||||
result = accessor.getDataCopy(newData.data(),newData.size());
|
||||
REQUIRE(result == HasReturnvaluesIF::RETURN_FAILED);
|
||||
// Expect data to be too small
|
||||
result = accessor2.getDataCopy(data.data(),data.size());
|
||||
REQUIRE(result == HasReturnvaluesIF::RETURN_FAILED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <cstring>
|
||||
#include <array>
|
||||
|
||||
#include "fsfw_tests/unit/CatchDefinitions.h"
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
#ifndef FSFW_UNITTEST_CONFIG_TESTSCONFIG_H_
|
||||
#define FSFW_UNITTEST_CONFIG_TESTSCONFIG_H_
|
||||
|
||||
#cmakedefine01 FSFW_CICD_BUILD
|
||||
|
||||
#define FSFW_ADD_DEFAULT_FACTORY_FUNCTIONS 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
Loading…
Reference in New Issue
Block a user