Merge remote-tracking branch 'upstream/development' into mueller/update-cmd-reply-maps-refactoring
This commit is contained in:
commit
4789200750
8
.gitignore
vendored
8
.gitignore
vendored
@ -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
Normal file
14
.idea/codeStyles/Project.xml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
|
<code_scheme name="Project" version="173">
|
||||||
|
<clangFormatSettings>
|
||||||
|
<option name="ENABLED" value="true" />
|
||||||
|
</clangFormatSettings>
|
||||||
|
<codeStyleSettings language="CMake">
|
||||||
|
<indentOptions>
|
||||||
|
<option name="INDENT_SIZE" value="2" />
|
||||||
|
<option name="CONTINUATION_INDENT_SIZE" value="0" />
|
||||||
|
<option name="TAB_SIZE" value="2" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
</code_scheme>
|
||||||
|
</component>
|
5
.idea/codeStyles/codeStyleConfig.xml
Normal file
5
.idea/codeStyles/codeStyleConfig.xml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
|
<state>
|
||||||
|
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||||
|
</state>
|
||||||
|
</component>
|
7
.run/fsfw-tests_coverage.run.xml
Normal file
7
.run/fsfw-tests_coverage.run.xml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="fsfw-tests_coverage" type="CMakeRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="fsfw-tests" TARGET_NAME="fsfw-tests_coverage" CONFIG_NAME="Debug Unittest" RUN_TARGET_PROJECT_NAME="fsfw-tests" RUN_TARGET_NAME="fsfw-tests">
|
||||||
|
<method v="2">
|
||||||
|
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
7
.run/fsfw.run.xml
Normal file
7
.run/fsfw.run.xml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="fsfw" type="CMakeRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="fsfw-tests" TARGET_NAME="fsfw" CONFIG_NAME="Debug Unittest" RUN_TARGET_PROJECT_NAME="fsfw-tests" RUN_TARGET_NAME="fsfw-tests">
|
||||||
|
<method v="2">
|
||||||
|
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
57
CHANGELOG.md
57
CHANGELOG.md
@ -12,6 +12,10 @@ 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
|
||||||
@ -27,7 +31,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
- `oneShotAction` flag in the `TestTask` class is not static anymore
|
- `oneShotAction` flag in the `TestTask` class is not static anymore
|
||||||
- Major update for version handling, using `git describe` to fetch version information with git.
|
- Major update for version handling, using `git describe` to fetch version information with git.
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/601
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/601
|
||||||
- Place `Version` class outside of `fsfw` namespace. It is generic
|
|
||||||
- Add helper functions provided by [`cmake-modules`](https://github.com/bilke/cmake-modules)
|
- Add helper functions provided by [`cmake-modules`](https://github.com/bilke/cmake-modules)
|
||||||
manually now. Those should not change too often and only a small subset is needed
|
manually now. Those should not change too often and only a small subset is needed
|
||||||
- Separate folder for easier update and for distinction
|
- Separate folder for easier update and for distinction
|
||||||
@ -44,6 +47,38 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
the message queue. Also streamlined and simplified `MessageQueue` implementation for all OSALs
|
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
|
||||||
@ -85,6 +120,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.
|
||||||
@ -99,9 +139,13 @@ https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/593
|
|||||||
- https://gitlab.kitware.com/cmake/cmake/-/issues/21696
|
- https://gitlab.kitware.com/cmake/cmake/-/issues/21696
|
||||||
Easiest solution for now: Keep this option OFF by default.
|
Easiest solution for now: Keep this option OFF by default.
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/616
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/616
|
||||||
|
- Linux HAL: Add wiretapping option for I2C. Enabled with `FSFW_HAL_I2C_WIRETAPPING` defined to 1
|
||||||
- Dedicated Version class and constant `fsfw::FSFW_VERSION` containing version information
|
- Dedicated Version class and constant `fsfw::FSFW_VERSION` containing version information
|
||||||
inside `fsfw/version.h`
|
inside `fsfw/version.h`
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/559
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/559
|
||||||
|
- Added generic PUS TC Scheduler Service 11. It depends on the new added Emebeded Template Library
|
||||||
|
(ETL) dependency.
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/594
|
||||||
- Added ETL dependency and improved library dependency management
|
- Added ETL dependency and improved library dependency management
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/592
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/592
|
||||||
- Add a `DummyPowerSwitcher` module which can be useful for test setups when no PCDU is available
|
- Add a `DummyPowerSwitcher` module which can be useful for test setups when no PCDU is available
|
||||||
@ -110,17 +154,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
|
||||||
|
123
CMakeLists.txt
123
CMakeLists.txt
@ -1,29 +1,77 @@
|
|||||||
cmake_minimum_required(VERSION 3.13)
|
cmake_minimum_required(VERSION 3.13)
|
||||||
set(LIB_FSFW_NAME fsfw)
|
|
||||||
project(${LIB_FSFW_NAME})
|
|
||||||
|
|
||||||
if(NOT CMAKE_CXX_STANDARD)
|
set(MSG_PREFIX "fsfw |")
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
# Add the cmake folder so the FindSphinx module is found
|
||||||
elseif(${CMAKE_CXX_STANDARD} LESS 17)
|
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||||
message(FATAL_ERROR "Compiling the FSFW requires a minimum of C++17 support")
|
list(APPEND CMAKE_MODULE_PATH
|
||||||
endif()
|
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake-modules/bilke")
|
||||||
|
list(APPEND CMAKE_MODULE_PATH
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake-modules/rpavlik")
|
||||||
|
|
||||||
|
# ##############################################################################
|
||||||
|
# Version file handling #
|
||||||
|
# ##############################################################################
|
||||||
|
|
||||||
set(FSFW_VERSION_IF_GIT_FAILS 4)
|
set(FSFW_VERSION_IF_GIT_FAILS 4)
|
||||||
set(FSFW_SUBVERSION_IF_GIT_FAILS 0)
|
set(FSFW_SUBVERSION_IF_GIT_FAILS 0)
|
||||||
set(FSFW_REVISION_IF_GIT_FAILS 0)
|
set(FSFW_REVISION_IF_GIT_FAILS 0)
|
||||||
|
|
||||||
# Add the cmake folder so the FindSphinx module is found
|
set(FSFW_GIT_VER_HANDLING_OK FALSE)
|
||||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
# Version handling
|
||||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake-modules")
|
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git)
|
||||||
set(MSG_PREFIX "fsfw |")
|
message(STATUS "${MSG_PREFIX} Determining version information with git")
|
||||||
|
include(FsfwHelpers)
|
||||||
|
determine_version_with_git("--exclude" "docker_*")
|
||||||
|
if(GIT_INFO)
|
||||||
|
set(FSFW_GIT_INFO
|
||||||
|
${GIT_INFO}
|
||||||
|
CACHE STRING "Version information retrieved with git describe")
|
||||||
|
list(GET FSFW_GIT_INFO 1 FSFW_VERSION)
|
||||||
|
list(GET FSFW_GIT_INFO 2 FSFW_SUBVERSION)
|
||||||
|
list(GET FSFW_GIT_INFO 3 FSFW_REVISION)
|
||||||
|
list(GET FSFW_GIT_INFO 4 FSFW_VCS_INFO)
|
||||||
|
if(NOT FSFW_VERSION)
|
||||||
|
set(FSFW_VERSION ${FSFW_VERSION_IF_GIT_FAILS})
|
||||||
|
endif()
|
||||||
|
if(NOT FSFW_SUBVERSION)
|
||||||
|
set(FSFW_SUBVERSION ${FSFW_SUBVERSION_IF_GIT_FAILS})
|
||||||
|
endif()
|
||||||
|
if(NOT FSFW_REVISION)
|
||||||
|
set(FSFW_REVISION ${FSFW_REVISION_IF_GIT_FAILS})
|
||||||
|
endif()
|
||||||
|
set(FSFW_GIT_VER_HANDLING_OK TRUE)
|
||||||
|
else()
|
||||||
|
set(FSFW_GIT_VER_HANDLING_OK FALSE)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
if(NOT FSFW_GIT_VER_HANDLING_OK)
|
||||||
|
set(FSFW_VERSION ${FSFW_VERSION_IF_GIT_FAILS})
|
||||||
|
set(FSFW_SUBVERSION ${FSFW_SUBVERSION_IF_GIT_FAILS})
|
||||||
|
set(FSFW_REVISION ${FSFW_REVISION_IF_GIT_FAILS})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(LIB_FSFW_NAME fsfw)
|
||||||
|
project(${LIB_FSFW_NAME}
|
||||||
|
VERSION ${FSFW_VERSION}.${FSFW_SUBVERSION}.${FSFW_REVISION})
|
||||||
|
|
||||||
|
if(NOT CMAKE_CXX_STANDARD)
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||||
|
elseif(${CMAKE_CXX_STANDARD} LESS 17)
|
||||||
|
message(
|
||||||
|
FATAL_ERROR
|
||||||
|
"${MSG_PREFIX} Compiling the FSFW requires a minimum of C++17 support")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(FSFW_SOURCES_DIR "${CMAKE_SOURCE_DIR}/src/fsfw")
|
||||||
|
|
||||||
set(FSFW_ETL_LIB_NAME etl)
|
set(FSFW_ETL_LIB_NAME etl)
|
||||||
set(FSFW_ETL_LIB_MAJOR_VERSION
|
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)
|
||||||
|
|
||||||
@ -57,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)
|
||||||
@ -90,47 +139,13 @@ if(IPO_SUPPORTED AND FSFW_ENABLE_IPO)
|
|||||||
TRUE)
|
TRUE)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(FSFW_GIT_VER_HANDLING_OK FALSE)
|
|
||||||
# Version handling
|
|
||||||
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git)
|
|
||||||
message(STATUS "${MSG_PREFIX} Determining version information with git")
|
|
||||||
include(FsfwHelpers)
|
|
||||||
determine_version_with_git("--exclude" "docker_*")
|
|
||||||
if(GIT_INFO)
|
|
||||||
set(FSFW_GIT_INFO
|
|
||||||
${GIT_INFO}
|
|
||||||
CACHE STRING "Version information retrieved with git describe")
|
|
||||||
list(GET FSFW_GIT_INFO 1 FSFW_VERSION)
|
|
||||||
list(GET FSFW_GIT_INFO 2 FSFW_SUBVERSION)
|
|
||||||
list(GET FSFW_GIT_INFO 3 FSFW_REVISION)
|
|
||||||
list(GET FSFW_GIT_INFO 4 FSFW_VERSION_CST_GIT_SHA1)
|
|
||||||
if(NOT FSFW_VERSION)
|
|
||||||
set(FSFW_VERSION ${FSFW_VERSION_IF_GIT_FAILS})
|
|
||||||
endif()
|
|
||||||
if(NOT FSFW_SUBVERSION)
|
|
||||||
set(FSFW_SUBVERSION ${FSFW_SUBVERSION_IF_GIT_FAILS})
|
|
||||||
endif()
|
|
||||||
if(NOT FSFW_REVISION)
|
|
||||||
set(FSFW_REVISION ${FSFW_REVISION_IF_GIT_FAILS})
|
|
||||||
endif()
|
|
||||||
set(FSFW_GIT_VER_HANDLING_OK TRUE)
|
|
||||||
else()
|
|
||||||
set(FSFW_GIT_VER_HANDLING_OK FALSE)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
if(NOT FSFW_GIT_VER_HANDLING_OK)
|
|
||||||
set(FSFW_VERSION ${FSFW_VERSION_IF_GIT_FAILS})
|
|
||||||
set(FSFW_SUBVERSION ${FSFW_SUBVERSION_IF_GIT_FAILS})
|
|
||||||
set(FSFW_REVISION ${FSFW_REVISION_IF_GIT_FAILS})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(FSFW_BUILD_UNITTESTS)
|
if(FSFW_BUILD_UNITTESTS)
|
||||||
message(
|
message(
|
||||||
STATUS
|
STATUS
|
||||||
"${MSG_PREFIX} Building the FSFW unittests in addition to the static library"
|
"${MSG_PREFIX} Building the FSFW unittests in addition to the static library"
|
||||||
)
|
)
|
||||||
# Check whether the user has already installed Catch2 first
|
# Check whether the user has already installed Catch2 first
|
||||||
find_package(Catch2 ${FSFW_CATCH2_LIB_MAJOR_VERSION} CONFIG QUIET)
|
find_package(Catch2 ${FSFW_CATCH2_LIB_MAJOR_VERSION})
|
||||||
# Not installed, so use FetchContent to download and provide Catch2
|
# Not installed, so use FetchContent to download and provide Catch2
|
||||||
if(NOT Catch2_FOUND)
|
if(NOT Catch2_FOUND)
|
||||||
message(
|
message(
|
||||||
@ -168,13 +183,10 @@ if(FSFW_BUILD_UNITTESTS)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
message(
|
message(STATUS "${MSG_PREFIX} Finding and/or providing ETL library")
|
||||||
STATUS
|
|
||||||
"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(
|
||||||
@ -217,7 +229,9 @@ target_include_directories(${LIB_FSFW_NAME}
|
|||||||
|
|
||||||
# Backwards comptability
|
# Backwards comptability
|
||||||
if(OS_FSFW AND NOT FSFW_OSAL)
|
if(OS_FSFW AND NOT FSFW_OSAL)
|
||||||
message(WARNING "Please pass the FSFW OSAL as FSFW_OSAL instead of OS_FSFW")
|
message(
|
||||||
|
WARNING
|
||||||
|
"${MSG_PREFIX} Please pass the FSFW OSAL as FSFW_OSAL instead of OS_FSFW")
|
||||||
set(FSFW_OSAL OS_FSFW)
|
set(FSFW_OSAL OS_FSFW)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@ -233,7 +247,6 @@ if(NOT FSFW_OSAL)
|
|||||||
"host"
|
"host"
|
||||||
CACHE STRING "OS abstraction layer used in the FSFW")
|
CACHE STRING "OS abstraction layer used in the FSFW")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(FSFW_OSAL_DEFINITION FSFW_OSAL_HOST)
|
set(FSFW_OSAL_DEFINITION FSFW_OSAL_HOST)
|
||||||
|
0
FSFWVersion.h.in
Normal file
0
FSFWVersion.h.in
Normal 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 ..
|
||||||
```
|
```
|
||||||
|
|
||||||
|
2
automation/Jenkinsfile
vendored
2
automation/Jenkinsfile
vendored
@ -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 ..'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,141 +0,0 @@
|
|||||||
# - Returns a version string from Git
|
|
||||||
#
|
|
||||||
# These functions force a re-configure on each git commit so that you can
|
|
||||||
# trust the values of the variables in your build system.
|
|
||||||
#
|
|
||||||
# get_git_head_revision(<refspecvar> <hashvar> [<additional arguments to git describe> ...])
|
|
||||||
#
|
|
||||||
# Returns the refspec and sha hash of the current head revision
|
|
||||||
#
|
|
||||||
# git_describe(<var> [<additional arguments to git describe> ...])
|
|
||||||
#
|
|
||||||
# Returns the results of git describe on the source tree, and adjusting
|
|
||||||
# the output so that it tests false if an error occurs.
|
|
||||||
#
|
|
||||||
# git_get_exact_tag(<var> [<additional arguments to git describe> ...])
|
|
||||||
#
|
|
||||||
# Returns the results of git describe --exact-match on the source tree,
|
|
||||||
# and adjusting the output so that it tests false if there was no exact
|
|
||||||
# matching tag.
|
|
||||||
#
|
|
||||||
# Requires CMake 2.6 or newer (uses the 'function' command)
|
|
||||||
#
|
|
||||||
# Original Author:
|
|
||||||
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
|
|
||||||
# http://academic.cleardefinition.com
|
|
||||||
# Iowa State University HCI Graduate Program/VRAC
|
|
||||||
#
|
|
||||||
# Copyright Iowa State University 2009-2010.
|
|
||||||
# Distributed under the Boost Software License, Version 1.0.
|
|
||||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
|
||||||
# http://www.boost.org/LICENSE_1_0.txt)
|
|
||||||
|
|
||||||
if(__get_git_revision_description)
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
set(__get_git_revision_description YES)
|
|
||||||
|
|
||||||
# We must run the following at "include" time, not at function call time,
|
|
||||||
# to find the path to this module rather than the path to a calling list file
|
|
||||||
get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH)
|
|
||||||
|
|
||||||
function(get_git_head_revision _refspecvar _hashvar)
|
|
||||||
set(GIT_PARENT_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
|
|
||||||
set(GIT_DIR "${GIT_PARENT_DIR}/.git")
|
|
||||||
while(NOT EXISTS "${GIT_DIR}") # .git dir not found, search parent directories
|
|
||||||
set(GIT_PREVIOUS_PARENT "${GIT_PARENT_DIR}")
|
|
||||||
get_filename_component(GIT_PARENT_DIR ${GIT_PARENT_DIR} PATH)
|
|
||||||
if(GIT_PARENT_DIR STREQUAL GIT_PREVIOUS_PARENT)
|
|
||||||
# We have reached the root directory, we are not in git
|
|
||||||
set(${_refspecvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
|
|
||||||
set(${_hashvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
set(GIT_DIR "${GIT_PARENT_DIR}/.git")
|
|
||||||
endwhile()
|
|
||||||
# check if this is a submodule
|
|
||||||
if(NOT IS_DIRECTORY ${GIT_DIR})
|
|
||||||
file(READ ${GIT_DIR} submodule)
|
|
||||||
string(REGEX REPLACE "gitdir: (.*)\n$" "\\1" GIT_DIR_RELATIVE ${submodule})
|
|
||||||
get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH)
|
|
||||||
|
|
||||||
if (IS_ABSOLUTE ${GIT_DIR_RELATIVE})
|
|
||||||
set(GIT_DIR ${GIT_DIR_RELATIVE})
|
|
||||||
else()
|
|
||||||
get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE} ABSOLUTE)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
endif()
|
|
||||||
set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data")
|
|
||||||
if(NOT EXISTS "${GIT_DATA}")
|
|
||||||
file(MAKE_DIRECTORY "${GIT_DATA}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(NOT EXISTS "${GIT_DIR}/HEAD")
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
set(HEAD_FILE "${GIT_DATA}/HEAD")
|
|
||||||
configure_file("${GIT_DIR}/HEAD" "${HEAD_FILE}" COPYONLY)
|
|
||||||
|
|
||||||
configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in"
|
|
||||||
"${GIT_DATA}/grabRef.cmake"
|
|
||||||
@ONLY)
|
|
||||||
include("${GIT_DATA}/grabRef.cmake")
|
|
||||||
|
|
||||||
set(${_refspecvar} "${HEAD_REF}" PARENT_SCOPE)
|
|
||||||
set(${_hashvar} "${HEAD_HASH}" PARENT_SCOPE)
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
function(git_describe _var)
|
|
||||||
if(NOT GIT_FOUND)
|
|
||||||
find_package(Git QUIET)
|
|
||||||
endif()
|
|
||||||
get_git_head_revision(refspec hash)
|
|
||||||
if(NOT GIT_FOUND)
|
|
||||||
set(${_var} "GIT-NOTFOUND" PARENT_SCOPE)
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
if(NOT hash)
|
|
||||||
set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE)
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# TODO sanitize
|
|
||||||
#if((${ARGN}" MATCHES "&&") OR
|
|
||||||
# (ARGN MATCHES "||") OR
|
|
||||||
# (ARGN MATCHES "\\;"))
|
|
||||||
# message("Please report the following error to the project!")
|
|
||||||
# message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}")
|
|
||||||
#endif()
|
|
||||||
|
|
||||||
#message(STATUS "Arguments to execute_process: ${ARGN}")
|
|
||||||
|
|
||||||
execute_process(COMMAND
|
|
||||||
${GIT_EXECUTABLE}
|
|
||||||
describe
|
|
||||||
${hash}
|
|
||||||
${ARGN}
|
|
||||||
WORKING_DIRECTORY
|
|
||||||
"${CMAKE_SOURCE_DIR}"
|
|
||||||
RESULT_VARIABLE
|
|
||||||
res
|
|
||||||
OUTPUT_VARIABLE
|
|
||||||
out
|
|
||||||
ERROR_QUIET
|
|
||||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
|
||||||
if(NOT res EQUAL 0)
|
|
||||||
set(out "${out}-${res}-NOTFOUND")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(${_var} "${out}" PARENT_SCOPE)
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
function(git_get_exact_tag _var)
|
|
||||||
git_describe(out --exact-match ${ARGN})
|
|
||||||
set(${_var} "${out}" PARENT_SCOPE)
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
function(git_get_tag _var)
|
|
||||||
git_describe(out --tags ${ARGN})
|
|
||||||
set(${_var} "${out}" PARENT_SCOPE)
|
|
||||||
endfunction()
|
|
@ -1,5 +1,7 @@
|
|||||||
The files in these folder were manually copy and pasted from the
|
The files in the `bilke` folder were manually copy and pasted from the
|
||||||
[cmake-modules repository](https://github.com/bilke/cmake-modules). It was decided to do
|
[cmake-modules repository](https://github.com/bilke/cmake-modules). It was decided to do
|
||||||
this because only a small subset of its provided functions are needed.
|
this because only a small subset of its provided functions are needed.
|
||||||
|
|
||||||
The license file in included here as well.
|
The files in the `rpavlik` folder were manually copy and pasted from the
|
||||||
|
[cmake-modules repository](https://github.com/rpavlik/cmake-modules). It was decided to do
|
||||||
|
this because only a small subset of its provided functions are needed.
|
||||||
|
284
cmake/cmake-modules/rpavlik/GetGitRevisionDescription.cmake
Normal file
284
cmake/cmake-modules/rpavlik/GetGitRevisionDescription.cmake
Normal file
@ -0,0 +1,284 @@
|
|||||||
|
# - Returns a version string from Git
|
||||||
|
#
|
||||||
|
# These functions force a re-configure on each git commit so that you can
|
||||||
|
# trust the values of the variables in your build system.
|
||||||
|
#
|
||||||
|
# get_git_head_revision(<refspecvar> <hashvar> [ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR])
|
||||||
|
#
|
||||||
|
# Returns the refspec and sha hash of the current head revision
|
||||||
|
#
|
||||||
|
# git_describe(<var> [<additional arguments to git describe> ...])
|
||||||
|
#
|
||||||
|
# Returns the results of git describe on the source tree, and adjusting
|
||||||
|
# the output so that it tests false if an error occurs.
|
||||||
|
#
|
||||||
|
# git_describe_working_tree(<var> [<additional arguments to git describe> ...])
|
||||||
|
#
|
||||||
|
# Returns the results of git describe on the working tree (--dirty option),
|
||||||
|
# and adjusting the output so that it tests false if an error occurs.
|
||||||
|
#
|
||||||
|
# git_get_exact_tag(<var> [<additional arguments to git describe> ...])
|
||||||
|
#
|
||||||
|
# Returns the results of git describe --exact-match on the source tree,
|
||||||
|
# and adjusting the output so that it tests false if there was no exact
|
||||||
|
# matching tag.
|
||||||
|
#
|
||||||
|
# git_local_changes(<var>)
|
||||||
|
#
|
||||||
|
# Returns either "CLEAN" or "DIRTY" with respect to uncommitted changes.
|
||||||
|
# Uses the return code of "git diff-index --quiet HEAD --".
|
||||||
|
# Does not regard untracked files.
|
||||||
|
#
|
||||||
|
# Requires CMake 2.6 or newer (uses the 'function' command)
|
||||||
|
#
|
||||||
|
# Original Author:
|
||||||
|
# 2009-2020 Ryan Pavlik <ryan.pavlik@gmail.com> <abiryan@ryand.net>
|
||||||
|
# http://academic.cleardefinition.com
|
||||||
|
#
|
||||||
|
# Copyright 2009-2013, Iowa State University.
|
||||||
|
# Copyright 2013-2020, Ryan Pavlik
|
||||||
|
# Copyright 2013-2020, Contributors
|
||||||
|
# SPDX-License-Identifier: BSL-1.0
|
||||||
|
# Distributed under the Boost Software License, Version 1.0.
|
||||||
|
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
# http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
if(__get_git_revision_description)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
set(__get_git_revision_description YES)
|
||||||
|
|
||||||
|
# We must run the following at "include" time, not at function call time,
|
||||||
|
# to find the path to this module rather than the path to a calling list file
|
||||||
|
get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH)
|
||||||
|
|
||||||
|
# Function _git_find_closest_git_dir finds the next closest .git directory
|
||||||
|
# that is part of any directory in the path defined by _start_dir.
|
||||||
|
# The result is returned in the parent scope variable whose name is passed
|
||||||
|
# as variable _git_dir_var. If no .git directory can be found, the
|
||||||
|
# function returns an empty string via _git_dir_var.
|
||||||
|
#
|
||||||
|
# Example: Given a path C:/bla/foo/bar and assuming C:/bla/.git exists and
|
||||||
|
# neither foo nor bar contain a file/directory .git. This wil return
|
||||||
|
# C:/bla/.git
|
||||||
|
#
|
||||||
|
function(_git_find_closest_git_dir _start_dir _git_dir_var)
|
||||||
|
set(cur_dir "${_start_dir}")
|
||||||
|
set(git_dir "${_start_dir}/.git")
|
||||||
|
while(NOT EXISTS "${git_dir}")
|
||||||
|
# .git dir not found, search parent directories
|
||||||
|
set(git_previous_parent "${cur_dir}")
|
||||||
|
get_filename_component(cur_dir "${cur_dir}" DIRECTORY)
|
||||||
|
if(cur_dir STREQUAL git_previous_parent)
|
||||||
|
# We have reached the root directory, we are not in git
|
||||||
|
set(${_git_dir_var}
|
||||||
|
""
|
||||||
|
PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
set(git_dir "${cur_dir}/.git")
|
||||||
|
endwhile()
|
||||||
|
set(${_git_dir_var}
|
||||||
|
"${git_dir}"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(get_git_head_revision _refspecvar _hashvar)
|
||||||
|
_git_find_closest_git_dir("${CMAKE_CURRENT_SOURCE_DIR}" GIT_DIR)
|
||||||
|
|
||||||
|
if("${ARGN}" STREQUAL "ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR")
|
||||||
|
set(ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR TRUE)
|
||||||
|
else()
|
||||||
|
set(ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR FALSE)
|
||||||
|
endif()
|
||||||
|
if(NOT "${GIT_DIR}" STREQUAL "")
|
||||||
|
file(RELATIVE_PATH _relative_to_source_dir "${CMAKE_SOURCE_DIR}"
|
||||||
|
"${GIT_DIR}")
|
||||||
|
if("${_relative_to_source_dir}" MATCHES "[.][.]" AND NOT ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR)
|
||||||
|
# We've gone above the CMake root dir.
|
||||||
|
set(GIT_DIR "")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
if("${GIT_DIR}" STREQUAL "")
|
||||||
|
set(${_refspecvar}
|
||||||
|
"GITDIR-NOTFOUND"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
set(${_hashvar}
|
||||||
|
"GITDIR-NOTFOUND"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Check if the current source dir is a git submodule or a worktree.
|
||||||
|
# In both cases .git is a file instead of a directory.
|
||||||
|
#
|
||||||
|
if(NOT IS_DIRECTORY ${GIT_DIR})
|
||||||
|
# The following git command will return a non empty string that
|
||||||
|
# points to the super project working tree if the current
|
||||||
|
# source dir is inside a git submodule.
|
||||||
|
# Otherwise the command will return an empty string.
|
||||||
|
#
|
||||||
|
execute_process(
|
||||||
|
COMMAND "${GIT_EXECUTABLE}" rev-parse
|
||||||
|
--show-superproject-working-tree
|
||||||
|
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
|
OUTPUT_VARIABLE out
|
||||||
|
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
if(NOT "${out}" STREQUAL "")
|
||||||
|
# If out is empty, GIT_DIR/CMAKE_CURRENT_SOURCE_DIR is in a submodule
|
||||||
|
file(READ ${GIT_DIR} submodule)
|
||||||
|
string(REGEX REPLACE "gitdir: (.*)$" "\\1" GIT_DIR_RELATIVE
|
||||||
|
${submodule})
|
||||||
|
string(STRIP ${GIT_DIR_RELATIVE} GIT_DIR_RELATIVE)
|
||||||
|
get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH)
|
||||||
|
get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE}
|
||||||
|
ABSOLUTE)
|
||||||
|
set(HEAD_SOURCE_FILE "${GIT_DIR}/HEAD")
|
||||||
|
else()
|
||||||
|
# GIT_DIR/CMAKE_CURRENT_SOURCE_DIR is in a worktree
|
||||||
|
file(READ ${GIT_DIR} worktree_ref)
|
||||||
|
# The .git directory contains a path to the worktree information directory
|
||||||
|
# inside the parent git repo of the worktree.
|
||||||
|
#
|
||||||
|
string(REGEX REPLACE "gitdir: (.*)$" "\\1" git_worktree_dir
|
||||||
|
${worktree_ref})
|
||||||
|
string(STRIP ${git_worktree_dir} git_worktree_dir)
|
||||||
|
_git_find_closest_git_dir("${git_worktree_dir}" GIT_DIR)
|
||||||
|
set(HEAD_SOURCE_FILE "${git_worktree_dir}/HEAD")
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
set(HEAD_SOURCE_FILE "${GIT_DIR}/HEAD")
|
||||||
|
endif()
|
||||||
|
set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data")
|
||||||
|
if(NOT EXISTS "${GIT_DATA}")
|
||||||
|
file(MAKE_DIRECTORY "${GIT_DATA}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT EXISTS "${HEAD_SOURCE_FILE}")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
set(HEAD_FILE "${GIT_DATA}/HEAD")
|
||||||
|
configure_file("${HEAD_SOURCE_FILE}" "${HEAD_FILE}" COPYONLY)
|
||||||
|
|
||||||
|
configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in"
|
||||||
|
"${GIT_DATA}/grabRef.cmake" @ONLY)
|
||||||
|
include("${GIT_DATA}/grabRef.cmake")
|
||||||
|
|
||||||
|
set(${_refspecvar}
|
||||||
|
"${HEAD_REF}"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
set(${_hashvar}
|
||||||
|
"${HEAD_HASH}"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(git_describe _var)
|
||||||
|
if(NOT GIT_FOUND)
|
||||||
|
find_package(Git QUIET)
|
||||||
|
endif()
|
||||||
|
get_git_head_revision(refspec hash)
|
||||||
|
if(NOT GIT_FOUND)
|
||||||
|
set(${_var}
|
||||||
|
"GIT-NOTFOUND"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
if(NOT hash)
|
||||||
|
set(${_var}
|
||||||
|
"HEAD-HASH-NOTFOUND"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# TODO sanitize
|
||||||
|
#if((${ARGN}" MATCHES "&&") OR
|
||||||
|
# (ARGN MATCHES "||") OR
|
||||||
|
# (ARGN MATCHES "\\;"))
|
||||||
|
# message("Please report the following error to the project!")
|
||||||
|
# message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}")
|
||||||
|
#endif()
|
||||||
|
|
||||||
|
#message(STATUS "Arguments to execute_process: ${ARGN}")
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND "${GIT_EXECUTABLE}" describe --tags --always ${hash} ${ARGN}
|
||||||
|
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
|
RESULT_VARIABLE res
|
||||||
|
OUTPUT_VARIABLE out
|
||||||
|
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
if(NOT res EQUAL 0)
|
||||||
|
set(out "${out}-${res}-NOTFOUND")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(${_var}
|
||||||
|
"${out}"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(git_describe_working_tree _var)
|
||||||
|
if(NOT GIT_FOUND)
|
||||||
|
find_package(Git QUIET)
|
||||||
|
endif()
|
||||||
|
if(NOT GIT_FOUND)
|
||||||
|
set(${_var}
|
||||||
|
"GIT-NOTFOUND"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND "${GIT_EXECUTABLE}" describe --dirty ${ARGN}
|
||||||
|
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
|
RESULT_VARIABLE res
|
||||||
|
OUTPUT_VARIABLE out
|
||||||
|
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
if(NOT res EQUAL 0)
|
||||||
|
set(out "${out}-${res}-NOTFOUND")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(${_var}
|
||||||
|
"${out}"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(git_get_exact_tag _var)
|
||||||
|
git_describe(out --exact-match ${ARGN})
|
||||||
|
set(${_var}
|
||||||
|
"${out}"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(git_local_changes _var)
|
||||||
|
if(NOT GIT_FOUND)
|
||||||
|
find_package(Git QUIET)
|
||||||
|
endif()
|
||||||
|
get_git_head_revision(refspec hash)
|
||||||
|
if(NOT GIT_FOUND)
|
||||||
|
set(${_var}
|
||||||
|
"GIT-NOTFOUND"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
if(NOT hash)
|
||||||
|
set(${_var}
|
||||||
|
"HEAD-HASH-NOTFOUND"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND "${GIT_EXECUTABLE}" diff-index --quiet HEAD --
|
||||||
|
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
|
RESULT_VARIABLE res
|
||||||
|
OUTPUT_VARIABLE out
|
||||||
|
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
if(res EQUAL 0)
|
||||||
|
set(${_var}
|
||||||
|
"CLEAN"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
else()
|
||||||
|
set(${_var}
|
||||||
|
"DIRTY"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
endif()
|
||||||
|
endfunction()
|
@ -1,4 +1,4 @@
|
|||||||
#
|
#
|
||||||
# Internal file for GetGitRevisionDescription.cmake
|
# Internal file for GetGitRevisionDescription.cmake
|
||||||
#
|
#
|
||||||
# Requires CMake 2.6 or newer (uses the 'function' command)
|
# Requires CMake 2.6 or newer (uses the 'function' command)
|
||||||
@ -8,10 +8,12 @@
|
|||||||
# http://academic.cleardefinition.com
|
# http://academic.cleardefinition.com
|
||||||
# Iowa State University HCI Graduate Program/VRAC
|
# Iowa State University HCI Graduate Program/VRAC
|
||||||
#
|
#
|
||||||
# Copyright Iowa State University 2009-2010.
|
# Copyright 2009-2012, Iowa State University
|
||||||
|
# Copyright 2011-2015, Contributors
|
||||||
# Distributed under the Boost Software License, Version 1.0.
|
# Distributed under the Boost Software License, Version 1.0.
|
||||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
# http://www.boost.org/LICENSE_1_0.txt)
|
# http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
# SPDX-License-Identifier: BSL-1.0
|
||||||
|
|
||||||
set(HEAD_HASH)
|
set(HEAD_HASH)
|
||||||
|
|
||||||
@ -22,10 +24,13 @@ if(HEAD_CONTENTS MATCHES "ref")
|
|||||||
# named branch
|
# named branch
|
||||||
string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}")
|
string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}")
|
||||||
if(EXISTS "@GIT_DIR@/${HEAD_REF}")
|
if(EXISTS "@GIT_DIR@/${HEAD_REF}")
|
||||||
configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
|
configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
|
||||||
elseif(EXISTS "@GIT_DIR@/logs/${HEAD_REF}")
|
else()
|
||||||
configure_file("@GIT_DIR@/logs/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
|
configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY)
|
||||||
set(HEAD_HASH "${HEAD_REF}")
|
file(READ "@GIT_DATA@/packed-refs" PACKED_REFS)
|
||||||
|
if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}")
|
||||||
|
set(HEAD_HASH "${CMAKE_MATCH_1}")
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
else()
|
else()
|
||||||
# detached HEAD
|
# detached HEAD
|
||||||
@ -33,6 +38,6 @@ else()
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(NOT HEAD_HASH)
|
if(NOT HEAD_HASH)
|
||||||
file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024)
|
file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024)
|
||||||
string(STRIP "${HEAD_HASH}" HEAD_HASH)
|
string(STRIP "${HEAD_HASH}" HEAD_HASH)
|
||||||
endif()
|
endif()
|
26
cmake/cmake-modules/rpavlik/LICENSES/BSD-3-Clause.txt
Normal file
26
cmake/cmake-modules/rpavlik/LICENSES/BSD-3-Clause.txt
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
Copyright (c) <year> <owner>. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
3. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
may be used to endorse or promote products derived from this software without
|
||||||
|
specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||||
|
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
23
cmake/cmake-modules/rpavlik/LICENSES/BSL-1.0.txt
Normal file
23
cmake/cmake-modules/rpavlik/LICENSES/BSL-1.0.txt
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
Boost Software License - Version 1.0 - August 17th, 2003
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person or organization
|
||||||
|
obtaining a copy of the software and accompanying documentation covered by
|
||||||
|
this license (the "Software") to use, reproduce, display, distribute, execute,
|
||||||
|
and transmit the Software, and to prepare derivative works of the Software,
|
||||||
|
and to permit third-parties to whom the Software is furnished to do so, all
|
||||||
|
subject to the following:
|
||||||
|
|
||||||
|
The copyright notices in the Software and this entire statement, including
|
||||||
|
the above license grant, this restriction and the following disclaimer, must
|
||||||
|
be included in all copies of the Software, in whole or in part, and all derivative
|
||||||
|
works of the Software, unless such copies or derivative works are solely in
|
||||||
|
the form of machine-executable object code generated by a source language
|
||||||
|
processor.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES
|
||||||
|
OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
23
cmake/cmake-modules/rpavlik/LICENSE_1_0.txt
Normal file
23
cmake/cmake-modules/rpavlik/LICENSE_1_0.txt
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
Boost Software License - Version 1.0 - August 17th, 2003
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person or organization
|
||||||
|
obtaining a copy of the software and accompanying documentation covered by
|
||||||
|
this license (the "Software") to use, reproduce, display, distribute,
|
||||||
|
execute, and transmit the Software, and to prepare derivative works of the
|
||||||
|
Software, and to permit third-parties to whom the Software is furnished to
|
||||||
|
do so, all subject to the following:
|
||||||
|
|
||||||
|
The copyright notices in the Software and this entire statement, including
|
||||||
|
the above license grant, this restriction and the following disclaimer,
|
||||||
|
must be included in all copies of the Software, in whole or in part, and
|
||||||
|
all derivative works of the Software, unless such copies or derivative
|
||||||
|
works are solely in the form of machine-executable object code generated by
|
||||||
|
a source language processor.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||||
|
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||||
|
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||||
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
@ -209,7 +209,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
|
||||||
|
@ -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 {
|
||||||
|
@ -6,6 +6,6 @@ static constexpr int FSFW_VERSION_MAJOR = @FSFW_VERSION@;
|
|||||||
static constexpr int FSFW_VERSION_MINOR = @FSFW_SUBVERSION@;
|
static constexpr int FSFW_VERSION_MINOR = @FSFW_SUBVERSION@;
|
||||||
static constexpr int FSFW_VERSION_REVISION = @FSFW_REVISION@;
|
static constexpr int FSFW_VERSION_REVISION = @FSFW_REVISION@;
|
||||||
// Also contains CST (Commits since tag) information
|
// Also contains CST (Commits since tag) information
|
||||||
static const char FSFW_VERSION_CST_GIT_SHA1[] = "@FSFW_VERSION_CST_GIT_SHA1@";
|
static const char FSFW_VCS_INFO[] = "@FSFW_VCS_INFO@";
|
||||||
|
|
||||||
#endif /* FSFW_VERSION_H_ */
|
#endif /* FSFW_VERSION_H_ */
|
||||||
|
@ -696,9 +696,9 @@ void LocalDataPoolManager::performPeriodicHkGeneration(HkReceiver& receiver) {
|
|||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
/* Configuration error */
|
/* Configuration error */
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::warning << "LocalDataPoolManager::performHkOperation: HK generation failed." << std::endl;
|
sif::warning << "LocalDataPoolManager::performPeriodicHkOperation: HK generation failed." << std::endl;
|
||||||
#else
|
#else
|
||||||
sif::printWarning("LocalDataPoolManager::performHkOperation: HK generation failed.\n");
|
sif::printWarning("LocalDataPoolManager::performPeriodicHkOperation: HK generation failed.\n");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@ enum : uint8_t {
|
|||||||
PUS_SERVICE_6 = 86,
|
PUS_SERVICE_6 = 86,
|
||||||
PUS_SERVICE_8 = 88,
|
PUS_SERVICE_8 = 88,
|
||||||
PUS_SERVICE_9 = 89,
|
PUS_SERVICE_9 = 89,
|
||||||
|
PUS_SERVICE_11 = 91,
|
||||||
PUS_SERVICE_17 = 97,
|
PUS_SERVICE_17 = 97,
|
||||||
PUS_SERVICE_23 = 103,
|
PUS_SERVICE_23 = 103,
|
||||||
MGM_LIS3MDL = 106,
|
MGM_LIS3MDL = 106,
|
||||||
|
@ -14,6 +14,7 @@ enum framework_objects : object_id_t {
|
|||||||
PUS_SERVICE_5_EVENT_REPORTING = 0x53000005,
|
PUS_SERVICE_5_EVENT_REPORTING = 0x53000005,
|
||||||
PUS_SERVICE_8_FUNCTION_MGMT = 0x53000008,
|
PUS_SERVICE_8_FUNCTION_MGMT = 0x53000008,
|
||||||
PUS_SERVICE_9_TIME_MGMT = 0x53000009,
|
PUS_SERVICE_9_TIME_MGMT = 0x53000009,
|
||||||
|
PUS_SERVICE_11_TC_SCHEDULER = 0x53000011,
|
||||||
PUS_SERVICE_17_TEST = 0x53000017,
|
PUS_SERVICE_17_TEST = 0x53000017,
|
||||||
PUS_SERVICE_20_PARAMETERS = 0x53000020,
|
PUS_SERVICE_20_PARAMETERS = 0x53000020,
|
||||||
PUS_SERVICE_200_MODE_MGMT = 0x53000200,
|
PUS_SERVICE_200_MODE_MGMT = 0x53000200,
|
||||||
|
@ -109,8 +109,8 @@ TcpTmTcServer::~TcpTmTcServer() { closeSocket(listenerTcpSocket); }
|
|||||||
using namespace tcpip;
|
using namespace tcpip;
|
||||||
// If a connection is accepted, the corresponding socket will be assigned to the new socket
|
// If a connection is accepted, the corresponding socket will be assigned to the new socket
|
||||||
socket_t connSocket = 0;
|
socket_t connSocket = 0;
|
||||||
// sockaddr clientSockAddr = {};
|
sockaddr clientSockAddr = {};
|
||||||
// socklen_t connectorSockAddrLen = 0;
|
socklen_t connectorSockAddrLen = 0;
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
|
|
||||||
// Listen for connection requests permanently for lifetime of program
|
// Listen for connection requests permanently for lifetime of program
|
||||||
@ -121,8 +121,7 @@ TcpTmTcServer::~TcpTmTcServer() { closeSocket(listenerTcpSocket); }
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// connSocket = accept(listenerTcpSocket, &clientSockAddr, &connectorSockAddrLen);
|
connSocket = accept(listenerTcpSocket, &clientSockAddr, &connectorSockAddrLen);
|
||||||
connSocket = accept(listenerTcpSocket, nullptr, nullptr);
|
|
||||||
|
|
||||||
if (connSocket == INVALID_SOCKET) {
|
if (connSocket == INVALID_SOCKET) {
|
||||||
handleError(Protocol::TCP, ErrorSources::ACCEPT_CALL, 500);
|
handleError(Protocol::TCP, ErrorSources::ACCEPT_CALL, 500);
|
||||||
@ -137,6 +136,7 @@ TcpTmTcServer::~TcpTmTcServer() { closeSocket(listenerTcpSocket); }
|
|||||||
if (retval != 0) {
|
if (retval != 0) {
|
||||||
handleError(Protocol::TCP, ErrorSources::SHUTDOWN_CALL);
|
handleError(Protocol::TCP, ErrorSources::SHUTDOWN_CALL);
|
||||||
}
|
}
|
||||||
|
|
||||||
closeSocket(connSocket);
|
closeSocket(connSocket);
|
||||||
connSocket = 0;
|
connSocket = 0;
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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();
|
||||||
};
|
};
|
||||||
|
@ -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. */
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
};
|
};
|
||||||
|
@ -3,9 +3,7 @@
|
|||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
#include "fsfw/ipc/MutexFactory.h"
|
|
||||||
#include "fsfw/objectmanager/ObjectManager.h"
|
#include "fsfw/objectmanager/ObjectManager.h"
|
||||||
#include "fsfw/osal/host/FixedTimeslotTask.h"
|
|
||||||
#include "fsfw/osal/host/Mutex.h"
|
#include "fsfw/osal/host/Mutex.h"
|
||||||
#include "fsfw/osal/host/taskHelpers.h"
|
#include "fsfw/osal/host/taskHelpers.h"
|
||||||
#include "fsfw/platform.h"
|
#include "fsfw/platform.h"
|
||||||
@ -22,12 +20,8 @@
|
|||||||
|
|
||||||
FixedTimeslotTask::FixedTimeslotTask(const char* name, TaskPriority setPriority,
|
FixedTimeslotTask::FixedTimeslotTask(const char* name, TaskPriority setPriority,
|
||||||
TaskStackSize setStack, TaskPeriod setPeriod,
|
TaskStackSize setStack, TaskPeriod setPeriod,
|
||||||
void (*setDeadlineMissedFunc)())
|
TaskDeadlineMissedFunction dlmFunc_)
|
||||||
: started(false),
|
: FixedTimeslotTaskBase(setPeriod, dlmFunc_), started(false), taskName(name) {
|
||||||
pollingSeqTable(setPeriod * 1000),
|
|
||||||
taskName(name),
|
|
||||||
period(setPeriod),
|
|
||||||
deadlineMissedFunc(setDeadlineMissedFunc) {
|
|
||||||
// It is propably possible to set task priorities by using the native
|
// It is propably possible to set task priorities by using the native
|
||||||
// task handles for Windows / Linux
|
// task handles for Windows / Linux
|
||||||
mainThread = std::thread(&FixedTimeslotTask::taskEntryPoint, this, this);
|
mainThread = std::thread(&FixedTimeslotTask::taskEntryPoint, this, this);
|
||||||
@ -39,7 +33,7 @@ FixedTimeslotTask::FixedTimeslotTask(const char* name, TaskPriority setPriority,
|
|||||||
tasks::insertTaskName(mainThread.get_id(), taskName);
|
tasks::insertTaskName(mainThread.get_id(), taskName);
|
||||||
}
|
}
|
||||||
|
|
||||||
FixedTimeslotTask::~FixedTimeslotTask(void) {
|
FixedTimeslotTask::~FixedTimeslotTask() {
|
||||||
// Do not delete objects, we were responsible for ptrs only.
|
// Do not delete objects, we were responsible for ptrs only.
|
||||||
terminateThread = true;
|
terminateThread = true;
|
||||||
if (mainThread.joinable()) {
|
if (mainThread.joinable()) {
|
||||||
@ -48,7 +42,7 @@ FixedTimeslotTask::~FixedTimeslotTask(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void FixedTimeslotTask::taskEntryPoint(void* argument) {
|
void FixedTimeslotTask::taskEntryPoint(void* argument) {
|
||||||
FixedTimeslotTask* originalTask(reinterpret_cast<FixedTimeslotTask*>(argument));
|
auto* originalTask(reinterpret_cast<FixedTimeslotTask*>(argument));
|
||||||
|
|
||||||
if (not originalTask->started) {
|
if (not originalTask->started) {
|
||||||
// we have to suspend/block here until the task is started.
|
// we have to suspend/block here until the task is started.
|
||||||
@ -81,7 +75,9 @@ ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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.
|
||||||
@ -106,37 +102,15 @@ void FixedTimeslotTask::taskFunctionality() {
|
|||||||
// we need to wait before executing the current slot
|
// we need to wait before executing the current slot
|
||||||
// this gives us the time to wait:
|
// this gives us the time to wait:
|
||||||
interval = chron_ms(this->pollingSeqTable.getIntervalToPreviousSlotMs());
|
interval = chron_ms(this->pollingSeqTable.getIntervalToPreviousSlotMs());
|
||||||
delayForInterval(¤tStartTime, interval);
|
if (not delayForInterval(¤tStartTime, interval)) {
|
||||||
// TODO deadline missed check
|
if (dlmFunc != nullptr) {
|
||||||
|
dlmFunc();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, uint32_t slotTimeMs,
|
|
||||||
int8_t executionStep) {
|
|
||||||
ExecutableObjectIF* executableObject =
|
|
||||||
ObjectManager::instance()->get<ExecutableObjectIF>(componentId);
|
|
||||||
if (executableObject != nullptr) {
|
|
||||||
pollingSeqTable.addSlot(componentId, slotTimeMs, executionStep, executableObject, this);
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "Component " << std::hex << "0x" << componentId
|
|
||||||
<< "not found, "
|
|
||||||
"not adding it to PST.."
|
|
||||||
<< std::dec << std::endl;
|
|
||||||
#else
|
|
||||||
sif::printError("Component 0x%08x not found, not adding it to PST..\n",
|
|
||||||
static_cast<unsigned int>(componentId));
|
|
||||||
#endif
|
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t FixedTimeslotTask::checkSequence() const { return pollingSeqTable.checkSequence(); }
|
|
||||||
|
|
||||||
uint32_t FixedTimeslotTask::getPeriodMs() const { return period * 1000; }
|
|
||||||
|
|
||||||
bool FixedTimeslotTask::delayForInterval(chron_ms* previousWakeTimeMs, const chron_ms interval) {
|
bool FixedTimeslotTask::delayForInterval(chron_ms* previousWakeTimeMs, const chron_ms interval) {
|
||||||
bool shouldDelay = false;
|
bool shouldDelay = false;
|
||||||
// Get current wakeup time
|
// Get current wakeup time
|
||||||
|
@ -6,10 +6,10 @@
|
|||||||
#include <thread>
|
#include <thread>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "../../objectmanager/ObjectManagerIF.h"
|
#include "fsfw/objectmanager/ObjectManagerIF.h"
|
||||||
#include "../../tasks/FixedSlotSequence.h"
|
#include "fsfw/tasks/FixedSlotSequence.h"
|
||||||
#include "../../tasks/FixedTimeslotTaskIF.h"
|
#include "fsfw/tasks/FixedTimeslotTaskBase.h"
|
||||||
#include "../../tasks/Typedef.h"
|
#include "fsfw/tasks/definitions.h"
|
||||||
|
|
||||||
class ExecutableObjectIF;
|
class ExecutableObjectIF;
|
||||||
|
|
||||||
@ -19,7 +19,7 @@ class ExecutableObjectIF;
|
|||||||
* @details
|
* @details
|
||||||
* @ingroup task_handling
|
* @ingroup task_handling
|
||||||
*/
|
*/
|
||||||
class FixedTimeslotTask : public FixedTimeslotTaskIF {
|
class FixedTimeslotTask : public FixedTimeslotTaskBase {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Standard constructor of the class.
|
* @brief Standard constructor of the class.
|
||||||
@ -39,7 +39,7 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF {
|
|||||||
* @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 ~FixedTimeslotTask(void);
|
~FixedTimeslotTask() override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The method to start the task.
|
* @brief The method to start the task.
|
||||||
@ -48,56 +48,22 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF {
|
|||||||
* The address of the task object is passed as an argument
|
* The address of the task object is passed as an argument
|
||||||
* to the system call.
|
* to the system call.
|
||||||
*/
|
*/
|
||||||
ReturnValue_t startTask(void);
|
ReturnValue_t startTask() override;
|
||||||
|
|
||||||
/**
|
ReturnValue_t sleepFor(uint32_t ms) override;
|
||||||
* Add timeslot to the polling sequence table.
|
|
||||||
* @param componentId
|
|
||||||
* @param slotTimeMs
|
|
||||||
* @param executionStep
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs, int8_t executionStep);
|
|
||||||
|
|
||||||
ReturnValue_t checkSequence() const override;
|
|
||||||
|
|
||||||
uint32_t getPeriodMs() const;
|
|
||||||
|
|
||||||
ReturnValue_t sleepFor(uint32_t ms);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
using chron_ms = std::chrono::milliseconds;
|
using chron_ms = std::chrono::milliseconds;
|
||||||
|
|
||||||
bool started;
|
bool started;
|
||||||
//!< Typedef for the List of objects.
|
|
||||||
typedef std::vector<ExecutableObjectIF*> ObjectList;
|
|
||||||
std::thread mainThread;
|
std::thread mainThread;
|
||||||
std::atomic<bool> terminateThread{false};
|
std::atomic<bool> terminateThread{false};
|
||||||
|
|
||||||
//! Polling sequence table which contains the object to execute
|
|
||||||
//! and information like the timeslots and the passed execution step.
|
|
||||||
FixedSlotSequence pollingSeqTable;
|
|
||||||
|
|
||||||
std::condition_variable initCondition;
|
std::condition_variable initCondition;
|
||||||
std::mutex initMutex;
|
std::mutex initMutex;
|
||||||
std::string taskName;
|
std::string taskName;
|
||||||
/**
|
|
||||||
* @brief The period of the task.
|
|
||||||
* @details
|
|
||||||
* The period determines the frequency of the task's execution.
|
|
||||||
* It is expressed in clock ticks.
|
|
||||||
*/
|
|
||||||
TaskPeriod period;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @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
|
||||||
@ -117,9 +83,9 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF {
|
|||||||
* the checkAndRestartPeriod system call blocks the task until the next
|
* the checkAndRestartPeriod system call blocks the task until the next
|
||||||
* period. On missing the deadline, the deadlineMissedFunction is executed.
|
* period. On missing the deadline, the deadlineMissedFunction is executed.
|
||||||
*/
|
*/
|
||||||
void taskFunctionality(void);
|
void taskFunctionality();
|
||||||
|
|
||||||
bool delayForInterval(chron_ms* previousWakeTimeMs, const chron_ms interval);
|
static bool delayForInterval(chron_ms* previousWakeTimeMs, chron_ms interval);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* FRAMEWORK_OSAL_HOST_FIXEDTIMESLOTTASK_H_ */
|
#endif /* FRAMEWORK_OSAL_HOST_FIXEDTIMESLOTTASK_H_ */
|
||||||
|
@ -3,13 +3,10 @@
|
|||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
#include "fsfw/ipc/MutexFactory.h"
|
|
||||||
#include "fsfw/objectmanager/ObjectManager.h"
|
|
||||||
#include "fsfw/osal/host/Mutex.h"
|
#include "fsfw/osal/host/Mutex.h"
|
||||||
#include "fsfw/osal/host/taskHelpers.h"
|
#include "fsfw/osal/host/taskHelpers.h"
|
||||||
#include "fsfw/platform.h"
|
#include "fsfw/platform.h"
|
||||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||||
#include "fsfw/tasks/ExecutableObjectIF.h"
|
|
||||||
|
|
||||||
#if defined(PLATFORM_WIN)
|
#if defined(PLATFORM_WIN)
|
||||||
#include <processthreadsapi.h>
|
#include <processthreadsapi.h>
|
||||||
@ -20,8 +17,8 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
PeriodicTask::PeriodicTask(const char* name, TaskPriority setPriority, TaskStackSize setStack,
|
PeriodicTask::PeriodicTask(const char* name, TaskPriority setPriority, TaskStackSize setStack,
|
||||||
TaskPeriod setPeriod, void (*setDeadlineMissedFunc)())
|
TaskPeriod setPeriod, TaskDeadlineMissedFunction dlmFunc_)
|
||||||
: started(false), taskName(name), period(setPeriod), deadlineMissedFunc(setDeadlineMissedFunc) {
|
: PeriodicTaskBase(setPeriod, dlmFunc_), started(false), taskName(name) {
|
||||||
// It is probably possible to set task priorities by using the native
|
// It is probably possible to set task priorities by using the native
|
||||||
// task handles for Windows / Linux
|
// task handles for Windows / Linux
|
||||||
mainThread = std::thread(&PeriodicTask::taskEntryPoint, this, this);
|
mainThread = std::thread(&PeriodicTask::taskEntryPoint, this, this);
|
||||||
@ -33,7 +30,7 @@ PeriodicTask::PeriodicTask(const char* name, TaskPriority setPriority, TaskStack
|
|||||||
tasks::insertTaskName(mainThread.get_id(), taskName);
|
tasks::insertTaskName(mainThread.get_id(), taskName);
|
||||||
}
|
}
|
||||||
|
|
||||||
PeriodicTask::~PeriodicTask(void) {
|
PeriodicTask::~PeriodicTask() {
|
||||||
// Do not delete objects, we were responsible for ptrs only.
|
// Do not delete objects, we were responsible for ptrs only.
|
||||||
terminateThread = true;
|
terminateThread = true;
|
||||||
if (mainThread.joinable()) {
|
if (mainThread.joinable()) {
|
||||||
@ -42,7 +39,7 @@ PeriodicTask::~PeriodicTask(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void PeriodicTask::taskEntryPoint(void* argument) {
|
void PeriodicTask::taskEntryPoint(void* argument) {
|
||||||
PeriodicTask* originalTask(reinterpret_cast<PeriodicTask*>(argument));
|
auto* originalTask(reinterpret_cast<PeriodicTask*>(argument));
|
||||||
|
|
||||||
if (not originalTask->started) {
|
if (not originalTask->started) {
|
||||||
// we have to suspend/block here until the task is started.
|
// we have to suspend/block here until the task is started.
|
||||||
@ -75,47 +72,27 @@ ReturnValue_t PeriodicTask::sleepFor(uint32_t ms) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void PeriodicTask::taskFunctionality() {
|
void PeriodicTask::taskFunctionality() {
|
||||||
for (const auto& object : objectList) {
|
initObjsAfterTaskCreation();
|
||||||
object->initializeAfterTaskCreation();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::chrono::milliseconds periodChrono(static_cast<uint32_t>(period * 1000));
|
std::chrono::milliseconds periodChrono(static_cast<uint32_t>(period * 1000));
|
||||||
auto currentStartTime{std::chrono::duration_cast<std::chrono::milliseconds>(
|
auto currentStartTime{std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||||
std::chrono::system_clock::now().time_since_epoch())};
|
std::chrono::system_clock::now().time_since_epoch())};
|
||||||
auto nextStartTime{currentStartTime};
|
|
||||||
|
|
||||||
/* Enter the loop that defines the task behavior. */
|
/* Enter the loop that defines the task behavior. */
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (terminateThread.load()) {
|
if (terminateThread.load()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
for (const auto& object : objectList) {
|
for (const auto& objectPair : objectList) {
|
||||||
object->performOperation();
|
objectPair.first->performOperation(objectPair.second);
|
||||||
}
|
}
|
||||||
if (not delayForInterval(¤tStartTime, periodChrono)) {
|
if (not delayForInterval(¤tStartTime, periodChrono)) {
|
||||||
if (deadlineMissedFunc != nullptr) {
|
if (dlmFunc != nullptr) {
|
||||||
this->deadlineMissedFunc();
|
this->dlmFunc();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t PeriodicTask::addComponent(object_id_t object) {
|
|
||||||
ExecutableObjectIF* newObject = ObjectManager::instance()->get<ExecutableObjectIF>(object);
|
|
||||||
return addComponent(newObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t PeriodicTask::addComponent(ExecutableObjectIF* object) {
|
|
||||||
if (object == nullptr) {
|
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
|
||||||
}
|
|
||||||
object->setTaskIF(this);
|
|
||||||
objectList.push_back(object);
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t PeriodicTask::getPeriodMs() const { return period * 1000; }
|
|
||||||
|
|
||||||
bool PeriodicTask::delayForInterval(chron_ms* previousWakeTimeMs, const chron_ms interval) {
|
bool PeriodicTask::delayForInterval(chron_ms* previousWakeTimeMs, const chron_ms interval) {
|
||||||
bool shouldDelay = false;
|
bool shouldDelay = false;
|
||||||
// Get current wakeup time
|
// Get current wakeup time
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
#include <thread>
|
#include <thread>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "../../objectmanager/ObjectManagerIF.h"
|
#include "fsfw/objectmanager/ObjectManagerIF.h"
|
||||||
#include "../../tasks/PeriodicTaskIF.h"
|
#include "fsfw/tasks/PeriodicTaskBase.h"
|
||||||
#include "../../tasks/Typedef.h"
|
#include "fsfw/tasks/definitions.h"
|
||||||
|
|
||||||
class ExecutableObjectIF;
|
class ExecutableObjectIF;
|
||||||
|
|
||||||
@ -19,7 +19,7 @@ class ExecutableObjectIF;
|
|||||||
*
|
*
|
||||||
* @ingroup task_handling
|
* @ingroup task_handling
|
||||||
*/
|
*/
|
||||||
class PeriodicTask : public PeriodicTaskIF {
|
class PeriodicTask : public PeriodicTaskBase {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Standard constructor of the class.
|
* @brief Standard constructor of the class.
|
||||||
@ -34,12 +34,12 @@ class PeriodicTask : public PeriodicTaskIF {
|
|||||||
* assigned.
|
* assigned.
|
||||||
*/
|
*/
|
||||||
PeriodicTask(const char* name, TaskPriority setPriority, TaskStackSize setStack,
|
PeriodicTask(const char* name, TaskPriority setPriority, TaskStackSize setStack,
|
||||||
TaskPeriod setPeriod, void (*setDeadlineMissedFunc)());
|
TaskPeriod setPeriod, TaskDeadlineMissedFunction dlmFunc);
|
||||||
/**
|
/**
|
||||||
* @brief Currently, the executed object's lifetime is not coupled with
|
* @brief Currently, the executed object's lifetime is not coupled with
|
||||||
* the task object's lifetime, so the destructor is empty.
|
* the task object's lifetime, so the destructor is empty.
|
||||||
*/
|
*/
|
||||||
virtual ~PeriodicTask(void);
|
~PeriodicTask() override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The method to start the task.
|
* @brief The method to start the task.
|
||||||
@ -48,63 +48,20 @@ class PeriodicTask : 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
|
|
||||||
* -@c RETURN_OK on success
|
|
||||||
* -@c RETURN_FAILED if the object could not be added.
|
|
||||||
*/
|
|
||||||
ReturnValue_t addComponent(object_id_t object);
|
|
||||||
|
|
||||||
/**
|
ReturnValue_t sleepFor(uint32_t ms) override;
|
||||||
* Adds an object to the list of objects to be executed.
|
|
||||||
* The objects are executed in the order added.
|
|
||||||
* @param object pointer to the object to add.
|
|
||||||
* @return
|
|
||||||
* -@c RETURN_OK on success
|
|
||||||
* -@c RETURN_FAILED if the object could not be added.
|
|
||||||
*/
|
|
||||||
ReturnValue_t addComponent(ExecutableObjectIF* object);
|
|
||||||
|
|
||||||
uint32_t getPeriodMs() const;
|
|
||||||
|
|
||||||
ReturnValue_t sleepFor(uint32_t ms);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
using chron_ms = std::chrono::milliseconds;
|
using chron_ms = std::chrono::milliseconds;
|
||||||
bool started;
|
bool started;
|
||||||
//!< Typedef for the List of objects.
|
|
||||||
typedef std::vector<ExecutableObjectIF*> ObjectList;
|
|
||||||
std::thread mainThread;
|
std::thread mainThread;
|
||||||
std::atomic<bool> terminateThread{false};
|
std::atomic<bool> terminateThread{false};
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief This attribute holds a list of objects to be executed.
|
|
||||||
*/
|
|
||||||
ObjectList objectList;
|
|
||||||
|
|
||||||
std::condition_variable initCondition;
|
std::condition_variable initCondition;
|
||||||
std::mutex initMutex;
|
std::mutex initMutex;
|
||||||
std::string taskName;
|
std::string taskName;
|
||||||
/**
|
|
||||||
* @brief The period of the task.
|
|
||||||
* @details
|
|
||||||
* The period determines the frequency of the task's execution.
|
|
||||||
* It is expressed in clock ticks.
|
|
||||||
*/
|
|
||||||
TaskPeriod period;
|
|
||||||
/**
|
|
||||||
* @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
|
||||||
@ -124,9 +81,9 @@ class PeriodicTask : public PeriodicTaskIF {
|
|||||||
* the checkAndRestartPeriod system call blocks the task until the next
|
* the checkAndRestartPeriod system call blocks the task until the next
|
||||||
* period. On missing the deadline, the deadlineMissedFunction is executed.
|
* period. On missing the deadline, the deadlineMissedFunction is executed.
|
||||||
*/
|
*/
|
||||||
void taskFunctionality(void);
|
void taskFunctionality();
|
||||||
|
|
||||||
bool delayForInterval(chron_ms* previousWakeTimeMs, const chron_ms interval);
|
static bool delayForInterval(chron_ms* previousWakeTimeMs, chron_ms interval);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* PERIODICTASK_H_ */
|
#endif /* FRAMEWORK_OSAL_HOST_PERIODICTASK_H_ */
|
||||||
|
@ -14,9 +14,9 @@ TaskFactory* TaskFactory::factoryInstance = new TaskFactory();
|
|||||||
// Not used for the host implementation for now because C++ thread abstraction is used
|
// Not used for the host implementation for now because C++ thread abstraction is used
|
||||||
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = 0;
|
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = 0;
|
||||||
|
|
||||||
TaskFactory::TaskFactory() {}
|
TaskFactory::TaskFactory() = default;
|
||||||
|
|
||||||
TaskFactory::~TaskFactory() {}
|
TaskFactory::~TaskFactory() = default;
|
||||||
|
|
||||||
TaskFactory* TaskFactory::instance() { return TaskFactory::factoryInstance; }
|
TaskFactory* TaskFactory::instance() { return TaskFactory::factoryInstance; }
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
std::mutex nameMapLock;
|
std::mutex nameMapLock;
|
||||||
std::map<std::thread::id, std::string> taskNameMap;
|
std::map<std::thread::id, std::string> taskNameMap;
|
||||||
|
|
||||||
ReturnValue_t tasks::insertTaskName(std::thread::id threadId, std::string taskName) {
|
ReturnValue_t tasks::insertTaskName(std::thread::id threadId, const std::string& taskName) {
|
||||||
std::lock_guard<std::mutex> lg(nameMapLock);
|
std::lock_guard<std::mutex> lg(nameMapLock);
|
||||||
auto returnPair = taskNameMap.emplace(threadId, taskName);
|
auto returnPair = taskNameMap.emplace(threadId, taskName);
|
||||||
if (not returnPair.second) {
|
if (not returnPair.second) {
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
namespace tasks {
|
namespace tasks {
|
||||||
|
|
||||||
ReturnValue_t insertTaskName(std::thread::id threadId, std::string taskName);
|
ReturnValue_t insertTaskName(std::thread::id threadId, const std::string& taskName);
|
||||||
std::string getTaskName(std::thread::id threadId);
|
std::string getTaskName(std::thread::id threadId);
|
||||||
|
|
||||||
} // namespace tasks
|
} // namespace tasks
|
||||||
|
@ -1,22 +1,20 @@
|
|||||||
#include "fsfw/osal/linux/FixedTimeslotTask.h"
|
#include "fsfw/osal/linux/FixedTimeslotTask.h"
|
||||||
|
|
||||||
#include <limits.h>
|
#include <climits>
|
||||||
|
|
||||||
#include "fsfw/objectmanager/ObjectManager.h"
|
|
||||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||||
|
|
||||||
uint32_t FixedTimeslotTask::deadlineMissedCount = 0;
|
|
||||||
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = PTHREAD_STACK_MIN;
|
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = PTHREAD_STACK_MIN;
|
||||||
|
|
||||||
FixedTimeslotTask::FixedTimeslotTask(const char* name_, int priority_, size_t stackSize_,
|
FixedTimeslotTask::FixedTimeslotTask(const char* name_, TaskPriority priority_, size_t stackSize_,
|
||||||
uint32_t periodMs_)
|
TaskPeriod periodSeconds_, TaskDeadlineMissedFunction dlmFunc_)
|
||||||
: PosixThread(name_, priority_, stackSize_), pst(periodMs_), started(false) {}
|
: FixedTimeslotTaskBase(periodSeconds_, dlmFunc_),
|
||||||
|
posixThread(name_, priority_, stackSize_),
|
||||||
FixedTimeslotTask::~FixedTimeslotTask() {}
|
started(false) {}
|
||||||
|
|
||||||
void* FixedTimeslotTask::taskEntryPoint(void* arg) {
|
void* FixedTimeslotTask::taskEntryPoint(void* arg) {
|
||||||
// The argument is re-interpreted as PollingTask.
|
// The argument is re-interpreted as PollingTask.
|
||||||
FixedTimeslotTask* originalTask(reinterpret_cast<FixedTimeslotTask*>(arg));
|
auto* originalTask(reinterpret_cast<FixedTimeslotTask*>(arg));
|
||||||
// The task's functionality is called.
|
// The task's functionality is called.
|
||||||
originalTask->taskFunctionality();
|
originalTask->taskFunctionality();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -24,7 +22,7 @@ void* FixedTimeslotTask::taskEntryPoint(void* arg) {
|
|||||||
|
|
||||||
ReturnValue_t FixedTimeslotTask::startTask() {
|
ReturnValue_t FixedTimeslotTask::startTask() {
|
||||||
started = true;
|
started = true;
|
||||||
createTask(&taskEntryPoint, this);
|
posixThread.createTask(&taskEntryPoint, this);
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,63 +30,36 @@ ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) {
|
|||||||
return PosixThread::sleep((uint64_t)ms * 1000000);
|
return PosixThread::sleep((uint64_t)ms * 1000000);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t FixedTimeslotTask::getPeriodMs() const { return pst.getLengthMs(); }
|
[[noreturn]] void FixedTimeslotTask::taskFunctionality() {
|
||||||
|
|
||||||
ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, uint32_t slotTimeMs,
|
|
||||||
int8_t executionStep) {
|
|
||||||
ExecutableObjectIF* executableObject =
|
|
||||||
ObjectManager::instance()->get<ExecutableObjectIF>(componentId);
|
|
||||||
if (executableObject != nullptr) {
|
|
||||||
pst.addSlot(componentId, slotTimeMs, executionStep, executableObject, this);
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "Component " << std::hex << componentId << " not found, not adding it to pst"
|
|
||||||
<< std::dec << std::endl;
|
|
||||||
#endif
|
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t FixedTimeslotTask::checkSequence() const { return pst.checkSequence(); }
|
|
||||||
|
|
||||||
void FixedTimeslotTask::taskFunctionality() {
|
|
||||||
// Like FreeRTOS pthreads are running as soon as they are created
|
// Like FreeRTOS pthreads are running as soon as they are created
|
||||||
if (!started) {
|
if (!started) {
|
||||||
suspend();
|
posixThread.suspend();
|
||||||
}
|
}
|
||||||
|
|
||||||
pst.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 = getCurrentMonotonicTimeMs();
|
uint64_t lastWakeTime = PosixThread::getCurrentMonotonicTimeMs();
|
||||||
uint64_t interval = pst.getIntervalToNextSlotMs();
|
uint32_t interval = 0;
|
||||||
|
|
||||||
// The task's "infinite" inner loop is entered.
|
// The task's "infinite" inner loop is entered.
|
||||||
while (1) {
|
while (true) {
|
||||||
if (pst.slotFollowsImmediately()) {
|
if (pollingSeqTable.slotFollowsImmediately()) {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
} else {
|
} else {
|
||||||
// The interval for the next polling slot is selected.
|
// The interval for the next polling slot is selected.
|
||||||
interval = this->pst.getIntervalToPreviousSlotMs();
|
interval = pollingSeqTable.getIntervalToPreviousSlotMs();
|
||||||
// The period is checked and restarted with the new interval.
|
// The period is checked and restarted with the new interval.
|
||||||
// If the deadline was missed, the deadlineMissedFunc is called.
|
// If the deadline was missed, the deadlineMissedFunc is called.
|
||||||
if (!PosixThread::delayUntil(&lastWakeTime, interval)) {
|
if (!PosixThread::delayUntil(&lastWakeTime, interval)) {
|
||||||
// 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.
|
||||||
this->pst.executeAndAdvance();
|
pollingSeqTable.executeAndAdvance();
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FixedTimeslotTask::missedDeadlineCounter() {
|
|
||||||
FixedTimeslotTask::deadlineMissedCount++;
|
|
||||||
if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::warning << "PST missed " << FixedTimeslotTask::deadlineMissedCount << " deadlines"
|
|
||||||
<< std::endl;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,11 +3,12 @@
|
|||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
#include "../../tasks/FixedSlotSequence.h"
|
|
||||||
#include "../../tasks/FixedTimeslotTaskIF.h"
|
|
||||||
#include "PosixThread.h"
|
#include "PosixThread.h"
|
||||||
|
#include "fsfw/tasks/FixedSlotSequence.h"
|
||||||
|
#include "fsfw/tasks/FixedTimeslotTaskBase.h"
|
||||||
|
#include "fsfw/tasks/definitions.h"
|
||||||
|
|
||||||
class FixedTimeslotTask : public FixedTimeslotTaskIF, public PosixThread {
|
class FixedTimeslotTask : public FixedTimeslotTaskBase {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Create a generic periodic task.
|
* Create a generic periodic task.
|
||||||
@ -21,29 +22,13 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF, public PosixThread {
|
|||||||
* @param period_
|
* @param period_
|
||||||
* @param deadlineMissedFunc_
|
* @param deadlineMissedFunc_
|
||||||
*/
|
*/
|
||||||
FixedTimeslotTask(const char* name_, int priority_, size_t stackSize_, uint32_t periodMs_);
|
FixedTimeslotTask(const char* name_, TaskPriority priority_, size_t stackSize_,
|
||||||
virtual ~FixedTimeslotTask();
|
TaskPeriod periodSeconds_, TaskDeadlineMissedFunction dlmFunc_);
|
||||||
|
~FixedTimeslotTask() override = default;
|
||||||
|
|
||||||
virtual ReturnValue_t startTask();
|
ReturnValue_t startTask() override;
|
||||||
|
|
||||||
virtual ReturnValue_t sleepFor(uint32_t ms);
|
ReturnValue_t sleepFor(uint32_t ms) override;
|
||||||
|
|
||||||
virtual uint32_t getPeriodMs() const;
|
|
||||||
|
|
||||||
virtual ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs, int8_t executionStep);
|
|
||||||
|
|
||||||
virtual ReturnValue_t checkSequence() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This static function can be used as #deadlineMissedFunc.
|
|
||||||
* It counts missedDeadlines and prints the number of missed deadlines every 10th time.
|
|
||||||
*/
|
|
||||||
static void missedDeadlineCounter();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A helper variable to count missed deadlines.
|
|
||||||
*/
|
|
||||||
static uint32_t deadlineMissedCount;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
@ -53,9 +38,12 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF, public PosixThread {
|
|||||||
* It links the functionalities provided by FixedSlotSequence with the
|
* It links the functionalities provided by FixedSlotSequence with the
|
||||||
* OS's System Calls to keep the timing of the periods.
|
* OS's System Calls to keep the timing of the periods.
|
||||||
*/
|
*/
|
||||||
virtual void taskFunctionality();
|
[[noreturn]] virtual void taskFunctionality();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
PosixThread posixThread;
|
||||||
|
bool started;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This is the entry point in a new thread.
|
* @brief This is the entry point in a new thread.
|
||||||
*
|
*
|
||||||
@ -68,9 +56,6 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF, public PosixThread {
|
|||||||
* arbitrary data.
|
* arbitrary data.
|
||||||
*/
|
*/
|
||||||
static void* taskEntryPoint(void* arg);
|
static void* taskEntryPoint(void* arg);
|
||||||
FixedSlotSequence pst;
|
|
||||||
|
|
||||||
bool started;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* FSFW_OSAL_LINUX_FIXEDTIMESLOTTASK_H_ */
|
#endif /* FSFW_OSAL_LINUX_FIXEDTIMESLOTTASK_H_ */
|
||||||
|
@ -1,86 +1,54 @@
|
|||||||
#include "fsfw/osal/linux/PeriodicPosixTask.h"
|
#include "PeriodicPosixTask.h"
|
||||||
|
|
||||||
#include <errno.h>
|
#include "fsfw/serviceinterface.h"
|
||||||
|
|
||||||
#include "fsfw/objectmanager/ObjectManager.h"
|
|
||||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
|
||||||
#include "fsfw/tasks/ExecutableObjectIF.h"
|
#include "fsfw/tasks/ExecutableObjectIF.h"
|
||||||
|
|
||||||
PeriodicPosixTask::PeriodicPosixTask(const char* name_, int priority_, size_t stackSize_,
|
PeriodicPosixTask::PeriodicPosixTask(const char* name_, int priority_, size_t stackSize_,
|
||||||
uint32_t period_, void(deadlineMissedFunc_)())
|
TaskPeriod period_, TaskDeadlineMissedFunction dlmFunc_)
|
||||||
: PosixThread(name_, priority_, stackSize_),
|
: PeriodicTaskBase(period_, dlmFunc_),
|
||||||
objectList(),
|
posixThread(name_, priority_, stackSize_),
|
||||||
started(false),
|
started(false) {}
|
||||||
periodMs(period_),
|
|
||||||
deadlineMissedFunc(deadlineMissedFunc_) {}
|
|
||||||
|
|
||||||
PeriodicPosixTask::~PeriodicPosixTask() {
|
|
||||||
// Not Implemented
|
|
||||||
}
|
|
||||||
|
|
||||||
void* PeriodicPosixTask::taskEntryPoint(void* arg) {
|
void* PeriodicPosixTask::taskEntryPoint(void* arg) {
|
||||||
// The argument is re-interpreted as PollingTask.
|
// The argument is re-interpreted as PollingTask.
|
||||||
PeriodicPosixTask* originalTask(reinterpret_cast<PeriodicPosixTask*>(arg));
|
auto* originalTask(reinterpret_cast<PeriodicPosixTask*>(arg));
|
||||||
// The task's functionality is called.
|
// The task's functionality is called.
|
||||||
originalTask->taskFunctionality();
|
originalTask->taskFunctionality();
|
||||||
return NULL;
|
return nullptr;
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t PeriodicPosixTask::addComponent(object_id_t object) {
|
|
||||||
ExecutableObjectIF* newObject = ObjectManager::instance()->get<ExecutableObjectIF>(object);
|
|
||||||
return addComponent(newObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t PeriodicPosixTask::addComponent(ExecutableObjectIF* object) {
|
|
||||||
if (object == nullptr) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "PeriodicTask::addComponent: Invalid object. Make sure"
|
|
||||||
<< " it implements ExecutableObjectIF!" << std::endl;
|
|
||||||
#else
|
|
||||||
sif::printError(
|
|
||||||
"PeriodicTask::addComponent: Invalid object. Make sure it "
|
|
||||||
"implements ExecutableObjectIF!\n");
|
|
||||||
#endif
|
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
|
||||||
}
|
|
||||||
objectList.push_back(object);
|
|
||||||
object->setTaskIF(this);
|
|
||||||
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t PeriodicPosixTask::sleepFor(uint32_t ms) {
|
ReturnValue_t PeriodicPosixTask::sleepFor(uint32_t ms) {
|
||||||
return PosixThread::sleep((uint64_t)ms * 1000000);
|
return PosixThread::sleep(static_cast<uint64_t>(ms) * 1000000);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t PeriodicPosixTask::startTask(void) {
|
ReturnValue_t PeriodicPosixTask::startTask() {
|
||||||
|
if (isEmpty()) {
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
started = true;
|
started = true;
|
||||||
PosixThread::createTask(&taskEntryPoint, this);
|
posixThread.createTask(&taskEntryPoint, this);
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PeriodicPosixTask::taskFunctionality(void) {
|
[[noreturn]] void PeriodicPosixTask::taskFunctionality() {
|
||||||
if (not started) {
|
if (not started) {
|
||||||
suspend();
|
posixThread.suspend();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto const& object : objectList) {
|
initObjsAfterTaskCreation();
|
||||||
object->initializeAfterTaskCreation();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t lastWakeTime = getCurrentMonotonicTimeMs();
|
uint64_t lastWakeTime = PosixThread::getCurrentMonotonicTimeMs();
|
||||||
|
uint64_t periodMs = getPeriodMs();
|
||||||
// The task's "infinite" inner loop is entered.
|
// The task's "infinite" inner loop is entered.
|
||||||
while (1) {
|
while (true) {
|
||||||
for (auto const& object : objectList) {
|
for (auto const& objOpCodePair : objectList) {
|
||||||
object->performOperation();
|
objOpCodePair.first->performOperation(objOpCodePair.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (not PosixThread::delayUntil(&lastWakeTime, periodMs)) {
|
if (not PosixThread::delayUntil(&lastWakeTime, periodMs)) {
|
||||||
if (this->deadlineMissedFunc != nullptr) {
|
if (dlmFunc != nullptr) {
|
||||||
this->deadlineMissedFunc();
|
dlmFunc();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t PeriodicPosixTask::getPeriodMs() const { return periodMs; }
|
|
||||||
|
@ -3,12 +3,13 @@
|
|||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "../../objectmanager/ObjectManagerIF.h"
|
|
||||||
#include "../../tasks/ExecutableObjectIF.h"
|
|
||||||
#include "../../tasks/PeriodicTaskIF.h"
|
|
||||||
#include "PosixThread.h"
|
#include "PosixThread.h"
|
||||||
|
#include "fsfw/objectmanager/ObjectManagerIF.h"
|
||||||
|
#include "fsfw/tasks/ExecutableObjectIF.h"
|
||||||
|
#include "fsfw/tasks/PeriodicTaskBase.h"
|
||||||
|
#include "fsfw/tasks/PeriodicTaskIF.h"
|
||||||
|
|
||||||
class PeriodicPosixTask : public PosixThread, public PeriodicTaskIF {
|
class PeriodicPosixTask : public PeriodicTaskBase {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Create a generic periodic task.
|
* Create a generic periodic task.
|
||||||
@ -22,9 +23,9 @@ class PeriodicPosixTask : public PosixThread, public PeriodicTaskIF {
|
|||||||
* @param period_
|
* @param period_
|
||||||
* @param deadlineMissedFunc_
|
* @param deadlineMissedFunc_
|
||||||
*/
|
*/
|
||||||
PeriodicPosixTask(const char* name_, int priority_, size_t stackSize_, uint32_t period_,
|
PeriodicPosixTask(const char* name_, int priority_, size_t stackSize_, TaskPeriod period_,
|
||||||
void (*deadlineMissedFunc_)());
|
TaskDeadlineMissedFunction dlmFunc_);
|
||||||
virtual ~PeriodicPosixTask();
|
~PeriodicPosixTask() override = default;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The method to start the task.
|
* @brief The method to start the task.
|
||||||
@ -34,42 +35,17 @@ class PeriodicPosixTask : public PosixThread, public PeriodicTaskIF {
|
|||||||
* 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 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;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef std::vector<ExecutableObjectIF*> ObjectList; //!< Typedef for the List of objects.
|
PosixThread posixThread;
|
||||||
/**
|
|
||||||
* @brief This attribute holds a list of objects to be executed.
|
|
||||||
*/
|
|
||||||
ObjectList objectList;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Flag to indicate that the task was started and is allowed to run
|
* @brief Flag to indicate that the task was started and is allowed to run
|
||||||
*/
|
*/
|
||||||
bool started;
|
bool started;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Period of the task in milliseconds
|
|
||||||
*/
|
|
||||||
uint32_t periodMs;
|
|
||||||
/**
|
/**
|
||||||
* @brief The function containing the actual functionality of the task.
|
* @brief The function containing the actual functionality of the task.
|
||||||
* @details The method sets and starts
|
* @details The method sets and starts
|
||||||
@ -78,7 +54,7 @@ class PeriodicPosixTask : public PosixThread, public PeriodicTaskIF {
|
|||||||
* will be blocked until the next period. On missing the deadline, the deadlineMissedFunction is
|
* will be blocked until the next period. On missing the deadline, the deadlineMissedFunction is
|
||||||
* executed.
|
* executed.
|
||||||
*/
|
*/
|
||||||
virtual void taskFunctionality(void);
|
[[noreturn]] virtual void taskFunctionality();
|
||||||
/**
|
/**
|
||||||
* @brief This is the entry point in a new thread.
|
* @brief This is the entry point in a new thread.
|
||||||
*
|
*
|
||||||
@ -86,14 +62,6 @@ class PeriodicPosixTask : public PosixThread, public PeriodicTaskIF {
|
|||||||
* of the child class. Needs a valid pointer to the derived class.
|
* of the child class. Needs a valid pointer to the derived class.
|
||||||
*/
|
*/
|
||||||
static void* taskEntryPoint(void* arg);
|
static void* taskEntryPoint(void* arg);
|
||||||
/**
|
|
||||||
* @brief The pointer to the deadline-missed function.
|
|
||||||
* @details This pointer stores the function that is executed if the task's deadline is missed.
|
|
||||||
* So, each may react individually on a timing failure. The pointer may be
|
|
||||||
* NULL, then nothing happens on missing the deadline. The deadline is equal to the next execution
|
|
||||||
* of the periodic task.
|
|
||||||
*/
|
|
||||||
void (*deadlineMissedFunc)();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* FRAMEWORK_OSAL_LINUX_PERIODICPOSIXTASK_H_ */
|
#endif /* FRAMEWORK_OSAL_LINUX_PERIODICPOSIXTASK_H_ */
|
||||||
|
@ -35,6 +35,21 @@ class PosixThread {
|
|||||||
*/
|
*/
|
||||||
void resume();
|
void resume();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function that has to be called by derived class because the
|
||||||
|
* derived class pointer has to be valid as argument.
|
||||||
|
* @details
|
||||||
|
* This function creates a pthread with the given parameters. As the
|
||||||
|
* function requires a pointer to the derived object it has to be called
|
||||||
|
* after the this pointer of the derived object is valid.
|
||||||
|
* Sets the taskEntryPoint as function to be called by new a thread.
|
||||||
|
* @param fnc_ Function which will be executed by the thread.
|
||||||
|
* @param arg_
|
||||||
|
* argument of the taskEntryPoint function, needs to be this pointer
|
||||||
|
* of derived class
|
||||||
|
*/
|
||||||
|
void createTask(void* (*fnc_)(void*), void* arg_);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delay function similar to FreeRtos delayUntil function
|
* Delay function similar to FreeRtos delayUntil function
|
||||||
*
|
*
|
||||||
@ -55,21 +70,6 @@ class PosixThread {
|
|||||||
protected:
|
protected:
|
||||||
pthread_t thread;
|
pthread_t thread;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Function that has to be called by derived class because the
|
|
||||||
* derived class pointer has to be valid as argument.
|
|
||||||
* @details
|
|
||||||
* This function creates a pthread with the given parameters. As the
|
|
||||||
* function requires a pointer to the derived object it has to be called
|
|
||||||
* after the this pointer of the derived object is valid.
|
|
||||||
* Sets the taskEntryPoint as function to be called by new a thread.
|
|
||||||
* @param fnc_ Function which will be executed by the thread.
|
|
||||||
* @param arg_
|
|
||||||
* argument of the taskEntryPoint function, needs to be this pointer
|
|
||||||
* of derived class
|
|
||||||
*/
|
|
||||||
void createTask(void* (*fnc_)(void*), void* arg_);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
char name[PTHREAD_MAX_NAMELEN];
|
char name[PTHREAD_MAX_NAMELEN];
|
||||||
int priority;
|
int priority;
|
||||||
|
@ -8,21 +8,22 @@
|
|||||||
// TODO: Different variant than the lazy loading in QueueFactory. What's better and why?
|
// TODO: Different variant than the lazy loading in QueueFactory. What's better and why?
|
||||||
TaskFactory* TaskFactory::factoryInstance = new TaskFactory();
|
TaskFactory* TaskFactory::factoryInstance = new TaskFactory();
|
||||||
|
|
||||||
TaskFactory::~TaskFactory() {}
|
TaskFactory::~TaskFactory() = default;
|
||||||
|
|
||||||
TaskFactory* TaskFactory::instance() { return TaskFactory::factoryInstance; }
|
TaskFactory* TaskFactory::instance() { return TaskFactory::factoryInstance; }
|
||||||
|
|
||||||
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_) {
|
||||||
return new PeriodicPosixTask(name_, taskPriority_, stackSize_, periodInSeconds_ * 1000,
|
return new PeriodicPosixTask(name_, taskPriority_, stackSize_, periodInSeconds_,
|
||||||
deadLineMissedFunction_);
|
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_) {
|
||||||
return new FixedTimeslotTask(name_, taskPriority_, stackSize_, periodInSeconds_ * 1000);
|
return new FixedTimeslotTask(name_, taskPriority_, stackSize_, periodInSeconds_,
|
||||||
|
deadLineMissedFunction_);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) {
|
ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) {
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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_ */
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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); }
|
|
||||||
|
@ -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_ */
|
||||||
|
@ -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) {
|
||||||
|
@ -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));
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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() {}
|
|
||||||
|
@ -17,28 +17,28 @@ void DummyPowerSwitcher::setInitialFusesList(std::vector<ReturnValue_t> fuseList
|
|||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t DummyPowerSwitcher::sendSwitchCommand(power::Switch_t switchNr, ReturnValue_t onOff) {
|
ReturnValue_t DummyPowerSwitcher::sendSwitchCommand(power::Switch_t switchNr, ReturnValue_t onOff) {
|
||||||
if (switchNr < switcherList.capacity()) {
|
if (switchNr < switcherList.size()) {
|
||||||
switcherList[switchNr] = onOff;
|
switcherList[switchNr] = onOff;
|
||||||
}
|
}
|
||||||
return RETURN_FAILED;
|
return RETURN_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t DummyPowerSwitcher::sendFuseOnCommand(uint8_t fuseNr) {
|
ReturnValue_t DummyPowerSwitcher::sendFuseOnCommand(uint8_t fuseNr) {
|
||||||
if (fuseNr < fuseList.capacity()) {
|
if (fuseNr < fuseList.size()) {
|
||||||
fuseList[fuseNr] = FUSE_ON;
|
fuseList[fuseNr] = FUSE_ON;
|
||||||
}
|
}
|
||||||
return RETURN_FAILED;
|
return RETURN_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t DummyPowerSwitcher::getSwitchState(power::Switch_t switchNr) const {
|
ReturnValue_t DummyPowerSwitcher::getSwitchState(power::Switch_t switchNr) const {
|
||||||
if (switchNr < switcherList.capacity()) {
|
if (switchNr < switcherList.size()) {
|
||||||
return switcherList[switchNr];
|
return switcherList[switchNr];
|
||||||
}
|
}
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t DummyPowerSwitcher::getFuseState(uint8_t fuseNr) const {
|
ReturnValue_t DummyPowerSwitcher::getFuseState(uint8_t fuseNr) const {
|
||||||
if (fuseNr < fuseList.capacity()) {
|
if (fuseNr < fuseList.size()) {
|
||||||
return fuseList[fuseNr];
|
return fuseList[fuseNr];
|
||||||
}
|
}
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
203
src/fsfw/pus/Service11TelecommandScheduling.h
Normal file
203
src/fsfw/pus/Service11TelecommandScheduling.h
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
#ifndef MISSION_PUS_SERVICE11TELECOMMANDSCHEDULING_H_
|
||||||
|
#define MISSION_PUS_SERVICE11TELECOMMANDSCHEDULING_H_
|
||||||
|
|
||||||
|
#include <etl/multimap.h>
|
||||||
|
#include <fsfw/tmtcservices/PusServiceBase.h>
|
||||||
|
#include <fsfw/tmtcservices/TmTcMessage.h>
|
||||||
|
|
||||||
|
#include "fsfw/FSFW.h"
|
||||||
|
#include "fsfw/returnvalues/FwClassIds.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief: PUS-Service 11 - Telecommand scheduling.
|
||||||
|
* @details:
|
||||||
|
* PUS-Service 11 - Telecommand scheduling.
|
||||||
|
* Full documentation: ECSS-E-ST-70-41C, p. 168:
|
||||||
|
* ST[11] time-based scheduling
|
||||||
|
*
|
||||||
|
* This service provides the capability to command pre-loaded
|
||||||
|
* application processes (telecommands) by releasing them at their
|
||||||
|
* due-time.
|
||||||
|
* References to telecommands are stored together with their due-timepoints
|
||||||
|
* and are released at their corresponding due-time.
|
||||||
|
*
|
||||||
|
* Necessary subservice functionalities are implemented.
|
||||||
|
* Those are:
|
||||||
|
* TC[11,4] activity insertion
|
||||||
|
* TC[11,5] activity deletion
|
||||||
|
* TC[11,6] filter-based activity deletion
|
||||||
|
* TC[11,7] activity time-shift
|
||||||
|
* TC[11,8] filter-based activity time-shift
|
||||||
|
*
|
||||||
|
* Groups are not supported.
|
||||||
|
* This service remains always enabled. Sending a disable-request has no effect.
|
||||||
|
*/
|
||||||
|
template <size_t MAX_NUM_TCS>
|
||||||
|
class Service11TelecommandScheduling final : public PusServiceBase {
|
||||||
|
public:
|
||||||
|
static constexpr uint8_t CLASS_ID = CLASS_ID::PUS_SERVICE_11;
|
||||||
|
|
||||||
|
static constexpr ReturnValue_t INVALID_TYPE_TIME_WINDOW =
|
||||||
|
HasReturnvaluesIF::makeReturnCode(CLASS_ID, 1);
|
||||||
|
static constexpr ReturnValue_t TIMESHIFTING_NOT_POSSIBLE =
|
||||||
|
HasReturnvaluesIF::makeReturnCode(CLASS_ID, 2);
|
||||||
|
static constexpr ReturnValue_t INVALID_RELATIVE_TIME =
|
||||||
|
HasReturnvaluesIF::makeReturnCode(CLASS_ID, 3);
|
||||||
|
|
||||||
|
static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PUS_SERVICE_11;
|
||||||
|
|
||||||
|
//! [EXPORT] : [COMMENT] Deletion of a TC from the map failed.
|
||||||
|
//! P1: First 32 bit of request ID, P2. Last 32 bit of Request ID
|
||||||
|
static constexpr Event TC_DELETION_FAILED = event::makeEvent(SUBSYSTEM_ID, 0, severity::MEDIUM);
|
||||||
|
|
||||||
|
// The types of PUS-11 subservices
|
||||||
|
enum Subservice : uint8_t {
|
||||||
|
ENABLE_SCHEDULING = 1,
|
||||||
|
DISABLE_SCHEDULING = 2,
|
||||||
|
RESET_SCHEDULING = 3,
|
||||||
|
INSERT_ACTIVITY = 4,
|
||||||
|
DELETE_ACTIVITY = 5,
|
||||||
|
FILTER_DELETE_ACTIVITY = 6,
|
||||||
|
TIMESHIFT_ACTIVITY = 7,
|
||||||
|
FILTER_TIMESHIFT_ACTIVITY = 8,
|
||||||
|
DETAIL_REPORT = 9,
|
||||||
|
TIMEBASE_SCHEDULE_DETAIL_REPORT = 10,
|
||||||
|
TIMESHIFT_ALL_SCHEDULE_ACTIVITIES = 15
|
||||||
|
};
|
||||||
|
|
||||||
|
// The types of time windows for TC[11,6] and TC[11,8], as defined in ECSS-E-ST-70-41C,
|
||||||
|
// requirement 8.11.3c (p. 507)
|
||||||
|
enum TypeOfTimeWindow : uint32_t {
|
||||||
|
SELECT_ALL = 0,
|
||||||
|
FROM_TIMETAG_TO_TIMETAG = 1,
|
||||||
|
FROM_TIMETAG = 2,
|
||||||
|
TO_TIMETAG = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
Service11TelecommandScheduling(object_id_t objectId, uint16_t apid, uint8_t serviceId,
|
||||||
|
AcceptsTelecommandsIF* tcRecipient,
|
||||||
|
uint16_t releaseTimeMarginSeconds = DEFAULT_RELEASE_TIME_MARGIN,
|
||||||
|
bool debugMode = false);
|
||||||
|
|
||||||
|
~Service11TelecommandScheduling() override;
|
||||||
|
|
||||||
|
void enableExpiredTcDeletion();
|
||||||
|
void disableExpiredTcDeletion();
|
||||||
|
|
||||||
|
/** PusServiceBase overrides */
|
||||||
|
ReturnValue_t handleRequest(uint8_t subservice) override;
|
||||||
|
ReturnValue_t performService() override;
|
||||||
|
ReturnValue_t initialize() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct TelecommandStruct {
|
||||||
|
uint64_t requestId{};
|
||||||
|
uint32_t seconds{};
|
||||||
|
store_address_t storeAddr; // uint16
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr uint16_t DEFAULT_RELEASE_TIME_MARGIN = 5;
|
||||||
|
|
||||||
|
// minimum release time offset to insert into schedule
|
||||||
|
const uint16_t RELEASE_TIME_MARGIN_SECONDS = 5;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* By default, the scheduling will be disabled. This is a standard requirement
|
||||||
|
*/
|
||||||
|
bool schedulingEnabled = false;
|
||||||
|
bool deleteExpiredTcWhenDisabled = true;
|
||||||
|
bool debugMode = false;
|
||||||
|
StorageManagerIF* tcStore = nullptr;
|
||||||
|
AcceptsTelecommandsIF* tcRecipient = nullptr;
|
||||||
|
MessageQueueId_t recipientMsgQueueId = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The telecommand map uses the exectution time as a Unix time stamp as
|
||||||
|
* the key. This is mapped to a generic telecommand struct.
|
||||||
|
*/
|
||||||
|
using TelecommandMap = etl::multimap<uint32_t, TelecommandStruct, MAX_NUM_TCS>;
|
||||||
|
using TcMapIter = typename TelecommandMap::iterator;
|
||||||
|
|
||||||
|
TelecommandMap telecommandMap;
|
||||||
|
|
||||||
|
ReturnValue_t handleResetCommand();
|
||||||
|
/**
|
||||||
|
* @brief Logic to be performed on an incoming TC[11,4].
|
||||||
|
* @return RETURN_OK if successful
|
||||||
|
*/
|
||||||
|
ReturnValue_t doInsertActivity(const uint8_t* data, size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Logic to be performed on an incoming TC[11,5].
|
||||||
|
* @return RETURN_OK if successful
|
||||||
|
*/
|
||||||
|
ReturnValue_t doDeleteActivity(const uint8_t* data, size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Logic to be performed on an incoming TC[11,6].
|
||||||
|
* @return RETURN_OK if successful
|
||||||
|
*/
|
||||||
|
ReturnValue_t doFilterDeleteActivity(const uint8_t* data, size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Logic to be performed on an incoming TC[11,7].
|
||||||
|
* @return RETURN_OK if successful
|
||||||
|
*/
|
||||||
|
ReturnValue_t doTimeshiftActivity(const uint8_t* data, size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Logic to be performed on an incoming TC[11,8].
|
||||||
|
* @return RETURN_OK if successful
|
||||||
|
*/
|
||||||
|
ReturnValue_t doFilterTimeshiftActivity(const uint8_t* data, size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Extracts the Request ID from the Application Data of a TC by utilizing a ctor of the
|
||||||
|
* class TcPacketPus.
|
||||||
|
* NOTE: This only works if the payload data is a TC (e.g. not for TC[11,5] which does not
|
||||||
|
* send a TC as payload)!
|
||||||
|
* @param data The Application data of the TC (get via getApplicationData()).
|
||||||
|
* @return requestId
|
||||||
|
*/
|
||||||
|
uint64_t getRequestIdFromDataTC(const uint8_t* data) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Extracts the Request ID from the Application Data directly, assuming it is packed
|
||||||
|
* as follows (acc. to ECSS): | source ID (uint32) | apid (uint32) | ssc (uint32) |.
|
||||||
|
* @param data Pointer to first byte described data
|
||||||
|
* @param dataSize Remaining size of data NOTE: non-const, this is modified by the function
|
||||||
|
* @param [out] requestId Request ID
|
||||||
|
* @return RETURN_OK if successful
|
||||||
|
*/
|
||||||
|
ReturnValue_t getRequestIdFromData(const uint8_t*& data, size_t& dataSize, uint64_t& requestId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Builds the Request ID from its three elements.
|
||||||
|
* @param sourceId Source ID
|
||||||
|
* @param apid Application Process ID (APID)
|
||||||
|
* @param ssc Source Sequence Count
|
||||||
|
* @return Request ID
|
||||||
|
*/
|
||||||
|
[[nodiscard]] uint64_t buildRequestId(uint32_t sourceId, uint16_t apid, uint16_t ssc) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the filter range for filter TCs from a data packet
|
||||||
|
* @param data TC data
|
||||||
|
* @param dataSize TC data size
|
||||||
|
* @param [out] itBegin Begin of filter range
|
||||||
|
* @param [out] itEnd End of filter range
|
||||||
|
* @return RETURN_OK if successful
|
||||||
|
*/
|
||||||
|
ReturnValue_t getMapFilterFromData(const uint8_t*& data, size_t& size, TcMapIter& itBegin,
|
||||||
|
TcMapIter& itEnd);
|
||||||
|
|
||||||
|
ReturnValue_t handleInvalidData(const char* ctx);
|
||||||
|
/**
|
||||||
|
* @brief Prints content of multimap. Use for simple debugging only.
|
||||||
|
*/
|
||||||
|
void debugPrintMultimapContent() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#include "Service11TelecommandScheduling.tpp"
|
||||||
|
|
||||||
|
#endif /* MISSION_PUS_SERVICE11TELECOMMANDSCHEDULING_H_ */
|
645
src/fsfw/pus/Service11TelecommandScheduling.tpp
Normal file
645
src/fsfw/pus/Service11TelecommandScheduling.tpp
Normal file
@ -0,0 +1,645 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
#include "fsfw/objectmanager/ObjectManager.h"
|
||||||
|
#include "fsfw/serialize/SerializeAdapter.h"
|
||||||
|
#include "fsfw/serviceinterface.h"
|
||||||
|
#include "fsfw/tmtcservices/AcceptsTelecommandsIF.h"
|
||||||
|
|
||||||
|
static constexpr auto DEF_END = SerializeIF::Endianness::BIG;
|
||||||
|
|
||||||
|
template <size_t MAX_NUM_TCS>
|
||||||
|
inline Service11TelecommandScheduling<MAX_NUM_TCS>::Service11TelecommandScheduling(
|
||||||
|
object_id_t objectId, uint16_t apid, uint8_t serviceId, AcceptsTelecommandsIF *tcRecipient,
|
||||||
|
uint16_t releaseTimeMarginSeconds, bool debugMode)
|
||||||
|
: PusServiceBase(objectId, apid, serviceId),
|
||||||
|
RELEASE_TIME_MARGIN_SECONDS(releaseTimeMarginSeconds),
|
||||||
|
debugMode(debugMode),
|
||||||
|
tcRecipient(tcRecipient) {}
|
||||||
|
|
||||||
|
template <size_t MAX_NUM_TCS>
|
||||||
|
inline Service11TelecommandScheduling<MAX_NUM_TCS>::~Service11TelecommandScheduling() = default;
|
||||||
|
|
||||||
|
template <size_t MAX_NUM_TCS>
|
||||||
|
inline ReturnValue_t Service11TelecommandScheduling<MAX_NUM_TCS>::handleRequest(
|
||||||
|
uint8_t subservice) {
|
||||||
|
if (debugMode) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::info << "PUS11::handleRequest: Handling request " << static_cast<int>(subservice);
|
||||||
|
#else
|
||||||
|
sif::printInfo("PUS11::handleRequest: Handling request %d\n", subservice);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
// Get de-serialized Timestamp
|
||||||
|
const uint8_t *data = currentPacket.getApplicationData();
|
||||||
|
size_t size = currentPacket.getApplicationDataSize();
|
||||||
|
if (data == nullptr) {
|
||||||
|
return handleInvalidData("handleRequest");
|
||||||
|
}
|
||||||
|
switch (subservice) {
|
||||||
|
case Subservice::ENABLE_SCHEDULING: {
|
||||||
|
schedulingEnabled = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Subservice::DISABLE_SCHEDULING: {
|
||||||
|
schedulingEnabled = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Subservice::RESET_SCHEDULING: {
|
||||||
|
return handleResetCommand();
|
||||||
|
}
|
||||||
|
case Subservice::INSERT_ACTIVITY:
|
||||||
|
return doInsertActivity(data, size);
|
||||||
|
case Subservice::DELETE_ACTIVITY:
|
||||||
|
return doDeleteActivity(data, size);
|
||||||
|
case Subservice::FILTER_DELETE_ACTIVITY:
|
||||||
|
return doFilterDeleteActivity(data, size);
|
||||||
|
case Subservice::TIMESHIFT_ACTIVITY:
|
||||||
|
return doTimeshiftActivity(data, size);
|
||||||
|
case Subservice::FILTER_TIMESHIFT_ACTIVITY:
|
||||||
|
return doFilterTimeshiftActivity(data, size);
|
||||||
|
default:
|
||||||
|
return AcceptsTelecommandsIF::INVALID_SUBSERVICE;
|
||||||
|
}
|
||||||
|
return RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t MAX_NUM_TCS>
|
||||||
|
inline ReturnValue_t Service11TelecommandScheduling<MAX_NUM_TCS>::performService() {
|
||||||
|
if (not schedulingEnabled) {
|
||||||
|
return RETURN_OK;
|
||||||
|
}
|
||||||
|
// get current time as UNIX timestamp
|
||||||
|
timeval tNow = {};
|
||||||
|
Clock::getClock_timeval(&tNow);
|
||||||
|
|
||||||
|
// TODO: Optionally limit the max number of released TCs per cycle?
|
||||||
|
// NOTE: The iterator is increased in the loop here. Increasing the iterator as for-loop arg
|
||||||
|
// does not work in this case as we are deleting the current element here.
|
||||||
|
for (auto it = telecommandMap.begin(); it != telecommandMap.end();) {
|
||||||
|
if (it->first <= tNow.tv_sec) {
|
||||||
|
if (schedulingEnabled) {
|
||||||
|
// release tc
|
||||||
|
TmTcMessage releaseMsg(it->second.storeAddr);
|
||||||
|
auto sendRet = this->requestQueue->sendMessage(recipientMsgQueueId, &releaseMsg, false);
|
||||||
|
|
||||||
|
if (sendRet != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
return sendRet;
|
||||||
|
}
|
||||||
|
if (debugMode) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::info << "Released TC & erased it from TC map" << std::endl;
|
||||||
|
#else
|
||||||
|
sif::printInfo("Released TC & erased it from TC map\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
telecommandMap.erase(it++);
|
||||||
|
} else if (deleteExpiredTcWhenDisabled) {
|
||||||
|
telecommandMap.erase(it++);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t MAX_NUM_TCS>
|
||||||
|
inline ReturnValue_t Service11TelecommandScheduling<MAX_NUM_TCS>::initialize() {
|
||||||
|
ReturnValue_t res = PusServiceBase::initialize();
|
||||||
|
if (res != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
tcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TC_STORE);
|
||||||
|
if (!tcStore) {
|
||||||
|
return ObjectManagerIF::CHILD_INIT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tcRecipient == nullptr) {
|
||||||
|
return ObjectManagerIF::CHILD_INIT_FAILED;
|
||||||
|
}
|
||||||
|
recipientMsgQueueId = tcRecipient->getRequestQueue();
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t MAX_NUM_TCS>
|
||||||
|
inline ReturnValue_t Service11TelecommandScheduling<MAX_NUM_TCS>::handleResetCommand() {
|
||||||
|
for (auto it = telecommandMap.begin(); it != telecommandMap.end(); it++) {
|
||||||
|
ReturnValue_t result = tcStore->deleteData(it->second.storeAddr);
|
||||||
|
if (result != RETURN_OK) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
// This should not happen
|
||||||
|
sif::warning << "Service11TelecommandScheduling::handleRequestDeleting: Deletion failed"
|
||||||
|
<< std::endl;
|
||||||
|
#else
|
||||||
|
sif::printWarning("Service11TelecommandScheduling::handleRequestDeleting: Deletion failed\n");
|
||||||
|
#endif
|
||||||
|
triggerEvent(TC_DELETION_FAILED, (it->second.requestId >> 32) & 0xffffffff,
|
||||||
|
it->second.requestId & 0xffffffff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
telecommandMap.clear();
|
||||||
|
return RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t MAX_NUM_TCS>
|
||||||
|
inline ReturnValue_t Service11TelecommandScheduling<MAX_NUM_TCS>::doInsertActivity(
|
||||||
|
const uint8_t *data, size_t size) {
|
||||||
|
uint32_t timestamp = 0;
|
||||||
|
ReturnValue_t result = SerializeAdapter::deSerialize(×tamp, &data, &size, DEF_END);
|
||||||
|
if (result != RETURN_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert possible if sched. time is above margin
|
||||||
|
// (See requirement for Time margin)
|
||||||
|
timeval tNow = {};
|
||||||
|
Clock::getClock_timeval(&tNow);
|
||||||
|
if (timestamp - tNow.tv_sec <= RELEASE_TIME_MARGIN_SECONDS) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::warning << "Service11TelecommandScheduling::doInsertActivity: Release time too close to "
|
||||||
|
"current time"
|
||||||
|
<< std::endl;
|
||||||
|
#else
|
||||||
|
sif::printWarning(
|
||||||
|
"Service11TelecommandScheduling::doInsertActivity: Release time too close to current "
|
||||||
|
"time\n");
|
||||||
|
#endif
|
||||||
|
return RETURN_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// store currentPacket and receive the store address
|
||||||
|
store_address_t addr{};
|
||||||
|
if (tcStore->addData(&addr, data, size) != RETURN_OK ||
|
||||||
|
addr.raw == storeId::INVALID_STORE_ADDRESS) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::error << "Service11TelecommandScheduling::doInsertActivity: Adding data to TC Store failed"
|
||||||
|
<< std::endl;
|
||||||
|
#else
|
||||||
|
sif::printError(
|
||||||
|
"Service11TelecommandScheduling::doInsertActivity: Adding data to TC Store failed\n");
|
||||||
|
#endif
|
||||||
|
return RETURN_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert into multimap with new store address
|
||||||
|
TelecommandStruct tc;
|
||||||
|
tc.seconds = timestamp;
|
||||||
|
tc.storeAddr = addr;
|
||||||
|
tc.requestId =
|
||||||
|
getRequestIdFromDataTC(data); // TODO: Missing sanity check of the returned request id
|
||||||
|
|
||||||
|
auto it = telecommandMap.insert(std::pair<uint32_t, TelecommandStruct>(timestamp, tc));
|
||||||
|
if (it == telecommandMap.end()) {
|
||||||
|
return RETURN_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (debugMode) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::info << "PUS11::doInsertActivity: Inserted into Multimap:" << std::endl;
|
||||||
|
#else
|
||||||
|
sif::printInfo("PUS11::doInsertActivity: Inserted into Multimap:\n");
|
||||||
|
#endif
|
||||||
|
debugPrintMultimapContent();
|
||||||
|
}
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t MAX_NUM_TCS>
|
||||||
|
inline ReturnValue_t Service11TelecommandScheduling<MAX_NUM_TCS>::doDeleteActivity(
|
||||||
|
const uint8_t *data, size_t size) {
|
||||||
|
// Get request ID
|
||||||
|
uint64_t requestId;
|
||||||
|
ReturnValue_t result = getRequestIdFromData(data, size, requestId);
|
||||||
|
if (result != RETURN_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEBUG
|
||||||
|
if (debugMode) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::info << "PUS11::doDeleteActivity: requestId: " << requestId << std::endl;
|
||||||
|
#else
|
||||||
|
sif::printInfo("PUS11::doDeleteActivity: requestId: %d\n", requestId);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
TcMapIter tcToDelete; // handle to the TC to be deleted, can be used if counter is valid
|
||||||
|
int tcToDeleteCount = 0; // counter of all found TCs. Should be 1.
|
||||||
|
|
||||||
|
for (auto it = telecommandMap.begin(); it != telecommandMap.end(); it++) {
|
||||||
|
if (it->second.requestId == requestId) {
|
||||||
|
tcToDelete = it;
|
||||||
|
tcToDeleteCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if 1 explicit TC is found via request ID
|
||||||
|
if (tcToDeleteCount == 0 || tcToDeleteCount > 1) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::warning << "Service11TelecommandScheduling::doDeleteActivity: No or more than 1 TC found. "
|
||||||
|
"Cannot explicitly delete TC"
|
||||||
|
<< std::endl;
|
||||||
|
#else
|
||||||
|
sif::printWarning(
|
||||||
|
"Service11TelecommandScheduling::doDeleteActivity: No or more than 1 TC found. "
|
||||||
|
"Cannot explicitly delete TC");
|
||||||
|
#endif
|
||||||
|
return RETURN_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete packet from store
|
||||||
|
if (tcStore->deleteData(tcToDelete->second.storeAddr) != RETURN_OK) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::error << "Service11TelecommandScheduling::doDeleteActivity: Could not delete TC from Store"
|
||||||
|
<< std::endl;
|
||||||
|
#else
|
||||||
|
sif::printError(
|
||||||
|
"Service11TelecommandScheduling::doDeleteActivity: Could not delete TC from Store\n");
|
||||||
|
#endif
|
||||||
|
return RETURN_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
telecommandMap.erase(tcToDelete);
|
||||||
|
if (debugMode) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::info << "PUS11::doDeleteActivity: Deleted TC from map" << std::endl;
|
||||||
|
#else
|
||||||
|
sif::printInfo("PUS11::doDeleteActivity: Deleted TC from map\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t MAX_NUM_TCS>
|
||||||
|
inline ReturnValue_t Service11TelecommandScheduling<MAX_NUM_TCS>::doFilterDeleteActivity(
|
||||||
|
const uint8_t *data, size_t size) {
|
||||||
|
TcMapIter itBegin;
|
||||||
|
TcMapIter itEnd;
|
||||||
|
|
||||||
|
ReturnValue_t result = getMapFilterFromData(data, size, itBegin, itEnd);
|
||||||
|
// get the filter window as map range via dedicated method
|
||||||
|
if (result != RETURN_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int deletedTCs = 0;
|
||||||
|
for (TcMapIter it = itBegin; it != itEnd; it++) {
|
||||||
|
// delete packet from store
|
||||||
|
if (tcStore->deleteData(it->second.storeAddr) != RETURN_OK) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::error << "Service11TelecommandScheduling::doFilterDeleteActivity: Could not delete TC "
|
||||||
|
"from Store"
|
||||||
|
<< std::endl;
|
||||||
|
#else
|
||||||
|
sif::printError(
|
||||||
|
"Service11TelecommandScheduling::doFilterDeleteActivity: Could not delete TC from "
|
||||||
|
"Store\n");
|
||||||
|
#endif
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
deletedTCs++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: Spec says this function erases all elements including itBegin but not itEnd,
|
||||||
|
// see here: https://www.cplusplus.com/reference/map/multimap/erase/
|
||||||
|
// Therefore we need to increase itEnd by 1. (Note that end() returns the "past-the-end" iterator)
|
||||||
|
if (itEnd != telecommandMap.end()) {
|
||||||
|
itEnd++;
|
||||||
|
}
|
||||||
|
|
||||||
|
telecommandMap.erase(itBegin, itEnd);
|
||||||
|
|
||||||
|
if (debugMode) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::info << "PUS11::doFilterDeleteActivity: Deleted " << deletedTCs << " TCs" << std::endl;
|
||||||
|
#else
|
||||||
|
sif::printInfo("PUS11::doFilterDeleteActivity: Deleted %d TCs\n", deletedTCs);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t MAX_NUM_TCS>
|
||||||
|
inline ReturnValue_t Service11TelecommandScheduling<MAX_NUM_TCS>::doTimeshiftActivity(
|
||||||
|
const uint8_t *data, size_t size) {
|
||||||
|
// Get relative time
|
||||||
|
uint32_t relativeTime = 0;
|
||||||
|
ReturnValue_t result = SerializeAdapter::deSerialize(&relativeTime, &data, &size, DEF_END);
|
||||||
|
if (result != RETURN_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
if (relativeTime == 0) {
|
||||||
|
return INVALID_RELATIVE_TIME;
|
||||||
|
}
|
||||||
|
// TODO further check sanity of the relative time?
|
||||||
|
|
||||||
|
// Get request ID
|
||||||
|
uint64_t requestId;
|
||||||
|
result = getRequestIdFromData(data, size, requestId);
|
||||||
|
if (result != RETURN_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (debugMode) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::info << "PUS11::doTimeshiftActivity: requestId: " << requestId << std::endl;
|
||||||
|
#else
|
||||||
|
sif::printInfo("PUS11::doTimeshiftActivity: requestId: %d\n", requestId);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: Despite having C++17 ETL multimap has no member function extract :(
|
||||||
|
|
||||||
|
TcMapIter tcToTimeshiftIt;
|
||||||
|
int tcToTimeshiftCount = 0;
|
||||||
|
|
||||||
|
for (auto it = telecommandMap.begin(); it != telecommandMap.end(); it++) {
|
||||||
|
if (it->second.requestId == requestId) {
|
||||||
|
tcToTimeshiftIt = it;
|
||||||
|
tcToTimeshiftCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tcToTimeshiftCount == 0 || tcToTimeshiftCount > 1) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::warning << "Service11TelecommandScheduling::doTimeshiftActivity: Either 0 or more than 1 "
|
||||||
|
"TCs found. No explicit timeshifting "
|
||||||
|
"possible"
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
#else
|
||||||
|
sif::printWarning(
|
||||||
|
"Service11TelecommandScheduling::doTimeshiftActivity: Either 0 or more than 1 TCs found. "
|
||||||
|
"No explicit timeshifting possible\n");
|
||||||
|
#endif
|
||||||
|
return TIMESHIFTING_NOT_POSSIBLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// temporarily hold the item
|
||||||
|
TelecommandStruct tempTc(tcToTimeshiftIt->second);
|
||||||
|
uint32_t tempKey = tcToTimeshiftIt->first + relativeTime;
|
||||||
|
|
||||||
|
// delete old entry from the mm
|
||||||
|
telecommandMap.erase(tcToTimeshiftIt);
|
||||||
|
|
||||||
|
// and then insert it again as new entry
|
||||||
|
telecommandMap.insert(std::make_pair(tempKey, tempTc));
|
||||||
|
|
||||||
|
if (debugMode) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::info << "PUS11::doTimeshiftActivity: Shifted TC" << std::endl;
|
||||||
|
#else
|
||||||
|
sif::printDebug("PUS11::doTimeshiftActivity: Shifted TC\n");
|
||||||
|
#endif
|
||||||
|
debugPrintMultimapContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
return RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t MAX_NUM_TCS>
|
||||||
|
inline ReturnValue_t Service11TelecommandScheduling<MAX_NUM_TCS>::doFilterTimeshiftActivity(
|
||||||
|
const uint8_t *data, size_t size) {
|
||||||
|
// Get relative time
|
||||||
|
uint32_t relativeTime = 0;
|
||||||
|
ReturnValue_t result = SerializeAdapter::deSerialize(&relativeTime, &data, &size, DEF_END);
|
||||||
|
if (result != RETURN_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
if (relativeTime == 0) {
|
||||||
|
return INVALID_RELATIVE_TIME;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do time window
|
||||||
|
TcMapIter itBegin;
|
||||||
|
TcMapIter itEnd;
|
||||||
|
result = getMapFilterFromData(data, size, itBegin, itEnd);
|
||||||
|
if (result != RETURN_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int shiftedItemsCount = 0;
|
||||||
|
for (auto it = itBegin; it != itEnd;) {
|
||||||
|
// temporarily hold the item
|
||||||
|
TelecommandStruct tempTc(it->second);
|
||||||
|
uint32_t tempKey = it->first + relativeTime;
|
||||||
|
|
||||||
|
// delete the old entry from the mm
|
||||||
|
telecommandMap.erase(it++);
|
||||||
|
|
||||||
|
// and then insert it again as new entry
|
||||||
|
telecommandMap.insert(std::make_pair(tempKey, tempTc));
|
||||||
|
shiftedItemsCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (debugMode) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::info << "PUS11::doFilterTimeshiftActivity: shiftedItemsCount: " << shiftedItemsCount
|
||||||
|
<< std::endl;
|
||||||
|
#else
|
||||||
|
sif::printInfo("PUS11::doFilterTimeshiftActivity: shiftedItemsCount: %d\n", shiftedItemsCount);
|
||||||
|
#endif
|
||||||
|
debugPrintMultimapContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shiftedItemsCount > 0) {
|
||||||
|
return RETURN_OK;
|
||||||
|
}
|
||||||
|
return RETURN_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t MAX_NUM_TCS>
|
||||||
|
inline uint64_t Service11TelecommandScheduling<MAX_NUM_TCS>::getRequestIdFromDataTC(
|
||||||
|
const uint8_t *data) const {
|
||||||
|
TcPacketPus mask(data);
|
||||||
|
|
||||||
|
uint32_t sourceId = mask.getSourceId();
|
||||||
|
uint16_t apid = mask.getAPID();
|
||||||
|
uint16_t sequenceCount = mask.getPacketSequenceCount();
|
||||||
|
|
||||||
|
return buildRequestId(sourceId, apid, sequenceCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t MAX_NUM_TCS>
|
||||||
|
inline ReturnValue_t Service11TelecommandScheduling<MAX_NUM_TCS>::getRequestIdFromData(
|
||||||
|
const uint8_t *&data, size_t &dataSize, uint64_t &requestId) {
|
||||||
|
uint32_t srcId = 0;
|
||||||
|
uint16_t apid = 0;
|
||||||
|
uint16_t ssc = 0;
|
||||||
|
|
||||||
|
ReturnValue_t result = SerializeAdapter::deSerialize(&srcId, &data, &dataSize, DEF_END);
|
||||||
|
if (result != RETURN_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
result = SerializeAdapter::deSerialize(&apid, &data, &dataSize, DEF_END);
|
||||||
|
if (result != RETURN_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
result = SerializeAdapter::deSerialize(&ssc, &data, &dataSize, DEF_END);
|
||||||
|
if (result != RETURN_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
requestId = buildRequestId(srcId, apid, ssc);
|
||||||
|
|
||||||
|
return RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t MAX_NUM_TCS>
|
||||||
|
inline uint64_t Service11TelecommandScheduling<MAX_NUM_TCS>::buildRequestId(uint32_t sourceId,
|
||||||
|
uint16_t apid,
|
||||||
|
uint16_t ssc) const {
|
||||||
|
auto sourceId64 = static_cast<uint64_t>(sourceId);
|
||||||
|
auto apid64 = static_cast<uint64_t>(apid);
|
||||||
|
auto ssc64 = static_cast<uint64_t>(ssc);
|
||||||
|
|
||||||
|
return (sourceId64 << 32) | (apid64 << 16) | ssc64;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t MAX_NUM_TCS>
|
||||||
|
inline ReturnValue_t Service11TelecommandScheduling<MAX_NUM_TCS>::getMapFilterFromData(
|
||||||
|
const uint8_t *&data, size_t &dataSize, TcMapIter &itBegin, TcMapIter &itEnd) {
|
||||||
|
// get filter type first
|
||||||
|
uint32_t typeRaw = 0;
|
||||||
|
ReturnValue_t result = SerializeAdapter::deSerialize(&typeRaw, &data, &dataSize, DEF_END);
|
||||||
|
if (result != RETURN_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeRaw > 3) {
|
||||||
|
return INVALID_TYPE_TIME_WINDOW;
|
||||||
|
}
|
||||||
|
auto type = static_cast<TypeOfTimeWindow>(typeRaw);
|
||||||
|
|
||||||
|
// we now have the type of delete activity - so now we set the range to delete,
|
||||||
|
// according to the type of time window.
|
||||||
|
// NOTE: Blocks are used in this switch-case statement so that timestamps can be
|
||||||
|
// cleanly redefined for each case.
|
||||||
|
switch (type) {
|
||||||
|
case TypeOfTimeWindow::SELECT_ALL: {
|
||||||
|
itBegin = telecommandMap.begin();
|
||||||
|
itEnd = telecommandMap.end();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TypeOfTimeWindow::FROM_TIMETAG: {
|
||||||
|
uint32_t fromTimestamp = 0;
|
||||||
|
result = SerializeAdapter::deSerialize(&fromTimestamp, &data, &dataSize, DEF_END);
|
||||||
|
if (result != RETURN_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
itBegin = telecommandMap.begin();
|
||||||
|
while (itBegin->first < fromTimestamp && itBegin != telecommandMap.end()) {
|
||||||
|
itBegin++;
|
||||||
|
}
|
||||||
|
|
||||||
|
itEnd = telecommandMap.end();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TypeOfTimeWindow::TO_TIMETAG: {
|
||||||
|
uint32_t toTimestamp;
|
||||||
|
result = SerializeAdapter::deSerialize(&toTimestamp, &data, &dataSize, DEF_END);
|
||||||
|
if (result != RETURN_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
itBegin = telecommandMap.begin();
|
||||||
|
itEnd = telecommandMap.begin();
|
||||||
|
while (itEnd->first <= toTimestamp && itEnd != telecommandMap.end()) {
|
||||||
|
itEnd++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TypeOfTimeWindow::FROM_TIMETAG_TO_TIMETAG: {
|
||||||
|
uint32_t fromTimestamp;
|
||||||
|
uint32_t toTimestamp;
|
||||||
|
|
||||||
|
result = SerializeAdapter::deSerialize(&fromTimestamp, &data, &dataSize,
|
||||||
|
SerializeIF::Endianness::BIG);
|
||||||
|
if (result != RETURN_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
result = SerializeAdapter::deSerialize(&toTimestamp, &data, &dataSize,
|
||||||
|
SerializeIF::Endianness::BIG);
|
||||||
|
if (result != RETURN_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
itBegin = telecommandMap.begin();
|
||||||
|
itEnd = telecommandMap.begin();
|
||||||
|
|
||||||
|
while (itBegin->first < fromTimestamp && itBegin != telecommandMap.end()) {
|
||||||
|
itBegin++;
|
||||||
|
}
|
||||||
|
while (itEnd->first <= toTimestamp && itEnd != telecommandMap.end()) {
|
||||||
|
itEnd++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return RETURN_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// additional security check, this should never be true
|
||||||
|
if (itBegin->first > itEnd->first) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
#else
|
||||||
|
sif::printError("11::GetMapFilterFromData: itBegin > itEnd\n");
|
||||||
|
#endif
|
||||||
|
return RETURN_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// the map range should now be set according to the sent filter.
|
||||||
|
return RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t MAX_NUM_TCS>
|
||||||
|
inline ReturnValue_t Service11TelecommandScheduling<MAX_NUM_TCS>::handleInvalidData(
|
||||||
|
const char *ctx) {
|
||||||
|
#if FSFW_VERBOSE_LEVEL >= 1
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::warning << "Service11TelecommandScheduling:: " << ctx << ": Invalid buffer" << std::endl;
|
||||||
|
#else
|
||||||
|
sif::printWarning("Service11TelecommandScheduling::%s: Invalid buffer\n", ctx);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
return RETURN_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t MAX_NUM_TCS>
|
||||||
|
inline void Service11TelecommandScheduling<MAX_NUM_TCS>::debugPrintMultimapContent() const {
|
||||||
|
#if FSFW_DISABLE_PRINTOUT == 0
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::debug << "Service11TelecommandScheduling::debugPrintMultimapContent: Multimap Content"
|
||||||
|
<< std::endl;
|
||||||
|
#else
|
||||||
|
sif::printDebug("Service11TelecommandScheduling::debugPrintMultimapContent: Multimap Content\n");
|
||||||
|
#endif
|
||||||
|
for (const auto &dit : telecommandMap) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::debug << "[" << dit.first << "]: Request ID: " << dit.second.requestId << " | "
|
||||||
|
<< "Store Address: " << dit.second.storeAddr.raw << std::endl;
|
||||||
|
#else
|
||||||
|
sif::printDebug("[%d]: Request ID: %d | Store Address: %d\n", dit.first, dit.second.requestId,
|
||||||
|
dit.second.storeAddr);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t MAX_NUM_TCS>
|
||||||
|
inline void Service11TelecommandScheduling<MAX_NUM_TCS>::enableExpiredTcDeletion() {
|
||||||
|
deleteExpiredTcWhenDisabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t MAX_NUM_TCS>
|
||||||
|
inline void Service11TelecommandScheduling<MAX_NUM_TCS>::disableExpiredTcDeletion() {
|
||||||
|
deleteExpiredTcWhenDisabled = false;
|
||||||
|
}
|
@ -85,7 +85,7 @@ ReturnValue_t Service5EventReporting::handleRequest(uint8_t subservice) {
|
|||||||
// In addition to the default PUSServiceBase initialization, this service needs
|
// In addition to the default PUSServiceBase initialization, this service needs
|
||||||
// to be registered to the event manager to listen for events.
|
// to be registered to the event manager to listen for events.
|
||||||
ReturnValue_t Service5EventReporting::initialize() {
|
ReturnValue_t Service5EventReporting::initialize() {
|
||||||
EventManagerIF* manager = ObjectManager::instance()->get<EventManagerIF>(objects::EVENT_MANAGER);
|
auto* manager = ObjectManager::instance()->get<EventManagerIF>(objects::EVENT_MANAGER);
|
||||||
if (manager == nullptr) {
|
if (manager == nullptr) {
|
||||||
return RETURN_FAILED;
|
return RETURN_FAILED;
|
||||||
}
|
}
|
||||||
|
@ -72,6 +72,7 @@ enum : uint8_t {
|
|||||||
DLE_ENCODER, // DLEE
|
DLE_ENCODER, // DLEE
|
||||||
PUS_SERVICE_3, // PUS3
|
PUS_SERVICE_3, // PUS3
|
||||||
PUS_SERVICE_9, // PUS9
|
PUS_SERVICE_9, // PUS9
|
||||||
|
PUS_SERVICE_11, // PUS11
|
||||||
FILE_SYSTEM, // FILS
|
FILE_SYSTEM, // FILS
|
||||||
LINUX_OSAL, // UXOS
|
LINUX_OSAL, // UXOS
|
||||||
HAL_SPI, // HSPI
|
HAL_SPI, // HSPI
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,2 +1,3 @@
|
|||||||
target_sources(${LIB_FSFW_NAME} PRIVATE FixedSequenceSlot.cpp
|
target_sources(
|
||||||
FixedSlotSequence.cpp)
|
${LIB_FSFW_NAME} PRIVATE FixedSequenceSlot.cpp FixedSlotSequence.cpp
|
||||||
|
PeriodicTaskBase.cpp FixedTimeslotTaskBase.cpp)
|
||||||
|
@ -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,6 +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(); }
|
||||||
|
@ -30,12 +30,12 @@ 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.
|
||||||
*/
|
*/
|
||||||
FixedSlotSequence(uint32_t setLengthMs);
|
explicit FixedSlotSequence(uint32_t setLengthMs);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The destructor of the FixedSlotSequence object.
|
* @brief The destructor of the FixedSlotSequence object.
|
||||||
@ -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,7 +157,9 @@ class FixedSlotSequence {
|
|||||||
* executing task!
|
* executing task!
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
ReturnValue_t intializeSequenceAfterTaskCreation() const;
|
[[nodiscard]] ReturnValue_t intializeSequenceAfterTaskCreation() const;
|
||||||
|
|
||||||
|
[[nodiscard]] bool isEmpty() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
@ -173,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;
|
||||||
};
|
};
|
||||||
|
27
src/fsfw/tasks/FixedTimeslotTaskBase.cpp
Normal file
27
src/fsfw/tasks/FixedTimeslotTaskBase.cpp
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#include "FixedTimeslotTaskBase.h"
|
||||||
|
|
||||||
|
#include "fsfw/objectmanager/ObjectManager.h"
|
||||||
|
|
||||||
|
FixedTimeslotTaskBase::FixedTimeslotTaskBase(TaskPeriod period_,
|
||||||
|
TaskDeadlineMissedFunction dlmFunc_)
|
||||||
|
: period(period_), pollingSeqTable(getPeriodMs()), dlmFunc(dlmFunc_) {}
|
||||||
|
uint32_t FixedTimeslotTaskBase::getPeriodMs() const { return static_cast<uint32_t>(period * 1000); }
|
||||||
|
|
||||||
|
bool FixedTimeslotTaskBase::isEmpty() const { return pollingSeqTable.isEmpty(); }
|
||||||
|
|
||||||
|
ReturnValue_t FixedTimeslotTaskBase::checkSequence() { return pollingSeqTable.checkSequence(); }
|
||||||
|
|
||||||
|
ReturnValue_t FixedTimeslotTaskBase::addSlot(object_id_t execId, ExecutableObjectIF* execObj,
|
||||||
|
uint32_t slotTimeMs, int8_t executionStep) {
|
||||||
|
if (execObj == nullptr) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::error << "Component 0x" << std::hex << std::setw(8) << std::setfill('0') << execObj
|
||||||
|
<< std::setfill(' ') << " not found, not adding it to PST" << std::dec << std::endl;
|
||||||
|
#else
|
||||||
|
sif::printError("Component 0x%08x not found, not adding it to PST\n");
|
||||||
|
#endif
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
pollingSeqTable.addSlot(execId, slotTimeMs, executionStep, execObj, this);
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
44
src/fsfw/tasks/FixedTimeslotTaskBase.h
Normal file
44
src/fsfw/tasks/FixedTimeslotTaskBase.h
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#ifndef FSFW_EXAMPLE_HOSTED_FIXEDTIMESLOTTASKBASE_H
|
||||||
|
#define FSFW_EXAMPLE_HOSTED_FIXEDTIMESLOTTASKBASE_H
|
||||||
|
|
||||||
|
#include "FixedSlotSequence.h"
|
||||||
|
#include "FixedTimeslotTaskIF.h"
|
||||||
|
#include "definitions.h"
|
||||||
|
|
||||||
|
class FixedTimeslotTaskBase : public FixedTimeslotTaskIF {
|
||||||
|
public:
|
||||||
|
explicit FixedTimeslotTaskBase(TaskPeriod period, TaskDeadlineMissedFunction dlmFunc = nullptr);
|
||||||
|
~FixedTimeslotTaskBase() override = default;
|
||||||
|
;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* @brief Period of task in floating point seconds
|
||||||
|
*/
|
||||||
|
TaskPeriod period;
|
||||||
|
|
||||||
|
//! Polling sequence table which contains the object to execute
|
||||||
|
//! and information like the timeslots and the passed execution step.
|
||||||
|
FixedSlotSequence pollingSeqTable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The pointer to the deadline-missed function.
|
||||||
|
* @details
|
||||||
|
* This pointer stores the function that is executed if the task's deadline
|
||||||
|
* is missed. So, each may react individually on a timing failure.
|
||||||
|
* The pointer may be NULL, then nothing happens on missing the deadline.
|
||||||
|
* The deadline is equal to the next execution of the periodic task.
|
||||||
|
*/
|
||||||
|
TaskDeadlineMissedFunction dlmFunc = nullptr;
|
||||||
|
|
||||||
|
ReturnValue_t checkSequence() override;
|
||||||
|
|
||||||
|
[[nodiscard]] uint32_t getPeriodMs() const override;
|
||||||
|
|
||||||
|
[[nodiscard]] bool isEmpty() const override;
|
||||||
|
|
||||||
|
ReturnValue_t addSlot(object_id_t execId, ExecutableObjectIF* componentId, uint32_t slotTimeMs,
|
||||||
|
int8_t executionStep) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // FSFW_EXAMPLE_HOSTED_FIXEDTIMESLOTTASKBASE_H
|
@ -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"
|
||||||
|
|
||||||
@ -11,10 +12,23 @@
|
|||||||
*/
|
*/
|
||||||
class FixedTimeslotTaskIF : public PeriodicTaskIF {
|
class FixedTimeslotTaskIF : public PeriodicTaskIF {
|
||||||
public:
|
public:
|
||||||
virtual ~FixedTimeslotTaskIF() {}
|
~FixedTimeslotTaskIF() override = default;
|
||||||
|
|
||||||
static constexpr ReturnValue_t SLOT_LIST_EMPTY =
|
static constexpr ReturnValue_t SLOT_LIST_EMPTY =
|
||||||
HasReturnvaluesIF::makeReturnCode(CLASS_ID::FIXED_SLOT_TASK_IF, 0);
|
HasReturnvaluesIF::makeReturnCode(CLASS_ID::FIXED_SLOT_TASK_IF, 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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() const = 0;
|
virtual ReturnValue_t checkSequence() = 0;
|
||||||
|
|
||||||
|
ReturnValue_t addComponent(object_id_t object, uint8_t opCode) override {
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t addComponent(ExecutableObjectIF* object, uint8_t opCode) override {
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* FRAMEWORK_TASKS_FIXEDTIMESLOTTASKIF_H_ */
|
#endif /* FRAMEWORK_TASKS_FIXEDTIMESLOTTASKIF_H_ */
|
||||||
|
71
src/fsfw/tasks/PeriodicTaskBase.cpp
Normal file
71
src/fsfw/tasks/PeriodicTaskBase.cpp
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
#include "PeriodicTaskBase.h"
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
#include "fsfw/objectmanager/ObjectManager.h"
|
||||||
|
#include "fsfw/serviceinterface.h"
|
||||||
|
|
||||||
|
PeriodicTaskBase::PeriodicTaskBase(TaskPeriod period_, TaskDeadlineMissedFunction dlmFunc_)
|
||||||
|
: period(period_), dlmFunc(dlmFunc_) {
|
||||||
|
// Hints at configuration error
|
||||||
|
if (PeriodicTaskBase::getPeriodMs() <= 1) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::warning << "Passed task period 0 or smaller than 1 ms" << std::endl;
|
||||||
|
#else
|
||||||
|
sif::printWarning("Passed task period 0 or smaller than 1ms\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t PeriodicTaskBase::getPeriodMs() const { return static_cast<uint32_t>(period * 1000); }
|
||||||
|
|
||||||
|
bool PeriodicTaskBase::isEmpty() const { return objectList.empty(); }
|
||||||
|
|
||||||
|
ReturnValue_t PeriodicTaskBase::addComponent(object_id_t object) { return addComponent(object, 0); }
|
||||||
|
|
||||||
|
ReturnValue_t PeriodicTaskBase::addComponent(ExecutableObjectIF* object) {
|
||||||
|
return addComponent(object, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t PeriodicTaskBase::initObjsAfterTaskCreation() {
|
||||||
|
std::set<ExecutableObjectIF*> uniqueObjects;
|
||||||
|
ReturnValue_t status = HasReturnvaluesIF::RETURN_OK;
|
||||||
|
uint32_t count = 0;
|
||||||
|
for (const auto& obj : objectList) {
|
||||||
|
// Ensure that each unique object is initialized once.
|
||||||
|
if (uniqueObjects.find(obj.first) == uniqueObjects.end()) {
|
||||||
|
ReturnValue_t result = obj.first->initializeAfterTaskCreation();
|
||||||
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
count++;
|
||||||
|
status = result;
|
||||||
|
}
|
||||||
|
uniqueObjects.emplace(obj.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (count > 0) {
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t PeriodicTaskBase::addComponent(object_id_t object, uint8_t opCode) {
|
||||||
|
auto* newObject = ObjectManager::instance()->get<ExecutableObjectIF>(object);
|
||||||
|
return addComponent(newObject, opCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t PeriodicTaskBase::addComponent(ExecutableObjectIF* object, uint8_t opCode) {
|
||||||
|
if (object == nullptr) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::error << "PeriodicTask::addComponent: Invalid object. Make sure"
|
||||||
|
<< " it implements ExecutableObjectIF!" << std::endl;
|
||||||
|
#else
|
||||||
|
sif::printError(
|
||||||
|
"PeriodicTask::addComponent: Invalid object. Make sure it "
|
||||||
|
"implements ExecutableObjectIF!\n");
|
||||||
|
#endif
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
objectList.push_back({object, opCode});
|
||||||
|
object->setTaskIF(this);
|
||||||
|
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
54
src/fsfw/tasks/PeriodicTaskBase.h
Normal file
54
src/fsfw/tasks/PeriodicTaskBase.h
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#ifndef FSFW_SRC_FSFW_TASKS_PERIODICTASKBASE_H_
|
||||||
|
#define FSFW_SRC_FSFW_TASKS_PERIODICTASKBASE_H_
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "fsfw/tasks/PeriodicTaskIF.h"
|
||||||
|
#include "fsfw/tasks/definitions.h"
|
||||||
|
|
||||||
|
class ExecutableObjectIF;
|
||||||
|
|
||||||
|
class PeriodicTaskBase : public PeriodicTaskIF {
|
||||||
|
public:
|
||||||
|
explicit PeriodicTaskBase(TaskPeriod period,
|
||||||
|
TaskDeadlineMissedFunction deadlineMissedFunc = nullptr);
|
||||||
|
|
||||||
|
ReturnValue_t addComponent(object_id_t object, uint8_t opCode) override;
|
||||||
|
ReturnValue_t addComponent(ExecutableObjectIF* object, uint8_t opCode) override;
|
||||||
|
|
||||||
|
ReturnValue_t addComponent(object_id_t object) override;
|
||||||
|
ReturnValue_t addComponent(ExecutableObjectIF* object) override;
|
||||||
|
|
||||||
|
[[nodiscard]] uint32_t getPeriodMs() const override;
|
||||||
|
|
||||||
|
[[nodiscard]] bool isEmpty() const override;
|
||||||
|
|
||||||
|
ReturnValue_t initObjsAfterTaskCreation();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
//! Typedef for the List of objects. Will contain the objects to execute and their respective
|
||||||
|
//! operation codes
|
||||||
|
using ObjectList = std::vector<std::pair<ExecutableObjectIF*, uint8_t>>;
|
||||||
|
/**
|
||||||
|
* @brief This attribute holds a list of objects to be executed.
|
||||||
|
*/
|
||||||
|
ObjectList objectList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Period of task in floating point seconds
|
||||||
|
*/
|
||||||
|
TaskPeriod period;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The pointer to the deadline-missed function.
|
||||||
|
* @details
|
||||||
|
* This pointer stores the function that is executed if the task's deadline
|
||||||
|
* is missed. So, each may react individually on a timing failure.
|
||||||
|
* The pointer may be NULL, then nothing happens on missing the deadline.
|
||||||
|
* The deadline is equal to the next execution of the periodic task.
|
||||||
|
*/
|
||||||
|
TaskDeadlineMissedFunction dlmFunc = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* FSFW_SRC_FSFW_TASKS_PERIODICTASKBASE_H_ */
|
@ -3,9 +3,8 @@
|
|||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
|
||||||
#include "../objectmanager/SystemObjectIF.h"
|
#include "fsfw/objectmanager/SystemObjectIF.h"
|
||||||
#include "../timemanager/Clock.h"
|
#include "fsfw/tasks/ExecutableObjectIF.h"
|
||||||
class ExecutableObjectIF;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* New version of TaskIF
|
* New version of TaskIF
|
||||||
@ -18,7 +17,7 @@ class PeriodicTaskIF {
|
|||||||
/**
|
/**
|
||||||
* @brief A virtual destructor as it is mandatory for interfaces.
|
* @brief A virtual destructor as it is mandatory for interfaces.
|
||||||
*/
|
*/
|
||||||
virtual ~PeriodicTaskIF() {}
|
virtual ~PeriodicTaskIF() = default;
|
||||||
/**
|
/**
|
||||||
* @brief With the startTask method, a created task can be started
|
* @brief With the startTask method, a created task can be started
|
||||||
* for the first time.
|
* for the first time.
|
||||||
@ -26,28 +25,29 @@ class PeriodicTaskIF {
|
|||||||
virtual ReturnValue_t startTask() = 0;
|
virtual ReturnValue_t startTask() = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a component (object) to a periodic task.
|
* Adds an object to the list of objects to be executed.
|
||||||
* @param object
|
* The objects are executed in the order added. The object needs to implement
|
||||||
* Add an object to the task. The object needs to implement ExecutableObjectIF
|
* ExecutableObjectIF
|
||||||
* @return
|
* @param object Id of the object to add.
|
||||||
|
* @return RETURN_OK on success, RETURN_FAILED if the object could not be added.
|
||||||
*/
|
*/
|
||||||
virtual ReturnValue_t addComponent(object_id_t object) {
|
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); };
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add an object to a periodic task.
|
* Adds an object to the list of objects to be executed.
|
||||||
* @param object
|
* The objects are executed in the order added.
|
||||||
* Add an object to the task.
|
* @param object pointer to the object to add.
|
||||||
* @return
|
* @return RETURN_OK on success, RETURN_FAILED if the object could not be added.
|
||||||
*/
|
*/
|
||||||
virtual ReturnValue_t addComponent(ExecutableObjectIF* object) {
|
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;
|
||||||
|
|
||||||
|
[[nodiscard]] virtual bool isEmpty() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* PERIODICTASKIF_H_ */
|
#endif /* FRAMEWORK_TASK_PERIODICTASKIF_H_ */
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
#include "FixedTimeslotTaskIF.h"
|
#include "FixedTimeslotTaskIF.h"
|
||||||
#include "Typedef.h"
|
#include "definitions.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Singleton Class that produces Tasks.
|
* Singleton Class that produces Tasks.
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
#ifndef FSFW_TASKS_TYPEDEF_H_
|
|
||||||
#define FSFW_TASKS_TYPEDEF_H_
|
|
||||||
|
|
||||||
#include <cstddef>
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
typedef const char* TaskName;
|
|
||||||
typedef uint32_t TaskPriority;
|
|
||||||
typedef size_t TaskStackSize;
|
|
||||||
typedef double TaskPeriod;
|
|
||||||
typedef void (*TaskDeadlineMissedFunction)();
|
|
||||||
|
|
||||||
#endif /* FSFW_TASKS_TYPEDEF_H_ */
|
|
13
src/fsfw/tasks/definitions.h
Normal file
13
src/fsfw/tasks/definitions.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#ifndef FSFW_TASKS_TYPEDEF_H_
|
||||||
|
#define FSFW_TASKS_TYPEDEF_H_
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
using TaskName = const char*;
|
||||||
|
using TaskPriority = int;
|
||||||
|
using TaskStackSize = size_t;
|
||||||
|
using TaskPeriod = double;
|
||||||
|
using TaskDeadlineMissedFunction = void (*)();
|
||||||
|
|
||||||
|
#endif /* FSFW_TASKS_TYPEDEF_H_ */
|
@ -9,7 +9,7 @@
|
|||||||
CCSDSDistributor::CCSDSDistributor(uint16_t setDefaultApid, object_id_t setObjectId)
|
CCSDSDistributor::CCSDSDistributor(uint16_t setDefaultApid, object_id_t setObjectId)
|
||||||
: TcDistributor(setObjectId), defaultApid(setDefaultApid) {}
|
: TcDistributor(setObjectId), defaultApid(setDefaultApid) {}
|
||||||
|
|
||||||
CCSDSDistributor::~CCSDSDistributor() {}
|
CCSDSDistributor::~CCSDSDistributor() = default;
|
||||||
|
|
||||||
TcDistributor::TcMqMapIter CCSDSDistributor::selectDestination() {
|
TcDistributor::TcMqMapIter CCSDSDistributor::selectDestination() {
|
||||||
#if CCSDS_DISTRIBUTOR_DEBUGGING == 1
|
#if CCSDS_DISTRIBUTOR_DEBUGGING == 1
|
||||||
@ -38,6 +38,7 @@ TcDistributor::TcMqMapIter CCSDSDistributor::selectDestination() {
|
|||||||
" store failed!\n");
|
" store failed!\n");
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
return queueMap.end();
|
||||||
}
|
}
|
||||||
SpacePacketBase currentPacket(packet);
|
SpacePacketBase currentPacket(packet);
|
||||||
|
|
||||||
@ -45,7 +46,7 @@ TcDistributor::TcMqMapIter CCSDSDistributor::selectDestination() {
|
|||||||
sif::info << "CCSDSDistributor::selectDestination has packet with APID " << std::hex
|
sif::info << "CCSDSDistributor::selectDestination has packet with APID " << std::hex
|
||||||
<< currentPacket.getAPID() << std::dec << std::endl;
|
<< currentPacket.getAPID() << std::dec << std::endl;
|
||||||
#endif
|
#endif
|
||||||
TcMqMapIter position = this->queueMap.find(currentPacket.getAPID());
|
auto position = this->queueMap.find(currentPacket.getAPID());
|
||||||
if (position != this->queueMap.end()) {
|
if (position != this->queueMap.end()) {
|
||||||
return position;
|
return position;
|
||||||
} else {
|
} else {
|
||||||
|
@ -15,7 +15,7 @@ PUSDistributor::PUSDistributor(uint16_t setApid, object_id_t setObjectId,
|
|||||||
tcStatus(RETURN_FAILED),
|
tcStatus(RETURN_FAILED),
|
||||||
packetSource(setPacketSource) {}
|
packetSource(setPacketSource) {}
|
||||||
|
|
||||||
PUSDistributor::~PUSDistributor() {}
|
PUSDistributor::~PUSDistributor() = default;
|
||||||
|
|
||||||
PUSDistributor::TcMqMapIter PUSDistributor::selectDestination() {
|
PUSDistributor::TcMqMapIter PUSDistributor::selectDestination() {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1 && PUS_DISTRIBUTOR_DEBUGGING == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1 && PUS_DISTRIBUTOR_DEBUGGING == 1
|
||||||
@ -23,7 +23,7 @@ PUSDistributor::TcMqMapIter PUSDistributor::selectDestination() {
|
|||||||
sif::debug << "PUSDistributor::handlePacket received: " << storeId.poolIndex << ", "
|
sif::debug << "PUSDistributor::handlePacket received: " << storeId.poolIndex << ", "
|
||||||
<< storeId.packetIndex << std::endl;
|
<< storeId.packetIndex << std::endl;
|
||||||
#endif
|
#endif
|
||||||
TcMqMapIter queueMapIt = this->queueMap.end();
|
auto queueMapIt = this->queueMap.end();
|
||||||
if (this->currentPacket == nullptr) {
|
if (this->currentPacket == nullptr) {
|
||||||
return queueMapIt;
|
return queueMapIt;
|
||||||
}
|
}
|
||||||
@ -48,10 +48,8 @@ PUSDistributor::TcMqMapIter PUSDistributor::selectDestination() {
|
|||||||
sif::warning << "PUSDistributor::handlePacket: Packet format invalid, " << keyword
|
sif::warning << "PUSDistributor::handlePacket: Packet format invalid, " << keyword
|
||||||
<< " error" << std::endl;
|
<< " error" << std::endl;
|
||||||
#else
|
#else
|
||||||
sif::printWarning(
|
sif::printWarning("PUSDistributor::handlePacket: Packet format invalid, %s error\n",
|
||||||
"PUSDistributor::handlePacket: Packet format invalid, "
|
keyword);
|
||||||
"%s error\n",
|
|
||||||
keyword);
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -133,8 +131,7 @@ ReturnValue_t PUSDistributor::initialize() {
|
|||||||
return ObjectManagerIF::CHILD_INIT_FAILED;
|
return ObjectManagerIF::CHILD_INIT_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
CCSDSDistributorIF* ccsdsDistributor =
|
auto* ccsdsDistributor = ObjectManager::instance()->get<CCSDSDistributorIF>(packetSource);
|
||||||
ObjectManager::instance()->get<CCSDSDistributorIF>(packetSource);
|
|
||||||
if (ccsdsDistributor == nullptr) {
|
if (ccsdsDistributor == nullptr) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::error << "PUSDistributor::initialize: Packet source invalid" << std::endl;
|
sif::error << "PUSDistributor::initialize: Packet source invalid" << std::endl;
|
||||||
|
@ -6,20 +6,20 @@
|
|||||||
#include "fsfw/objectmanager/frameworkObjects.h"
|
#include "fsfw/objectmanager/frameworkObjects.h"
|
||||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||||
|
|
||||||
StorageManagerIF* TcPacketStoredBase::store = nullptr;
|
StorageManagerIF* TcPacketStoredBase::STORE = nullptr;
|
||||||
|
|
||||||
TcPacketStoredBase::TcPacketStoredBase() {
|
TcPacketStoredBase::TcPacketStoredBase() {
|
||||||
this->storeAddress.raw = StorageManagerIF::INVALID_ADDRESS;
|
this->storeAddress.raw = StorageManagerIF::INVALID_ADDRESS;
|
||||||
this->checkAndSetStore();
|
TcPacketStoredBase::checkAndSetStore();
|
||||||
}
|
}
|
||||||
|
|
||||||
TcPacketStoredBase::~TcPacketStoredBase() {}
|
TcPacketStoredBase::~TcPacketStoredBase() = default;
|
||||||
|
|
||||||
ReturnValue_t TcPacketStoredBase::getData(const uint8_t** dataPtr, size_t* dataSize) {
|
ReturnValue_t TcPacketStoredBase::getData(const uint8_t** dataPtr, size_t* dataSize) {
|
||||||
auto result = this->store->getData(storeAddress, dataPtr, dataSize);
|
auto result = TcPacketStoredBase::STORE->getData(storeAddress, dataPtr, dataSize);
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::warning << "TcPacketStoredBase: Could not get data!" << std::endl;
|
sif::warning << "TcPacketStoredBase: Could not get data" << std::endl;
|
||||||
#else
|
#else
|
||||||
sif::printWarning("TcPacketStoredBase: Could not get data!\n");
|
sif::printWarning("TcPacketStoredBase: Could not get data!\n");
|
||||||
#endif
|
#endif
|
||||||
@ -28,11 +28,13 @@ ReturnValue_t TcPacketStoredBase::getData(const uint8_t** dataPtr, size_t* dataS
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool TcPacketStoredBase::checkAndSetStore() {
|
bool TcPacketStoredBase::checkAndSetStore() {
|
||||||
if (this->store == nullptr) {
|
if (TcPacketStoredBase::STORE == nullptr) {
|
||||||
this->store = ObjectManager::instance()->get<StorageManagerIF>(objects::TC_STORE);
|
TcPacketStoredBase::STORE = ObjectManager::instance()->get<StorageManagerIF>(objects::TC_STORE);
|
||||||
if (this->store == nullptr) {
|
if (TcPacketStoredBase::STORE == nullptr) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::error << "TcPacketStoredBase::TcPacketStoredBase: TC Store not found!" << std::endl;
|
sif::error << "TcPacketStoredBase::TcPacketStoredBase: TC Store not found" << std::endl;
|
||||||
|
#else
|
||||||
|
sif::printError("TcPacketStoredBase::TcPacketStoredBase: TC Store not found\n");
|
||||||
#endif
|
#endif
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -47,7 +49,7 @@ void TcPacketStoredBase::setStoreAddress(store_address_t setAddress,
|
|||||||
size_t tempSize;
|
size_t tempSize;
|
||||||
ReturnValue_t status = StorageManagerIF::RETURN_FAILED;
|
ReturnValue_t status = StorageManagerIF::RETURN_FAILED;
|
||||||
if (this->checkAndSetStore()) {
|
if (this->checkAndSetStore()) {
|
||||||
status = this->store->getData(this->storeAddress, &tempData, &tempSize);
|
status = TcPacketStoredBase::STORE->getData(this->storeAddress, &tempData, &tempSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status == StorageManagerIF::RETURN_OK) {
|
if (status == StorageManagerIF::RETURN_OK) {
|
||||||
|
@ -65,7 +65,7 @@ class TcPacketStoredBase : public TcPacketStoredIF {
|
|||||||
* call tries to set it and throws an error message in case of failures.
|
* call tries to set it and throws an error message in case of failures.
|
||||||
* The default store is objects::TC_STORE.
|
* The default store is objects::TC_STORE.
|
||||||
*/
|
*/
|
||||||
static StorageManagerIF* store;
|
static StorageManagerIF* STORE;
|
||||||
/**
|
/**
|
||||||
* The address where the packet data of the object instance is stored.
|
* The address where the packet data of the object instance is stored.
|
||||||
*/
|
*/
|
||||||
@ -77,7 +77,7 @@ class TcPacketStoredBase : public TcPacketStoredIF {
|
|||||||
* @return @li @c true if the store is linked or could be created.
|
* @return @li @c true if the store is linked or could be created.
|
||||||
* @li @c false otherwise.
|
* @li @c false otherwise.
|
||||||
*/
|
*/
|
||||||
bool checkAndSetStore();
|
static bool checkAndSetStore();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* TMTCPACKET_PUS_TcPacketStoredBase_H_ */
|
#endif /* TMTCPACKET_PUS_TCPACKETSTORED_H_ */
|
||||||
|
@ -9,7 +9,8 @@
|
|||||||
|
|
||||||
class TcPacketStoredIF {
|
class TcPacketStoredIF {
|
||||||
public:
|
public:
|
||||||
virtual ~TcPacketStoredIF(){};
|
virtual ~TcPacketStoredIF() = default;
|
||||||
|
;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* With this call, the stored packet can be set to another packet in a store. This is useful
|
* With this call, the stored packet can be set to another packet in a store. This is useful
|
||||||
|
@ -14,8 +14,8 @@ TcPacketStoredPus::TcPacketStoredPus(uint16_t apid, uint8_t service, uint8_t sub
|
|||||||
}
|
}
|
||||||
uint8_t* pData = nullptr;
|
uint8_t* pData = nullptr;
|
||||||
ReturnValue_t returnValue =
|
ReturnValue_t returnValue =
|
||||||
this->store->getFreeElement(&this->storeAddress, (TC_PACKET_MIN_SIZE + size), &pData);
|
this->STORE->getFreeElement(&this->storeAddress, (TC_PACKET_MIN_SIZE + size), &pData);
|
||||||
if (returnValue != this->store->RETURN_OK) {
|
if (returnValue != this->STORE->RETURN_OK) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::warning << "TcPacketStoredBase: Could not get free element from store!" << std::endl;
|
sif::warning << "TcPacketStoredBase: Could not get free element from store!" << std::endl;
|
||||||
#endif
|
#endif
|
||||||
@ -44,19 +44,19 @@ TcPacketStoredPus::TcPacketStoredPus(const uint8_t* data, size_t size) : TcPacke
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this->checkAndSetStore()) {
|
if (this->checkAndSetStore()) {
|
||||||
ReturnValue_t status = store->addData(&storeAddress, data, size);
|
ReturnValue_t status = STORE->addData(&storeAddress, data, size);
|
||||||
if (status != HasReturnvaluesIF::RETURN_OK) {
|
if (status != HasReturnvaluesIF::RETURN_OK) {
|
||||||
this->setData(nullptr, size);
|
this->setData(nullptr, size);
|
||||||
}
|
}
|
||||||
const uint8_t* storePtr = nullptr;
|
const uint8_t* storePtr = nullptr;
|
||||||
// Repoint base data pointer to the data in the store.
|
// Repoint base data pointer to the data in the store.
|
||||||
store->getData(storeAddress, &storePtr, &size);
|
STORE->getData(storeAddress, &storePtr, &size);
|
||||||
this->setData(const_cast<uint8_t*>(storePtr), size);
|
this->setData(const_cast<uint8_t*>(storePtr), size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t TcPacketStoredPus::deletePacket() {
|
ReturnValue_t TcPacketStoredPus::deletePacket() {
|
||||||
ReturnValue_t result = this->store->deleteData(this->storeAddress);
|
ReturnValue_t result = this->STORE->deleteData(this->storeAddress);
|
||||||
this->storeAddress.raw = StorageManagerIF::INVALID_ADDRESS;
|
this->storeAddress.raw = StorageManagerIF::INVALID_ADDRESS;
|
||||||
// To circumvent size checks
|
// To circumvent size checks
|
||||||
this->setData(nullptr, -1);
|
this->setData(nullptr, -1);
|
||||||
@ -68,7 +68,7 @@ TcPacketPusBase* TcPacketStoredPus::getPacketBase() { return this; }
|
|||||||
bool TcPacketStoredPus::isSizeCorrect() {
|
bool TcPacketStoredPus::isSizeCorrect() {
|
||||||
const uint8_t* temp_data = nullptr;
|
const uint8_t* temp_data = nullptr;
|
||||||
size_t temp_size;
|
size_t temp_size;
|
||||||
ReturnValue_t status = this->store->getData(this->storeAddress, &temp_data, &temp_size);
|
ReturnValue_t status = this->STORE->getData(this->storeAddress, &temp_data, &temp_size);
|
||||||
if (status == StorageManagerIF::RETURN_OK) {
|
if (status == StorageManagerIF::RETURN_OK) {
|
||||||
if (this->getFullSize() == temp_size) {
|
if (this->getFullSize() == temp_size) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#ifndef FRAMEWORK_TMTCSERVICES_ACCEPTSTELECOMMANDSIF_H_
|
#ifndef FRAMEWORK_TMTCSERVICES_ACCEPTSTELECOMMANDSIF_H_
|
||||||
#define FRAMEWORK_TMTCSERVICES_ACCEPTSTELECOMMANDSIF_H_
|
#define FRAMEWORK_TMTCSERVICES_ACCEPTSTELECOMMANDSIF_H_
|
||||||
|
|
||||||
#include "../ipc/MessageQueueSenderIF.h"
|
#include "fsfw/ipc/MessageQueueSenderIF.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This interface is implemented by classes that are sinks for
|
* @brief This interface is implemented by classes that are sinks for
|
||||||
@ -20,7 +20,7 @@ class AcceptsTelecommandsIF {
|
|||||||
/**
|
/**
|
||||||
* @brief The virtual destructor as it is mandatory for C++ interfaces.
|
* @brief The virtual destructor as it is mandatory for C++ interfaces.
|
||||||
*/
|
*/
|
||||||
virtual ~AcceptsTelecommandsIF() {}
|
virtual ~AcceptsTelecommandsIF() = default;
|
||||||
/**
|
/**
|
||||||
* @brief Getter for the service id.
|
* @brief Getter for the service id.
|
||||||
* @details Any receiving service (at least any PUS service) shall have a
|
* @details Any receiving service (at least any PUS service) shall have a
|
||||||
|
@ -12,19 +12,21 @@
|
|||||||
#undef minor
|
#undef minor
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const Version fsfw::FSFW_VERSION = {FSFW_VERSION_MAJOR, FSFW_VERSION_MINOR, FSFW_VERSION_REVISION,
|
const fsfw::Version fsfw::FSFW_VERSION = {FSFW_VERSION_MAJOR, FSFW_VERSION_MINOR,
|
||||||
FSFW_VERSION_CST_GIT_SHA1};
|
FSFW_VERSION_REVISION, FSFW_VCS_INFO};
|
||||||
|
|
||||||
Version::Version(int major, int minor, int revision, const char* addInfo)
|
fsfw::Version::Version(int major, int minor, int revision, const char* addInfo)
|
||||||
: major(major), minor(minor), revision(revision), addInfo(addInfo) {}
|
: major(major), minor(minor), revision(revision), addInfo(addInfo) {}
|
||||||
|
|
||||||
void Version::getVersion(char* str, size_t maxLen) const {
|
void fsfw::Version::getVersion(char* str, size_t maxLen) const {
|
||||||
size_t len = snprintf(str, maxLen, "%d.%d.%d", major, minor, revision);
|
size_t len = snprintf(str, maxLen, "%d.%d.%d", major, minor, revision);
|
||||||
if (addInfo != nullptr) {
|
if (addInfo != nullptr) {
|
||||||
snprintf(str + len, maxLen - len, "-%s", addInfo);
|
snprintf(str + len, maxLen - len, "-%s", addInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace fsfw {
|
||||||
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
std::ostream& operator<<(std::ostream& os, const Version& v) {
|
std::ostream& operator<<(std::ostream& os, const Version& v) {
|
||||||
os << v.major << "." << v.minor << "." << v.revision;
|
os << v.major << "." << v.minor << "." << v.revision;
|
||||||
@ -34,3 +36,5 @@ std::ostream& operator<<(std::ostream& os, const Version& v) {
|
|||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
} // namespace fsfw
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
#endif
|
#endif
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace fsfw {
|
||||||
|
|
||||||
class Version {
|
class Version {
|
||||||
public:
|
public:
|
||||||
Version(int major, int minor, int revision, const char* addInfo = nullptr);
|
Version(int major, int minor, int revision, const char* addInfo = nullptr);
|
||||||
@ -55,8 +57,6 @@ class Version {
|
|||||||
void getVersion(char* str, size_t maxLen) const;
|
void getVersion(char* str, size_t maxLen) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace fsfw {
|
|
||||||
|
|
||||||
extern const Version FSFW_VERSION;
|
extern const Version FSFW_VERSION;
|
||||||
|
|
||||||
} // namespace fsfw
|
} // namespace fsfw
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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();
|
||||||
|
@ -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);
|
||||||
|
@ -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(
|
||||||
@ -115,4 +117,4 @@ TEST_CASE("Internal Error Reporter", "[TestInternalError]") {
|
|||||||
}
|
}
|
||||||
QueueFactory::instance()->deleteMessageQueue(testQueue);
|
QueueFactory::instance()->deleteMessageQueue(testQueue);
|
||||||
QueueFactory::instance()->deleteMessageQueue(hkQueue);
|
QueueFactory::instance()->deleteMessageQueue(hkQueue);
|
||||||
}
|
}
|
||||||
|
@ -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_
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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"
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -10,12 +10,12 @@ TEST_CASE("Version API Tests", "[TestVersionAPI]") {
|
|||||||
// Check that major version is non-zero
|
// Check that major version is non-zero
|
||||||
REQUIRE(fsfw::FSFW_VERSION.major > 0);
|
REQUIRE(fsfw::FSFW_VERSION.major > 0);
|
||||||
uint32_t fsfwMajor = fsfw::FSFW_VERSION.major;
|
uint32_t fsfwMajor = fsfw::FSFW_VERSION.major;
|
||||||
REQUIRE(Version(255, 0, 0) > fsfw::FSFW_VERSION);
|
REQUIRE(fsfw::Version(255, 0, 0) > fsfw::FSFW_VERSION);
|
||||||
REQUIRE(Version(255, 0, 0) >= fsfw::FSFW_VERSION);
|
REQUIRE(fsfw::Version(255, 0, 0) >= fsfw::FSFW_VERSION);
|
||||||
REQUIRE(Version(0, 0, 0) < fsfw::FSFW_VERSION);
|
REQUIRE(fsfw::Version(0, 0, 0) < fsfw::FSFW_VERSION);
|
||||||
REQUIRE(Version(0, 0, 0) <= fsfw::FSFW_VERSION);
|
REQUIRE(fsfw::Version(0, 0, 0) <= fsfw::FSFW_VERSION);
|
||||||
Version v1 = Version(1, 1, 1);
|
auto v1 = fsfw::Version(1, 1, 1);
|
||||||
Version v2 = Version(1, 1, 1);
|
auto v2 = fsfw::Version(1, 1, 1);
|
||||||
REQUIRE(v1 == v2);
|
REQUIRE(v1 == v2);
|
||||||
REQUIRE(not(v1 < v2));
|
REQUIRE(not(v1 < v2));
|
||||||
REQUIRE(not(v1 > v2));
|
REQUIRE(not(v1 > v2));
|
||||||
|
Loading…
Reference in New Issue
Block a user