Compare commits

...

100 Commits

Author SHA1 Message Date
1e8ff8d02c tweak changelog 2022-07-08 17:38:43 +02:00
0df27fdc71 Merge branch 'develop' into mueller/update-cmd-reply-maps-refactoring 2022-07-08 17:35:43 +02:00
4789200750 Merge remote-tracking branch 'upstream/development' into mueller/update-cmd-reply-maps-refactoring 2022-07-08 17:29:21 +02:00
904ae2cc0e Merge remote-tracking branch 'origin/irini' into develop 2022-07-08 16:34:24 +02:00
4a2012ac30 Merge branch 'irini' into develop 2022-07-08 16:31:57 +02:00
6a62cf7f1e 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>
2022-07-04 13:04:00 +02:00
c5eb09314f delete run configs 2022-07-04 11:04:37 +02:00
682abd1b5b new clion folder in misc for .run configs 2022-07-04 10:55:09 +02:00
a4247cd723 Merge remote-tracking branch 'upstream/development' into mueller/update-from-upstream 2022-07-04 10:53:52 +02:00
39881e7671 Merge pull request 'some form updates' (#100) from mueller/afmt-gen-tweaks into develop
Reviewed-on: #100
2022-06-21 10:37:03 +02:00
541f563683 Merge pull request 'Fix StorageAccessor move assignment' (#643) from gaisser/fsfw:gaisser_storage_accessor_fix into development
Reviewed-on: fsfw/fsfw#643
2022-06-21 10:31:36 +02:00
5abbf42e9f some form updates 2022-06-21 00:49:58 +02:00
28ea71a077 Merge branch 'development' into gaisser_storage_accessor_fix 2022-06-20 17:56:58 +02:00
a044d7d724 Merge pull request 'new cmake options for CICD build' (#623) from mueller/new-cicd-cmake-opts into development
Reviewed-on: fsfw/fsfw#623
2022-06-20 17:56:29 +02:00
687700cee8 Merge branch 'development' into gaisser_storage_accessor_fix 2022-06-20 16:36:49 +02:00
732b615cb3 Merge branch 'development' into mueller/new-cicd-cmake-opts 2022-06-20 16:34:13 +02:00
394ce2ec3e Merge pull request 'LocalDataPoolManager Warning Text' (#642) from meier/debug-info into development
Reviewed-on: fsfw/fsfw#642
2022-06-20 16:15:30 +02:00
dde96ae220 Merge branch 'development' into gaisser_storage_accessor_fix 2022-06-20 16:15:05 +02:00
c3aaab4b93 Merge pull request 'Task IF refactoring' (#636) from mueller/task-if-refactoring into development
Reviewed-on: fsfw/fsfw#636
2022-06-20 16:08:03 +02:00
edf1d5ae8d Added more test cases 2022-06-20 16:02:35 +02:00
690991b4b5 include fix 2022-06-20 15:42:08 +02:00
1a294e6a13 include TestsConfig.h 2022-06-20 15:40:15 +02:00
8c4e34153b README updates 2022-06-20 15:36:48 +02:00
b60e4bcb90 Fix StorageAccessor move assignment
* Added Unittest for this
* Fixed missing include in test
2022-06-20 15:15:33 +02:00
b18410aa63 Merge remote-tracking branch 'refs/remotes/origin/mueller/task-if-refactoring' into mueller/task-if-refactoring 2022-06-20 15:02:38 +02:00
7f57a8784a Fixed deadline missed call on linux 2022-06-20 15:02:16 +02:00
4b33aa8262 bump ETL version 2022-06-20 14:25:39 +02:00
d47a908117 Merge branch 'development' into mueller/task-if-refactoring 2022-06-20 09:40:31 +02:00
fce95e04a8 Merge branch 'development' into mueller/new-cicd-cmake-opts 2022-06-20 09:39:58 +02:00
fc742e4270 Merge branch 'development' into meier/debug-info 2022-06-16 07:22:43 +02:00
b5183a19fc minor change in debug text 2022-06-16 07:03:58 +02:00
ca453a8f16 Merge pull request 'run auto formatters' (#641) from KSat/fsfw:mueller/reapply-fmt into development
Reviewed-on: fsfw/fsfw#641
2022-06-13 17:04:11 +02:00
b7c0c07141 Merge remote-tracking branch 'origin/development' into mueller/new-cicd-cmake-opts 2022-06-13 16:28:01 +02:00
0158102f11 Merge pull request 'apply afmt, basic CLion support' (#625) from mueller/apply-afmt into development
Reviewed-on: fsfw/fsfw#625
2022-06-13 16:27:02 +02:00
69859fdbc9 rerun afmt 2022-06-13 16:21:20 +02:00
90bccc744e Merge pull request 'Fix SPI ComIF shadowing warning' (#639) from KSat/fsfw:mueller/spi-com-if-shadowing into development
Reviewed-on: fsfw/fsfw#639
2022-06-13 14:35:46 +02:00
ab89108c55 Merge pull request 'some fixes for TC Map printout function' (#640) from KSat/fsfw:mueller/pus-11-printout-fixes into development
Reviewed-on: fsfw/fsfw#640
2022-06-13 14:29:36 +02:00
a682bbe400 remove static missed deadline 2022-06-13 14:23:56 +02:00
e67fc2ab0d some fixes for TC Map printout function 2022-06-13 10:56:37 +02:00
71ce966531 Merge branch 'mueller/spi-com-if-shadowing' of https://egit.irs.uni-stuttgart.de/KSat/fsfw into mueller/spi-com-if-shadowing 2022-06-13 10:54:25 +02:00
6b0f4a159f Merge remote-tracking branch 'upstream/development' into mueller/spi-com-if-shadowing 2022-06-13 10:54:20 +02:00
4a06b558c1 Fix SPI ComIF shadowing warning 2022-06-13 10:53:04 +02:00
6d921f03fd Fix SPI ComIF shadowing warning 2022-06-13 10:50:49 +02:00
65bc8213fe Merge branch 'development' into mueller/new-cicd-cmake-opts 2022-06-13 09:43:32 +02:00
a0ee86ace8 use override instead of virtual as recommended 2022-06-08 17:36:20 +02:00
a07a368272 Merge branch 'development' into mueller/apply-afmt 2022-06-08 17:34:04 +02:00
cb8a4bbbec Merge remote-tracking branch 'origin/development' into mueller/task-if-refactoring 2022-06-08 17:33:12 +02:00
17f54006b8 Merge pull request 'rtems fixes' (#635) from mueller/rtems-fixes into development
Reviewed-on: fsfw/fsfw#635
2022-06-08 16:12:53 +02:00
395cf9cfa7 added clion base files 2022-06-08 12:12:33 +02:00
a3c0b441ec update changelog 2022-06-08 12:12:33 +02:00
b4132800ae apply afmt, update .gitignore 2022-06-08 12:12:33 +02:00
ad53b48fcb explicitely ignore returnvalue in linux OSAL 2022-06-08 12:12:09 +02:00
dee40f9079 fixed unittests 2022-06-08 12:12:09 +02:00
92ec24352f fix unit test 2022-06-08 12:12:09 +02:00
3f9e459f48 update changelog 2022-06-08 12:12:09 +02:00
e0c7f8d51d apply afmt 2022-06-08 12:12:09 +02:00
eb79386c92 new addSlot function taking executable pointer 2022-06-08 12:12:09 +02:00
4542f31c40 improved custom checker API
- More clang-tidy improvements
2022-06-08 12:12:09 +02:00
689fb378d8 a regular set should suffice here 2022-06-08 12:12:09 +02:00
98b711a872 update changelog 2022-06-08 12:12:09 +02:00
800aa131fa reverted some unrelated changes 2022-06-08 12:12:09 +02:00
6983980304 missing newline and clang-tidy improvement 2022-06-08 12:12:09 +02:00
7c0ba59993 remove include 2022-06-08 12:12:09 +02:00
28873fc87b refactores rtems task module 2022-06-08 12:12:09 +02:00
24e849ed9c avoid compiler warning 2022-06-08 12:12:09 +02:00
d8985c141e some clang tidy stuff and bugfixes 2022-06-08 12:12:09 +02:00
7602b15256 important bugfix 2022-06-08 12:12:09 +02:00
d1a82bceed rtems fixes 2022-06-08 12:12:09 +02:00
7292b02907 refactor freeRTOS task components 2022-06-08 12:12:09 +02:00
347714d53a refactored and tested hosted and linux task IF 2022-06-08 12:12:09 +02:00
f230fa1617 continued refactoring 2022-06-08 12:12:09 +02:00
93615b100c continued refactoring 2022-06-08 12:12:09 +02:00
e18d3d559e refactoring host osal 2022-06-08 12:12:09 +02:00
08ff061d07 minor bugfix 2022-06-08 12:12:09 +02:00
cc351c1066 new base class for periodic tasks 2022-06-08 12:12:09 +02:00
664a548c53 removed some changes which belong in separate PR 2022-06-08 12:12:09 +02:00
e9895559a3 vector as core container is ok 2022-06-08 12:12:09 +02:00
eda5b8f593 refactor task IF 2022-06-08 12:12:09 +02:00
e03f55604a rtems fixes 2022-06-08 12:11:26 +02:00
51d7df2dba Merge branch 'development' into mueller/new-cicd-cmake-opts 2022-06-08 11:13:13 +02:00
12046a2db6 Merge pull request 'bump etl to 20.28.0' (#634) from mueller/bump-etl into development
Reviewed-on: fsfw/fsfw#634
2022-06-08 11:09:42 +02:00
c697d0f8ab bump etl to 20.28.0 2022-05-30 10:34:03 +02:00
940fd6f465 Merge branch 'development' into mueller/new-cicd-cmake-opts 2022-05-23 15:59:13 +02:00
8e9d4b451c better printout if ping test fails 2022-05-16 16:18:44 +02:00
816550b69c Merge remote-tracking branch 'upstream/development' into mueller/new-cicd-cmake-opts 2022-05-16 14:58:25 +02:00
bb640f8758 some ctors 2022-05-13 18:15:15 +02:00
c379f8671d added all new configuration classes 2022-05-13 18:10:10 +02:00
6c588cea53 apply cmake-fmt on all cmakelists.txt files 2022-05-13 17:33:43 +02:00
2ef9229c0b Merge remote-tracking branch 'upstream/development' into mueller/update-cmd-reply-maps-refactoring 2022-05-13 17:31:02 +02:00
8a12a5097e Merge branch 'mueller/apply-afmt' into mueller/new-cicd-cmake-opts 2022-05-13 13:50:41 +02:00
87e4a57ef7 added clion base files 2022-05-13 13:48:13 +02:00
0375ee1881 update changelog 2022-05-13 13:46:54 +02:00
c8e034d975 Merge branch 'development' into mueller/new-cicd-cmake-opts 2022-05-13 13:41:58 +02:00
2708b71d77 Merge remote-tracking branch 'origin/development' into mueller/new-cicd-cmake-opts 2022-05-13 12:00:40 +02:00
6366283ce2 Merge branch 'development' into mueller/apply-afmt 2022-05-13 11:50:03 +02:00
8dc640c162 apply afmt, update .gitignore 2022-05-13 11:39:37 +02:00
2e4b9bcd7c Merge remote-tracking branch 'origin/development' into mueller/new-cicd-cmake-opts 2022-05-12 17:42:49 +02:00
aacaf52fd9 Merge branch 'development' into mueller/new-cicd-cmake-opts 2022-05-09 15:34:36 +02:00
89f83f4e3d update changelog 2022-05-09 15:33:03 +02:00
39b7976056 new cmake options for CICD build 2022-05-09 15:26:38 +02:00
57 changed files with 458 additions and 539 deletions

8
.gitignore vendored
View File

@ -1,6 +1,14 @@
# PyCharm and CLion
/.idea/*
!/.idea/runConfigurations
!/.idea/cmake.xml
!/.idea/codeStyles
# Eclipse
.cproject .cproject
.project .project
.settings .settings
.metadata .metadata
/build* /build*
/cmake-build*

14
.idea/codeStyles/Project.xml generated Normal file
View 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 generated Normal file
View File

@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>

View File

@ -12,15 +12,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## Changes ## 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 - Bump C++ required version to C++17. Every project which uses the FSFW and every modern
compiler supports it compiler supports it
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/622 PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/622
- HAL Linux SPI: Set the Clock Default State when setting new SPI speed
and mode
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/573
- GPIO HAL: `Direction`, `GpioOperation` and `Levels` are enum classes now, which prevents
name clashes with Windows defines.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/572
- New CMake option `FSFW_HAL_LINUX_ADD_LIBGPIOD` to specifically exclude `gpiod` code. - New CMake option `FSFW_HAL_LINUX_ADD_LIBGPIOD` to specifically exclude `gpiod` code.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/572 PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/572
- HAL Devicehandlers: Periodic printout is run-time configurable now - HAL Devicehandlers: Periodic printout is run-time configurable now
@ -43,6 +41,38 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
the message queue. Also streamlined and simplified `MessageQueue` implementation for all OSALs the message queue. Also streamlined and simplified `MessageQueue` implementation for all OSALs
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/583 PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/583
### Task Module Refactoring
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/636
**Refactoring general task code**
- There was a lot of duplicate/boilerplate code inside the individual task IF OSAL implementations.
Remove it by introducing base classes `PeriodicTaskBase` and `FixedTimeslotTaskBase`.
**Refactor PeriodicTaskIF**
- Convert `virtual ReturnValue_t addComponent(object_id_t object)` to
`virtual ReturnValue_t addComponent(object_id_t object, uint8_t opCode = 0)`, allowing to pass
the operation code passed to `performOperation`. Updated API taking
an `ExecutableObjectIF` accordingly
**Refactor FixedTimeslotTaskIF**
- Add additional `addSlot` function which takes an `ExecutableObjectIF` pointer and its Object ID
**Refactor FixedSequenceSlot**
- Introduce typedef `CustomCheckFunc` for `ReturnValue_t (*customCheckFunction)(const SlotList&)`.
- Convert `ReturnValue_t (*customCheckFunction)(const SlotList&)` to
`ReturnValue_t (*customCheckFunction)(const SlotList&, void*)`, allowing arbitrary user arguments
for the custom checker
**Linux Task Module**
- Use composition instead of inheritance for the `PeriodicPosixTask` and make the `PosixTask` a
member of the class
### HAL ### HAL
- HAL Linux Uart: Baudrate and bits per word are enums now, avoiding misconfigurations - HAL Linux Uart: Baudrate and bits per word are enums now, avoiding misconfigurations
@ -55,6 +85,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/572 PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/572
- HAL Linux Uart: Baudrate and bits per word are enums now, avoiding misconfigurations - HAL Linux Uart: Baudrate and bits per word are enums now, avoiding misconfigurations
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/585 PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/585
- Linux HAL: Add wiretapping option for I2C. Enabled with `FSFW_HAL_I2C_WIRETAPPING` defined to 1
### Time ### Time
@ -84,6 +115,11 @@ https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/593
## Additions ## 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 - 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, 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. can make good use of it and it usually makes the code faster and/or smaller.
@ -112,17 +148,6 @@ https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/593
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/590 PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/590
- `Subsystem`: New API to add table and sequence entries - `Subsystem`: New API to add table and sequence entries
## HAL
- SPI: Cache the SPI device in the communication interface. Architecturally, this makes a
lot more sense because each ComIF should be responsible for one SPI bus.
- SPI: Move the empty transfer to update the line polarity to separate function. This means
it is not automatically called when calling the setter function for SPI speed and mode.
The user should call this function after locking the CS mutex if multiple SPI devices with
differing speeds and modes are attached to one bus.
- SPI: Getter functions for SPI speed and mode.
- I2C: Add wiretapping option for I2C. Enabled with `FSFW_HAL_I2C_WIRETAPPING` defined to 1.
## Fixed ## Fixed
- TCP TMTC Server: `MutexGuard` was not created properly in - TCP TMTC Server: `MutexGuard` was not created properly in

View File

@ -71,7 +71,7 @@ set(FSFW_ETL_LIB_MAJOR_VERSION
20 20
CACHE STRING "ETL library major version requirement") CACHE STRING "ETL library major version requirement")
set(FSFW_ETL_LIB_VERSION 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") CACHE STRING "ETL library exact version requirement")
set(FSFW_ETL_LINK_TARGET etl::etl) set(FSFW_ETL_LINK_TARGET etl::etl)
@ -105,6 +105,7 @@ endif()
option(FSFW_BUILD_UNITTESTS option(FSFW_BUILD_UNITTESTS
"Build unittest binary in addition to static library" OFF) "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) option(FSFW_BUILD_DOCS "Build documentation with Sphinx and Doxygen" OFF)
if(FSFW_BUILD_UNITTESTS) if(FSFW_BUILD_UNITTESTS)
option(FSFW_TESTS_GEN_COV "Generate coverage data for unittests" ON) option(FSFW_TESTS_GEN_COV "Generate coverage data for unittests" ON)
@ -182,10 +183,13 @@ if(FSFW_BUILD_UNITTESTS)
endif() endif()
endif() endif()
message(STATUS "${MSG_PREFIX} Finding and/or providing etl library with version ${FSFW_ETL_LIB_MAJOR_VERSION}") message(
STATUS
"${MSG_PREFIX} Finding and/or providing etl library with version ${FSFW_ETL_LIB_MAJOR_VERSION}"
)
# Check whether the user has already installed ETL first # Check whether the user has already installed ETL first
find_package(${FSFW_ETL_LIB_NAME} ${FSFW_ETL_LIB_MAJOR_VERSION} CONFIG QUIET) find_package(${FSFW_ETL_LIB_NAME} ${FSFW_ETL_LIB_MAJOR_VERSION} QUIET)
# Not installed, so use FetchContent to download and provide etl # Not installed, so use FetchContent to download and provide etl
if(NOT ${FSFW_ETL_LIB_NAME}_FOUND) if(NOT ${FSFW_ETL_LIB_NAME}_FOUND)
message( message(

View File

@ -99,7 +99,7 @@ add and link against the FSFW library in general.
4. Link against the FSFW library 4. Link against the FSFW library
```cmake ```sh
target_link_libraries(${YourProjectName} PRIVATE fsfw) 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 You can use the following commands inside the `fsfw` folder to set up the build system
```sh ```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 .. cmake -DFSFW_BUILD_UNITTESTS=ON -DFSFW_OSAL=host -DCMAKE_BUILD_TYPE=Debug ..
``` ```

View File

@ -14,7 +14,7 @@ pipeline {
stage('Configure') { stage('Configure') {
steps { steps {
dir(BUILDDIR) { dir(BUILDDIR) {
sh 'cmake -DFSFW_OSAL=host -DFSFW_BUILD_UNITTESTS=ON ..' sh 'cmake -DFSFW_OSAL=host -DFSFW_BUILD_UNITTESTS=ON -DFSFW_CICD_BUILD=ON ..'
} }
} }
} }

View File

@ -215,7 +215,7 @@ ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie* spiCookie, const
return result; return result;
} }
updateLinePolarity(fileDescriptor); updateLinePolarity(fileDescriptor);
ReturnValue_t result = gpioComIF->pullLow(gpioId); result = gpioComIF->pullLow(gpioId);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
#if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1

View File

@ -10,6 +10,10 @@
#include "stm32h7xx_hal.h" #include "stm32h7xx_hal.h"
#include "stm32h7xx_hal_spi.h" #include "stm32h7xx_hal_spi.h"
#ifndef STM_USE_PERIPHERAL_TX_BUFFER_MPU_PROTECTION
#define STM_USE_PERIPHERAL_TX_BUFFER_MPU_PROTECTION 1
#endif
enum class TransferStates { IDLE, WAIT, SUCCESS, FAILURE }; enum class TransferStates { IDLE, WAIT, SUCCESS, FAILURE };
class GyroL3GD20H { class GyroL3GD20H {

View File

@ -577,8 +577,9 @@ ReturnValue_t LocalDataPoolManager::handleHousekeepingMessage(CommandMessage* me
CommandMessage reply; CommandMessage reply;
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
if(result == WRONG_HK_PACKET_TYPE) { if (result == WRONG_HK_PACKET_TYPE) {
printWarningOrError(sif::OutputTypes::OUT_WARNING, "handleHousekeepingMessage", WRONG_HK_PACKET_TYPE); printWarningOrError(sif::OutputTypes::OUT_WARNING, "handleHousekeepingMessage",
WRONG_HK_PACKET_TYPE);
} }
HousekeepingMessage::setHkRequestFailureReply(&reply, sid, result); HousekeepingMessage::setHkRequestFailureReply(&reply, sid, result);
} else { } else {

View File

@ -1581,8 +1581,7 @@ void DeviceHandlerBase::disableCommandsAndReplies() {
if (!reply.second.periodic) { if (!reply.second.periodic) {
if (reply.second.countdown != nullptr) { if (reply.second.countdown != nullptr) {
reply.second.countdown->timeOut(); reply.second.countdown->timeOut();
} } else {
else {
reply.second.delayCycles = 0; reply.second.delayCycles = 0;
} }
reply.second.active = false; reply.second.active = false;

View File

@ -7,6 +7,7 @@
#include "DeviceHandlerFailureIsolation.h" #include "DeviceHandlerFailureIsolation.h"
#include "DeviceHandlerIF.h" #include "DeviceHandlerIF.h"
#include "DeviceHandlerThermalSet.h" #include "DeviceHandlerThermalSet.h"
#include "DhbCfgHelpers.h"
#include "fsfw/action/ActionHelper.h" #include "fsfw/action/ActionHelper.h"
#include "fsfw/action/HasActionsIF.h" #include "fsfw/action/HasActionsIF.h"
#include "fsfw/datapool/PoolVariableIF.h" #include "fsfw/datapool/PoolVariableIF.h"
@ -488,9 +489,9 @@ class DeviceHandlerBase : public DeviceHandlerIF,
* @return - @c RETURN_OK when the command was successfully inserted, * @return - @c RETURN_OK when the command was successfully inserted,
* - @c RETURN_FAILED else. * - @c RETURN_FAILED else.
*/ */
ReturnValue_t insertInCommandMap(DeviceCommandId_t deviceCommand, ReturnValue_t insertInCommandMap(
bool useAlternativeReply = false, DeviceCommandId_t deviceCommand, bool useAlternativeReply = false,
DeviceCommandId_t alternativeReplyId = 0); DeviceCommandId_t alternativeReplyId = DeviceHandlerIF::NO_COMMAND_ID);
/** /**
* Enables a periodic reply for a given command. It sets to delay cycles to the specified * Enables a periodic reply for a given command. It sets to delay cycles to the specified

View File

@ -0,0 +1,72 @@
#ifndef FSFW_SRC_FSFW_DEVICEHANDLERS_DHBCFGHELPERS_H_
#define FSFW_SRC_FSFW_DEVICEHANDLERS_DHBCFGHELPERS_H_
/**
* @brief This is the base class for configuration related to both DHB commands, replies and their
* combination
*/
struct CfgBase {
public:
explicit CfgBase(DeviceCommandId_t cmdAndOrReplyId) : cmdAndOrReplyId(cmdAndOrReplyId){};
DeviceCommandId_t cmdAndOrReplyId;
};
/**
* @brief Configuration class for commands
*/
struct CmdCfg {
public:
explicit CmdCfg(DeviceCommandId_t cmdId) : baseCfg(cmdId){};
CfgBase baseCfg;
//! This can be used if a command can trigger multiple replies
std::pair<bool, DeviceCommandId_t> alternativeReply = {false, DeviceHandlerIF::NO_COMMAND_ID};
};
/**
* @brief Configuration class for replies
*/
struct ReplyCfg {
public:
ReplyCfg(DeviceCommandId_t replyId, uint16_t maxDelayCycles)
: baseCfg(replyId), maxDelayCycles(maxDelayCycles){};
ReplyCfg(DeviceCommandId_t replyId, uint16_t maxDelayCycles, LocalPoolDataSetBase* set)
: ReplyCfg(replyId, maxDelayCycles) {
dataSet = set;
};
CfgBase baseCfg;
//! A data set can be mapped to a reply ID. This allows to omit the #getDataSetHandle
//! override in a user device handler as this pointer will be passed as long as the device
//! command ID is equal to the set ID.
LocalPoolDataSetBase* dataSet = nullptr;
//! For Command-Reply combinations:
//! The maximum number of cycles the handler should wait for a reply
//! to this command.
//!
//! Reply Only:
//! For periodic replies, this variable will be the number of delay cycles between the replies.
//! For the non-periodic variant, this variable is not used as there is no meaningful
//! definition for delay
uint16_t maxDelayCycles = 0;
//! First parameter: Specify whether reply is arriving periodically
//! Second parameter: Specify whether periodic reply should be enabled immediately
std::pair<bool, bool> periodicCfg = {false, false};
//! If a reply needs to be requested with a specific length, the length can be specified here
size_t replyLen = 0;
//! It is also possible to use a time based instead of a cycle based mechanism to specify
//! how long a reply takes. For non-periodic replies without a command, this variable is not used.
Countdown* countdown = nullptr;
};
/**
* @brief Configuration class for commands and replies
*/
struct CmdReplyCfg {
public:
CmdReplyCfg(CmdCfg cmdCfg, ReplyCfg replyCfg) : cmdCfg(cmdCfg), replyCfg(replyCfg) {}
CmdCfg cmdCfg;
ReplyCfg replyCfg;
};
#endif /* FSFW_SRC_FSFW_DEVICEHANDLERS_DHBCFGHELPERS_H_ */

View File

@ -16,7 +16,9 @@ elseif(FSFW_OSAL MATCHES "host")
else() else()
message(WARNING "${MSG_PREFIX} The FSFW_OSAL variable was not set. Assuming host OS..") message(
WARNING
"${MSG_PREFIX} The FSFW_OSAL variable was not set. Assuming host OS..")
# Not set. Assumuing this is a host build, try to determine host OS # Not set. Assumuing this is a host build, try to determine host OS
if(WIN32) if(WIN32)
add_subdirectory(host) add_subdirectory(host)

View File

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

View File

@ -4,11 +4,11 @@
#include "FreeRTOS.h" #include "FreeRTOS.h"
#include "FreeRTOSTaskIF.h" #include "FreeRTOSTaskIF.h"
#include "fsfw/tasks/FixedSlotSequence.h" #include "fsfw/tasks/FixedSlotSequence.h"
#include "fsfw/tasks/FixedTimeslotTaskIF.h" #include "fsfw/tasks/FixedTimeslotTaskBase.h"
#include "fsfw/tasks/Typedef.h" #include "fsfw/tasks/definitions.h"
#include "task.h" #include "task.h"
class FixedTimeslotTask : public FixedTimeslotTaskIF, public FreeRTOSTaskIF { class FixedTimeslotTask : public FixedTimeslotTaskBase, public FreeRTOSTaskIF {
public: public:
/** /**
* Keep in mind that you need to call before vTaskStartScheduler()! * Keep in mind that you need to call before vTaskStartScheduler()!
@ -23,7 +23,7 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF, public FreeRTOSTaskIF {
* @return Pointer to the newly created task. * @return Pointer to the newly created task.
*/ */
FixedTimeslotTask(TaskName name, TaskPriority setPriority, TaskStackSize setStack, FixedTimeslotTask(TaskName name, TaskPriority setPriority, TaskStackSize setStack,
TaskPeriod overallPeriod, void (*setDeadlineMissedFunc)()); TaskPeriod overallPeriod, TaskDeadlineMissedFunction dlmFunc);
/** /**
* @brief The destructor of the class. * @brief The destructor of the class.
@ -32,26 +32,9 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF, public FreeRTOSTaskIF {
* initialization for the PST and the device handlers. This is done by * initialization for the PST and the device handlers. This is done by
* calling the PST's destructor. * calling the PST's destructor.
*/ */
virtual ~FixedTimeslotTask(void); ~FixedTimeslotTask() override;
ReturnValue_t startTask(void); ReturnValue_t startTask() override;
/**
* This static function can be used as #deadlineMissedFunc.
* It counts missedDeadlines and prints the number of missed deadlines
* every 10th time.
*/
static void missedDeadlineCounter();
/**
* A helper variable to count missed deadlines.
*/
static uint32_t deadlineMissedCount;
ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs,
int8_t executionStep) override;
uint32_t getPeriodMs() const override;
ReturnValue_t checkSequence() const override;
ReturnValue_t sleepFor(uint32_t ms) override; ReturnValue_t sleepFor(uint32_t ms) override;
@ -61,17 +44,6 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF, public FreeRTOSTaskIF {
bool started; bool started;
TaskHandle_t handle; TaskHandle_t handle;
FixedSlotSequence pst;
/**
* @brief This attribute holds a function pointer that is executed when
* a deadline was missed.
* @details
* Another function may be announced to determine the actions to perform
* when a deadline was missed. Currently, only one function for missing
* any deadline is allowed. If not used, it shall be declared NULL.
*/
void (*deadlineMissedFunc)(void);
/** /**
* @brief This is the entry point for a new task. * @brief This is the entry point for a new task.
* @details * @details
@ -88,7 +60,7 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF, public FreeRTOSTaskIF {
* It links the functionalities provided by FixedSlotSequence with the * It links the functionalities provided by FixedSlotSequence with the
* OS's System Calls to keep the timing of the periods. * OS's System Calls to keep the timing of the periods.
*/ */
void taskFunctionality(void); [[noreturn]] void taskFunctionality();
void handleMissedDeadline(); void handleMissedDeadline();
}; };

View File

@ -6,11 +6,11 @@
class FreeRTOSTaskIF { class FreeRTOSTaskIF {
public: public:
virtual ~FreeRTOSTaskIF() {} virtual ~FreeRTOSTaskIF() = default;
virtual TaskHandle_t getTaskHandle() = 0; virtual TaskHandle_t getTaskHandle() = 0;
protected: protected:
bool checkMissedDeadline(const TickType_t xLastWakeTime, const TickType_t interval) { static bool checkMissedDeadline(const TickType_t xLastWakeTime, const TickType_t interval) {
/* Check whether deadline was missed while also taking overflows /* Check whether deadline was missed while also taking overflows
* into account. Drawing this on paper with a timeline helps to understand * into account. Drawing this on paper with a timeline helps to understand
* it. */ * it. */

View File

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

View File

@ -6,8 +6,8 @@
#include "FreeRTOS.h" #include "FreeRTOS.h"
#include "FreeRTOSTaskIF.h" #include "FreeRTOSTaskIF.h"
#include "fsfw/objectmanager/ObjectManagerIF.h" #include "fsfw/objectmanager/ObjectManagerIF.h"
#include "fsfw/tasks/PeriodicTaskIF.h" #include "fsfw/tasks/PeriodicTaskBase.h"
#include "fsfw/tasks/Typedef.h" #include "fsfw/tasks/definitions.h"
#include "task.h" #include "task.h"
class ExecutableObjectIF; class ExecutableObjectIF;
@ -17,7 +17,7 @@ class ExecutableObjectIF;
* periodic activities of multiple objects. * periodic activities of multiple objects.
* @ingroup task_handling * @ingroup task_handling
*/ */
class PeriodicTask : public PeriodicTaskIF, public FreeRTOSTaskIF { class PeriodicTask : public PeriodicTaskBase, public FreeRTOSTaskIF {
public: public:
/** /**
* Keep in Mind that you need to call before this vTaskStartScheduler()! * Keep in Mind that you need to call before this vTaskStartScheduler()!
@ -43,7 +43,7 @@ class PeriodicTask : public PeriodicTaskIF, public FreeRTOSTaskIF {
* @brief Currently, the executed object's lifetime is not coupled with * @brief Currently, the executed object's lifetime is not coupled with
* the task object's lifetime, so the destructor is empty. * the task object's lifetime, so the destructor is empty.
*/ */
virtual ~PeriodicTask(void); ~PeriodicTask() override;
/** /**
* @brief The method to start the task. * @brief The method to start the task.
@ -53,27 +53,6 @@ class PeriodicTask : public PeriodicTaskIF, public FreeRTOSTaskIF {
* to the system call. * to the system call.
*/ */
ReturnValue_t startTask() override; ReturnValue_t startTask() override;
/**
* Adds an object to the list of objects to be executed.
* The objects are executed in the order added.
* @param object Id of the object to add.
* @return
* -@c RETURN_OK on success
* -@c RETURN_FAILED if the object could not be added.
*/
ReturnValue_t addComponent(object_id_t object) override;
/**
* Adds an object to the list of objects to be executed.
* The objects are executed in the order added.
* @param object Id of the object to add.
* @return
* -@c RETURN_OK on success
* -@c RETURN_FAILED if the object could not be added.
*/
ReturnValue_t addComponent(ExecutableObjectIF* object) override;
uint32_t getPeriodMs() const override;
ReturnValue_t sleepFor(uint32_t ms) override; ReturnValue_t sleepFor(uint32_t ms) override;
@ -83,28 +62,6 @@ class PeriodicTask : public PeriodicTaskIF, public FreeRTOSTaskIF {
bool started; bool started;
TaskHandle_t handle; TaskHandle_t handle;
//! Typedef for the List of objects.
typedef std::vector<ExecutableObjectIF*> ObjectList;
/**
* @brief This attribute holds a list of objects to be executed.
*/
ObjectList objectList;
/**
* @brief The period of the task.
* @details
* The period determines the frequency of the task's execution.
* It is expressed in clock ticks.
*/
TaskPeriod period;
/**
* @brief The pointer to the deadline-missed function.
* @details
* This pointer stores the function that is executed if the task's deadline
* is missed so each may react individually on a timing failure.
* The pointer may be NULL, then nothing happens on missing the deadline.
* The deadline is equal to the next execution of the periodic task.
*/
void (*deadlineMissedFunc)(void);
/** /**
* @brief This is the function executed in the new task's context. * @brief This is the function executed in the new task's context.
* @details * @details
@ -125,7 +82,7 @@ class PeriodicTask : public PeriodicTaskIF, public FreeRTOSTaskIF {
* the next period. * the next period.
* On missing the deadline, the deadlineMissedFunction is executed. * On missing the deadline, the deadlineMissedFunction is executed.
*/ */
void taskFunctionality(void); [[noreturn]] void taskFunctionality();
void handleMissedDeadline(); void handleMissedDeadline();
}; };

View File

@ -74,8 +74,10 @@ ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) {
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
[[noreturn]] void FixedTimeslotTask::taskFunctionality() { void FixedTimeslotTask::taskFunctionality() {
pollingSeqTable.intializeSequenceAfterTaskCreation(); ReturnValue_t result = pollingSeqTable.intializeSequenceAfterTaskCreation();
// Ignore returnvalue for now
static_cast<void>(result);
// A local iterator for the Polling Sequence Table is created to // A local iterator for the Polling Sequence Table is created to
// find the start time for the first entry. // find the start time for the first entry.
@ -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 FixedTimeslotTask::delayForInterval(chron_ms* previousWakeTimeMs, const chron_ms interval) {
bool shouldDelay = false; bool shouldDelay = false;
// Get current wakeup time // Get current wakeup time

View File

@ -50,16 +50,6 @@ class FixedTimeslotTask : public FixedTimeslotTaskBase {
*/ */
ReturnValue_t startTask() override; 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; ReturnValue_t sleepFor(uint32_t ms) override;
protected: protected:
@ -93,7 +83,7 @@ class FixedTimeslotTask : public FixedTimeslotTaskBase {
* the checkAndRestartPeriod system call blocks the task until the next * the checkAndRestartPeriod system call blocks the task until the next
* period. On missing the deadline, the deadlineMissedFunction is executed. * period. On missing the deadline, the deadlineMissedFunction is executed.
*/ */
[[noreturn]] void taskFunctionality(); void taskFunctionality();
static bool delayForInterval(chron_ms* previousWakeTimeMs, chron_ms interval); static bool delayForInterval(chron_ms* previousWakeTimeMs, chron_ms interval);
}; };

View File

@ -133,5 +133,3 @@ bool PeriodicTask::delayForInterval(chron_ms* previousWakeTimeMs, const chron_ms
(*previousWakeTimeMs) = currentStartTime; (*previousWakeTimeMs) = currentStartTime;
return false; return false;
} }
bool PeriodicTask::isEmpty() const { return objectList.empty(); }

View File

@ -52,7 +52,6 @@ class PeriodicTask : public PeriodicTaskBase {
ReturnValue_t sleepFor(uint32_t ms) override; ReturnValue_t sleepFor(uint32_t ms) override;
bool isEmpty() const override;
protected: protected:
using chron_ms = std::chrono::milliseconds; using chron_ms = std::chrono::milliseconds;
bool started; bool started;

View File

@ -4,7 +4,6 @@
#include "fsfw/serviceinterface/ServiceInterface.h" #include "fsfw/serviceinterface/ServiceInterface.h"
uint32_t FixedTimeslotTask::deadlineMissedCount = 0;
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = PTHREAD_STACK_MIN; const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = PTHREAD_STACK_MIN;
FixedTimeslotTask::FixedTimeslotTask(const char* name_, TaskPriority priority_, size_t stackSize_, FixedTimeslotTask::FixedTimeslotTask(const char* name_, TaskPriority priority_, size_t stackSize_,
@ -37,7 +36,8 @@ ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) {
posixThread.suspend(); posixThread.suspend();
} }
pollingSeqTable.intializeSequenceAfterTaskCreation(); // Returnvalue ignored for now
static_cast<void>(pollingSeqTable.intializeSequenceAfterTaskCreation());
// The start time for the first entry is read. // The start time for the first entry is read.
uint64_t lastWakeTime = PosixThread::getCurrentMonotonicTimeMs(); 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 the deadline was missed, the deadlineMissedFunc is called.
if (!PosixThread::delayUntil(&lastWakeTime, interval)) { if (!PosixThread::delayUntil(&lastWakeTime, interval)) {
// No time left on timer -> we missed the deadline // No time left on timer -> we missed the deadline
missedDeadlineCounter(); if(dlmFunc != nullptr){
dlmFunc();
}
} }
} }
// The device handler for this slot is executed and the next one is chosen. // The device handler for this slot is executed and the next one is chosen.
pollingSeqTable.executeAndAdvance(); pollingSeqTable.executeAndAdvance();
} }
} }
void FixedTimeslotTask::missedDeadlineCounter() {
FixedTimeslotTask::deadlineMissedCount++;
if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "PST missed " << FixedTimeslotTask::deadlineMissedCount << " deadlines."
<< std::endl;
#endif
}
}

View File

@ -30,17 +30,6 @@ class FixedTimeslotTask : public FixedTimeslotTaskBase {
ReturnValue_t sleepFor(uint32_t ms) override; 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: protected:
/** /**
* @brief This function holds the main functionality of the thread. * @brief This function holds the main functionality of the thread.

View File

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

View File

@ -1,11 +1,11 @@
#ifndef FSFW_OSAL_RTEMS_FIXEDTIMESLOTTASK_H_ #ifndef FSFW_OSAL_RTEMS_FIXEDTIMESLOTTASK_H_
#define FSFW_OSAL_RTEMS_FIXEDTIMESLOTTASK_H_ #define FSFW_OSAL_RTEMS_FIXEDTIMESLOTTASK_H_
#include "../../tasks/FixedSlotSequence.h"
#include "../../tasks/FixedTimeslotTaskIF.h"
#include "RTEMSTaskBase.h" #include "RTEMSTaskBase.h"
#include "fsfw/tasks/FixedSlotSequence.h"
#include "fsfw/tasks/FixedTimeslotTaskBase.h"
class FixedTimeslotTask : public RTEMSTaskBase, public FixedTimeslotTaskIF { class FixedTimeslotTask : public FixedTimeslotTaskBase, public RTEMSTaskBase {
public: public:
/** /**
* @brief The standard constructor of the class. * @brief The standard constructor of the class.
@ -17,7 +17,7 @@ class FixedTimeslotTask : public RTEMSTaskBase, public FixedTimeslotTaskIF {
* @param getPst The object id of the completely initialized polling sequence. * @param getPst The object id of the completely initialized polling sequence.
*/ */
FixedTimeslotTask(const char *name, rtems_task_priority setPriority, size_t setStackSize, FixedTimeslotTask(const char *name, rtems_task_priority setPriority, size_t setStackSize,
uint32_t overallPeriod, void (*setDeadlineMissedFunc)()); TaskPeriod overallPeriod, TaskDeadlineMissedFunction dlmFunc);
/** /**
* @brief The destructor of the class. * @brief The destructor of the class.
@ -25,44 +25,17 @@ class FixedTimeslotTask : public RTEMSTaskBase, public FixedTimeslotTaskIF {
* The destructor frees all heap memory that was allocated on thread initialization * The destructor frees all heap memory that was allocated on thread initialization
* for the PST andthe device handlers. This is done by calling the PST's destructor. * for the PST andthe device handlers. This is done by calling the PST's destructor.
*/ */
virtual ~FixedTimeslotTask(void); ~FixedTimeslotTask() override;
ReturnValue_t startTask(void); ReturnValue_t startTask(void);
/**
* This static function can be used as #deadlineMissedFunc.
* It counts missedDeadlines and prints the number of missed deadlines every 10th time.
*/
static void missedDeadlineCounter();
/**
* A helper variable to count missed deadlines.
*/
static uint32_t deadlineMissedCount;
ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs, int8_t executionStep); ReturnValue_t sleepFor(uint32_t ms) override;
uint32_t getPeriodMs() const;
ReturnValue_t checkSequence() const;
ReturnValue_t sleepFor(uint32_t ms);
protected: protected:
/** /**
* @brief id of the associated OS period * @brief id of the associated OS period
*/ */
rtems_id periodId; rtems_id periodId;
FixedSlotSequence pst;
/**
* @brief This attribute holds a function pointer that is executed when a deadline was missed.
*
* @details
* Another function may be announced to determine the actions to perform when a deadline
* was missed. Currently, only one function for missing any deadline is allowed.
* If not used, it shall be declared NULL.
*/
void (*deadlineMissedFunc)(void) = nullptr;
/** /**
* @brief This is the entry point in a new polling thread. * @brief This is the entry point in a new polling thread.
* @details This method is the entry point in the new thread * @details This method is the entry point in the new thread
@ -76,7 +49,7 @@ class FixedTimeslotTask : public RTEMSTaskBase, public FixedTimeslotTaskIF {
* It links the functionalities provided by FixedSlotSequence with the OS's system calls to * It links the functionalities provided by FixedSlotSequence with the OS's system calls to
* keep the timing of the periods. * keep the timing of the periods.
*/ */
void taskFunctionality(void); [[noreturn]] void taskFunctionality();
}; };
#endif /* FSFW_OSAL_RTEMS_FIXEDTIMESLOTTASK_H_ */ #endif /* FSFW_OSAL_RTEMS_FIXEDTIMESLOTTASK_H_ */

View File

@ -65,7 +65,7 @@ ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, MessageQueu
} }
ReturnValue_t returnCode = convertReturnCode(result); ReturnValue_t returnCode = convertReturnCode(result);
if (result == MessageQueueIF::EMPTY) { if (returnCode == MessageQueueIF::EMPTY) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }

View File

@ -36,9 +36,9 @@ class MessageQueue : public MessageQueueBase {
* @param max_message_size With this parameter, the maximum message size can be adjusted. * @param max_message_size With this parameter, the maximum message size can be adjusted.
* This should be left default. * 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, size_t max_message_size = MessageQueueMessage::MAX_MESSAGE_SIZE,
MqArgs* args = nullptr); MqArgs* args = nullptr);
/** Copying message queues forbidden */ /** Copying message queues forbidden */
MessageQueue(const MessageQueue&) = delete; MessageQueue(const MessageQueue&) = delete;
@ -48,18 +48,19 @@ class MessageQueue : public MessageQueueBase {
* @brief The destructor deletes the formerly created message queue. * @brief The destructor deletes the formerly created message queue.
* @details This is accomplished by using the delete call provided by the operating system. * @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 // Implement non-generic MessageQueueIF functions not handled by MessageQueueBase
ReturnValue_t flush(uint32_t* count) override; ReturnValue_t flush(uint32_t* count) override;
ReturnValue_t receiveMessage(MessageQueueMessageIF* message) override;
ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message, ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
MessageQueueId_t sentFrom = NO_QUEUE, MessageQueueId_t sentFrom, bool ignoreFault) override;
bool ignoreFault = false) override;
private: private:
/** /**
* \brief This attribute stores a reference to the internal error reporter for reporting full * @brief This attribute stores a reference to the internal error reporter for reporting full
* queues. \details In the event of a full destination queue, the reporter will be notified. The * queues. @details In the event of a full destination queue, the reporter will be notified. The
* reference is set by lazy loading * reference is set by lazy loading
*/ */
InternalErrorReporterIF* internalErrorReporter; InternalErrorReporterIF* internalErrorReporter;

View File

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

View File

@ -3,9 +3,10 @@
#include <vector> #include <vector>
#include "../../objectmanager/ObjectManagerIF.h"
#include "../../tasks/PeriodicTaskIF.h"
#include "RTEMSTaskBase.h" #include "RTEMSTaskBase.h"
#include "fsfw/objectmanager/ObjectManagerIF.h"
#include "fsfw/tasks/PeriodicTaskBase.h"
#include "fsfw/tasks/PeriodicTaskIF.h"
class ExecutableObjectIF; class ExecutableObjectIF;
@ -18,7 +19,7 @@ class ExecutableObjectIF;
* @author baetz * @author baetz
* @ingroup task_handling * @ingroup task_handling
*/ */
class PeriodicTask : public RTEMSTaskBase, public PeriodicTaskIF { class PeriodicTask : public PeriodicTaskBase, public RTEMSTaskBase {
public: public:
/** /**
* @brief Standard constructor of the class. * @brief Standard constructor of the class.
@ -36,12 +37,12 @@ class PeriodicTask : public RTEMSTaskBase, public PeriodicTaskIF {
* that shall be assigned. * that shall be assigned.
*/ */
PeriodicTask(const char *name, rtems_task_priority setPriority, size_t setStack, PeriodicTask(const char *name, rtems_task_priority setPriority, size_t setStack,
rtems_interval setPeriod, void (*setDeadlineMissedFunc)()); TaskPeriod setPeriod, TaskDeadlineMissedFunction dlmFunc);
/** /**
* @brief Currently, the executed object's lifetime is not coupled with the task object's * @brief Currently, the executed object's lifetime is not coupled with the task object's
* lifetime, so the destructor is empty. * lifetime, so the destructor is empty.
*/ */
virtual ~PeriodicTask(void); ~PeriodicTask() override;
/** /**
* @brief The method to start the task. * @brief The method to start the task.
@ -50,33 +51,11 @@ class PeriodicTask : public RTEMSTaskBase, public PeriodicTaskIF {
* The address of the task object is passed as an argument * The address of the task object is passed as an argument
* to the system call. * to the system call.
*/ */
ReturnValue_t startTask(void); ReturnValue_t startTask() override;
/**
* Adds an object to the list of objects to be executed.
* The objects are executed in the order added.
* @param object Id of the object to add.
* @return RETURN_OK on success, RETURN_FAILED if the object could not be added.
*/
ReturnValue_t addComponent(object_id_t object) override;
/**
* Adds an object to the list of objects to be executed.
* The objects are executed in the order added.
* @param object pointer to the object to add.
* @return RETURN_OK on success, RETURN_FAILED if the object could not be added.
*/
ReturnValue_t addComponent(ExecutableObjectIF *object) override;
uint32_t getPeriodMs() const override;
ReturnValue_t sleepFor(uint32_t ms) override; ReturnValue_t sleepFor(uint32_t ms) override;
protected: protected:
typedef std::vector<ExecutableObjectIF *> ObjectList; //!< Typedef for the List of objects.
/**
* @brief This attribute holds a list of objects to be executed.
*/
ObjectList objectList;
/** /**
* @brief The period of the task. * @brief The period of the task.
* @details The period determines the frequency of the task's execution. It is expressed in * @details The period determines the frequency of the task's execution. It is expressed in
@ -87,14 +66,7 @@ class PeriodicTask : public RTEMSTaskBase, public PeriodicTaskIF {
* @brief id of the associated OS period * @brief id of the associated OS period
*/ */
rtems_id periodId = 0; rtems_id periodId = 0;
/**
* @brief The pointer to the deadline-missed function.
* @details This pointer stores the function that is executed if the task's deadline is missed.
* So, each may react individually on a timing failure. The pointer may be
* nullptr, then nothing happens on missing the deadline. The deadline is equal to the next
* execution of the periodic task.
*/
void (*deadlineMissedFunc)(void);
/** /**
* @brief This is the function executed in the new task's context. * @brief This is the function executed in the new task's context.
* @details It converts the argument back to the thread object type and copies the class * @details It converts the argument back to the thread object type and copies the class
@ -110,7 +82,7 @@ class PeriodicTask : public RTEMSTaskBase, public PeriodicTaskIF {
* are called. Afterwards the checkAndRestartPeriod system call blocks the task until the next * are called. Afterwards the checkAndRestartPeriod system call blocks the task until the next
* period. On missing the deadline, the deadlineMissedFunction is executed. * period. On missing the deadline, the deadlineMissedFunction is executed.
*/ */
void taskFunctionality(void); [[noreturn]] void taskFunctionality();
}; };
#endif /* FSFW_OSAL_RTEMS_PERIODICTASK_H_ */ #endif /* FSFW_OSAL_RTEMS_PERIODICTASK_H_ */

View File

@ -45,9 +45,9 @@ QueueFactory* QueueFactory::instance() {
return factoryInstance; return factoryInstance;
} }
QueueFactory::QueueFactory() {} QueueFactory::QueueFactory() = default;
QueueFactory::~QueueFactory() {} QueueFactory::~QueueFactory() = default;
MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, size_t maxMessageSize, MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, size_t maxMessageSize,
MqArgs* args) { MqArgs* args) {

View File

@ -32,7 +32,7 @@ RTEMSTaskBase::RTEMSTaskBase(rtems_task_priority set_priority, size_t stack_size
RTEMSTaskBase::~RTEMSTaskBase() { rtems_task_delete(id); } RTEMSTaskBase::~RTEMSTaskBase() { rtems_task_delete(id); }
rtems_id RTEMSTaskBase::getId() { return this->id; } rtems_id RTEMSTaskBase::getId() const { return this->id; }
ReturnValue_t RTEMSTaskBase::sleepFor(uint32_t ms) { ReturnValue_t RTEMSTaskBase::sleepFor(uint32_t ms) {
rtems_status_code status = rtems_task_wake_after(RtemsBasic::convertMsToTicks(ms)); rtems_status_code status = rtems_task_wake_after(RtemsBasic::convertMsToTicks(ms));

View File

@ -36,9 +36,9 @@ class RTEMSTaskBase {
/** /**
* @brief This method returns the task id of this class. * @brief This method returns the task id of this class.
*/ */
rtems_id getId(); rtems_id getId() const;
ReturnValue_t sleepFor(uint32_t ms); static ReturnValue_t sleepFor(uint32_t ms);
static ReturnValue_t setAndStartPeriod(rtems_interval period, rtems_id *periodId); static ReturnValue_t setAndStartPeriod(rtems_interval period, rtems_id *periodId);
static rtems_status_code restartPeriod(rtems_interval period, rtems_id periodId); static rtems_status_code restartPeriod(rtems_interval period, rtems_id periodId);

View File

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

View File

@ -29,9 +29,9 @@ class PowerSwitchIF : public HasReturnvaluesIF {
static const ReturnValue_t FUSE_ON = MAKE_RETURN_CODE(3); static const ReturnValue_t FUSE_ON = MAKE_RETURN_CODE(3);
static const ReturnValue_t FUSE_OFF = MAKE_RETURN_CODE(4); static const ReturnValue_t FUSE_OFF = MAKE_RETURN_CODE(4);
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PCDU_2; static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PCDU_2;
static const Event SWITCH_WENT_OFF = MAKE_EVENT( //!< Someone detected that a switch went off which shouldn't. Severity:
0, severity::LOW); //!< Someone detected that a switch went off which shouldn't. Severity: //!< Low, Parameter1: switchId1, Parameter2: switchId2
//!< Low, Parameter1: switchId1, Parameter2: switchId2 static const Event SWITCH_WENT_OFF = MAKE_EVENT(0, severity::LOW);
/** /**
* send a direct command to the Power Unit to enable/disable the specified switch. * send a direct command to the Power Unit to enable/disable the specified switch.
* *

View File

@ -615,23 +615,23 @@ inline ReturnValue_t Service11TelecommandScheduling<MAX_NUM_TCS>::handleInvalidD
template <size_t MAX_NUM_TCS> template <size_t MAX_NUM_TCS>
inline void Service11TelecommandScheduling<MAX_NUM_TCS>::debugPrintMultimapContent() const { inline void Service11TelecommandScheduling<MAX_NUM_TCS>::debugPrintMultimapContent() const {
for ([[maybe_unused]] const auto &dit : telecommandMap) {
#if FSFW_DISABLE_PRINTOUT == 0 #if FSFW_DISABLE_PRINTOUT == 0
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "Service11TelecommandScheduling::debugPrintMultimapContent: Multimap Content" sif::debug << "Service11TelecommandScheduling::debugPrintMultimapContent: Multimap Content"
<< std::endl; << 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 << " | " sif::debug << "[" << dit.first << "]: Request ID: " << dit.second.requestId << " | "
<< "Store Address: " << dit.second.storeAddr.raw << std::endl; << "Store Address: " << dit.second.storeAddr.raw << std::endl;
#else #else
sif::printDebug( sif::printDebug("[%d]: Request ID: %d | Store Address: %d\n", dit.first, dit.second.requestId,
"Service11TelecommandScheduling::debugPrintMultimapContent: Multimap Content\n"); dit.second.storeAddr);
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
#endif #endif
} }
#endif
} }
template <size_t MAX_NUM_TCS> template <size_t MAX_NUM_TCS>

View File

@ -248,16 +248,18 @@ void Service3Housekeeping::handleUnrequestedReply(CommandMessage* reply) {
case (HousekeepingMessage::HK_REQUEST_FAILURE): { case (HousekeepingMessage::HK_REQUEST_FAILURE): {
break; break;
} }
case(CommandMessage::REPLY_REJECTED): { case (CommandMessage::REPLY_REJECTED): {
sif::warning << "Service3Housekeeping::handleUnrequestedReply: Unexpected reply " sif::warning << "Service3Housekeeping::handleUnrequestedReply: Unexpected reply "
"rejected with error code" << reply->getParameter() << std::endl; "rejected with error code"
<< reply->getParameter() << std::endl;
break; break;
} }
default: { default: {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "Service3Housekeeping::handleUnrequestedReply: Invalid reply with reply " sif::warning << "Service3Housekeeping::handleUnrequestedReply: Invalid reply with reply "
"command " << command << "" << std::endl; "command "
<< command << "" << std::endl;
#else #else
sif::printWarning( sif::printWarning(
"Service3Housekeeping::handleUnrequestedReply: Invalid reply with " "Service3Housekeeping::handleUnrequestedReply: Invalid reply with "

View File

@ -13,7 +13,7 @@ StorageAccessor::StorageAccessor(store_address_t storeId, StorageManagerIF* stor
StorageAccessor& StorageAccessor::operator=(StorageAccessor&& other) { StorageAccessor& StorageAccessor::operator=(StorageAccessor&& other) {
// Call the parent move assignment and also assign own member. // Call the parent move assignment and also assign own member.
dataPointer = other.dataPointer; dataPointer = other.dataPointer;
StorageAccessor::operator=(std::move(other)); ConstStorageAccessor::operator=(std::move(other));
return *this; return *this;
} }

View File

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

View File

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

View File

@ -11,19 +11,17 @@ bool FixedTimeslotTaskBase::isEmpty() const { return pollingSeqTable.isEmpty();
ReturnValue_t FixedTimeslotTaskBase::checkSequence() { return pollingSeqTable.checkSequence(); } ReturnValue_t FixedTimeslotTaskBase::checkSequence() { return pollingSeqTable.checkSequence(); }
ReturnValue_t FixedTimeslotTaskBase::addSlot(object_id_t componentId, uint32_t slotTimeMs, ReturnValue_t FixedTimeslotTaskBase::addSlot(object_id_t execId, ExecutableObjectIF* execObj,
int8_t executionStep) { uint32_t slotTimeMs, int8_t executionStep) {
auto* executableObject = ObjectManager::instance()->get<ExecutableObjectIF>(componentId); if (execObj == nullptr) {
if (executableObject != nullptr) {
pollingSeqTable.addSlot(componentId, slotTimeMs, executionStep, executableObject, this);
return HasReturnvaluesIF::RETURN_OK;
}
#if FSFW_CPP_OSTREAM_ENABLED == 1 #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; << std::setfill(' ') << " not found, not adding it to PST" << std::dec << std::endl;
#else #else
sif::printError("Component 0x%08x not found, not adding it to PST\n"); sif::printError("Component 0x%08x not found, not adding it to PST\n");
#endif #endif
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
}
pollingSeqTable.addSlot(execId, slotTimeMs, executionStep, execObj, this);
return HasReturnvaluesIF::RETURN_OK;
} }

View File

@ -37,7 +37,7 @@ class FixedTimeslotTaskBase : public FixedTimeslotTaskIF {
[[nodiscard]] bool isEmpty() const override; [[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; int8_t executionStep) override;
}; };

View File

@ -2,6 +2,7 @@
#define FRAMEWORK_TASKS_FIXEDTIMESLOTTASKIF_H_ #define FRAMEWORK_TASKS_FIXEDTIMESLOTTASKIF_H_
#include "PeriodicTaskIF.h" #include "PeriodicTaskIF.h"
#include "fsfw/objectmanager/ObjectManager.h"
#include "fsfw/objectmanager/ObjectManagerIF.h" #include "fsfw/objectmanager/ObjectManagerIF.h"
#include "fsfw/returnvalues/FwClassIds.h" #include "fsfw/returnvalues/FwClassIds.h"
@ -15,6 +16,19 @@ class FixedTimeslotTaskIF : public PeriodicTaskIF {
static constexpr ReturnValue_t SLOT_LIST_EMPTY = static constexpr ReturnValue_t SLOT_LIST_EMPTY =
HasReturnvaluesIF::makeReturnCode(CLASS_ID::FIXED_SLOT_TASK_IF, 0); HasReturnvaluesIF::makeReturnCode(CLASS_ID::FIXED_SLOT_TASK_IF, 0);
/**
* Add an object with a slot time and the execution step to the task.
* The execution step will be passed to the object (e.g. as an operation
* code in #performOperation)
* @param componentId
* @param slotTimeMs
* @param executionStep
* @return
*/
virtual ReturnValue_t addSlot(object_id_t execId, ExecutableObjectIF* obj, uint32_t slotTimeMs,
int8_t executionStep) = 0;
/** /**
* Add an object with a slot time and the execution step to the task. * Add an object with a slot time and the execution step to the task.
* The execution step will be passed to the object (e.g. as an operation * The execution step will be passed to the object (e.g. as an operation
@ -25,12 +39,24 @@ class FixedTimeslotTaskIF : public PeriodicTaskIF {
* @return * @return
*/ */
virtual ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs, virtual ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs,
int8_t executionStep) = 0; int8_t executionStep) {
auto* execObj = ObjectManager::instance()->get<ExecutableObjectIF>(componentId);
return addSlot(componentId, execObj, slotTimeMs, executionStep);
}
/** /**
* Check whether the sequence is valid and perform all other required * Check whether the sequence is valid and perform all other required
* initialization steps which are needed after task creation * initialization steps which are needed after task creation
*/ */
virtual ReturnValue_t checkSequence() = 0; virtual ReturnValue_t checkSequence() = 0;
ReturnValue_t addComponent(object_id_t object, uint8_t opCode) override {
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t addComponent(ExecutableObjectIF* object, uint8_t opCode) override {
return HasReturnvaluesIF::RETURN_FAILED;
}
}; };
#endif /* FRAMEWORK_TASKS_FIXEDTIMESLOTTASKIF_H_ */ #endif /* FRAMEWORK_TASKS_FIXEDTIMESLOTTASKIF_H_ */

View File

@ -21,8 +21,14 @@ uint32_t PeriodicTaskBase::getPeriodMs() const { return static_cast<uint32_t>(pe
bool PeriodicTaskBase::isEmpty() const { return objectList.empty(); } 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() { ReturnValue_t PeriodicTaskBase::initObjsAfterTaskCreation() {
std::multiset<ExecutableObjectIF*> uniqueObjects; std::set<ExecutableObjectIF*> uniqueObjects;
ReturnValue_t status = HasReturnvaluesIF::RETURN_OK; ReturnValue_t status = HasReturnvaluesIF::RETURN_OK;
uint32_t count = 0; uint32_t count = 0;
for (const auto& obj : objectList) { for (const auto& obj : objectList) {

View File

@ -17,6 +17,9 @@ class PeriodicTaskBase : public PeriodicTaskIF {
ReturnValue_t addComponent(object_id_t object, uint8_t opCode) override; ReturnValue_t addComponent(object_id_t object, uint8_t opCode) override;
ReturnValue_t addComponent(ExecutableObjectIF* object, uint8_t opCode) override; ReturnValue_t addComponent(ExecutableObjectIF* object, uint8_t opCode) override;
ReturnValue_t addComponent(object_id_t object) override;
ReturnValue_t addComponent(ExecutableObjectIF* object) override;
[[nodiscard]] uint32_t getPeriodMs() const override; [[nodiscard]] uint32_t getPeriodMs() const override;
[[nodiscard]] bool isEmpty() const override; [[nodiscard]] bool isEmpty() const override;

View File

@ -31,9 +31,8 @@ class PeriodicTaskIF {
* @param object Id of the object to add. * @param object Id of the object to add.
* @return RETURN_OK on success, RETURN_FAILED if the object could not be added. * @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) { virtual ReturnValue_t addComponent(object_id_t object, uint8_t opCode) = 0;
return HasReturnvaluesIF::RETURN_FAILED; virtual ReturnValue_t addComponent(object_id_t object) { return addComponent(object, 0); };
};
/** /**
* Adds an object to the list of objects to be executed. * 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. * @param object pointer to the object to add.
* @return RETURN_OK on success, RETURN_FAILED if the object could not be added. * @return RETURN_OK on success, RETURN_FAILED if the object could not be added.
*/ */
virtual ReturnValue_t addComponent(ExecutableObjectIF* object, uint8_t opCode = 0) { virtual ReturnValue_t addComponent(ExecutableObjectIF* object, uint8_t opCode) = 0;
return HasReturnvaluesIF::RETURN_FAILED; virtual ReturnValue_t addComponent(ExecutableObjectIF* object) { return addComponent(object, 0); }
};
virtual ReturnValue_t sleepFor(uint32_t ms) = 0; virtual ReturnValue_t sleepFor(uint32_t ms) = 0;
virtual uint32_t getPeriodMs() const = 0; [[nodiscard]] virtual uint32_t getPeriodMs() const = 0;
virtual bool isEmpty() const = 0; [[nodiscard]] virtual bool isEmpty() const = 0;
}; };
#endif /* PERIODICTASKIF_H_ */ #endif /* FRAMEWORK_TASK_PERIODICTASKIF_H_ */

View File

@ -13,9 +13,9 @@ class ThermalComponentIF : public HasParametersIF {
static const Event COMPONENT_TEMP_HIGH = MAKE_EVENT(2, severity::LOW); static const Event COMPONENT_TEMP_HIGH = MAKE_EVENT(2, severity::LOW);
static const Event COMPONENT_TEMP_OOL_LOW = MAKE_EVENT(3, severity::LOW); static const Event COMPONENT_TEMP_OOL_LOW = MAKE_EVENT(3, severity::LOW);
static const Event COMPONENT_TEMP_OOL_HIGH = MAKE_EVENT(4, severity::LOW); static const Event COMPONENT_TEMP_OOL_HIGH = MAKE_EVENT(4, severity::LOW);
static const Event TEMP_NOT_IN_OP_RANGE = MAKE_EVENT( //!< Is thrown when a device should start-up, but the temperature is out
5, severity::LOW); //!< Is thrown when a device should start-up, but the temperature is out //!< of OP range. P1: thermalState of the component, P2: 0
//!< of OP range. P1: thermalState of the component, P2: 0 static const Event TEMP_NOT_IN_OP_RANGE = MAKE_EVENT(5, severity::LOW);
static const uint8_t INTERFACE_ID = CLASS_ID::THERMAL_COMPONENT_IF; static const uint8_t INTERFACE_ID = CLASS_ID::THERMAL_COMPONENT_IF;
static const ReturnValue_t INVALID_TARGET_STATE = MAKE_RETURN_CODE(1); static const ReturnValue_t INVALID_TARGET_STATE = MAKE_RETURN_CODE(1);

View File

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

View File

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

View File

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

View File

@ -2,7 +2,9 @@
#include <catch2/catch_test_macros.hpp> #include <catch2/catch_test_macros.hpp>
#include <fstream> #include <fstream>
#include <iostream>
#include "tests/TestsConfig.h"
#include "fsfw/container/DynamicFIFO.h" #include "fsfw/container/DynamicFIFO.h"
#include "fsfw/container/SimpleRingBuffer.h" #include "fsfw/container/SimpleRingBuffer.h"
#include "fsfw/platform.h" #include "fsfw/platform.h"
@ -61,6 +63,9 @@ TEST_CASE("Command Executor", "[cmd-exec]") {
std::string cmpString = "Hello World\n"; std::string cmpString = "Hello World\n";
CHECK(readString == cmpString); CHECK(readString == cmpString);
outputBuffer.deleteData(12, true); outputBuffer.deleteData(12, true);
// Issues with CI/CD
#if FSFW_CICD_BUILD == 0
// Test more complex command // Test more complex command
result = cmdExecutor.load("ping -c 1 localhost", false, false); result = cmdExecutor.load("ping -c 1 localhost", false, false);
REQUIRE(cmdExecutor.getCurrentState() == CommandExecutor::States::COMMAND_LOADED); REQUIRE(cmdExecutor.getCurrentState() == CommandExecutor::States::COMMAND_LOADED);
@ -81,16 +86,27 @@ TEST_CASE("Command Executor", "[cmd-exec]") {
REQUIRE(cmdExecutor.getCurrentState() == CommandExecutor::States::IDLE); REQUIRE(cmdExecutor.getCurrentState() == CommandExecutor::States::IDLE);
readBytes = 0; readBytes = 0;
sizesFifo.retrieve(&readBytes); sizesFifo.retrieve(&readBytes);
// That's about the size of the reply
bool beTrue = (readBytes > 200) and (readBytes < 300);
REQUIRE(beTrue);
uint8_t largerReadBuffer[1024] = {}; 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); outputBuffer.readData(largerReadBuffer, readBytes);
// You can also check this output in the debugger // You can also check this output in the debugger
std::string allTheReply(reinterpret_cast<char*>(largerReadBuffer)); std::string allTheReply(reinterpret_cast<char*>(largerReadBuffer));
// I am just going to assume that this string is the same across ping implementations // I am just going to assume that this string is the same across ping implementations
// of different Linux systems // of different Linux systems
REQUIRE(allTheReply.find("PING localhost") != std::string::npos); REQUIRE(allTheReply.find("PING localhost") != std::string::npos);
#endif
// Now check failing command // Now check failing command
result = cmdExecutor.load("false", false, false); result = cmdExecutor.load("false", false, false);

View File

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

View File

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

View File

@ -156,4 +156,31 @@ TEST_CASE("New Accessor", "[NewAccessor]") {
CHECK(receptionArray[i] == 42); 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);
}
}
} }

View File

@ -3,6 +3,7 @@
#include <catch2/catch_test_macros.hpp> #include <catch2/catch_test_macros.hpp>
#include <cstring> #include <cstring>
#include <array>
#include "fsfw_tests/unit/CatchDefinitions.h" #include "fsfw_tests/unit/CatchDefinitions.h"

View File

@ -1,6 +1,8 @@
#ifndef FSFW_UNITTEST_CONFIG_TESTSCONFIG_H_ #ifndef FSFW_UNITTEST_CONFIG_TESTSCONFIG_H_
#define FSFW_UNITTEST_CONFIG_TESTSCONFIG_H_ #define FSFW_UNITTEST_CONFIG_TESTSCONFIG_H_
#cmakedefine01 FSFW_CICD_BUILD
#define FSFW_ADD_DEFAULT_FACTORY_FUNCTIONS 1 #define FSFW_ADD_DEFAULT_FACTORY_FUNCTIONS 1
#ifdef __cplusplus #ifdef __cplusplus