Compare commits

...

196 Commits

Author SHA1 Message Date
06111ec3ed missing call added 2022-05-14 16:57:59 +02:00
51087518b0 spi mutex handling refactoring 2022-05-14 11:32:51 +02:00
e3d1308205 Merge pull request 'preproc guards' (#612) from eive/fsfw:mueller/missing-preproc-defs into development
Reviewed-on: fsfw/fsfw#612
2022-05-13 13:22:38 +02:00
99c72fd00b Merge pull request 'Auto-Formatter Script Improvements' (#626) from mueller/amft-cmakelists into development
Reviewed-on: fsfw/fsfw#626
2022-05-13 12:01:40 +02:00
811287aac8 delete old scripts 2022-05-13 11:57:22 +02:00
23fb06578b this is better 2022-05-13 11:56:37 +02:00
c86e99e6dc rename auto-formatter 2022-05-13 11:56:20 +02:00
4092de911c use variable for repeated section 2022-05-13 11:55:19 +02:00
00952e15b0 Merge branch 'development' into mueller/missing-preproc-defs 2022-05-13 11:50:24 +02:00
01ebf0f4d3 tab size 2022-05-13 11:49:01 +02:00
99fe6487c8 another small improvement 2022-05-13 11:48:18 +02:00
d4a6f987bc small fix 2022-05-13 11:46:59 +02:00
57bac4f262 Merge remote-tracking branch 'origin/development' into mueller/amft-cmakelists 2022-05-13 11:46:17 +02:00
cfa6843c8f check whether clang-format is installed 2022-05-13 11:46:04 +02:00
b6b3221b22 Merge pull request 'run auto-formatter over cmakelists.txt' (#619) from mueller/amft-cmakelists into development
Reviewed-on: fsfw/fsfw#619
2022-05-13 11:44:48 +02:00
deee4c43c0 finally this works 2022-05-13 11:37:58 +02:00
ad0b6f1ed1 another small fix 2022-05-13 11:35:59 +02:00
ec03a674bd Merge branch 'mueller/amft-cmakelists' of https://egit.irs.uni-stuttgart.de/fsfw/fsfw into mueller/amft-cmakelists 2022-05-13 11:35:28 +02:00
9e3d5b6a0c small fix 2022-05-13 11:35:18 +02:00
994c7299b9 add cmake-format command to shell script 2022-05-13 11:34:44 +02:00
57a830cb46 Merge branch 'development' into mueller/amft-cmakelists 2022-05-13 11:30:52 +02:00
c215508a12 another missing preproc guard 2022-05-13 00:25:52 +02:00
ccadbb5942 Merge branch 'development' into mueller/missing-preproc-defs 2022-05-13 00:24:04 +02:00
a83b86ccd2 Merge pull request 'refactor power module' (#590) from eive/fsfw:mueller/refactor-power-switch-if-etc into development
Reviewed-on: fsfw/fsfw#590
2022-05-12 18:37:45 +02:00
3046822e88 run cmake-format 2022-05-12 17:27:39 +02:00
6442dd0c38 Merge branch 'mueller/amft-cmakelists' of https://egit.irs.uni-stuttgart.de/fsfw/fsfw into mueller/amft-cmakelists 2022-05-12 17:16:15 +02:00
9b6fa646ed Merge remote-tracking branch 'origin/development' into mueller/amft-cmakelists 2022-05-12 17:16:10 +02:00
2d9d83a1c5 Merge branch 'development' into mueller/missing-preproc-defs 2022-05-12 17:10:54 +02:00
c561271070 Merge branch 'development' into mueller/refactor-power-switch-if-etc 2022-05-12 17:09:27 +02:00
b99160e850 Merge pull request 'Add LTO support' (#616) from mueller/add-lto-support into development
Reviewed-on: fsfw/fsfw#616
2022-05-12 16:56:54 +02:00
d11f898f70 update dummy power switcher docs 2022-05-12 15:02:06 +02:00
34e124f2db Merge branch 'development' into mueller/amft-cmakelists 2022-05-11 11:30:40 +02:00
e05c72b062 minor formatting fix 2022-05-10 13:08:14 +02:00
2ca8523215 Merge branch 'mueller/add-lto-support' of https://egit.irs.uni-stuttgart.de/fsfw/fsfw into mueller/add-lto-support 2022-05-10 11:57:01 +02:00
25775614de only check IPO support if enabled 2022-05-10 11:56:51 +02:00
0410ecd9e3 Merge branch 'development' into mueller/add-lto-support 2022-05-10 11:51:39 +02:00
0fe1b70bae keep LTO option off by default 2022-05-10 11:19:29 +02:00
c5b4499d98 Merge remote-tracking branch 'upstream/development' into mueller/refactor-power-switch-if-etc 2022-05-10 09:58:21 +02:00
458aa5c265 Merge branch 'development' into mueller/missing-preproc-defs 2022-05-10 09:56:29 +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
eb0223bc51 Merge branch 'development' into mueller/add-lto-support 2022-05-09 22:34:28 +02:00
d8bd08dd8c Merge branch 'development' into mueller/amft-cmakelists 2022-05-09 17:22:40 +02:00
18c2847b08 Merge branch 'development' into mueller/missing-preproc-defs 2022-05-09 17:21:48 +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
d983305ea5 Merge branch 'development' into mueller/amft-cmakelists 2022-05-09 16:34:22 +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
dd9e28fca1 Merge branch 'development' into mueller/add-lto-support 2022-05-09 16:09:31 +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
7b7f5d7e0a Merge branch 'mueller/add-lto-support' of https://egit.irs.uni-stuttgart.de/fsfw/fsfw into mueller/add-lto-support 2022-05-09 16:07:19 +02:00
fd112ed597 enable lto for test target 2022-05-09 16:07:05 +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
5989c88c88 indentation 2022-05-09 15:54:29 +02:00
da8a108cb7 Merge remote-tracking branch 'origin/development' into mueller/amft-cmakelists 2022-05-09 15:54:10 +02:00
75132c1e39 Merge branch 'development' into mueller/add-lto-support 2022-05-09 15:52:28 +02:00
281f91ec5d Merge remote-tracking branch 'origin/development' into mueller/health-srv-bugfix 2022-05-09 15:41:10 +02:00
15352b539d Merge remote-tracking branch 'upstream/development' into mueller/refactor-power-switch-if-etc 2022-05-09 15:37:32 +02:00
4015e85506 Merge branch 'development' into mueller/missing-preproc-defs 2022-05-09 15:35:49 +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
8a40878eb5 Merge remote-tracking branch 'origin/development' into mueller/add-lto-support 2022-05-09 15:17:16 +02:00
220469a2dd Merge remote-tracking branch 'origin/development' into mueller/amft-cmakelists 2022-05-09 15:16:12 +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
6308427d03 run auto-formatter over cmakelists.txt 2022-05-09 11:18:56 +02:00
c78b7c432b Merge branch 'development' into mueller/refactor-power-switch-if-etc 2022-05-09 11:02:45 +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
637512ad77 changelog update 2022-05-09 10:34:14 +02:00
a4bd5a2aaa update changelog 2022-05-09 10:31:03 +02:00
a943e4eebb enable LTO where applicable 2022-05-09 02:23:20 +02:00
cb0c80d8dc add option and cmake module for lto support 2022-05-09 02:22:16 +02:00
3332f68ce7 Tested only std::numeric_limits in MSVC 2022-05-02 17:22:13 +02:00
2fbf847367 Merge branch 'development' into mueller/missing-preproc-defs 2022-05-02 16:16:33 +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
57e6c46e72 Merge branch 'development' into mueller/missing-preproc-defs 2022-05-02 15:16:37 +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
a3617cad11 preproc guards 2022-05-02 15:12:38 +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
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
2c8531ea48 Merge remote-tracking branch 'upstream/development' into mueller/refactor-power-switch-if-etc 2022-04-27 08:45:04 +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
b94685e045 added missing PR cross-ref 2022-04-25 15:44:46 +02:00
572d602b72 improve changelog, add entry 2022-04-25 15:42:44 +02:00
88051c9302 Merge remote-tracking branch 'upstream/development' into mueller/refactor-power-switch-if-etc 2022-04-25 15:37:03 +02:00
80be937d9d Merge remote-tracking branch 'upstream/development' into mueller/compiler-warning-fixes-upstream-2 2022-04-25 15:24:17 +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
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
4ed9cc933f Merge branch 'development' into mueller/refactor-power-switch-if-etc 2022-04-11 16:11:27 +02:00
9947a648df fix compiler warnings 2022-04-11 16:06:13 +02:00
95f018a0b0 update IF method 2022-04-11 14:07:02 +02:00
8c2105ae0a correct init value for object ID 2022-04-11 14:00:37 +02:00
ed2c2af4a0 take upstream impl of local data pool manager 2022-04-11 13:59:38 +02:00
82df132e7d tests running again 2022-04-11 13:54:43 +02:00
a02619e5a2 strongly simplified and streamlined IPC MQ Impl
- Generic code was duplicated across all OSALs.
  Is contained in generic base class now
- Remove duplicate documentation
2022-04-11 11:19:38 +02:00
a011e70665 Merge branch 'development' into mueller/ipc-pass-arbitrary-args-to-mq 2022-04-04 17:21:11 +02:00
b2252bdc0b Merge remote-tracking branch 'upstream/development' into mueller/add-etl-dependency 2022-04-04 14:18:30 +02:00
b764194ed0 added more unit tests 2022-04-01 18:43:46 +02:00
2d0e4ba951 applied afmt 2022-04-01 18:38:54 +02:00
0d549b687d Merge branch 'mueller/refactor-power-switch-if-etc' of https://egit.irs.uni-stuttgart.de/eive/fsfw into mueller/refactor-power-switch-if-etc 2022-04-01 18:38:34 +02:00
738f572043 added unit tests, minor API change 2022-04-01 18:38:25 +02:00
cab508fd64 Merge branch 'development' into mueller/refactor-power-switch-if-etc 2022-04-01 17:28:14 +02:00
c20be13733 change switch type in header as well 2022-04-01 16:40:13 +02:00
fcb6437388 Merge branch 'development' into mueller/ipc-pass-arbitrary-args-to-mq 2022-03-31 14:42:15 +02:00
b42987059a make dummy power switcher a system object 2022-03-30 17:41:38 +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
23af170229 small tweaks 2022-03-28 12:59:03 +02:00
b32d1da421 this should compile 2022-03-28 12:57:11 +02:00
6f0362b956 refactor power module 2022-03-28 12:48:15 +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
a0dfdfab2c Allow passing a MqArgs struct to the MQ creation
The struct contains context information (which can be extended)
and an arbitrary user argument in form of a void pointer.
This makes the API a lot more flexible
2022-03-22 17:49:22 +01:00
106 changed files with 2350 additions and 1710 deletions

View File

@ -12,6 +12,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## Changes ## Changes
- Bump C++ required version to C++17. Every project which uses the FSFW and every modern
compiler supports it
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/622
- HAL Linux SPI: Set the Clock Default State when setting new SPI speed - HAL Linux SPI: Set the Clock Default State when setting new SPI speed
and mode and mode
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/573 PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/573
@ -22,9 +25,42 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/572 PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/572
- HAL Devicehandlers: Periodic printout is run-time configurable now - HAL Devicehandlers: Periodic printout is run-time configurable now
- `oneShotAction` flag in the `TestTask` class is not static anymore - `oneShotAction` flag in the `TestTask` class is not static anymore
- 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
### HAL
- HAL Linux SPI: Set the Clock Default State when setting new SPI speed
and mode
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/573
- GPIO HAL: `Direction`, `GpioOperation` and `Levels` are enum classes now, which prevents
name clashes with Windows defines.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/572
- HAL Linux Uart: Baudrate and bits per word are enums now, avoiding misconfigurations - HAL Linux Uart: Baudrate and bits per word are enums now, avoiding misconfigurations
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/585 PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/585
### Time
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/584 and
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/593
- `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)
### Power
- `PowerSwitchIF`: Remove `const` specifier from `sendSwitchCommand` and `sendFuseOnCommand` and
also specify a `ReturnValue_t` return type
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/590
- Extend `PowerSwitcher` module to optionally check current state when calling `turnOn` or
`turnOff`. Tis can be helpful to avoid commanding switches which do not need commanding
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/590
## Removed ## Removed
- Removed the `HkSwitchHelper`. This module should not be needed anymore, now that the local - Removed the `HkSwitchHelper`. This module should not be needed anymore, now that the local
@ -33,15 +69,47 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## Additions ## Additions
- LTO support: Allow using LTO/IPO by setting `FSFW_ENABLE_LTO=1`. CMake is able to detect whether
the user compiler supports IPO/LPO. LTO is on by default now. Most modern compilers support it,
can make good use of it and it usually makes the code faster and/or smaller.
After some more research:
Enabling LTO will actually cause the compiler to only produce thin LTO by adding
`-flto -fno-fat-lto-objects` to the compiler options. I am not sure this is an ideal choice
because if an application linking against the FSFW does not use LTO, there can be compile
issues (e.g. observed when compiling the FSFW tests without LTO). This is a known issue as
can be seen in the multiple CMake issues for it:
- https://gitlab.kitware.com/cmake/cmake/-/issues/22913,
- https://gitlab.kitware.com/cmake/cmake/-/issues/16808,
- https://gitlab.kitware.com/cmake/cmake/-/issues/21696
Easiest solution for now: Keep this option OFF by default.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/616
- Linux HAL: Add wiretapping option for I2C. Enabled with `FSFW_HAL_I2C_WIRETAPPING` defined to 1 - Linux HAL: Add wiretapping option for I2C. Enabled with `FSFW_HAL_I2C_WIRETAPPING` defined to 1
- Dedicated Version class and constant `fsfw::FSFW_VERSION` containing version information - Dedicated Version class and constant `fsfw::FSFW_VERSION` containing version information
inside `fsfw/version.h` inside `fsfw/version.h`
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/559 PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/559
- Added ETL dependency and improved library dependency management
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/592
- Add a `DummyPowerSwitcher` module which can be useful for test setups when no PCDU is available
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/590
- New typedef for switcher type
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/590
- `Subsystem`: New API to add table and sequence entries
## Fixed ## Fixed
- TCP TMTC Server: `MutexGuard` was not created properly in
`TcpTmTcServer::handleTmSending(socket_t connSocket, bool& tmSent)` call.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/618
- Fix infinite recursion in `prepareHealthSetReply` of PUS Health Service 201.
Is not currently used right now but might be used in the future
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/617
- Move some CMake directives further up top so they are not ignored
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/621
- Small bugfix in STM32 HAL for SPI - Small bugfix in STM32 HAL for SPI
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/599 PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/599
- HAL GPIO: Improved error checking in `LinuxLibgpioIF::configureGpios(...)`. If a GPIO
configuration fails, the function will exit prematurely with a dedicated error code
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/602
# [v4.0.0] # [v4.0.0]

View File

@ -1,5 +1,15 @@
cmake_minimum_required(VERSION 3.13) cmake_minimum_required(VERSION 3.13)
set(LIB_FSFW_NAME fsfw)
project(${LIB_FSFW_NAME})
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
elseif(${CMAKE_CXX_STANDARD} LESS 17)
message(FATAL_ERROR "Compiling the FSFW requires a minimum of C++17 support")
endif()
set(FSFW_VERSION 4) set(FSFW_VERSION 4)
set(FSFW_SUBVERSION 0) set(FSFW_SUBVERSION 0)
set(FSFW_REVISION 0) set(FSFW_REVISION 0)
@ -7,14 +17,45 @@ set(FSFW_REVISION 0)
# Add the cmake folder so the FindSphinx module is found # Add the cmake folder so the FindSphinx module is found
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
set(FSFW_ETL_LIB_NAME etl)
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")
# Keep this off by default for now. See PR:
# https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/616 for information which
# keeping this on by default is problematic
option(
FSFW_ENABLE_IPO
"Enable interprocedural optimization or link-time optimization if available"
OFF)
if(FSFW_ENABLE_IPO)
include(CheckIPOSupported)
check_ipo_supported(RESULT IPO_SUPPORTED OUTPUT IPO_ERROR)
if(NOT IPO_SUPPORTED)
message(STATUS "FSFW | IPO/LTO not supported: ${IPO_ERROR}")
endif()
endif()
option(FSFW_GENERATE_SECTIONS option(FSFW_GENERATE_SECTIONS
"Generate function and data sections. Required to remove unused code" ON "Generate function and data sections. Required to remove unused code" ON)
)
if(FSFW_GENERATE_SECTIONS) if(FSFW_GENERATE_SECTIONS)
option(FSFW_REMOVE_UNUSED_CODE "Remove unused code" ON) option(FSFW_REMOVE_UNUSED_CODE "Remove unused code" ON)
endif() endif()
option(FSFW_BUILD_UNITTESTS "Build unittest binary in addition to static library" OFF) option(FSFW_BUILD_UNITTESTS
"Build unittest binary in addition to static library" OFF)
option(FSFW_BUILD_DOCS "Build documentation with Sphinx and Doxygen" OFF) option(FSFW_BUILD_DOCS "Build documentation with Sphinx and Doxygen" OFF)
if(FSFW_BUILD_UNITTESTS) if(FSFW_BUILD_UNITTESTS)
option(FSFW_TESTS_GEN_COV "Generate coverage data for unittests" ON) option(FSFW_TESTS_GEN_COV "Generate coverage data for unittests" ON)
@ -38,50 +79,56 @@ option(FSFW_ADD_TMSTORAGE "Compile with tm storage components" OFF)
# Contrib sources # Contrib sources
option(FSFW_ADD_SGP4_PROPAGATOR "Add SGP4 propagator code" OFF) option(FSFW_ADD_SGP4_PROPAGATOR "Add SGP4 propagator code" OFF)
set(LIB_FSFW_NAME fsfw)
set(FSFW_TEST_TGT fsfw-tests) set(FSFW_TEST_TGT fsfw-tests)
set(FSFW_DUMMY_TGT fsfw-dummy) set(FSFW_DUMMY_TGT fsfw-dummy)
project(${LIB_FSFW_NAME})
add_library(${LIB_FSFW_NAME}) add_library(${LIB_FSFW_NAME})
if(IPO_SUPPORTED AND FSFW_ENABLE_IPO)
set_property(TARGET ${LIB_FSFW_NAME} PROPERTY INTERPROCEDURAL_OPTIMIZATION
TRUE)
endif()
if(FSFW_BUILD_UNITTESTS) if(FSFW_BUILD_UNITTESTS)
message(STATUS "Building the FSFW unittests in addition to the static library") message(
STATUS "Building the FSFW unittests in addition to the static library")
# Check whether the user has already installed Catch2 first # Check whether the user has already installed Catch2 first
find_package(Catch2 3 QUIET) find_package(Catch2 ${FSFW_CATCH2_LIB_MAJOR_VERSION})
# Not installed, so use FetchContent to download and provide Catch2 # Not installed, so use FetchContent to download and provide Catch2
if(NOT Catch2_FOUND) if(NOT Catch2_FOUND)
message(STATUS "Catch2 installation not found. Downloading Catch2 library with FetchContent") message(
STATUS
"Catch2 installation not found. Downloading Catch2 library with FetchContent"
)
include(FetchContent) include(FetchContent)
FetchContent_Declare( FetchContent_Declare(
Catch2 Catch2
GIT_REPOSITORY https://github.com/catchorg/Catch2.git GIT_REPOSITORY https://github.com/catchorg/Catch2.git
GIT_TAG v3.0.0-preview4 GIT_TAG ${FSFW_CATCH2_LIB_VERSION})
)
FetchContent_MakeAvailable(Catch2) list(APPEND FSFW_FETCH_CONTENT_TARGETS Catch2)
#fixes regression -preview4, to be confirmed in later releases
set_target_properties(Catch2 PROPERTIES DEBUG_POSTFIX "")
endif() endif()
set(FSFW_CONFIG_PATH tests/src/fsfw_tests/unit/testcfg) set(FSFW_CONFIG_PATH tests/src/fsfw_tests/unit/testcfg)
configure_file(tests/src/fsfw_tests/unit/testcfg/FSFWConfig.h.in FSFWConfig.h) configure_file(tests/src/fsfw_tests/unit/testcfg/FSFWConfig.h.in FSFWConfig.h)
configure_file(tests/src/fsfw_tests/unit/testcfg/TestsConfig.h.in tests/TestsConfig.h) configure_file(tests/src/fsfw_tests/unit/testcfg/TestsConfig.h.in
tests/TestsConfig.h)
project(${FSFW_TEST_TGT} CXX C) project(${FSFW_TEST_TGT} CXX C)
add_executable(${FSFW_TEST_TGT}) add_executable(${FSFW_TEST_TGT})
if(IPO_SUPPORTED AND FSFW_ENABLE_IPO)
set_property(TARGET ${FSFW_TEST_TGT} PROPERTY INTERPROCEDURAL_OPTIMIZATION
TRUE)
endif()
if(FSFW_TESTS_GEN_COV) if(FSFW_TESTS_GEN_COV)
message(STATUS "Generating coverage data for the library") message(STATUS "Generating coverage data for the library")
message(STATUS "Targets linking against ${LIB_FSFW_NAME} " message(STATUS "Targets linking against ${LIB_FSFW_NAME} "
"will be compiled with coverage data as well" "will be compiled with coverage data as well")
)
include(FetchContent) include(FetchContent)
FetchContent_Declare( FetchContent_Declare(
cmake-modules cmake-modules GIT_REPOSITORY https://github.com/bilke/cmake-modules.git)
GIT_REPOSITORY https://github.com/bilke/cmake-modules.git
)
FetchContent_MakeAvailable(cmake-modules) FetchContent_MakeAvailable(cmake-modules)
set(CMAKE_BUILD_TYPE "Debug") set(CMAKE_BUILD_TYPE "Debug")
list(APPEND CMAKE_MODULE_PATH ${cmake-modules_SOURCE_DIR}) list(APPEND CMAKE_MODULE_PATH ${cmake-modules_SOURCE_DIR})
@ -89,24 +136,49 @@ if(FSFW_BUILD_UNITTESTS)
endif() endif()
endif() endif()
message(STATUS "Finding and/or providing ETL library")
# Check whether the user has already installed ETL first
find_package(${FSFW_ETL_LIB_NAME} ${FSFW_ETL_LIB_MAJOR_VERSION} QUIET)
# Not installed, so use FetchContent to download and provide etl
if(NOT ${FSFW_ETL_LIB_NAME}_FOUND)
message(
STATUS
"No ETL installation was found with find_package. Installing and providing "
"etl with FindPackage")
include(FetchContent)
FetchContent_Declare(
${FSFW_ETL_LIB_NAME}
GIT_REPOSITORY https://github.com/ETLCPP/etl
GIT_TAG ${FSFW_ETL_LIB_VERSION})
list(APPEND FSFW_FETCH_CONTENT_TARGETS ${FSFW_ETL_LIB_NAME})
endif()
# The documentation for FetchContent recommends declaring all the dependencies
# before making them available. We make all declared dependency available here
# after their declaration
if(FSFW_FETCH_CONTENT_TARGETS)
FetchContent_MakeAvailable(${FSFW_FETCH_CONTENT_TARGETS})
if(TARGET ${FSFW_ETL_LIB_NAME})
add_library(${FSFW_ETL_LINK_TARGET} ALIAS ${FSFW_ETL_LIB_NAME})
endif()
if(TARGET Catch2)
# Fixes regression -preview4, to be confirmed in later releases Related
# GitHub issue: https://github.com/catchorg/Catch2/issues/2417
set_target_properties(Catch2 PROPERTIES DEBUG_POSTFIX "")
endif()
endif()
set(FSFW_CORE_INC_PATH "inc") set(FSFW_CORE_INC_PATH "inc")
set_property(CACHE FSFW_OSAL PROPERTY STRINGS host linux rtems freertos) set_property(CACHE FSFW_OSAL PROPERTY STRINGS host linux rtems freertos)
# For configure files # For configure files
target_include_directories(${LIB_FSFW_NAME} PRIVATE target_include_directories(${LIB_FSFW_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
${CMAKE_CURRENT_BINARY_DIR} target_include_directories(${LIB_FSFW_NAME}
) INTERFACE ${CMAKE_CURRENT_BINARY_DIR})
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 "Compiling the FSFW requires a minimum of C++11 support")
endif()
# Backwards comptability # Backwards comptability
if(OS_FSFW AND NOT FSFW_OSAL) if(OS_FSFW AND NOT FSFW_OSAL)
@ -118,14 +190,13 @@ if(NOT FSFW_OSAL)
message(STATUS "No OS for FSFW via FSFW_OSAL set. Assuming host OS") message(STATUS "No OS for FSFW via FSFW_OSAL set. Assuming host OS")
# Assume host OS and autodetermine from OS_FSFW # Assume host OS and autodetermine from OS_FSFW
if(UNIX) if(UNIX)
set(FSFW_OSAL "linux" set(FSFW_OSAL
CACHE STRING "linux"
"OS abstraction layer used in the FSFW" CACHE STRING "OS abstraction layer used in the FSFW")
)
elseif(WIN32) elseif(WIN32)
set(FSFW_OSAL "host" set(FSFW_OSAL
CACHE STRING "OS abstraction layer used in the FSFW" "host"
) CACHE STRING "OS abstraction layer used in the FSFW")
endif() endif()
endif() endif()
@ -141,16 +212,13 @@ elseif(FSFW_OSAL MATCHES linux)
elseif(FSFW_OSAL MATCHES freertos) elseif(FSFW_OSAL MATCHES freertos)
set(FSFW_OS_NAME "FreeRTOS") set(FSFW_OS_NAME "FreeRTOS")
set(FSFW_OSAL_FREERTOS ON) set(FSFW_OSAL_FREERTOS ON)
target_link_libraries(${LIB_FSFW_NAME} PRIVATE target_link_libraries(${LIB_FSFW_NAME} PRIVATE ${LIB_OS_NAME})
${LIB_OS_NAME}
)
elseif(FSFW_OSAL STREQUAL rtems) elseif(FSFW_OSAL STREQUAL rtems)
set(FSFW_OS_NAME "RTEMS") set(FSFW_OS_NAME "RTEMS")
set(FSFW_OSAL_RTEMS ON) set(FSFW_OSAL_RTEMS ON)
else() else()
message(WARNING message(
"Invalid operating system for FSFW specified! Setting to host.." WARNING "Invalid operating system for FSFW specified! Setting to host..")
)
set(FSFW_OS_NAME "Host") set(FSFW_OS_NAME "Host")
set(OS_FSFW "host") set(OS_FSFW "host")
endif() endif()
@ -176,69 +244,57 @@ if(FSFW_BUILD_UNITTESTS)
include(CodeCoverage) include(CodeCoverage)
# Remove quotes. # Remove quotes.
separate_arguments(COVERAGE_COMPILER_FLAGS separate_arguments(COVERAGE_COMPILER_FLAGS NATIVE_COMMAND
NATIVE_COMMAND "${COVERAGE_COMPILER_FLAGS}" "${COVERAGE_COMPILER_FLAGS}")
)
# Add compile options manually, we don't want coverage for Catch2 # Add compile options manually, we don't want coverage for Catch2
target_compile_options(${FSFW_TEST_TGT} PRIVATE target_compile_options(${FSFW_TEST_TGT}
"${COVERAGE_COMPILER_FLAGS}" PRIVATE "${COVERAGE_COMPILER_FLAGS}")
) target_compile_options(${LIB_FSFW_NAME}
target_compile_options(${LIB_FSFW_NAME} PRIVATE PRIVATE "${COVERAGE_COMPILER_FLAGS}")
"${COVERAGE_COMPILER_FLAGS}"
)
# Exclude directories here # Exclude directories here
if(WIN32) if(WIN32)
set(GCOVR_ADDITIONAL_ARGS set(GCOVR_ADDITIONAL_ARGS "--exclude-throw-branches"
"--exclude-throw-branches" "--exclude-unreachable-branches")
"--exclude-unreachable-branches" set(COVERAGE_EXCLUDES "/c/msys64/mingw64/*" "*/fsfw_hal/*")
)
set(COVERAGE_EXCLUDES
"/c/msys64/mingw64/*" "*/fsfw_hal/*"
)
elseif(UNIX) elseif(UNIX)
set(COVERAGE_EXCLUDES set(COVERAGE_EXCLUDES
"/usr/include/*" "/usr/bin/*" "Catch2/*" "/usr/include/*"
"/usr/local/include/*" "*/fsfw_tests/*" "/usr/bin/*"
"*/catch2-src/*" "*/fsfw_hal/*" "Catch2/*"
) "/usr/local/include/*"
"*/fsfw_tests/*"
"*/catch2-src/*"
"*/fsfw_hal/*")
endif() endif()
target_link_options(${FSFW_TEST_TGT} PRIVATE target_link_options(${FSFW_TEST_TGT} PRIVATE -fprofile-arcs
-fprofile-arcs -ftest-coverage)
-ftest-coverage target_link_options(${LIB_FSFW_NAME} PRIVATE -fprofile-arcs
) -ftest-coverage)
target_link_options(${LIB_FSFW_NAME} PRIVATE # Need to specify this as an interface, otherwise there will the compile
-fprofile-arcs # issues
-ftest-coverage target_link_options(${LIB_FSFW_NAME} INTERFACE -fprofile-arcs
) -ftest-coverage)
# Need to specify this as an interface, otherwise there will the compile issues
target_link_options(${LIB_FSFW_NAME} INTERFACE
-fprofile-arcs
-ftest-coverage
)
if(WIN32) if(WIN32)
setup_target_for_coverage_gcovr_html( setup_target_for_coverage_gcovr_html(
NAME ${FSFW_TEST_TGT}_coverage NAME ${FSFW_TEST_TGT}_coverage EXECUTABLE ${FSFW_TEST_TGT}
EXECUTABLE ${FSFW_TEST_TGT} DEPENDENCIES ${FSFW_TEST_TGT})
DEPENDENCIES ${FSFW_TEST_TGT}
)
else() else()
setup_target_for_coverage_lcov( setup_target_for_coverage_lcov(
NAME ${FSFW_TEST_TGT}_coverage NAME ${FSFW_TEST_TGT}_coverage EXECUTABLE ${FSFW_TEST_TGT}
EXECUTABLE ${FSFW_TEST_TGT} DEPENDENCIES ${FSFW_TEST_TGT})
DEPENDENCIES ${FSFW_TEST_TGT}
)
endif() endif()
endif() endif()
endif() endif()
target_link_libraries(${FSFW_TEST_TGT} PRIVATE Catch2::Catch2 ${LIB_FSFW_NAME}) target_link_libraries(${FSFW_TEST_TGT} PRIVATE Catch2::Catch2
${LIB_FSFW_NAME})
endif() endif()
# The project CMakeLists file has to set the FSFW_CONFIG_PATH and add it. # The project CMakeLists file has to set the FSFW_CONFIG_PATH and add it. If
# If this is not given, we include the default configuration and emit a warning. # this is not given, we include the default configuration and emit a warning.
if(NOT FSFW_CONFIG_PATH) if(NOT FSFW_CONFIG_PATH)
set(DEF_CONF_PATH misc/defaultcfg/fsfwconfig) set(DEF_CONF_PATH misc/defaultcfg/fsfwconfig)
if(NOT FSFW_BUILD_DOCS) if(NOT FSFW_BUILD_DOCS)
@ -249,22 +305,21 @@ if(NOT FSFW_CONFIG_PATH)
set(FSFW_CONFIG_PATH ${DEF_CONF_PATH}) set(FSFW_CONFIG_PATH ${DEF_CONF_PATH})
endif() endif()
# FSFW might be part of a possibly complicated folder structure, so we # FSFW might be part of a possibly complicated folder structure, so we extract
# extract the absolute path of the fsfwconfig folder. # the absolute path of the fsfwconfig folder.
if(IS_ABSOLUTE ${FSFW_CONFIG_PATH}) if(IS_ABSOLUTE ${FSFW_CONFIG_PATH})
set(FSFW_CONFIG_PATH_ABSOLUTE ${FSFW_CONFIG_PATH}) set(FSFW_CONFIG_PATH_ABSOLUTE ${FSFW_CONFIG_PATH})
else() else()
get_filename_component(FSFW_CONFIG_PATH_ABSOLUTE get_filename_component(FSFW_CONFIG_PATH_ABSOLUTE ${FSFW_CONFIG_PATH} REALPATH
${FSFW_CONFIG_PATH} REALPATH BASE_DIR ${CMAKE_SOURCE_DIR} BASE_DIR ${CMAKE_SOURCE_DIR})
)
endif() endif()
foreach(INCLUDE_PATH ${FSFW_ADDITIONAL_INC_PATHS}) foreach(INCLUDE_PATH ${FSFW_ADDITIONAL_INC_PATHS})
if(IS_ABSOLUTE ${INCLUDE_PATH}) if(IS_ABSOLUTE ${INCLUDE_PATH})
set(CURR_ABS_INC_PATH "${INCLUDE_PATH}") set(CURR_ABS_INC_PATH "${INCLUDE_PATH}")
else() else()
get_filename_component(CURR_ABS_INC_PATH get_filename_component(CURR_ABS_INC_PATH ${INCLUDE_PATH} REALPATH BASE_DIR
${INCLUDE_PATH} REALPATH BASE_DIR ${CMAKE_SOURCE_DIR}) ${CMAKE_SOURCE_DIR})
endif() endif()
if(CMAKE_VERBOSE) if(CMAKE_VERBOSE)
@ -297,23 +352,19 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
-Wcast-qual # Warn if the constness is cast away -Wcast-qual # Warn if the constness is cast away
-Wstringop-overflow=4 -Wstringop-overflow=4
# -Wstack-protector # Emits a few false positives for low level access # -Wstack-protector # Emits a few false positives for low level access
# -Wconversion # Creates many false positives # -Wconversion # Creates many false positives -Warith-conversion # Use
# -Warith-conversion # Use with Wconversion to find more implicit conversions # with Wconversion to find more implicit conversions -fanalyzer # Should
# -fanalyzer # Should be used to look through problems # be used to look through problems
) )
endif() endif()
if(FSFW_GENERATE_SECTIONS) if(FSFW_GENERATE_SECTIONS)
target_compile_options(${LIB_FSFW_NAME} PRIVATE target_compile_options(${LIB_FSFW_NAME} PRIVATE "-ffunction-sections"
"-ffunction-sections" "-fdata-sections")
"-fdata-sections"
)
endif() endif()
if(FSFW_REMOVE_UNUSED_CODE) if(FSFW_REMOVE_UNUSED_CODE)
target_link_options(${LIB_FSFW_NAME} PRIVATE target_link_options(${LIB_FSFW_NAME} PRIVATE "Wl,--gc-sections")
"Wl,--gc-sections"
)
endif() endif()
if(FSFW_WARNING_SHADOW_LOCAL_GCC) if(FSFW_WARNING_SHADOW_LOCAL_GCC)
@ -327,41 +378,31 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
endif() endif()
# Required include paths to compile the FSFW # Required include paths to compile the FSFW
target_include_directories(${LIB_FSFW_NAME} INTERFACE target_include_directories(
${CMAKE_SOURCE_DIR} ${LIB_FSFW_NAME} INTERFACE ${CMAKE_SOURCE_DIR} ${FSFW_CONFIG_PATH_ABSOLUTE}
${FSFW_CONFIG_PATH_ABSOLUTE} ${FSFW_CORE_INC_PATH} ${FSFW_ADD_INC_PATHS_ABS})
${FSFW_CORE_INC_PATH}
${FSFW_ADD_INC_PATHS_ABS}
)
# Includes path required to compile FSFW itself as well # Includes path required to compile FSFW itself as well We assume that the
# We assume that the fsfwconfig folder uses include relative to the project # fsfwconfig folder uses include relative to the project root here!
# root here! target_include_directories(
target_include_directories(${LIB_FSFW_NAME} PRIVATE ${LIB_FSFW_NAME} PRIVATE ${CMAKE_SOURCE_DIR} ${FSFW_CONFIG_PATH_ABSOLUTE}
${CMAKE_SOURCE_DIR} ${FSFW_CORE_INC_PATH} ${FSFW_ADD_INC_PATHS_ABS})
${FSFW_CONFIG_PATH_ABSOLUTE}
${FSFW_CORE_INC_PATH}
${FSFW_ADD_INC_PATHS_ABS}
)
target_compile_options(${LIB_FSFW_NAME} PRIVATE target_compile_options(${LIB_FSFW_NAME} PRIVATE ${FSFW_WARNING_FLAGS}
${FSFW_WARNING_FLAGS} ${COMPILER_FLAGS})
${COMPILER_FLAGS}
)
target_link_libraries(${LIB_FSFW_NAME} PRIVATE target_link_libraries(${LIB_FSFW_NAME} PRIVATE ${FSFW_ETL_LINK_TARGET}
${FSFW_ADDITIONAL_LINK_LIBS} ${FSFW_ADDITIONAL_LINK_LIBS})
)
string(CONCAT POST_BUILD_COMMENT string(
CONCAT
POST_BUILD_COMMENT
"######################################################################\n" "######################################################################\n"
"Built FSFW v${FSFW_VERSION}.${FSFW_SUBVERSION}.${FSFW_REVISION}, " "Built FSFW v${FSFW_VERSION}.${FSFW_SUBVERSION}.${FSFW_REVISION}, "
"Target OSAL: ${FSFW_OS_NAME}\n" "Target OSAL: ${FSFW_OS_NAME}\n"
"######################################################################\n" "######################################################################\n")
)
add_custom_command( add_custom_command(
TARGET ${LIB_FSFW_NAME} TARGET ${LIB_FSFW_NAME}
POST_BUILD POST_BUILD
COMMENT ${POST_BUILD_COMMENT} COMMENT ${POST_BUILD_COMMENT})
)

View File

@ -11,9 +11,15 @@ with Airbus Defence and Space GmbH.
## Quick facts ## Quick facts
The framework is designed for systems, which communicate with external devices, perform control loops, receive telecommands and send telemetry, and need to maintain a high level of availability. Therefore, a mode and health system provides control over the states of the software and the controlled devices. In addition, a simple mechanism of event based fault detection, isolation and recovery is implemented as well. The framework is designed for systems, which communicate with external devices, perform control loops,
receive telecommands and send telemetry, and need to maintain a high level of availability. Therefore,
a mode and health system provides control over the states of the software and the controlled devices.
In addition, a simple mechanism of event based fault detection, isolation and recovery is implemented as well.
The FSFW provides abstraction layers for operating systems to provide a uniform operating system abstraction layer (OSAL). Some components of this OSAL are required internally by the FSFW but is also very useful for developers to implement the same application logic on different operating systems with a uniform interface. The FSFW provides abstraction layers for operating systems to provide a uniform operating system
abstraction layer (OSAL). Some components of this OSAL are required internally by the FSFW but is
also very useful for developers to implement the same application logic on different operating
systems with a uniform interface.
Currently, the FSFW provides the following OSALs: Currently, the FSFW provides the following OSALs:
@ -45,6 +51,28 @@ A template configuration folder was provided and can be copied into the project
a starting point. The [configuration section](docs/README-config.md#top) provides more specific a starting point. The [configuration section](docs/README-config.md#top) provides more specific
information about the possible options. information about the possible options.
## Prerequisites
The Embedded Template Library (etl) is a dependency of the FSFW which is automatically
installed and provided by the build system unless the correction version was installed.
The current recommended version can be found inside the fsfw `CMakeLists.txt` file or by using
`ccmake` and looking up the `FSFW_ETL_LIB_MAJOR_VERSION` variable.
You can install the ETL library like this. On Linux, it might be necessary to add `sudo` before
the install call:
```cpp
git clone https://github.com/ETLCPP/etl
cd etl
git checkout <currentRecommendedVersion>
mkdir build && cd build
cmake ..
cmake --install .
```
It is recommended to install `20.27.2` or newer for the package version handling of
ETL to work.
## Adding the library ## Adding the library
The following steps show how to add and use FSFW components. It is still recommended to The following steps show how to add and use FSFW components. It is still recommended to
@ -83,6 +111,19 @@ The FSFW also has unittests which use the [Catch2 library](https://github.com/ca
These are built by setting the CMake option `FSFW_BUILD_UNITTESTS` to `ON` or `TRUE` These are built by setting the CMake option `FSFW_BUILD_UNITTESTS` to `ON` or `TRUE`
from your project `CMakeLists.txt` file or from the command line. from your project `CMakeLists.txt` file or from the command line.
You can install the Catch2 library, which prevents the build system to avoid re-downloading
the dependency if the unit tests are completely rebuilt. The current recommended version
can be found inside the fsfw `CMakeLists.txt` file or by using `ccmake` and looking up
the `FSFW_CATCH2_LIB_VERSION` variable.
```sh
git clone https://github.com/catchorg/Catch2.git
cd Catch2
git checkout <currentRecommendedVersion>
cmake -Bbuild -H. -DBUILD_TESTING=OFF
sudo cmake --build build/ --target install
```
The fsfw-tests binary will be built as part of the static library and dropped alongside it. The fsfw-tests binary will be built as part of the static library and dropped alongside it.
If the unittests are built, the library and the tests will be built with coverage information by If the unittests are built, the library and the tests will be built with coverage information by
default. This can be disabled by setting the `FSFW_TESTS_COV_GEN` option to `OFF` or `FALSE`. default. This can be disabled by setting the `FSFW_TESTS_COV_GEN` option to `OFF` or `FALSE`.

View File

@ -6,3 +6,9 @@ RUN apt-get --yes upgrade
#tzdata is a dependency, won't install otherwise #tzdata is a dependency, won't install otherwise
ARG DEBIAN_FRONTEND=noninteractive ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get --yes install gcc g++ cmake make lcov git valgrind nano iputils-ping RUN apt-get --yes install gcc g++ cmake make lcov git valgrind nano iputils-ping
RUN git clone https://github.com/catchorg/Catch2.git && \
cd Catch2 && \
git checkout v3.0.0-preview5 && \
cmake -Bbuild -H. -DBUILD_TESTING=OFF && \
cmake --build build/ --target install

View File

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

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 a starting point. The [configuration section](docs/README-config.md#top) provides more specific
information about the possible options. information about the possible options.
Prerequisites
-------------------
The Embedded Template Library (etl) is a dependency of the FSFW which is automatically
installed and provided by the build system unless the correction version was installed.
The current recommended version can be found inside the fsfw ``CMakeLists.txt`` file or by using
``ccmake`` and looking up the ``FSFW_ETL_LIB_MAJOR_VERSION`` variable.
You can install the ETL library like this. On Linux, it might be necessary to add ``sudo`` before
the install call:
.. code-block:: console
git clone https://github.com/ETLCPP/etl
cd etl
git checkout <currentRecommendedVersion>
mkdir build && cd build
cmake ..
cmake --install .
It is recommended to install ``20.27.2`` or newer for the package version handling of
ETL to work.
Adding the library Adding the library
------------------- -------------------
@ -60,6 +83,20 @@ The FSFW also has unittests which use the `Catch2 library`_.
These are built by setting the CMake option ``FSFW_BUILD_UNITTESTS`` to ``ON`` or `TRUE` These are built by setting the CMake option ``FSFW_BUILD_UNITTESTS`` to ``ON`` or `TRUE`
from your project `CMakeLists.txt` file or from the command line. from your project `CMakeLists.txt` file or from the command line.
You can install the Catch2 library, which prevents the build system to avoid re-downloading
the dependency if the unit tests are completely rebuilt. The current recommended version
can be found inside the fsfw ``CMakeLists.txt`` file or by using ``ccmake`` and looking up
the ``FSFW_CATCH2_LIB_VERSION`` variable.
.. code-block:: console
git clone https://github.com/catchorg/Catch2.git
cd Catch2
git checkout <currentRecommendedVersion>
cmake -Bbuild -H. -DBUILD_TESTING=OFF
sudo cmake --build build/ --target install
The fsfw-tests binary will be built as part of the static library and dropped alongside it. The fsfw-tests binary will be built as part of the static library and dropped alongside it.
If the unittests are built, the library and the tests will be built with coverage information by If the unittests are built, the library and the tests will be built with coverage information by
default. This can be disabled by setting the `FSFW_TESTS_COV_GEN` option to `OFF` or `FALSE`. default. This can be disabled by setting the `FSFW_TESTS_COV_GEN` option to `OFF` or `FALSE`.

View File

@ -1,9 +1,9 @@
#include "MgmLIS3MDLHandler.h" #include "MgmLIS3MDLHandler.h"
#include "fsfw/datapool/PoolReadGuard.h"
#include <cmath> #include <cmath>
#include "fsfw/datapool/PoolReadGuard.h"
MgmLIS3MDLHandler::MgmLIS3MDLHandler(object_id_t objectId, object_id_t deviceCommunication, MgmLIS3MDLHandler::MgmLIS3MDLHandler(object_id_t objectId, object_id_t deviceCommunication,
CookieIF *comCookie, uint32_t transitionDelay) CookieIF *comCookie, uint32_t transitionDelay)
: DeviceHandlerBase(objectId, deviceCommunication, comCookie), : DeviceHandlerBase(objectId, deviceCommunication, comCookie),

View File

@ -12,9 +12,14 @@ if(FSFW_HAL_LINUX_ADD_PERIPHERAL_DRIVERS)
if(FSFW_HAL_LINUX_ADD_LIBGPIOD) if(FSFW_HAL_LINUX_ADD_LIBGPIOD)
add_subdirectory(gpio) add_subdirectory(gpio)
endif() endif()
add_subdirectory(spi)
add_subdirectory(i2c)
add_subdirectory(uart) add_subdirectory(uart)
# Adding those does not really make sense on Apple systems which
# are generally host systems. It won't even compile as the headers
# are missing
if(NOT APPLE)
add_subdirectory(i2c)
add_subdirectory(spi)
endif()
endif() endif()
add_subdirectory(uio) add_subdirectory(uio)

View File

@ -20,7 +20,9 @@ LinuxLibgpioIF::~LinuxLibgpioIF() {
ReturnValue_t LinuxLibgpioIF::addGpios(GpioCookie* gpioCookie) { ReturnValue_t LinuxLibgpioIF::addGpios(GpioCookie* gpioCookie) {
ReturnValue_t result; ReturnValue_t result;
if (gpioCookie == nullptr) { if (gpioCookie == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "LinuxLibgpioIF::addGpios: Invalid cookie" << std::endl; sif::error << "LinuxLibgpioIF::addGpios: Invalid cookie" << std::endl;
#endif
return RETURN_FAILED; return RETURN_FAILED;
} }
@ -44,6 +46,7 @@ ReturnValue_t LinuxLibgpioIF::addGpios(GpioCookie* gpioCookie) {
} }
ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) { ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) {
ReturnValue_t result = RETURN_OK;
for (auto& gpioConfig : mapToAdd) { for (auto& gpioConfig : mapToAdd) {
auto& gpioType = gpioConfig.second->gpioType; auto& gpioType = gpioConfig.second->gpioType;
switch (gpioType) { switch (gpioType) {
@ -55,7 +58,7 @@ ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) {
if (regularGpio == nullptr) { if (regularGpio == nullptr) {
return GPIO_INVALID_INSTANCE; return GPIO_INVALID_INSTANCE;
} }
configureGpioByChip(gpioConfig.first, *regularGpio); result = configureGpioByChip(gpioConfig.first, *regularGpio);
break; break;
} }
case (gpio::GpioTypes::GPIO_REGULAR_BY_LABEL): { case (gpio::GpioTypes::GPIO_REGULAR_BY_LABEL): {
@ -63,7 +66,7 @@ ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) {
if (regularGpio == nullptr) { if (regularGpio == nullptr) {
return GPIO_INVALID_INSTANCE; return GPIO_INVALID_INSTANCE;
} }
configureGpioByLabel(gpioConfig.first, *regularGpio); result = configureGpioByLabel(gpioConfig.first, *regularGpio);
break; break;
} }
case (gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME): { case (gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME): {
@ -71,7 +74,7 @@ ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) {
if (regularGpio == nullptr) { if (regularGpio == nullptr) {
return GPIO_INVALID_INSTANCE; return GPIO_INVALID_INSTANCE;
} }
configureGpioByLineName(gpioConfig.first, *regularGpio); result = configureGpioByLineName(gpioConfig.first, *regularGpio);
break; break;
} }
case (gpio::GpioTypes::CALLBACK): { case (gpio::GpioTypes::CALLBACK): {
@ -83,8 +86,11 @@ ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) {
gpioCallback->initValue, gpioCallback->callbackArgs); gpioCallback->initValue, gpioCallback->callbackArgs);
} }
} }
if (result != RETURN_OK) {
return GPIO_INIT_FAILED;
} }
return RETURN_OK; }
return result;
} }
ReturnValue_t LinuxLibgpioIF::configureGpioByLabel(gpioId_t gpioId, ReturnValue_t LinuxLibgpioIF::configureGpioByLabel(gpioId_t gpioId,
@ -92,8 +98,10 @@ ReturnValue_t LinuxLibgpioIF::configureGpioByLabel(gpioId_t gpioId,
std::string& label = gpioByLabel.label; std::string& label = gpioByLabel.label;
struct gpiod_chip* chip = gpiod_chip_open_by_label(label.c_str()); struct gpiod_chip* chip = gpiod_chip_open_by_label(label.c_str());
if (chip == nullptr) { if (chip == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "LinuxLibgpioIF::configureGpioByLabel: Failed to open gpio from gpio " sif::warning << "LinuxLibgpioIF::configureGpioByLabel: Failed to open gpio from gpio "
<< "group with label " << label << ". Gpio ID: " << gpioId << std::endl; << "group with label " << label << ". Gpio ID: " << gpioId << std::endl;
#endif
return RETURN_FAILED; return RETURN_FAILED;
} }
std::string failOutput = "label: " + label; std::string failOutput = "label: " + label;
@ -104,8 +112,10 @@ ReturnValue_t LinuxLibgpioIF::configureGpioByChip(gpioId_t gpioId, GpiodRegularB
std::string& chipname = gpioByChip.chipname; std::string& chipname = gpioByChip.chipname;
struct gpiod_chip* chip = gpiod_chip_open_by_name(chipname.c_str()); struct gpiod_chip* chip = gpiod_chip_open_by_name(chipname.c_str());
if (chip == nullptr) { if (chip == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "LinuxLibgpioIF::configureGpioByChip: Failed to open chip " << chipname sif::warning << "LinuxLibgpioIF::configureGpioByChip: Failed to open chip " << chipname
<< ". Gpio ID: " << gpioId << std::endl; << ". Gpio ID: " << gpioId << std::endl;
#endif
return RETURN_FAILED; return RETURN_FAILED;
} }
std::string failOutput = "chipname: " + chipname; std::string failOutput = "chipname: " + chipname;
@ -129,8 +139,10 @@ ReturnValue_t LinuxLibgpioIF::configureGpioByLineName(gpioId_t gpioId,
struct gpiod_chip* chip = gpiod_chip_open_by_name(chipname); struct gpiod_chip* chip = gpiod_chip_open_by_name(chipname);
if (chip == nullptr) { if (chip == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "LinuxLibgpioIF::configureGpioByLineName: Failed to open chip " << chipname sif::warning << "LinuxLibgpioIF::configureGpioByLineName: Failed to open chip " << chipname
<< ". <Gpio ID: " << gpioId << std::endl; << ". <Gpio ID: " << gpioId << std::endl;
#endif
return RETURN_FAILED; return RETURN_FAILED;
} }
std::string failOutput = "line name: " + lineName; std::string failOutput = "line name: " + lineName;
@ -149,10 +161,12 @@ ReturnValue_t LinuxLibgpioIF::configureRegularGpio(gpioId_t gpioId, struct gpiod
lineNum = regularGpio.lineNum; lineNum = regularGpio.lineNum;
lineHandle = gpiod_chip_get_line(chip, lineNum); lineHandle = gpiod_chip_get_line(chip, lineNum);
if (!lineHandle) { if (!lineHandle) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "LinuxLibgpioIF::configureRegularGpio: Failed to open line " << std::endl; sif::warning << "LinuxLibgpioIF::configureRegularGpio: Failed to open line " << std::endl;
sif::warning << "GPIO ID: " << gpioId << ", line number: " << lineNum << ", " << failOutput sif::warning << "GPIO ID: " << gpioId << ", line number: " << lineNum << ", " << failOutput
<< std::endl; << std::endl;
sif::warning << "Check if Linux GPIO configuration has changed. " << std::endl; sif::warning << "Check if Linux GPIO configuration has changed. " << std::endl;
#endif
gpiod_chip_close(chip); gpiod_chip_close(chip);
return RETURN_FAILED; return RETURN_FAILED;
} }
@ -171,7 +185,9 @@ ReturnValue_t LinuxLibgpioIF::configureRegularGpio(gpioId_t gpioId, struct gpiod
break; break;
} }
default: { default: {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "LinuxLibgpioIF::configureGpios: Invalid direction specified" << std::endl; sif::error << "LinuxLibgpioIF::configureGpios: Invalid direction specified" << std::endl;
#endif
return GPIO_INVALID_INSTANCE; return GPIO_INVALID_INSTANCE;
} }
@ -200,7 +216,9 @@ ReturnValue_t LinuxLibgpioIF::configureRegularGpio(gpioId_t gpioId, struct gpiod
ReturnValue_t LinuxLibgpioIF::pullHigh(gpioId_t gpioId) { ReturnValue_t LinuxLibgpioIF::pullHigh(gpioId_t gpioId) {
gpioMapIter = gpioMap.find(gpioId); gpioMapIter = gpioMap.find(gpioId);
if (gpioMapIter == gpioMap.end()) { if (gpioMapIter == gpioMap.end()) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "LinuxLibgpioIF::pullHigh: Unknown GPIO ID " << gpioId << std::endl; sif::warning << "LinuxLibgpioIF::pullHigh: Unknown GPIO ID " << gpioId << std::endl;
#endif
return UNKNOWN_GPIO_ID; return UNKNOWN_GPIO_ID;
} }

View File

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

View File

@ -0,0 +1,43 @@
#pragma once
#include "fsfw/ipc/MutexIF.h"
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
#include "fsfw_hal/common/gpio/GpioIF.h"
class ManualCsLockWrapper : public HasReturnvaluesIF {
public:
ManualCsLockWrapper(MutexIF* lock, GpioIF* gpioIF, SpiCookie* cookie,
MutexIF::TimeoutType type = MutexIF::TimeoutType::BLOCKING,
uint32_t timeoutMs = 0)
: lock(lock), gpioIF(gpioIF), cookie(cookie), type(type), timeoutMs(timeoutMs) {
if (cookie == nullptr) {
// TODO: Error? Or maybe throw exception..
return;
}
cookie->setCsLockManual(true);
lockResult = lock->lockMutex(type, timeoutMs);
if (lockResult != RETURN_OK) {
return;
}
gpioResult = gpioIF->pullLow(cookie->getChipSelectPin());
}
~ManualCsLockWrapper() {
if (gpioResult == RETURN_OK) {
gpioIF->pullHigh(cookie->getChipSelectPin());
}
cookie->setCsLockManual(false);
if (lockResult == RETURN_OK) {
lock->unlockMutex();
}
}
ReturnValue_t lockResult;
ReturnValue_t gpioResult;
private:
MutexIF* lock;
GpioIF* gpioIF;
SpiCookie* cookie;
MutexIF::TimeoutType type;
uint32_t timeoutMs = 0;
};

View File

@ -196,16 +196,22 @@ ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie* spiCookie, const
bool fullDuplex = spiCookie->isFullDuplex(); bool fullDuplex = spiCookie->isFullDuplex();
gpioId_t gpioId = spiCookie->getChipSelectPin(); gpioId_t gpioId = spiCookie->getChipSelectPin();
bool csLockManual = spiCookie->getCsLockManual();
/* Pull SPI CS low. For now, no support for active high given */ MutexIF::TimeoutType csType;
if (gpioId != gpio::NO_GPIO) { dur_millis_t csTimeout = 0;
result = spiMutex->lockMutex(timeoutType, timeoutMs); // Pull SPI CS low. For now, no support for active high given
if (gpioId != gpio::NO_GPIO and not csLockManual) {
spiCookie->getMutexParams(csType, csTimeout);
result = csMutex->lockMutex(csType, csTimeout);
if (result != RETURN_OK) { if (result != RETURN_OK) {
#if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "SpiComIF::sendMessage: Failed to lock mutex" << std::endl; sif::error << "SpiComIF::sendMessage: Failed to lock mutex with code "
<< "0x" << std::hex << std::setfill('0') << std::setw(4) << result << std::dec
<< std::endl;
#else #else
sif::printError("SpiComIF::sendMessage: Failed to lock mutex\n"); sif::printError("SpiComIF::sendMessage: Failed to lock mutex with code %d\n", result);
#endif #endif
#endif #endif
return result; return result;
@ -248,7 +254,7 @@ ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie* spiCookie, const
} }
} }
if (gpioId != gpio::NO_GPIO) { if (gpioId != gpio::NO_GPIO and not csLockManual) {
gpioComIF->pullHigh(gpioId); gpioComIF->pullHigh(gpioId);
result = spiMutex->unlockMutex(); result = spiMutex->unlockMutex();
if (result != RETURN_OK) { if (result != RETURN_OK) {
@ -292,12 +298,27 @@ ReturnValue_t SpiComIF::performHalfDuplexReception(SpiCookie* spiCookie) {
return result; return result;
} }
bool csLockManual = spiCookie->getCsLockManual();
gpioId_t gpioId = spiCookie->getChipSelectPin(); gpioId_t gpioId = spiCookie->getChipSelectPin();
<<<<<<< Updated upstream
if (gpioId != gpio::NO_GPIO) { if (gpioId != gpio::NO_GPIO) {
result = spiMutex->lockMutex(timeoutType, timeoutMs); result = spiMutex->lockMutex(timeoutType, timeoutMs);
=======
MutexIF::TimeoutType csType;
dur_millis_t csTimeout = 0;
if (gpioId != gpio::NO_GPIO and not csLockManual) {
spiCookie->getMutexParams(csType, csTimeout);
result = csMutex->lockMutex(csType, csTimeout);
>>>>>>> Stashed changes
if (result != RETURN_OK) { if (result != RETURN_OK) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "SpiComIF::getSendSuccess: Failed to lock mutex" << std::endl; sif::error << "SpiComIF::sendMessage: Failed to lock mutex with code "
<< "0x" << std::hex << std::setfill('0') << std::setw(4) << result << std::dec
<< std::endl;
#else
sif::printError("SpiComIF::sendMessage: Failed to lock mutex with code %d\n", result);
#endif
#endif #endif
return result; return result;
} }
@ -315,7 +336,7 @@ ReturnValue_t SpiComIF::performHalfDuplexReception(SpiCookie* spiCookie) {
result = HALF_DUPLEX_TRANSFER_FAILED; result = HALF_DUPLEX_TRANSFER_FAILED;
} }
if (gpioId != gpio::NO_GPIO) { if (gpioId != gpio::NO_GPIO and not csLockManual) {
gpioComIF->pullHigh(gpioId); gpioComIF->pullHigh(gpioId);
result = spiMutex->unlockMutex(); result = spiMutex->unlockMutex();
if (result != RETURN_OK) { if (result != RETURN_OK) {
@ -346,6 +367,7 @@ ReturnValue_t SpiComIF::readReceivedMessage(CookieIF* cookie, uint8_t** buffer,
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
<<<<<<< Updated upstream
MutexIF* SpiComIF::getMutex(MutexIF::TimeoutType* timeoutType, uint32_t* timeoutMs) { MutexIF* SpiComIF::getMutex(MutexIF::TimeoutType* timeoutType, uint32_t* timeoutMs) {
if (timeoutType != nullptr) { if (timeoutType != nullptr) {
*timeoutType = this->timeoutType; *timeoutType = this->timeoutType;
@ -355,6 +377,9 @@ MutexIF* SpiComIF::getMutex(MutexIF::TimeoutType* timeoutType, uint32_t* timeout
} }
return spiMutex; return spiMutex;
} }
=======
MutexIF* SpiComIF::getCsMutex() { return csMutex; }
>>>>>>> Stashed changes
void SpiComIF::performSpiWiretapping(SpiCookie* spiCookie) { void SpiComIF::performSpiWiretapping(SpiCookie* spiCookie) {
if (spiCookie == nullptr) { if (spiCookie == nullptr) {

View File

@ -22,15 +22,15 @@ class SpiCookie;
*/ */
class SpiComIF : public DeviceCommunicationIF, public SystemObject { class SpiComIF : public DeviceCommunicationIF, public SystemObject {
public: public:
static constexpr uint8_t spiRetvalId = CLASS_ID::HAL_SPI; static constexpr uint8_t CLASS_ID = CLASS_ID::HAL_SPI;
static constexpr ReturnValue_t OPENING_FILE_FAILED = static constexpr ReturnValue_t OPENING_FILE_FAILED =
HasReturnvaluesIF::makeReturnCode(spiRetvalId, 0); HasReturnvaluesIF::makeReturnCode(CLASS_ID, 0);
/* Full duplex (ioctl) transfer failure */ /* Full duplex (ioctl) transfer failure */
static constexpr ReturnValue_t FULL_DUPLEX_TRANSFER_FAILED = static constexpr ReturnValue_t FULL_DUPLEX_TRANSFER_FAILED =
HasReturnvaluesIF::makeReturnCode(spiRetvalId, 1); HasReturnvaluesIF::makeReturnCode(CLASS_ID, 1);
/* Half duplex (read/write) transfer failure */ /* Half duplex (read/write) transfer failure */
static constexpr ReturnValue_t HALF_DUPLEX_TRANSFER_FAILED = static constexpr ReturnValue_t HALF_DUPLEX_TRANSFER_FAILED =
HasReturnvaluesIF::makeReturnCode(spiRetvalId, 2); HasReturnvaluesIF::makeReturnCode(CLASS_ID, 2);
SpiComIF(object_id_t objectId, GpioIF* gpioComIF); SpiComIF(object_id_t objectId, GpioIF* gpioComIF);
@ -44,7 +44,7 @@ class SpiComIF : public DeviceCommunicationIF, public SystemObject {
* @brief This function returns the mutex which can be used to protect the spi bus when * @brief This function returns the mutex which can be used to protect the spi bus when
* the chip select must be driven from outside of the com if. * the chip select must be driven from outside of the com if.
*/ */
MutexIF* getMutex(MutexIF::TimeoutType* timeoutType = nullptr, uint32_t* timeoutMs = nullptr); MutexIF* getCsMutex();
/** /**
* Perform a regular send operation using Linux iotcl. This is public so it can be used * Perform a regular send operation using Linux iotcl. This is public so it can be used
@ -70,10 +70,13 @@ class SpiComIF : public DeviceCommunicationIF, public SystemObject {
}; };
GpioIF* gpioComIF = nullptr; GpioIF* gpioComIF = nullptr;
std::string dev = "";
/**
* Protects the chip select operations. Lock when GPIO is pulled low, unlock after it was
* pulled high
*/
MutexIF* csMutex = nullptr;
MutexIF* spiMutex = nullptr;
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING;
uint32_t timeoutMs = 20;
spi_ioc_transfer clockUpdateTransfer = {}; spi_ioc_transfer clockUpdateTransfer = {};
using SpiDeviceMap = std::unordered_map<address_t, SpiInstance>; using SpiDeviceMap = std::unordered_map<address_t, SpiInstance>;

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, SpiCookie::SpiCookie(address_t spiAddress, gpioId_t chipSelect, std::string spiDev,
const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed) const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed)
@ -107,3 +107,17 @@ void SpiCookie::getCallback(spi::send_callback_function_t* callback, void** args
*callback = this->sendCallback; *callback = this->sendCallback;
*args = this->callbackArgs; *args = this->callbackArgs;
} }
void SpiCookie::setCsLockManual(bool enable) { manualCsLock = enable; }
bool SpiCookie::getCsLockManual() const { return manualCsLock; }
void SpiCookie::getMutexParams(MutexIF::TimeoutType& csTimeoutType, dur_millis_t& csTimeout) const {
csTimeoutType = this->csTimeoutType;
csTimeout = this->csTimeout;
}
void SpiCookie::setMutexParams(MutexIF::TimeoutType csTimeoutType, dur_millis_t csTimeout) {
this->csTimeoutType = csTimeoutType;
this->csTimeout = csTimeout;
}

View File

@ -2,6 +2,8 @@
#define LINUX_SPI_SPICOOKIE_H_ #define LINUX_SPI_SPICOOKIE_H_
#include <fsfw/devicehandlers/CookieIF.h> #include <fsfw/devicehandlers/CookieIF.h>
#include <fsfw/ipc/MutexIF.h>
#include <fsfw/timemanager/clockDefinitions.h>
#include <linux/spi/spidev.h> #include <linux/spi/spidev.h>
#include "../../common/gpio/gpioDefinitions.h" #include "../../common/gpio/gpioDefinitions.h"
@ -20,6 +22,8 @@
*/ */
class SpiCookie : public CookieIF { class SpiCookie : public CookieIF {
public: public:
static constexpr dur_millis_t DEFAULT_MUTEX_TIMEOUT = 20;
/** /**
* Each SPI device will have a corresponding cookie. The cookie is used by the communication * Each SPI device will have a corresponding cookie. The cookie is used by the communication
* interface and contains device specific information like the largest expected size to be * interface and contains device specific information like the largest expected size to be
@ -139,9 +143,43 @@ class SpiCookie : public CookieIF {
*/ */
void activateCsDeselect(bool deselectCs, uint16_t delayUsecs); void activateCsDeselect(bool deselectCs, uint16_t delayUsecs);
void getMutexParams(MutexIF::TimeoutType& csTimeoutType, dur_millis_t& csTimeout) const;
void setMutexParams(MutexIF::TimeoutType csTimeoutType, dur_millis_t csTimeout);
void setCsLockManual(bool enable);
bool getCsLockManual() const;
spi_ioc_transfer* getTransferStructHandle(); spi_ioc_transfer* getTransferStructHandle();
private: private:
address_t spiAddress;
gpioId_t chipSelectPin;
std::string spiDevice;
spi::SpiComIfModes comIfMode;
// Required for regular mode
const size_t maxSize;
spi::SpiModes spiMode;
/**
* If this is set to true, the SPI ComIF will not perform any mutex locking for the
* CS mechanism. The user is responsible to locking and unlocking the mutex for the
* whole duration of the transfers.
*/
bool manualCsLock = false;
uint32_t spiSpeed;
bool halfDuplex = false;
MutexIF::TimeoutType csTimeoutType = MutexIF::TimeoutType::WAITING;
dur_millis_t csTimeout = DEFAULT_MUTEX_TIMEOUT;
// Required for callback mode
spi::send_callback_function_t sendCallback = nullptr;
void* callbackArgs = nullptr;
struct spi_ioc_transfer spiTransferStruct = {};
UncommonParameters uncommonParameters;
/** /**
* Internal constructor which initializes every field * Internal constructor which initializes every field
* @param spiAddress * @param spiAddress
@ -154,27 +192,8 @@ class SpiCookie : public CookieIF {
* @param args * @param args
*/ */
SpiCookie(spi::SpiComIfModes comIfMode, address_t spiAddress, gpioId_t chipSelect, SpiCookie(spi::SpiComIfModes comIfMode, address_t spiAddress, gpioId_t chipSelect,
std::string spiDev, const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed, const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed,
spi::send_callback_function_t callback, void* args); spi::send_callback_function_t callback, void* args);
address_t spiAddress;
gpioId_t chipSelectPin;
std::string spiDevice;
spi::SpiComIfModes comIfMode;
// Required for regular mode
const size_t maxSize;
spi::SpiModes spiMode;
uint32_t spiSpeed;
bool halfDuplex = false;
// Required for callback mode
spi::send_callback_function_t sendCallback = nullptr;
void* callbackArgs = nullptr;
struct spi_ioc_transfer spiTransferStruct = {};
UncommonParameters uncommonParameters;
}; };
#endif /* LINUX_SPI_SPICOOKIE_H_ */ #endif /* LINUX_SPI_SPICOOKIE_H_ */

View File

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

View File

@ -24,9 +24,7 @@ void UartCookie::setParityEven() { parity = Parity::EVEN; }
Parity UartCookie::getParity() const { return parity; } Parity UartCookie::getParity() const { return parity; }
void UartCookie::setBitsPerWord(BitsPerWord bitsPerWord_) { void UartCookie::setBitsPerWord(BitsPerWord bitsPerWord_) { bitsPerWord = bitsPerWord_; }
bitsPerWord = bitsPerWord_;
}
BitsPerWord UartCookie::getBitsPerWord() const { return bitsPerWord; } BitsPerWord UartCookie::getBitsPerWord() const { return bitsPerWord; }

View File

@ -1,8 +0,0 @@
#!/bin/bash
if [[ ! -f README.md ]]; then
cd ..
fi
find ./src -iname *.h -o -iname *.cpp -o -iname *.c | xargs clang-format --style=file -i
find ./hal -iname *.h -o -iname *.cpp -o -iname *.c | xargs clang-format --style=file -i
find ./tests -iname *.h -o -iname *.cpp -o -iname *.c | xargs clang-format --style=file -i

22
scripts/auto-formatter.sh Executable file
View File

@ -0,0 +1,22 @@
#!/bin/bash
if [[ ! -f README.md ]]; then
cd ..
fi
cmake_fmt="cmake-format"
if command -v ${cmake_fmt} &> /dev/null; then
cmake_fmt_cmd="${cmake_fmt} -i CMakeLists.txt"
eval ${cmake_fmt_cmd}
else
echo "No ${cmake_fmt} tool found, not formatting CMake files"
fi
cpp_format="clang-format"
file_selectors="-iname *.h -o -iname *.cpp -o -iname *.c -o -iname *.tpp"
if command -v ${cpp_format} &> /dev/null; then
find ./src ${file_selectors} | xargs clang-format --style=file -i
find ./hal ${file_selectors} | xargs clang-format --style=file -i
find ./tests ${file_selectors} | xargs clang-format --style=file -i
else
echo "No ${cpp_format} tool found, not formatting C++/C files"
fi

View File

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

View File

@ -5,11 +5,11 @@
#error Include FIFOBase.h before FIFOBase.tpp! #error Include FIFOBase.h before FIFOBase.tpp!
#endif #endif
template<typename T> template <typename T>
inline FIFOBase<T>::FIFOBase(T* values, const size_t maxCapacity): inline FIFOBase<T>::FIFOBase(T* values, const size_t maxCapacity)
maxCapacity(maxCapacity), values(values){}; : maxCapacity(maxCapacity), values(values){};
template<typename T> template <typename T>
inline ReturnValue_t FIFOBase<T>::insert(T value) { inline ReturnValue_t FIFOBase<T>::insert(T value) {
if (full()) { if (full()) {
return FULL; return FULL;
@ -21,12 +21,12 @@ inline ReturnValue_t FIFOBase<T>::insert(T value) {
} }
}; };
template<typename T> template <typename T>
inline ReturnValue_t FIFOBase<T>::retrieve(T* value) { inline ReturnValue_t FIFOBase<T>::retrieve(T* value) {
if (empty()) { if (empty()) {
return EMPTY; return EMPTY;
} else { } else {
if (value == nullptr){ if (value == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
*value = values[readIndex]; *value = values[readIndex];
@ -36,12 +36,12 @@ inline ReturnValue_t FIFOBase<T>::retrieve(T* value) {
} }
}; };
template<typename T> template <typename T>
inline ReturnValue_t FIFOBase<T>::peek(T* value) { inline ReturnValue_t FIFOBase<T>::peek(T* value) {
if(empty()) { if (empty()) {
return EMPTY; return EMPTY;
} else { } else {
if (value == nullptr){ if (value == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
*value = values[readIndex]; *value = values[readIndex];
@ -49,28 +49,28 @@ inline ReturnValue_t FIFOBase<T>::peek(T* value) {
} }
}; };
template<typename T> template <typename T>
inline ReturnValue_t FIFOBase<T>::pop() { inline ReturnValue_t FIFOBase<T>::pop() {
T value; T value;
return this->retrieve(&value); return this->retrieve(&value);
}; };
template<typename T> template <typename T>
inline bool FIFOBase<T>::empty() { inline bool FIFOBase<T>::empty() {
return (currentSize == 0); return (currentSize == 0);
}; };
template<typename T> template <typename T>
inline bool FIFOBase<T>::full() { inline bool FIFOBase<T>::full() {
return (currentSize == maxCapacity); return (currentSize == maxCapacity);
} }
template<typename T> template <typename T>
inline size_t FIFOBase<T>::size() { inline size_t FIFOBase<T>::size() {
return currentSize; return currentSize;
} }
template<typename T> template <typename T>
inline size_t FIFOBase<T>::next(size_t current) { inline size_t FIFOBase<T>::next(size_t current) {
++current; ++current;
if (current == maxCapacity) { if (current == maxCapacity) {
@ -79,14 +79,13 @@ inline size_t FIFOBase<T>::next(size_t current) {
return current; return current;
} }
template<typename T> template <typename T>
inline size_t FIFOBase<T>::getMaxCapacity() const { inline size_t FIFOBase<T>::getMaxCapacity() const {
return maxCapacity; return maxCapacity;
} }
template <typename T>
template<typename T> inline void FIFOBase<T>::setContainer(T* data) {
inline void FIFOBase<T>::setContainer(T *data) {
this->values = data; this->values = data;
} }

View File

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

View File

@ -1,15 +1,15 @@
#ifndef FRAMEWORK_CONTAINER_FIXEDORDEREDMULTIMAP_TPP_ #ifndef FRAMEWORK_CONTAINER_FIXEDORDEREDMULTIMAP_TPP_
#define FRAMEWORK_CONTAINER_FIXEDORDEREDMULTIMAP_TPP_ #define FRAMEWORK_CONTAINER_FIXEDORDEREDMULTIMAP_TPP_
template <typename key_t, typename T, typename KEY_COMPARE>
template<typename key_t, typename T, typename KEY_COMPARE> inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::insert(key_t key, T value,
inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::insert(key_t key, T value, Iterator *storedValue) { Iterator *storedValue) {
if (_size == theMap.maxSize()) { if (_size == theMap.maxSize()) {
return MAP_FULL; return MAP_FULL;
} }
size_t position = findNicePlace(key); size_t position = findNicePlace(key);
memmove(static_cast<void*>(&theMap[position + 1]),static_cast<void*>(&theMap[position]), memmove(static_cast<void *>(&theMap[position + 1]), static_cast<void *>(&theMap[position]),
(_size - position) * sizeof(std::pair<key_t,T>)); (_size - position) * sizeof(std::pair<key_t, T>));
theMap[position].first = key; theMap[position].first = key;
theMap[position].second = value; theMap[position].second = value;
++_size; ++_size;
@ -18,12 +18,12 @@ inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::insert(key_t k
} }
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
template<typename key_t, typename T, typename KEY_COMPARE> template <typename key_t, typename T, typename KEY_COMPARE>
inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::insert(std::pair<key_t, T> pair) { inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::insert(std::pair<key_t, T> pair) {
return insert(pair.first, pair.second); return insert(pair.first, pair.second);
} }
template<typename key_t, typename T, typename KEY_COMPARE> template <typename key_t, typename T, typename KEY_COMPARE>
inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::exists(key_t key) const { inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::exists(key_t key) const {
ReturnValue_t result = KEY_DOES_NOT_EXIST; ReturnValue_t result = KEY_DOES_NOT_EXIST;
if (findFirstIndex(key) < _size) { if (findFirstIndex(key) < _size) {
@ -32,7 +32,7 @@ inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::exists(key_t k
return result; return result;
} }
template<typename key_t, typename T, typename KEY_COMPARE> template <typename key_t, typename T, typename KEY_COMPARE>
inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::erase(Iterator *iter) { inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::erase(Iterator *iter) {
size_t i; size_t i;
if ((i = findFirstIndex((*iter).value->first)) >= _size) { if ((i = findFirstIndex((*iter).value->first)) >= _size) {
@ -47,7 +47,7 @@ inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::erase(Iterator
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
template<typename key_t, typename T, typename KEY_COMPARE> template <typename key_t, typename T, typename KEY_COMPARE>
inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::erase(key_t key) { inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::erase(key_t key) {
size_t i; size_t i;
if ((i = findFirstIndex(key)) >= _size) { if ((i = findFirstIndex(key)) >= _size) {
@ -60,7 +60,7 @@ inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::erase(key_t ke
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
template<typename key_t, typename T, typename KEY_COMPARE> template <typename key_t, typename T, typename KEY_COMPARE>
inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::find(key_t key, T **value) const { inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::find(key_t key, T **value) const {
ReturnValue_t result = exists(key); ReturnValue_t result = exists(key);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
@ -70,8 +70,9 @@ inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::find(key_t key
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
template<typename key_t, typename T, typename KEY_COMPARE> template <typename key_t, typename T, typename KEY_COMPARE>
inline size_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::findFirstIndex(key_t key, size_t startAt) const { inline size_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::findFirstIndex(key_t key,
size_t startAt) const {
if (startAt >= _size) { if (startAt >= _size) {
return startAt + 1; return startAt + 1;
} }
@ -84,7 +85,7 @@ inline size_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::findFirstIndex(key_t
return i; return i;
} }
template<typename key_t, typename T, typename KEY_COMPARE> template <typename key_t, typename T, typename KEY_COMPARE>
inline size_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::findNicePlace(key_t key) const { inline size_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::findNicePlace(key_t key) const {
size_t i = 0; size_t i = 0;
for (i = 0; i < _size; ++i) { for (i = 0; i < _size; ++i) {
@ -95,15 +96,14 @@ inline size_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::findNicePlace(key_t k
return i; return i;
} }
template<typename key_t, typename T, typename KEY_COMPARE> template <typename key_t, typename T, typename KEY_COMPARE>
inline void FixedOrderedMultimap<key_t, T, KEY_COMPARE>::removeFromPosition(size_t position) { inline void FixedOrderedMultimap<key_t, T, KEY_COMPARE>::removeFromPosition(size_t position) {
if (_size <= position) { if (_size <= position) {
return; return;
} }
memmove(static_cast<void*>(&theMap[position]), static_cast<void*>(&theMap[position + 1]), memmove(static_cast<void *>(&theMap[position]), static_cast<void *>(&theMap[position + 1]),
(_size - position - 1) * sizeof(std::pair<key_t,T>)); (_size - position - 1) * sizeof(std::pair<key_t, T>));
--_size; --_size;
} }
#endif /* FRAMEWORK_CONTAINER_FIXEDORDEREDMULTIMAP_TPP_ */ #endif /* FRAMEWORK_CONTAINER_FIXEDORDEREDMULTIMAP_TPP_ */

View File

@ -10,16 +10,23 @@ class HybridIterator : public LinkedElement<T>::Iterator, public ArrayList<T, co
HybridIterator() {} HybridIterator() {}
HybridIterator(typename LinkedElement<T>::Iterator *iter) HybridIterator(typename LinkedElement<T>::Iterator *iter)
: LinkedElement<T>::Iterator(*iter), value(iter->value), linked(true) {} : LinkedElement<T>::Iterator(*iter), linked(true) {
if (iter != nullptr) {
value = iter->value;
}
}
HybridIterator(LinkedElement<T> *start) HybridIterator(LinkedElement<T> *start) : LinkedElement<T>::Iterator(start), linked(true) {
: LinkedElement<T>::Iterator(start), value(start->value), linked(true) {} if (start != nullptr) {
value = start->value;
}
}
HybridIterator(typename ArrayList<T, count_t>::Iterator start, HybridIterator(typename ArrayList<T, count_t>::Iterator start,
typename ArrayList<T, count_t>::Iterator end) typename ArrayList<T, count_t>::Iterator end)
: ArrayList<T, count_t>::Iterator(start), value(start.value), linked(false), end(end.value) { : ArrayList<T, count_t>::Iterator(start), value(start.value), linked(false), end(end.value) {
if (value == this->end) { if (value == this->end) {
value = NULL; value = nullptr;
} }
} }

View File

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

View File

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

View File

@ -787,7 +787,7 @@ ReturnValue_t LocalDataPoolManager::generateSetStructurePacket(sid_t sid, bool i
// Serialize set packet into store. // Serialize set packet into store.
size_t size = 0; size_t size = 0;
result = setPacket.serialize(&storePtr, &size, expectedSize, SerializeIF::Endianness::BIG); result = setPacket.serialize(&storePtr, &size, expectedSize, SerializeIF::Endianness::BIG);
if(result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
ipcStore->deleteData(storeId); ipcStore->deleteData(storeId);
return result; return result;
} }
@ -806,7 +806,7 @@ ReturnValue_t LocalDataPoolManager::generateSetStructurePacket(sid_t sid, bool i
} }
result = hkQueue->reply(&reply); result = hkQueue->reply(&reply);
if(result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
ipcStore->deleteData(storeId); ipcStore->deleteData(storeId);
} }
return result; return result;

View File

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

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, LocalPoolObjectBase(object_id_t poolOwner, lp_id_t poolId, DataSetIF* dataSet = nullptr,
pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE); pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE);
void setReadWriteMode(pool_rwm_t newReadWriteMode); void setReadWriteMode(pool_rwm_t newReadWriteMode) override;
pool_rwm_t getReadWriteMode() const; pool_rwm_t getReadWriteMode() const override;
bool isValid() const override; bool isValid() const override;
void setValid(bool valid) override; void setValid(bool valid) override;

View File

@ -5,33 +5,31 @@
#error Include LocalPoolVariable.h before LocalPoolVariable.tpp! #error Include LocalPoolVariable.h before LocalPoolVariable.tpp!
#endif #endif
template<typename T> template <typename T>
inline LocalPoolVariable<T>::LocalPoolVariable(HasLocalDataPoolIF* hkOwner, inline LocalPoolVariable<T>::LocalPoolVariable(HasLocalDataPoolIF* hkOwner, lp_id_t poolId,
lp_id_t poolId, DataSetIF* dataSet, pool_rwm_t setReadWriteMode): DataSetIF* dataSet, pool_rwm_t setReadWriteMode)
LocalPoolObjectBase(poolId, hkOwner, dataSet, setReadWriteMode) {} : LocalPoolObjectBase(poolId, hkOwner, dataSet, setReadWriteMode) {}
template<typename T> template <typename T>
inline LocalPoolVariable<T>::LocalPoolVariable(object_id_t poolOwner, inline LocalPoolVariable<T>::LocalPoolVariable(object_id_t poolOwner, lp_id_t poolId,
lp_id_t poolId, DataSetIF *dataSet, pool_rwm_t setReadWriteMode): DataSetIF* dataSet, pool_rwm_t setReadWriteMode)
LocalPoolObjectBase(poolOwner, poolId, dataSet, setReadWriteMode) {} : LocalPoolObjectBase(poolOwner, poolId, dataSet, setReadWriteMode) {}
template <typename T>
inline LocalPoolVariable<T>::LocalPoolVariable(gp_id_t globalPoolId, DataSetIF* dataSet,
pool_rwm_t setReadWriteMode)
: LocalPoolObjectBase(globalPoolId.objectId, globalPoolId.localPoolId, dataSet,
setReadWriteMode) {}
template<typename T> template <typename T>
inline LocalPoolVariable<T>::LocalPoolVariable(gp_id_t globalPoolId, inline ReturnValue_t LocalPoolVariable<T>::read(MutexIF::TimeoutType timeoutType,
DataSetIF *dataSet, pool_rwm_t setReadWriteMode): uint32_t timeoutMs) {
LocalPoolObjectBase(globalPoolId.objectId, globalPoolId.localPoolId, if (hkManager == nullptr) {
dataSet, setReadWriteMode){}
template<typename T>
inline ReturnValue_t LocalPoolVariable<T>::read(
MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) {
if(hkManager == nullptr) {
return readWithoutLock(); return readWithoutLock();
} }
MutexIF* mutex = LocalDpManagerAttorney::getMutexHandle(*hkManager); MutexIF* mutex = LocalDpManagerAttorney::getMutexHandle(*hkManager);
ReturnValue_t result = mutex->lockMutex(timeoutType, timeoutMs); ReturnValue_t result = mutex->lockMutex(timeoutType, timeoutMs);
if(result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
return result; return result;
} }
result = readWithoutLock(); result = readWithoutLock();
@ -39,23 +37,21 @@ inline ReturnValue_t LocalPoolVariable<T>::read(
return result; return result;
} }
template<typename T> template <typename T>
inline ReturnValue_t LocalPoolVariable<T>::readWithoutLock() { inline ReturnValue_t LocalPoolVariable<T>::readWithoutLock() {
if(readWriteMode == pool_rwm_t::VAR_WRITE) { if (readWriteMode == pool_rwm_t::VAR_WRITE) {
object_id_t targetObjectId = hkManager->getCreatorObjectId(); object_id_t targetObjectId = hkManager->getCreatorObjectId();
reportReadCommitError("LocalPoolVector", reportReadCommitError("LocalPoolVector", PoolVariableIF::INVALID_READ_WRITE_MODE, true,
PoolVariableIF::INVALID_READ_WRITE_MODE, true, targetObjectId, targetObjectId, localPoolId);
localPoolId);
return PoolVariableIF::INVALID_READ_WRITE_MODE; return PoolVariableIF::INVALID_READ_WRITE_MODE;
} }
PoolEntry<T>* poolEntry = nullptr; PoolEntry<T>* poolEntry = nullptr;
ReturnValue_t result = LocalDpManagerAttorney::fetchPoolEntry(*hkManager, localPoolId, ReturnValue_t result =
&poolEntry); LocalDpManagerAttorney::fetchPoolEntry(*hkManager, localPoolId, &poolEntry);
if(result != RETURN_OK) { if (result != RETURN_OK) {
object_id_t ownerObjectId = hkManager->getCreatorObjectId(); object_id_t ownerObjectId = hkManager->getCreatorObjectId();
reportReadCommitError("LocalPoolVariable", result, reportReadCommitError("LocalPoolVariable", result, false, ownerObjectId, localPoolId);
false, ownerObjectId, localPoolId);
return result; return result;
} }
@ -64,22 +60,22 @@ inline ReturnValue_t LocalPoolVariable<T>::readWithoutLock() {
return RETURN_OK; return RETURN_OK;
} }
template<typename T> template <typename T>
inline ReturnValue_t LocalPoolVariable<T>::commit(bool setValid, inline ReturnValue_t LocalPoolVariable<T>::commit(bool setValid, MutexIF::TimeoutType timeoutType,
MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) { uint32_t timeoutMs) {
this->setValid(setValid); this->setValid(setValid);
return commit(timeoutType, timeoutMs); return commit(timeoutType, timeoutMs);
} }
template<typename T> template <typename T>
inline ReturnValue_t LocalPoolVariable<T>::commit( inline ReturnValue_t LocalPoolVariable<T>::commit(MutexIF::TimeoutType timeoutType,
MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) { uint32_t timeoutMs) {
if(hkManager == nullptr) { if (hkManager == nullptr) {
return commitWithoutLock(); return commitWithoutLock();
} }
MutexIF* mutex = LocalDpManagerAttorney::getMutexHandle(*hkManager); MutexIF* mutex = LocalDpManagerAttorney::getMutexHandle(*hkManager);
ReturnValue_t result = mutex->lockMutex(timeoutType, timeoutMs); ReturnValue_t result = mutex->lockMutex(timeoutType, timeoutMs);
if(result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
return result; return result;
} }
result = commitWithoutLock(); result = commitWithoutLock();
@ -87,23 +83,21 @@ inline ReturnValue_t LocalPoolVariable<T>::commit(
return result; return result;
} }
template<typename T> template <typename T>
inline ReturnValue_t LocalPoolVariable<T>::commitWithoutLock() { inline ReturnValue_t LocalPoolVariable<T>::commitWithoutLock() {
if(readWriteMode == pool_rwm_t::VAR_READ) { if (readWriteMode == pool_rwm_t::VAR_READ) {
object_id_t targetObjectId = hkManager->getCreatorObjectId(); object_id_t targetObjectId = hkManager->getCreatorObjectId();
reportReadCommitError("LocalPoolVector", reportReadCommitError("LocalPoolVector", PoolVariableIF::INVALID_READ_WRITE_MODE, false,
PoolVariableIF::INVALID_READ_WRITE_MODE, false, targetObjectId, targetObjectId, localPoolId);
localPoolId);
return PoolVariableIF::INVALID_READ_WRITE_MODE; return PoolVariableIF::INVALID_READ_WRITE_MODE;
} }
PoolEntry<T>* poolEntry = nullptr; PoolEntry<T>* poolEntry = nullptr;
ReturnValue_t result = LocalDpManagerAttorney::fetchPoolEntry(*hkManager, localPoolId, ReturnValue_t result =
&poolEntry); LocalDpManagerAttorney::fetchPoolEntry(*hkManager, localPoolId, &poolEntry);
if(result != RETURN_OK) { if (result != RETURN_OK) {
object_id_t ownerObjectId = hkManager->getCreatorObjectId(); object_id_t ownerObjectId = hkManager->getCreatorObjectId();
reportReadCommitError("LocalPoolVariable", result, reportReadCommitError("LocalPoolVariable", result, false, ownerObjectId, localPoolId);
false, ownerObjectId, localPoolId);
return result; return result;
} }
@ -112,98 +106,88 @@ inline ReturnValue_t LocalPoolVariable<T>::commitWithoutLock() {
return RETURN_OK; return RETURN_OK;
} }
template<typename T> template <typename T>
inline ReturnValue_t LocalPoolVariable<T>::serialize(uint8_t** buffer, inline ReturnValue_t LocalPoolVariable<T>::serialize(
size_t* size, const size_t max_size, uint8_t** buffer, size_t* size, const size_t max_size,
SerializeIF::Endianness streamEndianness) const { SerializeIF::Endianness streamEndianness) const {
return SerializeAdapter::serialize(&value, return SerializeAdapter::serialize(&value, buffer, size, max_size, streamEndianness);
buffer, size ,max_size, streamEndianness);
} }
template<typename T> template <typename T>
inline size_t LocalPoolVariable<T>::getSerializedSize() const { inline size_t LocalPoolVariable<T>::getSerializedSize() const {
return SerializeAdapter::getSerializedSize(&value); return SerializeAdapter::getSerializedSize(&value);
} }
template<typename T> template <typename T>
inline ReturnValue_t LocalPoolVariable<T>::deSerialize(const uint8_t** buffer, inline ReturnValue_t LocalPoolVariable<T>::deSerialize(const uint8_t** buffer, size_t* size,
size_t* size, SerializeIF::Endianness streamEndianness) { SerializeIF::Endianness streamEndianness) {
return SerializeAdapter::deSerialize(&value, buffer, size, streamEndianness); return SerializeAdapter::deSerialize(&value, buffer, size, streamEndianness);
} }
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
template<typename T> template <typename T>
inline std::ostream& operator<< (std::ostream &out, inline std::ostream& operator<<(std::ostream& out, const LocalPoolVariable<T>& var) {
const LocalPoolVariable<T> &var) {
out << var.value; out << var.value;
return out; return out;
} }
#endif #endif
template<typename T> template <typename T>
inline LocalPoolVariable<T>::operator T() const { inline LocalPoolVariable<T>::operator T() const {
return value; return value;
} }
template<typename T> template <typename T>
inline LocalPoolVariable<T> & LocalPoolVariable<T>::operator=( inline LocalPoolVariable<T>& LocalPoolVariable<T>::operator=(const T& newValue) {
const T& newValue) {
value = newValue; value = newValue;
return *this; return *this;
} }
template<typename T> template <typename T>
inline LocalPoolVariable<T>& LocalPoolVariable<T>::operator =( inline LocalPoolVariable<T>& LocalPoolVariable<T>::operator=(
const LocalPoolVariable<T>& newPoolVariable) { const LocalPoolVariable<T>& newPoolVariable) {
value = newPoolVariable.value; value = newPoolVariable.value;
return *this; return *this;
} }
template<typename T> template <typename T>
inline bool LocalPoolVariable<T>::operator ==( inline bool LocalPoolVariable<T>::operator==(const LocalPoolVariable<T>& other) const {
const LocalPoolVariable<T> &other) const {
return this->value == other.value; return this->value == other.value;
} }
template<typename T> template <typename T>
inline bool LocalPoolVariable<T>::operator ==(const T &other) const { inline bool LocalPoolVariable<T>::operator==(const T& other) const {
return this->value == other; return this->value == other;
} }
template <typename T>
template<typename T> inline bool LocalPoolVariable<T>::operator!=(const LocalPoolVariable<T>& other) const {
inline bool LocalPoolVariable<T>::operator !=( return not(*this == other);
const LocalPoolVariable<T> &other) const {
return not (*this == other);
} }
template<typename T> template <typename T>
inline bool LocalPoolVariable<T>::operator !=(const T &other) const { inline bool LocalPoolVariable<T>::operator!=(const T& other) const {
return not (*this == other); return not(*this == other);
} }
template <typename T>
template<typename T> inline bool LocalPoolVariable<T>::operator<(const LocalPoolVariable<T>& other) const {
inline bool LocalPoolVariable<T>::operator <(
const LocalPoolVariable<T> &other) const {
return this->value < other.value; return this->value < other.value;
} }
template<typename T> template <typename T>
inline bool LocalPoolVariable<T>::operator <(const T &other) const { inline bool LocalPoolVariable<T>::operator<(const T& other) const {
return this->value < other; return this->value < other;
} }
template <typename T>
template<typename T> inline bool LocalPoolVariable<T>::operator>(const LocalPoolVariable<T>& other) const {
inline bool LocalPoolVariable<T>::operator >( return not(*this < other);
const LocalPoolVariable<T> &other) const {
return not (*this < other);
} }
template<typename T> template <typename T>
inline bool LocalPoolVariable<T>::operator >(const T &other) const { inline bool LocalPoolVariable<T>::operator>(const T& other) const {
return not (*this < other); return not(*this < other);
} }
#endif /* FSFW_DATAPOOLLOCAL_LOCALPOOLVARIABLE_TPP_ */ #endif /* FSFW_DATAPOOLLOCAL_LOCALPOOLVARIABLE_TPP_ */

View File

@ -5,48 +5,47 @@
#error Include LocalPoolVector.h before LocalPoolVector.tpp! #error Include LocalPoolVector.h before LocalPoolVector.tpp!
#endif #endif
template<typename T, uint16_t vectorSize> template <typename T, uint16_t vectorSize>
inline LocalPoolVector<T, vectorSize>::LocalPoolVector( inline LocalPoolVector<T, vectorSize>::LocalPoolVector(HasLocalDataPoolIF* hkOwner, lp_id_t poolId,
HasLocalDataPoolIF* hkOwner, lp_id_t poolId, DataSetIF* dataSet, DataSetIF* dataSet,
pool_rwm_t setReadWriteMode): pool_rwm_t setReadWriteMode)
LocalPoolObjectBase(poolId, hkOwner, dataSet, setReadWriteMode) {} : LocalPoolObjectBase(poolId, hkOwner, dataSet, setReadWriteMode) {}
template<typename T, uint16_t vectorSize> template <typename T, uint16_t vectorSize>
inline LocalPoolVector<T, vectorSize>::LocalPoolVector(object_id_t poolOwner, inline LocalPoolVector<T, vectorSize>::LocalPoolVector(object_id_t poolOwner, lp_id_t poolId,
lp_id_t poolId, DataSetIF *dataSet, pool_rwm_t setReadWriteMode): DataSetIF* dataSet,
LocalPoolObjectBase(poolOwner, poolId, dataSet, setReadWriteMode) {} pool_rwm_t setReadWriteMode)
: LocalPoolObjectBase(poolOwner, poolId, dataSet, setReadWriteMode) {}
template<typename T, uint16_t vectorSize> template <typename T, uint16_t vectorSize>
inline LocalPoolVector<T, vectorSize>::LocalPoolVector(gp_id_t globalPoolId, inline LocalPoolVector<T, vectorSize>::LocalPoolVector(gp_id_t globalPoolId, DataSetIF* dataSet,
DataSetIF *dataSet, pool_rwm_t setReadWriteMode): pool_rwm_t setReadWriteMode)
LocalPoolObjectBase(globalPoolId.objectId, globalPoolId.localPoolId, : LocalPoolObjectBase(globalPoolId.objectId, globalPoolId.localPoolId, dataSet,
dataSet, setReadWriteMode) {} setReadWriteMode) {}
template<typename T, uint16_t vectorSize> template <typename T, uint16_t vectorSize>
inline ReturnValue_t LocalPoolVector<T, vectorSize>::read( inline ReturnValue_t LocalPoolVector<T, vectorSize>::read(MutexIF::TimeoutType timeoutType,
MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) { uint32_t timeoutMs) {
MutexGuard(LocalDpManagerAttorney::getMutexHandle(*hkManager), timeoutType, timeoutMs); MutexGuard(LocalDpManagerAttorney::getMutexHandle(*hkManager), timeoutType, timeoutMs);
return readWithoutLock(); return readWithoutLock();
} }
template<typename T, uint16_t vectorSize> template <typename T, uint16_t vectorSize>
inline ReturnValue_t LocalPoolVector<T, vectorSize>::readWithoutLock() { inline ReturnValue_t LocalPoolVector<T, vectorSize>::readWithoutLock() {
if(readWriteMode == pool_rwm_t::VAR_WRITE) { if (readWriteMode == pool_rwm_t::VAR_WRITE) {
object_id_t targetObjectId = hkManager->getCreatorObjectId(); object_id_t targetObjectId = hkManager->getCreatorObjectId();
reportReadCommitError("LocalPoolVector", reportReadCommitError("LocalPoolVector", PoolVariableIF::INVALID_READ_WRITE_MODE, true,
PoolVariableIF::INVALID_READ_WRITE_MODE, true, targetObjectId, targetObjectId, localPoolId);
localPoolId);
return PoolVariableIF::INVALID_READ_WRITE_MODE; return PoolVariableIF::INVALID_READ_WRITE_MODE;
} }
PoolEntry<T>* poolEntry = nullptr; PoolEntry<T>* poolEntry = nullptr;
ReturnValue_t result = LocalDpManagerAttorney::fetchPoolEntry(*hkManager, localPoolId, ReturnValue_t result =
&poolEntry); LocalDpManagerAttorney::fetchPoolEntry(*hkManager, localPoolId, &poolEntry);
memset(this->value, 0, vectorSize * sizeof(T)); memset(this->value, 0, vectorSize * sizeof(T));
if(result != RETURN_OK) { if (result != RETURN_OK) {
object_id_t targetObjectId = hkManager->getCreatorObjectId(); object_id_t targetObjectId = hkManager->getCreatorObjectId();
reportReadCommitError("LocalPoolVector", result, true, targetObjectId, reportReadCommitError("LocalPoolVector", result, true, targetObjectId, localPoolId);
localPoolId);
return result; return result;
} }
std::memcpy(this->value, poolEntry->getDataPtr(), poolEntry->getByteSize()); std::memcpy(this->value, poolEntry->getDataPtr(), poolEntry->getByteSize());
@ -54,36 +53,35 @@ inline ReturnValue_t LocalPoolVector<T, vectorSize>::readWithoutLock() {
return RETURN_OK; return RETURN_OK;
} }
template<typename T, uint16_t vectorSize> template <typename T, uint16_t vectorSize>
inline ReturnValue_t LocalPoolVector<T, vectorSize>::commit(bool valid, inline ReturnValue_t LocalPoolVector<T, vectorSize>::commit(bool valid,
MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) { MutexIF::TimeoutType timeoutType,
uint32_t timeoutMs) {
this->setValid(valid); this->setValid(valid);
return commit(timeoutType, timeoutMs); return commit(timeoutType, timeoutMs);
} }
template<typename T, uint16_t vectorSize> template <typename T, uint16_t vectorSize>
inline ReturnValue_t LocalPoolVector<T, vectorSize>::commit( inline ReturnValue_t LocalPoolVector<T, vectorSize>::commit(MutexIF::TimeoutType timeoutType,
MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) { uint32_t timeoutMs) {
MutexGuard(LocalDpManagerAttorney::getMutexHandle(*hkManager), timeoutType, timeoutMs); MutexGuard(LocalDpManagerAttorney::getMutexHandle(*hkManager), timeoutType, timeoutMs);
return commitWithoutLock(); return commitWithoutLock();
} }
template<typename T, uint16_t vectorSize> template <typename T, uint16_t vectorSize>
inline ReturnValue_t LocalPoolVector<T, vectorSize>::commitWithoutLock() { inline ReturnValue_t LocalPoolVector<T, vectorSize>::commitWithoutLock() {
if(readWriteMode == pool_rwm_t::VAR_READ) { if (readWriteMode == pool_rwm_t::VAR_READ) {
object_id_t targetObjectId = hkManager->getCreatorObjectId(); object_id_t targetObjectId = hkManager->getCreatorObjectId();
reportReadCommitError("LocalPoolVector", reportReadCommitError("LocalPoolVector", PoolVariableIF::INVALID_READ_WRITE_MODE, false,
PoolVariableIF::INVALID_READ_WRITE_MODE, false, targetObjectId, targetObjectId, localPoolId);
localPoolId);
return PoolVariableIF::INVALID_READ_WRITE_MODE; return PoolVariableIF::INVALID_READ_WRITE_MODE;
} }
PoolEntry<T>* poolEntry = nullptr; PoolEntry<T>* poolEntry = nullptr;
ReturnValue_t result = LocalDpManagerAttorney::fetchPoolEntry(*hkManager, localPoolId, ReturnValue_t result =
&poolEntry); LocalDpManagerAttorney::fetchPoolEntry(*hkManager, localPoolId, &poolEntry);
if(result != RETURN_OK) { if (result != RETURN_OK) {
object_id_t targetObjectId = hkManager->getCreatorObjectId(); object_id_t targetObjectId = hkManager->getCreatorObjectId();
reportReadCommitError("LocalPoolVector", result, false, targetObjectId, reportReadCommitError("LocalPoolVector", result, false, targetObjectId, localPoolId);
localPoolId);
return result; return result;
} }
std::memcpy(poolEntry->getDataPtr(), this->value, poolEntry->getByteSize()); std::memcpy(poolEntry->getDataPtr(), this->value, poolEntry->getByteSize());
@ -91,48 +89,51 @@ inline ReturnValue_t LocalPoolVector<T, vectorSize>::commitWithoutLock() {
return RETURN_OK; return RETURN_OK;
} }
template<typename T, uint16_t vectorSize> template <typename T, uint16_t vectorSize>
inline T& LocalPoolVector<T, vectorSize>::operator [](size_t i) { inline T& LocalPoolVector<T, vectorSize>::operator[](size_t i) {
if(i < vectorSize) { if (i < vectorSize) {
return value[i]; return value[i];
} }
// If this happens, I have to set some value. I consider this // If this happens, I have to set some value. I consider this
// a configuration error, but I wont exit here. // a configuration error, but I wont exit here.
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "LocalPoolVector: Invalid index. Setting or returning" sif::warning << "LocalPoolVector: Invalid index. Setting or returning"
" last value!" << std::endl; " last value!"
<< std::endl;
#else #else
sif::printWarning("LocalPoolVector: Invalid index. Setting or returning" sif::printWarning(
"LocalPoolVector: Invalid index. Setting or returning"
" last value!\n"); " last value!\n");
#endif #endif
return value[vectorSize - 1]; return value[vectorSize - 1];
} }
template<typename T, uint16_t vectorSize> template <typename T, uint16_t vectorSize>
inline const T& LocalPoolVector<T, vectorSize>::operator [](size_t i) const { inline const T& LocalPoolVector<T, vectorSize>::operator[](size_t i) const {
if(i < vectorSize) { if (i < vectorSize) {
return value[i]; return value[i];
} }
// If this happens, I have to set some value. I consider this // If this happens, I have to set some value. I consider this
// a configuration error, but I wont exit here. // a configuration error, but I wont exit here.
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "LocalPoolVector: Invalid index. Setting or returning" sif::warning << "LocalPoolVector: Invalid index. Setting or returning"
" last value!" << std::endl; " last value!"
<< std::endl;
#else #else
sif::printWarning("LocalPoolVector: Invalid index. Setting or returning" sif::printWarning(
"LocalPoolVector: Invalid index. Setting or returning"
" last value!\n"); " last value!\n");
#endif #endif
return value[vectorSize - 1]; return value[vectorSize - 1];
} }
template<typename T, uint16_t vectorSize> template <typename T, uint16_t vectorSize>
inline ReturnValue_t LocalPoolVector<T, vectorSize>::serialize(uint8_t** buffer, inline ReturnValue_t LocalPoolVector<T, vectorSize>::serialize(
size_t* size, size_t maxSize, uint8_t** buffer, size_t* size, size_t maxSize,
SerializeIF::Endianness streamEndianness) const { SerializeIF::Endianness streamEndianness) const {
ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED;
for (uint16_t i = 0; i < vectorSize; i++) { for (uint16_t i = 0; i < vectorSize; i++) {
result = SerializeAdapter::serialize(&(value[i]), buffer, size, result = SerializeAdapter::serialize(&(value[i]), buffer, size, maxSize, streamEndianness);
maxSize, streamEndianness);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
break; break;
} }
@ -140,19 +141,17 @@ inline ReturnValue_t LocalPoolVector<T, vectorSize>::serialize(uint8_t** buffer,
return result; return result;
} }
template<typename T, uint16_t vectorSize> template <typename T, uint16_t vectorSize>
inline size_t LocalPoolVector<T, vectorSize>::getSerializedSize() const { inline size_t LocalPoolVector<T, vectorSize>::getSerializedSize() const {
return vectorSize * SerializeAdapter::getSerializedSize(value); return vectorSize * SerializeAdapter::getSerializedSize(value);
} }
template<typename T, uint16_t vectorSize> template <typename T, uint16_t vectorSize>
inline ReturnValue_t LocalPoolVector<T, vectorSize>::deSerialize( inline ReturnValue_t LocalPoolVector<T, vectorSize>::deSerialize(
const uint8_t** buffer, size_t* size, const uint8_t** buffer, size_t* size, SerializeIF::Endianness streamEndianness) {
SerializeIF::Endianness streamEndianness) {
ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED;
for (uint16_t i = 0; i < vectorSize; i++) { for (uint16_t i = 0; i < vectorSize; i++) {
result = SerializeAdapter::deSerialize(&(value[i]), buffer, size, result = SerializeAdapter::deSerialize(&(value[i]), buffer, size, streamEndianness);
streamEndianness);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
break; break;
} }
@ -161,13 +160,12 @@ inline ReturnValue_t LocalPoolVector<T, vectorSize>::deSerialize(
} }
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
template<typename T, uint16_t vectorSize> template <typename T, uint16_t vectorSize>
inline std::ostream& operator<< (std::ostream &out, inline std::ostream& operator<<(std::ostream& out, const LocalPoolVector<T, vectorSize>& var) {
const LocalPoolVector<T, vectorSize> &var) {
out << "Vector: ["; out << "Vector: [";
for(int i = 0;i < vectorSize; i++) { for (int i = 0; i < vectorSize; i++) {
out << var.value[i]; out << var.value[i];
if(i < vectorSize - 1) { if (i < vectorSize - 1) {
out << ", "; out << ", ";
} }
} }

View File

@ -459,8 +459,7 @@ size_t DeviceHandlerBase::getNextReplyLength(DeviceCommandId_t commandId) {
DeviceCommandMap::iterator command = cookieInfo.pendingCommand; DeviceCommandMap::iterator command = cookieInfo.pendingCommand;
if (command->second.useAlternativeReplyId) { if (command->second.useAlternativeReplyId) {
replyId = command->second.alternativeReplyId; replyId = command->second.alternativeReplyId;
} } else {
else {
replyId = commandId; replyId = commandId;
} }
DeviceReplyIter iter = deviceReplyMap.find(replyId); DeviceReplyIter iter = deviceReplyMap.find(replyId);

View File

@ -163,7 +163,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
* @param counter Specifies which Action to perform * @param counter Specifies which Action to perform
* @return RETURN_OK for successful execution * @return RETURN_OK for successful execution
*/ */
virtual ReturnValue_t performOperation(uint8_t counter); virtual ReturnValue_t performOperation(uint8_t counter) override;
/** /**
* @brief Initializes the device handler * @brief Initializes the device handler
@ -173,7 +173,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
* Calls fillCommandAndReplyMap(). * Calls fillCommandAndReplyMap().
* @return * @return
*/ */
virtual ReturnValue_t initialize(); virtual ReturnValue_t initialize() override;
/** /**
* @brief Intialization steps performed after all tasks have been created. * @brief Intialization steps performed after all tasks have been created.
@ -1058,11 +1058,12 @@ class DeviceHandlerBase : public DeviceHandlerIF,
* @param parameter1 Optional parameter 1 * @param parameter1 Optional parameter 1
* @param parameter2 Optional parameter 2 * @param parameter2 Optional parameter 2
*/ */
void triggerEvent(Event event, uint32_t parameter1 = 0, uint32_t parameter2 = 0); void triggerEvent(Event event, uint32_t parameter1 = 0, uint32_t parameter2 = 0) override;
/** /**
* Same as triggerEvent, but for forwarding if object is used as proxy. * Same as triggerEvent, but for forwarding if object is used as proxy.
*/ */
virtual void forwardEvent(Event event, uint32_t parameter1 = 0, uint32_t parameter2 = 0) const; virtual void forwardEvent(Event event, uint32_t parameter1 = 0,
uint32_t parameter2 = 0) const override;
/** /**
* Checks if current mode is transitional mode. * Checks if current mode is transitional mode.

View File

@ -25,7 +25,7 @@ class MatchTree : public SerializeableMatcherIF<T>, public BinaryTree<Serializea
: BinaryTree<SerializeableMatcherIF<T>>(root.element), maxDepth(maxDepth) {} : BinaryTree<SerializeableMatcherIF<T>>(root.element), maxDepth(maxDepth) {}
MatchTree() : BinaryTree<SerializeableMatcherIF<T>>(), maxDepth(-1) {} MatchTree() : BinaryTree<SerializeableMatcherIF<T>>(), maxDepth(-1) {}
virtual ~MatchTree() {} virtual ~MatchTree() {}
virtual bool match(T number) { return matchesTree(number); } virtual bool match(T number) override { return matchesTree(number); }
bool matchesTree(T number) { bool matchesTree(T number) {
iterator iter = this->begin(); iterator iter = this->begin();
if (iter == this->end()) { if (iter == this->end()) {
@ -179,6 +179,9 @@ class MatchTree : public SerializeableMatcherIF<T>, public BinaryTree<Serializea
virtual ReturnValue_t cleanUpElement(iterator position) { return HasReturnvaluesIF::RETURN_OK; } virtual ReturnValue_t cleanUpElement(iterator position) { return HasReturnvaluesIF::RETURN_OK; }
bool matchSubtree(iterator iter, T number) { bool matchSubtree(iterator iter, T number) {
if (iter == nullptr) {
return false;
}
bool isMatch = iter->match(number); bool isMatch = iter->match(number);
if (isMatch) { if (isMatch) {
if (iter.left() == this->end()) { if (iter.left() == this->end()) {

View File

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

View File

@ -1,6 +1,6 @@
target_sources(${LIB_FSFW_NAME} target_sources(${LIB_FSFW_NAME} PRIVATE
PRIVATE
CommandMessage.cpp CommandMessage.cpp
CommandMessageCleaner.cpp CommandMessageCleaner.cpp
MessageQueueMessage.cpp MessageQueueMessage.cpp
MessageQueueBase.cpp
) )

View File

@ -0,0 +1,54 @@
#include "MessageQueueBase.h"
MessageQueueBase::MessageQueueBase(MessageQueueId_t id, MessageQueueId_t defaultDest, MqArgs* args)
: id(id) {
this->defaultDest = defaultDest;
if (args != nullptr) {
this->args = *args;
}
}
MessageQueueBase::~MessageQueueBase() {}
ReturnValue_t MessageQueueBase::sendToDefault(MessageQueueMessageIF* message) {
return sendToDefaultFrom(message, this->getId(), false);
}
ReturnValue_t MessageQueueBase::reply(MessageQueueMessageIF* message) {
if (this->last != MessageQueueIF::NO_QUEUE) {
return sendMessageFrom(this->last, message, this->getId());
} else {
return NO_REPLY_PARTNER;
}
}
ReturnValue_t MessageQueueBase::receiveMessage(MessageQueueMessageIF* message,
MessageQueueId_t* receivedFrom) {
ReturnValue_t status = this->receiveMessage(message);
*receivedFrom = this->last;
return status;
}
MessageQueueId_t MessageQueueBase::getLastPartner() const { return last; }
MessageQueueId_t MessageQueueBase::getId() const { return id; }
MqArgs& MessageQueueBase::getMqArgs() { return args; }
void MessageQueueBase::setDefaultDestination(MessageQueueId_t defaultDestination) {
this->defaultDest = defaultDestination;
}
MessageQueueId_t MessageQueueBase::getDefaultDestination() const { return defaultDest; }
bool MessageQueueBase::isDefaultDestinationSet() const { return (defaultDest != NO_QUEUE); }
ReturnValue_t MessageQueueBase::sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
bool ignoreFault) {
return sendMessageFrom(sendTo, message, this->getId(), false);
}
ReturnValue_t MessageQueueBase::sendToDefaultFrom(MessageQueueMessageIF* message,
MessageQueueId_t sentFrom, bool ignoreFault) {
return sendMessageFrom(defaultDest, message, sentFrom, ignoreFault);
}

View File

@ -0,0 +1,40 @@
#ifndef FSFW_SRC_FSFW_IPC_MESSAGEQUEUEBASE_H_
#define FSFW_SRC_FSFW_IPC_MESSAGEQUEUEBASE_H_
#include <fsfw/ipc/MessageQueueIF.h>
#include <fsfw/ipc/definitions.h>
class MessageQueueBase : public MessageQueueIF {
public:
MessageQueueBase(MessageQueueId_t id, MessageQueueId_t defaultDest, MqArgs* mqArgs);
virtual ~MessageQueueBase();
// Default implementations for MessageQueueIF where possible
virtual MessageQueueId_t getLastPartner() const override;
virtual MessageQueueId_t getId() const override;
virtual MqArgs& getMqArgs() override;
virtual void setDefaultDestination(MessageQueueId_t defaultDestination) override;
virtual MessageQueueId_t getDefaultDestination() const override;
virtual bool isDefaultDestinationSet() const override;
virtual ReturnValue_t sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
bool ignoreFault) override;
virtual ReturnValue_t sendToDefault(MessageQueueMessageIF* message) override;
virtual ReturnValue_t reply(MessageQueueMessageIF* message) override;
virtual ReturnValue_t receiveMessage(MessageQueueMessageIF* message,
MessageQueueId_t* receivedFrom) override;
virtual ReturnValue_t sendToDefaultFrom(MessageQueueMessageIF* message, MessageQueueId_t sentFrom,
bool ignoreFault = false) override;
// OSAL specific, forward the abstract function
virtual ReturnValue_t receiveMessage(MessageQueueMessageIF* message) = 0;
virtual ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
MessageQueueId_t sentFrom, bool ignoreFault = false) = 0;
protected:
MessageQueueId_t id = MessageQueueIF::NO_QUEUE;
MessageQueueId_t last = MessageQueueIF::NO_QUEUE;
MessageQueueId_t defaultDest = MessageQueueIF::NO_QUEUE;
MqArgs args = {};
};
#endif /* FSFW_SRC_FSFW_IPC_MESSAGEQUEUEBASE_H_ */

View File

@ -1,6 +1,8 @@
#ifndef FSFW_IPC_MESSAGEQUEUEIF_H_ #ifndef FSFW_IPC_MESSAGEQUEUEIF_H_
#define FSFW_IPC_MESSAGEQUEUEIF_H_ #define FSFW_IPC_MESSAGEQUEUEIF_H_
#include <fsfw/ipc/definitions.h>
#include <cstdint> #include <cstdint>
#include "../returnvalues/HasReturnvaluesIF.h" #include "../returnvalues/HasReturnvaluesIF.h"
@ -44,8 +46,8 @@ class MessageQueueIF {
virtual ReturnValue_t reply(MessageQueueMessageIF* message) = 0; virtual ReturnValue_t reply(MessageQueueMessageIF* message) = 0;
/** /**
* @brief This function reads available messages from the message queue * @brief This function reads available messages from the message queue and returns the
* and returns the sender. * sender.
* @details * @details
* It works identically to the other receiveMessage call, but in addition * It works identically to the other receiveMessage call, but in addition
* returns the sender's queue id. * returns the sender's queue id.
@ -78,19 +80,16 @@ class MessageQueueIF {
*/ */
virtual ReturnValue_t flush(uint32_t* count) = 0; virtual ReturnValue_t flush(uint32_t* count) = 0;
/** /**
* @brief This method returns the message queue * @brief This method returns the message queue ID of the last communication partner.
* id of the last communication partner.
*/ */
virtual MessageQueueId_t getLastPartner() const = 0; virtual MessageQueueId_t getLastPartner() const = 0;
/** /**
* @brief This method returns the message queue * @brief This method returns the message queue ID of this class's message queue.
* id of this class's message queue.
*/ */
virtual MessageQueueId_t getId() const = 0; virtual MessageQueueId_t getId() const = 0;
/** /**
* @brief With the sendMessage call, a queue message * @brief With the sendMessage call, a queue message is sent to a receiving queue.
* is sent to a receiving queue.
* @details * @details
* This method takes the message provided, adds the sentFrom information * This method takes the message provided, adds the sentFrom information
* and passes it on to the destination provided with an operating system * and passes it on to the destination provided with an operating system
@ -129,8 +128,7 @@ class MessageQueueIF {
bool ignoreFault = false) = 0; bool ignoreFault = false) = 0;
/** /**
* @brief The sendToDefaultFrom method sends a queue message * @brief The sendToDefaultFrom method sends a queue message to the default destination.
* to the default destination.
* @details * @details
* In all other aspects, it works identical to the sendMessage method. * In all other aspects, it works identical to the sendMessage method.
* @param message * @param message
@ -164,6 +162,8 @@ class MessageQueueIF {
virtual MessageQueueId_t getDefaultDestination() const = 0; virtual MessageQueueId_t getDefaultDestination() const = 0;
virtual bool isDefaultDestinationSet() const = 0; virtual bool isDefaultDestinationSet() const = 0;
virtual MqArgs& getMqArgs() = 0;
}; };
#endif /* FSFW_IPC_MESSAGEQUEUEIF_H_ */ #endif /* FSFW_IPC_MESSAGEQUEUEIF_H_ */

View File

@ -5,6 +5,7 @@
#include "MessageQueueIF.h" #include "MessageQueueIF.h"
#include "MessageQueueMessage.h" #include "MessageQueueMessage.h"
#include "definitions.h"
/** /**
* Creates message queues. * Creates message queues.
@ -22,7 +23,8 @@ class QueueFactory {
static QueueFactory* instance(); static QueueFactory* instance();
MessageQueueIF* createMessageQueue(uint32_t messageDepth = 3, MessageQueueIF* createMessageQueue(uint32_t messageDepth = 3,
size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE); size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE,
MqArgs* args = nullptr);
void deleteMessageQueue(MessageQueueIF* queue); void deleteMessageQueue(MessageQueueIF* queue);

View File

@ -0,0 +1,14 @@
#ifndef FSFW_SRC_FSFW_IPC_DEFINITIONS_H_
#define FSFW_SRC_FSFW_IPC_DEFINITIONS_H_
#include <fsfw/objectmanager/SystemObjectIF.h>
#include <fsfw/objectmanager/frameworkObjects.h>
struct MqArgs {
MqArgs(){};
MqArgs(object_id_t objectId, void* args = nullptr) : objectId(objectId), args(args) {}
object_id_t objectId = objects::NO_OBJECT;
void* args = nullptr;
};
#endif /* FSFW_SRC_FSFW_IPC_DEFINITIONS_H_ */

View File

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

View File

@ -48,9 +48,10 @@ class SystemObject : public SystemObjectIF {
virtual ~SystemObject(); virtual ~SystemObject();
object_id_t getObjectId() const override; object_id_t getObjectId() const override;
virtual ReturnValue_t initialize() override; virtual ReturnValue_t initialize() override;
virtual ReturnValue_t checkObjectConnections(); virtual ReturnValue_t checkObjectConnections() override;
virtual void forwardEvent(Event event, uint32_t parameter1 = 0, uint32_t parameter2 = 0) const; virtual void forwardEvent(Event event, uint32_t parameter1 = 0,
uint32_t parameter2 = 0) const override;
}; };
#endif /* FSFW_OBJECTMANAGER_SYSTEMOBJECT_H_ */ #endif /* FSFW_OBJECTMANAGER_SYSTEMOBJECT_H_ */

View File

@ -19,6 +19,8 @@
#include <ws2tcpip.h> #include <ws2tcpip.h>
#elif defined(PLATFORM_UNIX) #elif defined(PLATFORM_UNIX)
#include <netdb.h> #include <netdb.h>
#include <utility>
#endif #endif
const std::string TcpTmTcServer::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT; const std::string TcpTmTcServer::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT;
@ -29,7 +31,7 @@ TcpTmTcServer::TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge,
: SystemObject(objectId), : SystemObject(objectId),
tmtcBridgeId(tmtcTcpBridge), tmtcBridgeId(tmtcTcpBridge),
receptionMode(receptionMode), receptionMode(receptionMode),
tcpConfig(customTcpServerPort), tcpConfig(std::move(customTcpServerPort)),
receptionBuffer(receptionBufferSize), receptionBuffer(receptionBufferSize),
ringBuffer(ringBufferSize, true) {} ringBuffer(ringBufferSize, true) {}
@ -103,7 +105,7 @@ ReturnValue_t TcpTmTcServer::initialize() {
TcpTmTcServer::~TcpTmTcServer() { closeSocket(listenerTcpSocket); } TcpTmTcServer::~TcpTmTcServer() { closeSocket(listenerTcpSocket); }
ReturnValue_t TcpTmTcServer::performOperation(uint8_t opCode) { [[noreturn]] ReturnValue_t TcpTmTcServer::performOperation(uint8_t opCode) {
using namespace tcpip; using namespace tcpip;
// If a connection is accepted, the corresponding socket will be assigned to the new socket // If a connection is accepted, the corresponding socket will be assigned to the new socket
socket_t connSocket = 0; socket_t connSocket = 0;
@ -138,7 +140,6 @@ ReturnValue_t TcpTmTcServer::performOperation(uint8_t opCode) {
closeSocket(connSocket); closeSocket(connSocket);
connSocket = 0; connSocket = 0;
} }
return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t TcpTmTcServer::initializeAfterTaskCreation() { ReturnValue_t TcpTmTcServer::initializeAfterTaskCreation() {
@ -159,7 +160,7 @@ void TcpTmTcServer::handleServerOperation(socket_t& connSocket) {
#endif #endif
while (true) { while (true) {
int retval = recv(connSocket, reinterpret_cast<char*>(receptionBuffer.data()), ssize_t retval = recv(connSocket, reinterpret_cast<char*>(receptionBuffer.data()),
receptionBuffer.capacity(), tcpConfig.tcpFlags); receptionBuffer.capacity(), tcpConfig.tcpFlags);
if (retval == 0) { if (retval == 0) {
size_t availableReadData = ringBuffer.getAvailableReadData(); size_t availableReadData = ringBuffer.getAvailableReadData();
@ -252,17 +253,17 @@ ReturnValue_t TcpTmTcServer::handleTcReception(uint8_t* spacePacket, size_t pack
return result; return result;
} }
std::string TcpTmTcServer::getTcpPort() const { return tcpConfig.tcpPort; } const std::string& TcpTmTcServer::getTcpPort() const { return tcpConfig.tcpPort; }
void TcpTmTcServer::setSpacePacketParsingOptions(std::vector<uint16_t> validPacketIds) { void TcpTmTcServer::setSpacePacketParsingOptions(std::vector<uint16_t> validPacketIds_) {
this->validPacketIds = validPacketIds; this->validPacketIds = std::move(validPacketIds_);
} }
TcpTmTcServer::TcpConfig& TcpTmTcServer::getTcpConfigStruct() { return tcpConfig; } TcpTmTcServer::TcpConfig& TcpTmTcServer::getTcpConfigStruct() { return tcpConfig; }
ReturnValue_t TcpTmTcServer::handleTmSending(socket_t connSocket, bool& tmSent) { ReturnValue_t TcpTmTcServer::handleTmSending(socket_t connSocket, bool& tmSent) {
// Access to the FIFO is mutex protected because it is filled by the bridge // Access to the FIFO is mutex protected because it is filled by the bridge
MutexGuard(tmtcBridge->mutex, tmtcBridge->timeoutType, tmtcBridge->mutexTimeoutMs); MutexGuard mg(tmtcBridge->mutex, tmtcBridge->timeoutType, tmtcBridge->mutexTimeoutMs);
store_address_t storeId; store_address_t storeId;
while ((not tmtcBridge->tmFifo->empty()) and while ((not tmtcBridge->tmFifo->empty()) and
(tmtcBridge->packetSentCounter < tmtcBridge->sentPacketsPerCycle)) { (tmtcBridge->packetSentCounter < tmtcBridge->sentPacketsPerCycle)) {
@ -283,7 +284,7 @@ ReturnValue_t TcpTmTcServer::handleTmSending(socket_t connSocket, bool& tmSent)
#endif #endif
arrayprinter::print(storeAccessor.data(), storeAccessor.size()); arrayprinter::print(storeAccessor.data(), storeAccessor.size());
} }
int retval = send(connSocket, reinterpret_cast<const char*>(storeAccessor.data()), ssize_t retval = send(connSocket, reinterpret_cast<const char*>(storeAccessor.data()),
storeAccessor.size(), tcpConfig.tcpTmFlags); storeAccessor.size(), tcpConfig.tcpTmFlags);
if (retval == static_cast<int>(storeAccessor.size())) { if (retval == static_cast<int>(storeAccessor.size())) {
// Packet sent, clear FIFO entry // Packet sent, clear FIFO entry
@ -339,6 +340,9 @@ ReturnValue_t TcpTmTcServer::handleTcRingBufferData(size_t availableReadData) {
size_t foundSize = 0; size_t foundSize = 0;
size_t readLen = 0; size_t readLen = 0;
while (readLen < readAmount) { while (readLen < readAmount) {
if (spacePacketParser == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
result = result =
spacePacketParser->parseSpacePackets(bufPtrPtr, readAmount, startIdx, foundSize, readLen); spacePacketParser->parseSpacePackets(bufPtrPtr, readAmount, startIdx, foundSize, readLen);
switch (result) { switch (result) {

View File

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

View File

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

View File

@ -21,11 +21,11 @@ class UdpTcPollingTask : public TcpIpBase, public SystemObject, public Executabl
public: public:
static constexpr size_t DEFAULT_MAX_RECV_SIZE = 1500; static constexpr size_t DEFAULT_MAX_RECV_SIZE = 1500;
//! 0.5 default milliseconds timeout for now. //! 0.5 default milliseconds timeout for now.
static constexpr timeval DEFAULT_TIMEOUT = {0, 500}; static const timeval DEFAULT_TIMEOUT;
UdpTcPollingTask(object_id_t objectId, object_id_t tmtcUdpBridge, size_t maxRecvSize = 0, UdpTcPollingTask(object_id_t objectId, object_id_t tmtcUdpBridge, size_t maxRecvSize = 0,
double timeoutSeconds = -1); double timeoutSeconds = -1);
virtual ~UdpTcPollingTask(); ~UdpTcPollingTask() override = default;
/** /**
* Turn on optional timeout for UDP polling. In the default mode, * Turn on optional timeout for UDP polling. In the default mode,
@ -34,9 +34,9 @@ class UdpTcPollingTask : public TcpIpBase, public SystemObject, public Executabl
*/ */
void setTimeout(double timeoutSeconds); void setTimeout(double timeoutSeconds);
virtual ReturnValue_t performOperation(uint8_t opCode) override; [[noreturn]] ReturnValue_t performOperation(uint8_t opCode) override;
virtual ReturnValue_t initialize() override; ReturnValue_t initialize() override;
virtual ReturnValue_t initializeAfterTaskCreation() override; ReturnValue_t initializeAfterTaskCreation() override;
protected: protected:
StorageManagerIF* tcStore = nullptr; StorageManagerIF* tcStore = nullptr;
@ -51,7 +51,7 @@ class UdpTcPollingTask : public TcpIpBase, public SystemObject, public Executabl
std::vector<uint8_t> receptionBuffer; std::vector<uint8_t> receptionBuffer;
size_t frameSize = 0; size_t frameSize = 0;
timeval receptionTimeout; timeval receptionTimeout{};
ReturnValue_t handleSuccessfullTcRead(size_t bytesRead); ReturnValue_t handleSuccessfullTcRead(size_t bytesRead);
}; };

View File

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

View File

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

View File

@ -11,9 +11,6 @@
// TODO sanitize input? // TODO sanitize input?
// TODO much of this code can be reused for tick-only systems // TODO much of this code can be reused for tick-only systems
uint16_t Clock::leapSeconds = 0;
MutexIF* Clock::timeMutex = nullptr;
uint32_t Clock::getTicksPerSecond(void) { return 1000; } uint32_t Clock::getTicksPerSecond(void) { return 1000; }
ReturnValue_t Clock::setClock(const TimeOfDay_t* time) { ReturnValue_t Clock::setClock(const TimeOfDay_t* time) {

View File

@ -4,8 +4,9 @@
#include "fsfw/osal/freertos/QueueMapManager.h" #include "fsfw/osal/freertos/QueueMapManager.h"
#include "fsfw/serviceinterface/ServiceInterface.h" #include "fsfw/serviceinterface/ServiceInterface.h"
MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize) MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize, MqArgs* args)
: maxMessageSize(maxMessageSize) { : MessageQueueBase(MessageQueueIF::NO_QUEUE, MessageQueueIF::NO_QUEUE, args),
maxMessageSize(maxMessageSize) {
handle = xQueueCreate(messageDepth, maxMessageSize); handle = xQueueCreate(messageDepth, maxMessageSize);
if (handle == nullptr) { if (handle == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
@ -15,10 +16,10 @@ MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize)
#else #else
sif::printError("MessageQueue::MessageQueue: Creation failed\n"); sif::printError("MessageQueue::MessageQueue: Creation failed\n");
sif::printError("Specified Message Depth: %d\n", messageDepth); sif::printError("Specified Message Depth: %d\n", messageDepth);
sif::printError("Specified MAximum Message Size: %d\n", maxMessageSize); sif::printError("Specified Maximum Message Size: %d\n", maxMessageSize);
#endif #endif
} }
QueueMapManager::instance()->addMessageQueue(handle, &queueId); QueueMapManager::instance()->addMessageQueue(handle, &id);
} }
MessageQueue::~MessageQueue() { MessageQueue::~MessageQueue() {
@ -29,28 +30,6 @@ MessageQueue::~MessageQueue() {
void MessageQueue::switchSystemContext(CallContext callContext) { this->callContext = callContext; } void MessageQueue::switchSystemContext(CallContext callContext) { this->callContext = callContext; }
ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
bool ignoreFault) {
return sendMessageFrom(sendTo, message, this->getId(), ignoreFault);
}
ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessageIF* message) {
return sendToDefaultFrom(message, this->getId());
}
ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessageIF* message,
MessageQueueId_t sentFrom, bool ignoreFault) {
return sendMessageFrom(defaultDestination, message, sentFrom, ignoreFault);
}
ReturnValue_t MessageQueue::reply(MessageQueueMessageIF* message) {
if (this->lastPartner != MessageQueueIF::NO_QUEUE) {
return sendMessageFrom(this->lastPartner, message, this->getId());
} else {
return NO_REPLY_PARTNER;
}
}
ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message, ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
MessageQueueId_t sentFrom, bool ignoreFault) { MessageQueueId_t sentFrom, bool ignoreFault) {
return sendMessageFromMessageQueue(sendTo, message, sentFrom, ignoreFault, callContext); return sendMessageFromMessageQueue(sendTo, message, sentFrom, ignoreFault, callContext);
@ -72,27 +51,16 @@ ReturnValue_t MessageQueue::handleSendResult(BaseType_t result, bool ignoreFault
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message,
MessageQueueId_t* receivedFrom) {
ReturnValue_t status = this->receiveMessage(message);
if (status == HasReturnvaluesIF::RETURN_OK) {
*receivedFrom = this->lastPartner;
}
return status;
}
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) { ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
BaseType_t result = xQueueReceive(handle, reinterpret_cast<void*>(message->getBuffer()), 0); BaseType_t result = xQueueReceive(handle, reinterpret_cast<void*>(message->getBuffer()), 0);
if (result == pdPASS) { if (result == pdPASS) {
this->lastPartner = message->getSender(); this->last = message->getSender();
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} else { } else {
return MessageQueueIF::EMPTY; return MessageQueueIF::EMPTY;
} }
} }
MessageQueueId_t MessageQueue::getLastPartner() const { return lastPartner; }
ReturnValue_t MessageQueue::flush(uint32_t* count) { ReturnValue_t MessageQueue::flush(uint32_t* count) {
// TODO FreeRTOS does not support flushing partially // TODO FreeRTOS does not support flushing partially
// Is always successful // Is always successful
@ -100,17 +68,6 @@ ReturnValue_t MessageQueue::flush(uint32_t* count) {
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
MessageQueueId_t MessageQueue::getId() const { return queueId; }
void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) {
defaultDestinationSet = true;
this->defaultDestination = defaultDestination;
}
MessageQueueId_t MessageQueue::getDefaultDestination() const { return defaultDestination; }
bool MessageQueue::isDefaultDestinationSet() const { return defaultDestinationSet; }
// static core function to send messages. // static core function to send messages.
ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, MessageQueueMessageIF* message,

View File

@ -1,12 +1,15 @@
#ifndef FSFW_OSAL_FREERTOS_MESSAGEQUEUE_H_ #ifndef FSFW_OSAL_FREERTOS_MESSAGEQUEUE_H_
#define FSFW_OSAL_FREERTOS_MESSAGEQUEUE_H_ #define FSFW_OSAL_FREERTOS_MESSAGEQUEUE_H_
#include <fsfw/ipc/MessageQueueBase.h>
#include "FreeRTOS.h" #include "FreeRTOS.h"
#include "TaskManagement.h" #include "TaskManagement.h"
#include "fsfw/internalerror/InternalErrorReporterIF.h" #include "fsfw/internalerror/InternalErrorReporterIF.h"
#include "fsfw/ipc/MessageQueueIF.h" #include "fsfw/ipc/MessageQueueIF.h"
#include "fsfw/ipc/MessageQueueMessage.h" #include "fsfw/ipc/MessageQueueMessage.h"
#include "fsfw/ipc/MessageQueueMessageIF.h" #include "fsfw/ipc/MessageQueueMessageIF.h"
#include "fsfw/ipc/definitions.h"
#include "queue.h" #include "queue.h"
/** /**
@ -32,7 +35,7 @@
* @ingroup osal * @ingroup osal
* @ingroup message_queue * @ingroup message_queue
*/ */
class MessageQueue : public MessageQueueIF { class MessageQueue : public MessageQueueBase {
friend class MessageQueueSenderIF; friend class MessageQueueSenderIF;
public: public:
@ -53,7 +56,8 @@ class MessageQueue : public MessageQueueIF {
* This should be left default. * This should be left default.
*/ */
MessageQueue(size_t messageDepth = 3, MessageQueue(size_t messageDepth = 3,
size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE); size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE,
MqArgs* args = nullptr);
/** Copying message queues forbidden */ /** Copying message queues forbidden */
MessageQueue(const MessageQueue&) = delete; MessageQueue(const MessageQueue&) = delete;
@ -73,40 +77,15 @@ class MessageQueue : public MessageQueueIF {
*/ */
void switchSystemContext(CallContext callContext); void switchSystemContext(CallContext callContext);
/** MessageQueueIF implementation */ QueueHandle_t getNativeQueueHandle();
ReturnValue_t sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
bool ignoreFault = false) override;
ReturnValue_t sendToDefault(MessageQueueMessageIF* message) override; // Implement non-generic MessageQueueIF functions not handled by MessageQueueBase
ReturnValue_t reply(MessageQueueMessageIF* message) override;
virtual ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message, virtual ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
MessageQueueId_t sentFrom = NO_QUEUE, MessageQueueId_t sentFrom = NO_QUEUE,
bool ignoreFault = false) override; bool ignoreFault = false) override;
virtual ReturnValue_t sendToDefaultFrom(MessageQueueMessageIF* message,
MessageQueueId_t sentFrom = NO_QUEUE,
bool ignoreFault = false) override;
ReturnValue_t receiveMessage(MessageQueueMessageIF* message,
MessageQueueId_t* receivedFrom) override;
ReturnValue_t receiveMessage(MessageQueueMessageIF* message) override; ReturnValue_t receiveMessage(MessageQueueMessageIF* message) override;
ReturnValue_t flush(uint32_t* count) override; ReturnValue_t flush(uint32_t* count) override;
MessageQueueId_t getLastPartner() const override;
MessageQueueId_t getId() const override;
void setDefaultDestination(MessageQueueId_t defaultDestination) override;
MessageQueueId_t getDefaultDestination() const override;
bool isDefaultDestinationSet() const override;
QueueHandle_t getNativeQueueHandle();
protected: protected:
/** /**
* @brief Implementation to be called from any send Call within * @brief Implementation to be called from any send Call within
@ -136,12 +115,8 @@ class MessageQueue : public MessageQueueIF {
static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault); static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault);
private: private:
bool defaultDestinationSet = false;
QueueHandle_t handle; QueueHandle_t handle;
MessageQueueId_t queueId = MessageQueueIF::NO_QUEUE;
MessageQueueId_t defaultDestination = MessageQueueIF::NO_QUEUE;
MessageQueueId_t lastPartner = MessageQueueIF::NO_QUEUE;
const size_t maxMessageSize; const size_t maxMessageSize;
//! Stores the current system context //! Stores the current system context
CallContext callContext = CallContext::TASK; CallContext callContext = CallContext::TASK;

View File

@ -22,8 +22,9 @@ QueueFactory::QueueFactory() {}
QueueFactory::~QueueFactory() {} QueueFactory::~QueueFactory() {}
MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, size_t maxMessageSize) { MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, size_t maxMessageSize,
return new MessageQueue(messageDepth, maxMessageSize); MqArgs* args) {
return new MessageQueue(messageDepth, maxMessageSize, args);
} }
void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) { delete queue; } void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) { delete queue; }

View File

@ -1,5 +1,4 @@
target_sources(${LIB_FSFW_NAME} target_sources(${LIB_FSFW_NAME} PRIVATE
PRIVATE
Clock.cpp Clock.cpp
FixedTimeslotTask.cpp FixedTimeslotTask.cpp
MessageQueue.cpp MessageQueue.cpp
@ -16,9 +15,13 @@ target_sources(${LIB_FSFW_NAME}
if(UNIX) if(UNIX)
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
target_link_libraries(${LIB_FSFW_NAME} target_link_libraries(${LIB_FSFW_NAME} PRIVATE
PRIVATE
rt
${CMAKE_THREAD_LIBS_INIT} ${CMAKE_THREAD_LIBS_INIT}
) )
if(NOT APPLE)
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
rt
)
endif()
endif() endif()

View File

@ -2,6 +2,7 @@
#include <chrono> #include <chrono>
#include "fsfw/ipc/MutexGuard.h"
#include "fsfw/platform.h" #include "fsfw/platform.h"
#include "fsfw/serviceinterface/ServiceInterface.h" #include "fsfw/serviceinterface/ServiceInterface.h"
@ -11,9 +12,6 @@
#include <fstream> #include <fstream>
#endif #endif
uint16_t Clock::leapSeconds = 0;
MutexIF* Clock::timeMutex = NULL;
using SystemClock = std::chrono::system_clock; using SystemClock = std::chrono::system_clock;
uint32_t Clock::getTicksPerSecond(void) { uint32_t Clock::getTicksPerSecond(void) {
@ -127,6 +125,13 @@ ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) {
auto seconds = std::chrono::time_point_cast<std::chrono::seconds>(now); auto seconds = std::chrono::time_point_cast<std::chrono::seconds>(now);
auto fraction = now - seconds; auto fraction = now - seconds;
time_t tt = SystemClock::to_time_t(now); time_t tt = SystemClock::to_time_t(now);
ReturnValue_t result = checkOrCreateClockMutex();
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
MutexGuard helper(timeMutex);
// gmtime writes its output in a global buffer which is not Thread Safe
// Therefore we have to use a Mutex here
struct tm* timeInfo; struct tm* timeInfo;
timeInfo = gmtime(&tt); timeInfo = gmtime(&tt);
time->year = timeInfo->tm_year + 1900; time->year = timeInfo->tm_year + 1900;

View File

@ -8,10 +8,12 @@
#include "fsfw/osal/host/QueueMapManager.h" #include "fsfw/osal/host/QueueMapManager.h"
#include "fsfw/serviceinterface/ServiceInterface.h" #include "fsfw/serviceinterface/ServiceInterface.h"
MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize) MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize, MqArgs* args)
: messageSize(maxMessageSize), messageDepth(messageDepth) { : MessageQueueBase(MessageQueueIF::NO_QUEUE, MessageQueueIF::NO_QUEUE, args),
messageSize(maxMessageSize),
messageDepth(messageDepth) {
queueLock = MutexFactory::instance()->createMutex(); queueLock = MutexFactory::instance()->createMutex();
auto result = QueueMapManager::instance()->addMessageQueue(this, &mqId); auto result = QueueMapManager::instance()->addMessageQueue(this, &id);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "MessageQueue::MessageQueue: Could not be created" << std::endl; sif::error << "MessageQueue::MessageQueue: Could not be created" << std::endl;
@ -23,42 +25,11 @@ MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize)
MessageQueue::~MessageQueue() { MutexFactory::instance()->deleteMutex(queueLock); } MessageQueue::~MessageQueue() { MutexFactory::instance()->deleteMutex(queueLock); }
ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
bool ignoreFault) {
return sendMessageFrom(sendTo, message, this->getId(), ignoreFault);
}
ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessageIF* message) {
return sendToDefaultFrom(message, this->getId());
}
ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessageIF* message,
MessageQueueId_t sentFrom, bool ignoreFault) {
return sendMessageFrom(defaultDestination, message, sentFrom, ignoreFault);
}
ReturnValue_t MessageQueue::reply(MessageQueueMessageIF* message) {
if (this->lastPartner != MessageQueueIF::NO_QUEUE) {
return sendMessageFrom(this->lastPartner, message, this->getId());
} else {
return MessageQueueIF::NO_REPLY_PARTNER;
}
}
ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message, ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
MessageQueueId_t sentFrom, bool ignoreFault) { MessageQueueId_t sentFrom, bool ignoreFault) {
return sendMessageFromMessageQueue(sendTo, message, sentFrom, ignoreFault); return sendMessageFromMessageQueue(sendTo, message, sentFrom, ignoreFault);
} }
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message,
MessageQueueId_t* receivedFrom) {
ReturnValue_t status = this->receiveMessage(message);
if (status == HasReturnvaluesIF::RETURN_OK) {
*receivedFrom = this->lastPartner;
}
return status;
}
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) { ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
if (messageQueue.empty()) { if (messageQueue.empty()) {
return MessageQueueIF::EMPTY; return MessageQueueIF::EMPTY;
@ -68,12 +39,10 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
message->getBuffer()); message->getBuffer());
messageQueue.pop(); messageQueue.pop();
// The last partner is the first uint32_t field in the message // The last partner is the first uint32_t field in the message
this->lastPartner = message->getSender(); this->last = message->getSender();
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
MessageQueueId_t MessageQueue::getLastPartner() const { return lastPartner; }
ReturnValue_t MessageQueue::flush(uint32_t* count) { ReturnValue_t MessageQueue::flush(uint32_t* count) {
*count = messageQueue.size(); *count = messageQueue.size();
// Clears the queue. // Clears the queue.
@ -81,17 +50,6 @@ ReturnValue_t MessageQueue::flush(uint32_t* count) {
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
MessageQueueId_t MessageQueue::getId() const { return mqId; }
void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) {
defaultDestinationSet = true;
this->defaultDestination = defaultDestination;
}
MessageQueueId_t MessageQueue::getDefaultDestination() const { return defaultDestination; }
bool MessageQueue::isDefaultDestinationSet() const { return defaultDestinationSet; }
// static core function to send messages. // static core function to send messages.
ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, MessageQueueMessageIF* message,

View File

@ -5,9 +5,11 @@
#include <queue> #include <queue>
#include "fsfw/internalerror/InternalErrorReporterIF.h" #include "fsfw/internalerror/InternalErrorReporterIF.h"
#include "fsfw/ipc/MessageQueueBase.h"
#include "fsfw/ipc/MessageQueueIF.h" #include "fsfw/ipc/MessageQueueIF.h"
#include "fsfw/ipc/MessageQueueMessage.h" #include "fsfw/ipc/MessageQueueMessage.h"
#include "fsfw/ipc/MutexIF.h" #include "fsfw/ipc/MutexIF.h"
#include "fsfw/ipc/definitions.h"
#include "fsfw/timemanager/Clock.h" #include "fsfw/timemanager/Clock.h"
/** /**
@ -33,7 +35,7 @@
* @ingroup osal * @ingroup osal
* @ingroup message_queue * @ingroup message_queue
*/ */
class MessageQueue : public MessageQueueIF { class MessageQueue : public MessageQueueBase {
friend class MessageQueueSenderIF; friend class MessageQueueSenderIF;
public: public:
@ -54,7 +56,8 @@ class MessageQueue : public MessageQueueIF {
* This should be left default. * This should be left default.
*/ */
MessageQueue(size_t messageDepth = 3, MessageQueue(size_t messageDepth = 3,
size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE); size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE,
MqArgs* args = nullptr);
/** Copying message queues forbidden */ /** Copying message queues forbidden */
MessageQueue(const MessageQueue&) = delete; MessageQueue(const MessageQueue&) = delete;
@ -67,121 +70,12 @@ class MessageQueue : public MessageQueueIF {
*/ */
virtual ~MessageQueue(); virtual ~MessageQueue();
/** // Implement non-generic MessageQueueIF functions not handled by MessageQueueBase
* @brief This operation sends a message to the given destination.
* @details It directly uses the sendMessage call of the MessageQueueSender
* parent, but passes its queue id as "sentFrom" parameter.
* @param sendTo This parameter specifies the message queue id of the
* destination message queue.
* @param message A pointer to a previously created message, which is sent.
* @param ignoreFault If set to true, the internal software fault counter
* is not incremented if queue is full.
*/
ReturnValue_t sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
bool ignoreFault = false) override;
/**
* @brief This operation sends a message to the default destination.
* @details As in the sendMessage method, this function uses the
* sendToDefault call of the MessageQueueSender parent class and adds its
* queue id as "sentFrom" information.
* @param message A pointer to a previously created message, which is sent.
*/
ReturnValue_t sendToDefault(MessageQueueMessageIF* message) override;
/**
* @brief This operation sends a message to the last communication partner.
* @details This operation simplifies answering an incoming message by using
* the stored lastPartner information as destination. If there was no
* message received yet (i.e. lastPartner is zero), an error code is returned.
* @param message A pointer to a previously created message, which is sent.
*/
ReturnValue_t reply(MessageQueueMessageIF* message) override;
/**
* @brief With the sendMessage call, a queue message is sent to a
* receiving queue.
* @details
* This method takes the message provided, adds the sentFrom information and
* passes it on to the destination provided with an operating system call.
* The OS's return value is returned.
* @param sendTo This parameter specifies the message queue id to send
* the message to.
* @param message This is a pointer to a previously created message,
* which is sent.
* @param sentFrom The sentFrom information can be set to inject the
* sender's queue id into the message. This variable is set to zero by
* default.
* @param ignoreFault If set to true, the internal software fault counter
* is not incremented if queue is full.
*/
virtual ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message, virtual ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
MessageQueueId_t sentFrom = NO_QUEUE, MessageQueueId_t sentFrom = NO_QUEUE,
bool ignoreFault = false) override; bool ignoreFault = false) override;
/**
* @brief The sendToDefault method sends a queue message to the default
* destination.
* @details
* In all other aspects, it works identical to the sendMessage method.
* @param message This is a pointer to a previously created message,
* which is sent.
* @param sentFrom The sentFrom information can be set to inject the
* sender's queue id into the message. This variable is set to zero by
* default.
*/
virtual ReturnValue_t sendToDefaultFrom(MessageQueueMessageIF* message,
MessageQueueId_t sentFrom = NO_QUEUE,
bool ignoreFault = false) override;
/**
* @brief This function reads available messages from the message queue
* and returns the sender.
* @details
* It works identically to the other receiveMessage call, but in addition
* returns the sender's queue id.
* @param message A pointer to a message in which the received data is stored.
* @param receivedFrom A pointer to a queue id in which the sender's id is stored.
*/
ReturnValue_t receiveMessage(MessageQueueMessageIF* message,
MessageQueueId_t* receivedFrom) override;
/**
* @brief This function reads available messages from the message queue.
* @details
* If data is available it is stored in the passed message pointer.
* The message's original content is overwritten and the sendFrom
* information is stored in the lastPartner attribute. Else, the lastPartner
* information remains untouched, the message's content is cleared and the
* function returns immediately.
* @param message A pointer to a message in which the received data is stored.
*/
ReturnValue_t receiveMessage(MessageQueueMessageIF* message) override; ReturnValue_t receiveMessage(MessageQueueMessageIF* message) override;
/**
* Deletes all pending messages in the queue.
* @param count The number of flushed messages.
* @return RETURN_OK on success.
*/
ReturnValue_t flush(uint32_t* count) override; ReturnValue_t flush(uint32_t* count) override;
/**
* @brief This method returns the message queue id of the last
* communication partner.
*/
MessageQueueId_t getLastPartner() const override;
/**
* @brief This method returns the message queue id of this class's
* message queue.
*/
MessageQueueId_t getId() const override;
/**
* @brief This method is a simple setter for the default destination.
*/
void setDefaultDestination(MessageQueueId_t defaultDestination) override;
/**
* @brief This method is a simple getter for the default destination.
*/
MessageQueueId_t getDefaultDestination() const override;
bool isDefaultDestinationSet() const override;
ReturnValue_t lockQueue(MutexIF::TimeoutType timeoutType, dur_millis_t lockTimeout); ReturnValue_t lockQueue(MutexIF::TimeoutType timeoutType, dur_millis_t lockTimeout);
ReturnValue_t unlockQueue(); ReturnValue_t unlockQueue();
@ -211,23 +105,14 @@ class MessageQueue : public MessageQueueIF {
MessageQueueId_t sentFrom = NO_QUEUE, MessageQueueId_t sentFrom = NO_QUEUE,
bool ignoreFault = false); bool ignoreFault = false);
// static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault);
private: private:
std::queue<std::vector<uint8_t>> messageQueue; std::queue<std::vector<uint8_t>> messageQueue;
/**
* @brief The class stores the queue id it got assigned.
* If initialization fails, the queue id is set to zero.
*/
MessageQueueId_t mqId = MessageQueueIF::NO_QUEUE;
size_t messageSize = 0; size_t messageSize = 0;
size_t messageDepth = 0; size_t messageDepth = 0;
MutexIF* queueLock; MutexIF* queueLock;
bool defaultDestinationSet = false;
MessageQueueId_t defaultDestination = MessageQueueIF::NO_QUEUE; MessageQueueId_t defaultDestination = MessageQueueIF::NO_QUEUE;
MessageQueueId_t lastPartner = MessageQueueIF::NO_QUEUE;
}; };
#endif /* FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_ */ #endif /* FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_ */

View File

@ -27,12 +27,13 @@ QueueFactory::QueueFactory() {}
QueueFactory::~QueueFactory() {} QueueFactory::~QueueFactory() {}
MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, size_t maxMessageSize) { MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, size_t maxMessageSize,
MqArgs* args) {
// A thread-safe queue can be implemented by using a combination // A thread-safe queue can be implemented by using a combination
// of std::queue and std::mutex. This uses dynamic memory allocation // of std::queue and std::mutex. This uses dynamic memory allocation
// which could be alleviated by using a custom allocator, external library // which could be alleviated by using a custom allocator, external library
// (etl::queue) or simply using std::queue, we're on a host machine anyway. // (etl::queue) or simply using std::queue, we're on a host machine anyway.
return new MessageQueue(messageDepth, maxMessageSize); return new MessageQueue(messageDepth, maxMessageSize, args);
} }
void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) { delete queue; } void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) { delete queue; }

View File

@ -14,16 +14,16 @@ target_sources(${LIB_FSFW_NAME} PRIVATE
TaskFactory.cpp TaskFactory.cpp
tcpipHelpers.cpp tcpipHelpers.cpp
unixUtility.cpp unixUtility.cpp
) )
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
target_link_libraries(${LIB_FSFW_NAME} PRIVATE target_link_libraries(${LIB_FSFW_NAME} PUBLIC
${CMAKE_THREAD_LIBS_INIT} ${CMAKE_THREAD_LIBS_INIT}
)
if(NOT APPLE)
target_link_libraries(${LIB_FSFW_NAME} PUBLIC
rt rt
) )
endif()
target_link_libraries(${LIB_FSFW_NAME} INTERFACE
${CMAKE_THREAD_LIBS_INIT}
)

View File

@ -8,11 +8,9 @@
#include <fstream> #include <fstream>
#include "fsfw/ipc/MutexGuard.h"
#include "fsfw/serviceinterface/ServiceInterface.h" #include "fsfw/serviceinterface/ServiceInterface.h"
uint16_t Clock::leapSeconds = 0;
MutexIF* Clock::timeMutex = NULL;
uint32_t Clock::getTicksPerSecond(void) { uint32_t Clock::getTicksPerSecond(void) {
uint32_t ticks = sysconf(_SC_CLK_TCK); uint32_t ticks = sysconf(_SC_CLK_TCK);
return ticks; return ticks;
@ -117,7 +115,13 @@ ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) {
// TODO errno // TODO errno
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
ReturnValue_t result = checkOrCreateClockMutex();
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
MutexGuard helper(timeMutex);
// gmtime writes its output in a global buffer which is not Thread Safe
// Therefore we have to use a Mutex here
struct tm* timeInfo; struct tm* timeInfo;
timeInfo = gmtime(&timeUnix.tv_sec); timeInfo = gmtime(&timeUnix.tv_sec);
time->year = timeInfo->tm_year + 1900; time->year = timeInfo->tm_year + 1900;

View File

@ -11,13 +11,10 @@
#include "fsfw/osal/linux/unixUtility.h" #include "fsfw/osal/linux/unixUtility.h"
#include "fsfw/serviceinterface/ServiceInterface.h" #include "fsfw/serviceinterface/ServiceInterface.h"
MessageQueue::MessageQueue(uint32_t messageDepth, size_t maxMessageSize) MessageQueue::MessageQueue(uint32_t messageDepth, size_t maxMessageSize, MqArgs* args)
: id(MessageQueueIF::NO_QUEUE), : MessageQueueBase(MessageQueueIF::NO_QUEUE, MessageQueueIF::NO_QUEUE, args),
lastPartner(MessageQueueIF::NO_QUEUE),
defaultDestination(MessageQueueIF::NO_QUEUE),
maxMessageSize(maxMessageSize) { maxMessageSize(maxMessageSize) {
mq_attr attributes; mq_attr attributes;
this->id = 0;
// Set attributes // Set attributes
attributes.mq_curmsgs = 0; attributes.mq_curmsgs = 0;
attributes.mq_maxmsg = messageDepth; attributes.mq_maxmsg = messageDepth;
@ -50,30 +47,6 @@ MessageQueue::~MessageQueue() {
} }
} }
ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
bool ignoreFault) {
return sendMessageFrom(sendTo, message, this->getId(), false);
}
ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessageIF* message) {
return sendToDefaultFrom(message, this->getId());
}
ReturnValue_t MessageQueue::reply(MessageQueueMessageIF* message) {
if (this->lastPartner != 0) {
return sendMessageFrom(this->lastPartner, message, this->getId());
} else {
return NO_REPLY_PARTNER;
}
}
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message,
MessageQueueId_t* receivedFrom) {
ReturnValue_t status = this->receiveMessage(message);
*receivedFrom = this->lastPartner;
return status;
}
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) { ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
if (message == nullptr) { if (message == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
@ -96,7 +69,7 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
int status = mq_receive(id, reinterpret_cast<char*>(message->getBuffer()), int status = mq_receive(id, reinterpret_cast<char*>(message->getBuffer()),
message->getMaximumMessageSize(), &messagePriority); message->getMaximumMessageSize(), &messagePriority);
if (status > 0) { if (status > 0) {
this->lastPartner = message->getSender(); this->last = message->getSender();
// Check size of incoming message. // Check size of incoming message.
if (message->getMessageSize() < message->getMinimumMessageSize()) { if (message->getMessageSize() < message->getMinimumMessageSize()) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
@ -164,8 +137,6 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
} }
} }
MessageQueueId_t MessageQueue::getLastPartner() const { return this->lastPartner; }
ReturnValue_t MessageQueue::flush(uint32_t* count) { ReturnValue_t MessageQueue::flush(uint32_t* count) {
mq_attr attrib; mq_attr attrib;
int status = mq_getattr(id, &attrib); int status = mq_getattr(id, &attrib);
@ -212,26 +183,11 @@ ReturnValue_t MessageQueue::flush(uint32_t* count) {
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
MessageQueueId_t MessageQueue::getId() const { return this->id; }
void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) {
this->defaultDestination = defaultDestination;
}
ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessageIF* message,
MessageQueueId_t sentFrom, bool ignoreFault) {
return sendMessageFrom(defaultDestination, message, sentFrom, ignoreFault);
}
ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message, ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
MessageQueueId_t sentFrom, bool ignoreFault) { MessageQueueId_t sentFrom, bool ignoreFault) {
return sendMessageFromMessageQueue(sendTo, message, sentFrom, ignoreFault); return sendMessageFromMessageQueue(sendTo, message, sentFrom, ignoreFault);
} }
MessageQueueId_t MessageQueue::getDefaultDestination() const { return this->defaultDestination; }
bool MessageQueue::isDefaultDestinationSet() const { return (defaultDestination != NO_QUEUE); }
uint16_t MessageQueue::queueCounter = 0; uint16_t MessageQueue::queueCounter = 0;
ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
@ -240,9 +196,9 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
bool ignoreFault) { bool ignoreFault) {
if (message == nullptr) { if (message == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "MessageQueue::sendMessageFromMessageQueue: Message is nullptr!" << std::endl; sif::error << "MessageQueue::sendMessageFromMessageQueue: Message is nullptr" << std::endl;
#else #else
sif::printError("MessageQueue::sendMessageFromMessageQueue: Message is nullptr!\n"); sif::printError("MessageQueue::sendMessageFromMessageQueue: Message is nullptr\n");
#endif #endif
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
@ -256,7 +212,7 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
if (!ignoreFault) { if (!ignoreFault) {
InternalErrorReporterIF* internalErrorReporter = InternalErrorReporterIF* internalErrorReporter =
ObjectManager::instance()->get<InternalErrorReporterIF>(objects::INTERNAL_ERROR_REPORTER); ObjectManager::instance()->get<InternalErrorReporterIF>(objects::INTERNAL_ERROR_REPORTER);
if (internalErrorReporter != NULL) { if (internalErrorReporter != nullptr) {
internalErrorReporter->queueMessageNotSent(); internalErrorReporter->queueMessageNotSent();
} }
} }

View File

@ -1,11 +1,13 @@
#ifndef FSFW_OSAL_LINUX_MESSAGEQUEUE_H_ #ifndef FSFW_OSAL_LINUX_MESSAGEQUEUE_H_
#define FSFW_OSAL_LINUX_MESSAGEQUEUE_H_ #define FSFW_OSAL_LINUX_MESSAGEQUEUE_H_
#include <fsfw/ipc/MessageQueueBase.h>
#include <mqueue.h> #include <mqueue.h>
#include "fsfw/internalerror/InternalErrorReporterIF.h" #include "fsfw/internalerror/InternalErrorReporterIF.h"
#include "fsfw/ipc/MessageQueueIF.h" #include "fsfw/ipc/MessageQueueIF.h"
#include "fsfw/ipc/MessageQueueMessage.h" #include "fsfw/ipc/MessageQueueMessage.h"
#include "fsfw/ipc/definitions.h"
/** /**
* @brief This class manages sending and receiving of message queue messages. * @brief This class manages sending and receiving of message queue messages.
* *
@ -25,7 +27,7 @@
* makes use of the operating system calls provided. * makes use of the operating system calls provided.
* @ingroup message_queue * @ingroup message_queue
*/ */
class MessageQueue : public MessageQueueIF { class MessageQueue : public MessageQueueBase {
friend class MessageQueueSenderIF; friend class MessageQueueSenderIF;
public: public:
@ -42,104 +44,24 @@ class MessageQueue : public MessageQueueIF {
* This should be left default. * This should be left default.
*/ */
MessageQueue(uint32_t messageDepth = 3, MessageQueue(uint32_t messageDepth = 3,
size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE); size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE,
MqArgs* args = nullptr);
/** Copying message queues forbidden */
MessageQueue(const MessageQueue&) = delete;
MessageQueue& operator=(const MessageQueue&) = delete;
/** /**
* @brief The destructor deletes the formerly created message queue. * @brief The destructor deletes the formerly created message queue.
* @details This is accomplished by using the delete call provided by the operating system. * @details This is accomplished by using the delete call provided by the operating system.
*/ */
virtual ~MessageQueue(); virtual ~MessageQueue();
/**
* @brief This operation sends a message to the given destination.
* @details It directly uses the sendMessage call of the MessageQueueSender parent, but passes
* its queue id as "sentFrom" parameter.
* @param sendTo This parameter specifies the message queue id of the destination message
* queue.
* @param message A pointer to a previously created message, which is sent.
* @param ignoreFault If set to true, the internal software fault counter is not incremented if
* queue is full.
*/
virtual ReturnValue_t sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
bool ignoreFault = false);
/**
* @brief This operation sends a message to the default destination.
* @details As in the sendMessage method, this function uses the sendToDefault call of the
* MessageQueueSender parent class and adds its queue id as "sentFrom"
* information.
* @param message A pointer to a previously created message, which is sent.
*/
virtual ReturnValue_t sendToDefault(MessageQueueMessageIF* message);
/**
* @brief This operation sends a message to the last communication partner.
* @details This operation simplifies answering an incoming message by using the stored
* lastParnter information as destination. If there was no message received yet
* (i.e. lastPartner is zero), an error code is returned.
* @param message A pointer to a previously created message, which is sent.
*/
ReturnValue_t reply(MessageQueueMessageIF* message);
/** // Implement non-generic MessageQueueIF functions not handled by MessageQueueBase
* @brief This function reads available messages from the message queue and returns the ReturnValue_t receiveMessage(MessageQueueMessageIF* message) override;
* sender. ReturnValue_t flush(uint32_t* count) override;
* @details It works identically to the other receiveMessage call, but in addition returns the ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
* sender's queue id. MessageQueueId_t sentFrom, bool ignoreFault = false) override;
* @param message A pointer to a message in which the received data is stored.
* @param receivedFrom A pointer to a queue id in which the sender's id is stored.
*/
ReturnValue_t receiveMessage(MessageQueueMessageIF* message, MessageQueueId_t* receivedFrom);
/**
* @brief This function reads available messages from the message queue.
* @details If data is available it is stored in the passed message pointer. The message's
* original content is overwritten and the sendFrom information is stored in
* the lastPartner attribute. Else, the lastPartner information remains untouched, the message's
* content is cleared and the function returns immediately.
* @param message A pointer to a message in which the received data is stored.
*/
ReturnValue_t receiveMessage(MessageQueueMessageIF* message);
/**
* Deletes all pending messages in the queue.
* @param count The number of flushed messages.
* @return RETURN_OK on success.
*/
ReturnValue_t flush(uint32_t* count);
/**
* @brief This method returns the message queue id of the last communication partner.
*/
MessageQueueId_t getLastPartner() const;
/**
* @brief This method returns the message queue id of this class's message queue.
*/
MessageQueueId_t getId() const;
/**
* \brief With the sendMessage call, a queue message is sent to a receiving queue.
* \param sendTo This parameter specifies the message queue id to send the message to.
* \param message This is a pointer to a previously created message, which is sent.
* \param sentFrom The sentFrom information can be set to inject the sender's queue id into the
* message. This variable is set to zero by default. \param ignoreFault If set to true, the
* internal software fault counter is not incremented if queue is full.
*/
virtual ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
MessageQueueId_t sentFrom, bool ignoreFault = false);
/**
* \brief The sendToDefault method sends a queue message to the default destination.
* \details In all other aspects, it works identical to the sendMessage method.
* \param message This is a pointer to a previously created message, which is sent.
* \param sentFrom The sentFrom information can be set to inject the sender's queue id into the
* message. This variable is set to zero by default.
*/
virtual ReturnValue_t sendToDefaultFrom(MessageQueueMessageIF* message,
MessageQueueId_t sentFrom = NO_QUEUE,
bool ignoreFault = false);
/**
* \brief This method is a simple setter for the default destination.
*/
void setDefaultDestination(MessageQueueId_t defaultDestination);
/**
* \brief This method is a simple getter for the default destination.
*/
MessageQueueId_t getDefaultDestination() const;
bool isDefaultDestinationSet() const;
protected: protected:
/** /**
@ -158,31 +80,10 @@ class MessageQueue : public MessageQueueIF {
bool ignoreFault = false); bool ignoreFault = false);
private: private:
/**
* @brief The class stores the queue id it got assigned from the operating system in this
* attribute. If initialization fails, the queue id is set to zero.
*/
MessageQueueId_t id;
/**
* @brief In this attribute, the queue id of the last communication partner is stored
* to allow for replying.
*/
MessageQueueId_t lastPartner;
/**
* @brief The message queue's name -a user specific information for the operating system- is
* generated automatically with the help of this static counter.
*/
/**
* \brief This attribute stores a default destination to send messages to.
* \details It is stored to simplify sending to always-the-same receiver. The attribute may
* be set in the constructor or by a setter call to setDefaultDestination.
*/
MessageQueueId_t defaultDestination;
/** /**
* The name of the message queue, stored for unlinking * The name of the message queue, stored for unlinking
*/ */
char name[16]; char name[16] = {};
static uint16_t queueCounter; static uint16_t queueCounter;
const size_t maxMessageSize; const size_t maxMessageSize;

View File

@ -28,8 +28,9 @@ QueueFactory::QueueFactory() {}
QueueFactory::~QueueFactory() {} QueueFactory::~QueueFactory() {}
MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, size_t maxMessageSize) { MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, size_t maxMessageSize,
return new MessageQueue(messageDepth, maxMessageSize); MqArgs* args) {
return new MessageQueue(messageDepth, maxMessageSize, args);
} }
void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) { delete queue; } void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) { delete queue; }

View File

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

View File

@ -6,8 +6,9 @@
#include "fsfw/osal/rtems/RtemsBasic.h" #include "fsfw/osal/rtems/RtemsBasic.h"
#include "fsfw/serviceinterface/ServiceInterface.h" #include "fsfw/serviceinterface/ServiceInterface.h"
MessageQueue::MessageQueue(size_t message_depth, size_t max_message_size) MessageQueue::MessageQueue(size_t message_depth, size_t max_message_size, MqArgs* args)
: id(0), lastPartner(0), defaultDestination(NO_QUEUE), internalErrorReporter(nullptr) { : MessageQueueBase(MessageQueueIF::NO_QUEUE, MessageQueueIF::NO_QUEUE, args),
internalErrorReporter(nullptr) {
rtems_name name = ('Q' << 24) + (queueCounter++ << 8); rtems_name name = ('Q' << 24) + (queueCounter++ << 8);
rtems_status_code status = rtems_status_code status =
rtems_message_queue_create(name, message_depth, max_message_size, 0, &(this->id)); rtems_message_queue_create(name, message_depth, max_message_size, 0, &(this->id));
@ -16,43 +17,19 @@ MessageQueue::MessageQueue(size_t message_depth, size_t max_message_size)
sif::error << "MessageQueue::MessageQueue: Creating Queue " << std::hex << name << std::dec sif::error << "MessageQueue::MessageQueue: Creating Queue " << std::hex << name << std::dec
<< " failed with status:" << (uint32_t)status << std::endl; << " failed with status:" << (uint32_t)status << std::endl;
#endif #endif
this->id = 0; this->id = MessageQueueIF::NO_QUEUE;
} }
} }
MessageQueue::~MessageQueue() { rtems_message_queue_delete(id); } MessageQueue::~MessageQueue() { rtems_message_queue_delete(id); }
ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
bool ignoreFault) {
return sendMessageFrom(sendTo, message, this->getId(), ignoreFault);
}
ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessageIF* message) {
return sendToDefaultFrom(message, this->getId());
}
ReturnValue_t MessageQueue::reply(MessageQueueMessageIF* message) {
if (this->lastPartner != 0) {
return sendMessage(this->lastPartner, message, this->getId());
} else {
return NO_REPLY_PARTNER;
}
}
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message,
MessageQueueId_t* receivedFrom) {
ReturnValue_t status = this->receiveMessage(message);
*receivedFrom = this->lastPartner;
return status;
}
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) { ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
size_t size = 0; size_t size = 0;
rtems_status_code status = rtems_status_code status =
rtems_message_queue_receive(id, message->getBuffer(), &size, RTEMS_NO_WAIT, 1); rtems_message_queue_receive(id, message->getBuffer(), &size, RTEMS_NO_WAIT, 1);
if (status == RTEMS_SUCCESSFUL) { if (status == RTEMS_SUCCESSFUL) {
message->setMessageSize(size); message->setMessageSize(size);
this->lastPartner = message->getSender(); this->last = message->getSender();
// Check size of incoming message. // Check size of incoming message.
if (message->getMessageSize() < message->getMinimumMessageSize()) { if (message->getMessageSize() < message->getMinimumMessageSize()) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
@ -65,19 +42,11 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
return convertReturnCode(status); return convertReturnCode(status);
} }
MessageQueueId_t MessageQueue::getLastPartner() const { return this->lastPartner; }
ReturnValue_t MessageQueue::flush(uint32_t* count) { ReturnValue_t MessageQueue::flush(uint32_t* count) {
rtems_status_code status = rtems_message_queue_flush(id, count); rtems_status_code status = rtems_message_queue_flush(id, count);
return convertReturnCode(status); return convertReturnCode(status);
} }
MessageQueueId_t MessageQueue::getId() const { return this->id; }
void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) {
this->defaultDestination = defaultDestination;
}
ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message, ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
MessageQueueId_t sentFrom, bool ignoreFault) { MessageQueueId_t sentFrom, bool ignoreFault) {
message->setSender(sentFrom); message->setSender(sentFrom);
@ -103,15 +72,6 @@ ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, MessageQueu
return returnCode; return returnCode;
} }
ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessageIF* message,
MessageQueueId_t sentFrom, bool ignoreFault) {
return sendMessageFrom(defaultDestination, message, sentFrom, ignoreFault);
}
MessageQueueId_t MessageQueue::getDefaultDestination() const { return this->defaultDestination; }
bool MessageQueue::isDefaultDestinationSet() const { return (defaultDestination != NO_QUEUE); }
ReturnValue_t MessageQueue::convertReturnCode(rtems_status_code inValue) { ReturnValue_t MessageQueue::convertReturnCode(rtems_status_code inValue) {
switch (inValue) { switch (inValue) {
case RTEMS_SUCCESSFUL: case RTEMS_SUCCESSFUL:

View File

@ -1,10 +1,13 @@
#ifndef FSFW_OSAL_RTEMS_MESSAGEQUEUE_H_ #ifndef FSFW_OSAL_RTEMS_MESSAGEQUEUE_H_
#define FSFW_OSAL_RTEMS_MESSAGEQUEUE_H_ #define FSFW_OSAL_RTEMS_MESSAGEQUEUE_H_
#include <fsfw/ipc/MessageQueueBase.h>
#include "RtemsBasic.h" #include "RtemsBasic.h"
#include "fsfw/internalerror/InternalErrorReporterIF.h" #include "fsfw/internalerror/InternalErrorReporterIF.h"
#include "fsfw/ipc/MessageQueueIF.h" #include "fsfw/ipc/MessageQueueIF.h"
#include "fsfw/ipc/MessageQueueMessage.h" #include "fsfw/ipc/MessageQueueMessage.h"
#include "fsfw/ipc/definitions.h"
/** /**
* @brief This class manages sending and receiving of message queue messages. * @brief This class manages sending and receiving of message queue messages.
@ -19,7 +22,7 @@
*as well as sending and receiving messages, the class makes use of the operating system calls *as well as sending and receiving messages, the class makes use of the operating system calls
*provided. \ingroup message_queue *provided. \ingroup message_queue
*/ */
class MessageQueue : public MessageQueueIF { class MessageQueue : public MessageQueueBase {
public: public:
/** /**
* @brief The constructor initializes and configures the message queue. * @brief The constructor initializes and configures the message queue.
@ -34,131 +37,26 @@ class MessageQueue : public MessageQueueIF {
* This should be left default. * This should be left default.
*/ */
MessageQueue(size_t message_depth = 3, MessageQueue(size_t message_depth = 3,
size_t max_message_size = MessageQueueMessage::MAX_MESSAGE_SIZE); size_t max_message_size = MessageQueueMessage::MAX_MESSAGE_SIZE,
MqArgs* args = nullptr);
/** Copying message queues forbidden */
MessageQueue(const MessageQueue&) = delete;
MessageQueue& operator=(const MessageQueue&) = delete;
/** /**
* @brief The destructor deletes the formerly created message queue. * @brief The destructor deletes the formerly created message queue.
* @details This is accomplished by using the delete call provided by the operating system. * @details This is accomplished by using the delete call provided by the operating system.
*/ */
virtual ~MessageQueue(); virtual ~MessageQueue();
/**
* @brief This operation sends a message to the given destination.
* @details It directly uses the sendMessage call of the MessageQueueSender parent, but passes
* its queue id as "sentFrom" parameter.
* @param sendTo This parameter specifies the message queue id of the destination message
* queue.
* @param message A pointer to a previously created message, which is sent.
* @param ignoreFault If set to true, the internal software fault counter is not incremented if
* queue is full.
*/
ReturnValue_t sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
bool ignoreFault = false);
/**
* @brief This operation sends a message to the default destination.
* @details As in the sendMessage method, this function uses the sendToDefault call of the
* MessageQueueSender parent class and adds its queue id as "sentFrom"
* information.
* @param message A pointer to a previously created message, which is sent.
*/
ReturnValue_t sendToDefault(MessageQueueMessageIF* message);
/**
* @brief This operation sends a message to the last communication partner.
* @details This operation simplifies answering an incoming message by using the stored
* lastParnter information as destination. If there was no message received yet
* (i.e. lastPartner is zero), an error code is returned.
* @param message A pointer to a previously created message, which is sent.
*/
ReturnValue_t reply(MessageQueueMessageIF* message);
/** // Implement non-generic MessageQueueIF functions not handled by MessageQueueBase
* @brief This function reads available messages from the message queue and returns the ReturnValue_t flush(uint32_t* count) override;
* sender. ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
* @details It works identically to the other receiveMessage call, but in addition returns the
* sender's queue id.
* @param message A pointer to a message in which the received data is stored.
* @param receivedFrom A pointer to a queue id in which the sender's id is stored.
*/
ReturnValue_t receiveMessage(MessageQueueMessageIF* message, MessageQueueId_t* receivedFrom);
/**
* @brief This function reads available messages from the message queue.
* @details If data is available it is stored in the passed message pointer. The message's
* original content is overwritten and the sendFrom information is stored in
* the lastPartner attribute. Else, the lastPartner information remains untouched, the message's
* content is cleared and the function returns immediately.
* @param message A pointer to a message in which the received data is stored.
*/
ReturnValue_t receiveMessage(MessageQueueMessageIF* message);
/**
* Deletes all pending messages in the queue.
* @param count The number of flushed messages.
* @return RETURN_OK on success.
*/
ReturnValue_t flush(uint32_t* count);
/**
* @brief This method returns the message queue id of the last communication partner.
*/
MessageQueueId_t getLastPartner() const;
/**
* @brief This method returns the message queue id of this class's message queue.
*/
MessageQueueId_t getId() const;
/**
* \brief With the sendMessage call, a queue message is sent to a receiving queue.
* \details This method takes the message provided, adds the sentFrom information and passes
* it on to the destination provided with an operating system call. The OS's
* return value is returned.
* \param sendTo This parameter specifies the message queue id to send the message to.
* \param message This is a pointer to a previously created message, which is sent.
* \param sentFrom The sentFrom information can be set to inject the sender's queue id into the
* message. This variable is set to zero by default. \param ignoreFault If set to true, the
* internal software fault counter is not incremented if queue is full.
*/
virtual ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
MessageQueueId_t sentFrom = NO_QUEUE, MessageQueueId_t sentFrom = NO_QUEUE,
bool ignoreFault = false); bool ignoreFault = false) override;
/**
* \brief The sendToDefault method sends a queue message to the default destination.
* \details In all other aspects, it works identical to the sendMessage method.
* \param message This is a pointer to a previously created message, which is sent.
* \param sentFrom The sentFrom information can be set to inject the sender's queue id into the
* message. This variable is set to zero by default.
*/
virtual ReturnValue_t sendToDefaultFrom(MessageQueueMessageIF* message,
MessageQueueId_t sentFrom = NO_QUEUE,
bool ignoreFault = false);
/**
* \brief This method is a simple setter for the default destination.
*/
void setDefaultDestination(MessageQueueId_t defaultDestination);
/**
* \brief This method is a simple getter for the default destination.
*/
MessageQueueId_t getDefaultDestination() const;
bool isDefaultDestinationSet() const;
private: private:
/**
* @brief The class stores the queue id it got assigned from the operating system in this
* attribute. If initialization fails, the queue id is set to zero.
*/
MessageQueueId_t id;
/**
* @brief In this attribute, the queue id of the last communication partner is stored
* to allow for replying.
*/
MessageQueueId_t lastPartner;
/**
* @brief The message queue's name -a user specific information for the operating system- is
* generated automatically with the help of this static counter.
*/
/**
* \brief This attribute stores a default destination to send messages to.
* \details It is stored to simplify sending to always-the-same receiver. The attribute may
* be set in the constructor or by a setter call to setDefaultDestination.
*/
MessageQueueId_t defaultDestination;
/** /**
* \brief This attribute stores a reference to the internal error reporter for reporting full * \brief This attribute stores a reference to the internal error reporter for reporting full
* queues. \details In the event of a full destination queue, the reporter will be notified. The * queues. \details In the event of a full destination queue, the reporter will be notified. The

View File

@ -59,14 +59,13 @@ class PeriodicTask : public RTEMSTaskBase, public PeriodicTaskIF {
*/ */
ReturnValue_t addComponent(object_id_t object) override; ReturnValue_t addComponent(object_id_t object) override;
/** /**
* Adds an object to the list of objects to be executed. * Adds an object to the list of objects to be executed.
* The objects are executed in the order added. * The objects are executed in the order added.
* @param object pointer to the object to add. * @param object pointer to the object to add.
* @return RETURN_OK on success, RETURN_FAILED if the object could not be added. * @return RETURN_OK on success, RETURN_FAILED if the object could not be added.
*/ */
ReturnValue_t addComponent(ExecutableObjectIF* object) override; ReturnValue_t addComponent(ExecutableObjectIF *object) override;
uint32_t getPeriodMs() const override; uint32_t getPeriodMs() const override;

View File

@ -49,8 +49,9 @@ QueueFactory::QueueFactory() {}
QueueFactory::~QueueFactory() {} QueueFactory::~QueueFactory() {}
MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, size_t maxMessageSize) { MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, size_t maxMessageSize,
return new MessageQueue(messageDepth, maxMessageSize); MqArgs* args) {
return new MessageQueue(messageDepth, maxMessageSize, args);
} }
void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) { delete queue; } void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) { delete queue; }

View File

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

View File

@ -0,0 +1,47 @@
#include "DummyPowerSwitcher.h"
DummyPowerSwitcher::DummyPowerSwitcher(object_id_t objectId, size_t numberOfSwitches,
size_t numberOfFuses, bool registerGlobally,
uint32_t switchDelayMs)
: SystemObject(objectId, registerGlobally),
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

@ -0,0 +1,38 @@
#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"
/**
* @brief This component can be used to simulate a power switcher like a
* Power Control Distribution Unit (PCDU)
* @details
* The dummy switcher will simply cache the commanded fuse and switch states and return them
* in the according switch getter functions. In that sense, it simulates an ideal PCDU.
*/
class DummyPowerSwitcher : public SystemObject, public PowerSwitchIF {
public:
DummyPowerSwitcher(object_id_t objectId, size_t numberOfSwitches, size_t numberOfFuses,
bool registerGlobally = true, 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; static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PCDU_1;
static const Event FUSE_CURRENT_HIGH = MAKE_EVENT( //! PSS detected that current on a fuse is totally out of bounds.
1, severity::LOW); //!< PSS detected that current on a fuse is totally out of bounds. static const Event FUSE_CURRENT_HIGH = MAKE_EVENT(1, severity::LOW);
static const Event FUSE_WENT_OFF = //! PSS detected a fuse that went off.
MAKE_EVENT(2, severity::LOW); //!< PSS detected a fuse that went off. static const Event FUSE_WENT_OFF = MAKE_EVENT(2, severity::LOW);
static const Event POWER_ABOVE_HIGH_LIMIT = //! PSS detected a fuse that violates its limits.
MAKE_EVENT(4, severity::LOW); //!< PSS detected a fuse that violates its limits. static const Event POWER_ABOVE_HIGH_LIMIT = MAKE_EVENT(4, severity::LOW);
static const Event POWER_BELOW_LOW_LIMIT = //! PSS detected a fuse that violates its limits.
MAKE_EVENT(5, severity::LOW); //!< PSS detected a fuse that violates its limits. static const Event POWER_BELOW_LOW_LIMIT = MAKE_EVENT(5, severity::LOW);
typedef std::list<PowerComponentIF *> DeviceList; typedef std::list<PowerComponentIF *> DeviceList;
Fuse(object_id_t fuseObjectId, uint8_t fuseId, sid_t variableSet, VariableIds ids, Fuse(object_id_t fuseObjectId, uint8_t fuseId, sid_t variableSet, VariableIds ids,
@ -54,7 +54,7 @@ class Fuse : public SystemObject,
ReturnValue_t check(); ReturnValue_t check();
uint8_t getFuseId() const; uint8_t getFuseId() const;
ReturnValue_t initialize(); ReturnValue_t initialize() override;
DeviceList devices; DeviceList devices;
ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize, ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize,
SerializeIF::Endianness streamEndianness) const override; SerializeIF::Endianness streamEndianness) const override;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
#ifndef FSFW_PUS_CSERVICE201HEALTHCOMMANDING_H_ #ifndef FSFW_PUS_CSERVICE201HEALTHCOMMANDING_H_
#define FSFW_PUS_CSERVICE201HEALTHCOMMANDING_H_ #define FSFW_PUS_CSERVICE201HEALTHCOMMANDING_H_
#include "../tmtcservices/CommandingServiceBase.h" #include "fsfw/tmtcservices/CommandingServiceBase.h"
/** /**
* @brief Custom PUS service to set health of all objects * @brief Custom PUS service to set health of all objects
@ -21,7 +21,7 @@ class CService201HealthCommanding : public CommandingServiceBase {
public: public:
CService201HealthCommanding(object_id_t objectId, uint16_t apid, uint8_t serviceId, CService201HealthCommanding(object_id_t objectId, uint16_t apid, uint8_t serviceId,
uint8_t numParallelCommands = 4, uint16_t commandTimeoutSeconds = 60); uint8_t numParallelCommands = 4, uint16_t commandTimeoutSeconds = 60);
virtual ~CService201HealthCommanding(); ~CService201HealthCommanding() override = default;
protected: protected:
/* CSB abstract function implementations */ /* CSB abstract function implementations */
@ -38,12 +38,10 @@ class CService201HealthCommanding : public CommandingServiceBase {
bool *isStep) override; bool *isStep) override;
private: private:
ReturnValue_t checkAndAcquireTargetID(object_id_t *objectIdToSet, const uint8_t *tcData, static ReturnValue_t checkInterfaceAndAcquireMessageQueue(MessageQueueId_t *MessageQueueToSet,
size_t tcDataLen); const object_id_t *objectId);
ReturnValue_t checkInterfaceAndAcquireMessageQueue(MessageQueueId_t *MessageQueueToSet,
object_id_t *objectId);
ReturnValue_t prepareHealthSetReply(const CommandMessage *reply); [[maybe_unused]] ReturnValue_t prepareHealthSetReply(const CommandMessage *reply);
enum Subservice { enum Subservice {
//! [EXPORT] : [TC] Set health of target object //! [EXPORT] : [TC] Set health of target object

View File

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

View File

@ -30,11 +30,11 @@ ReturnValue_t Subsystem::checkSequence(HybridIterator<ModeListEntry> iter,
return FALLBACK_SEQUENCE_DOES_NOT_EXIST; return FALLBACK_SEQUENCE_DOES_NOT_EXIST;
} }
if (iter.value == NULL) { if (iter.value == nullptr) {
return NO_TARGET_TABLE; return NO_TARGET_TABLE;
} }
for (; iter.value != NULL; ++iter) { for (; iter.value != nullptr; ++iter) {
if (!existsModeTable(iter->getTableId())) { if (!existsModeTable(iter->getTableId())) {
return TABLE_DOES_NOT_EXIST; return TABLE_DOES_NOT_EXIST;
} else { } else {
@ -66,13 +66,18 @@ HybridIterator<ModeListEntry> Subsystem::getCurrentTable() {
void Subsystem::performChildOperation() { void Subsystem::performChildOperation() {
if (isInTransition) { if (isInTransition) {
if (commandsOutstanding <= 0) { // all children of the current table were commanded and replied if (commandsOutstanding <= 0) { // all children of the current table were commanded and replied
if (currentSequenceIterator.value == NULL) { // we're through with this sequence if (currentSequenceIterator.value == nullptr) { // we're through with this sequence
if (checkStateAgainstTable(currentTargetTable, targetSubmode) == RETURN_OK) { if (checkStateAgainstTable(currentTargetTable, targetSubmode) == RETURN_OK) {
setMode(targetMode, targetSubmode); setMode(targetMode, targetSubmode);
isInTransition = false; isInTransition = false;
return; return;
} else { } else {
transitionFailed(TARGET_TABLE_NOT_REACHED, getSequence(targetMode)->getTableId()); Mode_t tableId = 0;
auto seq = getSequence(targetMode);
if (seq.value != nullptr) {
tableId = seq->getTableId();
}
transitionFailed(TARGET_TABLE_NOT_REACHED, tableId);
return; return;
} }
} }
@ -248,10 +253,13 @@ ReturnValue_t Subsystem::handleCommandMessage(CommandMessage *message) {
case ModeSequenceMessage::READ_TABLE: { case ModeSequenceMessage::READ_TABLE: {
ReturnValue_t result; ReturnValue_t result;
Mode_t table = ModeSequenceMessage::getSequenceId(message); Mode_t table = ModeSequenceMessage::getSequenceId(message);
EntryPointer *entry = NULL; EntryPointer *entry = nullptr;
result = modeTables.find(table, &entry); result = modeTables.find(table, &entry);
if (result != RETURN_OK) { if (result != RETURN_OK or entry == nullptr) {
replyToCommand(result, 0); replyToCommand(result, 0);
if (entry == nullptr) {
return result;
}
} }
SerializeIF *elements[2]; SerializeIF *elements[2];
@ -299,6 +307,11 @@ void Subsystem::replyToCommand(ReturnValue_t status, uint32_t parameter) {
} }
} }
ReturnValue_t Subsystem::addSequence(SequenceEntry sequence) {
return addSequence(sequence.table, sequence.mode, sequence.fallbackMode, sequence.inStore,
sequence.preInit);
}
ReturnValue_t Subsystem::addSequence(ArrayList<ModeListEntry> *sequence, Mode_t id, ReturnValue_t Subsystem::addSequence(ArrayList<ModeListEntry> *sequence, Mode_t id,
Mode_t fallbackSequence, bool inStore, bool preInit) { Mode_t fallbackSequence, bool inStore, bool preInit) {
ReturnValue_t result; ReturnValue_t result;
@ -342,6 +355,10 @@ ReturnValue_t Subsystem::addSequence(ArrayList<ModeListEntry> *sequence, Mode_t
return result; return result;
} }
ReturnValue_t Subsystem::addTable(TableEntry table) {
return addTable(table.table, table.mode, table.inStore, table.preInit);
}
ReturnValue_t Subsystem::addTable(ArrayList<ModeListEntry> *table, Mode_t id, bool inStore, ReturnValue_t Subsystem::addTable(ArrayList<ModeListEntry> *table, Mode_t id, bool inStore,
bool preInit) { bool preInit) {
ReturnValue_t result; ReturnValue_t result;
@ -450,6 +467,7 @@ ReturnValue_t Subsystem::initialize() {
} }
mode = initialMode; mode = initialMode;
submode = initSubmode;
return RETURN_OK; return RETURN_OK;
} }
@ -587,7 +605,10 @@ ReturnValue_t Subsystem::checkObjectConnections() {
return RETURN_OK; return RETURN_OK;
} }
void Subsystem::setInitialMode(Mode_t mode) { initialMode = mode; } void Subsystem::setInitialMode(Mode_t mode, Submode_t submode) {
this->initialMode = mode;
this->initSubmode = submode;
}
void Subsystem::cantKeepMode() { void Subsystem::cantKeepMode() {
ReturnValue_t result; ReturnValue_t result;

View File

@ -1,16 +1,37 @@
#ifndef FSFW_SUBSYSTEM_SUBSYSTEM_H_ #ifndef FSFW_SUBSYSTEM_SUBSYSTEM_H_
#define FSFW_SUBSYSTEM_SUBSYSTEM_H_ #define FSFW_SUBSYSTEM_SUBSYSTEM_H_
#include <FSFWConfig.h>
#include "../container/FixedArrayList.h" #include "../container/FixedArrayList.h"
#include "../container/FixedMap.h" #include "../container/FixedMap.h"
#include "../container/HybridIterator.h" #include "../container/HybridIterator.h"
#include "../container/SinglyLinkedList.h" #include "../container/SinglyLinkedList.h"
#include "../serialize/SerialArrayListAdapter.h" #include "../serialize/SerialArrayListAdapter.h"
#include "SubsystemBase.h" #include "SubsystemBase.h"
#include "fsfw/FSFW.h"
#include "modes/ModeDefinitions.h" #include "modes/ModeDefinitions.h"
struct TableSequenceBase {
public:
TableSequenceBase(Mode_t mode, ArrayList<ModeListEntry> *table) : mode(mode), table(table){};
Mode_t mode;
ArrayList<ModeListEntry> *table;
bool inStore = false;
bool preInit = true;
};
struct TableEntry : public TableSequenceBase {
public:
TableEntry(Mode_t mode, ArrayList<ModeListEntry> *table) : TableSequenceBase(mode, table){};
};
struct SequenceEntry : public TableSequenceBase {
public:
SequenceEntry(Mode_t mode, ArrayList<ModeListEntry> *table, Mode_t fallbackMode)
: TableSequenceBase(mode, table), fallbackMode(fallbackMode) {}
Mode_t fallbackMode;
};
/** /**
* @brief TODO: documentation missing * @brief TODO: documentation missing
* @details * @details
@ -45,13 +66,15 @@ class Subsystem : public SubsystemBase, public HasModeSequenceIF {
uint32_t maxNumberOfTables); uint32_t maxNumberOfTables);
virtual ~Subsystem(); virtual ~Subsystem();
ReturnValue_t addSequence(SequenceEntry sequence);
ReturnValue_t addSequence(ArrayList<ModeListEntry> *sequence, Mode_t id, Mode_t fallbackSequence, ReturnValue_t addSequence(ArrayList<ModeListEntry> *sequence, Mode_t id, Mode_t fallbackSequence,
bool inStore = true, bool preInit = true); bool inStore = true, bool preInit = true);
ReturnValue_t addTable(TableEntry table);
ReturnValue_t addTable(ArrayList<ModeListEntry> *table, Mode_t id, bool inStore = true, ReturnValue_t addTable(ArrayList<ModeListEntry> *table, Mode_t id, bool inStore = true,
bool preInit = true); bool preInit = true);
void setInitialMode(Mode_t mode); void setInitialMode(Mode_t mode, Submode_t submode = SUBMODE_NONE);
virtual ReturnValue_t initialize() override; virtual ReturnValue_t initialize() override;
@ -90,6 +113,7 @@ class Subsystem : public SubsystemBase, public HasModeSequenceIF {
Submode_t targetSubmode; Submode_t targetSubmode;
Mode_t initialMode = 0; Mode_t initialMode = 0;
Submode_t initSubmode = SUBMODE_NONE;
HybridIterator<ModeListEntry> currentSequenceIterator; HybridIterator<ModeListEntry> currentSequenceIterator;
@ -127,18 +151,18 @@ class Subsystem : public SubsystemBase, public HasModeSequenceIF {
ReturnValue_t deleteTable(Mode_t id); ReturnValue_t deleteTable(Mode_t id);
virtual void performChildOperation(); virtual void performChildOperation() override;
virtual ReturnValue_t handleCommandMessage(CommandMessage *message); virtual ReturnValue_t handleCommandMessage(CommandMessage *message) override;
bool isFallbackSequence(Mode_t SequenceId); bool isFallbackSequence(Mode_t SequenceId);
bool isTableUsed(Mode_t tableId); bool isTableUsed(Mode_t tableId);
virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
uint32_t *msToReachTheMode); uint32_t *msToReachTheMode) override;
virtual void startTransition(Mode_t mode, Submode_t submode); virtual void startTransition(Mode_t mode, Submode_t submode) override;
void sendSerializablesAsCommandMessage(Command_t command, SerializeIF **elements, uint8_t count); void sendSerializablesAsCommandMessage(Command_t command, SerializeIF **elements, uint8_t count);

View File

@ -123,15 +123,15 @@ class SubsystemBase : public SystemObject,
virtual void performChildOperation() = 0; virtual void performChildOperation() = 0;
virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
uint32_t *msToReachTheMode) = 0; uint32_t *msToReachTheMode) override = 0;
virtual void startTransition(Mode_t mode, Submode_t submode) = 0; virtual void startTransition(Mode_t mode, Submode_t submode) override = 0;
virtual void getMode(Mode_t *mode, Submode_t *submode); virtual void getMode(Mode_t *mode, Submode_t *submode) override;
virtual void setToExternalControl(); virtual void setToExternalControl() override;
virtual void announceMode(bool recursive); virtual void announceMode(bool recursive) override;
virtual void modeChanged(); virtual void modeChanged();
}; };

View File

@ -6,10 +6,6 @@
#include "fsfw/FSFW.h" #include "fsfw/FSFW.h"
CCSDSTime::CCSDSTime() {}
CCSDSTime::~CCSDSTime() {}
ReturnValue_t CCSDSTime::convertToCcsds(Ccs_seconds* to, const Clock::TimeOfDay_t* from) { ReturnValue_t CCSDSTime::convertToCcsds(Ccs_seconds* to, const Clock::TimeOfDay_t* from) {
ReturnValue_t result = checkTimeOfDay(from); ReturnValue_t result = checkTimeOfDay(from);
if (result != RETURN_OK) { if (result != RETURN_OK) {
@ -91,7 +87,7 @@ ReturnValue_t CCSDSTime::convertFromCDS(Clock::TimeOfDay_t* to, const uint8_t* f
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
return result; return result;
} }
return convertTimevalToTimeOfDay(to, &time); return Clock::convertTimevalToTimeOfDay(&time, to);
} }
ReturnValue_t CCSDSTime::convertFromCCS(Clock::TimeOfDay_t* to, const uint8_t* from, ReturnValue_t CCSDSTime::convertFromCCS(Clock::TimeOfDay_t* to, const uint8_t* from,
@ -428,7 +424,7 @@ ReturnValue_t CCSDSTime::convertFromCUC(timeval* to, const uint8_t* from, size_t
from++; from++;
ReturnValue_t result = convertFromCUC(to, pField, from, foundLength, maxLength - 1); ReturnValue_t result = convertFromCUC(to, pField, from, foundLength, maxLength - 1);
if (result == HasReturnvaluesIF::RETURN_OK) { if (result == HasReturnvaluesIF::RETURN_OK) {
if (foundLength != NULL) { if (foundLength != nullptr) {
*foundLength += 1; *foundLength += 1;
} }
} }
@ -489,11 +485,6 @@ ReturnValue_t CCSDSTime::checkTimeOfDay(const Clock::TimeOfDay_t* time) {
return RETURN_OK; return RETURN_OK;
} }
ReturnValue_t CCSDSTime::convertTimevalToTimeOfDay(Clock::TimeOfDay_t* to, timeval* from) {
// This is rather tricky. Implement only if needed. Also, if so, move to OSAL.
return UNSUPPORTED_TIME_FORMAT;
}
ReturnValue_t CCSDSTime::convertFromCDS(timeval* to, const uint8_t* from, size_t* foundLength, ReturnValue_t CCSDSTime::convertFromCDS(timeval* to, const uint8_t* from, size_t* foundLength,
size_t maxLength) { size_t maxLength) {
uint8_t pField = *from; uint8_t pField = *from;
@ -583,7 +574,7 @@ ReturnValue_t CCSDSTime::convertFromCDS(Clock::TimeOfDay_t* to, const CCSDSTime:
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
return result; return result;
} }
return CCSDSTime::convertTimevalToTimeOfDay(to, &tempTimeval); return Clock::convertTimevalToTimeOfDay(&tempTimeval, to);
} }
ReturnValue_t CCSDSTime::convertFromCUC(timeval* to, uint8_t pField, const uint8_t* from, ReturnValue_t CCSDSTime::convertFromCUC(timeval* to, uint8_t pField, const uint8_t* from,
@ -593,18 +584,18 @@ ReturnValue_t CCSDSTime::convertFromCUC(timeval* to, uint8_t pField, const uint8
uint8_t nCoarse = ((pField & 0b1100) >> 2) + 1; uint8_t nCoarse = ((pField & 0b1100) >> 2) + 1;
uint8_t nFine = (pField & 0b11); uint8_t nFine = (pField & 0b11);
size_t totalLength = nCoarse + nFine; size_t totalLength = nCoarse + nFine;
if (foundLength != NULL) { if (foundLength != nullptr) {
*foundLength = totalLength; *foundLength = totalLength;
} }
if (totalLength > maxLength) { if (totalLength > maxLength) {
return LENGTH_MISMATCH; return LENGTH_MISMATCH;
} }
for (int count = 0; count < nCoarse; count++) { for (int count = nCoarse; count > 0; count--) {
secs += *from << ((nCoarse * 8 - 8) * (1 + count)); secs += *from << (count * 8 - 8);
from++; from++;
} }
for (int count = 0; count < nFine; count++) { for (int count = nFine; count > 0; count--) {
subSeconds += *from << ((nFine * 8 - 8) * (1 + count)); subSeconds += *from << (count * 8 - 8);
from++; from++;
} }
// Move to POSIX epoch. // Move to POSIX epoch.

View File

@ -161,18 +161,37 @@ class CCSDSTime : public HasReturnvaluesIF {
*/ */
static ReturnValue_t convertFromCcsds(timeval *to, uint8_t const *from, size_t *foundLength, static ReturnValue_t convertFromCcsds(timeval *to, uint8_t const *from, size_t *foundLength,
size_t maxLength); size_t maxLength);
/**
* @brief Currently unsupported conversion due to leapseconds
*
* @param to Time Of Day (UTC)
* @param from Buffer to take the CUC from
* @param length Length of buffer
* @return ReturnValue_t UNSUPPORTED_TIME_FORMAT in any case ATM
*/
static ReturnValue_t convertFromCUC(Clock::TimeOfDay_t *to, uint8_t const *from, uint8_t length); static ReturnValue_t convertFromCUC(Clock::TimeOfDay_t *to, uint8_t const *from, uint8_t length);
/**
* @brief Converts from CCSDS CUC to timeval
*
* If input is CCSDS Epoch this is TAI! -> No leapsecond support.
*
* Currently, it only supports seconds + 2 Byte Subseconds (1/65536 seconds)
*
*
* @param to Timeval to write the result to
* @param from Buffer to read from
* @param foundLength Length found by this function (can be nullptr if unused)
* @param maxLength Max length of the buffer to be read
* @return ReturnValue_t - RETURN_OK if successful
* - LENGTH_MISMATCH if expected length is larger than maxLength
*/
static ReturnValue_t convertFromCUC(timeval *to, uint8_t const *from, size_t *foundLength, static ReturnValue_t convertFromCUC(timeval *to, uint8_t const *from, size_t *foundLength,
size_t maxLength); size_t maxLength);
static ReturnValue_t convertFromCUC(timeval *to, uint8_t pField, uint8_t const *from, static ReturnValue_t convertFromCUC(timeval *to, uint8_t pField, uint8_t const *from,
size_t *foundLength, size_t maxLength); size_t *foundLength, size_t maxLength);
static ReturnValue_t convertFromCCS(timeval *to, uint8_t const *from, size_t *foundLength, static ReturnValue_t convertFromCCS(timeval *to, uint8_t const *from, size_t *foundLength,
size_t maxLength); size_t maxLength);
static ReturnValue_t convertFromCCS(timeval *to, uint8_t pField, uint8_t const *from, static ReturnValue_t convertFromCCS(timeval *to, uint8_t pField, uint8_t const *from,
size_t *foundLength, size_t maxLength); size_t *foundLength, size_t maxLength);
@ -192,8 +211,8 @@ class CCSDSTime : public HasReturnvaluesIF {
static uint32_t subsecondsToMicroseconds(uint16_t subseconds); static uint32_t subsecondsToMicroseconds(uint16_t subseconds);
private: private:
CCSDSTime(); CCSDSTime(){};
virtual ~CCSDSTime(); virtual ~CCSDSTime(){};
/** /**
* checks a ccs time stream for validity * checks a ccs time stream for validity
* *
@ -223,7 +242,6 @@ class CCSDSTime : public HasReturnvaluesIF {
uint8_t *day); uint8_t *day);
static bool isLeapYear(uint32_t year); static bool isLeapYear(uint32_t year);
static ReturnValue_t convertTimevalToTimeOfDay(Clock::TimeOfDay_t *to, timeval *from);
}; };
#endif /* FSFW_TIMEMANAGER_CCSDSTIME_H_ */ #endif /* FSFW_TIMEMANAGER_CCSDSTIME_H_ */

View File

@ -99,6 +99,13 @@ class Clock {
*/ */
static ReturnValue_t getDateAndTime(TimeOfDay_t *time); static ReturnValue_t getDateAndTime(TimeOfDay_t *time);
/**
* Convert to time of day struct given the POSIX timeval struct
* @param from
* @param to
* @return
*/
static ReturnValue_t convertTimevalToTimeOfDay(const timeval *from, TimeOfDay_t *to);
/** /**
* Converts a time of day struct to POSIX seconds. * Converts a time of day struct to POSIX seconds.
* @param time The time of day as input * @param time The time of day as input
@ -166,6 +173,7 @@ class Clock {
static MutexIF *timeMutex; static MutexIF *timeMutex;
static uint16_t leapSeconds; static uint16_t leapSeconds;
static bool leapSecondsSet;
}; };
#endif /* FSFW_TIMEMANAGER_CLOCK_H_ */ #endif /* FSFW_TIMEMANAGER_CLOCK_H_ */

View File

@ -1,7 +1,13 @@
#include <ctime>
#include "fsfw/ipc/MutexGuard.h" #include "fsfw/ipc/MutexGuard.h"
#include "fsfw/timemanager/Clock.h" #include "fsfw/timemanager/Clock.h"
ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval *tt) { uint16_t Clock::leapSeconds = 0;
MutexIF* Clock::timeMutex = nullptr;
bool Clock::leapSecondsSet = false;
ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) {
uint16_t leapSeconds; uint16_t leapSeconds;
ReturnValue_t result = getLeapSeconds(&leapSeconds); ReturnValue_t result = getLeapSeconds(&leapSeconds);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
@ -27,12 +33,16 @@ ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) {
MutexGuard helper(timeMutex); MutexGuard helper(timeMutex);
leapSeconds = leapSeconds_; leapSeconds = leapSeconds_;
leapSecondsSet = true;
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t Clock::getLeapSeconds(uint16_t *leapSeconds_) { ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) {
if (timeMutex == nullptr) { if (not leapSecondsSet) {
return HasReturnvaluesIF::RETURN_FAILED;
}
if (checkOrCreateClockMutex() != HasReturnvaluesIF::RETURN_OK) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
MutexGuard helper(timeMutex); MutexGuard helper(timeMutex);
@ -42,9 +52,32 @@ ReturnValue_t Clock::getLeapSeconds(uint16_t *leapSeconds_) {
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t Clock::convertTimevalToTimeOfDay(const timeval* from, TimeOfDay_t* to) {
struct tm* timeInfo;
// According to https://en.cppreference.com/w/c/chrono/gmtime, the implementation of gmtime_s
// in the Windows CRT is incompatible with the C standard but this should not be an issue for
// this implementation
ReturnValue_t result = checkOrCreateClockMutex();
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
MutexGuard helper(timeMutex);
// gmtime writes its output in a global buffer which is not Thread Safe
// Therefore we have to use a Mutex here
timeInfo = gmtime(&from->tv_sec);
to->year = timeInfo->tm_year + 1900;
to->month = timeInfo->tm_mon + 1;
to->day = timeInfo->tm_mday;
to->hour = timeInfo->tm_hour;
to->minute = timeInfo->tm_min;
to->second = timeInfo->tm_sec;
to->usecond = from->tv_usec;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::checkOrCreateClockMutex() { ReturnValue_t Clock::checkOrCreateClockMutex() {
if (timeMutex == nullptr) { if (timeMutex == nullptr) {
MutexFactory *mutexFactory = MutexFactory::instance(); MutexFactory* mutexFactory = MutexFactory::instance();
if (mutexFactory == nullptr) { if (mutexFactory == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }

View File

@ -19,8 +19,8 @@ SpacePacket::SpacePacket(uint16_t packetDataLength, bool isTelecommand, uint16_t
SpacePacket::~SpacePacket(void) {} SpacePacket::~SpacePacket(void) {}
bool SpacePacket::addWholeData(const uint8_t* p_Data, uint32_t packet_size) { bool SpacePacket::addWholeData(const uint8_t* p_Data, uint32_t packet_size) {
if (packet_size <= sizeof(this->data)) { if (packet_size <= sizeof(this->localData)) {
memcpy(&this->localData.byteStream, p_Data, packet_size); memcpy(this->localData.byteStream, p_Data, packet_size);
return true; return true;
} else { } else {
return false; return false;

View File

@ -95,7 +95,7 @@ class CommandingServiceBase : public SystemObject,
*/ */
virtual ReturnValue_t performOperation(uint8_t opCode) override; virtual ReturnValue_t performOperation(uint8_t opCode) override;
virtual uint16_t getIdentifier(); virtual uint16_t getIdentifier() override;
/** /**
* Returns the requestQueue MessageQueueId_t * Returns the requestQueue MessageQueueId_t
@ -104,7 +104,7 @@ class CommandingServiceBase : public SystemObject,
* *
* @return requestQueue messageQueueId_t * @return requestQueue messageQueueId_t
*/ */
virtual MessageQueueId_t getRequestQueue(); virtual MessageQueueId_t getRequestQueue() override;
/** /**
* Returns the commandQueue MessageQueueId_t * Returns the commandQueue MessageQueueId_t
@ -166,7 +166,7 @@ class CommandingServiceBase : public SystemObject,
* @param objectId Target object ID * @param objectId Target object ID
* @return * @return
* - @c RETURN_OK to generate a verification start message * - @c RETURN_OK to generate a verification start message
* - @c EXECUTION_COMPELTE Fire-and-forget command. Generate a completion * - @c EXECUTION_COMPLETE Fire-and-forget command. Generate a completion
* verification message. * verification message.
* - @c Anything else rejects the packets and generates a start failure * - @c Anything else rejects the packets and generates a start failure
* verification. * verification.

View File

@ -1,8 +1,9 @@
#include "version.h" #include "version.h"
#include "fsfw/FSFWVersion.h"
#include <cstdio> #include <cstdio>
#include "fsfw/FSFWVersion.h"
#ifdef major #ifdef major
#undef major #undef major
#endif #endif

View File

@ -29,7 +29,7 @@ class Version {
} }
friend bool operator>(const Version& v1, const Version& v2) { friend bool operator>(const Version& v1, const Version& v2) {
return not (v1 < v2) and not (v1 == v2); return not(v1 < v2) and not(v1 == v2);
} }
friend bool operator<=(const Version& v1, const Version& v2) { return ((v1 == v2) or (v1 < v2)); } friend bool operator<=(const Version& v1, const Version& v2) { return ((v1 == v2) or (v1 < v2)); }

View File

@ -11,7 +11,10 @@ target_sources(${FSFW_TEST_TGT} PRIVATE
) )
add_subdirectory(testcfg) add_subdirectory(testcfg)
add_subdirectory(mocks)
add_subdirectory(action) add_subdirectory(action)
add_subdirectory(power)
add_subdirectory(container) add_subdirectory(container)
add_subdirectory(osal) add_subdirectory(osal)
add_subdirectory(serialize) add_subdirectory(serialize)

View File

@ -21,8 +21,10 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") {
REQUIRE(poolOwner->initializeHkManager() == retval::CATCH_OK); REQUIRE(poolOwner->initializeHkManager() == retval::CATCH_OK);
REQUIRE(poolOwner->initializeHkManagerAfterTaskCreation() == retval::CATCH_OK); REQUIRE(poolOwner->initializeHkManagerAfterTaskCreation() == retval::CATCH_OK);
MessageQueueMockBase* mqMock = poolOwner->getMockQueueHandle(); MessageQueueMockBase* poolOwnerMock = poolOwner->getMockQueueHandle();
REQUIRE(mqMock != nullptr); REQUIRE(poolOwnerMock != nullptr);
// MessageQueueIF* hkCommander = QueueFactory::instance()->createMessageQueue();
CommandMessage messageSent; CommandMessage messageSent;
uint8_t messagesSent = 0; uint8_t messagesSent = 0;
@ -41,9 +43,9 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") {
poolOwner->dataset.setChanged(true); poolOwner->dataset.setChanged(true);
/* Now the update message should be generated. */ /* Now the update message should be generated. */
REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK); REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK);
REQUIRE(mqMock->wasMessageSent() == true); REQUIRE(poolOwnerMock->wasMessageSent() == true);
REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK); REQUIRE(poolOwnerMock->receiveMessage(&messageSent) == retval::CATCH_OK);
CHECK(messageSent.getCommand() == CHECK(messageSent.getCommand() ==
static_cast<int>(HousekeepingMessage::UPDATE_NOTIFICATION_SET)); static_cast<int>(HousekeepingMessage::UPDATE_NOTIFICATION_SET));
@ -53,9 +55,9 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") {
poolOwner->dataset.setChanged(true); poolOwner->dataset.setChanged(true);
REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK); REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK);
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
CHECK(messagesSent == 1); CHECK(messagesSent == 1);
REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK); REQUIRE(poolOwnerMock->receiveMessage(&messageSent) == retval::CATCH_OK);
CHECK(messageSent.getCommand() == CHECK(messageSent.getCommand() ==
static_cast<int>(HousekeepingMessage::UPDATE_NOTIFICATION_SET)); static_cast<int>(HousekeepingMessage::UPDATE_NOTIFICATION_SET));
@ -63,15 +65,15 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") {
REQUIRE(poolOwner->subscribeWrapperSetUpdateHk() == retval::CATCH_OK); REQUIRE(poolOwner->subscribeWrapperSetUpdateHk() == retval::CATCH_OK);
poolOwner->dataset.setChanged(true); poolOwner->dataset.setChanged(true);
REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK); REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK);
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
CHECK(messagesSent == 2); CHECK(messagesSent == 2);
/* first message sent should be the update notification, considering /* first message sent should be the update notification, considering
the internal list is a vector checked in insertion order. */ the internal list is a vector checked in insertion order. */
REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK); REQUIRE(poolOwnerMock->receiveMessage(&messageSent) == retval::CATCH_OK);
CHECK(messageSent.getCommand() == CHECK(messageSent.getCommand() ==
static_cast<int>(HousekeepingMessage::UPDATE_NOTIFICATION_SET)); static_cast<int>(HousekeepingMessage::UPDATE_NOTIFICATION_SET));
REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK); REQUIRE(poolOwnerMock->receiveMessage(&messageSent) == retval::CATCH_OK);
CHECK(messageSent.getCommand() == static_cast<int>(HousekeepingMessage::HK_REPORT)); CHECK(messageSent.getCommand() == static_cast<int>(HousekeepingMessage::HK_REPORT));
/* Clear message to avoid memory leak, our mock won't do it for us (yet) */ /* Clear message to avoid memory leak, our mock won't do it for us (yet) */
CommandMessageCleaner::clearCommandMessage(&messageSent); CommandMessageCleaner::clearCommandMessage(&messageSent);
@ -99,9 +101,9 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") {
/* Trigger generation of snapshot */ /* Trigger generation of snapshot */
REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK); REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK);
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
CHECK(messagesSent == 1); CHECK(messagesSent == 1);
REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK); REQUIRE(poolOwnerMock->receiveMessage(&messageSent) == retval::CATCH_OK);
/* Check that snapshot was generated */ /* Check that snapshot was generated */
CHECK(messageSent.getCommand() == static_cast<int>(HousekeepingMessage::UPDATE_SNAPSHOT_SET)); CHECK(messageSent.getCommand() == static_cast<int>(HousekeepingMessage::UPDATE_SNAPSHOT_SET));
/* Now we deserialize the snapshot into a new dataset instance */ /* Now we deserialize the snapshot into a new dataset instance */
@ -162,12 +164,12 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") {
REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK); REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK);
/* Check update snapshot was sent. */ /* Check update snapshot was sent. */
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
CHECK(messagesSent == 1); CHECK(messagesSent == 1);
/* Should have been reset. */ /* Should have been reset. */
CHECK(poolVar->hasChanged() == false); CHECK(poolVar->hasChanged() == false);
REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK); REQUIRE(poolOwnerMock->receiveMessage(&messageSent) == retval::CATCH_OK);
CHECK(messageSent.getCommand() == CHECK(messageSent.getCommand() ==
static_cast<int>(HousekeepingMessage::UPDATE_SNAPSHOT_VARIABLE)); static_cast<int>(HousekeepingMessage::UPDATE_SNAPSHOT_VARIABLE));
/* Now we deserialize the snapshot into a new dataset instance */ /* Now we deserialize the snapshot into a new dataset instance */
@ -209,11 +211,11 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") {
REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK); REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK);
/* Check update notification was sent. */ /* Check update notification was sent. */
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
CHECK(messagesSent == 1); CHECK(messagesSent == 1);
/* Should have been reset. */ /* Should have been reset. */
CHECK(poolVar->hasChanged() == false); CHECK(poolVar->hasChanged() == false);
REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK); REQUIRE(poolOwnerMock->receiveMessage(&messageSent) == retval::CATCH_OK);
CHECK(messageSent.getCommand() == CHECK(messageSent.getCommand() ==
static_cast<int>(HousekeepingMessage::UPDATE_NOTIFICATION_VARIABLE)); static_cast<int>(HousekeepingMessage::UPDATE_NOTIFICATION_VARIABLE));
/* Now subscribe for the dataset update (HK and update) again with subscription interface */ /* Now subscribe for the dataset update (HK and update) again with subscription interface */
@ -225,26 +227,26 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") {
poolOwner->dataset.setChanged(true); poolOwner->dataset.setChanged(true);
REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK); REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK);
/* Now two messages should be sent. */ /* Now two messages should be sent. */
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
CHECK(messagesSent == 2); CHECK(messagesSent == 2);
mqMock->clearMessages(true); poolOwnerMock->clearMessages(true);
poolOwner->dataset.setChanged(true); poolOwner->dataset.setChanged(true);
poolVar->setChanged(true); poolVar->setChanged(true);
REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK); REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK);
/* Now three messages should be sent. */ /* Now three messages should be sent. */
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
CHECK(messagesSent == 3); CHECK(messagesSent == 3);
REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK); REQUIRE(poolOwnerMock->receiveMessage(&messageSent) == retval::CATCH_OK);
CHECK(messageSent.getCommand() == CHECK(messageSent.getCommand() ==
static_cast<int>(HousekeepingMessage::UPDATE_NOTIFICATION_VARIABLE)); static_cast<int>(HousekeepingMessage::UPDATE_NOTIFICATION_VARIABLE));
REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK); REQUIRE(poolOwnerMock->receiveMessage(&messageSent) == retval::CATCH_OK);
CHECK(messageSent.getCommand() == CHECK(messageSent.getCommand() ==
static_cast<int>(HousekeepingMessage::UPDATE_NOTIFICATION_SET)); static_cast<int>(HousekeepingMessage::UPDATE_NOTIFICATION_SET));
REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK); REQUIRE(poolOwnerMock->receiveMessage(&messageSent) == retval::CATCH_OK);
CHECK(messageSent.getCommand() == static_cast<int>(HousekeepingMessage::HK_REPORT)); CHECK(messageSent.getCommand() == static_cast<int>(HousekeepingMessage::HK_REPORT));
CommandMessageCleaner::clearCommandMessage(&messageSent); CommandMessageCleaner::clearCommandMessage(&messageSent);
REQUIRE(mqMock->receiveMessage(&messageSent) == static_cast<int>(MessageQueueIF::EMPTY)); REQUIRE(poolOwnerMock->receiveMessage(&messageSent) == static_cast<int>(MessageQueueIF::EMPTY));
} }
SECTION("PeriodicHKAndMessaging") { SECTION("PeriodicHKAndMessaging") {
@ -255,38 +257,38 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") {
REQUIRE(poolOwner->subscribePeriodicHk(true) == retval::CATCH_OK); REQUIRE(poolOwner->subscribePeriodicHk(true) == retval::CATCH_OK);
REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK); REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK);
/* Now HK packet should be sent as message immediately. */ /* Now HK packet should be sent as message immediately. */
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
CHECK(messagesSent == 1); CHECK(messagesSent == 1);
CHECK(mqMock->popMessage() == retval::CATCH_OK); CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
LocalPoolDataSetBase* setHandle = poolOwner->getDataSetHandle(lpool::testSid); LocalPoolDataSetBase* setHandle = poolOwner->getDataSetHandle(lpool::testSid);
REQUIRE(setHandle != nullptr); REQUIRE(setHandle != nullptr);
CHECK(poolOwner->poolManager.generateHousekeepingPacket(lpool::testSid, setHandle, false) == CHECK(poolOwner->poolManager.generateHousekeepingPacket(lpool::testSid, setHandle, false) ==
retval::CATCH_OK); retval::CATCH_OK);
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
CHECK(messagesSent == 1); CHECK(messagesSent == 1);
CHECK(mqMock->popMessage() == retval::CATCH_OK); CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
CHECK(setHandle->getReportingEnabled() == true); CHECK(setHandle->getReportingEnabled() == true);
CommandMessage hkCmd; CommandMessage hkCmd;
HousekeepingMessage::setToggleReportingCommand(&hkCmd, lpool::testSid, false, false); HousekeepingMessage::setToggleReportingCommand(&hkCmd, lpool::testSid, false, false);
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK); CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK);
CHECK(setHandle->getReportingEnabled() == false); CHECK(setHandle->getReportingEnabled() == false);
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
CHECK(messagesSent == 1); CHECK(messagesSent == 1);
CHECK(mqMock->popMessage() == retval::CATCH_OK); CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
HousekeepingMessage::setToggleReportingCommand(&hkCmd, lpool::testSid, true, false); HousekeepingMessage::setToggleReportingCommand(&hkCmd, lpool::testSid, true, false);
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK); CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK);
CHECK(setHandle->getReportingEnabled() == true); CHECK(setHandle->getReportingEnabled() == true);
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
CHECK(mqMock->popMessage() == retval::CATCH_OK); CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
HousekeepingMessage::setToggleReportingCommand(&hkCmd, lpool::testSid, false, false); HousekeepingMessage::setToggleReportingCommand(&hkCmd, lpool::testSid, false, false);
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK); CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK);
CHECK(setHandle->getReportingEnabled() == false); CHECK(setHandle->getReportingEnabled() == false);
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
CHECK(mqMock->popMessage() == retval::CATCH_OK); CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
HousekeepingMessage::setCollectionIntervalModificationCommand(&hkCmd, lpool::testSid, 0.4, HousekeepingMessage::setCollectionIntervalModificationCommand(&hkCmd, lpool::testSid, 0.4,
false); false);
@ -294,23 +296,23 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") {
/* For non-diagnostics and a specified minimum frequency of 0.2 seconds, the /* For non-diagnostics and a specified minimum frequency of 0.2 seconds, the
resulting collection interval should be 1.0 second */ resulting collection interval should be 1.0 second */
CHECK(poolOwner->dataset.getCollectionInterval() == 1.0); CHECK(poolOwner->dataset.getCollectionInterval() == 1.0);
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
CHECK(messagesSent == 1); CHECK(messagesSent == 1);
CHECK(mqMock->popMessage() == retval::CATCH_OK); CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
HousekeepingMessage::setStructureReportingCommand(&hkCmd, lpool::testSid, false); HousekeepingMessage::setStructureReportingCommand(&hkCmd, lpool::testSid, false);
REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK); REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK);
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK); CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK);
/* Now HK packet should be sent as message. */ /* Now HK packet should be sent as message. */
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
CHECK(messagesSent == 1); CHECK(messagesSent == 1);
CHECK(mqMock->popMessage() == retval::CATCH_OK); CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
HousekeepingMessage::setOneShotReportCommand(&hkCmd, lpool::testSid, false); HousekeepingMessage::setOneShotReportCommand(&hkCmd, lpool::testSid, false);
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK); CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK);
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
CHECK(messagesSent == 1); CHECK(messagesSent == 1);
CHECK(mqMock->popMessage() == retval::CATCH_OK); CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
HousekeepingMessage::setUpdateNotificationSetCommand(&hkCmd, lpool::testSid); HousekeepingMessage::setUpdateNotificationSetCommand(&hkCmd, lpool::testSid);
sid_t sidToCheck; sid_t sidToCheck;
@ -326,62 +328,62 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") {
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) ==
static_cast<int>(LocalDataPoolManager::WRONG_HK_PACKET_TYPE)); static_cast<int>(LocalDataPoolManager::WRONG_HK_PACKET_TYPE));
/* We still expect a failure message being sent */ /* We still expect a failure message being sent */
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
CHECK(messagesSent == 1); CHECK(messagesSent == 1);
CHECK(mqMock->popMessage() == retval::CATCH_OK); CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
HousekeepingMessage::setCollectionIntervalModificationCommand(&hkCmd, lpool::testSid, 0.4, HousekeepingMessage::setCollectionIntervalModificationCommand(&hkCmd, lpool::testSid, 0.4,
false); false);
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) ==
static_cast<int>(LocalDataPoolManager::WRONG_HK_PACKET_TYPE)); static_cast<int>(LocalDataPoolManager::WRONG_HK_PACKET_TYPE));
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
CHECK(messagesSent == 1); CHECK(messagesSent == 1);
CHECK(mqMock->popMessage() == retval::CATCH_OK); CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
HousekeepingMessage::setStructureReportingCommand(&hkCmd, lpool::testSid, false); HousekeepingMessage::setStructureReportingCommand(&hkCmd, lpool::testSid, false);
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) ==
static_cast<int>(LocalDataPoolManager::WRONG_HK_PACKET_TYPE)); static_cast<int>(LocalDataPoolManager::WRONG_HK_PACKET_TYPE));
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
CHECK(messagesSent == 1); CHECK(messagesSent == 1);
CHECK(mqMock->popMessage() == retval::CATCH_OK); CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
HousekeepingMessage::setStructureReportingCommand(&hkCmd, lpool::testSid, true); HousekeepingMessage::setStructureReportingCommand(&hkCmd, lpool::testSid, true);
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK); CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK);
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
CHECK(messagesSent == 1); CHECK(messagesSent == 1);
CHECK(mqMock->popMessage() == retval::CATCH_OK); CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
HousekeepingMessage::setCollectionIntervalModificationCommand(&hkCmd, lpool::testSid, 0.4, HousekeepingMessage::setCollectionIntervalModificationCommand(&hkCmd, lpool::testSid, 0.4,
true); true);
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK); CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK);
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
CHECK(messagesSent == 1); CHECK(messagesSent == 1);
CHECK(mqMock->popMessage() == retval::CATCH_OK); CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
HousekeepingMessage::setToggleReportingCommand(&hkCmd, lpool::testSid, true, true); HousekeepingMessage::setToggleReportingCommand(&hkCmd, lpool::testSid, true, true);
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK); CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK);
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
CHECK(messagesSent == 1); CHECK(messagesSent == 1);
CHECK(mqMock->popMessage() == retval::CATCH_OK); CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
HousekeepingMessage::setToggleReportingCommand(&hkCmd, lpool::testSid, false, true); HousekeepingMessage::setToggleReportingCommand(&hkCmd, lpool::testSid, false, true);
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK); CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK);
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
CHECK(messagesSent == 1); CHECK(messagesSent == 1);
CHECK(mqMock->popMessage() == retval::CATCH_OK); CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
HousekeepingMessage::setOneShotReportCommand(&hkCmd, lpool::testSid, false); HousekeepingMessage::setOneShotReportCommand(&hkCmd, lpool::testSid, false);
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) ==
static_cast<int>(LocalDataPoolManager::WRONG_HK_PACKET_TYPE)); static_cast<int>(LocalDataPoolManager::WRONG_HK_PACKET_TYPE));
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
CHECK(messagesSent == 1); CHECK(messagesSent == 1);
CHECK(mqMock->popMessage() == retval::CATCH_OK); CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
HousekeepingMessage::setOneShotReportCommand(&hkCmd, lpool::testSid, true); HousekeepingMessage::setOneShotReportCommand(&hkCmd, lpool::testSid, true);
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK); CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK);
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
CHECK(messagesSent == 1); CHECK(messagesSent == 1);
CHECK(mqMock->popMessage() == retval::CATCH_OK); CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
HousekeepingMessage::setUpdateNotificationVariableCommand(&hkCmd, lpool::uint8VarGpid); HousekeepingMessage::setUpdateNotificationVariableCommand(&hkCmd, lpool::uint8VarGpid);
gp_id_t gpidToCheck; gp_id_t gpidToCheck;
@ -407,5 +409,5 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") {
/* we need to reset the subscription list because the pool owner /* we need to reset the subscription list because the pool owner
is a global object. */ is a global object. */
CHECK(poolOwner->reset() == retval::CATCH_OK); CHECK(poolOwner->reset() == retval::CATCH_OK);
mqMock->clearMessages(true); poolOwnerMock->clearMessages(true);
} }

View File

@ -3,4 +3,5 @@ target_sources(${FSFW_TEST_TGT} PRIVATE
testOpDivider.cpp testOpDivider.cpp
testBitutil.cpp testBitutil.cpp
testCRC.cpp testCRC.cpp
testTimevalOperations.cpp
) )

View File

@ -0,0 +1,124 @@
#include <fsfw/globalfunctions/timevalOperations.h>
#include <catch2/catch_approx.hpp>
#include <catch2/catch_test_macros.hpp>
#include "fsfw_tests/unit/CatchDefinitions.h"
TEST_CASE("TimevalTest", "[timevalOperations]") {
SECTION("Comparison") {
timeval t1;
t1.tv_sec = 1648227422;
t1.tv_usec = 123456;
timeval t2;
t2.tv_sec = 1648227422;
t2.tv_usec = 123456;
REQUIRE(t1 == t2);
REQUIRE(t2 == t1);
REQUIRE_FALSE(t1 != t2);
REQUIRE_FALSE(t2 != t1);
REQUIRE(t1 <= t2);
REQUIRE(t2 <= t1);
REQUIRE(t1 >= t2);
REQUIRE(t2 >= t1);
REQUIRE_FALSE(t1 < t2);
REQUIRE_FALSE(t2 < t1);
REQUIRE_FALSE(t1 > t2);
REQUIRE_FALSE(t2 > t1);
timeval t3;
t3.tv_sec = 1648227422;
t3.tv_usec = 123457;
REQUIRE_FALSE(t1 == t3);
REQUIRE(t1 != t3);
REQUIRE(t1 <= t3);
REQUIRE_FALSE(t3 <= t1);
REQUIRE_FALSE(t1 >= t3);
REQUIRE(t3 >= t1);
REQUIRE(t1 < t3);
REQUIRE_FALSE(t3 < t1);
REQUIRE_FALSE(t1 > t3);
REQUIRE(t3 > t1);
timeval t4;
t4.tv_sec = 1648227423;
t4.tv_usec = 123456;
REQUIRE_FALSE(t1 == t4);
REQUIRE(t1 != t4);
REQUIRE(t1 <= t4);
REQUIRE_FALSE(t4 <= t1);
REQUIRE_FALSE(t1 >= t4);
REQUIRE(t4 >= t1);
REQUIRE(t1 < t4);
REQUIRE_FALSE(t4 < t1);
REQUIRE_FALSE(t1 > t4);
REQUIRE(t4 > t1);
}
SECTION("Operators") {
timeval t1;
t1.tv_sec = 1648227422;
t1.tv_usec = 123456;
timeval t2;
t2.tv_sec = 1648227422;
t2.tv_usec = 123456;
timeval t3 = t1 - t2;
REQUIRE(t3.tv_sec == 0);
REQUIRE(t3.tv_usec == 0);
timeval t4 = t1 - t3;
REQUIRE(t4.tv_sec == 1648227422);
REQUIRE(t4.tv_usec == 123456);
timeval t5 = t3 - t1;
REQUIRE(t5.tv_sec == -1648227422);
REQUIRE(t5.tv_usec == -123456);
timeval t6;
t6.tv_sec = 1648227400;
t6.tv_usec = 999999;
timeval t7 = t6 + t1;
REQUIRE(t7.tv_sec == (1648227422ull + 1648227400ull + 1ull));
REQUIRE(t7.tv_usec == 123455);
timeval t8 = t1 - t6;
REQUIRE(t8.tv_sec == 1648227422 - 1648227400 - 1);
REQUIRE(t8.tv_usec == 123457);
double scalar = 2;
timeval t9 = t1 * scalar;
REQUIRE(t9.tv_sec == 3296454844);
REQUIRE(t9.tv_usec == 246912);
timeval t10 = scalar * t1;
REQUIRE(t10.tv_sec == 3296454844);
REQUIRE(t10.tv_usec == 246912);
timeval t11 = t6 * scalar;
REQUIRE(t11.tv_sec == (3296454800 + 1));
REQUIRE(t11.tv_usec == 999998);
timeval t12 = t1 / scalar;
REQUIRE(t12.tv_sec == 824113711);
REQUIRE(t12.tv_usec == 61728);
timeval t13 = t6 / scalar;
REQUIRE(t13.tv_sec == 824113700);
// Rounding issue
REQUIRE(t13.tv_usec == 499999);
double scalar2 = t9 / t1;
REQUIRE(scalar2 == Catch::Approx(2.0));
double scalar3 = t1 / t6;
REQUIRE(scalar3 == Catch::Approx(1.000000013));
double scalar4 = t3 / t1;
REQUIRE(scalar4 == Catch::Approx(0));
double scalar5 = t12 / t1;
REQUIRE(scalar5 == Catch::Approx(0.5));
}
SECTION("timevalOperations::toTimeval") {
double seconds = 1648227422.123456;
timeval t1 = timevalOperations::toTimeval(seconds);
REQUIRE(t1.tv_sec == 1648227422);
// Allow 1 usec rounding tolerance
REQUIRE(t1.tv_usec >= 123455);
REQUIRE(t1.tv_usec <= 123457);
}
}

View File

@ -0,0 +1,3 @@
target_sources(${FSFW_TEST_TGT} PRIVATE
PowerSwitcherMock.cpp
)

View File

@ -5,15 +5,17 @@
#include <queue> #include <queue>
#include "fsfw/ipc/CommandMessage.h" #include "fsfw/ipc/CommandMessage.h"
#include "fsfw/ipc/MessageQueueBase.h"
#include "fsfw/ipc/MessageQueueIF.h" #include "fsfw/ipc/MessageQueueIF.h"
#include "fsfw/ipc/MessageQueueMessage.h" #include "fsfw/ipc/MessageQueueMessage.h"
#include "fsfw_tests/unit/CatchDefinitions.h" #include "fsfw_tests/unit/CatchDefinitions.h"
class MessageQueueMockBase : public MessageQueueIF { class MessageQueueMockBase : public MessageQueueBase {
public: public:
MessageQueueId_t myQueueId = tconst::testQueueId; MessageQueueMockBase()
: MessageQueueBase(MessageQueueIF::NO_QUEUE, MessageQueueIF::NO_QUEUE, nullptr) {}
uint8_t messageSentCounter = 0; uint8_t messageSentCounter = 0;
bool defaultDestSet = false;
bool messageSent = false; bool messageSent = false;
bool wasMessageSent(uint8_t* messageSentCounter = nullptr, bool resetCounter = true) { bool wasMessageSent(uint8_t* messageSentCounter = nullptr, bool resetCounter = true) {
@ -38,39 +40,19 @@ class MessageQueueMockBase : public MessageQueueIF {
return receiveMessage(&message); return receiveMessage(&message);
} }
virtual ReturnValue_t reply(MessageQueueMessageIF* message) { virtual ReturnValue_t receiveMessage(MessageQueueMessageIF* message) override {
return sendMessage(myQueueId, message);
};
virtual ReturnValue_t receiveMessage(MessageQueueMessageIF* message,
MessageQueueId_t* receivedFrom) {
return receiveMessage(message);
}
virtual ReturnValue_t receiveMessage(MessageQueueMessageIF* message) {
if (messagesSentQueue.empty()) { if (messagesSentQueue.empty()) {
return MessageQueueIF::EMPTY; return MessageQueueIF::EMPTY;
} }
this->last = message->getSender();
std::memcpy(message->getBuffer(), messagesSentQueue.front().getBuffer(), std::memcpy(message->getBuffer(), messagesSentQueue.front().getBuffer(),
message->getMessageSize()); message->getMessageSize());
messagesSentQueue.pop(); messagesSentQueue.pop();
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
virtual ReturnValue_t flush(uint32_t* count) { return HasReturnvaluesIF::RETURN_OK; } virtual ReturnValue_t flush(uint32_t* count) { return HasReturnvaluesIF::RETURN_OK; }
virtual MessageQueueId_t getLastPartner() const { return myQueueId; }
virtual MessageQueueId_t getId() const { return myQueueId; }
virtual ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message, virtual ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
MessageQueueId_t sentFrom, bool ignoreFault = false) { MessageQueueId_t sentFrom,
return sendMessage(sendTo, message);
}
virtual ReturnValue_t sendToDefaultFrom(MessageQueueMessageIF* message, MessageQueueId_t sentFrom,
bool ignoreFault = false) {
return sendMessage(myQueueId, message);
}
virtual ReturnValue_t sendToDefault(MessageQueueMessageIF* message) {
return sendMessage(myQueueId, message);
}
virtual ReturnValue_t sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
bool ignoreFault = false) override { bool ignoreFault = false) override {
messageSent = true; messageSent = true;
messageSentCounter++; messageSentCounter++;
@ -78,13 +60,10 @@ class MessageQueueMockBase : public MessageQueueIF {
messagesSentQueue.push(messageRef); messagesSentQueue.push(messageRef);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
virtual void setDefaultDestination(MessageQueueId_t defaultDestination) {
myQueueId = defaultDestination;
defaultDestSet = true;
}
virtual MessageQueueId_t getDefaultDestination() const { return myQueueId; } virtual ReturnValue_t reply(MessageQueueMessageIF* message) override {
virtual bool isDefaultDestinationSet() const { return defaultDestSet; } return sendMessageFrom(MessageQueueIF::NO_QUEUE, message, this->getId(), false);
}
void clearMessages(bool clearCommandMessages = true) { void clearMessages(bool clearCommandMessages = true) {
while (not messagesSentQueue.empty()) { while (not messagesSentQueue.empty()) {

View File

@ -0,0 +1,77 @@
#include "PowerSwitcherMock.h"
static uint32_t SWITCH_REQUEST_UPDATE_VALUE = 0;
PowerSwitcherMock::PowerSwitcherMock() {}
ReturnValue_t PowerSwitcherMock::sendSwitchCommand(power::Switch_t switchNr, ReturnValue_t onOff) {
if (switchMap.count(switchNr) == 0) {
switchMap.emplace(switchNr, SwitchInfo(switchNr, onOff));
} else {
SwitchInfo& info = switchMap.at(switchNr);
info.currentState = onOff;
if (onOff == PowerSwitchIF::SWITCH_ON) {
info.timesCalledOn++;
} else {
info.timesCalledOff++;
}
}
return RETURN_OK;
}
ReturnValue_t PowerSwitcherMock::sendFuseOnCommand(uint8_t fuseNr) {
if (fuseMap.count(fuseNr) == 0) {
fuseMap.emplace(fuseNr, FuseInfo(fuseNr));
} else {
FuseInfo& info = fuseMap.at(fuseNr);
info.timesCalled++;
}
return RETURN_OK;
}
ReturnValue_t PowerSwitcherMock::getSwitchState(power::Switch_t switchNr) const {
if (switchMap.count(switchNr) == 1) {
auto& info = switchMap.at(switchNr);
SWITCH_REQUEST_UPDATE_VALUE++;
return info.currentState;
}
return RETURN_FAILED;
}
ReturnValue_t PowerSwitcherMock::getFuseState(uint8_t fuseNr) const {
if (fuseMap.count(fuseNr) == 1) {
return FUSE_ON;
} else {
return FUSE_OFF;
}
return RETURN_FAILED;
}
uint32_t PowerSwitcherMock::getSwitchDelayMs(void) const { return 5000; }
SwitchInfo::SwitchInfo() : switcher(0) {}
SwitchInfo::SwitchInfo(power::Switch_t switcher, ReturnValue_t initState)
: switcher(switcher), currentState(initState) {}
FuseInfo::FuseInfo(uint8_t fuse) : fuse(fuse) {}
void PowerSwitcherMock::getSwitchInfo(power::Switch_t switcher, SwitchInfo& info) {
if (switchMap.count(switcher) == 1) {
info = switchMap.at(switcher);
}
}
void PowerSwitcherMock::getFuseInfo(uint8_t fuse, FuseInfo& info) {
if (fuseMap.count(fuse) == 1) {
info = fuseMap.at(fuse);
}
}
uint32_t PowerSwitcherMock::getAmountSwitchStatWasRequested() {
return SWITCH_REQUEST_UPDATE_VALUE;
}
void PowerSwitcherMock::initSwitch(power::Switch_t switchNr) {
switchMap.emplace(switchNr, SwitchInfo(switchNr, PowerSwitchIF::SWITCH_OFF));
}

View File

@ -0,0 +1,52 @@
#ifndef FSFW_TESTS_SRC_FSFW_TESTS_UNIT_MOCKS_POWERSWITCHERMOCK_H_
#define FSFW_TESTS_SRC_FSFW_TESTS_UNIT_MOCKS_POWERSWITCHERMOCK_H_
#include <fsfw/power/PowerSwitchIF.h>
#include <map>
#include <utility>
struct SwitchInfo {
public:
SwitchInfo();
SwitchInfo(power::Switch_t switcher, ReturnValue_t initState);
power::Switch_t switcher;
ReturnValue_t currentState = PowerSwitchIF::SWITCH_OFF;
uint32_t timesCalledOn = 0;
uint32_t timesCalledOff = 0;
uint32_t timesStatusRequested = 0;
};
struct FuseInfo {
public:
FuseInfo(uint8_t fuse);
uint8_t fuse;
uint32_t timesCalled = 0;
};
class PowerSwitcherMock : public PowerSwitchIF {
public:
PowerSwitcherMock();
ReturnValue_t sendSwitchCommand(power::Switch_t switchNr, ReturnValue_t onOff) override;
ReturnValue_t sendFuseOnCommand(uint8_t fuseNr) override;
ReturnValue_t getSwitchState(power::Switch_t switchNr) const override;
ReturnValue_t getFuseState(uint8_t fuseNr) const override;
uint32_t getSwitchDelayMs(void) const override;
void getSwitchInfo(power::Switch_t switcher, SwitchInfo& info);
void getFuseInfo(uint8_t fuse, FuseInfo& info);
uint32_t getAmountSwitchStatWasRequested();
void initSwitch(power::Switch_t switchNr);
private:
using SwitchOnOffPair = std::pair<power::Switch_t, ReturnValue_t>;
using FuseOnOffPair = std::pair<uint8_t, ReturnValue_t>;
std::map<power::Switch_t, SwitchInfo> switchMap;
std::map<uint8_t, FuseInfo> fuseMap;
};
#endif /* FSFW_TESTS_SRC_FSFW_TESTS_UNIT_MOCKS_POWERSWITCHERMOCK_H_ */

View File

@ -1,4 +1,5 @@
target_sources(${FSFW_TEST_TGT} PRIVATE target_sources(${FSFW_TEST_TGT} PRIVATE
TestMessageQueue.cpp TestMessageQueue.cpp
TestSemaphore.cpp TestSemaphore.cpp
TestClock.cpp
) )

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