Merge branch 'development' into meier/dhbReplyTimeout
All checks were successful
fsfw/fsfw/pipeline/pr-development This commit looks good
All checks were successful
fsfw/fsfw/pipeline/pr-development This commit looks good
This commit is contained in:
commit
3e9ae62b28
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>
|
7
.run/fsfw-tests_coverage.run.xml
Normal file
7
.run/fsfw-tests_coverage.run.xml
Normal file
@ -0,0 +1,7 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="fsfw-tests_coverage" type="CMakeRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="fsfw-tests" TARGET_NAME="fsfw-tests_coverage" CONFIG_NAME="Debug Unittest" RUN_TARGET_PROJECT_NAME="fsfw-tests" RUN_TARGET_NAME="fsfw-tests">
|
||||
<method v="2">
|
||||
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
7
.run/fsfw.run.xml
Normal file
7
.run/fsfw.run.xml
Normal file
@ -0,0 +1,7 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="fsfw" type="CMakeRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="fsfw-tests" TARGET_NAME="fsfw" CONFIG_NAME="Debug Unittest" RUN_TARGET_PROJECT_NAME="fsfw-tests" RUN_TARGET_NAME="fsfw-tests">
|
||||
<method v="2">
|
||||
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</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 ..'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -210,7 +210,7 @@ ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie* spiCookie, const
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
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 {
|
||||
|
@ -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,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::error << "PST missed " << FixedTimeslotTask::deadlineMissedCount << " deadlines."
|
||||
<< std::endl;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t FixedTimeslotTask::startTask() {
|
||||
started = true;
|
||||
|
||||
@ -63,31 +51,12 @@ ReturnValue_t FixedTimeslotTask::startTask() {
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, uint32_t slotTimeMs,
|
||||
int8_t executionStep) {
|
||||
ExecutableObjectIF* handler = ObjectManager::instance()->get<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();
|
||||
};
|
||||
|
@ -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(¤tStartTime, interval);
|
||||
// TODO deadline missed check
|
||||
if (not delayForInterval(¤tStartTime, interval)) {
|
||||
if (dlmFunc != nullptr) {
|
||||
dlmFunc();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, uint32_t slotTimeMs,
|
||||
int8_t executionStep) {
|
||||
ExecutableObjectIF* executableObject =
|
||||
ObjectManager::instance()->get<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
|
||||
|
@ -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_ */
|
||||
|
@ -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(¤tStartTime, periodChrono)) {
|
||||
if (deadlineMissedFunc != nullptr) {
|
||||
this->deadlineMissedFunc();
|
||||
if (dlmFunc != nullptr) {
|
||||
this->dlmFunc();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t PeriodicTask::addComponent(object_id_t object) {
|
||||
ExecutableObjectIF* newObject = ObjectManager::instance()->get<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
|
||||
|
@ -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_ */
|
||||
|
@ -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; }
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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::error << "PST missed " << FixedTimeslotTask::deadlineMissedCount << " deadlines."
|
||||
<< std::endl;
|
||||
#endif
|
||||
pollingSeqTable.executeAndAdvance();
|
||||
}
|
||||
}
|
||||
|
@ -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 < |