Compare commits

..

136 Commits

Author SHA1 Message Date
7b767b238a some more fixes 2022-05-10 16:58:34 +02:00
42ac1af4b2 update changelog 2022-05-10 16:55:22 +02:00
1e5ba0212e possible fix for cicd 2022-05-10 16:53:33 +02:00
ac95e8f250 cmakelists update 2022-05-10 16:53:15 +02:00
1e569128c6 update auto-gen file 2022-05-10 16:48:23 +02:00
f35c4049c0 removed faulty include 2022-05-10 16:47:51 +02:00
5d946f5640 commit seems to change 2022-05-10 16:46:03 +02:00
f57bd290d9 this compiles 2022-05-10 16:43:16 +02:00
aa4e2d7209 remove custom command which reset .h.in file 2022-05-10 16:13:32 +02:00
58cb96ece0 update changelog 2022-05-10 12:28:40 +02:00
88cc8c46a1 this appears to do the trick 2022-05-10 12:26:21 +02:00
377c3325d2 update cmake-modules file 2022-05-10 12:16:38 +02:00
efb3d982f3 added missing prefix 2022-05-10 11:52:40 +02:00
dd986fefd3 experimenting with PRE_BUILD command 2022-05-10 11:51:25 +02:00
b38329aa0e Merge branch 'development' into mueller/extend-version-class 2022-05-10 11:19:48 +02:00
4499c9bf04 Merge pull request 'Added new functions to add sequences and tables' (#606) from eive/fsfw:mueller/new-ss-adder-functions into development
Reviewed-on: fsfw/fsfw#606
2022-05-10 09:35:16 +02:00
be6a492022 Merge branch 'development' into mueller/extend-version-class 2022-05-09 22:34:09 +02:00
d45cda93b2 Merge pull request 'important bugfix for TCP server' (#618) from mueller/tcp-server-bugfix into development
Reviewed-on: fsfw/fsfw#618
2022-05-09 16:59:54 +02:00
3448292e8a Merge branch 'development' into mueller/tcp-server-bugfix 2022-05-09 16:56:07 +02:00
c83cc492c0 Merge pull request 'Compile Time Size Check fixed' (#614) from gaisser/fsfw:gaisser_fix_compile_check into development
Reviewed-on: fsfw/fsfw#614
2022-05-09 16:14:44 +02:00
ece32f88f4 Merge remote-tracking branch 'origin/development' into mueller/tcp-server-bugfix 2022-05-09 16:14:17 +02:00
46cfe65321 Merge pull request 'Health Service Bugfix' (#617) from mueller/health-srv-bugfix into development
Reviewed-on: fsfw/fsfw#617
2022-05-09 16:08:28 +02:00
96eb8fc21f Merge branch 'development' into gaisser_fix_compile_check 2022-05-09 15:59:44 +02:00
88fa4f1d9d Merge remote-tracking branch 'origin/development' into mueller/tcp-server-bugfix 2022-05-09 15:55:07 +02:00
736f8d0238 order fix 2022-05-09 15:50:49 +02:00
f1acf8e18b Merge remote-tracking branch 'upstream/development' into mueller/extend-version-class 2022-05-09 15:48:04 +02:00
281f91ec5d Merge remote-tracking branch 'origin/development' into mueller/health-srv-bugfix 2022-05-09 15:41:10 +02:00
118f1da8dd Merge pull request 'Bump C++ standard to C++17' (#622) from mueller/cpp17-update into development
Reviewed-on: fsfw/fsfw#622
2022-05-09 15:33:52 +02:00
8b0508d50a Merge branch 'development' into gaisser_fix_compile_check 2022-05-09 15:17:28 +02:00
83de5b4ec1 Merge branch 'development' into mueller/cpp17-update 2022-05-09 15:13:50 +02:00
fe1c51ae6d Merge pull request 'CMake move some directives up top' (#621) from mueller/cmake-fixes into development
Reviewed-on: fsfw/fsfw#621
2022-05-09 15:13:02 +02:00
10cc954d27 update changelog 2022-05-09 15:09:07 +02:00
73ff9b97db bump CMAKE_CXX_STANDARD to C++17 2022-05-09 15:07:46 +02:00
b0d71597f0 update changelog 2022-05-09 14:58:39 +02:00
226f28dc7b Move some directives up top 2022-05-09 14:53:52 +02:00
398d04dc50 fixed tests 2022-05-09 11:15:18 +02:00
80a5ed3c5b added back fsfw namespace 2022-05-09 11:06:45 +02:00
5d5a355110 Merge remote-tracking branch 'upstream/development' into mueller/extend-version-class 2022-05-09 11:04:15 +02:00
6bfdace512 update changelog 2022-05-09 11:00:31 +02:00
16e55a98ce important bugfix for TCP server 2022-05-09 10:57:23 +02:00
79f17843d8 update changelog 2022-05-09 10:50:29 +02:00
e5e163bdbf mark unused function 2022-05-09 10:47:56 +02:00
4e4820af05 bugfix for prepareHealthSetReply function 2022-05-09 10:47:23 +02:00
3332f68ce7 Tested only std::numeric_limits in MSVC 2022-05-02 17:22:13 +02:00
54feb77770 Proposed fix for gcc and clang 2022-05-02 16:14:23 +02:00
1a07864a5f Merge pull request 'CCSDS Time CUC Tests' (#593) from gaisser/fsfw:gaisser_cuc_tests into development
Reviewed-on: fsfw/fsfw#593
2022-05-02 15:29:48 +02:00
3e9d6bdbb9 Merge branch 'development' into gaisser_cuc_tests 2022-05-02 15:24:32 +02:00
c295539c79 Merge pull request 'Fixes to allow compilation on MacOS' (#611) from mueller/mac-os into development
Reviewed-on: fsfw/fsfw#611
2022-05-02 15:22:19 +02:00
cddf16f941 Merge branch 'development' into mueller/mac-os 2022-05-02 15:15:53 +02:00
a3dee05fe3 Merge pull request 'space packet bug fix' (#607) from meier/spacePacketBugFix into development
Reviewed-on: fsfw/fsfw#607
2022-05-02 15:15:28 +02:00
8edf4c3c8d Merge branch 'development' into meier/spacePacketBugFix 2022-05-02 15:10:32 +02:00
7801c6effe Merge remote-tracking branch 'upstream/development' into mueller/new-ss-adder-functions 2022-05-02 15:09:09 +02:00
8cc94a55ab Merge pull request 'Bump Catch2 dependency & Catch2 pre-installed for CI/CD' (#605) from mueller/bump-catch2 into development
Reviewed-on: fsfw/fsfw#605
2022-05-02 15:03:08 +02:00
b62c19a364 Merge branch 'development' into mueller/extend-version-class 2022-05-02 14:48:23 +02:00
daffb6b666 Merge branch 'development' into gaisser_cuc_tests 2022-05-02 14:45:33 +02:00
7cfb1e6076 Merge branch 'development' into mueller/bump-catch2 2022-05-02 14:36:44 +02:00
cc36baff78 Merge pull request 'Hotfix CMake & ETL' (#604) from mueller/hotfix-etl into development
Reviewed-on: fsfw/fsfw#604
2022-05-02 14:36:29 +02:00
4c65109ac0 Merge branch 'development' into meier/spacePacketBugFix 2022-05-02 14:36:24 +02:00
861bd15eda Merge branch 'development' into mueller/hotfix-etl 2022-05-02 14:20:40 +02:00
7b979eadff Merge pull request 'fix compiler warnings and auto-formatting' (#598) from eive/fsfw:mueller/compiler-warning-fixes-upstream-2 into development
Reviewed-on: fsfw/fsfw#598
2022-05-02 14:17:00 +02:00
16714ceb40 Merge branch 'development' into gaisser_cuc_tests 2022-05-02 13:58:17 +02:00
fea301bcc9 Merge remote-tracking branch 'origin/mueller/hotfix-etl' into mueller/mac-os 2022-05-02 09:35:28 +02:00
77450eb4b7 removed flag which does not exist 2022-05-02 09:09:41 +02:00
28015c4735 it compiles and runs 2022-05-01 17:48:49 +02:00
7d61e67d20 more macos changes 2022-04-30 19:02:41 +02:00
afcbc8be0a changes for MacOS 2022-04-30 18:40:22 +02:00
7a2269262b Merge branch 'development' into meier/spacePacketBugFix 2022-04-29 08:45:10 +02:00
9731dc1e61 space packet bug fix 2022-04-29 07:47:23 +02:00
bf2e0f2d73 added option to change initial submode 2022-04-28 16:49:13 +02:00
e98857fab4 update changelog 2022-04-28 14:37:21 +02:00
29b0a352fc added new functions to add sequences and tables 2022-04-28 14:26:00 +02:00
8642b13fd1 Merge branch 'mueller/hotfix-etl' into mueller/bump-catch2 2022-04-27 21:55:45 +02:00
6aa72892ed clean usage of FetchContent_MakeAvailable 2022-04-27 21:53:57 +02:00
70f0a72f1b added explicit checkout of v3.0.0-preview5 2022-04-27 13:54:15 +02:00
b5d890eedd install Catch2 for docker_d2 and update Jenkinsfile 2022-04-27 13:43:49 +02:00
50b1b48678 link Catch2 issue 2022-04-27 13:36:26 +02:00
0e0dbc74aa Merge branch 'mueller/hotfix-etl' into mueller/bump-catch2 2022-04-27 09:45:42 +02:00
8c34051d8b bump Catch2 revision 2022-04-27 09:45:20 +02:00
b00d83cb1a bump ETL revision 2022-04-27 09:41:16 +02:00
17e609c3a5 some more var replacements 2022-04-27 09:37:11 +02:00
64f0166b64 hotfix for new ETL dependency 2022-04-27 09:16:52 +02:00
c80f06fbcb hotfix for ETL lib dep 2022-04-27 09:08:17 +02:00
70eb8325a0 Merge remote-tracking branch 'upstream/development' into mueller/compiler-warning-fixes-upstream-2 2022-04-27 08:47:45 +02:00
8e4ad10627 Merge remote-tracking branch 'upstream/development' into mueller/extend-version-class 2022-04-27 08:46:18 +02:00
e796f82203 Merge pull request 'gpio bug fix' (#602) from KSat/fsfw:hoffmann/gpioBugfix into development
Reviewed-on: fsfw/fsfw#602
2022-04-27 08:41:54 +02:00
5b7ca8c13c update CHANGELOG.md, apply afmt 2022-04-27 08:39:21 +02:00
031739ef51 Merge branch 'development' into hoffmann/gpioBugfix 2022-04-25 15:45:21 +02:00
80be937d9d Merge remote-tracking branch 'upstream/development' into mueller/compiler-warning-fixes-upstream-2 2022-04-25 15:24:17 +02:00
d62ee6a611 Merge remote-tracking branch 'upstream/development' into mueller/extend-version-class 2022-04-25 15:23:46 +02:00
b8516b15cb Merge pull request 'Added an additional conversion function' (#584) from eive/fsfw:mueller/clock-addition into development
Reviewed-on: fsfw/fsfw#584
2022-04-25 15:22:07 +02:00
4032228005 Merge remote-tracking branch 'upstream/development' into mueller/extend-version-class 2022-04-25 15:15:54 +02:00
ac5a54b5da Merge branch 'development' into mueller/clock-addition 2022-04-25 15:12:24 +02:00
29015b340b update changelog 2022-04-25 15:10:50 +02:00
64274acbeb Merge pull request 'Add ETL dependency' (#592) from KSat/fsfw:mueller/add-etl-dependency into development
Reviewed-on: fsfw/fsfw#592
2022-04-25 15:08:05 +02:00
ff98c42514 Merge branch 'development' into mueller/clock-addition 2022-04-25 14:54:22 +02:00
126ac52975 Merge pull request 'Allow passing a MqArgs struct to the MQ creation' (#583) from eive/fsfw:mueller/ipc-pass-arbitrary-args-to-mq into development
Reviewed-on: fsfw/fsfw#583
2022-04-25 14:43:52 +02:00
70d3197212 gpio init bug fix
Return values from configureGpios were not checked
2022-04-25 14:32:05 +02:00
dd90980520 push test 2022-04-25 14:19:03 +02:00
352ab43c1f Merge remote-tracking branch 'upstream/development' into mueller/add-etl-dependency 2022-04-12 17:11:41 +02:00
07f5dbb9ac Merge branch 'development' into mueller/compiler-warning-fixes-upstream-2 2022-04-12 17:08:56 +02:00
97e98eae24 Merge branch 'development' into mueller/ipc-pass-arbitrary-args-to-mq 2022-04-12 17:06:30 +02:00
afce942bf8 Merge branch 'development' into mueller/compiler-warning-fixes-upstream-2 2022-04-11 17:33:04 +02:00
a1d7a56dfa small fix 2022-04-11 17:14:43 +02:00
cb78fefbb3 afmt 2022-04-11 17:14:04 +02:00
c55925959b Merge branch 'mueller/add-etl-dependency' of https://egit.irs.uni-stuttgart.de/KSat/fsfw into mueller/add-etl-dependency 2022-04-11 16:44:30 +02:00
4f0669c574 doc update 2022-04-11 16:44:20 +02:00
f0d996ffd2 Merge branch 'development' into mueller/add-etl-dependency 2022-04-11 16:17:46 +02:00
f4d05c2c9c Merge branch 'mueller/ipc-pass-arbitrary-args-to-mq' of https://egit.irs.uni-stuttgart.de/eive/fsfw into mueller/ipc-pass-arbitrary-args-to-mq 2022-04-11 16:13:55 +02:00
d1151ca707 changelog update 2022-04-11 16:13:47 +02:00
82f46992f6 Merge branch 'development' into mueller/ipc-pass-arbitrary-args-to-mq 2022-04-11 16:11:57 +02:00
9947a648df fix compiler warnings 2022-04-11 16:06:13 +02:00
b2252bdc0b Merge remote-tracking branch 'upstream/development' into mueller/add-etl-dependency 2022-04-04 14:18:30 +02:00
a3930dafc5 Moved unused constructors 2022-03-28 21:37:25 +02:00
4f9797af3b Updated CCSDS CuC Functions 2022-03-28 21:24:33 +02:00
1a530633ca small fix 2022-03-28 21:10:51 +02:00
8037e8074b more docs 2022-03-28 21:03:18 +02:00
d07e0e5576 trying something 2022-03-28 21:01:26 +02:00
5525466b52 update changelog 2022-03-28 20:57:30 +02:00
c2a89bf709 bugfix 2022-03-28 20:57:13 +02:00
8dd0b2608d cache version variables 2022-03-28 20:55:34 +02:00
05495077ec doc update 2022-03-28 20:53:39 +02:00
8ff9eadf30 update changelog, add basic instructions for etl 2022-03-28 20:43:36 +02:00
082c86ea18 link ETL lib as well 2022-03-28 20:18:49 +02:00
2800d6f28c add ETL dependency 2022-03-28 20:16:11 +02:00
b4effe7a46 Clang format 2022-03-28 18:33:24 +02:00
e6e71436c2 Added more tests 2022-03-28 18:32:51 +02:00
a887f852c8 Merge branch 'development' into mueller/clock-addition 2022-03-28 15:45:58 +02:00
0b3255e463 Fixed tests 2022-03-28 15:17:59 +02:00
631a531212 Merge branch 'development' into mueller/clock-addition 2022-03-28 14:51:23 +02:00
665d8cd479 Applied clang format 2022-03-25 18:48:53 +01:00
10398855a9 Added more unittest coverage
Added Mutex for gmtime functions
Moved Statics used in ClockCommon to ClockCommon
2022-03-25 18:47:31 +01:00
d0fec93dc3 argument order inversion 2022-03-25 13:42:49 +01:00
59ab54b2fb call corrections 2022-03-25 13:41:37 +01:00
7095999bd2 remove CCSDSTime function 2022-03-25 13:34:35 +01:00
7ffb4107d2 added missing docs 2022-03-25 13:34:08 +01:00
9ce59d3c75 added an additional conversion function
- timeval to TimeOfDay_t
2022-03-22 17:54:09 +01:00
128 changed files with 1547 additions and 1529 deletions

View File

@ -12,6 +12,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## 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
and mode
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
- 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
- Place `Version` class outside of `fsfw` namespace. It is generic
- 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
- 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
- use `int` for version numbers to allow unset or uninitialized version
- 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
- 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.
- 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
@ -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
inside `fsfw/version.h`
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
- 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
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]

View File

@ -1,13 +1,85 @@
cmake_minimum_required(VERSION 3.13)
set(FSFW_VERSION_IF_GIT_FAILS 4)
set(FSFW_SUBVERSION_IF_GIT_FAILS 0)
set(FSFW_REVISION_IF_GIT_FAILS 0)
set(MSG_PREFIX "fsfw |")
# 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/cmake-modules")
set(MSG_PREFIX "fsfw |")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake-modules/bilke")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake-modules/rpavlik")
##########################
# Version file handling #
##########################
set(FSFW_VERSION_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
"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
option(FSFW_ADD_SGP4_PROPAGATOR "Add SGP4 propagator code" OFF)
set(LIB_FSFW_NAME fsfw)
set(FSFW_TEST_TGT fsfw-tests)
set(FSFW_DUMMY_TGT fsfw-dummy)
project(${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)
message(STATUS "${MSG_PREFIX} Building the FSFW unittests in addition to the static library")
# 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
if(NOT Catch2_FOUND)
message(STATUS "${MSG_PREFIX} Catch2 installation not found. Downloading Catch2 library with FetchContent")
@ -91,12 +131,10 @@ if(FSFW_BUILD_UNITTESTS)
FetchContent_Declare(
Catch2
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
GIT_TAG v3.0.0-preview4
GIT_TAG ${FSFW_CATCH2_LIB_VERSION}
)
FetchContent_MakeAvailable(Catch2)
#fixes regression -preview4, to be confirmed in later releases
set_target_properties(Catch2 PROPERTIES DEBUG_POSTFIX "")
list(APPEND FSFW_FETCH_CONTENT_TARGETS Catch2)
endif()
set(FSFW_CONFIG_PATH tests/src/fsfw_tests/unit/testcfg)
@ -116,6 +154,42 @@ if(FSFW_BUILD_UNITTESTS)
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_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}
)
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
if(OS_FSFW AND NOT FSFW_OSAL)
message(WARNING "${MSG_PREFIX} Please pass the FSFW OSAL as FSFW_OSAL instead of OS_FSFW")
@ -183,7 +250,7 @@ else()
endif()
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")
@ -377,6 +444,7 @@ target_compile_options(${LIB_FSFW_NAME} PRIVATE
)
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
${FSFW_ETL_LINK_TARGET}
${FSFW_ADDITIONAL_LINK_LIBS}
)
@ -392,3 +460,18 @@ add_custom_command(
POST_BUILD
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 ""
)

View File

@ -11,9 +11,15 @@ with Airbus Defence and Space GmbH.
## 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:
@ -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
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
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`
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.
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`.

View File

@ -6,3 +6,9 @@ RUN apt-get --yes upgrade
#tzdata is a dependency, won't install otherwise
ARG DEBIAN_FRONTEND=noninteractive
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

View File

@ -3,7 +3,7 @@ pipeline {
BUILDDIR = 'build-tests'
}
agent {
docker { image 'fsfw-ci:d1'}
docker { image 'fsfw-ci:d2'}
}
stages {
stage('Clean') {

View File

@ -8,6 +8,7 @@
function(determine_version_with_git)
include(GetGitRevisionDescription)
git_describe(VERSION ${ARGN})
get_git_head_revision(GIT_BRANCH HASH_VAR)
string(FIND ${VERSION} "." VALID_VERSION)
if(VALID_VERSION EQUAL -1)
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]+\\.([0-9]+).*" "\\1" _VERSION_PATCH "${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})
list(APPEND GIT_INFO ${_VERSION_MAJOR})
list(APPEND GIT_INFO ${_VERSION_MINOR})
list(APPEND GIT_INFO ${_VERSION_PATCH})
list(APPEND GIT_INFO ${VERSION_SHA1})
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}")
endfunction()

View File

@ -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()

View File

@ -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
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.

View 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()

View File

@ -1,4 +1,4 @@
#
#
# Internal file for GetGitRevisionDescription.cmake
#
# Requires CMake 2.6 or newer (uses the 'function' command)
@ -8,10 +8,12 @@
# http://academic.cleardefinition.com
# 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.
# (See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
# SPDX-License-Identifier: BSL-1.0
set(HEAD_HASH)
@ -22,10 +24,13 @@ if(HEAD_CONTENTS MATCHES "ref")
# named branch
string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}")
if(EXISTS "@GIT_DIR@/${HEAD_REF}")
configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
elseif(EXISTS "@GIT_DIR@/logs/${HEAD_REF}")
configure_file("@GIT_DIR@/logs/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
set(HEAD_HASH "${HEAD_REF}")
configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
else()
configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY)
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()
else()
# detached HEAD
@ -33,6 +38,6 @@ else()
endif()
if(NOT HEAD_HASH)
file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024)
string(STRIP "${HEAD_HASH}" HEAD_HASH)
file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024)
string(STRIP "${HEAD_HASH}" HEAD_HASH)
endif()

View 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.

View 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.

View 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
View 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()

View File

@ -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
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
-------------------
@ -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`
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.
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`.

View File

@ -375,16 +375,13 @@ float MgmLIS3MDLHandler::getSensitivityFactor(MGMLIS3MDL::Sensitivies sens) {
ReturnValue_t MgmLIS3MDLHandler::enableTemperatureSensor(const uint8_t *commandData,
size_t commandDataLen) {
if(commandData == nullptr) {
return INVALID_COMMAND_PARAMETER;
}
triggerEvent(CHANGE_OF_SETUP_PARAMETER);
uint32_t size = 2;
commandBuffer[0] = writeCommand(MGMLIS3MDL::CTRL_REG1);
if (commandDataLen > 1) {
return INVALID_NUMBER_OR_LENGTH_OF_PARAMETERS;
}
switch (commandData[0]) {
switch (*commandData) {
case (MGMLIS3MDL::ON): {
commandBuffer[1] = registers[0] | (1 << 7);
break;

View File

@ -12,9 +12,14 @@ if(FSFW_HAL_LINUX_ADD_PERIPHERAL_DRIVERS)
if(FSFW_HAL_LINUX_ADD_LIBGPIOD)
add_subdirectory(gpio)
endif()
add_subdirectory(spi)
add_subdirectory(i2c)
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()
add_subdirectory(uio)

View File

@ -1,27 +0,0 @@
#ifndef FSFW_HAL_SRC_FSFW_HAL_LINUX_GPIO_GPIO_H_
#define FSFW_HAL_SRC_FSFW_HAL_LINUX_GPIO_GPIO_H_
#include "fsfw_hal/common/gpio/GpioIF.h"
#include "fsfw_hal/common/gpio/gpioDefinitions.h"
/**
* @brief Additional abstraction layer for handling GPIOs.
*
* @author J. Meier
*/
class Gpio {
public:
Gpio(gpioId_t gpioId, GpioIF* gpioIF) : gpioId(gpioId), gpioIF(gpioIF) {
if (gpioIF == nullptr) {
sif::error << "Gpio::Gpio: Invalid GpioIF" << std::endl;
}
}
ReturnValue_t pullHigh() { return gpioIF->pullHigh(gpioId); }
ReturnValue_t pullLow() { return gpioIF->pullLow(gpioId); }
private:
gpioId_t gpioId = gpio::NO_GPIO;
GpioIF* gpioIF = nullptr;
};
#endif /* FSFW_HAL_SRC_FSFW_HAL_LINUX_GPIO_GPIO_H_ */

View File

@ -44,6 +44,7 @@ ReturnValue_t LinuxLibgpioIF::addGpios(GpioCookie* gpioCookie) {
}
ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) {
ReturnValue_t result = RETURN_OK;
for (auto& gpioConfig : mapToAdd) {
auto& gpioType = gpioConfig.second->gpioType;
switch (gpioType) {
@ -55,7 +56,7 @@ ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) {
if (regularGpio == nullptr) {
return GPIO_INVALID_INSTANCE;
}
configureGpioByChip(gpioConfig.first, *regularGpio);
result = configureGpioByChip(gpioConfig.first, *regularGpio);
break;
}
case (gpio::GpioTypes::GPIO_REGULAR_BY_LABEL): {
@ -63,7 +64,7 @@ ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) {
if (regularGpio == nullptr) {
return GPIO_INVALID_INSTANCE;
}
configureGpioByLabel(gpioConfig.first, *regularGpio);
result = configureGpioByLabel(gpioConfig.first, *regularGpio);
break;
}
case (gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME): {
@ -71,7 +72,7 @@ ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) {
if (regularGpio == nullptr) {
return GPIO_INVALID_INSTANCE;
}
configureGpioByLineName(gpioConfig.first, *regularGpio);
result = configureGpioByLineName(gpioConfig.first, *regularGpio);
break;
}
case (gpio::GpioTypes::CALLBACK): {
@ -83,8 +84,11 @@ ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) {
gpioCallback->initValue, gpioCallback->callbackArgs);
}
}
if (result != RETURN_OK) {
return GPIO_INIT_FAILED;
}
}
return RETURN_OK;
return result;
}
ReturnValue_t LinuxLibgpioIF::configureGpioByLabel(gpioId_t gpioId,

View File

@ -29,6 +29,8 @@ class LinuxLibgpioIF : public GpioIF, public SystemObject {
HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 4);
static constexpr ReturnValue_t GPIO_DUPLICATE_DETECTED =
HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 5);
static constexpr ReturnValue_t GPIO_INIT_FAILED =
HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 6);
LinuxLibgpioIF(object_id_t objectId);
virtual ~LinuxLibgpioIF();

View File

@ -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,
const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed)

View File

@ -265,6 +265,7 @@ void UartComIF::configureBaudrate(struct termios* options, UartCookie* uartCooki
cfsetispeed(options, B230400);
cfsetospeed(options, B230400);
break;
#ifndef __APPLE__
case UartBaudRate::RATE_460800:
cfsetispeed(options, B460800);
cfsetospeed(options, B460800);
@ -313,6 +314,7 @@ void UartComIF::configureBaudrate(struct termios* options, UartCookie* uartCooki
cfsetispeed(options, B4000000);
cfsetospeed(options, B4000000);
break;
#endif // ! __APPLE__
default:
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "UartComIF::configureBaudrate: Baudrate not supported" << std::endl;

View File

@ -2,8 +2,8 @@
#include <fsfw/serviceinterface.h>
UartCookie::UartCookie(object_id_t handlerId, std::string deviceFile, UartBaudRate baudrate,
size_t maxReplyLen, UartModes uartMode)
UartCookie::UartCookie(object_id_t handlerId, std::string deviceFile, UartModes uartMode,
UartBaudRate baudrate, size_t maxReplyLen)
: handlerId(handlerId),
deviceFile(deviceFile),
uartMode(uartMode),

View File

@ -69,8 +69,8 @@ class UartCookie : public CookieIF {
* 8 databits (number of bits transfered with one uart frame)
* One stop bit
*/
UartCookie(object_id_t handlerId, std::string deviceFile, UartBaudRate baudrate,
size_t maxReplyLen, UartModes uartMode = UartModes::NON_CANONICAL);
UartCookie(object_id_t handlerId, std::string deviceFile, UartModes uartMode,
UartBaudRate baudrate, size_t maxReplyLen);
virtual ~UartCookie();

View File

@ -1,5 +1,6 @@
target_sources(${LIB_FSFW_NAME} PRIVATE
version.cpp
versionAutogen.cpp
)
# Core

View File

@ -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_ */

View File

@ -16,8 +16,8 @@ class CommandActionHelper {
public:
CommandActionHelper(CommandsActionsIF* owner);
virtual ~CommandActionHelper();
ReturnValue_t commandAction(object_id_t commandTo, ActionId_t actionId,
const uint8_t* data = nullptr, uint32_t size = 0);
ReturnValue_t commandAction(object_id_t commandTo, ActionId_t actionId, const uint8_t* data,
uint32_t size);
ReturnValue_t commandAction(object_id_t commandTo, ActionId_t actionId, SerializeIF* data);
ReturnValue_t initialize();
ReturnValue_t handleReply(CommandMessage* reply);

View File

@ -12,9 +12,7 @@ object_id_t CFDPHandler::packetDestination = 0;
CFDPHandler::CFDPHandler(object_id_t setObjectId, CFDPDistributor* dist)
: SystemObject(setObjectId) {
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
requestQueue = QueueFactory::instance()->createMessageQueue(
CFDP_HANDLER_MAX_RECEPTION, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
requestQueue = QueueFactory::instance()->createMessageQueue(CFDP_HANDLER_MAX_RECEPTION);
distributor = dist;
}

View File

@ -44,7 +44,7 @@ class HeaderSerializer : public SerializeIF, public PduHeaderIF {
cfdp::WidthInBytes getLenEntityIds() const override;
cfdp::WidthInBytes getLenSeqNum() const override;
cfdp::SegmentMetadataFlag getSegmentMetadataFlag() const override;
bool hasSegmentMetadataFlag() const;
bool hasSegmentMetadataFlag() const override;
void setSegmentationControl(cfdp::SegmentationControl);
void getSourceId(cfdp::EntityId& sourceId) const override;

View File

@ -2,6 +2,7 @@
#define FIXEDARRAYLIST_H_
#include <cmath>
#include <limits>
#include "ArrayList.h"
/**
@ -9,10 +10,8 @@
*/
template <typename T, size_t MAX_SIZE, typename count_t = uint8_t>
class FixedArrayList : public ArrayList<T, count_t> {
#if !defined(_MSC_VER)
static_assert(MAX_SIZE <= (std::pow(2, sizeof(count_t) * 8) - 1),
static_assert(MAX_SIZE <= std::numeric_limits<count_t>::max(),
"count_t is not large enough to hold MAX_SIZE");
#endif
private:
T data[MAX_SIZE];

View File

@ -10,7 +10,7 @@ class HybridIterator : public LinkedElement<T>::Iterator, public ArrayList<T, co
HybridIterator() {}
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;
}

View File

@ -13,9 +13,7 @@ ControllerBase::ControllerBase(object_id_t setObjectId, object_id_t parentId,
submode(SUBMODE_NONE),
modeHelper(this),
healthHelper(this, setObjectId) {
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
commandQueue = QueueFactory::instance()->createMessageQueue(
commandQueueDepth, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
commandQueue = QueueFactory::instance()->createMessageQueue(commandQueueDepth);
}
ControllerBase::~ControllerBase() { QueueFactory::instance()->deleteMessageQueue(commandQueue); }

View File

@ -55,7 +55,7 @@ class ControllerBase : public HasModesIF,
virtual void performControlOperation() = 0;
virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
uint32_t *msToReachTheMode) = 0;
uint32_t *msToReachTheMode) override = 0;
const object_id_t parentId;
@ -80,9 +80,9 @@ class ControllerBase : public HasModesIF,
/** Mode helpers */
virtual void modeChanged(Mode_t mode, Submode_t submode);
virtual void startTransition(Mode_t mode, Submode_t submode);
virtual void getMode(Mode_t *mode, Submode_t *submode);
virtual void setToExternalControl();
virtual void startTransition(Mode_t mode, Submode_t submode) override;
virtual void getMode(Mode_t *mode, Submode_t *submode) override;
virtual void setToExternalControl() override;
virtual void announceMode(bool recursive);
/** HK helpers */
virtual void changeHK(Mode_t mode, Submode_t submode, bool enable);

View File

@ -1,4 +1,4 @@
target_sources(${LIB_FSFW_NAME} PRIVATE
PoolDataSetBase.cpp
PoolEntry.cpp
target_sources(${LIB_FSFW_NAME} PRIVATE
PoolDataSetBase.cpp
PoolEntry.cpp
)

View File

@ -109,7 +109,7 @@ class PoolDataSetBase : public PoolDataSetIF, public SerializeIF, public HasRetu
*/
virtual ReturnValue_t unlockDataPool() override;
virtual uint16_t getFillCount() const;
virtual uint16_t getFillCount() const override;
/* SerializeIF implementations */
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, const size_t maxSize,

View File

@ -7,26 +7,24 @@
#include "fsfw/serviceinterface/ServiceInterface.h"
template <typename T>
PoolEntry<T>::PoolEntry(uint8_t len, bool setValid) : length(len), valid(setValid) {
this->address = new T[this->length]();
std::memset(this->address, 0, this->getByteSize());
}
template <typename T>
PoolEntry<T>::PoolEntry(std::initializer_list<T> initValues, bool setValid)
: length(static_cast<uint8_t>(initValues.size())), valid(setValid) {
this->address = new T[this->length]();
if (initValues.size() > 0) {
std::copy(initValues.begin(), initValues.end(), this->address);
PoolEntry<T>::PoolEntry(std::initializer_list<T> initValue, bool setValid)
: length(static_cast<uint8_t>(initValue.size())), valid(setValid) {
this->address = new T[this->length];
if (initValue.size() == 0) {
std::memset(this->address, 0, this->getByteSize());
} else {
std::copy(initValue.begin(), initValue.end(), this->address);
}
}
template <typename T>
PoolEntry<T>::PoolEntry(const T* initValue, uint8_t setLength, bool setValid)
PoolEntry<T>::PoolEntry(T* initValue, uint8_t setLength, bool setValid)
: length(setLength), valid(setValid) {
this->address = new T[this->length]();
this->address = new T[this->length];
if (initValue != nullptr) {
std::memcpy(this->address, initValue, this->getByteSize());
} else {
std::memset(this->address, 0, this->getByteSize());
}
}

View File

@ -33,9 +33,6 @@ class PoolEntry : public PoolEntryIF {
"instead! The ECSS standard defines a boolean as a one bit "
"field. Therefore it is preferred to store a boolean as an "
"uint8_t");
PoolEntry(uint8_t len = 1, bool setValid = false);
/**
* @brief In the classe's constructor, space is allocated on the heap and
* potential initialization values are copied to that space.
@ -52,7 +49,7 @@ class PoolEntry : public PoolEntryIF {
* @param setValid
* Sets the initialization flag. It is invalid by default.
*/
PoolEntry(std::initializer_list<T> initValue, bool setValid = false);
PoolEntry(std::initializer_list<T> initValue = {0}, bool setValid = false);
/**
* @brief In the classe's constructor, space is allocated on the heap and
@ -65,7 +62,7 @@ class PoolEntry : public PoolEntryIF {
* @param setValid
* Sets the initialization flag. It is invalid by default.
*/
PoolEntry(const T* initValue, uint8_t setLength = 1, bool setValid = false);
PoolEntry(T* initValue, uint8_t setLength = 1, bool setValid = false);
//! Explicitely deleted copy ctor, copying is not allowed.
PoolEntry(const PoolEntry&) = delete;

View File

@ -94,13 +94,14 @@ ReturnValue_t LocalPoolDataSetBase::serializeWithValidityBuffer(
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
const uint8_t validityMaskSize = std::ceil(static_cast<float>(fillCount) / 8.0);
uint8_t *validityPtr = nullptr;
#ifdef _MSC_VER
/* Use a std::vector here because MSVC will (rightly) not create a fixed size array
with a non constant size specifier */
std::vector<uint8_t> validityMask(validityMaskSize);
#if defined(_MSC_VER) || defined(__clang__)
// Use a std::vector here because MSVC will (rightly) not create a fixed size array
// with a non constant size specifier. The Apple compiler (LLVM) will not accept
// the initialization of a variable sized array
std::vector<uint8_t> validityMask(validityMaskSize, 0);
validityPtr = validityMask.data();
#else
uint8_t validityMask[validityMaskSize] = {0};
uint8_t validityMask[validityMaskSize] = {};
validityPtr = validityMask;
#endif
uint8_t validBufferIndex = 0;

View File

@ -162,7 +162,6 @@ class LocalPoolDataSetBase : public PoolDataSetBase, public MarkChangedIF {
object_id_t getCreatorObjectId();
bool getReportingEnabled() const;
void setReportingEnabled(bool enabled);
/**
* Returns the current periodic HK generation interval this set
@ -190,6 +189,7 @@ class LocalPoolDataSetBase : public PoolDataSetBase, public MarkChangedIF {
* Used for periodic generation.
*/
bool reportingEnabled = false;
void setReportingEnabled(bool enabled);
void initializePeriodicHelper(float collectionInterval, dur_millis_t minimumPeriodicInterval,
uint8_t nonDiagIntervalFactor = 5);

View File

@ -23,8 +23,8 @@ class LocalPoolObjectBase : public PoolVariableIF, public HasReturnvaluesIF, pub
LocalPoolObjectBase(object_id_t poolOwner, lp_id_t poolId, DataSetIF* dataSet = nullptr,
pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE);
void setReadWriteMode(pool_rwm_t newReadWriteMode);
pool_rwm_t getReadWriteMode() const;
void setReadWriteMode(pool_rwm_t newReadWriteMode) override;
pool_rwm_t getReadWriteMode() const override;
bool isValid() const override;
void setValid(bool valid) override;

View File

@ -26,7 +26,11 @@ void AssemblyBase::performChildOperation() {
void AssemblyBase::startTransition(Mode_t mode, Submode_t submode) {
doStartTransition(mode, submode);
triggerModeHelperEvents(mode, submode);
if (modeHelper.isForced()) {
triggerEvent(FORCING_MODE, mode, submode);
} else {
triggerEvent(CHANGING_MODE, mode, submode);
}
}
void AssemblyBase::doStartTransition(Mode_t mode, Submode_t submode) {
@ -73,10 +77,9 @@ bool AssemblyBase::handleChildrenChangedHealth() {
}
HealthState healthState = healthHelper.healthTable->getHealth(iter->first);
if (healthState == HasHealthIF::NEEDS_RECOVERY) {
triggerEvent(TRYING_RECOVERY, iter->first, 0);
triggerEvent(TRYING_RECOVERY);
recoveryState = RECOVERY_STARTED;
recoveringDevice = iter;
// The user needs to take care of commanding the children off in commandChildren
doStartTransition(targetMode, targetSubmode);
} else {
triggerEvent(CHILD_CHANGED_HEALTH);
@ -225,9 +228,6 @@ ReturnValue_t AssemblyBase::handleHealthReply(CommandMessage* message) {
bool AssemblyBase::checkAndHandleRecovery() {
switch (recoveryState) {
case RECOVERY_STARTED:
// The recovery was already start in #handleChildrenChangedHealth and we just need
// to wait for an off time period.
// TODO: make time period configurable
recoveryState = RECOVERY_WAIT;
recoveryOffTimer.resetTimer();
return true;
@ -266,11 +266,3 @@ void AssemblyBase::overwriteDeviceHealth(object_id_t objectId, HasHealthIF::Heal
modeHelper.setForced(true);
sendHealthCommand(childrenMap[objectId].commandQueue, EXTERNAL_CONTROL);
}
void AssemblyBase::triggerModeHelperEvents(Mode_t mode, Submode_t submode) {
if (modeHelper.isForced()) {
triggerEvent(FORCING_MODE, mode, submode);
} else {
triggerEvent(CHANGING_MODE, mode, submode);
}
}

View File

@ -12,8 +12,7 @@
* Documentation: Dissertation Baetz p.156, 157.
*
* This class reduces the complexity of controller components which would
* otherwise be needed for the handling of redundant devices. However, it can also be used to
* manage the mode keeping and recovery of non-redundant devices
* otherwise be needed for the handling of redundant devices.
*
* The template class monitors mode and health state of its children
* and checks availability of devices on every detected change.
@ -27,9 +26,11 @@
*
* Important:
*
* The implementation must call #registerChild for all commanded children during initialization.
* The implementation must call registerChild(object_id_t child)
* for all commanded children during initialization.
* The implementation must call the initialization function of the base class.
* (This will call the function in SubsystemBase)
*
*/
class AssemblyBase : public SubsystemBase {
public:
@ -46,14 +47,13 @@ class AssemblyBase : public SubsystemBase {
protected:
/**
* Command children to reach [mode,submode] combination. Can be done by setting
* #commandsOutstanding correctly, or using #executeTable. In case of an FDIR recovery,
* the user needs to ensure that the target devices are healthy. If a device is not healthy,
* a recovery might be on-going and the device needs to be commanded to off first.
* Command children to reach [mode,submode] combination
* Can be done by setting #commandsOutstanding correctly,
* or using executeTable()
* @param mode
* @param submode
* @return
* - @c RETURN_OK if OK
* - @c RETURN_OK if ok
* - @c NEED_SECOND_STEP if children need to be commanded again
*/
virtual ReturnValue_t commandChildren(Mode_t mode, Submode_t submode) = 0;
@ -120,19 +120,8 @@ class AssemblyBase : public SubsystemBase {
virtual ReturnValue_t handleHealthReply(CommandMessage *message);
/**
* @brief Default periodic handler
* @details
* This is the default periodic handler which will be called by the SubsystemBase
* performOperation. It performs the child transitions or reacts to changed health/mode states
* of children objects
*/
virtual void performChildOperation() override;
virtual void performChildOperation();
/**
* This function handles changed mode or health states of children
* @return
*/
bool handleChildrenChanged();
/**
@ -145,37 +134,12 @@ class AssemblyBase : public SubsystemBase {
bool handleChildrenChangedHealth();
/**
* Core transition handler. The default implementation will only do something if
* #commandsOutstanding is smaller or equal to zero, which means that all mode commands
* from the #doPerformTransition call were executed successfully.
*
* Unless a second step was requested, the function will then use #checkChildrenState to
* determine whether the target mode was reached.
*
* There is some special handling for certain (internal) modes:
* - A second step is necessary. #commandChildren will be performed again
* - The device health was overwritten. #commandChildren will be called
* - A recovery is ongoing. #checkAndHandleRecovery will be called.
*/
virtual void handleChildrenTransition();
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, uint32_t *msToReachTheMode);
/**
* Calls #doStartTransition and triggers an informative event as well that the mode will
* change
* @param mode
* @param submode
*/
virtual void startTransition(Mode_t mode, Submode_t submode);
/**
* This function starts the transition by setting the internal #targetSubmode and #targetMode
* variables and then calling the #commandChildren function.
* @param mode
* @param submode
*/
virtual void doStartTransition(Mode_t mode, Submode_t submode);
virtual bool isInTransition();
@ -196,7 +160,7 @@ class AssemblyBase : public SubsystemBase {
* Manages recovery of a device
* @return true if recovery is still ongoing, false else.
*/
virtual bool checkAndHandleRecovery();
bool checkAndHandleRecovery();
/**
* Helper method to overwrite health state of one of the children.
@ -204,8 +168,6 @@ class AssemblyBase : public SubsystemBase {
* @param objectId Must be a registered child.
*/
void overwriteDeviceHealth(object_id_t objectId, HasHealthIF::HealthState oldHealth);
void triggerModeHelperEvents(Mode_t mode, Submode_t submode);
};
#endif /* FSFW_DEVICEHANDLERS_ASSEMBLYBASE_H_ */

View File

@ -39,9 +39,8 @@ DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, object_id_t device
childTransitionDelay(5000),
transitionSourceMode(_MODE_POWER_DOWN),
transitionSourceSubMode(SUBMODE_NONE) {
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
commandQueue = QueueFactory::instance()->createMessageQueue(
cmdQueueSize, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
cmdQueueSize, MessageQueueMessage::MAX_MESSAGE_SIZE);
insertInCommandMap(RAW_COMMAND_ID);
cookieInfo.state = COOKIE_UNUSED;
cookieInfo.pendingCommand = deviceCommandMap.end();
@ -49,6 +48,9 @@ DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, object_id_t device
printWarningOrError(sif::OutputTypes::OUT_ERROR, "DeviceHandlerBase",
HasReturnvaluesIF::RETURN_FAILED, "Invalid cookie");
}
if (this->fdirInstance == nullptr) {
this->fdirInstance = new DeviceHandlerFailureIsolation(setObjectId, defaultFdirParentId);
}
}
void DeviceHandlerBase::setHkDestination(object_id_t hkDestination) {
@ -124,18 +126,6 @@ ReturnValue_t DeviceHandlerBase::initialize() {
if (result != RETURN_OK) {
return result;
}
if (this->fdirInstance == nullptr) {
this->fdirInstance =
new DeviceHandlerFailureIsolation(this->getObjectId(), defaultFdirParentId);
}
if (this->parent != objects::NO_OBJECT) {
HasModesIF* modeIF = ObjectManager::instance()->get<HasModesIF>(this->parent);
HasHealthIF* healthIF = ObjectManager::instance()->get<HasHealthIF>(this->parent);
if (modeIF != nullptr and healthIF != nullptr) {
setParentQueue(modeIF->getCommandQueue());
}
}
communicationInterface =
ObjectManager::instance()->get<DeviceCommunicationIF>(deviceCommunicationId);
@ -362,12 +352,14 @@ void DeviceHandlerBase::doStateMachine() {
}
} break;
case _MODE_WAIT_OFF: {
uint32_t currentUptime;
Clock::getUptime(&currentUptime);
if (powerSwitcher == nullptr) {
setMode(MODE_OFF);
break;
}
uint32_t currentUptime;
Clock::getUptime(&currentUptime);
if (currentUptime - timeoutStart >= powerSwitcher->getSwitchDelayMs()) {
triggerEvent(MODE_TRANSITION_FAILED, PowerSwitchIF::SWITCH_TIMEOUT, 0);
setMode(MODE_ERROR_ON);
@ -1407,8 +1399,6 @@ void DeviceHandlerBase::setTaskIF(PeriodicTaskIF* task) { executingTask = task;
void DeviceHandlerBase::debugInterface(uint8_t positionTracker, object_id_t objectId,
uint32_t parameter) {}
Submode_t DeviceHandlerBase::getInitialSubmode() { return SUBMODE_NONE; }
void DeviceHandlerBase::performOperationHook() {}
ReturnValue_t DeviceHandlerBase::initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
@ -1431,7 +1421,7 @@ ReturnValue_t DeviceHandlerBase::initializeAfterTaskCreation() {
this->poolManager.initializeAfterTaskCreation();
if (setStartupImmediately) {
startTransition(MODE_ON, getInitialSubmode());
startTransition(MODE_ON, SUBMODE_NONE);
}
return HasReturnvaluesIF::RETURN_OK;
}
@ -1515,11 +1505,3 @@ MessageQueueId_t DeviceHandlerBase::getCommanderQueueId(DeviceCommandId_t replyI
}
return commandIter->second.sendReplyTo;
}
void DeviceHandlerBase::setCustomFdir(FailureIsolationBase* fdir) { this->fdirInstance = fdir; }
void DeviceHandlerBase::setParent(object_id_t parent) { this->parent = parent; }
void DeviceHandlerBase::setPowerSwitcher(PowerSwitchIF* switcher) {
this->powerSwitcher = switcher;
}

View File

@ -103,9 +103,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
DeviceHandlerBase(object_id_t setObjectId, object_id_t deviceCommunication, CookieIF *comCookie,
FailureIsolationBase *fdirInstance = nullptr, size_t cmdQueueSize = 20);
void setCustomFdir(FailureIsolationBase *fdir);
void setParent(object_id_t parent);
void setPowerSwitcher(PowerSwitchIF *switcher);
void setHkDestination(object_id_t hkDestination);
/**
@ -166,7 +163,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
* @param counter Specifies which Action to perform
* @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
@ -176,7 +173,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
* Calls fillCommandAndReplyMap().
* @return
*/
virtual ReturnValue_t initialize();
virtual ReturnValue_t initialize() override;
/**
* @brief Intialization steps performed after all tasks have been created.
@ -652,12 +649,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
virtual void debugInterface(uint8_t positionTracker = 0, object_id_t objectId = 0,
uint32_t parameter = 0);
/**
* @brief Can be overwritten by a child to specify the initial submode when device has been set
* to startup immediately.
*/
virtual Submode_t getInitialSubmode();
protected:
static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_BASE;
@ -831,7 +822,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
/** Pointer to the used FDIR instance. If not provided by child,
* default class is instantiated. */
FailureIsolationBase *fdirInstance;
object_id_t parent = objects::NO_OBJECT;
//! To correctly delete the default instance.
bool defaultFDIRUsed;
@ -1068,11 +1058,12 @@ class DeviceHandlerBase : public DeviceHandlerIF,
* @param parameter1 Optional parameter 1
* @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.
*/
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.

View File

@ -29,7 +29,6 @@ ReturnValue_t DeviceHandlerFailureIsolation::eventReceived(EventMessage* event)
switch (event->getEvent()) {
case HasModesIF::MODE_TRANSITION_FAILED:
case HasModesIF::OBJECT_IN_INVALID_MODE:
case DeviceHandlerIF::DEVICE_WANTS_HARD_REBOOT:
// We'll try a recovery as long as defined in MAX_REBOOT.
// Might cause some AssemblyBase cycles, so keep number low.
handleRecovery(event->getEvent());

View File

@ -109,7 +109,6 @@ class DeviceHandlerIF {
static const Event INVALID_DEVICE_COMMAND = MAKE_EVENT(8, severity::LOW);
static const Event MONITORING_LIMIT_EXCEEDED = MAKE_EVENT(9, severity::LOW);
static const Event MONITORING_AMBIGUOUS = MAKE_EVENT(10, severity::HIGH);
static const Event DEVICE_WANTS_HARD_REBOOT = MAKE_EVENT(11, severity::HIGH);
static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_IF;

View File

@ -8,9 +8,7 @@ HealthDevice::HealthDevice(object_id_t setObjectId, MessageQueueId_t parentQueue
parentQueue(parentQueue),
commandQueue(),
healthHelper(this, setObjectId) {
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
commandQueue = QueueFactory::instance()->createMessageQueue(
3, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
commandQueue = QueueFactory::instance()->createMessageQueue(3);
}
HealthDevice::~HealthDevice() { QueueFactory::instance()->deleteMessageQueue(commandQueue); }

View File

@ -18,9 +18,8 @@ const LocalPool::LocalPoolConfig EventManager::poolConfig = {
EventManager::EventManager(object_id_t setObjectId)
: SystemObject(setObjectId), factoryBackend(0, poolConfig, false, true) {
mutex = MutexFactory::instance()->createMutex();
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
eventReportQueue = QueueFactory::instance()->createMessageQueue(
MAX_EVENTS_PER_CYCLE, EventMessage::EVENT_MESSAGE_SIZE, &mqArgs);
eventReportQueue = QueueFactory::instance()->createMessageQueue(MAX_EVENTS_PER_CYCLE,
EventMessage::EVENT_MESSAGE_SIZE);
}
EventManager::~EventManager() {
@ -47,20 +46,9 @@ ReturnValue_t EventManager::performOperation(uint8_t opCode) {
void EventManager::notifyListeners(EventMessage* message) {
lockMutex();
for (auto& listener : listenerList) {
if (listener.second.match(message)) {
ReturnValue_t result =
MessageQueueSenderIF::sendMessage(listener.first, message, message->getSender());
if (result != HasReturnvaluesIF::RETURN_OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << std::hex << "EventManager::notifyListeners: MSG to 0x" << std::setfill('0')
<< std::setw(8) << listener.first << " failed with result 0x" << std::setw(4)
<< result << std::setfill(' ') << std::endl;
#else
sif::printError("Sending message to listener 0x%08x failed with result %04x\n",
listener.first, result);
#endif
}
for (auto iter = listenerList.begin(); iter != listenerList.end(); ++iter) {
if (iter->second.match(message)) {
MessageQueueSenderIF::sendMessage(iter->first, message, message->getSender());
}
}
unlockMutex();
@ -201,19 +189,4 @@ void EventManager::printUtility(sif::OutputTypes printType, EventMessage* messag
}
}
void EventManager::printListeners() {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "Event manager listener MQ IDs:" << std::setfill('0') << std::hex << std::endl;
for (auto& listener : listenerList) {
sif::info << "0x" << std::setw(8) << listener.first << std::endl;
}
sif::info << std::dec << std::setfill(' ');
#else
sif::printInfo("Event manager listener MQ IDs:\n");
for (auto& listener : listenerList) {
sif::printInfo("0x%08x\n", listener.first);
}
#endif
}
#endif /* FSFW_OBJ_EVENT_TRANSLATION == 1 */

View File

@ -42,7 +42,6 @@ class EventManager : public EventManagerIF, public ExecutableObjectIF, public Sy
object_id_t reporterFrom = 0, object_id_t reporterTo = 0,
bool reporterInverted = false);
ReturnValue_t performOperation(uint8_t opCode);
void printListeners();
protected:
MessageQueueIF* eventReportQueue = nullptr;

View File

@ -9,9 +9,8 @@
FailureIsolationBase::FailureIsolationBase(object_id_t owner, object_id_t parent,
uint8_t messageDepth, uint8_t parameterDomainBase)
: ownerId(owner), faultTreeParent(parent), parameterDomainBase(parameterDomainBase) {
auto mqArgs = MqArgs(owner, static_cast<void*>(this));
eventQueue = QueueFactory::instance()->createMessageQueue(
messageDepth, EventMessage::EVENT_MESSAGE_SIZE, &mqArgs);
eventQueue =
QueueFactory::instance()->createMessageQueue(messageDepth, EventMessage::EVENT_MESSAGE_SIZE);
}
FailureIsolationBase::~FailureIsolationBase() {
@ -52,12 +51,11 @@ ReturnValue_t FailureIsolationBase::initialize() {
ObjectManager::instance()->get<ConfirmsFailuresIF>(faultTreeParent);
if (parentIF == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "FailureIsolationBase::intialize: Parent object "
<< "invalid" << std::endl;
sif::error << "Make sure it implements ConfirmsFailuresIF" << std::endl;
#else
sif::printError("FailureIsolationBase::intialize: Parent object invalid\n");
sif::printError("Make sure it implements ConfirmsFailuresIF\n");
sif::error << "FailureIsolationBase::intialize: Parent object"
<< "invalid." << std::endl;
#endif
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "Make sure it implements ConfirmsFailuresIF." << std::endl;
#endif
return ObjectManagerIF::CHILD_INIT_FAILED;
return RETURN_FAILED;

View File

@ -14,12 +14,13 @@ class FailureIsolationBase : public HasReturnvaluesIF,
public HasParametersIF {
public:
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::FDIR_1;
//! FDIR has an internal state, which changed from par2 (oldState) to par1 (newState).
static const Event FDIR_CHANGED_STATE = MAKE_EVENT(1, severity::INFO);
//! FDIR tries to restart device. Par1: event that caused recovery.
static const Event FDIR_STARTS_RECOVERY = MAKE_EVENT(2, severity::MEDIUM);
//! FDIR turns off device. Par1: event that caused recovery.
static const Event FDIR_TURNS_OFF_DEVICE = MAKE_EVENT(3, severity::MEDIUM);
static const Event FDIR_CHANGED_STATE =
MAKE_EVENT(1, severity::INFO); //!< FDIR has an internal state, which changed from par2
//!< (oldState) to par1 (newState).
static const Event FDIR_STARTS_RECOVERY = MAKE_EVENT(
2, severity::MEDIUM); //!< FDIR tries to restart device. Par1: event that caused recovery.
static const Event FDIR_TURNS_OFF_DEVICE = MAKE_EVENT(
3, severity::MEDIUM); //!< FDIR turns off device. Par1: event that caused recovery.
FailureIsolationBase(object_id_t owner, object_id_t parent = objects::NO_OBJECT,
uint8_t messageDepth = 10, uint8_t parameterDomainBase = 0xF0);

View File

@ -1,13 +1,13 @@
target_sources(${LIB_FSFW_NAME} PRIVATE
arrayprinter.cpp
AsciiConverter.cpp
CRC.cpp
DleEncoder.cpp
DleParser.cpp
PeriodicOperationDivider.cpp
timevalOperations.cpp
Type.cpp
bitutility.cpp
target_sources(${LIB_FSFW_NAME}
PRIVATE
arrayprinter.cpp
AsciiConverter.cpp
CRC.cpp
DleEncoder.cpp
PeriodicOperationDivider.cpp
timevalOperations.cpp
Type.cpp
bitutility.cpp
)
add_subdirectory(math)

View File

@ -1,231 +0,0 @@
#include "DleParser.h"
#include <fsfw/globalfunctions/DleEncoder.h>
#include <fsfw/serviceinterface/ServiceInterface.h>
#include <cstdio>
DleParser::DleParser(SimpleRingBuffer& decodeRingBuf, DleEncoder& decoder, BufPair encodedBuf,
BufPair decodedBuf, UserHandler handler, void* args)
: decodeRingBuf(decodeRingBuf),
decoder(decoder),
encodedBuf(encodedBuf),
decodedBuf(decodedBuf),
handler(handler),
ctx(args) {
if (handler == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "DleParser::DleParser: Invalid user handler" << std::endl;
#else
sif::printError("DleParser::DleParser: Invalid user handler\n");
#endif
}
}
ReturnValue_t DleParser::passData(uint8_t* data, size_t len) {
if (data == nullptr or len == 0 or handler == nullptr) {
return RETURN_FAILED;
}
size_t copyIntoRingBufFromHere = 0;
size_t copyAmount = len;
size_t startIdx = 0;
ReturnValue_t result = RETURN_OK;
bool startFoundInThisPacket = false;
for (size_t idx = 0; idx < len; idx++) {
if (data[idx] == DleEncoder::STX_CHAR) {
if (not startFound and not startFoundInThisPacket) {
startIdx = idx;
copyIntoRingBufFromHere = idx;
copyAmount = len - idx;
} else {
// Maybe print warning, should not happen
decodeRingBuf.clear();
ErrorInfo info;
info.len = idx;
prepareErrorContext(ErrorTypes::CONSECUTIVE_STX_CHARS, info);
handler(ctx);
copyIntoRingBufFromHere = idx;
copyAmount = len - idx;
}
startFound = true;
startFoundInThisPacket = true;
} else if (data[idx] == DleEncoder::ETX_CHAR) {
if (startFoundInThisPacket) {
size_t readLen = 0;
size_t decodedLen = 0;
result = decoder.decode(data + startIdx, idx + 1 - startIdx, &readLen, decodedBuf.first,
decodedBuf.second, &decodedLen);
if (result == HasReturnvaluesIF::RETURN_OK) {
ctx.setType(ContextType::PACKET_FOUND);
ctx.decodedPacket.first = decodedBuf.first;
ctx.decodedPacket.second = decodedLen;
this->handler(ctx);
} else if (result == DleEncoder::STREAM_TOO_SHORT) {
ErrorInfo info;
info.res = result;
prepareErrorContext(ErrorTypes::DECODING_BUF_TOO_SMALL, info);
handler(ctx);
} else {
ErrorInfo info;
info.res = result;
prepareErrorContext(ErrorTypes::DECODING_BUF_TOO_SMALL, info);
handler(ctx);
}
decodeRingBuf.clear();
if ((idx + 1) < len) {
copyIntoRingBufFromHere = idx + 1;
copyAmount = len - idx - 1;
} else {
copyAmount = 0;
}
} else if (startFound) {
// ETX found but STX was found in another mini packet. Reconstruct the full packet
// to decode it
result = decodeRingBuf.writeData(data, idx + 1);
if (result != HasReturnvaluesIF::RETURN_OK) {
ErrorInfo info;
info.res = result;
prepareErrorContext(ErrorTypes::RING_BUF_ERROR, info);
handler(ctx);
}
size_t fullEncodedLen = decodeRingBuf.getAvailableReadData();
if (fullEncodedLen > encodedBuf.second) {
ErrorInfo info;
info.len = fullEncodedLen;
prepareErrorContext(ErrorTypes::ENCODED_BUF_TOO_SMALL, info);
handler(ctx);
decodeRingBuf.clear();
} else {
size_t decodedLen = 0;
size_t readLen = 0;
decodeRingBuf.readData(encodedBuf.first, fullEncodedLen, true);
result = decoder.decode(encodedBuf.first, fullEncodedLen, &readLen, decodedBuf.first,
decodedBuf.second, &decodedLen);
if (result == HasReturnvaluesIF::RETURN_OK) {
if (this->handler != nullptr) {
ctx.setType(ContextType::PACKET_FOUND);
ctx.decodedPacket.first = decodedBuf.first;
ctx.decodedPacket.second = decodedLen;
this->handler(ctx);
}
} else if (result == DleEncoder::STREAM_TOO_SHORT) {
ErrorInfo info;
info.res = result;
prepareErrorContext(ErrorTypes::DECODING_BUF_TOO_SMALL, info);
handler(ctx);
} else {
ErrorInfo info;
info.res = result;
prepareErrorContext(ErrorTypes::DECODE_ERROR, info);
handler(ctx);
}
decodeRingBuf.clear();
startFound = false;
startFoundInThisPacket = false;
if ((idx + 1) < len) {
copyIntoRingBufFromHere = idx + 1;
copyAmount = len - idx - 1;
} else {
copyAmount = 0;
}
}
} else {
// End data without preceeding STX
ErrorInfo info;
info.len = idx + 1;
prepareErrorContext(ErrorTypes::CONSECUTIVE_ETX_CHARS, info);
handler(ctx);
decodeRingBuf.clear();
if ((idx + 1) < len) {
copyIntoRingBufFromHere = idx + 1;
copyAmount = len - idx - 1;
} else {
copyAmount = 0;
}
}
startFoundInThisPacket = false;
startFound = false;
}
}
if (copyAmount > 0) {
result = decodeRingBuf.writeData(data + copyIntoRingBufFromHere, copyAmount);
if (result != HasReturnvaluesIF::RETURN_OK) {
ErrorInfo info;
info.res = result;
prepareErrorContext(ErrorTypes::RING_BUF_ERROR, info);
handler(ctx);
}
}
return RETURN_OK;
}
void DleParser::defaultFoundPacketHandler(uint8_t* packet, size_t len, void* args) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "DleParserBase::handleFoundPacket: Detected DLE packet with " << len << " bytes"
<< std::endl;
#else
sif::printInfo("DleParserBase::handleFoundPacket: Detected DLE packet with %d bytes\n", len);
#endif
#endif
}
void DleParser::defaultErrorHandler(ErrorTypes err, ErrorInfo ctx) {
switch (err) {
case (ErrorTypes::NONE): {
errorPrinter("No error");
break;
}
case (ErrorTypes::DECODE_ERROR): {
errorPrinter("Decode Error");
break;
}
case (ErrorTypes::RING_BUF_ERROR): {
errorPrinter("Ring Buffer Error");
break;
}
case (ErrorTypes::ENCODED_BUF_TOO_SMALL):
case (ErrorTypes::DECODING_BUF_TOO_SMALL): {
char opt[64];
snprintf(opt, sizeof(opt), ": Too small for packet with length %d", ctx.len);
if (err == ErrorTypes::ENCODED_BUF_TOO_SMALL) {
errorPrinter("Encoded buf too small", opt);
} else {
errorPrinter("Decoding buf too small", opt);
}
break;
}
case (ErrorTypes::CONSECUTIVE_STX_CHARS): {
errorPrinter("Consecutive STX chars detected");
break;
}
case (ErrorTypes::CONSECUTIVE_ETX_CHARS): {
errorPrinter("Consecutive ETX chars detected");
break;
}
}
}
void DleParser::errorPrinter(const char* str, const char* opt) {
if (opt == nullptr) {
opt = "";
}
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "DleParserBase::handleParseError: " << str << opt << std::endl;
#else
sif::printInfo("DleParserBase::handleParseError: %s%s\n", str, opt);
#endif
#endif
}
void DleParser::prepareErrorContext(ErrorTypes err, ErrorInfo info) {
ctx.setType(ContextType::ERROR);
ctx.error.first = err;
ctx.error.second = info;
}
void DleParser::reset() {
startFound = false;
decodeRingBuf.clear();
}

View File

@ -1,127 +0,0 @@
#ifndef MISSION_DEVICES_DLEPARSER_H_
#define MISSION_DEVICES_DLEPARSER_H_
#include <fsfw/container/SimpleRingBuffer.h>
#include <fsfw/globalfunctions/DleEncoder.h>
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
#include <cstddef>
#include <utility>
/**
* @brief This base helper class can be used to extract DLE encoded packets from a data stream
* @details
* The core API of the parser takes received packets which can contains DLE packets. The parser
* can deal with DLE packets split across multiple packets. It does so by using a dedicated
* decoding ring buffer. The user can process received packets and detect errors by
* overriding two provided virtual methods. This also allows detecting multiple DLE packets
* inside one passed packet.
*/
class DleParser : public HasReturnvaluesIF {
public:
using BufPair = std::pair<uint8_t*, size_t>;
enum class ContextType { PACKET_FOUND, ERROR };
enum class ErrorTypes {
NONE,
ENCODED_BUF_TOO_SMALL,
DECODING_BUF_TOO_SMALL,
DECODE_ERROR,
RING_BUF_ERROR,
CONSECUTIVE_STX_CHARS,
CONSECUTIVE_ETX_CHARS
};
union ErrorInfo {
size_t len;
ReturnValue_t res;
};
using ErrorPair = std::pair<ErrorTypes, ErrorInfo>;
struct Context {
public:
Context(void* args) : userArgs(args) { setType(ContextType::PACKET_FOUND); }
void setType(ContextType type) {
if (type == ContextType::PACKET_FOUND) {
error.first = ErrorTypes::NONE;
error.second.len = 0;
} else {
decodedPacket.first = nullptr;
decodedPacket.second = 0;
}
}
ContextType getType() const { return type; }
BufPair decodedPacket = {};
ErrorPair error;
void* userArgs;
private:
ContextType type;
};
using UserHandler = void (*)(const Context& ctx);
/**
* Base class constructor
* @param decodeRingBuf Ring buffer used to store multiple packets to allow detecting DLE packets
* split across multiple packets
* @param decoder Decoder instance
* @param encodedBuf Buffer used to store encoded packets. It has to be large enough to hold
* the largest expected encoded DLE packet size
* @param decodedBuf Buffer used to store decoded packets. It has to be large enough to hold the
* largest expected decoded DLE packet size
* @param handler Function which will be called on a found packet
* @param args Arbitrary user argument
*/
DleParser(SimpleRingBuffer& decodeRingBuf, DleEncoder& decoder, BufPair encodedBuf,
BufPair decodedBuf, UserHandler handler, void* args);
/**
* This function allows to pass new data into the parser. It then scans for DLE packets
* automatically and inserts (part of) the packet into a ring buffer if necessary.
* @param data
* @param len
* @return
*/
ReturnValue_t passData(uint8_t* data, size_t len);
/**
* Example found packet handler
* function call
* @param packet Decoded packet
* @param len Length of detected packet
*/
void defaultFoundPacketHandler(uint8_t* packet, size_t len, void* args);
/**
* Will be called if an error occured in the #passData call
* @param err
* @param ctx Context information depending on the error type
* - For buffer length errors, will be set to the detected packet length which is too large
* - For decode or ring buffer errors, will be set to the result returned from the failed call
*/
static void defaultErrorHandler(ErrorTypes err, ErrorInfo ctx);
static void errorPrinter(const char* str, const char* opt = nullptr);
void prepareErrorContext(ErrorTypes err, ErrorInfo ctx);
/**
* Resets the parser by resetting the internal states and clearing the decoding ring buffer
*/
void reset();
private:
SimpleRingBuffer& decodeRingBuf;
DleEncoder& decoder;
BufPair encodedBuf;
BufPair decodedBuf;
UserHandler handler = nullptr;
Context ctx;
bool startFound = false;
};
#endif /* MISSION_DEVICES_DLEPARSER_H_ */

View File

@ -25,7 +25,7 @@ class MatchTree : public SerializeableMatcherIF<T>, public BinaryTree<Serializea
: BinaryTree<SerializeableMatcherIF<T>>(root.element), maxDepth(maxDepth) {}
MatchTree() : BinaryTree<SerializeableMatcherIF<T>>(), maxDepth(-1) {}
virtual ~MatchTree() {}
virtual bool match(T number) { return matchesTree(number); }
virtual bool match(T number) override { return matchesTree(number); }
bool matchesTree(T number) {
iterator iter = this->begin();
if (iter == this->end()) {

View File

@ -15,7 +15,7 @@ class RangeMatcher : public SerializeableMatcherIF<T> {
RangeMatcher(T lowerBound, T upperBound, bool inverted = false)
: inverted(inverted), lowerBound(lowerBound), upperBound(upperBound) {}
bool match(T input) {
bool match(T input) override {
if (inverted) {
return !doMatch(input);
} else {

View File

@ -23,15 +23,19 @@ class HasHealthIF {
static const Event HEALTH_INFO = MAKE_EVENT(6, severity::INFO);
static const Event CHILD_CHANGED_HEALTH = MAKE_EVENT(7, severity::INFO);
static const Event CHILD_PROBLEMS = MAKE_EVENT(8, severity::LOW);
//! Assembly overwrites health information of children to keep satellite alive.
static const Event OVERWRITING_HEALTH = MAKE_EVENT(9, severity::LOW);
//! Someone starts a recovery of a component (typically power-cycle). No parameters.
static const Event TRYING_RECOVERY = MAKE_EVENT(10, severity::MEDIUM);
//! Recovery is ongoing. Comes twice during recovery.
//! P1: 0 for the first, 1 for the second event. P2: 0
static const Event RECOVERY_STEP = MAKE_EVENT(11, severity::MEDIUM);
//! Recovery was completed. Not necessarily successful. No parameters.
static const Event RECOVERY_DONE = MAKE_EVENT(12, severity::MEDIUM);
static const Event OVERWRITING_HEALTH =
MAKE_EVENT(9, severity::LOW); //!< Assembly overwrites health information of children to keep
//!< satellite alive.
static const Event TRYING_RECOVERY =
MAKE_EVENT(10, severity::MEDIUM); //!< Someone starts a recovery of a component (typically
//!< power-cycle). No parameters.
static const Event RECOVERY_STEP =
MAKE_EVENT(11, severity::MEDIUM); //!< Recovery is ongoing. Comes twice during recovery. P1:
//!< 0 for the first, 1 for the second event. P2: 0
static const Event RECOVERY_DONE = MAKE_EVENT(
12,
severity::MEDIUM); //!< Recovery was completed. Not necessarily successful. No parameters.
virtual ~HasHealthIF() {}
virtual MessageQueueId_t getCommandQueue() const = 0;

View File

@ -7,13 +7,11 @@
InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId, uint32_t messageQueueDepth)
: SystemObject(setObjectId),
commandQueue(QueueFactory::instance()->createMessageQueue(messageQueueDepth)),
poolManager(this, commandQueue),
internalErrorSid(setObjectId, InternalErrorDataset::ERROR_SET_ID),
internalErrorDataset(this) {
mutex = MutexFactory::instance()->createMutex();
auto mqArgs = MqArgs(setObjectId, static_cast<void *>(this));
commandQueue = QueueFactory::instance()->createMessageQueue(
messageQueueDepth, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
}
InternalErrorReporter::~InternalErrorReporter() { MutexFactory::instance()->deleteMutex(mutex); }
@ -38,14 +36,15 @@ ReturnValue_t InternalErrorReporter::performOperation(uint8_t opCode) {
if ((newQueueHits > 0) or (newTmHits > 0) or (newStoreHits > 0)) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "InternalErrorReporter::performOperation: Errors "
<< "occured: Queue | TM | Store : " << newQueueHits << " | " << newTmHits << " | "
<< newStoreHits << std::endl;
<< "occured!" << std::endl;
sif::debug << "Queue errors: " << newQueueHits << std::endl;
sif::debug << "TM errors: " << newTmHits << std::endl;
sif::debug << "Store errors: " << newStoreHits << std::endl;
#else
sif::printDebug(
"InternalErrorReporter::performOperation: Errors occured: Queue | TM | Store: %lu | %lu "
"| %lu\n",
static_cast<unsigned int>(newQueueHits), static_cast<unsigned int>(newTmHits),
static_cast<unsigned int>(newStoreHits));
sif::printDebug("InternalErrorReporter::performOperation: Errors occured!\n");
sif::printDebug("Queue errors: %lu\n", static_cast<unsigned int>(newQueueHits));
sif::printDebug("TM errors: %lu\n", static_cast<unsigned int>(newTmHits));
sif::printDebug("Store errors: %lu\n", static_cast<unsigned int>(newStoreHits));
#endif
}
}

View File

@ -19,33 +19,32 @@ class HasModesIF {
static const ReturnValue_t INVALID_SUBMODE = MAKE_RETURN_CODE(0x04);
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::SYSTEM_MANAGER;
//! An object announces changing the mode. p1: target mode. p2: target submode
static const Event CHANGING_MODE = MAKE_EVENT(0, severity::INFO);
//! An Object announces its mode; parameter1 is mode, parameter2 is submode
static const Event MODE_INFO = MAKE_EVENT(1, severity::INFO);
static const Event CHANGING_MODE =
MAKE_EVENT(0, severity::INFO); //!< An object announces changing the mode. p1: target mode.
//!< p2: target submode
static const Event MODE_INFO = MAKE_EVENT(
1,
severity::INFO); //!< An Object announces its mode; parameter1 is mode, parameter2 is submode
static const Event FALLBACK_FAILED = MAKE_EVENT(2, severity::HIGH);
static const Event MODE_TRANSITION_FAILED = MAKE_EVENT(3, severity::LOW);
static const Event CANT_KEEP_MODE = MAKE_EVENT(4, severity::HIGH);
//! Indicates a bug or configuration failure: Object is in a mode it should never be in.
static const Event OBJECT_IN_INVALID_MODE = MAKE_EVENT(5, severity::LOW);
//! The mode is changed, but for some reason, the change is forced, i.e. EXTERNAL_CONTROL ignored.
//! p1: target mode. p2: target submode
static const Event FORCING_MODE = MAKE_EVENT(6, severity::MEDIUM);
//! A mode command was rejected by the called object. Par1: called object id, Par2: return code.
static const Event MODE_CMD_REJECTED = MAKE_EVENT(7, severity::LOW);
static const Event OBJECT_IN_INVALID_MODE =
MAKE_EVENT(5, severity::LOW); //!< Indicates a bug or configuration failure: Object is in a
//!< mode it should never be in.
static const Event FORCING_MODE = MAKE_EVENT(
6, severity::MEDIUM); //!< The mode is changed, but for some reason, the change is forced,
//!< i.e. EXTERNAL_CONTROL ignored. p1: target mode. p2: target submode
static const Event MODE_CMD_REJECTED =
MAKE_EVENT(7, severity::LOW); //!< A mode command was rejected by the called object. Par1:
//!< called object id, Par2: return code.
//! The device is powered and ready to perform operations. In this mode, no commands are
//! sent by the device handler itself, but direct commands van be commanded and will be
//! interpreted
static constexpr Mode_t MODE_ON = 1;
//! The device is powered off. The only command accepted in this mode is a mode change to on.
static constexpr Mode_t MODE_OFF = 0;
static constexpr Mode_t MODE_INVALID = -1;
static constexpr Mode_t MODE_UNDEFINED = -2;
//! To avoid checks against magic number "0".
static const Submode_t SUBMODE_NONE = 0;
static const Mode_t MODE_ON =
1; //!< The device is powered and ready to perform operations. In this mode, no commands are
//!< sent by the device handler itself, but direct commands van be commanded and will be
//!< interpreted
static const Mode_t MODE_OFF = 0; //!< The device is powered off. The only command accepted in
//!< this mode is a mode change to on.
static const Submode_t SUBMODE_NONE = 0; //!< To avoid checks against magic number "0".
virtual ~HasModesIF() {}
virtual MessageQueueId_t getCommandQueue() const = 0;

View File

@ -34,7 +34,7 @@ class MonitoringReportContent : public SerialLinkedListAdapter<SerializeIF> {
SerializeElement<T> limitValue;
SerializeElement<ReturnValue_t> oldState;
SerializeElement<ReturnValue_t> newState;
uint8_t rawTimestamp[TimeStamperIF::MISSION_TIMESTAMP_SIZE];
uint8_t rawTimestamp[TimeStamperIF::MISSION_TIMESTAMP_SIZE] = {};
SerializeElement<SerialBufferAdapter<uint8_t>> timestampSerializer;
TimeStamperIF* timeStamper;
MonitoringReportContent()
@ -46,7 +46,6 @@ class MonitoringReportContent : public SerialLinkedListAdapter<SerializeIF> {
limitValue(0),
oldState(0),
newState(0),
rawTimestamp({0}),
timestampSerializer(rawTimestamp, sizeof(rawTimestamp)),
timeStamper(NULL) {
setAllNext();

View File

@ -95,16 +95,13 @@ void ObjectManager::initialize() {
for (auto const& it : objectList) {
result = it.second->initialize();
if (result != RETURN_OK) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
object_id_t var = it.first;
sif::error << "ObjectManager::initialize: Object 0x" << std::hex << std::setw(8)
<< std::setfill('0') << it.first << " failed to initialize with code 0x" << result
<< std::dec << std::setfill(' ') << std::endl;
#else
sif::printError(
"ObjectManager::initialize: Object 0x%08x failed to initialize with code 0x%04x\n", var,
it.first);
#endif
<< std::setfill('0') << var
<< " failed to "
"initialize with code 0x"
<< result << std::dec << std::setfill(' ') << std::endl;
#endif
errorCount++;
}

View File

@ -48,9 +48,10 @@ class SystemObject : public SystemObjectIF {
virtual ~SystemObject();
object_id_t getObjectId() const 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_ */

View File

@ -19,6 +19,8 @@
#include <ws2tcpip.h>
#elif defined(PLATFORM_UNIX)
#include <netdb.h>
#include <utility>
#endif
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),
tmtcBridgeId(tmtcTcpBridge),
receptionMode(receptionMode),
tcpConfig(customTcpServerPort),
tcpConfig(std::move(customTcpServerPort)),
receptionBuffer(receptionBufferSize),
ringBuffer(ringBufferSize, true) {}
@ -103,7 +105,7 @@ ReturnValue_t TcpTmTcServer::initialize() {
TcpTmTcServer::~TcpTmTcServer() { closeSocket(listenerTcpSocket); }
ReturnValue_t TcpTmTcServer::performOperation(uint8_t opCode) {
[[noreturn]] ReturnValue_t TcpTmTcServer::performOperation(uint8_t opCode) {
using namespace tcpip;
// If a connection is accepted, the corresponding socket will be assigned to the new socket
socket_t connSocket = 0;
@ -138,7 +140,6 @@ ReturnValue_t TcpTmTcServer::performOperation(uint8_t opCode) {
closeSocket(connSocket);
connSocket = 0;
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t TcpTmTcServer::initializeAfterTaskCreation() {
@ -159,7 +160,7 @@ void TcpTmTcServer::handleServerOperation(socket_t& connSocket) {
#endif
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);
if (retval == 0) {
size_t availableReadData = ringBuffer.getAvailableReadData();
@ -252,17 +253,17 @@ ReturnValue_t TcpTmTcServer::handleTcReception(uint8_t* spacePacket, size_t pack
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) {
this->validPacketIds = validPacketIds;
void TcpTmTcServer::setSpacePacketParsingOptions(std::vector<uint16_t> validPacketIds_) {
this->validPacketIds = std::move(validPacketIds_);
}
TcpTmTcServer::TcpConfig& TcpTmTcServer::getTcpConfigStruct() { return tcpConfig; }
ReturnValue_t TcpTmTcServer::handleTmSending(socket_t connSocket, bool& tmSent) {
// 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;
while ((not tmtcBridge->tmFifo->empty()) and
(tmtcBridge->packetSentCounter < tmtcBridge->sentPacketsPerCycle)) {
@ -283,7 +284,7 @@ ReturnValue_t TcpTmTcServer::handleTmSending(socket_t connSocket, bool& tmSent)
#endif
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);
if (retval == static_cast<int>(storeAccessor.size())) {
// Packet sent, clear FIFO entry
@ -339,6 +340,9 @@ ReturnValue_t TcpTmTcServer::handleTcRingBufferData(size_t availableReadData) {
size_t foundSize = 0;
size_t readLen = 0;
while (readLen < readAmount) {
if(spacePacketParser == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
result =
spacePacketParser->parseSpacePackets(bufPtrPtr, readAmount, startIdx, foundSize, readLen);
switch (result) {

View File

@ -17,6 +17,7 @@
#endif
#include <string>
#include <utility>
#include <vector>
class TcpTmTcBridge;
@ -44,7 +45,7 @@ class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableOb
struct TcpConfig {
public:
TcpConfig(std::string tcpPort) : tcpPort(tcpPort) {}
explicit TcpConfig(std::string tcpPort) : tcpPort(std::move(tcpPort)) {}
/**
* Passed to the recv call
@ -84,7 +85,7 @@ class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableOb
size_t ringBufferSize = RING_BUFFER_SIZE,
std::string customTcpServerPort = DEFAULT_SERVER_PORT,
ReceptionModes receptionMode = ReceptionModes::SPACE_PACKETS);
virtual ~TcpTmTcServer();
~TcpTmTcServer() override;
void enableWiretapping(bool enable);
@ -97,10 +98,10 @@ class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableOb
void setSpacePacketParsingOptions(std::vector<uint16_t> validPacketIds);
ReturnValue_t initialize() override;
ReturnValue_t performOperation(uint8_t opCode) override;
[[noreturn]] ReturnValue_t performOperation(uint8_t opCode) override;
ReturnValue_t initializeAfterTaskCreation() override;
std::string getTcpPort() const;
[[nodiscard]] const std::string& getTcpPort() const;
protected:
StorageManagerIF* tcStore = nullptr;
@ -115,7 +116,7 @@ class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableOb
ReceptionModes receptionMode;
TcpConfig tcpConfig;
struct sockaddr tcpAddress;
struct sockaddr tcpAddress = {};
socket_t listenerTcpSocket = 0;
MessageQueueId_t targetTcDestination = MessageQueueIF::NO_QUEUE;

View File

@ -16,11 +16,13 @@
//! Debugging preprocessor define.
#define FSFW_UDP_RECV_WIRETAPPING_ENABLED 0
const timeval UdpTcPollingTask::DEFAULT_TIMEOUT = {0, 500000};
UdpTcPollingTask::UdpTcPollingTask(object_id_t objectId, object_id_t tmtcUdpBridge,
size_t maxRecvSize, double timeoutSeconds)
: SystemObject(objectId), tmtcBridgeId(tmtcUdpBridge) {
if (frameSize > 0) {
this->frameSize = frameSize;
if (maxRecvSize > 0) {
this->frameSize = maxRecvSize;
} else {
this->frameSize = DEFAULT_MAX_RECV_SIZE;
}
@ -31,22 +33,20 @@ UdpTcPollingTask::UdpTcPollingTask(object_id_t objectId, object_id_t tmtcUdpBrid
receptionBuffer.resize(this->frameSize);
if (timeoutSeconds == -1) {
receptionTimeout = DEFAULT_TIMEOUT;
receptionTimeout = UdpTcPollingTask::DEFAULT_TIMEOUT;
} else {
receptionTimeout = timevalOperations::toTimeval(timeoutSeconds);
}
}
UdpTcPollingTask::~UdpTcPollingTask() {}
ReturnValue_t UdpTcPollingTask::performOperation(uint8_t opCode) {
[[noreturn]] ReturnValue_t UdpTcPollingTask::performOperation(uint8_t opCode) {
/* Sender Address is cached here. */
struct sockaddr senderAddress;
struct sockaddr senderAddress {};
socklen_t senderAddressSize = sizeof(senderAddress);
/* Poll for new UDP datagrams in permanent loop. */
while (true) {
int bytesReceived =
ssize_t bytesReceived =
recvfrom(this->serverSocket, reinterpret_cast<char*>(receptionBuffer.data()), frameSize,
receptionFlags, &senderAddress, &senderAddressSize);
if (bytesReceived == SOCKET_ERROR) {
@ -70,7 +70,6 @@ ReturnValue_t UdpTcPollingTask::performOperation(uint8_t opCode) {
}
tmtcBridge->checkAndSetClientAddress(senderAddress);
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t UdpTcPollingTask::handleSuccessfullTcRead(size_t bytesRead) {
@ -155,7 +154,7 @@ void UdpTcPollingTask::setTimeout(double timeoutSeconds) {
#endif
}
#elif defined(PLATFORM_UNIX)
timeval tval;
timeval tval{};
tval = timevalOperations::toTimeval(timeoutSeconds);
int result = setsockopt(serverSocket, SOL_SOCKET, SO_RCVTIMEO, &tval, sizeof(receptionTimeout));
if (result == -1) {

View File

@ -21,11 +21,11 @@ class UdpTcPollingTask : public TcpIpBase, public SystemObject, public Executabl
public:
static constexpr size_t DEFAULT_MAX_RECV_SIZE = 1500;
//! 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,
double timeoutSeconds = -1);
virtual ~UdpTcPollingTask();
~UdpTcPollingTask() override = default;
/**
* 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);
virtual ReturnValue_t performOperation(uint8_t opCode) override;
virtual ReturnValue_t initialize() override;
virtual ReturnValue_t initializeAfterTaskCreation() override;
[[noreturn]] ReturnValue_t performOperation(uint8_t opCode) override;
ReturnValue_t initialize() override;
ReturnValue_t initializeAfterTaskCreation() override;
protected:
StorageManagerIF* tcStore = nullptr;
@ -51,7 +51,7 @@ class UdpTcPollingTask : public TcpIpBase, public SystemObject, public Executabl
std::vector<uint8_t> receptionBuffer;
size_t frameSize = 0;
timeval receptionTimeout;
timeval receptionTimeout{};
ReturnValue_t handleSuccessfullTcRead(size_t bytesRead);
};

View File

@ -20,13 +20,13 @@
const std::string UdpTmTcBridge::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT;
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)
: TmTcBridge(objectId, tcDestination, tmStoreId, tcStoreId) {
if (udpServerPort == "") {
this->udpServerPort = DEFAULT_SERVER_PORT;
if (udpServerPort_.empty()) {
udpServerPort = DEFAULT_SERVER_PORT;
} else {
this->udpServerPort = udpServerPort;
udpServerPort = udpServerPort_;
}
mutex = MutexFactory::instance()->createMutex();
@ -117,8 +117,8 @@ ReturnValue_t UdpTmTcBridge::sendTm(const uint8_t *data, size_t dataLen) {
tcpip::printAddress(&clientAddress);
#endif
int bytesSent = sendto(serverSocket, reinterpret_cast<const char *>(data), dataLen, flags,
&clientAddress, clientAddressLen);
ssize_t bytesSent = sendto(serverSocket, reinterpret_cast<const char *>(data), dataLen, flags,
&clientAddress, clientAddressLen);
if (bytesSent == SOCKET_ERROR) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "TmTcUdpBridge::sendTm: Send operation failed." << std::endl;
@ -150,7 +150,7 @@ void UdpTmTcBridge::checkAndSetClientAddress(sockaddr &newAddress) {
clientAddressLen = sizeof(clientAddress);
}
void UdpTmTcBridge::setMutexProperties(MutexIF::TimeoutType timeoutType, dur_millis_t timeoutMs) {
this->timeoutType = timeoutType;
this->mutexTimeoutMs = timeoutMs;
void UdpTmTcBridge::setMutexProperties(MutexIF::TimeoutType timeoutType_, dur_millis_t timeoutMs) {
timeoutType = timeoutType_;
mutexTimeoutMs = timeoutMs;
}

View File

@ -29,10 +29,10 @@ class UdpTmTcBridge : public TmTcBridge, public TcpIpBase {
/* The ports chosen here should not be used by any other process. */
static const std::string DEFAULT_SERVER_PORT;
UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination, std::string udpServerPort = "",
object_id_t tmStoreId = objects::TM_STORE,
UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination,
const std::string& udpServerPort = "", object_id_t tmStoreId = objects::TM_STORE,
object_id_t tcStoreId = objects::TC_STORE);
virtual ~UdpTmTcBridge();
~UdpTmTcBridge() override;
/**
* Set properties of internal mutex.
@ -46,12 +46,12 @@ class UdpTmTcBridge : public TmTcBridge, public TcpIpBase {
std::string getUdpPort() const;
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:
std::string udpServerPort;
struct sockaddr clientAddress;
struct sockaddr clientAddress = {};
socklen_t clientAddressLen = 0;
//! Access to the client address is mutex protected as it is set by another task.

View File

@ -11,9 +11,6 @@
// TODO sanitize input?
// 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; }
ReturnValue_t Clock::setClock(const TimeOfDay_t* time) {

View File

@ -1,24 +1,27 @@
target_sources(${LIB_FSFW_NAME}
PRIVATE
Clock.cpp
FixedTimeslotTask.cpp
MessageQueue.cpp
Mutex.cpp
MutexFactory.cpp
PeriodicTask.cpp
QueueFactory.cpp
QueueMapManager.cpp
SemaphoreFactory.cpp
TaskFactory.cpp
taskHelpers.cpp
target_sources(${LIB_FSFW_NAME} PRIVATE
Clock.cpp
FixedTimeslotTask.cpp
MessageQueue.cpp
Mutex.cpp
MutexFactory.cpp
PeriodicTask.cpp
QueueFactory.cpp
QueueMapManager.cpp
SemaphoreFactory.cpp
TaskFactory.cpp
taskHelpers.cpp
)
if(UNIX)
find_package(Threads REQUIRED)
target_link_libraries(${LIB_FSFW_NAME}
PRIVATE
rt
${CMAKE_THREAD_LIBS_INIT}
)
find_package(Threads REQUIRED)
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
${CMAKE_THREAD_LIBS_INIT}
)
if(NOT APPLE)
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
rt
)
endif()
endif()

View File

@ -2,6 +2,7 @@
#include <chrono>
#include "fsfw/ipc/MutexGuard.h"
#include "fsfw/platform.h"
#include "fsfw/serviceinterface/ServiceInterface.h"
@ -11,9 +12,6 @@
#include <fstream>
#endif
uint16_t Clock::leapSeconds = 0;
MutexIF* Clock::timeMutex = NULL;
using SystemClock = std::chrono::system_clock;
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 fraction = now - seconds;
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;
timeInfo = gmtime(&tt);
time->year = timeInfo->tm_year + 1900;

View File

@ -1,29 +1,29 @@
target_sources(${LIB_FSFW_NAME} PRIVATE
Clock.cpp
BinarySemaphore.cpp
CountingSemaphore.cpp
FixedTimeslotTask.cpp
InternalErrorCodes.cpp
MessageQueue.cpp
Mutex.cpp
MutexFactory.cpp
PeriodicPosixTask.cpp
PosixThread.cpp
QueueFactory.cpp
SemaphoreFactory.cpp
TaskFactory.cpp
tcpipHelpers.cpp
unixUtility.cpp
)
Clock.cpp
BinarySemaphore.cpp
CountingSemaphore.cpp
FixedTimeslotTask.cpp
InternalErrorCodes.cpp
MessageQueue.cpp
Mutex.cpp
MutexFactory.cpp
PeriodicPosixTask.cpp
PosixThread.cpp
QueueFactory.cpp
SemaphoreFactory.cpp
TaskFactory.cpp
tcpipHelpers.cpp
unixUtility.cpp
)
find_package(Threads REQUIRED)
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
${CMAKE_THREAD_LIBS_INIT}
target_link_libraries(${LIB_FSFW_NAME} PUBLIC
${CMAKE_THREAD_LIBS_INIT}
)
if(NOT APPLE)
target_link_libraries(${LIB_FSFW_NAME} PUBLIC
rt
)
target_link_libraries(${LIB_FSFW_NAME} INTERFACE
${CMAKE_THREAD_LIBS_INIT}
)
)
endif()

View File

@ -6,16 +6,11 @@
#include <time.h>
#include <unistd.h>
#include <cstring>
#include <fstream>
#include "fsfw/ipc/MutexGuard.h"
#include "fsfw/serviceinterface/ServiceInterface.h"
uint16_t Clock::leapSeconds = 0;
MutexIF* Clock::timeMutex = NULL;
void handleClockError(const char* func);
uint32_t Clock::getTicksPerSecond(void) {
uint32_t ticks = sysconf(_SC_CLK_TCK);
return ticks;
@ -30,7 +25,7 @@ ReturnValue_t Clock::setClock(const TimeOfDay_t* time) {
int status = clock_settime(CLOCK_REALTIME, &timeUnix);
if (status != 0) {
handleClockError("setClock");
// TODO errno
return HasReturnvaluesIF::RETURN_FAILED;
}
return HasReturnvaluesIF::RETURN_OK;
@ -42,7 +37,7 @@ ReturnValue_t Clock::setClock(const timeval* time) {
timeUnix.tv_nsec = (__syscall_slong_t)time->tv_usec * 1000;
int status = clock_settime(CLOCK_REALTIME, &timeUnix);
if (status != 0) {
handleClockError("setClock");
// TODO errno
return HasReturnvaluesIF::RETURN_FAILED;
}
return HasReturnvaluesIF::RETURN_OK;
@ -52,7 +47,6 @@ ReturnValue_t Clock::getClock_timeval(timeval* time) {
timespec timeUnix;
int status = clock_gettime(CLOCK_REALTIME, &timeUnix);
if (status != 0) {
handleClockError("getClock_timeval");
return HasReturnvaluesIF::RETURN_FAILED;
}
time->tv_sec = timeUnix.tv_sec;
@ -121,7 +115,13 @@ ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) {
// TODO errno
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;
timeInfo = gmtime(&timeUnix.tv_sec);
time->year = timeInfo->tm_year + 1900;
@ -155,14 +155,3 @@ ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) {
*JD2000 = (time.tv_sec - 946728000. + time.tv_usec / 1000000.) / 24. / 3600.;
return HasReturnvaluesIF::RETURN_OK;
}
void handleClockError(const char* func) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "Clock::" << func << ": Failed with code " << errno << ": " << strerror(errno)
<< std::endl;
#else
sif::printWarning("Clock::%s: Failed with code %d: %s\n", func, errno, strerror(errno));
#endif
#endif
}

View File

@ -6,9 +6,6 @@
#include "fsfw/ipc/MutexGuard.h"
#include "fsfw/osal/rtems/RtemsBasic.h"
uint16_t Clock::leapSeconds = 0;
MutexIF* Clock::timeMutex = nullptr;
uint32_t Clock::getTicksPerSecond(void) {
rtems_interval ticks_per_second = rtems_clock_get_ticks_per_second();
return static_cast<uint32_t>(ticks_per_second);

View File

@ -66,7 +66,7 @@ class HasParametersIF {
* @param newValues
* @param startAtIndex Linear index, runs left to right, top to bottom for
* matrix indexes.
* @return RETURN_OK if parameter is valid and a set function of the parameter wrapper was called.
* @return
*/
virtual ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueIdentifier,
ParameterWrapper *parameterWrapper,

View File

@ -211,13 +211,9 @@ ReturnValue_t ParameterWrapper::copyFrom(const ParameterWrapper *from,
if (data == nullptr) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "ParameterWrapper::copyFrom: Called on read-only variable or "
"data pointer not set"
<< std::endl;
sif::warning << "ParameterWrapper::copyFrom: Called on read-only variable!" << std::endl;
#else
sif::printWarning(
"ParameterWrapper::copyFrom: Called on read-only variable "
"or data pointer not set\n");
sif::printWarning("ParameterWrapper::copyFrom: Called on read-only variable!\n");
#endif
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
return READONLY;
@ -226,9 +222,9 @@ ReturnValue_t ParameterWrapper::copyFrom(const ParameterWrapper *from,
if (from->readonlyData == nullptr) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "ParameterWrapper::copyFrom: Source not set" << std::endl;
sif::warning << "ParameterWrapper::copyFrom: Source not set!" << std::endl;
#else
sif::printWarning("ParameterWrapper::copyFrom: Source not set\n");
sif::printWarning("ParameterWrapper::copyFrom: Source not set!\n");
#endif
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
return SOURCE_NOT_SET;
@ -237,9 +233,9 @@ ReturnValue_t ParameterWrapper::copyFrom(const ParameterWrapper *from,
if (type != from->type) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "ParameterWrapper::copyFrom: Datatype missmatch" << std::endl;
sif::warning << "ParameterWrapper::copyFrom: Datatype missmatch!" << std::endl;
#else
sif::printWarning("ParameterWrapper::copyFrom: Datatype missmatch\n");
sif::printWarning("ParameterWrapper::copyFrom: Datatype missmatch!\n");
#endif
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
return DATATYPE_MISSMATCH;
@ -249,9 +245,9 @@ ReturnValue_t ParameterWrapper::copyFrom(const ParameterWrapper *from,
if (rows == 0 or columns == 0) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "ParameterWrapper::copyFrom: Columns or rows zero" << std::endl;
sif::warning << "ParameterWrapper::copyFrom: Columns or rows zero!" << std::endl;
#else
sif::printWarning("ParameterWrapper::copyFrom: Columns or rows zero\n");
sif::printWarning("ParameterWrapper::copyFrom: Columns or rows zero!\n");
#endif
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
return COLUMN_OR_ROWS_ZERO;

View File

@ -1,8 +1,7 @@
target_sources(${LIB_FSFW_NAME} PRIVATE
Fuse.cpp
PowerComponent.cpp
PowerSensor.cpp
PowerSwitcher.cpp
DummyPowerSwitcher.cpp
PowerSwitcherComponent.cpp
target_sources(${LIB_FSFW_NAME}
PRIVATE
Fuse.cpp
PowerComponent.cpp
PowerSensor.cpp
PowerSwitcher.cpp
)

View File

@ -1,46 +0,0 @@
#include "DummyPowerSwitcher.h"
DummyPowerSwitcher::DummyPowerSwitcher(object_id_t objectId, size_t numberOfSwitches,
size_t numberOfFuses, uint32_t switchDelayMs)
: SystemObject(objectId),
switcherList(numberOfSwitches),
fuseList(numberOfFuses),
switchDelayMs(switchDelayMs) {}
void DummyPowerSwitcher::setInitialSwitcherList(std::vector<ReturnValue_t> switcherList) {
this->switcherList = switcherList;
}
void DummyPowerSwitcher::setInitialFusesList(std::vector<ReturnValue_t> fuseList) {
this->fuseList = fuseList;
}
ReturnValue_t DummyPowerSwitcher::sendSwitchCommand(power::Switch_t switchNr, ReturnValue_t onOff) {
if (switchNr < switcherList.capacity()) {
switcherList[switchNr] = onOff;
}
return RETURN_FAILED;
}
ReturnValue_t DummyPowerSwitcher::sendFuseOnCommand(uint8_t fuseNr) {
if (fuseNr < fuseList.capacity()) {
fuseList[fuseNr] = FUSE_ON;
}
return RETURN_FAILED;
}
ReturnValue_t DummyPowerSwitcher::getSwitchState(power::Switch_t switchNr) const {
if (switchNr < switcherList.capacity()) {
return switcherList[switchNr];
}
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t DummyPowerSwitcher::getFuseState(uint8_t fuseNr) const {
if (fuseNr < fuseList.capacity()) {
return fuseList[fuseNr];
}
return HasReturnvaluesIF::RETURN_FAILED;
}
uint32_t DummyPowerSwitcher::getSwitchDelayMs(void) const { return switchDelayMs; }

View File

@ -1,31 +0,0 @@
#ifndef FSFW_SRC_FSFW_POWER_DUMMYPOWERSWITCHER_H_
#define FSFW_SRC_FSFW_POWER_DUMMYPOWERSWITCHER_H_
#include <cstddef>
#include <vector>
#include "PowerSwitchIF.h"
#include "definitions.h"
#include "fsfw/objectmanager/SystemObject.h"
class DummyPowerSwitcher : public SystemObject, public PowerSwitchIF {
public:
DummyPowerSwitcher(object_id_t objectId, size_t numberOfSwitches, size_t numberOfFuses,
uint32_t switchDelayMs = 5000);
void setInitialSwitcherList(std::vector<ReturnValue_t> switcherList);
void setInitialFusesList(std::vector<ReturnValue_t> switcherList);
virtual ReturnValue_t sendSwitchCommand(power::Switch_t switchNr, ReturnValue_t onOff) override;
virtual ReturnValue_t sendFuseOnCommand(uint8_t fuseNr) override;
virtual ReturnValue_t getSwitchState(power::Switch_t switchNr) const override;
virtual ReturnValue_t getFuseState(uint8_t fuseNr) const override;
virtual uint32_t getSwitchDelayMs(void) const override;
private:
std::vector<ReturnValue_t> switcherList;
std::vector<ReturnValue_t> fuseList;
uint32_t switchDelayMs = 5000;
};
#endif /* FSFW_SRC_FSFW_POWER_DUMMYPOWERSWITCHER_H_ */

View File

@ -34,14 +34,14 @@ class Fuse : public SystemObject,
};
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PCDU_1;
//! PSS detected that current on a fuse is totally out of bounds.
static const Event FUSE_CURRENT_HIGH = MAKE_EVENT(1, severity::LOW);
//! PSS detected a fuse that went off.
static const Event FUSE_WENT_OFF = MAKE_EVENT(2, severity::LOW);
//! PSS detected a fuse that violates its limits.
static const Event POWER_ABOVE_HIGH_LIMIT = MAKE_EVENT(4, severity::LOW);
//! PSS detected a fuse that violates its limits.
static const Event POWER_BELOW_LOW_LIMIT = MAKE_EVENT(5, severity::LOW);
static const Event FUSE_CURRENT_HIGH = MAKE_EVENT(
1, severity::LOW); //!< PSS detected that current on a fuse is totally out of bounds.
static const Event FUSE_WENT_OFF =
MAKE_EVENT(2, severity::LOW); //!< PSS detected a fuse that went off.
static const Event POWER_ABOVE_HIGH_LIMIT =
MAKE_EVENT(4, severity::LOW); //!< PSS detected a fuse that violates its limits.
static const Event POWER_BELOW_LOW_LIMIT =
MAKE_EVENT(5, severity::LOW); //!< PSS detected a fuse that violates its limits.
typedef std::list<PowerComponentIF *> DeviceList;
Fuse(object_id_t fuseObjectId, uint8_t fuseId, sid_t variableSet, VariableIds ids,
@ -54,7 +54,7 @@ class Fuse : public SystemObject,
ReturnValue_t check();
uint8_t getFuseId() const;
ReturnValue_t initialize();
ReturnValue_t initialize() override;
DeviceList devices;
ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize,
SerializeIF::Endianness streamEndianness) const override;

View File

@ -15,9 +15,7 @@ PowerSensor::PowerSensor(object_id_t objectId, sid_t setId, VariableIds ids, Def
limits.currentMin, limits.currentMax, events.currentLow, events.currentHigh),
voltageLimit(objectId, MODULE_ID_VOLTAGE, ids.pidVoltage, confirmationCount,
limits.voltageMin, limits.voltageMax, events.voltageLow, events.voltageHigh) {
auto mqArgs = MqArgs(objectId, static_cast<void*>(this));
commandQueue = QueueFactory::instance()->createMessageQueue(
3, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
commandQueue = QueueFactory::instance()->createMessageQueue();
}
PowerSensor::~PowerSensor() { QueueFactory::instance()->deleteMessageQueue(commandQueue); }

View File

@ -3,7 +3,6 @@
#include "../events/Event.h"
#include "../returnvalues/HasReturnvaluesIF.h"
#include "definitions.h"
/**
*
* @brief This interface defines a connection to a device that is capable of
@ -38,11 +37,11 @@ class PowerSwitchIF : public HasReturnvaluesIF {
* @param switchNr
* @param onOff on == @c SWITCH_ON; off != @c SWITCH_ON
*/
virtual ReturnValue_t sendSwitchCommand(power::Switch_t switchNr, ReturnValue_t onOff) = 0;
virtual void sendSwitchCommand(uint8_t switchNr, ReturnValue_t onOff) const = 0;
/**
* Sends a command to the Power Unit to enable a certain fuse.
*/
virtual ReturnValue_t sendFuseOnCommand(uint8_t fuseNr) = 0;
virtual void sendFuseOnCommand(uint8_t fuseNr) const = 0;
/**
* get the state of the Switches.
@ -52,7 +51,7 @@ class PowerSwitchIF : public HasReturnvaluesIF {
* - @c SWITCH_OFF if the specified switch is off.
* - @c RETURN_FAILED if an error occured
*/
virtual ReturnValue_t getSwitchState(power::Switch_t switchNr) const = 0;
virtual ReturnValue_t getSwitchState(uint8_t switchNr) const = 0;
/**
* get state of a fuse.
* @param fuseNr

View File

@ -1,12 +1,19 @@
#include "fsfw/power/PowerSwitcher.h"
#include "definitions.h"
#include "fsfw/objectmanager/ObjectManager.h"
#include "fsfw/serviceinterface/ServiceInterface.h"
PowerSwitcher::PowerSwitcher(PowerSwitchIF* switcher, power::Switch_t setSwitch1,
power::Switch_t setSwitch2, PowerSwitcher::State_t setStartState)
: power(switcher), state(setStartState), firstSwitch(setSwitch1), secondSwitch(setSwitch2) {}
PowerSwitcher::PowerSwitcher(uint8_t setSwitch1, uint8_t setSwitch2,
PowerSwitcher::State_t setStartState)
: state(setStartState), firstSwitch(setSwitch1), secondSwitch(setSwitch2) {}
ReturnValue_t PowerSwitcher::initialize(object_id_t powerSwitchId) {
power = ObjectManager::instance()->get<PowerSwitchIF>(powerSwitchId);
if (power == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t PowerSwitcher::getStateOfSwitches() {
SwitchReturn_t result = howManySwitches();
@ -45,37 +52,18 @@ void PowerSwitcher::commandSwitches(ReturnValue_t onOff) {
return;
}
void PowerSwitcher::turnOn(bool checkCurrentState) {
if (checkCurrentState) {
if (getStateOfSwitches() == PowerSwitchIF::SWITCH_ON) {
state = SWITCH_IS_ON;
return;
}
}
void PowerSwitcher::turnOn() {
commandSwitches(PowerSwitchIF::SWITCH_ON);
state = WAIT_ON;
}
void PowerSwitcher::turnOff(bool checkCurrentState) {
if (checkCurrentState) {
if (getStateOfSwitches() == PowerSwitchIF::SWITCH_OFF) {
state = SWITCH_IS_OFF;
return;
}
}
void PowerSwitcher::turnOff() {
commandSwitches(PowerSwitchIF::SWITCH_OFF);
state = WAIT_OFF;
}
bool PowerSwitcher::active() {
if (state == WAIT_OFF or state == WAIT_ON) {
return true;
}
return false;
}
PowerSwitcher::SwitchReturn_t PowerSwitcher::howManySwitches() {
if (secondSwitch == power::NO_SWITCH) {
if (secondSwitch == NO_SWITCH) {
return ONE_SWITCH;
} else {
return TWO_SWITCHES;

View File

@ -14,28 +14,28 @@ class PowerSwitcher : public HasReturnvaluesIF {
SWITCH_IS_OFF,
SWITCH_IS_ON,
};
State_t state;
static const uint8_t INTERFACE_ID = CLASS_ID::POWER_SWITCHER;
static const ReturnValue_t IN_POWER_TRANSITION = MAKE_RETURN_CODE(1);
static const ReturnValue_t SWITCH_STATE_MISMATCH = MAKE_RETURN_CODE(2);
PowerSwitcher(PowerSwitchIF* switcher, uint8_t setSwitch1, uint8_t setSwitch2 = power::NO_SWITCH,
PowerSwitcher(uint8_t setSwitch1, uint8_t setSwitch2 = NO_SWITCH,
State_t setStartState = SWITCH_IS_OFF);
void turnOn(bool checkCurrentState = true);
void turnOff(bool checkCurrentState = true);
bool active();
ReturnValue_t initialize(object_id_t powerSwitchId);
void turnOn();
void turnOff();
void doStateMachine();
State_t getState();
ReturnValue_t checkSwitchState();
uint32_t getSwitchDelay();
power::Switch_t getFirstSwitch() const;
power::Switch_t getSecondSwitch() const;
uint8_t getFirstSwitch() const;
uint8_t getSecondSwitch() const;
private:
uint8_t firstSwitch;
uint8_t secondSwitch;
PowerSwitchIF* power = nullptr;
State_t state;
power::Switch_t firstSwitch = power::NO_SWITCH;
power::Switch_t secondSwitch = power::NO_SWITCH;
static const uint8_t NO_SWITCH = 0xFF;
enum SwitchReturn_t { ONE_SWITCH = 1, TWO_SWITCHES = 2 };
ReturnValue_t getStateOfSwitches();
void commandSwitches(ReturnValue_t onOff);

View File

@ -1,107 +0,0 @@
#include "PowerSwitcherComponent.h"
#include <fsfw/ipc/QueueFactory.h>
#include <fsfw/power/PowerSwitchIF.h>
PowerSwitcherComponent::PowerSwitcherComponent(object_id_t objectId, PowerSwitchIF *pwrSwitcher,
power::Switch_t pwrSwitch)
: SystemObject(objectId),
switcher(pwrSwitcher, pwrSwitch),
modeHelper(this),
healthHelper(this, objectId) {
queue = QueueFactory::instance()->createMessageQueue();
}
ReturnValue_t PowerSwitcherComponent::performOperation(uint8_t opCode) {
ReturnValue_t result;
CommandMessage command;
for (result = queue->receiveMessage(&command); result == RETURN_OK;
result = queue->receiveMessage(&command)) {
result = healthHelper.handleHealthCommand(&command);
if (result == RETURN_OK) {
continue;
}
result = modeHelper.handleModeCommand(&command);
if (result == RETURN_OK) {
continue;
}
}
if (switcher.active()) {
switcher.doStateMachine();
auto currState = switcher.getState();
if (currState == PowerSwitcher::SWITCH_IS_OFF) {
setMode(MODE_OFF, 0);
} else if (currState == PowerSwitcher::SWITCH_IS_ON) {
setMode(MODE_ON, 0);
}
}
return RETURN_OK;
}
ReturnValue_t PowerSwitcherComponent::initialize() {
ReturnValue_t result = modeHelper.initialize();
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
result = healthHelper.initialize();
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
return SystemObject::initialize();
}
MessageQueueId_t PowerSwitcherComponent::getCommandQueue() const { return queue->getId(); }
void PowerSwitcherComponent::getMode(Mode_t *mode, Submode_t *submode) {
*mode = this->mode;
*submode = this->submode;
}
ReturnValue_t PowerSwitcherComponent::setHealth(HealthState health) {
healthHelper.setHealth(health);
return RETURN_OK;
}
ReturnValue_t PowerSwitcherComponent::checkModeCommand(Mode_t mode, Submode_t submode,
uint32_t *msToReachTheMode) {
*msToReachTheMode = 5000;
if (mode != MODE_ON and mode != MODE_OFF) {
return TRANS_NOT_ALLOWED;
}
return RETURN_OK;
}
void PowerSwitcherComponent::startTransition(Mode_t mode, Submode_t submode) {
if (mode == MODE_OFF) {
switcher.turnOff(true);
switcher.doStateMachine();
if (switcher.getState() == PowerSwitcher::SWITCH_IS_OFF) {
setMode(MODE_OFF, 0);
}
} else if (mode == MODE_ON) {
switcher.turnOn(true);
switcher.doStateMachine();
if (switcher.getState() == PowerSwitcher::SWITCH_IS_ON) {
setMode(MODE_ON, 0);
}
}
}
void PowerSwitcherComponent::setToExternalControl() {
healthHelper.setHealth(HasHealthIF::EXTERNAL_CONTROL);
}
void PowerSwitcherComponent::announceMode(bool recursive) {
triggerEvent(MODE_INFO, mode, submode);
}
void PowerSwitcherComponent::setMode(Mode_t newMode, Submode_t newSubmode) {
this->mode = newMode;
this->submode = newSubmode;
modeHelper.modeChanged(mode, submode);
announceMode(false);
}
HasHealthIF::HealthState PowerSwitcherComponent::getHealth() { return healthHelper.getHealth(); }

View File

@ -1,62 +0,0 @@
#ifndef _FSFW_POWER_POWERSWITCHERCOMPONENT_H_
#define _FSFW_POWER_POWERSWITCHERCOMPONENT_H_
#include <fsfw/health/HasHealthIF.h>
#include <fsfw/health/HealthHelper.h>
#include <fsfw/modes/HasModesIF.h>
#include <fsfw/modes/ModeHelper.h>
#include <fsfw/objectmanager/SystemObject.h>
#include <fsfw/power/PowerSwitcher.h>
#include <fsfw/power/definitions.h>
#include <fsfw/tasks/ExecutableObjectIF.h>
class PowerSwitchIF;
/**
* @brief Allows to create an power switch object with its own mode and health
* @details
* This basic component allows to create an object which is solely responsible for managing a
* switch. It also has a mode and a health by implementing the respective interface components
* which allows integrating this component into a system mode tree.
*
* Commanding this component to MODE_OFF will cause the switcher to turn the switch off while
* commanding in to MODE_ON will cause the switcher to turn the switch on.
*/
class PowerSwitcherComponent : public SystemObject,
public HasReturnvaluesIF,
public ExecutableObjectIF,
public HasModesIF,
public HasHealthIF {
public:
PowerSwitcherComponent(object_id_t objectId, PowerSwitchIF *pwrSwitcher,
power::Switch_t pwrSwitch);
private:
MessageQueueIF *queue = nullptr;
PowerSwitcher switcher;
Mode_t mode = MODE_OFF;
Submode_t submode = 0;
ModeHelper modeHelper;
HealthHelper healthHelper;
void setMode(Mode_t newMode, Submode_t newSubmode);
virtual ReturnValue_t performOperation(uint8_t opCode) override;
ReturnValue_t initialize() override;
MessageQueueId_t getCommandQueue() const override;
void getMode(Mode_t *mode, Submode_t *submode) override;
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
uint32_t *msToReachTheMode) override;
void startTransition(Mode_t mode, Submode_t submode) override;
void setToExternalControl() override;
void announceMode(bool recursive) override;
ReturnValue_t setHealth(HealthState health) override;
HasHealthIF::HealthState getHealth() override;
};
#endif /* _FSFW_POWER_POWERSWITCHERCOMPONENT_H_ */

View File

@ -1,13 +0,0 @@
#ifndef FSFW_SRC_FSFW_POWER_DEFINITIONS_H_
#define FSFW_SRC_FSFW_POWER_DEFINITIONS_H_
#include <cstdint>
namespace power {
using Switch_t = uint8_t;
static constexpr Switch_t NO_SWITCH = 0xFF;
} // namespace power
#endif /* FSFW_SRC_FSFW_POWER_DEFINITIONS_H_ */

View File

@ -13,8 +13,6 @@ CService201HealthCommanding::CService201HealthCommanding(object_id_t objectId, u
: CommandingServiceBase(objectId, apid, serviceId, numParallelCommands, commandTimeoutSeconds) {
}
CService201HealthCommanding::~CService201HealthCommanding() {}
ReturnValue_t CService201HealthCommanding::isValidSubservice(uint8_t subservice) {
switch (subservice) {
case (Subservice::COMMAND_SET_HEALTH):
@ -43,8 +41,8 @@ ReturnValue_t CService201HealthCommanding::getMessageQueueAndObject(uint8_t subs
}
ReturnValue_t CService201HealthCommanding::checkInterfaceAndAcquireMessageQueue(
MessageQueueId_t *messageQueueToSet, object_id_t *objectId) {
HasHealthIF *destination = ObjectManager::instance()->get<HasHealthIF>(*objectId);
MessageQueueId_t *messageQueueToSet, const object_id_t *objectId) {
auto *destination = ObjectManager::instance()->get<HasHealthIF>(*objectId);
if (destination == nullptr) {
return CommandingServiceBase::INVALID_OBJECT;
}
@ -77,6 +75,10 @@ ReturnValue_t CService201HealthCommanding::prepareCommand(CommandMessage *messag
HealthMessage::setHealthMessage(message, HealthMessage::HEALTH_ANNOUNCE_ALL);
break;
}
default: {
// Should never happen, subservice was already checked
result = RETURN_FAILED;
}
}
return result;
}
@ -95,10 +97,9 @@ ReturnValue_t CService201HealthCommanding::handleReply(const CommandMessage *rep
}
// Not used for now, health state already reported by event
ReturnValue_t CService201HealthCommanding::prepareHealthSetReply(const CommandMessage *reply) {
prepareHealthSetReply(reply);
uint8_t health = static_cast<uint8_t>(HealthMessage::getHealth(reply));
uint8_t oldHealth = static_cast<uint8_t>(HealthMessage::getOldHealth(reply));
[[maybe_unused]] ReturnValue_t CService201HealthCommanding::prepareHealthSetReply(const CommandMessage *reply) {
auto health = static_cast<uint8_t>(HealthMessage::getHealth(reply));
auto oldHealth = static_cast<uint8_t>(HealthMessage::getOldHealth(reply));
HealthSetReply healthSetReply(health, oldHealth);
return sendTmPacket(Subservice::REPLY_HEALTH_SET, &healthSetReply);
}

View File

@ -1,7 +1,7 @@
#ifndef 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
@ -21,7 +21,7 @@ class CService201HealthCommanding : public CommandingServiceBase {
public:
CService201HealthCommanding(object_id_t objectId, uint16_t apid, uint8_t serviceId,
uint8_t numParallelCommands = 4, uint16_t commandTimeoutSeconds = 60);
virtual ~CService201HealthCommanding();
~CService201HealthCommanding() override = default;
protected:
/* CSB abstract function implementations */
@ -38,12 +38,10 @@ class CService201HealthCommanding : public CommandingServiceBase {
bool *isStep) override;
private:
ReturnValue_t checkAndAcquireTargetID(object_id_t *objectIdToSet, const uint8_t *tcData,
size_t tcDataLen);
ReturnValue_t checkInterfaceAndAcquireMessageQueue(MessageQueueId_t *MessageQueueToSet,
object_id_t *objectId);
static ReturnValue_t checkInterfaceAndAcquireMessageQueue(MessageQueueId_t *MessageQueueToSet,
const object_id_t *objectId);
ReturnValue_t prepareHealthSetReply(const CommandMessage *reply);
[[maybe_unused]] ReturnValue_t prepareHealthSetReply(const CommandMessage *reply);
enum Subservice {
//! [EXPORT] : [TC] Set health of target object

View File

@ -16,9 +16,7 @@ Service1TelecommandVerification::Service1TelecommandVerification(object_id_t obj
apid(apid),
serviceId(serviceId),
targetDestination(targetDestination) {
auto mqArgs = MqArgs(objectId, static_cast<void*>(this));
tmQueue = QueueFactory::instance()->createMessageQueue(
messageQueueDepth, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
tmQueue = QueueFactory::instance()->createMessageQueue(messageQueueDepth);
}
Service1TelecommandVerification::~Service1TelecommandVerification() {

View File

@ -214,11 +214,11 @@ ReturnValue_t Service3Housekeeping::handleReply(const CommandMessage* reply,
default:
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "Service3Housekeeping::handleReply: Invalid reply with "
<< "reply command " << command << std::endl;
<< "reply command " << command << "!" << std::endl;
#else
sif::printWarning(
"Service3Housekeeping::handleReply: Invalid reply with "
"reply command %hu\n",
"reply command %hu!\n",
command);
#endif
return CommandingServiceBase::INVALID_REPLY;

View File

@ -43,7 +43,7 @@ class Service3Housekeeping : public CommandingServiceBase, public AcceptsHkPacke
CommandMessage* optionalNextCommand, object_id_t objectId,
bool* isStep) override;
virtual MessageQueueId_t getHkQueue() const;
virtual MessageQueueId_t getHkQueue() const override;
private:
enum class Subservice {

View File

@ -12,9 +12,7 @@ Service5EventReporting::Service5EventReporting(object_id_t objectId, uint16_t ap
uint32_t messageQueueDepth)
: PusServiceBase(objectId, apid, serviceId),
maxNumberReportsPerCycle(maxNumberReportsPerCycle) {
auto mqArgs = MqArgs(objectId, static_cast<void*>(this));
eventQueue = QueueFactory::instance()->createMessageQueue(
messageQueueDepth, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
eventQueue = QueueFactory::instance()->createMessageQueue(messageQueueDepth);
}
Service5EventReporting::~Service5EventReporting() {
@ -38,6 +36,9 @@ ReturnValue_t Service5EventReporting::performService() {
}
}
}
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "Service5EventReporting::generateEventReport: Too many events" << std::endl;
#endif
return HasReturnvaluesIF::RETURN_OK;
}
@ -86,7 +87,7 @@ ReturnValue_t Service5EventReporting::handleRequest(uint8_t subservice) {
// to be registered to the event manager to listen for events.
ReturnValue_t Service5EventReporting::initialize() {
EventManagerIF* manager = ObjectManager::instance()->get<EventManagerIF>(objects::EVENT_MANAGER);
if (manager == nullptr) {
if (manager == NULL) {
return RETURN_FAILED;
}
// register Service 5 as listener for events

View File

@ -41,7 +41,7 @@
class Service5EventReporting : public PusServiceBase {
public:
Service5EventReporting(object_id_t objectId, uint16_t apid, uint8_t serviceId,
size_t maxNumberReportsPerCycle, uint32_t messageQueueDepth);
size_t maxNumberReportsPerCycle = 10, uint32_t messageQueueDepth = 10);
virtual ~Service5EventReporting();
/***

View File

@ -6,10 +6,10 @@
class Service9TimeManagement : public PusServiceBase {
public:
static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PUS_SERVICE_9;
//!< Clock has been set. P1: New Uptime. P2: Old Uptime
static constexpr Event CLOCK_SET = MAKE_EVENT(0, severity::INFO);
//!< Clock could not be set. P1: Returncode.
static constexpr Event CLOCK_SET_FAILURE = MAKE_EVENT(1, severity::LOW);
static constexpr Event CLOCK_SET =
MAKE_EVENT(0, severity::INFO); //!< Clock has been set. P1: New Uptime. P2: Old Uptime
static constexpr Event CLOCK_SET_FAILURE =
MAKE_EVENT(1, severity::LOW); //!< Clock could not be set. P1: Returncode.
static constexpr uint8_t CLASS_ID = CLASS_ID::PUS_SERVICE_9;

View File

@ -307,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,
Mode_t fallbackSequence, bool inStore, bool preInit) {
ReturnValue_t result;
@ -350,6 +355,10 @@ ReturnValue_t Subsystem::addSequence(ArrayList<ModeListEntry> *sequence, Mode_t
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,
bool preInit) {
ReturnValue_t result;
@ -458,6 +467,7 @@ ReturnValue_t Subsystem::initialize() {
}
mode = initialMode;
submode = initSubmode;
return RETURN_OK;
}
@ -595,7 +605,10 @@ ReturnValue_t Subsystem::checkObjectConnections() {
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() {
ReturnValue_t result;

View File

@ -10,13 +10,31 @@
#include "fsfw/FSFW.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 This class extends the SubsystemBase to perform the management of mode tables
* and mode sequences
* @brief TODO: documentation missing
* @details
* This class is able to use mode tables and sequences to command all its children into the
* right mode. Fallback sequences can be used to handle failed transitions or have a fallback
* in case a component can't keep its current mode.
*/
class Subsystem : public SubsystemBase, public HasModeSequenceIF {
public:
@ -48,13 +66,15 @@ class Subsystem : public SubsystemBase, public HasModeSequenceIF {
uint32_t maxNumberOfTables);
virtual ~Subsystem();
ReturnValue_t addSequence(SequenceEntry sequence);
ReturnValue_t addSequence(ArrayList<ModeListEntry> *sequence, Mode_t id, Mode_t fallbackSequence,
bool inStore = true, bool preInit = true);
ReturnValue_t addTable(TableEntry table);
ReturnValue_t addTable(ArrayList<ModeListEntry> *table, Mode_t id, bool inStore = true,
bool preInit = true);
void setInitialMode(Mode_t mode);
void setInitialMode(Mode_t mode, Submode_t submode = SUBMODE_NONE);
virtual ReturnValue_t initialize() override;
@ -93,6 +113,7 @@ class Subsystem : public SubsystemBase, public HasModeSequenceIF {
Submode_t targetSubmode;
Mode_t initialMode = 0;
Submode_t initSubmode = SUBMODE_NONE;
HybridIterator<ModeListEntry> currentSequenceIterator;
@ -130,18 +151,18 @@ class Subsystem : public SubsystemBase, public HasModeSequenceIF {
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 isTableUsed(Mode_t tableId);
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);

View File

@ -8,13 +8,11 @@ SubsystemBase::SubsystemBase(object_id_t setObjectId, object_id_t parent, Mode_t
uint16_t commandQueueDepth)
: SystemObject(setObjectId),
mode(initialMode),
commandQueue(QueueFactory::instance()->createMessageQueue(commandQueueDepth,
CommandMessage::MAX_MESSAGE_SIZE)),
healthHelper(this, setObjectId),
modeHelper(this),
parentId(parent) {
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
commandQueue = QueueFactory::instance()->createMessageQueue(
commandQueueDepth, CommandMessage::MAX_MESSAGE_SIZE, &mqArgs);
}
parentId(parent) {}
SubsystemBase::~SubsystemBase() { QueueFactory::instance()->deleteMessageQueue(commandQueue); }
@ -33,9 +31,8 @@ ReturnValue_t SubsystemBase::registerChild(object_id_t objectId) {
info.mode = MODE_OFF;
}
} else {
// intentional to force an initial command during system startup
info.commandQueue = child->getCommandQueue();
info.mode = HasModesIF::MODE_UNDEFINED;
info.mode = -1; // intentional to force an initial command during system startup
}
info.submode = SUBMODE_NONE;

Some files were not shown because too many files have changed in this diff Show More