Compare commits
144 Commits
24ef96d1b8
...
mueller/ex
Author | SHA1 | Date | |
---|---|---|---|
7b767b238a | |||
42ac1af4b2 | |||
1e5ba0212e | |||
ac95e8f250 | |||
1e569128c6 | |||
f35c4049c0 | |||
5d946f5640 | |||
f57bd290d9 | |||
aa4e2d7209 | |||
58cb96ece0 | |||
88cc8c46a1 | |||
377c3325d2 | |||
efb3d982f3 | |||
dd986fefd3 | |||
b38329aa0e | |||
4499c9bf04 | |||
be6a492022 | |||
d45cda93b2 | |||
3448292e8a | |||
c83cc492c0 | |||
ece32f88f4 | |||
46cfe65321 | |||
96eb8fc21f | |||
88fa4f1d9d | |||
736f8d0238 | |||
f1acf8e18b | |||
281f91ec5d | |||
118f1da8dd | |||
8b0508d50a | |||
83de5b4ec1 | |||
fe1c51ae6d | |||
10cc954d27 | |||
73ff9b97db | |||
b0d71597f0 | |||
226f28dc7b | |||
398d04dc50 | |||
80a5ed3c5b | |||
5d5a355110 | |||
6bfdace512 | |||
16e55a98ce | |||
79f17843d8 | |||
e5e163bdbf | |||
4e4820af05 | |||
3332f68ce7 | |||
54feb77770 | |||
1a07864a5f | |||
3e9d6bdbb9 | |||
c295539c79 | |||
cddf16f941 | |||
a3dee05fe3 | |||
8edf4c3c8d | |||
7801c6effe | |||
8cc94a55ab | |||
b62c19a364 | |||
daffb6b666 | |||
7cfb1e6076 | |||
cc36baff78 | |||
4c65109ac0 | |||
861bd15eda | |||
7b979eadff | |||
16714ceb40 | |||
fea301bcc9 | |||
77450eb4b7 | |||
28015c4735 | |||
7d61e67d20 | |||
afcbc8be0a | |||
7a2269262b | |||
9731dc1e61 | |||
bf2e0f2d73 | |||
e98857fab4 | |||
29b0a352fc | |||
8642b13fd1 | |||
6aa72892ed | |||
70f0a72f1b | |||
b5d890eedd | |||
50b1b48678 | |||
0e0dbc74aa | |||
8c34051d8b | |||
b00d83cb1a | |||
17e609c3a5 | |||
64f0166b64 | |||
c80f06fbcb | |||
70eb8325a0 | |||
8e4ad10627 | |||
e796f82203 | |||
5b7ca8c13c | |||
031739ef51 | |||
80be937d9d | |||
d62ee6a611 | |||
b8516b15cb | |||
4032228005 | |||
ac5a54b5da | |||
29015b340b | |||
64274acbeb | |||
ff98c42514 | |||
126ac52975 | |||
70d3197212 | |||
dd90980520 | |||
352ab43c1f | |||
07f5dbb9ac | |||
97e98eae24 | |||
afce942bf8 | |||
a1d7a56dfa | |||
cb78fefbb3 | |||
c55925959b | |||
4f0669c574 | |||
f0d996ffd2 | |||
f4d05c2c9c | |||
d1151ca707 | |||
82f46992f6 | |||
9947a648df | |||
95f018a0b0 | |||
8c2105ae0a | |||
ed2c2af4a0 | |||
82df132e7d | |||
a02619e5a2 | |||
a011e70665 | |||
b2252bdc0b | |||
fcb6437388 | |||
a3930dafc5 | |||
4f9797af3b | |||
1a530633ca | |||
8037e8074b | |||
d07e0e5576 | |||
5525466b52 | |||
c2a89bf709 | |||
8dd0b2608d | |||
05495077ec | |||
8ff9eadf30 | |||
082c86ea18 | |||
2800d6f28c | |||
b4effe7a46 | |||
e6e71436c2 | |||
a887f852c8 | |||
0b3255e463 | |||
631a531212 | |||
665d8cd479 | |||
10398855a9 | |||
d0fec93dc3 | |||
59ab54b2fb | |||
7095999bd2 | |||
7ffb4107d2 | |||
9ce59d3c75 | |||
a0dfdfab2c |
33
CHANGELOG.md
33
CHANGELOG.md
@ -12,6 +12,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
|
|
||||||
## Changes
|
## Changes
|
||||||
|
|
||||||
|
- Bump C++ required version to C++17. Every project which uses the FSFW and every modern
|
||||||
|
compiler supports it
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/622
|
||||||
- HAL Linux SPI: Set the Clock Default State when setting new SPI speed
|
- HAL Linux SPI: Set the Clock Default State when setting new SPI speed
|
||||||
and mode
|
and mode
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/573
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/573
|
||||||
@ -26,10 +29,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/585
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/585
|
||||||
- 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
|
||||||
|
- Add helper functions provided by [`cmake-modules`](https://github.com/rpavlik/cmake-modules)
|
||||||
|
manually now. Those should not change too often and only a small subset is needed
|
||||||
|
- Separate folder for easier update and for distinction
|
||||||
- LICENSE file included
|
- LICENSE file included
|
||||||
- use `int` for version numbers to allow unset or uninitialized version
|
- use `int` for version numbers to allow unset or uninitialized version
|
||||||
- Initialize Version object with numbers set to -1
|
- Initialize Version object with numbers set to -1
|
||||||
@ -38,6 +43,18 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
versions since the last tag
|
versions since the last tag
|
||||||
- Additional information is set to the last part of the git describe output for `FSFW_VERSION` now.
|
- Additional information is set to the last part of the git describe output for `FSFW_VERSION` now.
|
||||||
- Version still need to be hand-updated if the FSFW is not included as a submodule for now.
|
- Version still need to be hand-updated if the FSFW is not included as a submodule for now.
|
||||||
|
- CMake will auto-generate a file named `versionAutogen.cpp` on each rebuild which contains
|
||||||
|
the version retrieved with git
|
||||||
|
- IPC Message Queue Handling: Allow passing an optional `MqArgs` argument into the MessageQueue
|
||||||
|
creation call. It allows passing context information and an arbitrary user argument into
|
||||||
|
the message queue. Also streamlined and simplified `MessageQueue` implementation for all OSALs
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/583
|
||||||
|
- Clock:
|
||||||
|
- `timeval` to `TimeOfDay_t`
|
||||||
|
- Added Mutex for gmtime calls: (compare http://www.opengate.at/blog/2020/01/timeless/)
|
||||||
|
- Moved the statics used by Clock in ClockCommon.cpp to this file
|
||||||
|
- Better check for leap seconds
|
||||||
|
- Added Unittests for Clock (only getter)
|
||||||
|
|
||||||
## Removed
|
## Removed
|
||||||
|
|
||||||
@ -51,11 +68,25 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
- 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 ETL dependency and improved library dependency management
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/592
|
||||||
|
- `Subsystem`: New API to add table and sequence entries
|
||||||
|
|
||||||
## Fixed
|
## Fixed
|
||||||
|
|
||||||
|
- TCP TMTC Server: `MutexGuard` was not created properly in
|
||||||
|
`TcpTmTcServer::handleTmSending(socket_t connSocket, bool& tmSent)` call.
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/618
|
||||||
|
- Fix infinite recursion in `prepareHealthSetReply` of PUS Health Service 201.
|
||||||
|
Is not currently used right now but might be used in the future
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/617
|
||||||
|
- Move some CMake directives further up top so they are not ignored
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/621
|
||||||
- Small bugfix in STM32 HAL for SPI
|
- Small bugfix in STM32 HAL for SPI
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/599
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/599
|
||||||
|
- HAL GPIO: Improved error checking in `LinuxLibgpioIF::configureGpios(...)`. If a GPIO
|
||||||
|
configuration fails, the function will exit prematurely with a dedicated error code
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/602
|
||||||
|
|
||||||
# [v4.0.0]
|
# [v4.0.0]
|
||||||
|
|
||||||
|
185
CMakeLists.txt
185
CMakeLists.txt
@ -1,13 +1,85 @@
|
|||||||
cmake_minimum_required(VERSION 3.13)
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
|
||||||
set(FSFW_VERSION_IF_GIT_FAILS 4)
|
set(MSG_PREFIX "fsfw |")
|
||||||
set(FSFW_SUBVERSION_IF_GIT_FAILS 0)
|
|
||||||
set(FSFW_REVISION_IF_GIT_FAILS 0)
|
|
||||||
|
|
||||||
# Add the cmake folder so the FindSphinx module is found
|
# Add the cmake folder so the FindSphinx module is found
|
||||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake-modules")
|
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake-modules/bilke")
|
||||||
set(MSG_PREFIX "fsfw |")
|
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake-modules/rpavlik")
|
||||||
|
|
||||||
|
##########################
|
||||||
|
# Version file handling #
|
||||||
|
##########################
|
||||||
|
|
||||||
|
set(FSFW_VERSION_MAJOR_IF_GIT_FAILS 4)
|
||||||
|
set(FSFW_VERSION_MINOR_IF_GIT_FAILS 0)
|
||||||
|
set(FSFW_VERSION_REVISION_IF_GIT_FAILS 0)
|
||||||
|
|
||||||
|
set(FSFW_GIT_VER_HANDLING_OK FALSE)
|
||||||
|
# Check whether we got any revision (which isn't
|
||||||
|
# always the case, e.g. when someone downloaded a zip
|
||||||
|
# file from Github instead of a checkout)
|
||||||
|
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" FORCE)
|
||||||
|
list(GET FSFW_GIT_INFO 1 FSFW_VERSION_MAJOR)
|
||||||
|
list(GET FSFW_GIT_INFO 2 FSFW_VERSION_MINOR)
|
||||||
|
list(GET FSFW_GIT_INFO 3 FSFW_VERSION_REVISION)
|
||||||
|
list(GET FSFW_GIT_INFO 4 FSFW_VERSION_VCS_INFO)
|
||||||
|
if(NOT FSFW_VERSION_MAJOR)
|
||||||
|
set(FSFW_VERSION_MAJOR ${FSFW_VERSION_MAJOR_IF_GIT_FAILS})
|
||||||
|
endif()
|
||||||
|
if(NOT FSFW_VERSION_MINOR)
|
||||||
|
set(FSFW_VERSION_MINOR ${FSFW_VERSION_MINOR_IF_GIT_FAILS})
|
||||||
|
endif()
|
||||||
|
if(NOT FSFW_VERSION_REVISION)
|
||||||
|
set(FSFW_VERSION_REVISION ${FSFW_VERSION_REVISION_IF_GIT_FAILS})
|
||||||
|
endif()
|
||||||
|
set(FSFW_GIT_VER_HANDLING_OK TRUE)
|
||||||
|
else()
|
||||||
|
set(FSFW_GIT_VER_HANDLING_OK FALSE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT FSFW_GIT_VER_HANDLING_OK)
|
||||||
|
set(FSFW_VERSION_MAJOR ${FSFW_VERSION_MAJOR_IF_GIT_FAILS})
|
||||||
|
set(FSFW_VERSION_MINOR ${FSFW_VERSION_MINOR_IF_GIT_FAILS})
|
||||||
|
set(FSFW_VERSION_REVISION ${FSFW_VERSION_REVISION_IF_GIT_FAILS})
|
||||||
|
set(GIT_REV "N/A")
|
||||||
|
set(GIT_DIFF "")
|
||||||
|
set(GIT_BRANCH "N/A")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
set(LIB_FSFW_NAME fsfw)
|
||||||
|
project(${LIB_FSFW_NAME} VERSION ${FSFW_VERSION_MAJOR}.${FSFW_VERSION_MINOR}.${FSFW_VERSION_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_MAJOR_VERSION 20 CACHE STRING
|
||||||
|
"ETL library major version requirement"
|
||||||
|
)
|
||||||
|
set(FSFW_ETL_LIB_VERSION ${FSFW_ETL_LIB_MAJOR_VERSION}.27.3 CACHE STRING
|
||||||
|
"ETL library exact version requirement"
|
||||||
|
)
|
||||||
|
set(FSFW_ETL_LINK_TARGET etl::etl)
|
||||||
|
|
||||||
|
set(FSFW_CATCH2_LIB_MAJOR_VERSION 3 CACHE STRING
|
||||||
|
"Catch2 library major version requirement"
|
||||||
|
)
|
||||||
|
set(FSFW_CATCH2_LIB_VERSION v${FSFW_CATCH2_LIB_MAJOR_VERSION}.0.0-preview5 CACHE STRING
|
||||||
|
"Catch2 library exact version requirement"
|
||||||
|
)
|
||||||
|
|
||||||
|
set(FSFW_ETL_LIB_NAME etl)
|
||||||
|
|
||||||
option(FSFW_GENERATE_SECTIONS
|
option(FSFW_GENERATE_SECTIONS
|
||||||
"Generate function and data sections. Required to remove unused code" ON
|
"Generate function and data sections. Required to remove unused code" ON
|
||||||
@ -40,49 +112,17 @@ option(FSFW_ADD_TMSTORAGE "Compile with tm storage components" OFF)
|
|||||||
# Contrib sources
|
# Contrib sources
|
||||||
option(FSFW_ADD_SGP4_PROPAGATOR "Add SGP4 propagator code" OFF)
|
option(FSFW_ADD_SGP4_PROPAGATOR "Add SGP4 propagator code" OFF)
|
||||||
|
|
||||||
set(LIB_FSFW_NAME fsfw)
|
|
||||||
set(FSFW_TEST_TGT fsfw-tests)
|
set(FSFW_TEST_TGT fsfw-tests)
|
||||||
set(FSFW_DUMMY_TGT fsfw-dummy)
|
set(FSFW_DUMMY_TGT fsfw-dummy)
|
||||||
|
|
||||||
project(${LIB_FSFW_NAME})
|
|
||||||
add_library(${LIB_FSFW_NAME})
|
add_library(${LIB_FSFW_NAME})
|
||||||
|
|
||||||
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(STATUS "${MSG_PREFIX} Building the FSFW unittests in addition to the static library")
|
message(STATUS "${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 3 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(STATUS "${MSG_PREFIX} Catch2 installation not found. Downloading Catch2 library with FetchContent")
|
message(STATUS "${MSG_PREFIX} Catch2 installation not found. Downloading Catch2 library with FetchContent")
|
||||||
@ -91,12 +131,10 @@ if(FSFW_BUILD_UNITTESTS)
|
|||||||
FetchContent_Declare(
|
FetchContent_Declare(
|
||||||
Catch2
|
Catch2
|
||||||
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
|
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
|
||||||
GIT_TAG v3.0.0-preview4
|
GIT_TAG ${FSFW_CATCH2_LIB_VERSION}
|
||||||
)
|
)
|
||||||
|
|
||||||
FetchContent_MakeAvailable(Catch2)
|
list(APPEND FSFW_FETCH_CONTENT_TARGETS Catch2)
|
||||||
#fixes regression -preview4, to be confirmed in later releases
|
|
||||||
set_target_properties(Catch2 PROPERTIES DEBUG_POSTFIX "")
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(FSFW_CONFIG_PATH tests/src/fsfw_tests/unit/testcfg)
|
set(FSFW_CONFIG_PATH tests/src/fsfw_tests/unit/testcfg)
|
||||||
@ -116,6 +154,42 @@ if(FSFW_BUILD_UNITTESTS)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
message(STATUS "${MSG_PREFIX} Finding and/or providing ETL library")
|
||||||
|
|
||||||
|
# Check whether the user has already installed ETL first
|
||||||
|
find_package(${FSFW_ETL_LIB_NAME} ${FSFW_ETL_LIB_MAJOR_VERSION} QUIET)
|
||||||
|
# Not installed, so use FetchContent to download and provide etl
|
||||||
|
if(NOT ${FSFW_ETL_LIB_NAME}_FOUND)
|
||||||
|
message(STATUS
|
||||||
|
"No ETL installation was found with find_package. Installing and providing "
|
||||||
|
"etl with FindPackage"
|
||||||
|
)
|
||||||
|
include(FetchContent)
|
||||||
|
|
||||||
|
FetchContent_Declare(
|
||||||
|
${FSFW_ETL_LIB_NAME}
|
||||||
|
GIT_REPOSITORY https://github.com/ETLCPP/etl
|
||||||
|
GIT_TAG ${FSFW_ETL_LIB_VERSION}
|
||||||
|
)
|
||||||
|
|
||||||
|
list(APPEND FSFW_FETCH_CONTENT_TARGETS ${FSFW_ETL_LIB_NAME})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# The documentation for FetchContent recommends declaring all the dependencies
|
||||||
|
# before making them available. We make all declared dependency available here
|
||||||
|
# after their declaration
|
||||||
|
if(FSFW_FETCH_CONTENT_TARGETS)
|
||||||
|
FetchContent_MakeAvailable(${FSFW_FETCH_CONTENT_TARGETS})
|
||||||
|
if(TARGET ${FSFW_ETL_LIB_NAME})
|
||||||
|
add_library(${FSFW_ETL_LINK_TARGET} ALIAS ${FSFW_ETL_LIB_NAME})
|
||||||
|
endif()
|
||||||
|
if(TARGET Catch2)
|
||||||
|
# Fixes regression -preview4, to be confirmed in later releases
|
||||||
|
# Related GitHub issue: https://github.com/catchorg/Catch2/issues/2417
|
||||||
|
set_target_properties(Catch2 PROPERTIES DEBUG_POSTFIX "")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
set(FSFW_CORE_INC_PATH "inc")
|
set(FSFW_CORE_INC_PATH "inc")
|
||||||
|
|
||||||
set_property(CACHE FSFW_OSAL PROPERTY STRINGS host linux rtems freertos)
|
set_property(CACHE FSFW_OSAL PROPERTY STRINGS host linux rtems freertos)
|
||||||
@ -128,13 +202,6 @@ target_include_directories(${LIB_FSFW_NAME} INTERFACE
|
|||||||
${CMAKE_CURRENT_BINARY_DIR}
|
${CMAKE_CURRENT_BINARY_DIR}
|
||||||
)
|
)
|
||||||
|
|
||||||
if(NOT CMAKE_CXX_STANDARD)
|
|
||||||
set(CMAKE_CXX_STANDARD 11)
|
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
|
||||||
elseif(${CMAKE_CXX_STANDARD} LESS 11)
|
|
||||||
message(FATAL_ERROR "${MSG_PREFIX} Compiling the FSFW requires a minimum of C++11 support")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Backwards comptability
|
# Backwards comptability
|
||||||
if(OS_FSFW AND NOT FSFW_OSAL)
|
if(OS_FSFW AND NOT FSFW_OSAL)
|
||||||
message(WARNING "${MSG_PREFIX} 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")
|
||||||
@ -183,7 +250,7 @@ else()
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
configure_file(src/fsfw/FSFW.h.in fsfw/FSFW.h)
|
configure_file(src/fsfw/FSFW.h.in fsfw/FSFW.h)
|
||||||
configure_file(src/fsfw/FSFWVersion.h.in fsfw/FSFWVersion.h)
|
# configure_file(src/fsfw/FSFWVersion.h.in fsfw/FSFWVersion.h)
|
||||||
|
|
||||||
message(STATUS "${MSG_PREFIX} Compiling FSFW for the ${FSFW_OS_NAME} operating system")
|
message(STATUS "${MSG_PREFIX} Compiling FSFW for the ${FSFW_OS_NAME} operating system")
|
||||||
|
|
||||||
@ -377,6 +444,7 @@ target_compile_options(${LIB_FSFW_NAME} PRIVATE
|
|||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
|
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
|
||||||
|
${FSFW_ETL_LINK_TARGET}
|
||||||
${FSFW_ADDITIONAL_LINK_LIBS}
|
${FSFW_ADDITIONAL_LINK_LIBS}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -392,3 +460,18 @@ add_custom_command(
|
|||||||
POST_BUILD
|
POST_BUILD
|
||||||
COMMENT ${POST_BUILD_COMMENT}
|
COMMENT ${POST_BUILD_COMMENT}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Add a custom command that produces version.cpp, plus
|
||||||
|
# a dummy output that's not actually produced, in order
|
||||||
|
# to force version.cmake to always be re-run before the build
|
||||||
|
add_custom_command(
|
||||||
|
TARGET ${LIB_FSFW_NAME}
|
||||||
|
COMMAND ${CMAKE_COMMAND} -DVERSION_DIR=${FSFW_SOURCES_DIR}
|
||||||
|
-DVERSION_MAJOR=${FSFW_VERSION_MAJOR}
|
||||||
|
-DVERSION_MINOR=${FSFW_VERSION_MINOR}
|
||||||
|
-DVERSION_REVISION=${FSFW_VERSION_REVISION}
|
||||||
|
-DVERSION_VCS_INFO=${FSFW_VERSION_VCS_INFO}
|
||||||
|
-P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/version.cmake
|
||||||
|
BYPRODUCTS ${FSFW_SOURCES_DIR}/versionAutogen.cpp
|
||||||
|
COMMENT ""
|
||||||
|
)
|
||||||
|
45
README.md
45
README.md
@ -11,9 +11,15 @@ with Airbus Defence and Space GmbH.
|
|||||||
|
|
||||||
## Quick facts
|
## Quick facts
|
||||||
|
|
||||||
The framework is designed for systems, which communicate with external devices, perform control loops, receive telecommands and send telemetry, and need to maintain a high level of availability. Therefore, a mode and health system provides control over the states of the software and the controlled devices. In addition, a simple mechanism of event based fault detection, isolation and recovery is implemented as well.
|
The framework is designed for systems, which communicate with external devices, perform control loops,
|
||||||
|
receive telecommands and send telemetry, and need to maintain a high level of availability. Therefore,
|
||||||
|
a mode and health system provides control over the states of the software and the controlled devices.
|
||||||
|
In addition, a simple mechanism of event based fault detection, isolation and recovery is implemented as well.
|
||||||
|
|
||||||
The FSFW provides abstraction layers for operating systems to provide a uniform operating system abstraction layer (OSAL). Some components of this OSAL are required internally by the FSFW but is also very useful for developers to implement the same application logic on different operating systems with a uniform interface.
|
The FSFW provides abstraction layers for operating systems to provide a uniform operating system
|
||||||
|
abstraction layer (OSAL). Some components of this OSAL are required internally by the FSFW but is
|
||||||
|
also very useful for developers to implement the same application logic on different operating
|
||||||
|
systems with a uniform interface.
|
||||||
|
|
||||||
Currently, the FSFW provides the following OSALs:
|
Currently, the FSFW provides the following OSALs:
|
||||||
|
|
||||||
@ -45,6 +51,28 @@ A template configuration folder was provided and can be copied into the project
|
|||||||
a starting point. The [configuration section](docs/README-config.md#top) provides more specific
|
a starting point. The [configuration section](docs/README-config.md#top) provides more specific
|
||||||
information about the possible options.
|
information about the possible options.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
The Embedded Template Library (etl) is a dependency of the FSFW which is automatically
|
||||||
|
installed and provided by the build system unless the correction version was installed.
|
||||||
|
The current recommended version can be found inside the fsfw `CMakeLists.txt` file or by using
|
||||||
|
`ccmake` and looking up the `FSFW_ETL_LIB_MAJOR_VERSION` variable.
|
||||||
|
|
||||||
|
You can install the ETL library like this. On Linux, it might be necessary to add `sudo` before
|
||||||
|
the install call:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
git clone https://github.com/ETLCPP/etl
|
||||||
|
cd etl
|
||||||
|
git checkout <currentRecommendedVersion>
|
||||||
|
mkdir build && cd build
|
||||||
|
cmake ..
|
||||||
|
cmake --install .
|
||||||
|
```
|
||||||
|
|
||||||
|
It is recommended to install `20.27.2` or newer for the package version handling of
|
||||||
|
ETL to work.
|
||||||
|
|
||||||
## Adding the library
|
## Adding the library
|
||||||
|
|
||||||
The following steps show how to add and use FSFW components. It is still recommended to
|
The following steps show how to add and use FSFW components. It is still recommended to
|
||||||
@ -83,6 +111,19 @@ The FSFW also has unittests which use the [Catch2 library](https://github.com/ca
|
|||||||
These are built by setting the CMake option `FSFW_BUILD_UNITTESTS` to `ON` or `TRUE`
|
These are built by setting the CMake option `FSFW_BUILD_UNITTESTS` to `ON` or `TRUE`
|
||||||
from your project `CMakeLists.txt` file or from the command line.
|
from your project `CMakeLists.txt` file or from the command line.
|
||||||
|
|
||||||
|
You can install the Catch2 library, which prevents the build system to avoid re-downloading
|
||||||
|
the dependency if the unit tests are completely rebuilt. The current recommended version
|
||||||
|
can be found inside the fsfw `CMakeLists.txt` file or by using `ccmake` and looking up
|
||||||
|
the `FSFW_CATCH2_LIB_VERSION` variable.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git clone https://github.com/catchorg/Catch2.git
|
||||||
|
cd Catch2
|
||||||
|
git checkout <currentRecommendedVersion>
|
||||||
|
cmake -Bbuild -H. -DBUILD_TESTING=OFF
|
||||||
|
sudo cmake --build build/ --target install
|
||||||
|
```
|
||||||
|
|
||||||
The fsfw-tests binary will be built as part of the static library and dropped alongside it.
|
The fsfw-tests binary will be built as part of the static library and dropped alongside it.
|
||||||
If the unittests are built, the library and the tests will be built with coverage information by
|
If the unittests are built, the library and the tests will be built with coverage information by
|
||||||
default. This can be disabled by setting the `FSFW_TESTS_COV_GEN` option to `OFF` or `FALSE`.
|
default. This can be disabled by setting the `FSFW_TESTS_COV_GEN` option to `OFF` or `FALSE`.
|
||||||
|
@ -6,3 +6,9 @@ RUN apt-get --yes upgrade
|
|||||||
#tzdata is a dependency, won't install otherwise
|
#tzdata is a dependency, won't install otherwise
|
||||||
ARG DEBIAN_FRONTEND=noninteractive
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
RUN apt-get --yes install gcc g++ cmake make lcov git valgrind nano iputils-ping
|
RUN apt-get --yes install gcc g++ cmake make lcov git valgrind nano iputils-ping
|
||||||
|
|
||||||
|
RUN git clone https://github.com/catchorg/Catch2.git && \
|
||||||
|
cd Catch2 && \
|
||||||
|
git checkout v3.0.0-preview5 && \
|
||||||
|
cmake -Bbuild -H. -DBUILD_TESTING=OFF && \
|
||||||
|
cmake --build build/ --target install
|
||||||
|
2
automation/Jenkinsfile
vendored
2
automation/Jenkinsfile
vendored
@ -3,7 +3,7 @@ pipeline {
|
|||||||
BUILDDIR = 'build-tests'
|
BUILDDIR = 'build-tests'
|
||||||
}
|
}
|
||||||
agent {
|
agent {
|
||||||
docker { image 'fsfw-ci:d1'}
|
docker { image 'fsfw-ci:d2'}
|
||||||
}
|
}
|
||||||
stages {
|
stages {
|
||||||
stage('Clean') {
|
stage('Clean') {
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
function(determine_version_with_git)
|
function(determine_version_with_git)
|
||||||
include(GetGitRevisionDescription)
|
include(GetGitRevisionDescription)
|
||||||
git_describe(VERSION ${ARGN})
|
git_describe(VERSION ${ARGN})
|
||||||
|
get_git_head_revision(GIT_BRANCH HASH_VAR)
|
||||||
string(FIND ${VERSION} "." VALID_VERSION)
|
string(FIND ${VERSION} "." VALID_VERSION)
|
||||||
if(VALID_VERSION EQUAL -1)
|
if(VALID_VERSION EQUAL -1)
|
||||||
message(WARNING "Version string ${VERSION} retrieved with git describe is invalid")
|
message(WARNING "Version string ${VERSION} retrieved with git describe is invalid")
|
||||||
@ -18,11 +19,14 @@ function(determine_version_with_git)
|
|||||||
string(REGEX REPLACE "^v[0-9]+\\.([0-9]+).*" "\\1" _VERSION_MINOR "${VERSION}")
|
string(REGEX REPLACE "^v[0-9]+\\.([0-9]+).*" "\\1" _VERSION_MINOR "${VERSION}")
|
||||||
string(REGEX REPLACE "^v[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" _VERSION_PATCH "${VERSION}")
|
string(REGEX REPLACE "^v[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" _VERSION_PATCH "${VERSION}")
|
||||||
string(REGEX REPLACE "^v[0-9]+\\.[0-9]+\\.[0-9]+-(.*)" "\\1" VERSION_SHA1 "${VERSION}")
|
string(REGEX REPLACE "^v[0-9]+\\.[0-9]+\\.[0-9]+-(.*)" "\\1" VERSION_SHA1 "${VERSION}")
|
||||||
|
string(STRIP "${GIT_BRANCH}" GIT_BRANCH)
|
||||||
set(GIT_INFO ${VERSION})
|
set(GIT_INFO ${VERSION})
|
||||||
list(APPEND GIT_INFO ${_VERSION_MAJOR})
|
list(APPEND GIT_INFO ${_VERSION_MAJOR})
|
||||||
list(APPEND GIT_INFO ${_VERSION_MINOR})
|
list(APPEND GIT_INFO ${_VERSION_MINOR})
|
||||||
list(APPEND GIT_INFO ${_VERSION_PATCH})
|
list(APPEND GIT_INFO ${_VERSION_PATCH})
|
||||||
list(APPEND GIT_INFO ${VERSION_SHA1})
|
list(APPEND GIT_INFO ${VERSION_SHA1})
|
||||||
set(GIT_INFO ${GIT_INFO} PARENT_SCOPE)
|
set(GIT_INFO ${GIT_INFO} PARENT_SCOPE)
|
||||||
|
set(GIT_BRANCH ${GIT_BRANCH} PARENT_SCOPE)
|
||||||
|
message(STATUS "${MSG_PREFIX} git branch ${GIT_BRANCH}")
|
||||||
message(STATUS "${MSG_PREFIX} Set git version info into GIT_INFO from the git tag ${VERSION}")
|
message(STATUS "${MSG_PREFIX} Set git version info into GIT_INFO from the git tag ${VERSION}")
|
||||||
endfunction()
|
endfunction()
|
||||||
|
@ -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()
|
@ -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)
|
||||||
|
|
||||||
@ -23,9 +25,12 @@ if(HEAD_CONTENTS MATCHES "ref")
|
|||||||
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
|
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.
|
38
cmake/version.cmake
Normal file
38
cmake/version.cmake
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
if(NOT DEFINED VERSION_MAJOR)
|
||||||
|
message(WARNING "version.cmake | No VERSION_MAJOR variable passed. Setting to 0")
|
||||||
|
set(VERSION_MAJOR 0)
|
||||||
|
endif()
|
||||||
|
if(NOT DEFINED VERSION_MINOR)
|
||||||
|
message(WARNING "version.cmake | No VERSION_MINOR variable passed. Setting to 0")
|
||||||
|
set(VERSION_MINOR 0)
|
||||||
|
endif()
|
||||||
|
if(NOT DEFINED VERSION_REVISION)
|
||||||
|
message(WARNING "version.cmake | No VERSION_REVISION variable passed. Setting to 0")
|
||||||
|
set(VERSION_REVISION 0)
|
||||||
|
endif()
|
||||||
|
if(NOT DEFINED VERSION_VCS_INFO)
|
||||||
|
set(VERSION_VCS_INFO "")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(VERSION_TO_SET "#include \"version.h\"
|
||||||
|
|
||||||
|
namespace fsfw {
|
||||||
|
|
||||||
|
const int FSFW_VERSION_MAJOR = ${VERSION_MAJOR};
|
||||||
|
const int FSFW_VERSION_MINOR = ${VERSION_MINOR};
|
||||||
|
const int FSFW_VERSION_REVISION = ${VERSION_MINOR};
|
||||||
|
const char FSFW_VCS_INFO[] = \"${VERSION_VCS_INFO}\";
|
||||||
|
|
||||||
|
};
|
||||||
|
")
|
||||||
|
|
||||||
|
if(EXISTS ${VERSION_DIR}/versionAutogen.cpp)
|
||||||
|
file(READ ${VERSION_DIR}/versionAutogen.cpp OLD_VERSION)
|
||||||
|
else()
|
||||||
|
set(OLD_VERSION "")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (NOT "${VERSION_TO_SET}" STREQUAL "${OLD_VERSION}")
|
||||||
|
message(STATUS "Updating versionAutogen.cpp file")
|
||||||
|
file(WRITE ${VERSION_DIR}/versionAutogen.cpp "${VERSION_TO_SET}")
|
||||||
|
endif()
|
@ -19,6 +19,29 @@ A template configuration folder was provided and can be copied into the project
|
|||||||
a starting point. The [configuration section](docs/README-config.md#top) provides more specific
|
a starting point. The [configuration section](docs/README-config.md#top) provides more specific
|
||||||
information about the possible options.
|
information about the possible options.
|
||||||
|
|
||||||
|
Prerequisites
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
The Embedded Template Library (etl) is a dependency of the FSFW which is automatically
|
||||||
|
installed and provided by the build system unless the correction version was installed.
|
||||||
|
The current recommended version can be found inside the fsfw ``CMakeLists.txt`` file or by using
|
||||||
|
``ccmake`` and looking up the ``FSFW_ETL_LIB_MAJOR_VERSION`` variable.
|
||||||
|
|
||||||
|
You can install the ETL library like this. On Linux, it might be necessary to add ``sudo`` before
|
||||||
|
the install call:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
git clone https://github.com/ETLCPP/etl
|
||||||
|
cd etl
|
||||||
|
git checkout <currentRecommendedVersion>
|
||||||
|
mkdir build && cd build
|
||||||
|
cmake ..
|
||||||
|
cmake --install .
|
||||||
|
|
||||||
|
It is recommended to install ``20.27.2`` or newer for the package version handling of
|
||||||
|
ETL to work.
|
||||||
|
|
||||||
Adding the library
|
Adding the library
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
@ -60,6 +83,20 @@ The FSFW also has unittests which use the `Catch2 library`_.
|
|||||||
These are built by setting the CMake option ``FSFW_BUILD_UNITTESTS`` to ``ON`` or `TRUE`
|
These are built by setting the CMake option ``FSFW_BUILD_UNITTESTS`` to ``ON`` or `TRUE`
|
||||||
from your project `CMakeLists.txt` file or from the command line.
|
from your project `CMakeLists.txt` file or from the command line.
|
||||||
|
|
||||||
|
You can install the Catch2 library, which prevents the build system to avoid re-downloading
|
||||||
|
the dependency if the unit tests are completely rebuilt. The current recommended version
|
||||||
|
can be found inside the fsfw ``CMakeLists.txt`` file or by using ``ccmake`` and looking up
|
||||||
|
the ``FSFW_CATCH2_LIB_VERSION`` variable.
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
git clone https://github.com/catchorg/Catch2.git
|
||||||
|
cd Catch2
|
||||||
|
git checkout <currentRecommendedVersion>
|
||||||
|
cmake -Bbuild -H. -DBUILD_TESTING=OFF
|
||||||
|
sudo cmake --build build/ --target install
|
||||||
|
|
||||||
|
|
||||||
The fsfw-tests binary will be built as part of the static library and dropped alongside it.
|
The fsfw-tests binary will be built as part of the static library and dropped alongside it.
|
||||||
If the unittests are built, the library and the tests will be built with coverage information by
|
If the unittests are built, the library and the tests will be built with coverage information by
|
||||||
default. This can be disabled by setting the `FSFW_TESTS_COV_GEN` option to `OFF` or `FALSE`.
|
default. This can be disabled by setting the `FSFW_TESTS_COV_GEN` option to `OFF` or `FALSE`.
|
||||||
|
@ -12,9 +12,14 @@ if(FSFW_HAL_LINUX_ADD_PERIPHERAL_DRIVERS)
|
|||||||
if(FSFW_HAL_LINUX_ADD_LIBGPIOD)
|
if(FSFW_HAL_LINUX_ADD_LIBGPIOD)
|
||||||
add_subdirectory(gpio)
|
add_subdirectory(gpio)
|
||||||
endif()
|
endif()
|
||||||
add_subdirectory(spi)
|
|
||||||
add_subdirectory(i2c)
|
|
||||||
add_subdirectory(uart)
|
add_subdirectory(uart)
|
||||||
|
# Adding those does not really make sense on Apple systems which
|
||||||
|
# are generally host systems. It won't even compile as the headers
|
||||||
|
# are missing
|
||||||
|
if(NOT APPLE)
|
||||||
|
add_subdirectory(i2c)
|
||||||
|
add_subdirectory(spi)
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_subdirectory(uio)
|
add_subdirectory(uio)
|
||||||
|
@ -44,6 +44,7 @@ ReturnValue_t LinuxLibgpioIF::addGpios(GpioCookie* gpioCookie) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) {
|
ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) {
|
||||||
|
ReturnValue_t result = RETURN_OK;
|
||||||
for (auto& gpioConfig : mapToAdd) {
|
for (auto& gpioConfig : mapToAdd) {
|
||||||
auto& gpioType = gpioConfig.second->gpioType;
|
auto& gpioType = gpioConfig.second->gpioType;
|
||||||
switch (gpioType) {
|
switch (gpioType) {
|
||||||
@ -55,7 +56,7 @@ ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) {
|
|||||||
if (regularGpio == nullptr) {
|
if (regularGpio == nullptr) {
|
||||||
return GPIO_INVALID_INSTANCE;
|
return GPIO_INVALID_INSTANCE;
|
||||||
}
|
}
|
||||||
configureGpioByChip(gpioConfig.first, *regularGpio);
|
result = configureGpioByChip(gpioConfig.first, *regularGpio);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case (gpio::GpioTypes::GPIO_REGULAR_BY_LABEL): {
|
case (gpio::GpioTypes::GPIO_REGULAR_BY_LABEL): {
|
||||||
@ -63,7 +64,7 @@ ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) {
|
|||||||
if (regularGpio == nullptr) {
|
if (regularGpio == nullptr) {
|
||||||
return GPIO_INVALID_INSTANCE;
|
return GPIO_INVALID_INSTANCE;
|
||||||
}
|
}
|
||||||
configureGpioByLabel(gpioConfig.first, *regularGpio);
|
result = configureGpioByLabel(gpioConfig.first, *regularGpio);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case (gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME): {
|
case (gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME): {
|
||||||
@ -71,7 +72,7 @@ ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) {
|
|||||||
if (regularGpio == nullptr) {
|
if (regularGpio == nullptr) {
|
||||||
return GPIO_INVALID_INSTANCE;
|
return GPIO_INVALID_INSTANCE;
|
||||||
}
|
}
|
||||||
configureGpioByLineName(gpioConfig.first, *regularGpio);
|
result = configureGpioByLineName(gpioConfig.first, *regularGpio);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case (gpio::GpioTypes::CALLBACK): {
|
case (gpio::GpioTypes::CALLBACK): {
|
||||||
@ -83,8 +84,11 @@ ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) {
|
|||||||
gpioCallback->initValue, gpioCallback->callbackArgs);
|
gpioCallback->initValue, gpioCallback->callbackArgs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (result != RETURN_OK) {
|
||||||
|
return GPIO_INIT_FAILED;
|
||||||
}
|
}
|
||||||
return RETURN_OK;
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t LinuxLibgpioIF::configureGpioByLabel(gpioId_t gpioId,
|
ReturnValue_t LinuxLibgpioIF::configureGpioByLabel(gpioId_t gpioId,
|
||||||
|
@ -29,6 +29,8 @@ class LinuxLibgpioIF : public GpioIF, public SystemObject {
|
|||||||
HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 4);
|
HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 4);
|
||||||
static constexpr ReturnValue_t GPIO_DUPLICATE_DETECTED =
|
static constexpr ReturnValue_t GPIO_DUPLICATE_DETECTED =
|
||||||
HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 5);
|
HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 5);
|
||||||
|
static constexpr ReturnValue_t GPIO_INIT_FAILED =
|
||||||
|
HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 6);
|
||||||
|
|
||||||
LinuxLibgpioIF(object_id_t objectId);
|
LinuxLibgpioIF(object_id_t objectId);
|
||||||
virtual ~LinuxLibgpioIF();
|
virtual ~LinuxLibgpioIF();
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#include "fsfw_hal/linux/spi/SpiCookie.h"
|
#include "SpiCookie.h"
|
||||||
|
|
||||||
SpiCookie::SpiCookie(address_t spiAddress, gpioId_t chipSelect, std::string spiDev,
|
SpiCookie::SpiCookie(address_t spiAddress, gpioId_t chipSelect, std::string spiDev,
|
||||||
const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed)
|
const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed)
|
||||||
|
@ -265,6 +265,7 @@ void UartComIF::configureBaudrate(struct termios* options, UartCookie* uartCooki
|
|||||||
cfsetispeed(options, B230400);
|
cfsetispeed(options, B230400);
|
||||||
cfsetospeed(options, B230400);
|
cfsetospeed(options, B230400);
|
||||||
break;
|
break;
|
||||||
|
#ifndef __APPLE__
|
||||||
case UartBaudRate::RATE_460800:
|
case UartBaudRate::RATE_460800:
|
||||||
cfsetispeed(options, B460800);
|
cfsetispeed(options, B460800);
|
||||||
cfsetospeed(options, B460800);
|
cfsetospeed(options, B460800);
|
||||||
@ -313,6 +314,7 @@ void UartComIF::configureBaudrate(struct termios* options, UartCookie* uartCooki
|
|||||||
cfsetispeed(options, B4000000);
|
cfsetispeed(options, B4000000);
|
||||||
cfsetospeed(options, B4000000);
|
cfsetospeed(options, B4000000);
|
||||||
break;
|
break;
|
||||||
|
#endif // ! __APPLE__
|
||||||
default:
|
default:
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::warning << "UartComIF::configureBaudrate: Baudrate not supported" << std::endl;
|
sif::warning << "UartComIF::configureBaudrate: Baudrate not supported" << std::endl;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
target_sources(${LIB_FSFW_NAME} PRIVATE
|
||||||
version.cpp
|
version.cpp
|
||||||
|
versionAutogen.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
# Core
|
# Core
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
#ifndef FSFW_VERSION_H_
|
|
||||||
#define FSFW_VERSION_H_
|
|
||||||
|
|
||||||
// Versioning is managed in project CMakeLists.txt file
|
|
||||||
static constexpr int FSFW_VERSION_MAJOR = @FSFW_VERSION@;
|
|
||||||
static constexpr int FSFW_VERSION_MINOR = @FSFW_SUBVERSION@;
|
|
||||||
static constexpr int FSFW_VERSION_REVISION = @FSFW_REVISION@;
|
|
||||||
// Also contains CST (Commits since tag) information
|
|
||||||
static const char FSFW_VERSION_CST_GIT_SHA1[] = "@FSFW_VERSION_CST_GIT_SHA1@";
|
|
||||||
|
|
||||||
#endif /* FSFW_VERSION_H_ */
|
|
@ -44,7 +44,7 @@ class HeaderSerializer : public SerializeIF, public PduHeaderIF {
|
|||||||
cfdp::WidthInBytes getLenEntityIds() const override;
|
cfdp::WidthInBytes getLenEntityIds() const override;
|
||||||
cfdp::WidthInBytes getLenSeqNum() const override;
|
cfdp::WidthInBytes getLenSeqNum() const override;
|
||||||
cfdp::SegmentMetadataFlag getSegmentMetadataFlag() const override;
|
cfdp::SegmentMetadataFlag getSegmentMetadataFlag() const override;
|
||||||
bool hasSegmentMetadataFlag() const;
|
bool hasSegmentMetadataFlag() const override;
|
||||||
void setSegmentationControl(cfdp::SegmentationControl);
|
void setSegmentationControl(cfdp::SegmentationControl);
|
||||||
|
|
||||||
void getSourceId(cfdp::EntityId& sourceId) const override;
|
void getSourceId(cfdp::EntityId& sourceId) const override;
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#define FIXEDARRAYLIST_H_
|
#define FIXEDARRAYLIST_H_
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
#include "ArrayList.h"
|
#include "ArrayList.h"
|
||||||
/**
|
/**
|
||||||
@ -9,10 +10,8 @@
|
|||||||
*/
|
*/
|
||||||
template <typename T, size_t MAX_SIZE, typename count_t = uint8_t>
|
template <typename T, size_t MAX_SIZE, typename count_t = uint8_t>
|
||||||
class FixedArrayList : public ArrayList<T, count_t> {
|
class FixedArrayList : public ArrayList<T, count_t> {
|
||||||
#if !defined(_MSC_VER)
|
static_assert(MAX_SIZE <= std::numeric_limits<count_t>::max(),
|
||||||
static_assert(MAX_SIZE <= (std::pow(2, sizeof(count_t) * 8) - 1),
|
|
||||||
"count_t is not large enough to hold MAX_SIZE");
|
"count_t is not large enough to hold MAX_SIZE");
|
||||||
#endif
|
|
||||||
private:
|
private:
|
||||||
T data[MAX_SIZE];
|
T data[MAX_SIZE];
|
||||||
|
|
||||||
|
@ -10,16 +10,23 @@ class HybridIterator : public LinkedElement<T>::Iterator, public ArrayList<T, co
|
|||||||
HybridIterator() {}
|
HybridIterator() {}
|
||||||
|
|
||||||
HybridIterator(typename LinkedElement<T>::Iterator *iter)
|
HybridIterator(typename LinkedElement<T>::Iterator *iter)
|
||||||
: LinkedElement<T>::Iterator(*iter), value(iter->value), linked(true) {}
|
: LinkedElement<T>::Iterator(*iter), linked(true) {
|
||||||
|
if (iter != nullptr) {
|
||||||
|
value = iter->value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
HybridIterator(LinkedElement<T> *start)
|
HybridIterator(LinkedElement<T> *start) : LinkedElement<T>::Iterator(start), linked(true) {
|
||||||
: LinkedElement<T>::Iterator(start), value(start->value), linked(true) {}
|
if (start != nullptr) {
|
||||||
|
value = start->value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
HybridIterator(typename ArrayList<T, count_t>::Iterator start,
|
HybridIterator(typename ArrayList<T, count_t>::Iterator start,
|
||||||
typename ArrayList<T, count_t>::Iterator end)
|
typename ArrayList<T, count_t>::Iterator end)
|
||||||
: ArrayList<T, count_t>::Iterator(start), value(start.value), linked(false), end(end.value) {
|
: ArrayList<T, count_t>::Iterator(start), value(start.value), linked(false), end(end.value) {
|
||||||
if (value == this->end) {
|
if (value == this->end) {
|
||||||
value = NULL;
|
value = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ class ControllerBase : public HasModesIF,
|
|||||||
virtual void performControlOperation() = 0;
|
virtual void performControlOperation() = 0;
|
||||||
|
|
||||||
virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
|
virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
|
||||||
uint32_t *msToReachTheMode) = 0;
|
uint32_t *msToReachTheMode) override = 0;
|
||||||
|
|
||||||
const object_id_t parentId;
|
const object_id_t parentId;
|
||||||
|
|
||||||
@ -80,9 +80,9 @@ class ControllerBase : public HasModesIF,
|
|||||||
|
|
||||||
/** Mode helpers */
|
/** Mode helpers */
|
||||||
virtual void modeChanged(Mode_t mode, Submode_t submode);
|
virtual void modeChanged(Mode_t mode, Submode_t submode);
|
||||||
virtual void startTransition(Mode_t mode, Submode_t submode);
|
virtual void startTransition(Mode_t mode, Submode_t submode) override;
|
||||||
virtual void getMode(Mode_t *mode, Submode_t *submode);
|
virtual void getMode(Mode_t *mode, Submode_t *submode) override;
|
||||||
virtual void setToExternalControl();
|
virtual void setToExternalControl() override;
|
||||||
virtual void announceMode(bool recursive);
|
virtual void announceMode(bool recursive);
|
||||||
/** HK helpers */
|
/** HK helpers */
|
||||||
virtual void changeHK(Mode_t mode, Submode_t submode, bool enable);
|
virtual void changeHK(Mode_t mode, Submode_t submode, bool enable);
|
||||||
|
@ -109,7 +109,7 @@ class PoolDataSetBase : public PoolDataSetIF, public SerializeIF, public HasRetu
|
|||||||
*/
|
*/
|
||||||
virtual ReturnValue_t unlockDataPool() override;
|
virtual ReturnValue_t unlockDataPool() override;
|
||||||
|
|
||||||
virtual uint16_t getFillCount() const;
|
virtual uint16_t getFillCount() const override;
|
||||||
|
|
||||||
/* SerializeIF implementations */
|
/* SerializeIF implementations */
|
||||||
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, const size_t maxSize,
|
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, const size_t maxSize,
|
||||||
|
@ -94,13 +94,14 @@ ReturnValue_t LocalPoolDataSetBase::serializeWithValidityBuffer(
|
|||||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
||||||
const uint8_t validityMaskSize = std::ceil(static_cast<float>(fillCount) / 8.0);
|
const uint8_t validityMaskSize = std::ceil(static_cast<float>(fillCount) / 8.0);
|
||||||
uint8_t *validityPtr = nullptr;
|
uint8_t *validityPtr = nullptr;
|
||||||
#ifdef _MSC_VER
|
#if defined(_MSC_VER) || defined(__clang__)
|
||||||
/* Use a std::vector here because MSVC will (rightly) not create a fixed size array
|
// Use a std::vector here because MSVC will (rightly) not create a fixed size array
|
||||||
with a non constant size specifier */
|
// with a non constant size specifier. The Apple compiler (LLVM) will not accept
|
||||||
std::vector<uint8_t> validityMask(validityMaskSize);
|
// the initialization of a variable sized array
|
||||||
|
std::vector<uint8_t> validityMask(validityMaskSize, 0);
|
||||||
validityPtr = validityMask.data();
|
validityPtr = validityMask.data();
|
||||||
#else
|
#else
|
||||||
uint8_t validityMask[validityMaskSize] = {0};
|
uint8_t validityMask[validityMaskSize] = {};
|
||||||
validityPtr = validityMask;
|
validityPtr = validityMask;
|
||||||
#endif
|
#endif
|
||||||
uint8_t validBufferIndex = 0;
|
uint8_t validBufferIndex = 0;
|
||||||
|
@ -23,8 +23,8 @@ class LocalPoolObjectBase : public PoolVariableIF, public HasReturnvaluesIF, pub
|
|||||||
LocalPoolObjectBase(object_id_t poolOwner, lp_id_t poolId, DataSetIF* dataSet = nullptr,
|
LocalPoolObjectBase(object_id_t poolOwner, lp_id_t poolId, DataSetIF* dataSet = nullptr,
|
||||||
pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE);
|
pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE);
|
||||||
|
|
||||||
void setReadWriteMode(pool_rwm_t newReadWriteMode);
|
void setReadWriteMode(pool_rwm_t newReadWriteMode) override;
|
||||||
pool_rwm_t getReadWriteMode() const;
|
pool_rwm_t getReadWriteMode() const override;
|
||||||
|
|
||||||
bool isValid() const override;
|
bool isValid() const override;
|
||||||
void setValid(bool valid) override;
|
void setValid(bool valid) override;
|
||||||
|
@ -163,7 +163,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||||||
* @param counter Specifies which Action to perform
|
* @param counter Specifies which Action to perform
|
||||||
* @return RETURN_OK for successful execution
|
* @return RETURN_OK for successful execution
|
||||||
*/
|
*/
|
||||||
virtual ReturnValue_t performOperation(uint8_t counter);
|
virtual ReturnValue_t performOperation(uint8_t counter) override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Initializes the device handler
|
* @brief Initializes the device handler
|
||||||
@ -173,7 +173,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||||||
* Calls fillCommandAndReplyMap().
|
* Calls fillCommandAndReplyMap().
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
virtual ReturnValue_t initialize();
|
virtual ReturnValue_t initialize() override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Intialization steps performed after all tasks have been created.
|
* @brief Intialization steps performed after all tasks have been created.
|
||||||
@ -1058,11 +1058,12 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||||||
* @param parameter1 Optional parameter 1
|
* @param parameter1 Optional parameter 1
|
||||||
* @param parameter2 Optional parameter 2
|
* @param parameter2 Optional parameter 2
|
||||||
*/
|
*/
|
||||||
void triggerEvent(Event event, uint32_t parameter1 = 0, uint32_t parameter2 = 0);
|
void triggerEvent(Event event, uint32_t parameter1 = 0, uint32_t parameter2 = 0) override;
|
||||||
/**
|
/**
|
||||||
* Same as triggerEvent, but for forwarding if object is used as proxy.
|
* Same as triggerEvent, but for forwarding if object is used as proxy.
|
||||||
*/
|
*/
|
||||||
virtual void forwardEvent(Event event, uint32_t parameter1 = 0, uint32_t parameter2 = 0) const;
|
virtual void forwardEvent(Event event, uint32_t parameter1 = 0,
|
||||||
|
uint32_t parameter2 = 0) const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if current mode is transitional mode.
|
* Checks if current mode is transitional mode.
|
||||||
|
@ -25,7 +25,7 @@ class MatchTree : public SerializeableMatcherIF<T>, public BinaryTree<Serializea
|
|||||||
: BinaryTree<SerializeableMatcherIF<T>>(root.element), maxDepth(maxDepth) {}
|
: BinaryTree<SerializeableMatcherIF<T>>(root.element), maxDepth(maxDepth) {}
|
||||||
MatchTree() : BinaryTree<SerializeableMatcherIF<T>>(), maxDepth(-1) {}
|
MatchTree() : BinaryTree<SerializeableMatcherIF<T>>(), maxDepth(-1) {}
|
||||||
virtual ~MatchTree() {}
|
virtual ~MatchTree() {}
|
||||||
virtual bool match(T number) { return matchesTree(number); }
|
virtual bool match(T number) override { return matchesTree(number); }
|
||||||
bool matchesTree(T number) {
|
bool matchesTree(T number) {
|
||||||
iterator iter = this->begin();
|
iterator iter = this->begin();
|
||||||
if (iter == this->end()) {
|
if (iter == this->end()) {
|
||||||
@ -179,6 +179,9 @@ class MatchTree : public SerializeableMatcherIF<T>, public BinaryTree<Serializea
|
|||||||
virtual ReturnValue_t cleanUpElement(iterator position) { return HasReturnvaluesIF::RETURN_OK; }
|
virtual ReturnValue_t cleanUpElement(iterator position) { return HasReturnvaluesIF::RETURN_OK; }
|
||||||
|
|
||||||
bool matchSubtree(iterator iter, T number) {
|
bool matchSubtree(iterator iter, T number) {
|
||||||
|
if (iter == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
bool isMatch = iter->match(number);
|
bool isMatch = iter->match(number);
|
||||||
if (isMatch) {
|
if (isMatch) {
|
||||||
if (iter.left() == this->end()) {
|
if (iter.left() == this->end()) {
|
||||||
|
@ -15,7 +15,7 @@ class RangeMatcher : public SerializeableMatcherIF<T> {
|
|||||||
RangeMatcher(T lowerBound, T upperBound, bool inverted = false)
|
RangeMatcher(T lowerBound, T upperBound, bool inverted = false)
|
||||||
: inverted(inverted), lowerBound(lowerBound), upperBound(upperBound) {}
|
: inverted(inverted), lowerBound(lowerBound), upperBound(upperBound) {}
|
||||||
|
|
||||||
bool match(T input) {
|
bool match(T input) override {
|
||||||
if (inverted) {
|
if (inverted) {
|
||||||
return !doMatch(input);
|
return !doMatch(input);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
target_sources(${LIB_FSFW_NAME}
|
target_sources(${LIB_FSFW_NAME} PRIVATE
|
||||||
PRIVATE
|
|
||||||
CommandMessage.cpp
|
CommandMessage.cpp
|
||||||
CommandMessageCleaner.cpp
|
CommandMessageCleaner.cpp
|
||||||
MessageQueueMessage.cpp
|
MessageQueueMessage.cpp
|
||||||
|
MessageQueueBase.cpp
|
||||||
)
|
)
|
54
src/fsfw/ipc/MessageQueueBase.cpp
Normal file
54
src/fsfw/ipc/MessageQueueBase.cpp
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#include "MessageQueueBase.h"
|
||||||
|
|
||||||
|
MessageQueueBase::MessageQueueBase(MessageQueueId_t id, MessageQueueId_t defaultDest, MqArgs* args)
|
||||||
|
: id(id) {
|
||||||
|
this->defaultDest = defaultDest;
|
||||||
|
if (args != nullptr) {
|
||||||
|
this->args = *args;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageQueueBase::~MessageQueueBase() {}
|
||||||
|
|
||||||
|
ReturnValue_t MessageQueueBase::sendToDefault(MessageQueueMessageIF* message) {
|
||||||
|
return sendToDefaultFrom(message, this->getId(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t MessageQueueBase::reply(MessageQueueMessageIF* message) {
|
||||||
|
if (this->last != MessageQueueIF::NO_QUEUE) {
|
||||||
|
return sendMessageFrom(this->last, message, this->getId());
|
||||||
|
} else {
|
||||||
|
return NO_REPLY_PARTNER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t MessageQueueBase::receiveMessage(MessageQueueMessageIF* message,
|
||||||
|
MessageQueueId_t* receivedFrom) {
|
||||||
|
ReturnValue_t status = this->receiveMessage(message);
|
||||||
|
*receivedFrom = this->last;
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageQueueId_t MessageQueueBase::getLastPartner() const { return last; }
|
||||||
|
|
||||||
|
MessageQueueId_t MessageQueueBase::getId() const { return id; }
|
||||||
|
|
||||||
|
MqArgs& MessageQueueBase::getMqArgs() { return args; }
|
||||||
|
|
||||||
|
void MessageQueueBase::setDefaultDestination(MessageQueueId_t defaultDestination) {
|
||||||
|
this->defaultDest = defaultDestination;
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageQueueId_t MessageQueueBase::getDefaultDestination() const { return defaultDest; }
|
||||||
|
|
||||||
|
bool MessageQueueBase::isDefaultDestinationSet() const { return (defaultDest != NO_QUEUE); }
|
||||||
|
|
||||||
|
ReturnValue_t MessageQueueBase::sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
||||||
|
bool ignoreFault) {
|
||||||
|
return sendMessageFrom(sendTo, message, this->getId(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t MessageQueueBase::sendToDefaultFrom(MessageQueueMessageIF* message,
|
||||||
|
MessageQueueId_t sentFrom, bool ignoreFault) {
|
||||||
|
return sendMessageFrom(defaultDest, message, sentFrom, ignoreFault);
|
||||||
|
}
|
40
src/fsfw/ipc/MessageQueueBase.h
Normal file
40
src/fsfw/ipc/MessageQueueBase.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#ifndef FSFW_SRC_FSFW_IPC_MESSAGEQUEUEBASE_H_
|
||||||
|
#define FSFW_SRC_FSFW_IPC_MESSAGEQUEUEBASE_H_
|
||||||
|
|
||||||
|
#include <fsfw/ipc/MessageQueueIF.h>
|
||||||
|
#include <fsfw/ipc/definitions.h>
|
||||||
|
|
||||||
|
class MessageQueueBase : public MessageQueueIF {
|
||||||
|
public:
|
||||||
|
MessageQueueBase(MessageQueueId_t id, MessageQueueId_t defaultDest, MqArgs* mqArgs);
|
||||||
|
virtual ~MessageQueueBase();
|
||||||
|
|
||||||
|
// Default implementations for MessageQueueIF where possible
|
||||||
|
virtual MessageQueueId_t getLastPartner() const override;
|
||||||
|
virtual MessageQueueId_t getId() const override;
|
||||||
|
virtual MqArgs& getMqArgs() override;
|
||||||
|
virtual void setDefaultDestination(MessageQueueId_t defaultDestination) override;
|
||||||
|
virtual MessageQueueId_t getDefaultDestination() const override;
|
||||||
|
virtual bool isDefaultDestinationSet() const override;
|
||||||
|
virtual ReturnValue_t sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
||||||
|
bool ignoreFault) override;
|
||||||
|
virtual ReturnValue_t sendToDefault(MessageQueueMessageIF* message) override;
|
||||||
|
virtual ReturnValue_t reply(MessageQueueMessageIF* message) override;
|
||||||
|
virtual ReturnValue_t receiveMessage(MessageQueueMessageIF* message,
|
||||||
|
MessageQueueId_t* receivedFrom) override;
|
||||||
|
virtual ReturnValue_t sendToDefaultFrom(MessageQueueMessageIF* message, MessageQueueId_t sentFrom,
|
||||||
|
bool ignoreFault = false) override;
|
||||||
|
|
||||||
|
// OSAL specific, forward the abstract function
|
||||||
|
virtual ReturnValue_t receiveMessage(MessageQueueMessageIF* message) = 0;
|
||||||
|
virtual ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
||||||
|
MessageQueueId_t sentFrom, bool ignoreFault = false) = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
MessageQueueId_t id = MessageQueueIF::NO_QUEUE;
|
||||||
|
MessageQueueId_t last = MessageQueueIF::NO_QUEUE;
|
||||||
|
MessageQueueId_t defaultDest = MessageQueueIF::NO_QUEUE;
|
||||||
|
MqArgs args = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* FSFW_SRC_FSFW_IPC_MESSAGEQUEUEBASE_H_ */
|
@ -1,6 +1,8 @@
|
|||||||
#ifndef FSFW_IPC_MESSAGEQUEUEIF_H_
|
#ifndef FSFW_IPC_MESSAGEQUEUEIF_H_
|
||||||
#define FSFW_IPC_MESSAGEQUEUEIF_H_
|
#define FSFW_IPC_MESSAGEQUEUEIF_H_
|
||||||
|
|
||||||
|
#include <fsfw/ipc/definitions.h>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
#include "../returnvalues/HasReturnvaluesIF.h"
|
#include "../returnvalues/HasReturnvaluesIF.h"
|
||||||
@ -44,8 +46,8 @@ class MessageQueueIF {
|
|||||||
virtual ReturnValue_t reply(MessageQueueMessageIF* message) = 0;
|
virtual ReturnValue_t reply(MessageQueueMessageIF* message) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This function reads available messages from the message queue
|
* @brief This function reads available messages from the message queue and returns the
|
||||||
* and returns the sender.
|
* sender.
|
||||||
* @details
|
* @details
|
||||||
* It works identically to the other receiveMessage call, but in addition
|
* It works identically to the other receiveMessage call, but in addition
|
||||||
* returns the sender's queue id.
|
* returns the sender's queue id.
|
||||||
@ -78,19 +80,16 @@ class MessageQueueIF {
|
|||||||
*/
|
*/
|
||||||
virtual ReturnValue_t flush(uint32_t* count) = 0;
|
virtual ReturnValue_t flush(uint32_t* count) = 0;
|
||||||
/**
|
/**
|
||||||
* @brief This method returns the message queue
|
* @brief This method returns the message queue ID of the last communication partner.
|
||||||
* id of the last communication partner.
|
|
||||||
*/
|
*/
|
||||||
virtual MessageQueueId_t getLastPartner() const = 0;
|
virtual MessageQueueId_t getLastPartner() const = 0;
|
||||||
/**
|
/**
|
||||||
* @brief This method returns the message queue
|
* @brief This method returns the message queue ID of this class's message queue.
|
||||||
* id of this class's message queue.
|
|
||||||
*/
|
*/
|
||||||
virtual MessageQueueId_t getId() const = 0;
|
virtual MessageQueueId_t getId() const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief With the sendMessage call, a queue message
|
* @brief With the sendMessage call, a queue message is sent to a receiving queue.
|
||||||
* is sent to a receiving queue.
|
|
||||||
* @details
|
* @details
|
||||||
* This method takes the message provided, adds the sentFrom information
|
* This method takes the message provided, adds the sentFrom information
|
||||||
* and passes it on to the destination provided with an operating system
|
* and passes it on to the destination provided with an operating system
|
||||||
@ -129,8 +128,7 @@ class MessageQueueIF {
|
|||||||
bool ignoreFault = false) = 0;
|
bool ignoreFault = false) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The sendToDefaultFrom method sends a queue message
|
* @brief The sendToDefaultFrom method sends a queue message to the default destination.
|
||||||
* to the default destination.
|
|
||||||
* @details
|
* @details
|
||||||
* In all other aspects, it works identical to the sendMessage method.
|
* In all other aspects, it works identical to the sendMessage method.
|
||||||
* @param message
|
* @param message
|
||||||
@ -164,6 +162,8 @@ class MessageQueueIF {
|
|||||||
virtual MessageQueueId_t getDefaultDestination() const = 0;
|
virtual MessageQueueId_t getDefaultDestination() const = 0;
|
||||||
|
|
||||||
virtual bool isDefaultDestinationSet() const = 0;
|
virtual bool isDefaultDestinationSet() const = 0;
|
||||||
|
|
||||||
|
virtual MqArgs& getMqArgs() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* FSFW_IPC_MESSAGEQUEUEIF_H_ */
|
#endif /* FSFW_IPC_MESSAGEQUEUEIF_H_ */
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include "MessageQueueIF.h"
|
#include "MessageQueueIF.h"
|
||||||
#include "MessageQueueMessage.h"
|
#include "MessageQueueMessage.h"
|
||||||
|
#include "definitions.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates message queues.
|
* Creates message queues.
|
||||||
@ -22,7 +23,8 @@ class QueueFactory {
|
|||||||
static QueueFactory* instance();
|
static QueueFactory* instance();
|
||||||
|
|
||||||
MessageQueueIF* createMessageQueue(uint32_t messageDepth = 3,
|
MessageQueueIF* createMessageQueue(uint32_t messageDepth = 3,
|
||||||
size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE);
|
size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE,
|
||||||
|
MqArgs* args = nullptr);
|
||||||
|
|
||||||
void deleteMessageQueue(MessageQueueIF* queue);
|
void deleteMessageQueue(MessageQueueIF* queue);
|
||||||
|
|
||||||
|
14
src/fsfw/ipc/definitions.h
Normal file
14
src/fsfw/ipc/definitions.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#ifndef FSFW_SRC_FSFW_IPC_DEFINITIONS_H_
|
||||||
|
#define FSFW_SRC_FSFW_IPC_DEFINITIONS_H_
|
||||||
|
|
||||||
|
#include <fsfw/objectmanager/SystemObjectIF.h>
|
||||||
|
#include <fsfw/objectmanager/frameworkObjects.h>
|
||||||
|
|
||||||
|
struct MqArgs {
|
||||||
|
MqArgs(){};
|
||||||
|
MqArgs(object_id_t objectId, void* args = nullptr) : objectId(objectId), args(args) {}
|
||||||
|
object_id_t objectId = objects::NO_OBJECT;
|
||||||
|
void* args = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* FSFW_SRC_FSFW_IPC_DEFINITIONS_H_ */
|
@ -34,7 +34,7 @@ class MonitoringReportContent : public SerialLinkedListAdapter<SerializeIF> {
|
|||||||
SerializeElement<T> limitValue;
|
SerializeElement<T> limitValue;
|
||||||
SerializeElement<ReturnValue_t> oldState;
|
SerializeElement<ReturnValue_t> oldState;
|
||||||
SerializeElement<ReturnValue_t> newState;
|
SerializeElement<ReturnValue_t> newState;
|
||||||
uint8_t rawTimestamp[TimeStamperIF::MISSION_TIMESTAMP_SIZE];
|
uint8_t rawTimestamp[TimeStamperIF::MISSION_TIMESTAMP_SIZE] = {};
|
||||||
SerializeElement<SerialBufferAdapter<uint8_t>> timestampSerializer;
|
SerializeElement<SerialBufferAdapter<uint8_t>> timestampSerializer;
|
||||||
TimeStamperIF* timeStamper;
|
TimeStamperIF* timeStamper;
|
||||||
MonitoringReportContent()
|
MonitoringReportContent()
|
||||||
@ -46,7 +46,6 @@ class MonitoringReportContent : public SerialLinkedListAdapter<SerializeIF> {
|
|||||||
limitValue(0),
|
limitValue(0),
|
||||||
oldState(0),
|
oldState(0),
|
||||||
newState(0),
|
newState(0),
|
||||||
rawTimestamp({0}),
|
|
||||||
timestampSerializer(rawTimestamp, sizeof(rawTimestamp)),
|
timestampSerializer(rawTimestamp, sizeof(rawTimestamp)),
|
||||||
timeStamper(NULL) {
|
timeStamper(NULL) {
|
||||||
setAllNext();
|
setAllNext();
|
||||||
|
@ -48,9 +48,10 @@ class SystemObject : public SystemObjectIF {
|
|||||||
virtual ~SystemObject();
|
virtual ~SystemObject();
|
||||||
object_id_t getObjectId() const override;
|
object_id_t getObjectId() const override;
|
||||||
virtual ReturnValue_t initialize() override;
|
virtual ReturnValue_t initialize() override;
|
||||||
virtual ReturnValue_t checkObjectConnections();
|
virtual ReturnValue_t checkObjectConnections() override;
|
||||||
|
|
||||||
virtual void forwardEvent(Event event, uint32_t parameter1 = 0, uint32_t parameter2 = 0) const;
|
virtual void forwardEvent(Event event, uint32_t parameter1 = 0,
|
||||||
|
uint32_t parameter2 = 0) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* FSFW_OBJECTMANAGER_SYSTEMOBJECT_H_ */
|
#endif /* FSFW_OBJECTMANAGER_SYSTEMOBJECT_H_ */
|
||||||
|
@ -19,6 +19,8 @@
|
|||||||
#include <ws2tcpip.h>
|
#include <ws2tcpip.h>
|
||||||
#elif defined(PLATFORM_UNIX)
|
#elif defined(PLATFORM_UNIX)
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const std::string TcpTmTcServer::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT;
|
const std::string TcpTmTcServer::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT;
|
||||||
@ -29,7 +31,7 @@ TcpTmTcServer::TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge,
|
|||||||
: SystemObject(objectId),
|
: SystemObject(objectId),
|
||||||
tmtcBridgeId(tmtcTcpBridge),
|
tmtcBridgeId(tmtcTcpBridge),
|
||||||
receptionMode(receptionMode),
|
receptionMode(receptionMode),
|
||||||
tcpConfig(customTcpServerPort),
|
tcpConfig(std::move(customTcpServerPort)),
|
||||||
receptionBuffer(receptionBufferSize),
|
receptionBuffer(receptionBufferSize),
|
||||||
ringBuffer(ringBufferSize, true) {}
|
ringBuffer(ringBufferSize, true) {}
|
||||||
|
|
||||||
@ -103,7 +105,7 @@ ReturnValue_t TcpTmTcServer::initialize() {
|
|||||||
|
|
||||||
TcpTmTcServer::~TcpTmTcServer() { closeSocket(listenerTcpSocket); }
|
TcpTmTcServer::~TcpTmTcServer() { closeSocket(listenerTcpSocket); }
|
||||||
|
|
||||||
ReturnValue_t TcpTmTcServer::performOperation(uint8_t opCode) {
|
[[noreturn]] ReturnValue_t TcpTmTcServer::performOperation(uint8_t opCode) {
|
||||||
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;
|
||||||
@ -138,7 +140,6 @@ ReturnValue_t TcpTmTcServer::performOperation(uint8_t opCode) {
|
|||||||
closeSocket(connSocket);
|
closeSocket(connSocket);
|
||||||
connSocket = 0;
|
connSocket = 0;
|
||||||
}
|
}
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t TcpTmTcServer::initializeAfterTaskCreation() {
|
ReturnValue_t TcpTmTcServer::initializeAfterTaskCreation() {
|
||||||
@ -159,7 +160,7 @@ void TcpTmTcServer::handleServerOperation(socket_t& connSocket) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
int retval = recv(connSocket, reinterpret_cast<char*>(receptionBuffer.data()),
|
ssize_t retval = recv(connSocket, reinterpret_cast<char*>(receptionBuffer.data()),
|
||||||
receptionBuffer.capacity(), tcpConfig.tcpFlags);
|
receptionBuffer.capacity(), tcpConfig.tcpFlags);
|
||||||
if (retval == 0) {
|
if (retval == 0) {
|
||||||
size_t availableReadData = ringBuffer.getAvailableReadData();
|
size_t availableReadData = ringBuffer.getAvailableReadData();
|
||||||
@ -252,17 +253,17 @@ ReturnValue_t TcpTmTcServer::handleTcReception(uint8_t* spacePacket, size_t pack
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string TcpTmTcServer::getTcpPort() const { return tcpConfig.tcpPort; }
|
const std::string& TcpTmTcServer::getTcpPort() const { return tcpConfig.tcpPort; }
|
||||||
|
|
||||||
void TcpTmTcServer::setSpacePacketParsingOptions(std::vector<uint16_t> validPacketIds) {
|
void TcpTmTcServer::setSpacePacketParsingOptions(std::vector<uint16_t> validPacketIds_) {
|
||||||
this->validPacketIds = validPacketIds;
|
this->validPacketIds = std::move(validPacketIds_);
|
||||||
}
|
}
|
||||||
|
|
||||||
TcpTmTcServer::TcpConfig& TcpTmTcServer::getTcpConfigStruct() { return tcpConfig; }
|
TcpTmTcServer::TcpConfig& TcpTmTcServer::getTcpConfigStruct() { return tcpConfig; }
|
||||||
|
|
||||||
ReturnValue_t TcpTmTcServer::handleTmSending(socket_t connSocket, bool& tmSent) {
|
ReturnValue_t TcpTmTcServer::handleTmSending(socket_t connSocket, bool& tmSent) {
|
||||||
// Access to the FIFO is mutex protected because it is filled by the bridge
|
// Access to the FIFO is mutex protected because it is filled by the bridge
|
||||||
MutexGuard(tmtcBridge->mutex, tmtcBridge->timeoutType, tmtcBridge->mutexTimeoutMs);
|
MutexGuard mg(tmtcBridge->mutex, tmtcBridge->timeoutType, tmtcBridge->mutexTimeoutMs);
|
||||||
store_address_t storeId;
|
store_address_t storeId;
|
||||||
while ((not tmtcBridge->tmFifo->empty()) and
|
while ((not tmtcBridge->tmFifo->empty()) and
|
||||||
(tmtcBridge->packetSentCounter < tmtcBridge->sentPacketsPerCycle)) {
|
(tmtcBridge->packetSentCounter < tmtcBridge->sentPacketsPerCycle)) {
|
||||||
@ -283,7 +284,7 @@ ReturnValue_t TcpTmTcServer::handleTmSending(socket_t connSocket, bool& tmSent)
|
|||||||
#endif
|
#endif
|
||||||
arrayprinter::print(storeAccessor.data(), storeAccessor.size());
|
arrayprinter::print(storeAccessor.data(), storeAccessor.size());
|
||||||
}
|
}
|
||||||
int retval = send(connSocket, reinterpret_cast<const char*>(storeAccessor.data()),
|
ssize_t retval = send(connSocket, reinterpret_cast<const char*>(storeAccessor.data()),
|
||||||
storeAccessor.size(), tcpConfig.tcpTmFlags);
|
storeAccessor.size(), tcpConfig.tcpTmFlags);
|
||||||
if (retval == static_cast<int>(storeAccessor.size())) {
|
if (retval == static_cast<int>(storeAccessor.size())) {
|
||||||
// Packet sent, clear FIFO entry
|
// Packet sent, clear FIFO entry
|
||||||
@ -339,6 +340,9 @@ ReturnValue_t TcpTmTcServer::handleTcRingBufferData(size_t availableReadData) {
|
|||||||
size_t foundSize = 0;
|
size_t foundSize = 0;
|
||||||
size_t readLen = 0;
|
size_t readLen = 0;
|
||||||
while (readLen < readAmount) {
|
while (readLen < readAmount) {
|
||||||
|
if(spacePacketParser == nullptr) {
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
result =
|
result =
|
||||||
spacePacketParser->parseSpacePackets(bufPtrPtr, readAmount, startIdx, foundSize, readLen);
|
spacePacketParser->parseSpacePackets(bufPtrPtr, readAmount, startIdx, foundSize, readLen);
|
||||||
switch (result) {
|
switch (result) {
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class TcpTmTcBridge;
|
class TcpTmTcBridge;
|
||||||
@ -44,7 +45,7 @@ class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableOb
|
|||||||
|
|
||||||
struct TcpConfig {
|
struct TcpConfig {
|
||||||
public:
|
public:
|
||||||
TcpConfig(std::string tcpPort) : tcpPort(tcpPort) {}
|
explicit TcpConfig(std::string tcpPort) : tcpPort(std::move(tcpPort)) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Passed to the recv call
|
* Passed to the recv call
|
||||||
@ -84,7 +85,7 @@ class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableOb
|
|||||||
size_t ringBufferSize = RING_BUFFER_SIZE,
|
size_t ringBufferSize = RING_BUFFER_SIZE,
|
||||||
std::string customTcpServerPort = DEFAULT_SERVER_PORT,
|
std::string customTcpServerPort = DEFAULT_SERVER_PORT,
|
||||||
ReceptionModes receptionMode = ReceptionModes::SPACE_PACKETS);
|
ReceptionModes receptionMode = ReceptionModes::SPACE_PACKETS);
|
||||||
virtual ~TcpTmTcServer();
|
~TcpTmTcServer() override;
|
||||||
|
|
||||||
void enableWiretapping(bool enable);
|
void enableWiretapping(bool enable);
|
||||||
|
|
||||||
@ -97,10 +98,10 @@ class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableOb
|
|||||||
void setSpacePacketParsingOptions(std::vector<uint16_t> validPacketIds);
|
void setSpacePacketParsingOptions(std::vector<uint16_t> validPacketIds);
|
||||||
|
|
||||||
ReturnValue_t initialize() override;
|
ReturnValue_t initialize() override;
|
||||||
ReturnValue_t performOperation(uint8_t opCode) override;
|
[[noreturn]] ReturnValue_t performOperation(uint8_t opCode) override;
|
||||||
ReturnValue_t initializeAfterTaskCreation() override;
|
ReturnValue_t initializeAfterTaskCreation() override;
|
||||||
|
|
||||||
std::string getTcpPort() const;
|
[[nodiscard]] const std::string& getTcpPort() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
StorageManagerIF* tcStore = nullptr;
|
StorageManagerIF* tcStore = nullptr;
|
||||||
@ -115,7 +116,7 @@ class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableOb
|
|||||||
|
|
||||||
ReceptionModes receptionMode;
|
ReceptionModes receptionMode;
|
||||||
TcpConfig tcpConfig;
|
TcpConfig tcpConfig;
|
||||||
struct sockaddr tcpAddress;
|
struct sockaddr tcpAddress = {};
|
||||||
socket_t listenerTcpSocket = 0;
|
socket_t listenerTcpSocket = 0;
|
||||||
|
|
||||||
MessageQueueId_t targetTcDestination = MessageQueueIF::NO_QUEUE;
|
MessageQueueId_t targetTcDestination = MessageQueueIF::NO_QUEUE;
|
||||||
|
@ -16,11 +16,13 @@
|
|||||||
//! Debugging preprocessor define.
|
//! Debugging preprocessor define.
|
||||||
#define FSFW_UDP_RECV_WIRETAPPING_ENABLED 0
|
#define FSFW_UDP_RECV_WIRETAPPING_ENABLED 0
|
||||||
|
|
||||||
|
const timeval UdpTcPollingTask::DEFAULT_TIMEOUT = {0, 500000};
|
||||||
|
|
||||||
UdpTcPollingTask::UdpTcPollingTask(object_id_t objectId, object_id_t tmtcUdpBridge,
|
UdpTcPollingTask::UdpTcPollingTask(object_id_t objectId, object_id_t tmtcUdpBridge,
|
||||||
size_t maxRecvSize, double timeoutSeconds)
|
size_t maxRecvSize, double timeoutSeconds)
|
||||||
: SystemObject(objectId), tmtcBridgeId(tmtcUdpBridge) {
|
: SystemObject(objectId), tmtcBridgeId(tmtcUdpBridge) {
|
||||||
if (frameSize > 0) {
|
if (maxRecvSize > 0) {
|
||||||
this->frameSize = frameSize;
|
this->frameSize = maxRecvSize;
|
||||||
} else {
|
} else {
|
||||||
this->frameSize = DEFAULT_MAX_RECV_SIZE;
|
this->frameSize = DEFAULT_MAX_RECV_SIZE;
|
||||||
}
|
}
|
||||||
@ -31,22 +33,20 @@ UdpTcPollingTask::UdpTcPollingTask(object_id_t objectId, object_id_t tmtcUdpBrid
|
|||||||
receptionBuffer.resize(this->frameSize);
|
receptionBuffer.resize(this->frameSize);
|
||||||
|
|
||||||
if (timeoutSeconds == -1) {
|
if (timeoutSeconds == -1) {
|
||||||
receptionTimeout = DEFAULT_TIMEOUT;
|
receptionTimeout = UdpTcPollingTask::DEFAULT_TIMEOUT;
|
||||||
} else {
|
} else {
|
||||||
receptionTimeout = timevalOperations::toTimeval(timeoutSeconds);
|
receptionTimeout = timevalOperations::toTimeval(timeoutSeconds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UdpTcPollingTask::~UdpTcPollingTask() {}
|
[[noreturn]] ReturnValue_t UdpTcPollingTask::performOperation(uint8_t opCode) {
|
||||||
|
|
||||||
ReturnValue_t UdpTcPollingTask::performOperation(uint8_t opCode) {
|
|
||||||
/* Sender Address is cached here. */
|
/* Sender Address is cached here. */
|
||||||
struct sockaddr senderAddress;
|
struct sockaddr senderAddress {};
|
||||||
socklen_t senderAddressSize = sizeof(senderAddress);
|
socklen_t senderAddressSize = sizeof(senderAddress);
|
||||||
|
|
||||||
/* Poll for new UDP datagrams in permanent loop. */
|
/* Poll for new UDP datagrams in permanent loop. */
|
||||||
while (true) {
|
while (true) {
|
||||||
int bytesReceived =
|
ssize_t bytesReceived =
|
||||||
recvfrom(this->serverSocket, reinterpret_cast<char*>(receptionBuffer.data()), frameSize,
|
recvfrom(this->serverSocket, reinterpret_cast<char*>(receptionBuffer.data()), frameSize,
|
||||||
receptionFlags, &senderAddress, &senderAddressSize);
|
receptionFlags, &senderAddress, &senderAddressSize);
|
||||||
if (bytesReceived == SOCKET_ERROR) {
|
if (bytesReceived == SOCKET_ERROR) {
|
||||||
@ -70,7 +70,6 @@ ReturnValue_t UdpTcPollingTask::performOperation(uint8_t opCode) {
|
|||||||
}
|
}
|
||||||
tmtcBridge->checkAndSetClientAddress(senderAddress);
|
tmtcBridge->checkAndSetClientAddress(senderAddress);
|
||||||
}
|
}
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t UdpTcPollingTask::handleSuccessfullTcRead(size_t bytesRead) {
|
ReturnValue_t UdpTcPollingTask::handleSuccessfullTcRead(size_t bytesRead) {
|
||||||
@ -155,7 +154,7 @@ void UdpTcPollingTask::setTimeout(double timeoutSeconds) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#elif defined(PLATFORM_UNIX)
|
#elif defined(PLATFORM_UNIX)
|
||||||
timeval tval;
|
timeval tval{};
|
||||||
tval = timevalOperations::toTimeval(timeoutSeconds);
|
tval = timevalOperations::toTimeval(timeoutSeconds);
|
||||||
int result = setsockopt(serverSocket, SOL_SOCKET, SO_RCVTIMEO, &tval, sizeof(receptionTimeout));
|
int result = setsockopt(serverSocket, SOL_SOCKET, SO_RCVTIMEO, &tval, sizeof(receptionTimeout));
|
||||||
if (result == -1) {
|
if (result == -1) {
|
||||||
|
@ -21,11 +21,11 @@ class UdpTcPollingTask : public TcpIpBase, public SystemObject, public Executabl
|
|||||||
public:
|
public:
|
||||||
static constexpr size_t DEFAULT_MAX_RECV_SIZE = 1500;
|
static constexpr size_t DEFAULT_MAX_RECV_SIZE = 1500;
|
||||||
//! 0.5 default milliseconds timeout for now.
|
//! 0.5 default milliseconds timeout for now.
|
||||||
static constexpr timeval DEFAULT_TIMEOUT = {0, 500};
|
static const timeval DEFAULT_TIMEOUT;
|
||||||
|
|
||||||
UdpTcPollingTask(object_id_t objectId, object_id_t tmtcUdpBridge, size_t maxRecvSize = 0,
|
UdpTcPollingTask(object_id_t objectId, object_id_t tmtcUdpBridge, size_t maxRecvSize = 0,
|
||||||
double timeoutSeconds = -1);
|
double timeoutSeconds = -1);
|
||||||
virtual ~UdpTcPollingTask();
|
~UdpTcPollingTask() override = default;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Turn on optional timeout for UDP polling. In the default mode,
|
* Turn on optional timeout for UDP polling. In the default mode,
|
||||||
@ -34,9 +34,9 @@ class UdpTcPollingTask : public TcpIpBase, public SystemObject, public Executabl
|
|||||||
*/
|
*/
|
||||||
void setTimeout(double timeoutSeconds);
|
void setTimeout(double timeoutSeconds);
|
||||||
|
|
||||||
virtual ReturnValue_t performOperation(uint8_t opCode) override;
|
[[noreturn]] ReturnValue_t performOperation(uint8_t opCode) override;
|
||||||
virtual ReturnValue_t initialize() override;
|
ReturnValue_t initialize() override;
|
||||||
virtual ReturnValue_t initializeAfterTaskCreation() override;
|
ReturnValue_t initializeAfterTaskCreation() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
StorageManagerIF* tcStore = nullptr;
|
StorageManagerIF* tcStore = nullptr;
|
||||||
@ -51,7 +51,7 @@ class UdpTcPollingTask : public TcpIpBase, public SystemObject, public Executabl
|
|||||||
std::vector<uint8_t> receptionBuffer;
|
std::vector<uint8_t> receptionBuffer;
|
||||||
|
|
||||||
size_t frameSize = 0;
|
size_t frameSize = 0;
|
||||||
timeval receptionTimeout;
|
timeval receptionTimeout{};
|
||||||
|
|
||||||
ReturnValue_t handleSuccessfullTcRead(size_t bytesRead);
|
ReturnValue_t handleSuccessfullTcRead(size_t bytesRead);
|
||||||
};
|
};
|
||||||
|
@ -20,13 +20,13 @@
|
|||||||
const std::string UdpTmTcBridge::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT;
|
const std::string UdpTmTcBridge::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT;
|
||||||
|
|
||||||
UdpTmTcBridge::UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination,
|
UdpTmTcBridge::UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination,
|
||||||
std::string udpServerPort, object_id_t tmStoreId,
|
const std::string &udpServerPort_, object_id_t tmStoreId,
|
||||||
object_id_t tcStoreId)
|
object_id_t tcStoreId)
|
||||||
: TmTcBridge(objectId, tcDestination, tmStoreId, tcStoreId) {
|
: TmTcBridge(objectId, tcDestination, tmStoreId, tcStoreId) {
|
||||||
if (udpServerPort == "") {
|
if (udpServerPort_.empty()) {
|
||||||
this->udpServerPort = DEFAULT_SERVER_PORT;
|
udpServerPort = DEFAULT_SERVER_PORT;
|
||||||
} else {
|
} else {
|
||||||
this->udpServerPort = udpServerPort;
|
udpServerPort = udpServerPort_;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex = MutexFactory::instance()->createMutex();
|
mutex = MutexFactory::instance()->createMutex();
|
||||||
@ -117,7 +117,7 @@ ReturnValue_t UdpTmTcBridge::sendTm(const uint8_t *data, size_t dataLen) {
|
|||||||
tcpip::printAddress(&clientAddress);
|
tcpip::printAddress(&clientAddress);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int bytesSent = sendto(serverSocket, reinterpret_cast<const char *>(data), dataLen, flags,
|
ssize_t bytesSent = sendto(serverSocket, reinterpret_cast<const char *>(data), dataLen, flags,
|
||||||
&clientAddress, clientAddressLen);
|
&clientAddress, clientAddressLen);
|
||||||
if (bytesSent == SOCKET_ERROR) {
|
if (bytesSent == SOCKET_ERROR) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
@ -150,7 +150,7 @@ void UdpTmTcBridge::checkAndSetClientAddress(sockaddr &newAddress) {
|
|||||||
clientAddressLen = sizeof(clientAddress);
|
clientAddressLen = sizeof(clientAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UdpTmTcBridge::setMutexProperties(MutexIF::TimeoutType timeoutType, dur_millis_t timeoutMs) {
|
void UdpTmTcBridge::setMutexProperties(MutexIF::TimeoutType timeoutType_, dur_millis_t timeoutMs) {
|
||||||
this->timeoutType = timeoutType;
|
timeoutType = timeoutType_;
|
||||||
this->mutexTimeoutMs = timeoutMs;
|
mutexTimeoutMs = timeoutMs;
|
||||||
}
|
}
|
||||||
|
@ -29,10 +29,10 @@ class UdpTmTcBridge : public TmTcBridge, public TcpIpBase {
|
|||||||
/* The ports chosen here should not be used by any other process. */
|
/* The ports chosen here should not be used by any other process. */
|
||||||
static const std::string DEFAULT_SERVER_PORT;
|
static const std::string DEFAULT_SERVER_PORT;
|
||||||
|
|
||||||
UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination, std::string udpServerPort = "",
|
UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination,
|
||||||
object_id_t tmStoreId = objects::TM_STORE,
|
const std::string& udpServerPort = "", object_id_t tmStoreId = objects::TM_STORE,
|
||||||
object_id_t tcStoreId = objects::TC_STORE);
|
object_id_t tcStoreId = objects::TC_STORE);
|
||||||
virtual ~UdpTmTcBridge();
|
~UdpTmTcBridge() override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set properties of internal mutex.
|
* Set properties of internal mutex.
|
||||||
@ -46,12 +46,12 @@ class UdpTmTcBridge : public TmTcBridge, public TcpIpBase {
|
|||||||
std::string getUdpPort() const;
|
std::string getUdpPort() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual ReturnValue_t sendTm(const uint8_t* data, size_t dataLen) override;
|
ReturnValue_t sendTm(const uint8_t* data, size_t dataLen) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string udpServerPort;
|
std::string udpServerPort;
|
||||||
|
|
||||||
struct sockaddr clientAddress;
|
struct sockaddr clientAddress = {};
|
||||||
socklen_t clientAddressLen = 0;
|
socklen_t clientAddressLen = 0;
|
||||||
|
|
||||||
//! Access to the client address is mutex protected as it is set by another task.
|
//! Access to the client address is mutex protected as it is set by another task.
|
||||||
|
@ -11,9 +11,6 @@
|
|||||||
// TODO sanitize input?
|
// TODO sanitize input?
|
||||||
// TODO much of this code can be reused for tick-only systems
|
// TODO much of this code can be reused for tick-only systems
|
||||||
|
|
||||||
uint16_t Clock::leapSeconds = 0;
|
|
||||||
MutexIF* Clock::timeMutex = nullptr;
|
|
||||||
|
|
||||||
uint32_t Clock::getTicksPerSecond(void) { return 1000; }
|
uint32_t Clock::getTicksPerSecond(void) { return 1000; }
|
||||||
|
|
||||||
ReturnValue_t Clock::setClock(const TimeOfDay_t* time) {
|
ReturnValue_t Clock::setClock(const TimeOfDay_t* time) {
|
||||||
|
@ -4,8 +4,9 @@
|
|||||||
#include "fsfw/osal/freertos/QueueMapManager.h"
|
#include "fsfw/osal/freertos/QueueMapManager.h"
|
||||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||||
|
|
||||||
MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize)
|
MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize, MqArgs* args)
|
||||||
: maxMessageSize(maxMessageSize) {
|
: MessageQueueBase(MessageQueueIF::NO_QUEUE, MessageQueueIF::NO_QUEUE, args),
|
||||||
|
maxMessageSize(maxMessageSize) {
|
||||||
handle = xQueueCreate(messageDepth, maxMessageSize);
|
handle = xQueueCreate(messageDepth, maxMessageSize);
|
||||||
if (handle == nullptr) {
|
if (handle == nullptr) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
@ -15,10 +16,10 @@ MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize)
|
|||||||
#else
|
#else
|
||||||
sif::printError("MessageQueue::MessageQueue: Creation failed\n");
|
sif::printError("MessageQueue::MessageQueue: Creation failed\n");
|
||||||
sif::printError("Specified Message Depth: %d\n", messageDepth);
|
sif::printError("Specified Message Depth: %d\n", messageDepth);
|
||||||
sif::printError("Specified MAximum Message Size: %d\n", maxMessageSize);
|
sif::printError("Specified Maximum Message Size: %d\n", maxMessageSize);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
QueueMapManager::instance()->addMessageQueue(handle, &queueId);
|
QueueMapManager::instance()->addMessageQueue(handle, &id);
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageQueue::~MessageQueue() {
|
MessageQueue::~MessageQueue() {
|
||||||
@ -29,28 +30,6 @@ MessageQueue::~MessageQueue() {
|
|||||||
|
|
||||||
void MessageQueue::switchSystemContext(CallContext callContext) { this->callContext = callContext; }
|
void MessageQueue::switchSystemContext(CallContext callContext) { this->callContext = callContext; }
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
|
||||||
bool ignoreFault) {
|
|
||||||
return sendMessageFrom(sendTo, message, this->getId(), ignoreFault);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessageIF* message) {
|
|
||||||
return sendToDefaultFrom(message, this->getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessageIF* message,
|
|
||||||
MessageQueueId_t sentFrom, bool ignoreFault) {
|
|
||||||
return sendMessageFrom(defaultDestination, message, sentFrom, ignoreFault);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::reply(MessageQueueMessageIF* message) {
|
|
||||||
if (this->lastPartner != MessageQueueIF::NO_QUEUE) {
|
|
||||||
return sendMessageFrom(this->lastPartner, message, this->getId());
|
|
||||||
} else {
|
|
||||||
return NO_REPLY_PARTNER;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
||||||
MessageQueueId_t sentFrom, bool ignoreFault) {
|
MessageQueueId_t sentFrom, bool ignoreFault) {
|
||||||
return sendMessageFromMessageQueue(sendTo, message, sentFrom, ignoreFault, callContext);
|
return sendMessageFromMessageQueue(sendTo, message, sentFrom, ignoreFault, callContext);
|
||||||
@ -72,27 +51,16 @@ ReturnValue_t MessageQueue::handleSendResult(BaseType_t result, bool ignoreFault
|
|||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message,
|
|
||||||
MessageQueueId_t* receivedFrom) {
|
|
||||||
ReturnValue_t status = this->receiveMessage(message);
|
|
||||||
if (status == HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
*receivedFrom = this->lastPartner;
|
|
||||||
}
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
|
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
|
||||||
BaseType_t result = xQueueReceive(handle, reinterpret_cast<void*>(message->getBuffer()), 0);
|
BaseType_t result = xQueueReceive(handle, reinterpret_cast<void*>(message->getBuffer()), 0);
|
||||||
if (result == pdPASS) {
|
if (result == pdPASS) {
|
||||||
this->lastPartner = message->getSender();
|
this->last = message->getSender();
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
} else {
|
} else {
|
||||||
return MessageQueueIF::EMPTY;
|
return MessageQueueIF::EMPTY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageQueueId_t MessageQueue::getLastPartner() const { return lastPartner; }
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::flush(uint32_t* count) {
|
ReturnValue_t MessageQueue::flush(uint32_t* count) {
|
||||||
// TODO FreeRTOS does not support flushing partially
|
// TODO FreeRTOS does not support flushing partially
|
||||||
// Is always successful
|
// Is always successful
|
||||||
@ -100,17 +68,6 @@ ReturnValue_t MessageQueue::flush(uint32_t* count) {
|
|||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageQueueId_t MessageQueue::getId() const { return queueId; }
|
|
||||||
|
|
||||||
void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) {
|
|
||||||
defaultDestinationSet = true;
|
|
||||||
this->defaultDestination = defaultDestination;
|
|
||||||
}
|
|
||||||
|
|
||||||
MessageQueueId_t MessageQueue::getDefaultDestination() const { return defaultDestination; }
|
|
||||||
|
|
||||||
bool MessageQueue::isDefaultDestinationSet() const { return defaultDestinationSet; }
|
|
||||||
|
|
||||||
// static core function to send messages.
|
// static core function to send messages.
|
||||||
ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
|
ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
|
||||||
MessageQueueMessageIF* message,
|
MessageQueueMessageIF* message,
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
#ifndef FSFW_OSAL_FREERTOS_MESSAGEQUEUE_H_
|
#ifndef FSFW_OSAL_FREERTOS_MESSAGEQUEUE_H_
|
||||||
#define FSFW_OSAL_FREERTOS_MESSAGEQUEUE_H_
|
#define FSFW_OSAL_FREERTOS_MESSAGEQUEUE_H_
|
||||||
|
|
||||||
|
#include <fsfw/ipc/MessageQueueBase.h>
|
||||||
|
|
||||||
#include "FreeRTOS.h"
|
#include "FreeRTOS.h"
|
||||||
#include "TaskManagement.h"
|
#include "TaskManagement.h"
|
||||||
#include "fsfw/internalerror/InternalErrorReporterIF.h"
|
#include "fsfw/internalerror/InternalErrorReporterIF.h"
|
||||||
#include "fsfw/ipc/MessageQueueIF.h"
|
#include "fsfw/ipc/MessageQueueIF.h"
|
||||||
#include "fsfw/ipc/MessageQueueMessage.h"
|
#include "fsfw/ipc/MessageQueueMessage.h"
|
||||||
#include "fsfw/ipc/MessageQueueMessageIF.h"
|
#include "fsfw/ipc/MessageQueueMessageIF.h"
|
||||||
|
#include "fsfw/ipc/definitions.h"
|
||||||
#include "queue.h"
|
#include "queue.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -32,7 +35,7 @@
|
|||||||
* @ingroup osal
|
* @ingroup osal
|
||||||
* @ingroup message_queue
|
* @ingroup message_queue
|
||||||
*/
|
*/
|
||||||
class MessageQueue : public MessageQueueIF {
|
class MessageQueue : public MessageQueueBase {
|
||||||
friend class MessageQueueSenderIF;
|
friend class MessageQueueSenderIF;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -53,7 +56,8 @@ class MessageQueue : public MessageQueueIF {
|
|||||||
* This should be left default.
|
* This should be left default.
|
||||||
*/
|
*/
|
||||||
MessageQueue(size_t messageDepth = 3,
|
MessageQueue(size_t messageDepth = 3,
|
||||||
size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE);
|
size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE,
|
||||||
|
MqArgs* args = nullptr);
|
||||||
|
|
||||||
/** Copying message queues forbidden */
|
/** Copying message queues forbidden */
|
||||||
MessageQueue(const MessageQueue&) = delete;
|
MessageQueue(const MessageQueue&) = delete;
|
||||||
@ -73,40 +77,15 @@ class MessageQueue : public MessageQueueIF {
|
|||||||
*/
|
*/
|
||||||
void switchSystemContext(CallContext callContext);
|
void switchSystemContext(CallContext callContext);
|
||||||
|
|
||||||
/** MessageQueueIF implementation */
|
QueueHandle_t getNativeQueueHandle();
|
||||||
ReturnValue_t sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
|
||||||
bool ignoreFault = false) override;
|
|
||||||
|
|
||||||
ReturnValue_t sendToDefault(MessageQueueMessageIF* message) override;
|
// Implement non-generic MessageQueueIF functions not handled by MessageQueueBase
|
||||||
|
|
||||||
ReturnValue_t reply(MessageQueueMessageIF* message) override;
|
|
||||||
virtual ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
virtual ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
||||||
MessageQueueId_t sentFrom = NO_QUEUE,
|
MessageQueueId_t sentFrom = NO_QUEUE,
|
||||||
bool ignoreFault = false) override;
|
bool ignoreFault = false) override;
|
||||||
|
|
||||||
virtual ReturnValue_t sendToDefaultFrom(MessageQueueMessageIF* message,
|
|
||||||
MessageQueueId_t sentFrom = NO_QUEUE,
|
|
||||||
bool ignoreFault = false) override;
|
|
||||||
|
|
||||||
ReturnValue_t receiveMessage(MessageQueueMessageIF* message,
|
|
||||||
MessageQueueId_t* receivedFrom) override;
|
|
||||||
|
|
||||||
ReturnValue_t receiveMessage(MessageQueueMessageIF* message) override;
|
ReturnValue_t receiveMessage(MessageQueueMessageIF* message) override;
|
||||||
|
|
||||||
ReturnValue_t flush(uint32_t* count) override;
|
ReturnValue_t flush(uint32_t* count) override;
|
||||||
|
|
||||||
MessageQueueId_t getLastPartner() const override;
|
|
||||||
|
|
||||||
MessageQueueId_t getId() const override;
|
|
||||||
|
|
||||||
void setDefaultDestination(MessageQueueId_t defaultDestination) override;
|
|
||||||
|
|
||||||
MessageQueueId_t getDefaultDestination() const override;
|
|
||||||
|
|
||||||
bool isDefaultDestinationSet() const override;
|
|
||||||
|
|
||||||
QueueHandle_t getNativeQueueHandle();
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* @brief Implementation to be called from any send Call within
|
* @brief Implementation to be called from any send Call within
|
||||||
@ -136,12 +115,8 @@ class MessageQueue : public MessageQueueIF {
|
|||||||
static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault);
|
static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool defaultDestinationSet = false;
|
|
||||||
QueueHandle_t handle;
|
QueueHandle_t handle;
|
||||||
MessageQueueId_t queueId = MessageQueueIF::NO_QUEUE;
|
|
||||||
|
|
||||||
MessageQueueId_t defaultDestination = MessageQueueIF::NO_QUEUE;
|
|
||||||
MessageQueueId_t lastPartner = MessageQueueIF::NO_QUEUE;
|
|
||||||
const size_t maxMessageSize;
|
const size_t maxMessageSize;
|
||||||
//! Stores the current system context
|
//! Stores the current system context
|
||||||
CallContext callContext = CallContext::TASK;
|
CallContext callContext = CallContext::TASK;
|
||||||
|
@ -22,8 +22,9 @@ QueueFactory::QueueFactory() {}
|
|||||||
|
|
||||||
QueueFactory::~QueueFactory() {}
|
QueueFactory::~QueueFactory() {}
|
||||||
|
|
||||||
MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, size_t maxMessageSize) {
|
MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, size_t maxMessageSize,
|
||||||
return new MessageQueue(messageDepth, maxMessageSize);
|
MqArgs* args) {
|
||||||
|
return new MessageQueue(messageDepth, maxMessageSize, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) { delete queue; }
|
void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) { delete queue; }
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
target_sources(${LIB_FSFW_NAME}
|
target_sources(${LIB_FSFW_NAME} PRIVATE
|
||||||
PRIVATE
|
|
||||||
Clock.cpp
|
Clock.cpp
|
||||||
FixedTimeslotTask.cpp
|
FixedTimeslotTask.cpp
|
||||||
MessageQueue.cpp
|
MessageQueue.cpp
|
||||||
@ -16,9 +15,13 @@ target_sources(${LIB_FSFW_NAME}
|
|||||||
if(UNIX)
|
if(UNIX)
|
||||||
find_package(Threads REQUIRED)
|
find_package(Threads REQUIRED)
|
||||||
|
|
||||||
target_link_libraries(${LIB_FSFW_NAME}
|
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
|
||||||
PRIVATE
|
|
||||||
rt
|
|
||||||
${CMAKE_THREAD_LIBS_INIT}
|
${CMAKE_THREAD_LIBS_INIT}
|
||||||
)
|
)
|
||||||
|
if(NOT APPLE)
|
||||||
|
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
|
||||||
|
rt
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
endif()
|
endif()
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
|
#include "fsfw/ipc/MutexGuard.h"
|
||||||
#include "fsfw/platform.h"
|
#include "fsfw/platform.h"
|
||||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||||
|
|
||||||
@ -11,9 +12,6 @@
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
uint16_t Clock::leapSeconds = 0;
|
|
||||||
MutexIF* Clock::timeMutex = NULL;
|
|
||||||
|
|
||||||
using SystemClock = std::chrono::system_clock;
|
using SystemClock = std::chrono::system_clock;
|
||||||
|
|
||||||
uint32_t Clock::getTicksPerSecond(void) {
|
uint32_t Clock::getTicksPerSecond(void) {
|
||||||
@ -127,6 +125,13 @@ ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) {
|
|||||||
auto seconds = std::chrono::time_point_cast<std::chrono::seconds>(now);
|
auto seconds = std::chrono::time_point_cast<std::chrono::seconds>(now);
|
||||||
auto fraction = now - seconds;
|
auto fraction = now - seconds;
|
||||||
time_t tt = SystemClock::to_time_t(now);
|
time_t tt = SystemClock::to_time_t(now);
|
||||||
|
ReturnValue_t result = checkOrCreateClockMutex();
|
||||||
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
MutexGuard helper(timeMutex);
|
||||||
|
// gmtime writes its output in a global buffer which is not Thread Safe
|
||||||
|
// Therefore we have to use a Mutex here
|
||||||
struct tm* timeInfo;
|
struct tm* timeInfo;
|
||||||
timeInfo = gmtime(&tt);
|
timeInfo = gmtime(&tt);
|
||||||
time->year = timeInfo->tm_year + 1900;
|
time->year = timeInfo->tm_year + 1900;
|
||||||
|
@ -8,10 +8,12 @@
|
|||||||
#include "fsfw/osal/host/QueueMapManager.h"
|
#include "fsfw/osal/host/QueueMapManager.h"
|
||||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||||
|
|
||||||
MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize)
|
MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize, MqArgs* args)
|
||||||
: messageSize(maxMessageSize), messageDepth(messageDepth) {
|
: MessageQueueBase(MessageQueueIF::NO_QUEUE, MessageQueueIF::NO_QUEUE, args),
|
||||||
|
messageSize(maxMessageSize),
|
||||||
|
messageDepth(messageDepth) {
|
||||||
queueLock = MutexFactory::instance()->createMutex();
|
queueLock = MutexFactory::instance()->createMutex();
|
||||||
auto result = QueueMapManager::instance()->addMessageQueue(this, &mqId);
|
auto result = QueueMapManager::instance()->addMessageQueue(this, &id);
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::error << "MessageQueue::MessageQueue: Could not be created" << std::endl;
|
sif::error << "MessageQueue::MessageQueue: Could not be created" << std::endl;
|
||||||
@ -23,42 +25,11 @@ MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize)
|
|||||||
|
|
||||||
MessageQueue::~MessageQueue() { MutexFactory::instance()->deleteMutex(queueLock); }
|
MessageQueue::~MessageQueue() { MutexFactory::instance()->deleteMutex(queueLock); }
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
|
||||||
bool ignoreFault) {
|
|
||||||
return sendMessageFrom(sendTo, message, this->getId(), ignoreFault);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessageIF* message) {
|
|
||||||
return sendToDefaultFrom(message, this->getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessageIF* message,
|
|
||||||
MessageQueueId_t sentFrom, bool ignoreFault) {
|
|
||||||
return sendMessageFrom(defaultDestination, message, sentFrom, ignoreFault);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::reply(MessageQueueMessageIF* message) {
|
|
||||||
if (this->lastPartner != MessageQueueIF::NO_QUEUE) {
|
|
||||||
return sendMessageFrom(this->lastPartner, message, this->getId());
|
|
||||||
} else {
|
|
||||||
return MessageQueueIF::NO_REPLY_PARTNER;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
||||||
MessageQueueId_t sentFrom, bool ignoreFault) {
|
MessageQueueId_t sentFrom, bool ignoreFault) {
|
||||||
return sendMessageFromMessageQueue(sendTo, message, sentFrom, ignoreFault);
|
return sendMessageFromMessageQueue(sendTo, message, sentFrom, ignoreFault);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message,
|
|
||||||
MessageQueueId_t* receivedFrom) {
|
|
||||||
ReturnValue_t status = this->receiveMessage(message);
|
|
||||||
if (status == HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
*receivedFrom = this->lastPartner;
|
|
||||||
}
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
|
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
|
||||||
if (messageQueue.empty()) {
|
if (messageQueue.empty()) {
|
||||||
return MessageQueueIF::EMPTY;
|
return MessageQueueIF::EMPTY;
|
||||||
@ -68,12 +39,10 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
|
|||||||
message->getBuffer());
|
message->getBuffer());
|
||||||
messageQueue.pop();
|
messageQueue.pop();
|
||||||
// The last partner is the first uint32_t field in the message
|
// The last partner is the first uint32_t field in the message
|
||||||
this->lastPartner = message->getSender();
|
this->last = message->getSender();
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageQueueId_t MessageQueue::getLastPartner() const { return lastPartner; }
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::flush(uint32_t* count) {
|
ReturnValue_t MessageQueue::flush(uint32_t* count) {
|
||||||
*count = messageQueue.size();
|
*count = messageQueue.size();
|
||||||
// Clears the queue.
|
// Clears the queue.
|
||||||
@ -81,17 +50,6 @@ ReturnValue_t MessageQueue::flush(uint32_t* count) {
|
|||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageQueueId_t MessageQueue::getId() const { return mqId; }
|
|
||||||
|
|
||||||
void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) {
|
|
||||||
defaultDestinationSet = true;
|
|
||||||
this->defaultDestination = defaultDestination;
|
|
||||||
}
|
|
||||||
|
|
||||||
MessageQueueId_t MessageQueue::getDefaultDestination() const { return defaultDestination; }
|
|
||||||
|
|
||||||
bool MessageQueue::isDefaultDestinationSet() const { return defaultDestinationSet; }
|
|
||||||
|
|
||||||
// static core function to send messages.
|
// static core function to send messages.
|
||||||
ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
|
ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
|
||||||
MessageQueueMessageIF* message,
|
MessageQueueMessageIF* message,
|
||||||
|
@ -5,9 +5,11 @@
|
|||||||
#include <queue>
|
#include <queue>
|
||||||
|
|
||||||
#include "fsfw/internalerror/InternalErrorReporterIF.h"
|
#include "fsfw/internalerror/InternalErrorReporterIF.h"
|
||||||
|
#include "fsfw/ipc/MessageQueueBase.h"
|
||||||
#include "fsfw/ipc/MessageQueueIF.h"
|
#include "fsfw/ipc/MessageQueueIF.h"
|
||||||
#include "fsfw/ipc/MessageQueueMessage.h"
|
#include "fsfw/ipc/MessageQueueMessage.h"
|
||||||
#include "fsfw/ipc/MutexIF.h"
|
#include "fsfw/ipc/MutexIF.h"
|
||||||
|
#include "fsfw/ipc/definitions.h"
|
||||||
#include "fsfw/timemanager/Clock.h"
|
#include "fsfw/timemanager/Clock.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -33,7 +35,7 @@
|
|||||||
* @ingroup osal
|
* @ingroup osal
|
||||||
* @ingroup message_queue
|
* @ingroup message_queue
|
||||||
*/
|
*/
|
||||||
class MessageQueue : public MessageQueueIF {
|
class MessageQueue : public MessageQueueBase {
|
||||||
friend class MessageQueueSenderIF;
|
friend class MessageQueueSenderIF;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -54,7 +56,8 @@ class MessageQueue : public MessageQueueIF {
|
|||||||
* This should be left default.
|
* This should be left default.
|
||||||
*/
|
*/
|
||||||
MessageQueue(size_t messageDepth = 3,
|
MessageQueue(size_t messageDepth = 3,
|
||||||
size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE);
|
size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE,
|
||||||
|
MqArgs* args = nullptr);
|
||||||
|
|
||||||
/** Copying message queues forbidden */
|
/** Copying message queues forbidden */
|
||||||
MessageQueue(const MessageQueue&) = delete;
|
MessageQueue(const MessageQueue&) = delete;
|
||||||
@ -67,121 +70,12 @@ class MessageQueue : public MessageQueueIF {
|
|||||||
*/
|
*/
|
||||||
virtual ~MessageQueue();
|
virtual ~MessageQueue();
|
||||||
|
|
||||||
/**
|
// Implement non-generic MessageQueueIF functions not handled by MessageQueueBase
|
||||||
* @brief This operation sends a message to the given destination.
|
|
||||||
* @details It directly uses the sendMessage call of the MessageQueueSender
|
|
||||||
* parent, but passes its queue id as "sentFrom" parameter.
|
|
||||||
* @param sendTo This parameter specifies the message queue id of the
|
|
||||||
* destination message queue.
|
|
||||||
* @param message A pointer to a previously created message, which is sent.
|
|
||||||
* @param ignoreFault If set to true, the internal software fault counter
|
|
||||||
* is not incremented if queue is full.
|
|
||||||
*/
|
|
||||||
ReturnValue_t sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
|
||||||
bool ignoreFault = false) override;
|
|
||||||
/**
|
|
||||||
* @brief This operation sends a message to the default destination.
|
|
||||||
* @details As in the sendMessage method, this function uses the
|
|
||||||
* sendToDefault call of the MessageQueueSender parent class and adds its
|
|
||||||
* queue id as "sentFrom" information.
|
|
||||||
* @param message A pointer to a previously created message, which is sent.
|
|
||||||
*/
|
|
||||||
ReturnValue_t sendToDefault(MessageQueueMessageIF* message) override;
|
|
||||||
/**
|
|
||||||
* @brief This operation sends a message to the last communication partner.
|
|
||||||
* @details This operation simplifies answering an incoming message by using
|
|
||||||
* the stored lastPartner information as destination. If there was no
|
|
||||||
* message received yet (i.e. lastPartner is zero), an error code is returned.
|
|
||||||
* @param message A pointer to a previously created message, which is sent.
|
|
||||||
*/
|
|
||||||
ReturnValue_t reply(MessageQueueMessageIF* message) override;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief With the sendMessage call, a queue message is sent to a
|
|
||||||
* receiving queue.
|
|
||||||
* @details
|
|
||||||
* This method takes the message provided, adds the sentFrom information and
|
|
||||||
* passes it on to the destination provided with an operating system call.
|
|
||||||
* The OS's return value is returned.
|
|
||||||
* @param sendTo This parameter specifies the message queue id to send
|
|
||||||
* the message to.
|
|
||||||
* @param message This is a pointer to a previously created message,
|
|
||||||
* which is sent.
|
|
||||||
* @param sentFrom The sentFrom information can be set to inject the
|
|
||||||
* sender's queue id into the message. This variable is set to zero by
|
|
||||||
* default.
|
|
||||||
* @param ignoreFault If set to true, the internal software fault counter
|
|
||||||
* is not incremented if queue is full.
|
|
||||||
*/
|
|
||||||
virtual ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
virtual ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
||||||
MessageQueueId_t sentFrom = NO_QUEUE,
|
MessageQueueId_t sentFrom = NO_QUEUE,
|
||||||
bool ignoreFault = false) override;
|
bool ignoreFault = false) override;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The sendToDefault method sends a queue message to the default
|
|
||||||
* destination.
|
|
||||||
* @details
|
|
||||||
* In all other aspects, it works identical to the sendMessage method.
|
|
||||||
* @param message This is a pointer to a previously created message,
|
|
||||||
* which is sent.
|
|
||||||
* @param sentFrom The sentFrom information can be set to inject the
|
|
||||||
* sender's queue id into the message. This variable is set to zero by
|
|
||||||
* default.
|
|
||||||
*/
|
|
||||||
virtual ReturnValue_t sendToDefaultFrom(MessageQueueMessageIF* message,
|
|
||||||
MessageQueueId_t sentFrom = NO_QUEUE,
|
|
||||||
bool ignoreFault = false) override;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief This function reads available messages from the message queue
|
|
||||||
* and returns the sender.
|
|
||||||
* @details
|
|
||||||
* It works identically to the other receiveMessage call, but in addition
|
|
||||||
* returns the sender's queue id.
|
|
||||||
* @param message A pointer to a message in which the received data is stored.
|
|
||||||
* @param receivedFrom A pointer to a queue id in which the sender's id is stored.
|
|
||||||
*/
|
|
||||||
ReturnValue_t receiveMessage(MessageQueueMessageIF* message,
|
|
||||||
MessageQueueId_t* receivedFrom) override;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief This function reads available messages from the message queue.
|
|
||||||
* @details
|
|
||||||
* If data is available it is stored in the passed message pointer.
|
|
||||||
* The message's original content is overwritten and the sendFrom
|
|
||||||
* information is stored in the lastPartner attribute. Else, the lastPartner
|
|
||||||
* information remains untouched, the message's content is cleared and the
|
|
||||||
* function returns immediately.
|
|
||||||
* @param message A pointer to a message in which the received data is stored.
|
|
||||||
*/
|
|
||||||
ReturnValue_t receiveMessage(MessageQueueMessageIF* message) override;
|
ReturnValue_t receiveMessage(MessageQueueMessageIF* message) override;
|
||||||
/**
|
|
||||||
* Deletes all pending messages in the queue.
|
|
||||||
* @param count The number of flushed messages.
|
|
||||||
* @return RETURN_OK on success.
|
|
||||||
*/
|
|
||||||
ReturnValue_t flush(uint32_t* count) override;
|
ReturnValue_t flush(uint32_t* count) override;
|
||||||
/**
|
|
||||||
* @brief This method returns the message queue id of the last
|
|
||||||
* communication partner.
|
|
||||||
*/
|
|
||||||
MessageQueueId_t getLastPartner() const override;
|
|
||||||
/**
|
|
||||||
* @brief This method returns the message queue id of this class's
|
|
||||||
* message queue.
|
|
||||||
*/
|
|
||||||
MessageQueueId_t getId() const override;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief This method is a simple setter for the default destination.
|
|
||||||
*/
|
|
||||||
void setDefaultDestination(MessageQueueId_t defaultDestination) override;
|
|
||||||
/**
|
|
||||||
* @brief This method is a simple getter for the default destination.
|
|
||||||
*/
|
|
||||||
MessageQueueId_t getDefaultDestination() const override;
|
|
||||||
|
|
||||||
bool isDefaultDestinationSet() const override;
|
|
||||||
|
|
||||||
ReturnValue_t lockQueue(MutexIF::TimeoutType timeoutType, dur_millis_t lockTimeout);
|
ReturnValue_t lockQueue(MutexIF::TimeoutType timeoutType, dur_millis_t lockTimeout);
|
||||||
ReturnValue_t unlockQueue();
|
ReturnValue_t unlockQueue();
|
||||||
@ -211,23 +105,14 @@ class MessageQueue : public MessageQueueIF {
|
|||||||
MessageQueueId_t sentFrom = NO_QUEUE,
|
MessageQueueId_t sentFrom = NO_QUEUE,
|
||||||
bool ignoreFault = false);
|
bool ignoreFault = false);
|
||||||
|
|
||||||
// static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::queue<std::vector<uint8_t>> messageQueue;
|
std::queue<std::vector<uint8_t>> messageQueue;
|
||||||
/**
|
|
||||||
* @brief The class stores the queue id it got assigned.
|
|
||||||
* If initialization fails, the queue id is set to zero.
|
|
||||||
*/
|
|
||||||
MessageQueueId_t mqId = MessageQueueIF::NO_QUEUE;
|
|
||||||
size_t messageSize = 0;
|
size_t messageSize = 0;
|
||||||
size_t messageDepth = 0;
|
size_t messageDepth = 0;
|
||||||
|
|
||||||
MutexIF* queueLock;
|
MutexIF* queueLock;
|
||||||
|
|
||||||
bool defaultDestinationSet = false;
|
|
||||||
MessageQueueId_t defaultDestination = MessageQueueIF::NO_QUEUE;
|
MessageQueueId_t defaultDestination = MessageQueueIF::NO_QUEUE;
|
||||||
MessageQueueId_t lastPartner = MessageQueueIF::NO_QUEUE;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_ */
|
#endif /* FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_ */
|
||||||
|
@ -27,12 +27,13 @@ QueueFactory::QueueFactory() {}
|
|||||||
|
|
||||||
QueueFactory::~QueueFactory() {}
|
QueueFactory::~QueueFactory() {}
|
||||||
|
|
||||||
MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, size_t maxMessageSize) {
|
MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, size_t maxMessageSize,
|
||||||
|
MqArgs* args) {
|
||||||
// A thread-safe queue can be implemented by using a combination
|
// A thread-safe queue can be implemented by using a combination
|
||||||
// of std::queue and std::mutex. This uses dynamic memory allocation
|
// of std::queue and std::mutex. This uses dynamic memory allocation
|
||||||
// which could be alleviated by using a custom allocator, external library
|
// which could be alleviated by using a custom allocator, external library
|
||||||
// (etl::queue) or simply using std::queue, we're on a host machine anyway.
|
// (etl::queue) or simply using std::queue, we're on a host machine anyway.
|
||||||
return new MessageQueue(messageDepth, maxMessageSize);
|
return new MessageQueue(messageDepth, maxMessageSize, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) { delete queue; }
|
void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) { delete queue; }
|
||||||
|
@ -18,12 +18,12 @@ target_sources(${LIB_FSFW_NAME} PRIVATE
|
|||||||
|
|
||||||
find_package(Threads REQUIRED)
|
find_package(Threads REQUIRED)
|
||||||
|
|
||||||
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
|
target_link_libraries(${LIB_FSFW_NAME} PUBLIC
|
||||||
${CMAKE_THREAD_LIBS_INIT}
|
${CMAKE_THREAD_LIBS_INIT}
|
||||||
|
)
|
||||||
|
|
||||||
|
if(NOT APPLE)
|
||||||
|
target_link_libraries(${LIB_FSFW_NAME} PUBLIC
|
||||||
rt
|
rt
|
||||||
)
|
)
|
||||||
|
endif()
|
||||||
target_link_libraries(${LIB_FSFW_NAME} INTERFACE
|
|
||||||
${CMAKE_THREAD_LIBS_INIT}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
@ -8,11 +8,9 @@
|
|||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
|
#include "fsfw/ipc/MutexGuard.h"
|
||||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||||
|
|
||||||
uint16_t Clock::leapSeconds = 0;
|
|
||||||
MutexIF* Clock::timeMutex = NULL;
|
|
||||||
|
|
||||||
uint32_t Clock::getTicksPerSecond(void) {
|
uint32_t Clock::getTicksPerSecond(void) {
|
||||||
uint32_t ticks = sysconf(_SC_CLK_TCK);
|
uint32_t ticks = sysconf(_SC_CLK_TCK);
|
||||||
return ticks;
|
return ticks;
|
||||||
@ -117,7 +115,13 @@ ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) {
|
|||||||
// TODO errno
|
// TODO errno
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
}
|
}
|
||||||
|
ReturnValue_t result = checkOrCreateClockMutex();
|
||||||
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
MutexGuard helper(timeMutex);
|
||||||
|
// gmtime writes its output in a global buffer which is not Thread Safe
|
||||||
|
// Therefore we have to use a Mutex here
|
||||||
struct tm* timeInfo;
|
struct tm* timeInfo;
|
||||||
timeInfo = gmtime(&timeUnix.tv_sec);
|
timeInfo = gmtime(&timeUnix.tv_sec);
|
||||||
time->year = timeInfo->tm_year + 1900;
|
time->year = timeInfo->tm_year + 1900;
|
||||||
|
@ -11,13 +11,10 @@
|
|||||||
#include "fsfw/osal/linux/unixUtility.h"
|
#include "fsfw/osal/linux/unixUtility.h"
|
||||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||||
|
|
||||||
MessageQueue::MessageQueue(uint32_t messageDepth, size_t maxMessageSize)
|
MessageQueue::MessageQueue(uint32_t messageDepth, size_t maxMessageSize, MqArgs* args)
|
||||||
: id(MessageQueueIF::NO_QUEUE),
|
: MessageQueueBase(MessageQueueIF::NO_QUEUE, MessageQueueIF::NO_QUEUE, args),
|
||||||
lastPartner(MessageQueueIF::NO_QUEUE),
|
|
||||||
defaultDestination(MessageQueueIF::NO_QUEUE),
|
|
||||||
maxMessageSize(maxMessageSize) {
|
maxMessageSize(maxMessageSize) {
|
||||||
mq_attr attributes;
|
mq_attr attributes;
|
||||||
this->id = 0;
|
|
||||||
// Set attributes
|
// Set attributes
|
||||||
attributes.mq_curmsgs = 0;
|
attributes.mq_curmsgs = 0;
|
||||||
attributes.mq_maxmsg = messageDepth;
|
attributes.mq_maxmsg = messageDepth;
|
||||||
@ -50,30 +47,6 @@ MessageQueue::~MessageQueue() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
|
||||||
bool ignoreFault) {
|
|
||||||
return sendMessageFrom(sendTo, message, this->getId(), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessageIF* message) {
|
|
||||||
return sendToDefaultFrom(message, this->getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::reply(MessageQueueMessageIF* message) {
|
|
||||||
if (this->lastPartner != 0) {
|
|
||||||
return sendMessageFrom(this->lastPartner, message, this->getId());
|
|
||||||
} else {
|
|
||||||
return NO_REPLY_PARTNER;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message,
|
|
||||||
MessageQueueId_t* receivedFrom) {
|
|
||||||
ReturnValue_t status = this->receiveMessage(message);
|
|
||||||
*receivedFrom = this->lastPartner;
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
|
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
|
||||||
if (message == nullptr) {
|
if (message == nullptr) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
@ -96,7 +69,7 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
|
|||||||
int status = mq_receive(id, reinterpret_cast<char*>(message->getBuffer()),
|
int status = mq_receive(id, reinterpret_cast<char*>(message->getBuffer()),
|
||||||
message->getMaximumMessageSize(), &messagePriority);
|
message->getMaximumMessageSize(), &messagePriority);
|
||||||
if (status > 0) {
|
if (status > 0) {
|
||||||
this->lastPartner = message->getSender();
|
this->last = message->getSender();
|
||||||
// Check size of incoming message.
|
// Check size of incoming message.
|
||||||
if (message->getMessageSize() < message->getMinimumMessageSize()) {
|
if (message->getMessageSize() < message->getMinimumMessageSize()) {
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
@ -164,8 +137,6 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageQueueId_t MessageQueue::getLastPartner() const { return this->lastPartner; }
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::flush(uint32_t* count) {
|
ReturnValue_t MessageQueue::flush(uint32_t* count) {
|
||||||
mq_attr attrib;
|
mq_attr attrib;
|
||||||
int status = mq_getattr(id, &attrib);
|
int status = mq_getattr(id, &attrib);
|
||||||
@ -212,26 +183,11 @@ ReturnValue_t MessageQueue::flush(uint32_t* count) {
|
|||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageQueueId_t MessageQueue::getId() const { return this->id; }
|
|
||||||
|
|
||||||
void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) {
|
|
||||||
this->defaultDestination = defaultDestination;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessageIF* message,
|
|
||||||
MessageQueueId_t sentFrom, bool ignoreFault) {
|
|
||||||
return sendMessageFrom(defaultDestination, message, sentFrom, ignoreFault);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
||||||
MessageQueueId_t sentFrom, bool ignoreFault) {
|
MessageQueueId_t sentFrom, bool ignoreFault) {
|
||||||
return sendMessageFromMessageQueue(sendTo, message, sentFrom, ignoreFault);
|
return sendMessageFromMessageQueue(sendTo, message, sentFrom, ignoreFault);
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageQueueId_t MessageQueue::getDefaultDestination() const { return this->defaultDestination; }
|
|
||||||
|
|
||||||
bool MessageQueue::isDefaultDestinationSet() const { return (defaultDestination != NO_QUEUE); }
|
|
||||||
|
|
||||||
uint16_t MessageQueue::queueCounter = 0;
|
uint16_t MessageQueue::queueCounter = 0;
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
|
ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
|
||||||
@ -240,9 +196,9 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
|
|||||||
bool ignoreFault) {
|
bool ignoreFault) {
|
||||||
if (message == nullptr) {
|
if (message == nullptr) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::error << "MessageQueue::sendMessageFromMessageQueue: Message is nullptr!" << std::endl;
|
sif::error << "MessageQueue::sendMessageFromMessageQueue: Message is nullptr" << std::endl;
|
||||||
#else
|
#else
|
||||||
sif::printError("MessageQueue::sendMessageFromMessageQueue: Message is nullptr!\n");
|
sif::printError("MessageQueue::sendMessageFromMessageQueue: Message is nullptr\n");
|
||||||
#endif
|
#endif
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
}
|
}
|
||||||
@ -256,7 +212,7 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
|
|||||||
if (!ignoreFault) {
|
if (!ignoreFault) {
|
||||||
InternalErrorReporterIF* internalErrorReporter =
|
InternalErrorReporterIF* internalErrorReporter =
|
||||||
ObjectManager::instance()->get<InternalErrorReporterIF>(objects::INTERNAL_ERROR_REPORTER);
|
ObjectManager::instance()->get<InternalErrorReporterIF>(objects::INTERNAL_ERROR_REPORTER);
|
||||||
if (internalErrorReporter != NULL) {
|
if (internalErrorReporter != nullptr) {
|
||||||
internalErrorReporter->queueMessageNotSent();
|
internalErrorReporter->queueMessageNotSent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
#ifndef FSFW_OSAL_LINUX_MESSAGEQUEUE_H_
|
#ifndef FSFW_OSAL_LINUX_MESSAGEQUEUE_H_
|
||||||
#define FSFW_OSAL_LINUX_MESSAGEQUEUE_H_
|
#define FSFW_OSAL_LINUX_MESSAGEQUEUE_H_
|
||||||
|
|
||||||
|
#include <fsfw/ipc/MessageQueueBase.h>
|
||||||
#include <mqueue.h>
|
#include <mqueue.h>
|
||||||
|
|
||||||
#include "fsfw/internalerror/InternalErrorReporterIF.h"
|
#include "fsfw/internalerror/InternalErrorReporterIF.h"
|
||||||
#include "fsfw/ipc/MessageQueueIF.h"
|
#include "fsfw/ipc/MessageQueueIF.h"
|
||||||
#include "fsfw/ipc/MessageQueueMessage.h"
|
#include "fsfw/ipc/MessageQueueMessage.h"
|
||||||
|
#include "fsfw/ipc/definitions.h"
|
||||||
/**
|
/**
|
||||||
* @brief This class manages sending and receiving of message queue messages.
|
* @brief This class manages sending and receiving of message queue messages.
|
||||||
*
|
*
|
||||||
@ -25,7 +27,7 @@
|
|||||||
* makes use of the operating system calls provided.
|
* makes use of the operating system calls provided.
|
||||||
* @ingroup message_queue
|
* @ingroup message_queue
|
||||||
*/
|
*/
|
||||||
class MessageQueue : public MessageQueueIF {
|
class MessageQueue : public MessageQueueBase {
|
||||||
friend class MessageQueueSenderIF;
|
friend class MessageQueueSenderIF;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -42,104 +44,24 @@ class MessageQueue : public MessageQueueIF {
|
|||||||
* This should be left default.
|
* This should be left default.
|
||||||
*/
|
*/
|
||||||
MessageQueue(uint32_t messageDepth = 3,
|
MessageQueue(uint32_t messageDepth = 3,
|
||||||
size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE);
|
size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE,
|
||||||
|
MqArgs* args = nullptr);
|
||||||
|
|
||||||
|
/** Copying message queues forbidden */
|
||||||
|
MessageQueue(const MessageQueue&) = delete;
|
||||||
|
MessageQueue& operator=(const MessageQueue&) = delete;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @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();
|
virtual ~MessageQueue();
|
||||||
/**
|
|
||||||
* @brief This operation sends a message to the given destination.
|
|
||||||
* @details It directly uses the sendMessage call of the MessageQueueSender parent, but passes
|
|
||||||
* its queue id as "sentFrom" parameter.
|
|
||||||
* @param sendTo This parameter specifies the message queue id of the destination message
|
|
||||||
* queue.
|
|
||||||
* @param message A pointer to a previously created message, which is sent.
|
|
||||||
* @param ignoreFault If set to true, the internal software fault counter is not incremented if
|
|
||||||
* queue is full.
|
|
||||||
*/
|
|
||||||
virtual ReturnValue_t sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
|
||||||
bool ignoreFault = false);
|
|
||||||
/**
|
|
||||||
* @brief This operation sends a message to the default destination.
|
|
||||||
* @details As in the sendMessage method, this function uses the sendToDefault call of the
|
|
||||||
* MessageQueueSender parent class and adds its queue id as "sentFrom"
|
|
||||||
* information.
|
|
||||||
* @param message A pointer to a previously created message, which is sent.
|
|
||||||
*/
|
|
||||||
virtual ReturnValue_t sendToDefault(MessageQueueMessageIF* message);
|
|
||||||
/**
|
|
||||||
* @brief This operation sends a message to the last communication partner.
|
|
||||||
* @details This operation simplifies answering an incoming message by using the stored
|
|
||||||
* lastParnter information as destination. If there was no message received yet
|
|
||||||
* (i.e. lastPartner is zero), an error code is returned.
|
|
||||||
* @param message A pointer to a previously created message, which is sent.
|
|
||||||
*/
|
|
||||||
ReturnValue_t reply(MessageQueueMessageIF* message);
|
|
||||||
|
|
||||||
/**
|
// Implement non-generic MessageQueueIF functions not handled by MessageQueueBase
|
||||||
* @brief This function reads available messages from the message queue and returns the
|
ReturnValue_t receiveMessage(MessageQueueMessageIF* message) override;
|
||||||
* sender.
|
ReturnValue_t flush(uint32_t* count) override;
|
||||||
* @details It works identically to the other receiveMessage call, but in addition returns the
|
ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
||||||
* sender's queue id.
|
MessageQueueId_t sentFrom, bool ignoreFault = false) override;
|
||||||
* @param message A pointer to a message in which the received data is stored.
|
|
||||||
* @param receivedFrom A pointer to a queue id in which the sender's id is stored.
|
|
||||||
*/
|
|
||||||
ReturnValue_t receiveMessage(MessageQueueMessageIF* message, MessageQueueId_t* receivedFrom);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief This function reads available messages from the message queue.
|
|
||||||
* @details If data is available it is stored in the passed message pointer. The message's
|
|
||||||
* original content is overwritten and the sendFrom information is stored in
|
|
||||||
* the lastPartner attribute. Else, the lastPartner information remains untouched, the message's
|
|
||||||
* content is cleared and the function returns immediately.
|
|
||||||
* @param message A pointer to a message in which the received data is stored.
|
|
||||||
*/
|
|
||||||
ReturnValue_t receiveMessage(MessageQueueMessageIF* message);
|
|
||||||
/**
|
|
||||||
* Deletes all pending messages in the queue.
|
|
||||||
* @param count The number of flushed messages.
|
|
||||||
* @return RETURN_OK on success.
|
|
||||||
*/
|
|
||||||
ReturnValue_t flush(uint32_t* count);
|
|
||||||
/**
|
|
||||||
* @brief This method returns the message queue id of the last communication partner.
|
|
||||||
*/
|
|
||||||
MessageQueueId_t getLastPartner() const;
|
|
||||||
/**
|
|
||||||
* @brief This method returns the message queue id of this class's message queue.
|
|
||||||
*/
|
|
||||||
MessageQueueId_t getId() const;
|
|
||||||
/**
|
|
||||||
* \brief With the sendMessage call, a queue message is sent to a receiving queue.
|
|
||||||
* \param sendTo This parameter specifies the message queue id to send the message to.
|
|
||||||
* \param message This is a pointer to a previously created message, which is sent.
|
|
||||||
* \param sentFrom The sentFrom information can be set to inject the sender's queue id into the
|
|
||||||
* message. This variable is set to zero by default. \param ignoreFault If set to true, the
|
|
||||||
* internal software fault counter is not incremented if queue is full.
|
|
||||||
*/
|
|
||||||
virtual ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
|
||||||
MessageQueueId_t sentFrom, bool ignoreFault = false);
|
|
||||||
/**
|
|
||||||
* \brief The sendToDefault method sends a queue message to the default destination.
|
|
||||||
* \details In all other aspects, it works identical to the sendMessage method.
|
|
||||||
* \param message This is a pointer to a previously created message, which is sent.
|
|
||||||
* \param sentFrom The sentFrom information can be set to inject the sender's queue id into the
|
|
||||||
* message. This variable is set to zero by default.
|
|
||||||
*/
|
|
||||||
virtual ReturnValue_t sendToDefaultFrom(MessageQueueMessageIF* message,
|
|
||||||
MessageQueueId_t sentFrom = NO_QUEUE,
|
|
||||||
bool ignoreFault = false);
|
|
||||||
/**
|
|
||||||
* \brief This method is a simple setter for the default destination.
|
|
||||||
*/
|
|
||||||
void setDefaultDestination(MessageQueueId_t defaultDestination);
|
|
||||||
/**
|
|
||||||
* \brief This method is a simple getter for the default destination.
|
|
||||||
*/
|
|
||||||
MessageQueueId_t getDefaultDestination() const;
|
|
||||||
|
|
||||||
bool isDefaultDestinationSet() const;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
@ -158,31 +80,10 @@ class MessageQueue : public MessageQueueIF {
|
|||||||
bool ignoreFault = false);
|
bool ignoreFault = false);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
|
||||||
* @brief The class stores the queue id it got assigned from the operating system in this
|
|
||||||
* attribute. If initialization fails, the queue id is set to zero.
|
|
||||||
*/
|
|
||||||
MessageQueueId_t id;
|
|
||||||
/**
|
|
||||||
* @brief In this attribute, the queue id of the last communication partner is stored
|
|
||||||
* to allow for replying.
|
|
||||||
*/
|
|
||||||
MessageQueueId_t lastPartner;
|
|
||||||
/**
|
|
||||||
* @brief The message queue's name -a user specific information for the operating system- is
|
|
||||||
* generated automatically with the help of this static counter.
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* \brief This attribute stores a default destination to send messages to.
|
|
||||||
* \details It is stored to simplify sending to always-the-same receiver. The attribute may
|
|
||||||
* be set in the constructor or by a setter call to setDefaultDestination.
|
|
||||||
*/
|
|
||||||
MessageQueueId_t defaultDestination;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name of the message queue, stored for unlinking
|
* The name of the message queue, stored for unlinking
|
||||||
*/
|
*/
|
||||||
char name[16];
|
char name[16] = {};
|
||||||
|
|
||||||
static uint16_t queueCounter;
|
static uint16_t queueCounter;
|
||||||
const size_t maxMessageSize;
|
const size_t maxMessageSize;
|
||||||
|
@ -28,8 +28,9 @@ QueueFactory::QueueFactory() {}
|
|||||||
|
|
||||||
QueueFactory::~QueueFactory() {}
|
QueueFactory::~QueueFactory() {}
|
||||||
|
|
||||||
MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, size_t maxMessageSize) {
|
MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, size_t maxMessageSize,
|
||||||
return new MessageQueue(messageDepth, maxMessageSize);
|
MqArgs* args) {
|
||||||
|
return new MessageQueue(messageDepth, maxMessageSize, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) { delete queue; }
|
void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) { delete queue; }
|
||||||
|
@ -6,9 +6,6 @@
|
|||||||
#include "fsfw/ipc/MutexGuard.h"
|
#include "fsfw/ipc/MutexGuard.h"
|
||||||
#include "fsfw/osal/rtems/RtemsBasic.h"
|
#include "fsfw/osal/rtems/RtemsBasic.h"
|
||||||
|
|
||||||
uint16_t Clock::leapSeconds = 0;
|
|
||||||
MutexIF* Clock::timeMutex = nullptr;
|
|
||||||
|
|
||||||
uint32_t Clock::getTicksPerSecond(void) {
|
uint32_t Clock::getTicksPerSecond(void) {
|
||||||
rtems_interval ticks_per_second = rtems_clock_get_ticks_per_second();
|
rtems_interval ticks_per_second = rtems_clock_get_ticks_per_second();
|
||||||
return static_cast<uint32_t>(ticks_per_second);
|
return static_cast<uint32_t>(ticks_per_second);
|
||||||
|
@ -6,8 +6,9 @@
|
|||||||
#include "fsfw/osal/rtems/RtemsBasic.h"
|
#include "fsfw/osal/rtems/RtemsBasic.h"
|
||||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||||
|
|
||||||
MessageQueue::MessageQueue(size_t message_depth, size_t max_message_size)
|
MessageQueue::MessageQueue(size_t message_depth, size_t max_message_size, MqArgs* args)
|
||||||
: id(0), lastPartner(0), defaultDestination(NO_QUEUE), internalErrorReporter(nullptr) {
|
: MessageQueueBase(MessageQueueIF::NO_QUEUE, MessageQueueIF::NO_QUEUE, args),
|
||||||
|
internalErrorReporter(nullptr) {
|
||||||
rtems_name name = ('Q' << 24) + (queueCounter++ << 8);
|
rtems_name name = ('Q' << 24) + (queueCounter++ << 8);
|
||||||
rtems_status_code status =
|
rtems_status_code status =
|
||||||
rtems_message_queue_create(name, message_depth, max_message_size, 0, &(this->id));
|
rtems_message_queue_create(name, message_depth, max_message_size, 0, &(this->id));
|
||||||
@ -16,43 +17,19 @@ MessageQueue::MessageQueue(size_t message_depth, size_t max_message_size)
|
|||||||
sif::error << "MessageQueue::MessageQueue: Creating Queue " << std::hex << name << std::dec
|
sif::error << "MessageQueue::MessageQueue: Creating Queue " << std::hex << name << std::dec
|
||||||
<< " failed with status:" << (uint32_t)status << std::endl;
|
<< " failed with status:" << (uint32_t)status << std::endl;
|
||||||
#endif
|
#endif
|
||||||
this->id = 0;
|
this->id = MessageQueueIF::NO_QUEUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageQueue::~MessageQueue() { rtems_message_queue_delete(id); }
|
MessageQueue::~MessageQueue() { rtems_message_queue_delete(id); }
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
|
||||||
bool ignoreFault) {
|
|
||||||
return sendMessageFrom(sendTo, message, this->getId(), ignoreFault);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessageIF* message) {
|
|
||||||
return sendToDefaultFrom(message, this->getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::reply(MessageQueueMessageIF* message) {
|
|
||||||
if (this->lastPartner != 0) {
|
|
||||||
return sendMessage(this->lastPartner, message, this->getId());
|
|
||||||
} else {
|
|
||||||
return NO_REPLY_PARTNER;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message,
|
|
||||||
MessageQueueId_t* receivedFrom) {
|
|
||||||
ReturnValue_t status = this->receiveMessage(message);
|
|
||||||
*receivedFrom = this->lastPartner;
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
|
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
rtems_status_code status =
|
rtems_status_code status =
|
||||||
rtems_message_queue_receive(id, message->getBuffer(), &size, RTEMS_NO_WAIT, 1);
|
rtems_message_queue_receive(id, message->getBuffer(), &size, RTEMS_NO_WAIT, 1);
|
||||||
if (status == RTEMS_SUCCESSFUL) {
|
if (status == RTEMS_SUCCESSFUL) {
|
||||||
message->setMessageSize(size);
|
message->setMessageSize(size);
|
||||||
this->lastPartner = message->getSender();
|
this->last = message->getSender();
|
||||||
// Check size of incoming message.
|
// Check size of incoming message.
|
||||||
if (message->getMessageSize() < message->getMinimumMessageSize()) {
|
if (message->getMessageSize() < message->getMinimumMessageSize()) {
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
@ -65,19 +42,11 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
|
|||||||
return convertReturnCode(status);
|
return convertReturnCode(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageQueueId_t MessageQueue::getLastPartner() const { return this->lastPartner; }
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::flush(uint32_t* count) {
|
ReturnValue_t MessageQueue::flush(uint32_t* count) {
|
||||||
rtems_status_code status = rtems_message_queue_flush(id, count);
|
rtems_status_code status = rtems_message_queue_flush(id, count);
|
||||||
return convertReturnCode(status);
|
return convertReturnCode(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageQueueId_t MessageQueue::getId() const { return this->id; }
|
|
||||||
|
|
||||||
void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) {
|
|
||||||
this->defaultDestination = defaultDestination;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
||||||
MessageQueueId_t sentFrom, bool ignoreFault) {
|
MessageQueueId_t sentFrom, bool ignoreFault) {
|
||||||
message->setSender(sentFrom);
|
message->setSender(sentFrom);
|
||||||
@ -103,15 +72,6 @@ ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, MessageQueu
|
|||||||
return returnCode;
|
return returnCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessageIF* message,
|
|
||||||
MessageQueueId_t sentFrom, bool ignoreFault) {
|
|
||||||
return sendMessageFrom(defaultDestination, message, sentFrom, ignoreFault);
|
|
||||||
}
|
|
||||||
|
|
||||||
MessageQueueId_t MessageQueue::getDefaultDestination() const { return this->defaultDestination; }
|
|
||||||
|
|
||||||
bool MessageQueue::isDefaultDestinationSet() const { return (defaultDestination != NO_QUEUE); }
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::convertReturnCode(rtems_status_code inValue) {
|
ReturnValue_t MessageQueue::convertReturnCode(rtems_status_code inValue) {
|
||||||
switch (inValue) {
|
switch (inValue) {
|
||||||
case RTEMS_SUCCESSFUL:
|
case RTEMS_SUCCESSFUL:
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
#ifndef FSFW_OSAL_RTEMS_MESSAGEQUEUE_H_
|
#ifndef FSFW_OSAL_RTEMS_MESSAGEQUEUE_H_
|
||||||
#define FSFW_OSAL_RTEMS_MESSAGEQUEUE_H_
|
#define FSFW_OSAL_RTEMS_MESSAGEQUEUE_H_
|
||||||
|
|
||||||
|
#include <fsfw/ipc/MessageQueueBase.h>
|
||||||
|
|
||||||
#include "RtemsBasic.h"
|
#include "RtemsBasic.h"
|
||||||
#include "fsfw/internalerror/InternalErrorReporterIF.h"
|
#include "fsfw/internalerror/InternalErrorReporterIF.h"
|
||||||
#include "fsfw/ipc/MessageQueueIF.h"
|
#include "fsfw/ipc/MessageQueueIF.h"
|
||||||
#include "fsfw/ipc/MessageQueueMessage.h"
|
#include "fsfw/ipc/MessageQueueMessage.h"
|
||||||
|
#include "fsfw/ipc/definitions.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This class manages sending and receiving of message queue messages.
|
* @brief This class manages sending and receiving of message queue messages.
|
||||||
@ -19,7 +22,7 @@
|
|||||||
*as well as sending and receiving messages, the class makes use of the operating system calls
|
*as well as sending and receiving messages, the class makes use of the operating system calls
|
||||||
*provided. \ingroup message_queue
|
*provided. \ingroup message_queue
|
||||||
*/
|
*/
|
||||||
class MessageQueue : public MessageQueueIF {
|
class MessageQueue : public MessageQueueBase {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief The constructor initializes and configures the message queue.
|
* @brief The constructor initializes and configures the message queue.
|
||||||
@ -34,131 +37,26 @@ class MessageQueue : public MessageQueueIF {
|
|||||||
* This should be left default.
|
* This should be left default.
|
||||||
*/
|
*/
|
||||||
MessageQueue(size_t message_depth = 3,
|
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);
|
||||||
|
|
||||||
|
/** Copying message queues forbidden */
|
||||||
|
MessageQueue(const MessageQueue&) = delete;
|
||||||
|
MessageQueue& operator=(const MessageQueue&) = delete;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @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();
|
virtual ~MessageQueue();
|
||||||
/**
|
|
||||||
* @brief This operation sends a message to the given destination.
|
|
||||||
* @details It directly uses the sendMessage call of the MessageQueueSender parent, but passes
|
|
||||||
* its queue id as "sentFrom" parameter.
|
|
||||||
* @param sendTo This parameter specifies the message queue id of the destination message
|
|
||||||
* queue.
|
|
||||||
* @param message A pointer to a previously created message, which is sent.
|
|
||||||
* @param ignoreFault If set to true, the internal software fault counter is not incremented if
|
|
||||||
* queue is full.
|
|
||||||
*/
|
|
||||||
ReturnValue_t sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
|
||||||
bool ignoreFault = false);
|
|
||||||
/**
|
|
||||||
* @brief This operation sends a message to the default destination.
|
|
||||||
* @details As in the sendMessage method, this function uses the sendToDefault call of the
|
|
||||||
* MessageQueueSender parent class and adds its queue id as "sentFrom"
|
|
||||||
* information.
|
|
||||||
* @param message A pointer to a previously created message, which is sent.
|
|
||||||
*/
|
|
||||||
ReturnValue_t sendToDefault(MessageQueueMessageIF* message);
|
|
||||||
/**
|
|
||||||
* @brief This operation sends a message to the last communication partner.
|
|
||||||
* @details This operation simplifies answering an incoming message by using the stored
|
|
||||||
* lastParnter information as destination. If there was no message received yet
|
|
||||||
* (i.e. lastPartner is zero), an error code is returned.
|
|
||||||
* @param message A pointer to a previously created message, which is sent.
|
|
||||||
*/
|
|
||||||
ReturnValue_t reply(MessageQueueMessageIF* message);
|
|
||||||
|
|
||||||
/**
|
// Implement non-generic MessageQueueIF functions not handled by MessageQueueBase
|
||||||
* @brief This function reads available messages from the message queue and returns the
|
ReturnValue_t flush(uint32_t* count) override;
|
||||||
* sender.
|
ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
||||||
* @details It works identically to the other receiveMessage call, but in addition returns the
|
|
||||||
* sender's queue id.
|
|
||||||
* @param message A pointer to a message in which the received data is stored.
|
|
||||||
* @param receivedFrom A pointer to a queue id in which the sender's id is stored.
|
|
||||||
*/
|
|
||||||
ReturnValue_t receiveMessage(MessageQueueMessageIF* message, MessageQueueId_t* receivedFrom);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief This function reads available messages from the message queue.
|
|
||||||
* @details If data is available it is stored in the passed message pointer. The message's
|
|
||||||
* original content is overwritten and the sendFrom information is stored in
|
|
||||||
* the lastPartner attribute. Else, the lastPartner information remains untouched, the message's
|
|
||||||
* content is cleared and the function returns immediately.
|
|
||||||
* @param message A pointer to a message in which the received data is stored.
|
|
||||||
*/
|
|
||||||
ReturnValue_t receiveMessage(MessageQueueMessageIF* message);
|
|
||||||
/**
|
|
||||||
* Deletes all pending messages in the queue.
|
|
||||||
* @param count The number of flushed messages.
|
|
||||||
* @return RETURN_OK on success.
|
|
||||||
*/
|
|
||||||
ReturnValue_t flush(uint32_t* count);
|
|
||||||
/**
|
|
||||||
* @brief This method returns the message queue id of the last communication partner.
|
|
||||||
*/
|
|
||||||
MessageQueueId_t getLastPartner() const;
|
|
||||||
/**
|
|
||||||
* @brief This method returns the message queue id of this class's message queue.
|
|
||||||
*/
|
|
||||||
MessageQueueId_t getId() const;
|
|
||||||
/**
|
|
||||||
* \brief With the sendMessage call, a queue message is sent to a receiving queue.
|
|
||||||
* \details This method takes the message provided, adds the sentFrom information and passes
|
|
||||||
* it on to the destination provided with an operating system call. The OS's
|
|
||||||
* return value is returned.
|
|
||||||
* \param sendTo This parameter specifies the message queue id to send the message to.
|
|
||||||
* \param message This is a pointer to a previously created message, which is sent.
|
|
||||||
* \param sentFrom The sentFrom information can be set to inject the sender's queue id into the
|
|
||||||
* message. This variable is set to zero by default. \param ignoreFault If set to true, the
|
|
||||||
* internal software fault counter is not incremented if queue is full.
|
|
||||||
*/
|
|
||||||
virtual ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
|
||||||
MessageQueueId_t sentFrom = NO_QUEUE,
|
MessageQueueId_t sentFrom = NO_QUEUE,
|
||||||
bool ignoreFault = false);
|
bool ignoreFault = false) override;
|
||||||
/**
|
|
||||||
* \brief The sendToDefault method sends a queue message to the default destination.
|
|
||||||
* \details In all other aspects, it works identical to the sendMessage method.
|
|
||||||
* \param message This is a pointer to a previously created message, which is sent.
|
|
||||||
* \param sentFrom The sentFrom information can be set to inject the sender's queue id into the
|
|
||||||
* message. This variable is set to zero by default.
|
|
||||||
*/
|
|
||||||
virtual ReturnValue_t sendToDefaultFrom(MessageQueueMessageIF* message,
|
|
||||||
MessageQueueId_t sentFrom = NO_QUEUE,
|
|
||||||
bool ignoreFault = false);
|
|
||||||
/**
|
|
||||||
* \brief This method is a simple setter for the default destination.
|
|
||||||
*/
|
|
||||||
void setDefaultDestination(MessageQueueId_t defaultDestination);
|
|
||||||
/**
|
|
||||||
* \brief This method is a simple getter for the default destination.
|
|
||||||
*/
|
|
||||||
MessageQueueId_t getDefaultDestination() const;
|
|
||||||
|
|
||||||
bool isDefaultDestinationSet() const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
|
||||||
* @brief The class stores the queue id it got assigned from the operating system in this
|
|
||||||
* attribute. If initialization fails, the queue id is set to zero.
|
|
||||||
*/
|
|
||||||
MessageQueueId_t id;
|
|
||||||
/**
|
|
||||||
* @brief In this attribute, the queue id of the last communication partner is stored
|
|
||||||
* to allow for replying.
|
|
||||||
*/
|
|
||||||
MessageQueueId_t lastPartner;
|
|
||||||
/**
|
|
||||||
* @brief The message queue's name -a user specific information for the operating system- is
|
|
||||||
* generated automatically with the help of this static counter.
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* \brief This attribute stores a default destination to send messages to.
|
|
||||||
* \details It is stored to simplify sending to always-the-same receiver. The attribute may
|
|
||||||
* be set in the constructor or by a setter call to setDefaultDestination.
|
|
||||||
*/
|
|
||||||
MessageQueueId_t defaultDestination;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \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
|
||||||
|
@ -49,8 +49,9 @@ QueueFactory::QueueFactory() {}
|
|||||||
|
|
||||||
QueueFactory::~QueueFactory() {}
|
QueueFactory::~QueueFactory() {}
|
||||||
|
|
||||||
MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, size_t maxMessageSize) {
|
MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, size_t maxMessageSize,
|
||||||
return new MessageQueue(messageDepth, maxMessageSize);
|
MqArgs* args) {
|
||||||
|
return new MessageQueue(messageDepth, maxMessageSize, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) { delete queue; }
|
void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) { delete queue; }
|
||||||
|
@ -54,7 +54,7 @@ class Fuse : public SystemObject,
|
|||||||
|
|
||||||
ReturnValue_t check();
|
ReturnValue_t check();
|
||||||
uint8_t getFuseId() const;
|
uint8_t getFuseId() const;
|
||||||
ReturnValue_t initialize();
|
ReturnValue_t initialize() override;
|
||||||
DeviceList devices;
|
DeviceList devices;
|
||||||
ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize,
|
ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize,
|
||||||
SerializeIF::Endianness streamEndianness) const override;
|
SerializeIF::Endianness streamEndianness) const override;
|
||||||
|
@ -13,8 +13,6 @@ CService201HealthCommanding::CService201HealthCommanding(object_id_t objectId, u
|
|||||||
: CommandingServiceBase(objectId, apid, serviceId, numParallelCommands, commandTimeoutSeconds) {
|
: CommandingServiceBase(objectId, apid, serviceId, numParallelCommands, commandTimeoutSeconds) {
|
||||||
}
|
}
|
||||||
|
|
||||||
CService201HealthCommanding::~CService201HealthCommanding() {}
|
|
||||||
|
|
||||||
ReturnValue_t CService201HealthCommanding::isValidSubservice(uint8_t subservice) {
|
ReturnValue_t CService201HealthCommanding::isValidSubservice(uint8_t subservice) {
|
||||||
switch (subservice) {
|
switch (subservice) {
|
||||||
case (Subservice::COMMAND_SET_HEALTH):
|
case (Subservice::COMMAND_SET_HEALTH):
|
||||||
@ -43,8 +41,8 @@ ReturnValue_t CService201HealthCommanding::getMessageQueueAndObject(uint8_t subs
|
|||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t CService201HealthCommanding::checkInterfaceAndAcquireMessageQueue(
|
ReturnValue_t CService201HealthCommanding::checkInterfaceAndAcquireMessageQueue(
|
||||||
MessageQueueId_t *messageQueueToSet, object_id_t *objectId) {
|
MessageQueueId_t *messageQueueToSet, const object_id_t *objectId) {
|
||||||
HasHealthIF *destination = ObjectManager::instance()->get<HasHealthIF>(*objectId);
|
auto *destination = ObjectManager::instance()->get<HasHealthIF>(*objectId);
|
||||||
if (destination == nullptr) {
|
if (destination == nullptr) {
|
||||||
return CommandingServiceBase::INVALID_OBJECT;
|
return CommandingServiceBase::INVALID_OBJECT;
|
||||||
}
|
}
|
||||||
@ -77,6 +75,10 @@ ReturnValue_t CService201HealthCommanding::prepareCommand(CommandMessage *messag
|
|||||||
HealthMessage::setHealthMessage(message, HealthMessage::HEALTH_ANNOUNCE_ALL);
|
HealthMessage::setHealthMessage(message, HealthMessage::HEALTH_ANNOUNCE_ALL);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
default: {
|
||||||
|
// Should never happen, subservice was already checked
|
||||||
|
result = RETURN_FAILED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -95,10 +97,9 @@ ReturnValue_t CService201HealthCommanding::handleReply(const CommandMessage *rep
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Not used for now, health state already reported by event
|
// Not used for now, health state already reported by event
|
||||||
ReturnValue_t CService201HealthCommanding::prepareHealthSetReply(const CommandMessage *reply) {
|
[[maybe_unused]] ReturnValue_t CService201HealthCommanding::prepareHealthSetReply(const CommandMessage *reply) {
|
||||||
prepareHealthSetReply(reply);
|
auto health = static_cast<uint8_t>(HealthMessage::getHealth(reply));
|
||||||
uint8_t health = static_cast<uint8_t>(HealthMessage::getHealth(reply));
|
auto oldHealth = static_cast<uint8_t>(HealthMessage::getOldHealth(reply));
|
||||||
uint8_t oldHealth = static_cast<uint8_t>(HealthMessage::getOldHealth(reply));
|
|
||||||
HealthSetReply healthSetReply(health, oldHealth);
|
HealthSetReply healthSetReply(health, oldHealth);
|
||||||
return sendTmPacket(Subservice::REPLY_HEALTH_SET, &healthSetReply);
|
return sendTmPacket(Subservice::REPLY_HEALTH_SET, &healthSetReply);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#ifndef FSFW_PUS_CSERVICE201HEALTHCOMMANDING_H_
|
#ifndef FSFW_PUS_CSERVICE201HEALTHCOMMANDING_H_
|
||||||
#define FSFW_PUS_CSERVICE201HEALTHCOMMANDING_H_
|
#define FSFW_PUS_CSERVICE201HEALTHCOMMANDING_H_
|
||||||
|
|
||||||
#include "../tmtcservices/CommandingServiceBase.h"
|
#include "fsfw/tmtcservices/CommandingServiceBase.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Custom PUS service to set health of all objects
|
* @brief Custom PUS service to set health of all objects
|
||||||
@ -21,7 +21,7 @@ class CService201HealthCommanding : public CommandingServiceBase {
|
|||||||
public:
|
public:
|
||||||
CService201HealthCommanding(object_id_t objectId, uint16_t apid, uint8_t serviceId,
|
CService201HealthCommanding(object_id_t objectId, uint16_t apid, uint8_t serviceId,
|
||||||
uint8_t numParallelCommands = 4, uint16_t commandTimeoutSeconds = 60);
|
uint8_t numParallelCommands = 4, uint16_t commandTimeoutSeconds = 60);
|
||||||
virtual ~CService201HealthCommanding();
|
~CService201HealthCommanding() override = default;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/* CSB abstract function implementations */
|
/* CSB abstract function implementations */
|
||||||
@ -38,12 +38,10 @@ class CService201HealthCommanding : public CommandingServiceBase {
|
|||||||
bool *isStep) override;
|
bool *isStep) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ReturnValue_t checkAndAcquireTargetID(object_id_t *objectIdToSet, const uint8_t *tcData,
|
static ReturnValue_t checkInterfaceAndAcquireMessageQueue(MessageQueueId_t *MessageQueueToSet,
|
||||||
size_t tcDataLen);
|
const object_id_t *objectId);
|
||||||
ReturnValue_t checkInterfaceAndAcquireMessageQueue(MessageQueueId_t *MessageQueueToSet,
|
|
||||||
object_id_t *objectId);
|
|
||||||
|
|
||||||
ReturnValue_t prepareHealthSetReply(const CommandMessage *reply);
|
[[maybe_unused]] ReturnValue_t prepareHealthSetReply(const CommandMessage *reply);
|
||||||
|
|
||||||
enum Subservice {
|
enum Subservice {
|
||||||
//! [EXPORT] : [TC] Set health of target object
|
//! [EXPORT] : [TC] Set health of target object
|
||||||
|
@ -43,7 +43,7 @@ class Service3Housekeeping : public CommandingServiceBase, public AcceptsHkPacke
|
|||||||
CommandMessage* optionalNextCommand, object_id_t objectId,
|
CommandMessage* optionalNextCommand, object_id_t objectId,
|
||||||
bool* isStep) override;
|
bool* isStep) override;
|
||||||
|
|
||||||
virtual MessageQueueId_t getHkQueue() const;
|
virtual MessageQueueId_t getHkQueue() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum class Subservice {
|
enum class Subservice {
|
||||||
|
@ -30,11 +30,11 @@ ReturnValue_t Subsystem::checkSequence(HybridIterator<ModeListEntry> iter,
|
|||||||
return FALLBACK_SEQUENCE_DOES_NOT_EXIST;
|
return FALLBACK_SEQUENCE_DOES_NOT_EXIST;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iter.value == NULL) {
|
if (iter.value == nullptr) {
|
||||||
return NO_TARGET_TABLE;
|
return NO_TARGET_TABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (; iter.value != NULL; ++iter) {
|
for (; iter.value != nullptr; ++iter) {
|
||||||
if (!existsModeTable(iter->getTableId())) {
|
if (!existsModeTable(iter->getTableId())) {
|
||||||
return TABLE_DOES_NOT_EXIST;
|
return TABLE_DOES_NOT_EXIST;
|
||||||
} else {
|
} else {
|
||||||
@ -66,13 +66,18 @@ HybridIterator<ModeListEntry> Subsystem::getCurrentTable() {
|
|||||||
void Subsystem::performChildOperation() {
|
void Subsystem::performChildOperation() {
|
||||||
if (isInTransition) {
|
if (isInTransition) {
|
||||||
if (commandsOutstanding <= 0) { // all children of the current table were commanded and replied
|
if (commandsOutstanding <= 0) { // all children of the current table were commanded and replied
|
||||||
if (currentSequenceIterator.value == NULL) { // we're through with this sequence
|
if (currentSequenceIterator.value == nullptr) { // we're through with this sequence
|
||||||
if (checkStateAgainstTable(currentTargetTable, targetSubmode) == RETURN_OK) {
|
if (checkStateAgainstTable(currentTargetTable, targetSubmode) == RETURN_OK) {
|
||||||
setMode(targetMode, targetSubmode);
|
setMode(targetMode, targetSubmode);
|
||||||
isInTransition = false;
|
isInTransition = false;
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
transitionFailed(TARGET_TABLE_NOT_REACHED, getSequence(targetMode)->getTableId());
|
Mode_t tableId = 0;
|
||||||
|
auto seq = getSequence(targetMode);
|
||||||
|
if (seq.value != nullptr) {
|
||||||
|
tableId = seq->getTableId();
|
||||||
|
}
|
||||||
|
transitionFailed(TARGET_TABLE_NOT_REACHED, tableId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -248,10 +253,13 @@ ReturnValue_t Subsystem::handleCommandMessage(CommandMessage *message) {
|
|||||||
case ModeSequenceMessage::READ_TABLE: {
|
case ModeSequenceMessage::READ_TABLE: {
|
||||||
ReturnValue_t result;
|
ReturnValue_t result;
|
||||||
Mode_t table = ModeSequenceMessage::getSequenceId(message);
|
Mode_t table = ModeSequenceMessage::getSequenceId(message);
|
||||||
EntryPointer *entry = NULL;
|
EntryPointer *entry = nullptr;
|
||||||
result = modeTables.find(table, &entry);
|
result = modeTables.find(table, &entry);
|
||||||
if (result != RETURN_OK) {
|
if (result != RETURN_OK or entry == nullptr) {
|
||||||
replyToCommand(result, 0);
|
replyToCommand(result, 0);
|
||||||
|
if (entry == nullptr) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SerializeIF *elements[2];
|
SerializeIF *elements[2];
|
||||||
@ -299,6 +307,11 @@ void Subsystem::replyToCommand(ReturnValue_t status, uint32_t parameter) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ReturnValue_t Subsystem::addSequence(SequenceEntry sequence) {
|
||||||
|
return addSequence(sequence.table, sequence.mode, sequence.fallbackMode, sequence.inStore,
|
||||||
|
sequence.preInit);
|
||||||
|
}
|
||||||
|
|
||||||
ReturnValue_t Subsystem::addSequence(ArrayList<ModeListEntry> *sequence, Mode_t id,
|
ReturnValue_t Subsystem::addSequence(ArrayList<ModeListEntry> *sequence, Mode_t id,
|
||||||
Mode_t fallbackSequence, bool inStore, bool preInit) {
|
Mode_t fallbackSequence, bool inStore, bool preInit) {
|
||||||
ReturnValue_t result;
|
ReturnValue_t result;
|
||||||
@ -342,6 +355,10 @@ ReturnValue_t Subsystem::addSequence(ArrayList<ModeListEntry> *sequence, Mode_t
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ReturnValue_t Subsystem::addTable(TableEntry table) {
|
||||||
|
return addTable(table.table, table.mode, table.inStore, table.preInit);
|
||||||
|
}
|
||||||
|
|
||||||
ReturnValue_t Subsystem::addTable(ArrayList<ModeListEntry> *table, Mode_t id, bool inStore,
|
ReturnValue_t Subsystem::addTable(ArrayList<ModeListEntry> *table, Mode_t id, bool inStore,
|
||||||
bool preInit) {
|
bool preInit) {
|
||||||
ReturnValue_t result;
|
ReturnValue_t result;
|
||||||
@ -450,6 +467,7 @@ ReturnValue_t Subsystem::initialize() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mode = initialMode;
|
mode = initialMode;
|
||||||
|
submode = initSubmode;
|
||||||
|
|
||||||
return RETURN_OK;
|
return RETURN_OK;
|
||||||
}
|
}
|
||||||
@ -587,7 +605,10 @@ ReturnValue_t Subsystem::checkObjectConnections() {
|
|||||||
return RETURN_OK;
|
return RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Subsystem::setInitialMode(Mode_t mode) { initialMode = mode; }
|
void Subsystem::setInitialMode(Mode_t mode, Submode_t submode) {
|
||||||
|
this->initialMode = mode;
|
||||||
|
this->initSubmode = submode;
|
||||||
|
}
|
||||||
|
|
||||||
void Subsystem::cantKeepMode() {
|
void Subsystem::cantKeepMode() {
|
||||||
ReturnValue_t result;
|
ReturnValue_t result;
|
||||||
|
@ -1,16 +1,37 @@
|
|||||||
#ifndef FSFW_SUBSYSTEM_SUBSYSTEM_H_
|
#ifndef FSFW_SUBSYSTEM_SUBSYSTEM_H_
|
||||||
#define FSFW_SUBSYSTEM_SUBSYSTEM_H_
|
#define FSFW_SUBSYSTEM_SUBSYSTEM_H_
|
||||||
|
|
||||||
#include <FSFWConfig.h>
|
|
||||||
|
|
||||||
#include "../container/FixedArrayList.h"
|
#include "../container/FixedArrayList.h"
|
||||||
#include "../container/FixedMap.h"
|
#include "../container/FixedMap.h"
|
||||||
#include "../container/HybridIterator.h"
|
#include "../container/HybridIterator.h"
|
||||||
#include "../container/SinglyLinkedList.h"
|
#include "../container/SinglyLinkedList.h"
|
||||||
#include "../serialize/SerialArrayListAdapter.h"
|
#include "../serialize/SerialArrayListAdapter.h"
|
||||||
#include "SubsystemBase.h"
|
#include "SubsystemBase.h"
|
||||||
|
#include "fsfw/FSFW.h"
|
||||||
#include "modes/ModeDefinitions.h"
|
#include "modes/ModeDefinitions.h"
|
||||||
|
|
||||||
|
struct TableSequenceBase {
|
||||||
|
public:
|
||||||
|
TableSequenceBase(Mode_t mode, ArrayList<ModeListEntry> *table) : mode(mode), table(table){};
|
||||||
|
Mode_t mode;
|
||||||
|
ArrayList<ModeListEntry> *table;
|
||||||
|
bool inStore = false;
|
||||||
|
bool preInit = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TableEntry : public TableSequenceBase {
|
||||||
|
public:
|
||||||
|
TableEntry(Mode_t mode, ArrayList<ModeListEntry> *table) : TableSequenceBase(mode, table){};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SequenceEntry : public TableSequenceBase {
|
||||||
|
public:
|
||||||
|
SequenceEntry(Mode_t mode, ArrayList<ModeListEntry> *table, Mode_t fallbackMode)
|
||||||
|
: TableSequenceBase(mode, table), fallbackMode(fallbackMode) {}
|
||||||
|
|
||||||
|
Mode_t fallbackMode;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief TODO: documentation missing
|
* @brief TODO: documentation missing
|
||||||
* @details
|
* @details
|
||||||
@ -45,13 +66,15 @@ class Subsystem : public SubsystemBase, public HasModeSequenceIF {
|
|||||||
uint32_t maxNumberOfTables);
|
uint32_t maxNumberOfTables);
|
||||||
virtual ~Subsystem();
|
virtual ~Subsystem();
|
||||||
|
|
||||||
|
ReturnValue_t addSequence(SequenceEntry sequence);
|
||||||
ReturnValue_t addSequence(ArrayList<ModeListEntry> *sequence, Mode_t id, Mode_t fallbackSequence,
|
ReturnValue_t addSequence(ArrayList<ModeListEntry> *sequence, Mode_t id, Mode_t fallbackSequence,
|
||||||
bool inStore = true, bool preInit = true);
|
bool inStore = true, bool preInit = true);
|
||||||
|
|
||||||
|
ReturnValue_t addTable(TableEntry table);
|
||||||
ReturnValue_t addTable(ArrayList<ModeListEntry> *table, Mode_t id, bool inStore = true,
|
ReturnValue_t addTable(ArrayList<ModeListEntry> *table, Mode_t id, bool inStore = true,
|
||||||
bool preInit = true);
|
bool preInit = true);
|
||||||
|
|
||||||
void setInitialMode(Mode_t mode);
|
void setInitialMode(Mode_t mode, Submode_t submode = SUBMODE_NONE);
|
||||||
|
|
||||||
virtual ReturnValue_t initialize() override;
|
virtual ReturnValue_t initialize() override;
|
||||||
|
|
||||||
@ -90,6 +113,7 @@ class Subsystem : public SubsystemBase, public HasModeSequenceIF {
|
|||||||
Submode_t targetSubmode;
|
Submode_t targetSubmode;
|
||||||
|
|
||||||
Mode_t initialMode = 0;
|
Mode_t initialMode = 0;
|
||||||
|
Submode_t initSubmode = SUBMODE_NONE;
|
||||||
|
|
||||||
HybridIterator<ModeListEntry> currentSequenceIterator;
|
HybridIterator<ModeListEntry> currentSequenceIterator;
|
||||||
|
|
||||||
@ -127,18 +151,18 @@ class Subsystem : public SubsystemBase, public HasModeSequenceIF {
|
|||||||
|
|
||||||
ReturnValue_t deleteTable(Mode_t id);
|
ReturnValue_t deleteTable(Mode_t id);
|
||||||
|
|
||||||
virtual void performChildOperation();
|
virtual void performChildOperation() override;
|
||||||
|
|
||||||
virtual ReturnValue_t handleCommandMessage(CommandMessage *message);
|
virtual ReturnValue_t handleCommandMessage(CommandMessage *message) override;
|
||||||
|
|
||||||
bool isFallbackSequence(Mode_t SequenceId);
|
bool isFallbackSequence(Mode_t SequenceId);
|
||||||
|
|
||||||
bool isTableUsed(Mode_t tableId);
|
bool isTableUsed(Mode_t tableId);
|
||||||
|
|
||||||
virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
|
virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
|
||||||
uint32_t *msToReachTheMode);
|
uint32_t *msToReachTheMode) override;
|
||||||
|
|
||||||
virtual void startTransition(Mode_t mode, Submode_t submode);
|
virtual void startTransition(Mode_t mode, Submode_t submode) override;
|
||||||
|
|
||||||
void sendSerializablesAsCommandMessage(Command_t command, SerializeIF **elements, uint8_t count);
|
void sendSerializablesAsCommandMessage(Command_t command, SerializeIF **elements, uint8_t count);
|
||||||
|
|
||||||
|
@ -123,15 +123,15 @@ class SubsystemBase : public SystemObject,
|
|||||||
virtual void performChildOperation() = 0;
|
virtual void performChildOperation() = 0;
|
||||||
|
|
||||||
virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
|
virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
|
||||||
uint32_t *msToReachTheMode) = 0;
|
uint32_t *msToReachTheMode) override = 0;
|
||||||
|
|
||||||
virtual void startTransition(Mode_t mode, Submode_t submode) = 0;
|
virtual void startTransition(Mode_t mode, Submode_t submode) override = 0;
|
||||||
|
|
||||||
virtual void getMode(Mode_t *mode, Submode_t *submode);
|
virtual void getMode(Mode_t *mode, Submode_t *submode) override;
|
||||||
|
|
||||||
virtual void setToExternalControl();
|
virtual void setToExternalControl() override;
|
||||||
|
|
||||||
virtual void announceMode(bool recursive);
|
virtual void announceMode(bool recursive) override;
|
||||||
|
|
||||||
virtual void modeChanged();
|
virtual void modeChanged();
|
||||||
};
|
};
|
||||||
|
@ -6,10 +6,6 @@
|
|||||||
|
|
||||||
#include "fsfw/FSFW.h"
|
#include "fsfw/FSFW.h"
|
||||||
|
|
||||||
CCSDSTime::CCSDSTime() {}
|
|
||||||
|
|
||||||
CCSDSTime::~CCSDSTime() {}
|
|
||||||
|
|
||||||
ReturnValue_t CCSDSTime::convertToCcsds(Ccs_seconds* to, const Clock::TimeOfDay_t* from) {
|
ReturnValue_t CCSDSTime::convertToCcsds(Ccs_seconds* to, const Clock::TimeOfDay_t* from) {
|
||||||
ReturnValue_t result = checkTimeOfDay(from);
|
ReturnValue_t result = checkTimeOfDay(from);
|
||||||
if (result != RETURN_OK) {
|
if (result != RETURN_OK) {
|
||||||
@ -91,7 +87,7 @@ ReturnValue_t CCSDSTime::convertFromCDS(Clock::TimeOfDay_t* to, const uint8_t* f
|
|||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
return convertTimevalToTimeOfDay(to, &time);
|
return Clock::convertTimevalToTimeOfDay(&time, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t CCSDSTime::convertFromCCS(Clock::TimeOfDay_t* to, const uint8_t* from,
|
ReturnValue_t CCSDSTime::convertFromCCS(Clock::TimeOfDay_t* to, const uint8_t* from,
|
||||||
@ -428,7 +424,7 @@ ReturnValue_t CCSDSTime::convertFromCUC(timeval* to, const uint8_t* from, size_t
|
|||||||
from++;
|
from++;
|
||||||
ReturnValue_t result = convertFromCUC(to, pField, from, foundLength, maxLength - 1);
|
ReturnValue_t result = convertFromCUC(to, pField, from, foundLength, maxLength - 1);
|
||||||
if (result == HasReturnvaluesIF::RETURN_OK) {
|
if (result == HasReturnvaluesIF::RETURN_OK) {
|
||||||
if (foundLength != NULL) {
|
if (foundLength != nullptr) {
|
||||||
*foundLength += 1;
|
*foundLength += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -489,11 +485,6 @@ ReturnValue_t CCSDSTime::checkTimeOfDay(const Clock::TimeOfDay_t* time) {
|
|||||||
return RETURN_OK;
|
return RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t CCSDSTime::convertTimevalToTimeOfDay(Clock::TimeOfDay_t* to, timeval* from) {
|
|
||||||
// This is rather tricky. Implement only if needed. Also, if so, move to OSAL.
|
|
||||||
return UNSUPPORTED_TIME_FORMAT;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t CCSDSTime::convertFromCDS(timeval* to, const uint8_t* from, size_t* foundLength,
|
ReturnValue_t CCSDSTime::convertFromCDS(timeval* to, const uint8_t* from, size_t* foundLength,
|
||||||
size_t maxLength) {
|
size_t maxLength) {
|
||||||
uint8_t pField = *from;
|
uint8_t pField = *from;
|
||||||
@ -583,7 +574,7 @@ ReturnValue_t CCSDSTime::convertFromCDS(Clock::TimeOfDay_t* to, const CCSDSTime:
|
|||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
return CCSDSTime::convertTimevalToTimeOfDay(to, &tempTimeval);
|
return Clock::convertTimevalToTimeOfDay(&tempTimeval, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t CCSDSTime::convertFromCUC(timeval* to, uint8_t pField, const uint8_t* from,
|
ReturnValue_t CCSDSTime::convertFromCUC(timeval* to, uint8_t pField, const uint8_t* from,
|
||||||
@ -593,18 +584,18 @@ ReturnValue_t CCSDSTime::convertFromCUC(timeval* to, uint8_t pField, const uint8
|
|||||||
uint8_t nCoarse = ((pField & 0b1100) >> 2) + 1;
|
uint8_t nCoarse = ((pField & 0b1100) >> 2) + 1;
|
||||||
uint8_t nFine = (pField & 0b11);
|
uint8_t nFine = (pField & 0b11);
|
||||||
size_t totalLength = nCoarse + nFine;
|
size_t totalLength = nCoarse + nFine;
|
||||||
if (foundLength != NULL) {
|
if (foundLength != nullptr) {
|
||||||
*foundLength = totalLength;
|
*foundLength = totalLength;
|
||||||
}
|
}
|
||||||
if (totalLength > maxLength) {
|
if (totalLength > maxLength) {
|
||||||
return LENGTH_MISMATCH;
|
return LENGTH_MISMATCH;
|
||||||
}
|
}
|
||||||
for (int count = 0; count < nCoarse; count++) {
|
for (int count = nCoarse; count > 0; count--) {
|
||||||
secs += *from << ((nCoarse * 8 - 8) * (1 + count));
|
secs += *from << (count * 8 - 8);
|
||||||
from++;
|
from++;
|
||||||
}
|
}
|
||||||
for (int count = 0; count < nFine; count++) {
|
for (int count = nFine; count > 0; count--) {
|
||||||
subSeconds += *from << ((nFine * 8 - 8) * (1 + count));
|
subSeconds += *from << (count * 8 - 8);
|
||||||
from++;
|
from++;
|
||||||
}
|
}
|
||||||
// Move to POSIX epoch.
|
// Move to POSIX epoch.
|
||||||
|
@ -161,18 +161,37 @@ class CCSDSTime : public HasReturnvaluesIF {
|
|||||||
*/
|
*/
|
||||||
static ReturnValue_t convertFromCcsds(timeval *to, uint8_t const *from, size_t *foundLength,
|
static ReturnValue_t convertFromCcsds(timeval *to, uint8_t const *from, size_t *foundLength,
|
||||||
size_t maxLength);
|
size_t maxLength);
|
||||||
|
/**
|
||||||
|
* @brief Currently unsupported conversion due to leapseconds
|
||||||
|
*
|
||||||
|
* @param to Time Of Day (UTC)
|
||||||
|
* @param from Buffer to take the CUC from
|
||||||
|
* @param length Length of buffer
|
||||||
|
* @return ReturnValue_t UNSUPPORTED_TIME_FORMAT in any case ATM
|
||||||
|
*/
|
||||||
static ReturnValue_t convertFromCUC(Clock::TimeOfDay_t *to, uint8_t const *from, uint8_t length);
|
static ReturnValue_t convertFromCUC(Clock::TimeOfDay_t *to, uint8_t const *from, uint8_t length);
|
||||||
|
/**
|
||||||
|
* @brief Converts from CCSDS CUC to timeval
|
||||||
|
*
|
||||||
|
* If input is CCSDS Epoch this is TAI! -> No leapsecond support.
|
||||||
|
*
|
||||||
|
* Currently, it only supports seconds + 2 Byte Subseconds (1/65536 seconds)
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param to Timeval to write the result to
|
||||||
|
* @param from Buffer to read from
|
||||||
|
* @param foundLength Length found by this function (can be nullptr if unused)
|
||||||
|
* @param maxLength Max length of the buffer to be read
|
||||||
|
* @return ReturnValue_t - RETURN_OK if successful
|
||||||
|
* - LENGTH_MISMATCH if expected length is larger than maxLength
|
||||||
|
*/
|
||||||
static ReturnValue_t convertFromCUC(timeval *to, uint8_t const *from, size_t *foundLength,
|
static ReturnValue_t convertFromCUC(timeval *to, uint8_t const *from, size_t *foundLength,
|
||||||
size_t maxLength);
|
size_t maxLength);
|
||||||
|
|
||||||
static ReturnValue_t convertFromCUC(timeval *to, uint8_t pField, uint8_t const *from,
|
static ReturnValue_t convertFromCUC(timeval *to, uint8_t pField, uint8_t const *from,
|
||||||
size_t *foundLength, size_t maxLength);
|
size_t *foundLength, size_t maxLength);
|
||||||
|
|
||||||
static ReturnValue_t convertFromCCS(timeval *to, uint8_t const *from, size_t *foundLength,
|
static ReturnValue_t convertFromCCS(timeval *to, uint8_t const *from, size_t *foundLength,
|
||||||
size_t maxLength);
|
size_t maxLength);
|
||||||
|
|
||||||
static ReturnValue_t convertFromCCS(timeval *to, uint8_t pField, uint8_t const *from,
|
static ReturnValue_t convertFromCCS(timeval *to, uint8_t pField, uint8_t const *from,
|
||||||
size_t *foundLength, size_t maxLength);
|
size_t *foundLength, size_t maxLength);
|
||||||
|
|
||||||
@ -192,8 +211,8 @@ class CCSDSTime : public HasReturnvaluesIF {
|
|||||||
static uint32_t subsecondsToMicroseconds(uint16_t subseconds);
|
static uint32_t subsecondsToMicroseconds(uint16_t subseconds);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CCSDSTime();
|
CCSDSTime(){};
|
||||||
virtual ~CCSDSTime();
|
virtual ~CCSDSTime(){};
|
||||||
/**
|
/**
|
||||||
* checks a ccs time stream for validity
|
* checks a ccs time stream for validity
|
||||||
*
|
*
|
||||||
@ -223,7 +242,6 @@ class CCSDSTime : public HasReturnvaluesIF {
|
|||||||
uint8_t *day);
|
uint8_t *day);
|
||||||
|
|
||||||
static bool isLeapYear(uint32_t year);
|
static bool isLeapYear(uint32_t year);
|
||||||
static ReturnValue_t convertTimevalToTimeOfDay(Clock::TimeOfDay_t *to, timeval *from);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* FSFW_TIMEMANAGER_CCSDSTIME_H_ */
|
#endif /* FSFW_TIMEMANAGER_CCSDSTIME_H_ */
|
||||||
|
@ -99,6 +99,13 @@ class Clock {
|
|||||||
*/
|
*/
|
||||||
static ReturnValue_t getDateAndTime(TimeOfDay_t *time);
|
static ReturnValue_t getDateAndTime(TimeOfDay_t *time);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert to time of day struct given the POSIX timeval struct
|
||||||
|
* @param from
|
||||||
|
* @param to
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
static ReturnValue_t convertTimevalToTimeOfDay(const timeval *from, TimeOfDay_t *to);
|
||||||
/**
|
/**
|
||||||
* Converts a time of day struct to POSIX seconds.
|
* Converts a time of day struct to POSIX seconds.
|
||||||
* @param time The time of day as input
|
* @param time The time of day as input
|
||||||
@ -166,6 +173,7 @@ class Clock {
|
|||||||
|
|
||||||
static MutexIF *timeMutex;
|
static MutexIF *timeMutex;
|
||||||
static uint16_t leapSeconds;
|
static uint16_t leapSeconds;
|
||||||
|
static bool leapSecondsSet;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* FSFW_TIMEMANAGER_CLOCK_H_ */
|
#endif /* FSFW_TIMEMANAGER_CLOCK_H_ */
|
||||||
|
@ -1,6 +1,12 @@
|
|||||||
|
#include <ctime>
|
||||||
|
|
||||||
#include "fsfw/ipc/MutexGuard.h"
|
#include "fsfw/ipc/MutexGuard.h"
|
||||||
#include "fsfw/timemanager/Clock.h"
|
#include "fsfw/timemanager/Clock.h"
|
||||||
|
|
||||||
|
uint16_t Clock::leapSeconds = 0;
|
||||||
|
MutexIF* Clock::timeMutex = nullptr;
|
||||||
|
bool Clock::leapSecondsSet = false;
|
||||||
|
|
||||||
ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) {
|
ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) {
|
||||||
uint16_t leapSeconds;
|
uint16_t leapSeconds;
|
||||||
ReturnValue_t result = getLeapSeconds(&leapSeconds);
|
ReturnValue_t result = getLeapSeconds(&leapSeconds);
|
||||||
@ -27,12 +33,16 @@ ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) {
|
|||||||
MutexGuard helper(timeMutex);
|
MutexGuard helper(timeMutex);
|
||||||
|
|
||||||
leapSeconds = leapSeconds_;
|
leapSeconds = leapSeconds_;
|
||||||
|
leapSecondsSet = true;
|
||||||
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) {
|
ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) {
|
||||||
if (timeMutex == nullptr) {
|
if (not leapSecondsSet) {
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
if (checkOrCreateClockMutex() != HasReturnvaluesIF::RETURN_OK) {
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
}
|
}
|
||||||
MutexGuard helper(timeMutex);
|
MutexGuard helper(timeMutex);
|
||||||
@ -42,6 +52,29 @@ ReturnValue_t Clock::getLeapSeconds(uint16_t *leapSeconds_) {
|
|||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ReturnValue_t Clock::convertTimevalToTimeOfDay(const timeval* from, TimeOfDay_t* to) {
|
||||||
|
struct tm* timeInfo;
|
||||||
|
// According to https://en.cppreference.com/w/c/chrono/gmtime, the implementation of gmtime_s
|
||||||
|
// in the Windows CRT is incompatible with the C standard but this should not be an issue for
|
||||||
|
// this implementation
|
||||||
|
ReturnValue_t result = checkOrCreateClockMutex();
|
||||||
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
MutexGuard helper(timeMutex);
|
||||||
|
// gmtime writes its output in a global buffer which is not Thread Safe
|
||||||
|
// Therefore we have to use a Mutex here
|
||||||
|
timeInfo = gmtime(&from->tv_sec);
|
||||||
|
to->year = timeInfo->tm_year + 1900;
|
||||||
|
to->month = timeInfo->tm_mon + 1;
|
||||||
|
to->day = timeInfo->tm_mday;
|
||||||
|
to->hour = timeInfo->tm_hour;
|
||||||
|
to->minute = timeInfo->tm_min;
|
||||||
|
to->second = timeInfo->tm_sec;
|
||||||
|
to->usecond = from->tv_usec;
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
ReturnValue_t Clock::checkOrCreateClockMutex() {
|
ReturnValue_t Clock::checkOrCreateClockMutex() {
|
||||||
if (timeMutex == nullptr) {
|
if (timeMutex == nullptr) {
|
||||||
MutexFactory* mutexFactory = MutexFactory::instance();
|
MutexFactory* mutexFactory = MutexFactory::instance();
|
||||||
|
@ -19,8 +19,8 @@ SpacePacket::SpacePacket(uint16_t packetDataLength, bool isTelecommand, uint16_t
|
|||||||
SpacePacket::~SpacePacket(void) {}
|
SpacePacket::~SpacePacket(void) {}
|
||||||
|
|
||||||
bool SpacePacket::addWholeData(const uint8_t* p_Data, uint32_t packet_size) {
|
bool SpacePacket::addWholeData(const uint8_t* p_Data, uint32_t packet_size) {
|
||||||
if (packet_size <= sizeof(this->data)) {
|
if (packet_size <= sizeof(this->localData)) {
|
||||||
memcpy(&this->localData.byteStream, p_Data, packet_size);
|
memcpy(this->localData.byteStream, p_Data, packet_size);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
@ -95,7 +95,7 @@ class CommandingServiceBase : public SystemObject,
|
|||||||
*/
|
*/
|
||||||
virtual ReturnValue_t performOperation(uint8_t opCode) override;
|
virtual ReturnValue_t performOperation(uint8_t opCode) override;
|
||||||
|
|
||||||
virtual uint16_t getIdentifier();
|
virtual uint16_t getIdentifier() override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the requestQueue MessageQueueId_t
|
* Returns the requestQueue MessageQueueId_t
|
||||||
@ -104,7 +104,7 @@ class CommandingServiceBase : public SystemObject,
|
|||||||
*
|
*
|
||||||
* @return requestQueue messageQueueId_t
|
* @return requestQueue messageQueueId_t
|
||||||
*/
|
*/
|
||||||
virtual MessageQueueId_t getRequestQueue();
|
virtual MessageQueueId_t getRequestQueue() override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the commandQueue MessageQueueId_t
|
* Returns the commandQueue MessageQueueId_t
|
||||||
@ -166,7 +166,7 @@ class CommandingServiceBase : public SystemObject,
|
|||||||
* @param objectId Target object ID
|
* @param objectId Target object ID
|
||||||
* @return
|
* @return
|
||||||
* - @c RETURN_OK to generate a verification start message
|
* - @c RETURN_OK to generate a verification start message
|
||||||
* - @c EXECUTION_COMPELTE Fire-and-forget command. Generate a completion
|
* - @c EXECUTION_COMPLETE Fire-and-forget command. Generate a completion
|
||||||
* verification message.
|
* verification message.
|
||||||
* - @c Anything else rejects the packets and generates a start failure
|
* - @c Anything else rejects the packets and generates a start failure
|
||||||
* verification.
|
* verification.
|
||||||
|
@ -2,8 +2,6 @@
|
|||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
#include "fsfw/FSFWVersion.h"
|
|
||||||
|
|
||||||
#ifdef major
|
#ifdef major
|
||||||
#undef major
|
#undef major
|
||||||
#endif
|
#endif
|
||||||
@ -12,19 +10,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 +34,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,9 +57,12 @@ class Version {
|
|||||||
void getVersion(char* str, size_t maxLen) const;
|
void getVersion(char* str, size_t maxLen) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace fsfw {
|
extern const int FSFW_VERSION_MAJOR;
|
||||||
|
extern const int FSFW_VERSION_MINOR;
|
||||||
|
extern const int FSFW_VERSION_REVISION;
|
||||||
|
extern const char FSFW_VCS_INFO[];
|
||||||
|
|
||||||
extern const Version FSFW_VERSION;
|
extern const fsfw::Version FSFW_VERSION;
|
||||||
|
|
||||||
} // namespace fsfw
|
} // namespace fsfw
|
||||||
|
|
||||||
|
10
src/fsfw/versionAutogen.cpp
Normal file
10
src/fsfw/versionAutogen.cpp
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#include "version.h"
|
||||||
|
|
||||||
|
namespace fsfw {
|
||||||
|
|
||||||
|
const int FSFW_VERSION_MAJOR = 4;
|
||||||
|
const int FSFW_VERSION_MINOR = 0;
|
||||||
|
const int FSFW_VERSION_REVISION = 0;
|
||||||
|
const char FSFW_VCS_INFO[] = "292-g42ac1af4";
|
||||||
|
|
||||||
|
};
|
@ -21,8 +21,10 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") {
|
|||||||
REQUIRE(poolOwner->initializeHkManager() == retval::CATCH_OK);
|
REQUIRE(poolOwner->initializeHkManager() == retval::CATCH_OK);
|
||||||
REQUIRE(poolOwner->initializeHkManagerAfterTaskCreation() == retval::CATCH_OK);
|
REQUIRE(poolOwner->initializeHkManagerAfterTaskCreation() == retval::CATCH_OK);
|
||||||
|
|
||||||
MessageQueueMockBase* mqMock = poolOwner->getMockQueueHandle();
|
MessageQueueMockBase* poolOwnerMock = poolOwner->getMockQueueHandle();
|
||||||
REQUIRE(mqMock != nullptr);
|
REQUIRE(poolOwnerMock != nullptr);
|
||||||
|
|
||||||
|
// MessageQueueIF* hkCommander = QueueFactory::instance()->createMessageQueue();
|
||||||
CommandMessage messageSent;
|
CommandMessage messageSent;
|
||||||
uint8_t messagesSent = 0;
|
uint8_t messagesSent = 0;
|
||||||
|
|
||||||
@ -41,9 +43,9 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") {
|
|||||||
poolOwner->dataset.setChanged(true);
|
poolOwner->dataset.setChanged(true);
|
||||||
/* Now the update message should be generated. */
|
/* Now the update message should be generated. */
|
||||||
REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK);
|
REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK);
|
||||||
REQUIRE(mqMock->wasMessageSent() == true);
|
REQUIRE(poolOwnerMock->wasMessageSent() == true);
|
||||||
|
|
||||||
REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK);
|
REQUIRE(poolOwnerMock->receiveMessage(&messageSent) == retval::CATCH_OK);
|
||||||
CHECK(messageSent.getCommand() ==
|
CHECK(messageSent.getCommand() ==
|
||||||
static_cast<int>(HousekeepingMessage::UPDATE_NOTIFICATION_SET));
|
static_cast<int>(HousekeepingMessage::UPDATE_NOTIFICATION_SET));
|
||||||
|
|
||||||
@ -53,9 +55,9 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") {
|
|||||||
poolOwner->dataset.setChanged(true);
|
poolOwner->dataset.setChanged(true);
|
||||||
REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK);
|
REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK);
|
||||||
|
|
||||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||||
CHECK(messagesSent == 1);
|
CHECK(messagesSent == 1);
|
||||||
REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK);
|
REQUIRE(poolOwnerMock->receiveMessage(&messageSent) == retval::CATCH_OK);
|
||||||
CHECK(messageSent.getCommand() ==
|
CHECK(messageSent.getCommand() ==
|
||||||
static_cast<int>(HousekeepingMessage::UPDATE_NOTIFICATION_SET));
|
static_cast<int>(HousekeepingMessage::UPDATE_NOTIFICATION_SET));
|
||||||
|
|
||||||
@ -63,15 +65,15 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") {
|
|||||||
REQUIRE(poolOwner->subscribeWrapperSetUpdateHk() == retval::CATCH_OK);
|
REQUIRE(poolOwner->subscribeWrapperSetUpdateHk() == retval::CATCH_OK);
|
||||||
poolOwner->dataset.setChanged(true);
|
poolOwner->dataset.setChanged(true);
|
||||||
REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK);
|
REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK);
|
||||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||||
CHECK(messagesSent == 2);
|
CHECK(messagesSent == 2);
|
||||||
/* first message sent should be the update notification, considering
|
/* first message sent should be the update notification, considering
|
||||||
the internal list is a vector checked in insertion order. */
|
the internal list is a vector checked in insertion order. */
|
||||||
REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK);
|
REQUIRE(poolOwnerMock->receiveMessage(&messageSent) == retval::CATCH_OK);
|
||||||
CHECK(messageSent.getCommand() ==
|
CHECK(messageSent.getCommand() ==
|
||||||
static_cast<int>(HousekeepingMessage::UPDATE_NOTIFICATION_SET));
|
static_cast<int>(HousekeepingMessage::UPDATE_NOTIFICATION_SET));
|
||||||
|
|
||||||
REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK);
|
REQUIRE(poolOwnerMock->receiveMessage(&messageSent) == retval::CATCH_OK);
|
||||||
CHECK(messageSent.getCommand() == static_cast<int>(HousekeepingMessage::HK_REPORT));
|
CHECK(messageSent.getCommand() == static_cast<int>(HousekeepingMessage::HK_REPORT));
|
||||||
/* Clear message to avoid memory leak, our mock won't do it for us (yet) */
|
/* Clear message to avoid memory leak, our mock won't do it for us (yet) */
|
||||||
CommandMessageCleaner::clearCommandMessage(&messageSent);
|
CommandMessageCleaner::clearCommandMessage(&messageSent);
|
||||||
@ -99,9 +101,9 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") {
|
|||||||
|
|
||||||
/* Trigger generation of snapshot */
|
/* Trigger generation of snapshot */
|
||||||
REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK);
|
REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK);
|
||||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||||
CHECK(messagesSent == 1);
|
CHECK(messagesSent == 1);
|
||||||
REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK);
|
REQUIRE(poolOwnerMock->receiveMessage(&messageSent) == retval::CATCH_OK);
|
||||||
/* Check that snapshot was generated */
|
/* Check that snapshot was generated */
|
||||||
CHECK(messageSent.getCommand() == static_cast<int>(HousekeepingMessage::UPDATE_SNAPSHOT_SET));
|
CHECK(messageSent.getCommand() == static_cast<int>(HousekeepingMessage::UPDATE_SNAPSHOT_SET));
|
||||||
/* Now we deserialize the snapshot into a new dataset instance */
|
/* Now we deserialize the snapshot into a new dataset instance */
|
||||||
@ -162,12 +164,12 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") {
|
|||||||
REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK);
|
REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK);
|
||||||
|
|
||||||
/* Check update snapshot was sent. */
|
/* Check update snapshot was sent. */
|
||||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||||
CHECK(messagesSent == 1);
|
CHECK(messagesSent == 1);
|
||||||
|
|
||||||
/* Should have been reset. */
|
/* Should have been reset. */
|
||||||
CHECK(poolVar->hasChanged() == false);
|
CHECK(poolVar->hasChanged() == false);
|
||||||
REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK);
|
REQUIRE(poolOwnerMock->receiveMessage(&messageSent) == retval::CATCH_OK);
|
||||||
CHECK(messageSent.getCommand() ==
|
CHECK(messageSent.getCommand() ==
|
||||||
static_cast<int>(HousekeepingMessage::UPDATE_SNAPSHOT_VARIABLE));
|
static_cast<int>(HousekeepingMessage::UPDATE_SNAPSHOT_VARIABLE));
|
||||||
/* Now we deserialize the snapshot into a new dataset instance */
|
/* Now we deserialize the snapshot into a new dataset instance */
|
||||||
@ -209,11 +211,11 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") {
|
|||||||
REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK);
|
REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK);
|
||||||
|
|
||||||
/* Check update notification was sent. */
|
/* Check update notification was sent. */
|
||||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||||
CHECK(messagesSent == 1);
|
CHECK(messagesSent == 1);
|
||||||
/* Should have been reset. */
|
/* Should have been reset. */
|
||||||
CHECK(poolVar->hasChanged() == false);
|
CHECK(poolVar->hasChanged() == false);
|
||||||
REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK);
|
REQUIRE(poolOwnerMock->receiveMessage(&messageSent) == retval::CATCH_OK);
|
||||||
CHECK(messageSent.getCommand() ==
|
CHECK(messageSent.getCommand() ==
|
||||||
static_cast<int>(HousekeepingMessage::UPDATE_NOTIFICATION_VARIABLE));
|
static_cast<int>(HousekeepingMessage::UPDATE_NOTIFICATION_VARIABLE));
|
||||||
/* Now subscribe for the dataset update (HK and update) again with subscription interface */
|
/* Now subscribe for the dataset update (HK and update) again with subscription interface */
|
||||||
@ -225,26 +227,26 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") {
|
|||||||
poolOwner->dataset.setChanged(true);
|
poolOwner->dataset.setChanged(true);
|
||||||
REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK);
|
REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK);
|
||||||
/* Now two messages should be sent. */
|
/* Now two messages should be sent. */
|
||||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||||
CHECK(messagesSent == 2);
|
CHECK(messagesSent == 2);
|
||||||
mqMock->clearMessages(true);
|
poolOwnerMock->clearMessages(true);
|
||||||
|
|
||||||
poolOwner->dataset.setChanged(true);
|
poolOwner->dataset.setChanged(true);
|
||||||
poolVar->setChanged(true);
|
poolVar->setChanged(true);
|
||||||
REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK);
|
REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK);
|
||||||
/* Now three messages should be sent. */
|
/* Now three messages should be sent. */
|
||||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||||
CHECK(messagesSent == 3);
|
CHECK(messagesSent == 3);
|
||||||
REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK);
|
REQUIRE(poolOwnerMock->receiveMessage(&messageSent) == retval::CATCH_OK);
|
||||||
CHECK(messageSent.getCommand() ==
|
CHECK(messageSent.getCommand() ==
|
||||||
static_cast<int>(HousekeepingMessage::UPDATE_NOTIFICATION_VARIABLE));
|
static_cast<int>(HousekeepingMessage::UPDATE_NOTIFICATION_VARIABLE));
|
||||||
REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK);
|
REQUIRE(poolOwnerMock->receiveMessage(&messageSent) == retval::CATCH_OK);
|
||||||
CHECK(messageSent.getCommand() ==
|
CHECK(messageSent.getCommand() ==
|
||||||
static_cast<int>(HousekeepingMessage::UPDATE_NOTIFICATION_SET));
|
static_cast<int>(HousekeepingMessage::UPDATE_NOTIFICATION_SET));
|
||||||
REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK);
|
REQUIRE(poolOwnerMock->receiveMessage(&messageSent) == retval::CATCH_OK);
|
||||||
CHECK(messageSent.getCommand() == static_cast<int>(HousekeepingMessage::HK_REPORT));
|
CHECK(messageSent.getCommand() == static_cast<int>(HousekeepingMessage::HK_REPORT));
|
||||||
CommandMessageCleaner::clearCommandMessage(&messageSent);
|
CommandMessageCleaner::clearCommandMessage(&messageSent);
|
||||||
REQUIRE(mqMock->receiveMessage(&messageSent) == static_cast<int>(MessageQueueIF::EMPTY));
|
REQUIRE(poolOwnerMock->receiveMessage(&messageSent) == static_cast<int>(MessageQueueIF::EMPTY));
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("PeriodicHKAndMessaging") {
|
SECTION("PeriodicHKAndMessaging") {
|
||||||
@ -255,38 +257,38 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") {
|
|||||||
REQUIRE(poolOwner->subscribePeriodicHk(true) == retval::CATCH_OK);
|
REQUIRE(poolOwner->subscribePeriodicHk(true) == retval::CATCH_OK);
|
||||||
REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK);
|
REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK);
|
||||||
/* Now HK packet should be sent as message immediately. */
|
/* Now HK packet should be sent as message immediately. */
|
||||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||||
CHECK(messagesSent == 1);
|
CHECK(messagesSent == 1);
|
||||||
CHECK(mqMock->popMessage() == retval::CATCH_OK);
|
CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
|
||||||
|
|
||||||
LocalPoolDataSetBase* setHandle = poolOwner->getDataSetHandle(lpool::testSid);
|
LocalPoolDataSetBase* setHandle = poolOwner->getDataSetHandle(lpool::testSid);
|
||||||
REQUIRE(setHandle != nullptr);
|
REQUIRE(setHandle != nullptr);
|
||||||
CHECK(poolOwner->poolManager.generateHousekeepingPacket(lpool::testSid, setHandle, false) ==
|
CHECK(poolOwner->poolManager.generateHousekeepingPacket(lpool::testSid, setHandle, false) ==
|
||||||
retval::CATCH_OK);
|
retval::CATCH_OK);
|
||||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||||
CHECK(messagesSent == 1);
|
CHECK(messagesSent == 1);
|
||||||
CHECK(mqMock->popMessage() == retval::CATCH_OK);
|
CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
|
||||||
|
|
||||||
CHECK(setHandle->getReportingEnabled() == true);
|
CHECK(setHandle->getReportingEnabled() == true);
|
||||||
CommandMessage hkCmd;
|
CommandMessage hkCmd;
|
||||||
HousekeepingMessage::setToggleReportingCommand(&hkCmd, lpool::testSid, false, false);
|
HousekeepingMessage::setToggleReportingCommand(&hkCmd, lpool::testSid, false, false);
|
||||||
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK);
|
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK);
|
||||||
CHECK(setHandle->getReportingEnabled() == false);
|
CHECK(setHandle->getReportingEnabled() == false);
|
||||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||||
CHECK(messagesSent == 1);
|
CHECK(messagesSent == 1);
|
||||||
CHECK(mqMock->popMessage() == retval::CATCH_OK);
|
CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
|
||||||
|
|
||||||
HousekeepingMessage::setToggleReportingCommand(&hkCmd, lpool::testSid, true, false);
|
HousekeepingMessage::setToggleReportingCommand(&hkCmd, lpool::testSid, true, false);
|
||||||
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK);
|
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK);
|
||||||
CHECK(setHandle->getReportingEnabled() == true);
|
CHECK(setHandle->getReportingEnabled() == true);
|
||||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||||
CHECK(mqMock->popMessage() == retval::CATCH_OK);
|
CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
|
||||||
|
|
||||||
HousekeepingMessage::setToggleReportingCommand(&hkCmd, lpool::testSid, false, false);
|
HousekeepingMessage::setToggleReportingCommand(&hkCmd, lpool::testSid, false, false);
|
||||||
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK);
|
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK);
|
||||||
CHECK(setHandle->getReportingEnabled() == false);
|
CHECK(setHandle->getReportingEnabled() == false);
|
||||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||||
CHECK(mqMock->popMessage() == retval::CATCH_OK);
|
CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
|
||||||
|
|
||||||
HousekeepingMessage::setCollectionIntervalModificationCommand(&hkCmd, lpool::testSid, 0.4,
|
HousekeepingMessage::setCollectionIntervalModificationCommand(&hkCmd, lpool::testSid, 0.4,
|
||||||
false);
|
false);
|
||||||
@ -294,23 +296,23 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") {
|
|||||||
/* For non-diagnostics and a specified minimum frequency of 0.2 seconds, the
|
/* For non-diagnostics and a specified minimum frequency of 0.2 seconds, the
|
||||||
resulting collection interval should be 1.0 second */
|
resulting collection interval should be 1.0 second */
|
||||||
CHECK(poolOwner->dataset.getCollectionInterval() == 1.0);
|
CHECK(poolOwner->dataset.getCollectionInterval() == 1.0);
|
||||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||||
CHECK(messagesSent == 1);
|
CHECK(messagesSent == 1);
|
||||||
CHECK(mqMock->popMessage() == retval::CATCH_OK);
|
CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
|
||||||
|
|
||||||
HousekeepingMessage::setStructureReportingCommand(&hkCmd, lpool::testSid, false);
|
HousekeepingMessage::setStructureReportingCommand(&hkCmd, lpool::testSid, false);
|
||||||
REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK);
|
REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK);
|
||||||
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK);
|
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK);
|
||||||
/* Now HK packet should be sent as message. */
|
/* Now HK packet should be sent as message. */
|
||||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||||
CHECK(messagesSent == 1);
|
CHECK(messagesSent == 1);
|
||||||
CHECK(mqMock->popMessage() == retval::CATCH_OK);
|
CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
|
||||||
|
|
||||||
HousekeepingMessage::setOneShotReportCommand(&hkCmd, lpool::testSid, false);
|
HousekeepingMessage::setOneShotReportCommand(&hkCmd, lpool::testSid, false);
|
||||||
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK);
|
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK);
|
||||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||||
CHECK(messagesSent == 1);
|
CHECK(messagesSent == 1);
|
||||||
CHECK(mqMock->popMessage() == retval::CATCH_OK);
|
CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
|
||||||
|
|
||||||
HousekeepingMessage::setUpdateNotificationSetCommand(&hkCmd, lpool::testSid);
|
HousekeepingMessage::setUpdateNotificationSetCommand(&hkCmd, lpool::testSid);
|
||||||
sid_t sidToCheck;
|
sid_t sidToCheck;
|
||||||
@ -326,62 +328,62 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") {
|
|||||||
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) ==
|
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) ==
|
||||||
static_cast<int>(LocalDataPoolManager::WRONG_HK_PACKET_TYPE));
|
static_cast<int>(LocalDataPoolManager::WRONG_HK_PACKET_TYPE));
|
||||||
/* We still expect a failure message being sent */
|
/* We still expect a failure message being sent */
|
||||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||||
CHECK(messagesSent == 1);
|
CHECK(messagesSent == 1);
|
||||||
CHECK(mqMock->popMessage() == retval::CATCH_OK);
|
CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
|
||||||
|
|
||||||
HousekeepingMessage::setCollectionIntervalModificationCommand(&hkCmd, lpool::testSid, 0.4,
|
HousekeepingMessage::setCollectionIntervalModificationCommand(&hkCmd, lpool::testSid, 0.4,
|
||||||
false);
|
false);
|
||||||
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) ==
|
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) ==
|
||||||
static_cast<int>(LocalDataPoolManager::WRONG_HK_PACKET_TYPE));
|
static_cast<int>(LocalDataPoolManager::WRONG_HK_PACKET_TYPE));
|
||||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||||
CHECK(messagesSent == 1);
|
CHECK(messagesSent == 1);
|
||||||
CHECK(mqMock->popMessage() == retval::CATCH_OK);
|
CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
|
||||||
|
|
||||||
HousekeepingMessage::setStructureReportingCommand(&hkCmd, lpool::testSid, false);
|
HousekeepingMessage::setStructureReportingCommand(&hkCmd, lpool::testSid, false);
|
||||||
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) ==
|
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) ==
|
||||||
static_cast<int>(LocalDataPoolManager::WRONG_HK_PACKET_TYPE));
|
static_cast<int>(LocalDataPoolManager::WRONG_HK_PACKET_TYPE));
|
||||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||||
CHECK(messagesSent == 1);
|
CHECK(messagesSent == 1);
|
||||||
CHECK(mqMock->popMessage() == retval::CATCH_OK);
|
CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
|
||||||
|
|
||||||
HousekeepingMessage::setStructureReportingCommand(&hkCmd, lpool::testSid, true);
|
HousekeepingMessage::setStructureReportingCommand(&hkCmd, lpool::testSid, true);
|
||||||
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK);
|
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK);
|
||||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||||
CHECK(messagesSent == 1);
|
CHECK(messagesSent == 1);
|
||||||
CHECK(mqMock->popMessage() == retval::CATCH_OK);
|
CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
|
||||||
|
|
||||||
HousekeepingMessage::setCollectionIntervalModificationCommand(&hkCmd, lpool::testSid, 0.4,
|
HousekeepingMessage::setCollectionIntervalModificationCommand(&hkCmd, lpool::testSid, 0.4,
|
||||||
true);
|
true);
|
||||||
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK);
|
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK);
|
||||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||||
CHECK(messagesSent == 1);
|
CHECK(messagesSent == 1);
|
||||||
CHECK(mqMock->popMessage() == retval::CATCH_OK);
|
CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
|
||||||
|
|
||||||
HousekeepingMessage::setToggleReportingCommand(&hkCmd, lpool::testSid, true, true);
|
HousekeepingMessage::setToggleReportingCommand(&hkCmd, lpool::testSid, true, true);
|
||||||
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK);
|
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK);
|
||||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||||
CHECK(messagesSent == 1);
|
CHECK(messagesSent == 1);
|
||||||
CHECK(mqMock->popMessage() == retval::CATCH_OK);
|
CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
|
||||||
|
|
||||||
HousekeepingMessage::setToggleReportingCommand(&hkCmd, lpool::testSid, false, true);
|
HousekeepingMessage::setToggleReportingCommand(&hkCmd, lpool::testSid, false, true);
|
||||||
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK);
|
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK);
|
||||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||||
CHECK(messagesSent == 1);
|
CHECK(messagesSent == 1);
|
||||||
CHECK(mqMock->popMessage() == retval::CATCH_OK);
|
CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
|
||||||
|
|
||||||
HousekeepingMessage::setOneShotReportCommand(&hkCmd, lpool::testSid, false);
|
HousekeepingMessage::setOneShotReportCommand(&hkCmd, lpool::testSid, false);
|
||||||
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) ==
|
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) ==
|
||||||
static_cast<int>(LocalDataPoolManager::WRONG_HK_PACKET_TYPE));
|
static_cast<int>(LocalDataPoolManager::WRONG_HK_PACKET_TYPE));
|
||||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||||
CHECK(messagesSent == 1);
|
CHECK(messagesSent == 1);
|
||||||
CHECK(mqMock->popMessage() == retval::CATCH_OK);
|
CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
|
||||||
|
|
||||||
HousekeepingMessage::setOneShotReportCommand(&hkCmd, lpool::testSid, true);
|
HousekeepingMessage::setOneShotReportCommand(&hkCmd, lpool::testSid, true);
|
||||||
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK);
|
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK);
|
||||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||||
CHECK(messagesSent == 1);
|
CHECK(messagesSent == 1);
|
||||||
CHECK(mqMock->popMessage() == retval::CATCH_OK);
|
CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
|
||||||
|
|
||||||
HousekeepingMessage::setUpdateNotificationVariableCommand(&hkCmd, lpool::uint8VarGpid);
|
HousekeepingMessage::setUpdateNotificationVariableCommand(&hkCmd, lpool::uint8VarGpid);
|
||||||
gp_id_t gpidToCheck;
|
gp_id_t gpidToCheck;
|
||||||
@ -407,5 +409,5 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") {
|
|||||||
/* we need to reset the subscription list because the pool owner
|
/* we need to reset the subscription list because the pool owner
|
||||||
is a global object. */
|
is a global object. */
|
||||||
CHECK(poolOwner->reset() == retval::CATCH_OK);
|
CHECK(poolOwner->reset() == retval::CATCH_OK);
|
||||||
mqMock->clearMessages(true);
|
poolOwnerMock->clearMessages(true);
|
||||||
}
|
}
|
||||||
|
@ -3,4 +3,5 @@ target_sources(${FSFW_TEST_TGT} PRIVATE
|
|||||||
testOpDivider.cpp
|
testOpDivider.cpp
|
||||||
testBitutil.cpp
|
testBitutil.cpp
|
||||||
testCRC.cpp
|
testCRC.cpp
|
||||||
|
testTimevalOperations.cpp
|
||||||
)
|
)
|
||||||
|
@ -0,0 +1,124 @@
|
|||||||
|
#include <fsfw/globalfunctions/timevalOperations.h>
|
||||||
|
|
||||||
|
#include <catch2/catch_approx.hpp>
|
||||||
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
|
||||||
|
#include "fsfw_tests/unit/CatchDefinitions.h"
|
||||||
|
|
||||||
|
TEST_CASE("TimevalTest", "[timevalOperations]") {
|
||||||
|
SECTION("Comparison") {
|
||||||
|
timeval t1;
|
||||||
|
t1.tv_sec = 1648227422;
|
||||||
|
t1.tv_usec = 123456;
|
||||||
|
timeval t2;
|
||||||
|
t2.tv_sec = 1648227422;
|
||||||
|
t2.tv_usec = 123456;
|
||||||
|
REQUIRE(t1 == t2);
|
||||||
|
REQUIRE(t2 == t1);
|
||||||
|
REQUIRE_FALSE(t1 != t2);
|
||||||
|
REQUIRE_FALSE(t2 != t1);
|
||||||
|
REQUIRE(t1 <= t2);
|
||||||
|
REQUIRE(t2 <= t1);
|
||||||
|
REQUIRE(t1 >= t2);
|
||||||
|
REQUIRE(t2 >= t1);
|
||||||
|
REQUIRE_FALSE(t1 < t2);
|
||||||
|
REQUIRE_FALSE(t2 < t1);
|
||||||
|
REQUIRE_FALSE(t1 > t2);
|
||||||
|
REQUIRE_FALSE(t2 > t1);
|
||||||
|
|
||||||
|
timeval t3;
|
||||||
|
t3.tv_sec = 1648227422;
|
||||||
|
t3.tv_usec = 123457;
|
||||||
|
REQUIRE_FALSE(t1 == t3);
|
||||||
|
REQUIRE(t1 != t3);
|
||||||
|
REQUIRE(t1 <= t3);
|
||||||
|
REQUIRE_FALSE(t3 <= t1);
|
||||||
|
REQUIRE_FALSE(t1 >= t3);
|
||||||
|
REQUIRE(t3 >= t1);
|
||||||
|
REQUIRE(t1 < t3);
|
||||||
|
REQUIRE_FALSE(t3 < t1);
|
||||||
|
REQUIRE_FALSE(t1 > t3);
|
||||||
|
REQUIRE(t3 > t1);
|
||||||
|
|
||||||
|
timeval t4;
|
||||||
|
t4.tv_sec = 1648227423;
|
||||||
|
t4.tv_usec = 123456;
|
||||||
|
REQUIRE_FALSE(t1 == t4);
|
||||||
|
REQUIRE(t1 != t4);
|
||||||
|
REQUIRE(t1 <= t4);
|
||||||
|
REQUIRE_FALSE(t4 <= t1);
|
||||||
|
REQUIRE_FALSE(t1 >= t4);
|
||||||
|
REQUIRE(t4 >= t1);
|
||||||
|
REQUIRE(t1 < t4);
|
||||||
|
REQUIRE_FALSE(t4 < t1);
|
||||||
|
REQUIRE_FALSE(t1 > t4);
|
||||||
|
REQUIRE(t4 > t1);
|
||||||
|
}
|
||||||
|
SECTION("Operators") {
|
||||||
|
timeval t1;
|
||||||
|
t1.tv_sec = 1648227422;
|
||||||
|
t1.tv_usec = 123456;
|
||||||
|
timeval t2;
|
||||||
|
t2.tv_sec = 1648227422;
|
||||||
|
t2.tv_usec = 123456;
|
||||||
|
timeval t3 = t1 - t2;
|
||||||
|
REQUIRE(t3.tv_sec == 0);
|
||||||
|
REQUIRE(t3.tv_usec == 0);
|
||||||
|
timeval t4 = t1 - t3;
|
||||||
|
REQUIRE(t4.tv_sec == 1648227422);
|
||||||
|
REQUIRE(t4.tv_usec == 123456);
|
||||||
|
timeval t5 = t3 - t1;
|
||||||
|
REQUIRE(t5.tv_sec == -1648227422);
|
||||||
|
REQUIRE(t5.tv_usec == -123456);
|
||||||
|
|
||||||
|
timeval t6;
|
||||||
|
t6.tv_sec = 1648227400;
|
||||||
|
t6.tv_usec = 999999;
|
||||||
|
|
||||||
|
timeval t7 = t6 + t1;
|
||||||
|
REQUIRE(t7.tv_sec == (1648227422ull + 1648227400ull + 1ull));
|
||||||
|
REQUIRE(t7.tv_usec == 123455);
|
||||||
|
|
||||||
|
timeval t8 = t1 - t6;
|
||||||
|
REQUIRE(t8.tv_sec == 1648227422 - 1648227400 - 1);
|
||||||
|
REQUIRE(t8.tv_usec == 123457);
|
||||||
|
|
||||||
|
double scalar = 2;
|
||||||
|
timeval t9 = t1 * scalar;
|
||||||
|
REQUIRE(t9.tv_sec == 3296454844);
|
||||||
|
REQUIRE(t9.tv_usec == 246912);
|
||||||
|
timeval t10 = scalar * t1;
|
||||||
|
REQUIRE(t10.tv_sec == 3296454844);
|
||||||
|
REQUIRE(t10.tv_usec == 246912);
|
||||||
|
timeval t11 = t6 * scalar;
|
||||||
|
REQUIRE(t11.tv_sec == (3296454800 + 1));
|
||||||
|
REQUIRE(t11.tv_usec == 999998);
|
||||||
|
|
||||||
|
timeval t12 = t1 / scalar;
|
||||||
|
REQUIRE(t12.tv_sec == 824113711);
|
||||||
|
REQUIRE(t12.tv_usec == 61728);
|
||||||
|
|
||||||
|
timeval t13 = t6 / scalar;
|
||||||
|
REQUIRE(t13.tv_sec == 824113700);
|
||||||
|
// Rounding issue
|
||||||
|
REQUIRE(t13.tv_usec == 499999);
|
||||||
|
|
||||||
|
double scalar2 = t9 / t1;
|
||||||
|
REQUIRE(scalar2 == Catch::Approx(2.0));
|
||||||
|
double scalar3 = t1 / t6;
|
||||||
|
REQUIRE(scalar3 == Catch::Approx(1.000000013));
|
||||||
|
double scalar4 = t3 / t1;
|
||||||
|
REQUIRE(scalar4 == Catch::Approx(0));
|
||||||
|
double scalar5 = t12 / t1;
|
||||||
|
REQUIRE(scalar5 == Catch::Approx(0.5));
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("timevalOperations::toTimeval") {
|
||||||
|
double seconds = 1648227422.123456;
|
||||||
|
timeval t1 = timevalOperations::toTimeval(seconds);
|
||||||
|
REQUIRE(t1.tv_sec == 1648227422);
|
||||||
|
// Allow 1 usec rounding tolerance
|
||||||
|
REQUIRE(t1.tv_usec >= 123455);
|
||||||
|
REQUIRE(t1.tv_usec <= 123457);
|
||||||
|
}
|
||||||
|
}
|
@ -5,15 +5,17 @@
|
|||||||
#include <queue>
|
#include <queue>
|
||||||
|
|
||||||
#include "fsfw/ipc/CommandMessage.h"
|
#include "fsfw/ipc/CommandMessage.h"
|
||||||
|
#include "fsfw/ipc/MessageQueueBase.h"
|
||||||
#include "fsfw/ipc/MessageQueueIF.h"
|
#include "fsfw/ipc/MessageQueueIF.h"
|
||||||
#include "fsfw/ipc/MessageQueueMessage.h"
|
#include "fsfw/ipc/MessageQueueMessage.h"
|
||||||
#include "fsfw_tests/unit/CatchDefinitions.h"
|
#include "fsfw_tests/unit/CatchDefinitions.h"
|
||||||
|
|
||||||
class MessageQueueMockBase : public MessageQueueIF {
|
class MessageQueueMockBase : public MessageQueueBase {
|
||||||
public:
|
public:
|
||||||
MessageQueueId_t myQueueId = tconst::testQueueId;
|
MessageQueueMockBase()
|
||||||
|
: MessageQueueBase(MessageQueueIF::NO_QUEUE, MessageQueueIF::NO_QUEUE, nullptr) {}
|
||||||
|
|
||||||
uint8_t messageSentCounter = 0;
|
uint8_t messageSentCounter = 0;
|
||||||
bool defaultDestSet = false;
|
|
||||||
bool messageSent = false;
|
bool messageSent = false;
|
||||||
|
|
||||||
bool wasMessageSent(uint8_t* messageSentCounter = nullptr, bool resetCounter = true) {
|
bool wasMessageSent(uint8_t* messageSentCounter = nullptr, bool resetCounter = true) {
|
||||||
@ -38,39 +40,19 @@ class MessageQueueMockBase : public MessageQueueIF {
|
|||||||
return receiveMessage(&message);
|
return receiveMessage(&message);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ReturnValue_t reply(MessageQueueMessageIF* message) {
|
virtual ReturnValue_t receiveMessage(MessageQueueMessageIF* message) override {
|
||||||
return sendMessage(myQueueId, message);
|
|
||||||
};
|
|
||||||
virtual ReturnValue_t receiveMessage(MessageQueueMessageIF* message,
|
|
||||||
MessageQueueId_t* receivedFrom) {
|
|
||||||
return receiveMessage(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ReturnValue_t receiveMessage(MessageQueueMessageIF* message) {
|
|
||||||
if (messagesSentQueue.empty()) {
|
if (messagesSentQueue.empty()) {
|
||||||
return MessageQueueIF::EMPTY;
|
return MessageQueueIF::EMPTY;
|
||||||
}
|
}
|
||||||
|
this->last = message->getSender();
|
||||||
std::memcpy(message->getBuffer(), messagesSentQueue.front().getBuffer(),
|
std::memcpy(message->getBuffer(), messagesSentQueue.front().getBuffer(),
|
||||||
message->getMessageSize());
|
message->getMessageSize());
|
||||||
messagesSentQueue.pop();
|
messagesSentQueue.pop();
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
virtual ReturnValue_t flush(uint32_t* count) { return HasReturnvaluesIF::RETURN_OK; }
|
virtual ReturnValue_t flush(uint32_t* count) { return HasReturnvaluesIF::RETURN_OK; }
|
||||||
virtual MessageQueueId_t getLastPartner() const { return myQueueId; }
|
|
||||||
virtual MessageQueueId_t getId() const { return myQueueId; }
|
|
||||||
virtual ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
virtual ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
||||||
MessageQueueId_t sentFrom, bool ignoreFault = false) {
|
MessageQueueId_t sentFrom,
|
||||||
return sendMessage(sendTo, message);
|
|
||||||
}
|
|
||||||
virtual ReturnValue_t sendToDefaultFrom(MessageQueueMessageIF* message, MessageQueueId_t sentFrom,
|
|
||||||
bool ignoreFault = false) {
|
|
||||||
return sendMessage(myQueueId, message);
|
|
||||||
}
|
|
||||||
virtual ReturnValue_t sendToDefault(MessageQueueMessageIF* message) {
|
|
||||||
return sendMessage(myQueueId, message);
|
|
||||||
}
|
|
||||||
virtual ReturnValue_t sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
|
||||||
bool ignoreFault = false) override {
|
bool ignoreFault = false) override {
|
||||||
messageSent = true;
|
messageSent = true;
|
||||||
messageSentCounter++;
|
messageSentCounter++;
|
||||||
@ -78,13 +60,10 @@ class MessageQueueMockBase : public MessageQueueIF {
|
|||||||
messagesSentQueue.push(messageRef);
|
messagesSentQueue.push(messageRef);
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
virtual void setDefaultDestination(MessageQueueId_t defaultDestination) {
|
|
||||||
myQueueId = defaultDestination;
|
|
||||||
defaultDestSet = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual MessageQueueId_t getDefaultDestination() const { return myQueueId; }
|
virtual ReturnValue_t reply(MessageQueueMessageIF* message) override {
|
||||||
virtual bool isDefaultDestinationSet() const { return defaultDestSet; }
|
return sendMessageFrom(MessageQueueIF::NO_QUEUE, message, this->getId(), false);
|
||||||
|
}
|
||||||
|
|
||||||
void clearMessages(bool clearCommandMessages = true) {
|
void clearMessages(bool clearCommandMessages = true) {
|
||||||
while (not messagesSentQueue.empty()) {
|
while (not messagesSentQueue.empty()) {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
target_sources(${FSFW_TEST_TGT} PRIVATE
|
target_sources(${FSFW_TEST_TGT} PRIVATE
|
||||||
TestMessageQueue.cpp
|
TestMessageQueue.cpp
|
||||||
TestSemaphore.cpp
|
TestSemaphore.cpp
|
||||||
|
TestClock.cpp
|
||||||
)
|
)
|
||||||
|
86
tests/src/fsfw_tests/unit/osal/TestClock.cpp
Normal file
86
tests/src/fsfw_tests/unit/osal/TestClock.cpp
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
#include <fsfw/globalfunctions/timevalOperations.h>
|
||||||
|
#include <fsfw/timemanager/Clock.h>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <catch2/catch_approx.hpp>
|
||||||
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
|
||||||
|
#include "fsfw_tests/unit/CatchDefinitions.h"
|
||||||
|
|
||||||
|
TEST_CASE("OSAL::Clock Test", "[OSAL::Clock Test]") {
|
||||||
|
SECTION("Test getClock") {
|
||||||
|
timeval time;
|
||||||
|
ReturnValue_t result = Clock::getClock_timeval(&time);
|
||||||
|
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
|
||||||
|
Clock::TimeOfDay_t timeOfDay;
|
||||||
|
result = Clock::getDateAndTime(&timeOfDay);
|
||||||
|
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
|
||||||
|
timeval timeOfDayAsTimeval;
|
||||||
|
result = Clock::convertTimeOfDayToTimeval(&timeOfDay, &timeOfDayAsTimeval);
|
||||||
|
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
|
||||||
|
// We require timeOfDayAsTimeval to be larger than time as it
|
||||||
|
// was request a few ns later
|
||||||
|
double difference = timevalOperations::toDouble(timeOfDayAsTimeval - time);
|
||||||
|
CHECK(difference >= 0.0);
|
||||||
|
CHECK(difference <= 0.005);
|
||||||
|
|
||||||
|
// Conversion in the other direction
|
||||||
|
Clock::TimeOfDay_t timevalAsTimeOfDay;
|
||||||
|
result = Clock::convertTimevalToTimeOfDay(&time, &timevalAsTimeOfDay);
|
||||||
|
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
|
||||||
|
CHECK(timevalAsTimeOfDay.year <= timeOfDay.year);
|
||||||
|
// TODO We should write TimeOfDay operators!
|
||||||
|
}
|
||||||
|
SECTION("Leap seconds") {
|
||||||
|
uint16_t leapSeconds = 0;
|
||||||
|
ReturnValue_t result = Clock::getLeapSeconds(&leapSeconds);
|
||||||
|
REQUIRE(result == HasReturnvaluesIF::RETURN_FAILED);
|
||||||
|
REQUIRE(leapSeconds == 0);
|
||||||
|
result = Clock::setLeapSeconds(18);
|
||||||
|
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
|
||||||
|
result = Clock::getLeapSeconds(&leapSeconds);
|
||||||
|
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
|
||||||
|
REQUIRE(leapSeconds == 18);
|
||||||
|
}
|
||||||
|
SECTION("usec Test") {
|
||||||
|
timeval timeAsTimeval;
|
||||||
|
ReturnValue_t result = Clock::getClock_timeval(&timeAsTimeval);
|
||||||
|
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
|
||||||
|
uint64_t timeAsUsec = 0;
|
||||||
|
result = Clock::getClock_usecs(&timeAsUsec);
|
||||||
|
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
|
||||||
|
double timeAsUsecDouble = static_cast<double>(timeAsUsec) / 1000000.0;
|
||||||
|
timeval timeAsUsecTimeval = timevalOperations::toTimeval(timeAsUsecDouble);
|
||||||
|
double difference = timevalOperations::toDouble(timeAsUsecTimeval - timeAsTimeval);
|
||||||
|
// We accept 5 ms difference
|
||||||
|
CHECK(difference >= 0.0);
|
||||||
|
CHECK(difference <= 0.005);
|
||||||
|
uint64_t timevalAsUint64 = static_cast<uint64_t>(timeAsTimeval.tv_sec) * 1000000ull +
|
||||||
|
static_cast<uint64_t>(timeAsTimeval.tv_usec);
|
||||||
|
CHECK((timeAsUsec - timevalAsUint64) >= 0);
|
||||||
|
CHECK((timeAsUsec - timevalAsUint64) <= (5 * 1000));
|
||||||
|
}
|
||||||
|
SECTION("Test j2000") {
|
||||||
|
double j2000;
|
||||||
|
timeval time;
|
||||||
|
time.tv_sec = 1648208539;
|
||||||
|
time.tv_usec = 0;
|
||||||
|
ReturnValue_t result = Clock::convertTimevalToJD2000(time, &j2000);
|
||||||
|
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
|
||||||
|
double correctJ2000 = 2459663.98772 - 2451545.0;
|
||||||
|
CHECK(j2000 == Catch::Approx(correctJ2000).margin(1.2 * 1e-8));
|
||||||
|
}
|
||||||
|
SECTION("Convert to TT") {
|
||||||
|
timeval utcTime;
|
||||||
|
utcTime.tv_sec = 1648208539;
|
||||||
|
utcTime.tv_usec = 999000;
|
||||||
|
timeval tt;
|
||||||
|
ReturnValue_t result = Clock::setLeapSeconds(27);
|
||||||
|
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
|
||||||
|
result = Clock::convertUTCToTT(utcTime, &tt);
|
||||||
|
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
|
||||||
|
CHECK(tt.tv_usec == 183000);
|
||||||
|
// The plus 1 is a own forced overflow of usecs
|
||||||
|
CHECK(tt.tv_sec == (1648208539 + 27 + 10 + 32 + 1));
|
||||||
|
}
|
||||||
|
}
|
@ -81,7 +81,8 @@ TEST_CASE("CCSDSTime Tests", "[TestCCSDSTime]") {
|
|||||||
std::string timeAscii = "2022-12-31T23:59:59.123Z";
|
std::string timeAscii = "2022-12-31T23:59:59.123Z";
|
||||||
Clock::TimeOfDay_t timeTo;
|
Clock::TimeOfDay_t timeTo;
|
||||||
const uint8_t* timeChar = reinterpret_cast<const uint8_t*>(timeAscii.c_str());
|
const uint8_t* timeChar = reinterpret_cast<const uint8_t*>(timeAscii.c_str());
|
||||||
CCSDSTime::convertFromASCII(&timeTo, timeChar, timeAscii.length());
|
auto result = CCSDSTime::convertFromASCII(&timeTo, timeChar, timeAscii.length());
|
||||||
|
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
|
||||||
REQUIRE(timeTo.year == 2022);
|
REQUIRE(timeTo.year == 2022);
|
||||||
REQUIRE(timeTo.month == 12);
|
REQUIRE(timeTo.month == 12);
|
||||||
REQUIRE(timeTo.day == 31);
|
REQUIRE(timeTo.day == 31);
|
||||||
@ -89,6 +90,19 @@ TEST_CASE("CCSDSTime Tests", "[TestCCSDSTime]") {
|
|||||||
REQUIRE(timeTo.minute == 59);
|
REQUIRE(timeTo.minute == 59);
|
||||||
REQUIRE(timeTo.second == 59);
|
REQUIRE(timeTo.second == 59);
|
||||||
REQUIRE(timeTo.usecond == Catch::Approx(123000));
|
REQUIRE(timeTo.usecond == Catch::Approx(123000));
|
||||||
|
|
||||||
|
std::string timeAscii2 = "2022-365T23:59:59.123Z";
|
||||||
|
const uint8_t* timeChar2 = reinterpret_cast<const uint8_t*>(timeAscii2.c_str());
|
||||||
|
Clock::TimeOfDay_t timeTo2;
|
||||||
|
result = CCSDSTime::convertFromCcsds(&timeTo2, timeChar2, timeAscii2.length());
|
||||||
|
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
|
||||||
|
REQUIRE(timeTo2.year == 2022);
|
||||||
|
REQUIRE(timeTo2.month == 12);
|
||||||
|
REQUIRE(timeTo2.day == 31);
|
||||||
|
REQUIRE(timeTo2.hour == 23);
|
||||||
|
REQUIRE(timeTo2.minute == 59);
|
||||||
|
REQUIRE(timeTo2.second == 59);
|
||||||
|
REQUIRE(timeTo2.usecond == Catch::Approx(123000));
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("CDS Conversions") {
|
SECTION("CDS Conversions") {
|
||||||
@ -119,6 +133,7 @@ TEST_CASE("CCSDSTime Tests", "[TestCCSDSTime]") {
|
|||||||
CHECK(cdsTime.msDay_h == 0xE0);
|
CHECK(cdsTime.msDay_h == 0xE0);
|
||||||
CHECK(cdsTime.msDay_l == 0xC5);
|
CHECK(cdsTime.msDay_l == 0xC5);
|
||||||
CHECK(cdsTime.msDay_ll == 0xC3);
|
CHECK(cdsTime.msDay_ll == 0xC3);
|
||||||
|
CHECK(cdsTime.pField == CCSDSTime::P_FIELD_CDS_SHORT);
|
||||||
|
|
||||||
// Conversion back to timeval
|
// Conversion back to timeval
|
||||||
timeval timeReturnAsTimeval;
|
timeval timeReturnAsTimeval;
|
||||||
@ -128,5 +143,77 @@ TEST_CASE("CCSDSTime Tests", "[TestCCSDSTime]") {
|
|||||||
timeval difference = timeAsTimeval - timeReturnAsTimeval;
|
timeval difference = timeAsTimeval - timeReturnAsTimeval;
|
||||||
CHECK(difference.tv_usec == 456);
|
CHECK(difference.tv_usec == 456);
|
||||||
CHECK(difference.tv_sec == 0);
|
CHECK(difference.tv_sec == 0);
|
||||||
|
|
||||||
|
Clock::TimeOfDay_t timeReturnAsTimeOfDay;
|
||||||
|
result = CCSDSTime::convertFromCDS(&timeReturnAsTimeOfDay, &cdsTime);
|
||||||
|
CHECK(result == HasReturnvaluesIF::RETURN_OK);
|
||||||
|
CHECK(timeReturnAsTimeOfDay.year == 2020);
|
||||||
|
CHECK(timeReturnAsTimeOfDay.month == 2);
|
||||||
|
CHECK(timeReturnAsTimeOfDay.day == 29);
|
||||||
|
CHECK(timeReturnAsTimeOfDay.hour == 13);
|
||||||
|
CHECK(timeReturnAsTimeOfDay.minute == 24);
|
||||||
|
CHECK(timeReturnAsTimeOfDay.second == 45);
|
||||||
|
// micro seconds precision is lost
|
||||||
|
CHECK(timeReturnAsTimeOfDay.usecond == 123000);
|
||||||
|
|
||||||
|
Clock::TimeOfDay_t timeReturnAsTodFromBuffer;
|
||||||
|
const uint8_t* buffer = reinterpret_cast<const uint8_t*>(&cdsTime);
|
||||||
|
result = CCSDSTime::convertFromCDS(&timeReturnAsTodFromBuffer, buffer, sizeof(cdsTime));
|
||||||
|
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
|
||||||
|
CHECK(timeReturnAsTodFromBuffer.year == time.year);
|
||||||
|
CHECK(timeReturnAsTodFromBuffer.month == time.month);
|
||||||
|
CHECK(timeReturnAsTodFromBuffer.day == time.day);
|
||||||
|
CHECK(timeReturnAsTodFromBuffer.hour == time.hour);
|
||||||
|
CHECK(timeReturnAsTodFromBuffer.minute == time.minute);
|
||||||
|
CHECK(timeReturnAsTodFromBuffer.second == time.second);
|
||||||
|
CHECK(timeReturnAsTodFromBuffer.usecond == 123000);
|
||||||
|
|
||||||
|
Clock::TimeOfDay_t todFromCCSDS;
|
||||||
|
result = CCSDSTime::convertFromCcsds(&todFromCCSDS, buffer, sizeof(cdsTime));
|
||||||
|
CHECK(result == HasReturnvaluesIF::RETURN_OK);
|
||||||
|
CHECK(todFromCCSDS.year == time.year);
|
||||||
|
CHECK(todFromCCSDS.month == time.month);
|
||||||
|
CHECK(todFromCCSDS.day == time.day);
|
||||||
|
CHECK(todFromCCSDS.hour == time.hour);
|
||||||
|
CHECK(todFromCCSDS.minute == time.minute);
|
||||||
|
CHECK(todFromCCSDS.second == time.second);
|
||||||
|
CHECK(todFromCCSDS.usecond == 123000);
|
||||||
|
}
|
||||||
|
SECTION("CUC") {
|
||||||
|
timeval to;
|
||||||
|
// seconds = 0x771E960F, microseconds = 0x237
|
||||||
|
// microseconds = 567000
|
||||||
|
// This gives 37158.912 1/65536 seconds -> rounded to 37159 -> 0x9127
|
||||||
|
// This results in -> 567001 us
|
||||||
|
std::array<uint8_t, 7> cucBuffer = {
|
||||||
|
CCSDSTime::P_FIELD_CUC_6B_CCSDS, 0x77, 0x1E, 0x96, 0x0F, 0x91, 0x27};
|
||||||
|
size_t foundLength = 0;
|
||||||
|
auto result = CCSDSTime::convertFromCUC(&to, cucBuffer.data(), &foundLength, cucBuffer.size());
|
||||||
|
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
|
||||||
|
REQUIRE(foundLength == 7);
|
||||||
|
REQUIRE(to.tv_sec == 1619801999); // TAI (no leap seconds)
|
||||||
|
REQUIRE(to.tv_usec == 567001);
|
||||||
|
|
||||||
|
Clock::TimeOfDay_t tod;
|
||||||
|
result = CCSDSTime::convertFromCUC(&tod, cucBuffer.data(), cucBuffer.size());
|
||||||
|
// This test must be changed if this is ever going to be implemented
|
||||||
|
REQUIRE(result == CCSDSTime::UNSUPPORTED_TIME_FORMAT);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("CCSDS Failures") {
|
||||||
|
Clock::TimeOfDay_t time;
|
||||||
|
time.year = 2020;
|
||||||
|
time.month = 12;
|
||||||
|
time.day = 32;
|
||||||
|
time.hour = 13;
|
||||||
|
time.minute = 24;
|
||||||
|
time.second = 45;
|
||||||
|
time.usecond = 123456;
|
||||||
|
CCSDSTime::Ccs_mseconds to;
|
||||||
|
auto result = CCSDSTime::convertToCcsds(&to, &time);
|
||||||
|
REQUIRE(result == CCSDSTime::INVALID_TIME_FORMAT);
|
||||||
|
CCSDSTime::Ccs_seconds to2;
|
||||||
|
result = CCSDSTime::convertToCcsds(&to2, &time);
|
||||||
|
REQUIRE(result == CCSDSTime::INVALID_TIME_FORMAT);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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));
|
||||||
|
Reference in New Issue
Block a user