Compare commits
621 Commits
mueller/ex
...
fdcfd89ed2
Author | SHA1 | Date | |
---|---|---|---|
fdcfd89ed2 | |||
03fa77e2b3 | |||
8970a7379a | |||
43048c852a | |||
19817bd3a5 | |||
1db04cf20c | |||
52ee50ba8c | |||
f11433e50f | |||
edc5a314b8 | |||
54fc35eae7 | |||
05d4162f5b | |||
e030878023 | |||
c96e304b68 | |||
9bbe1dc716 | |||
74794bb71b | |||
6f751c2cf9 | |||
9a2e68b37e | |||
91067cde98 | |||
428018e4f1 | |||
8b6dd3f868 | |||
f6ede7cd3e | |||
4da18172b3 | |||
6e5239e9a0 | |||
78b09ed0c9 | |||
fdf35232ee | |||
8465670374 | |||
3b23fb77b4 | |||
6f7be281ef | |||
3686bbc486 | |||
ecac08814e | |||
e8b8fff0b5 | |||
4d34f93cfc | |||
adbf375f38 | |||
2e42f53682 | |||
c519b70302 | |||
45ee307bc4 | |||
8a2068aca6 | |||
aa60484111 | |||
e99c7f3824 | |||
2ee3ef1f1d | |||
ce48827ee5 | |||
0d80fad685 | |||
c6253bf0dd | |||
93933dee02 | |||
0e49640306 | |||
32fea9838e | |||
0519083894 | |||
904ae2cc0e | |||
4a2012ac30 | |||
6a62cf7f1e | |||
14bac9a418 | |||
3bef73708f | |||
fef6ddceff | |||
c5eb09314f | |||
682abd1b5b | |||
a4247cd723 | |||
5a9db72814 | |||
5cccd5caba | |||
7de56f189b | |||
df97bbc691 | |||
2d2f65bf89 | |||
3e9ae62b28 | |||
2ebefdffae | |||
45792e86b9 | |||
39881e7671 | |||
541f563683 | |||
5abbf42e9f | |||
28ea71a077 | |||
a044d7d724 | |||
687700cee8 | |||
732b615cb3 | |||
394ce2ec3e | |||
dde96ae220 | |||
c3aaab4b93 | |||
edf1d5ae8d | |||
690991b4b5 | |||
1a294e6a13 | |||
8c4e34153b | |||
b60e4bcb90 | |||
b18410aa63 | |||
7f57a8784a | |||
4b33aa8262 | |||
1910a7838c | |||
ba3a99466a | |||
d47a908117 | |||
fce95e04a8 | |||
438efe074e | |||
1759700b6a | |||
c7618294ac | |||
af890c6218 | |||
7f3e5e42bb | |||
fc742e4270 | |||
b5183a19fc | |||
ca453a8f16 | |||
b7c0c07141 | |||
0158102f11 | |||
69859fdbc9 | |||
90bccc744e | |||
ab89108c55 | |||
a682bbe400 | |||
e67fc2ab0d | |||
71ce966531 | |||
6b0f4a159f | |||
4a06b558c1 | |||
6d921f03fd | |||
65bc8213fe | |||
a0ee86ace8 | |||
a07a368272 | |||
cb8a4bbbec | |||
17f54006b8 | |||
395cf9cfa7 | |||
a3c0b441ec | |||
b4132800ae | |||
ad53b48fcb | |||
dee40f9079 | |||
92ec24352f | |||
3f9e459f48 | |||
e0c7f8d51d | |||
eb79386c92 | |||
4542f31c40 | |||
689fb378d8 | |||
98b711a872 | |||
800aa131fa | |||
6983980304 | |||
7c0ba59993 | |||
28873fc87b | |||
24e849ed9c | |||
d8985c141e | |||
7602b15256 | |||
d1a82bceed | |||
7292b02907 | |||
347714d53a | |||
f230fa1617 | |||
93615b100c | |||
e18d3d559e | |||
08ff061d07 | |||
cc351c1066 | |||
664a548c53 | |||
e9895559a3 | |||
eda5b8f593 | |||
e03f55604a | |||
51d7df2dba | |||
12046a2db6 | |||
21eb386f3c | |||
ade36e65c6 | |||
103661facc | |||
ae2f7219fd | |||
4fba2704aa | |||
161dbde0d7 | |||
2fa4fd61d0 | |||
bf673c56c6 | |||
cda81fc841 | |||
c697d0f8ab | |||
5a69c1f8b9 | |||
1d1d91f591 | |||
043b8b5b3f | |||
95a64e1da3 | |||
ab68817e9a | |||
36652e6fce | |||
3749f31ab4 | |||
ebbe08639c | |||
d286fc1855 | |||
cf35cca923 | |||
2058817ba5 | |||
c328891030 | |||
76a459a02c | |||
fbec1b3dc9 | |||
c4fa7281ae | |||
ac62443f31 | |||
8cfe848dfe | |||
c7cf8e710d | |||
af7c6c57a3 | |||
c835525196 | |||
7dddcdfd55 | |||
261eea381e | |||
24069dfd78 | |||
40cc557978 | |||
e59f1f26bf | |||
f7cde80088 | |||
e60a665de4 | |||
34658ef7db | |||
4b128d2435 | |||
f35b0ffbbd | |||
940fd6f465 | |||
f288d5120d | |||
5a425a1c58 | |||
5e62258aa6 | |||
b8b7756a3e | |||
4cc108f3a1 | |||
c0292f072e | |||
336ad9b7be | |||
942bfafaa3 | |||
0b53b4873f | |||
8e2597f609 | |||
dac700b80a | |||
d0fc360697 | |||
3a16290707 | |||
08f1ebf9fc | |||
64e7d4bb5e | |||
1886da0d3f | |||
b47eb0a7ff | |||
b1e30ae9ff | |||
86ca4f246b | |||
e87b5a0207 | |||
d504589c3c | |||
7b3de87364 | |||
576414438c | |||
13cda86d23 | |||
e758f0be2e | |||
18b342e94b | |||
f9c42d3583 | |||
d267a3651b | |||
e8023886f6 | |||
14a1b4a7ac | |||
e49de9422a | |||
e1dd27b9dd | |||
0ea044c203 | |||
8e9d4b451c | |||
4b323053ec | |||
d871f55a89 | |||
816550b69c | |||
7fee852dbd | |||
1e7032f89c | |||
f0debecbbc | |||
ef9d7aa7d3 | |||
b8fd2db434 | |||
878e32cbe8 | |||
4821706561 | |||
1611a4e1f0 | |||
55ed7ab93e | |||
bcd19045cc | |||
dba08fed7a | |||
7df1922633 | |||
eed6a64597 | |||
4841d5d92d | |||
5736023ffa | |||
ac78a79ca2 | |||
bf7388c059 | |||
8a12a5097e | |||
87e4a57ef7 | |||
0375ee1881 | |||
c8e034d975 | |||
e98aa005cb | |||
52310f7d32 | |||
e3d1308205 | |||
970f039e85 | |||
99c72fd00b | |||
2708b71d77 | |||
5a4539def4 | |||
13a34cd677 | |||
811287aac8 | |||
23fb06578b | |||
c86e99e6dc | |||
4092de911c | |||
00952e15b0 | |||
6366283ce2 | |||
01ebf0f4d3 | |||
99fe6487c8 | |||
d4a6f987bc | |||
57bac4f262 | |||
cfa6843c8f | |||
b6b3221b22 | |||
8dc640c162 | |||
deee4c43c0 | |||
ad0b6f1ed1 | |||
ec03a674bd | |||
9e3d5b6a0c | |||
994c7299b9 | |||
57a830cb46 | |||
ff40a71582 | |||
271057ca6b | |||
c2de911efa | |||
861335212e | |||
038e47a46e | |||
c215508a12 | |||
ccadbb5942 | |||
fc2b709148 | |||
02473a0cd7 | |||
ab45aa1296 | |||
171c48495c | |||
a83b86ccd2 | |||
2e4b9bcd7c | |||
3046822e88 | |||
6442dd0c38 | |||
9b6fa646ed | |||
e77bde459b | |||
2d9d83a1c5 | |||
c561271070 | |||
70d4fc1e0a | |||
b8cfb36426 | |||
e5c140e0ae | |||
b99160e850 | |||
c4c340fde1 | |||
9a4c7589cc | |||
d11f898f70 | |||
c0ff84bb9d | |||
d1ff32bf96 | |||
dafcaa6007 | |||
5eb52133ac | |||
025e7647d3 | |||
0a97077a0e | |||
bc994595da | |||
e1604b292c | |||
34e124f2db | |||
ab2d7ca98f | |||
56e4fca06f | |||
e06c457743 | |||
5941c21adf | |||
0e880de0d0 | |||
29c3a43760 | |||
e05c72b062 | |||
2ca8523215 | |||
25775614de | |||
0410ecd9e3 | |||
0fe1b70bae | |||
c5b4499d98 | |||
458aa5c265 | |||
eb0223bc51 | |||
d8bd08dd8c | |||
18c2847b08 | |||
d983305ea5 | |||
dd9e28fca1 | |||
7b7f5d7e0a | |||
fd112ed597 | |||
5989c88c88 | |||
da8a108cb7 | |||
75132c1e39 | |||
eb494707af | |||
15352b539d | |||
4015e85506 | |||
aacaf52fd9 | |||
89f83f4e3d | |||
39b7976056 | |||
8a40878eb5 | |||
220469a2dd | |||
7afe30ea88 | |||
6308427d03 | |||
c78b7c432b | |||
637512ad77 | |||
a4bd5a2aaa | |||
a943e4eebb | |||
cb0c80d8dc | |||
d72b212fa6 | |||
43f0841d0a | |||
9e5fb64d0e | |||
71f704c980 | |||
a72cc487df | |||
de2d4da161 | |||
19bd26d998 | |||
f59b05c86c | |||
80cb0e682f | |||
8ee26f81f9 | |||
3556eca8e8 | |||
a9041b84a3 | |||
83d9dbc052 | |||
2220120d54 | |||
15eb22f9ee | |||
2fbf847367 | |||
7f6c8b8b12 | |||
57e6c46e72 | |||
a3617cad11 | |||
789668ae50 | |||
7760b3063e | |||
d04f88bee0 | |||
e867d09111 | |||
43aad11859 | |||
3225a8e350 | |||
1c4ea6dd0d | |||
e2eb4bfea4 | |||
41682aab3f | |||
496bc665d6 | |||
2c8531ea48 | |||
d3e7037759 | |||
d61fe7db93 | |||
c1be1fe232 | |||
ec2e274f22 | |||
c5a7b98a7d | |||
6a8da303fb | |||
0aee86442e | |||
3d047f9629 | |||
1739edd9b0 | |||
951c077abc | |||
466a3639a5 | |||
900ef5b912 | |||
b94685e045 | |||
572d602b72 | |||
88051c9302 | |||
91ef4ff30b | |||
755dcf66a3 | |||
50ce13d596 | |||
68302e7c5e | |||
b7ffd2653b | |||
280b641cbc | |||
24ef96d1b8 | |||
befaca78c6 | |||
af4f002a25 | |||
9f7b9be800 | |||
2c0f3b52e9 | |||
aa1ea33647 | |||
9798b6b4ab | |||
f0d7eaf35a | |||
b128ef9da9 | |||
085213c60f | |||
613dbe9592 | |||
e949368b06 | |||
4d49cb6a3c | |||
e0c9bf5871 | |||
935a8e13a5 | |||
5ff88129b8 | |||
ce17be63f4 | |||
2734d9d758 | |||
35f257800e | |||
7a5ce57bbc | |||
d0b7c22afc | |||
a18bc15cbb | |||
4ed9cc933f | |||
7af1c86f1c | |||
bd0b7aa230 | |||
72e0938f9a | |||
dd1b0a9380 | |||
c45328b34d | |||
478b305fbe | |||
28e93696df | |||
942d1e5e4b | |||
adfefdd93f | |||
6ce09e968d | |||
290db6ccad | |||
94ed582297 | |||
47ced1efac | |||
85a6e4b129 | |||
f94bc02b6c | |||
5bda877d97 | |||
51e7f1c2f2 | |||
a11d7455df | |||
4dc903fe20 | |||
3325cc18fc | |||
43917d98c0 | |||
e3ffcae3e0 | |||
0677de39aa | |||
aded4fae1e | |||
7df51f7202 | |||
7530c44849 | |||
e4c6a69f77 | |||
761a0c9bac | |||
4dee913d51 | |||
b764194ed0 | |||
2d0e4ba951 | |||
0d549b687d | |||
738f572043 | |||
cab508fd64 | |||
c7daf697a8 | |||
518666f822 | |||
c20be13733 | |||
318cd8e244 | |||
1bc7a91869 | |||
8e26e287c3 | |||
ce2f7c4fdf | |||
b3d2d440d7 | |||
fbf9626fde | |||
29cf8c9009 | |||
61d0815de8 | |||
127fbeb980 | |||
b42987059a | |||
c2581ff4f5 | |||
7b6f68c509 | |||
532607bf8f | |||
a230dc4313 | |||
82fc7f33a8 | |||
bfa77cf810 | |||
b7a316008a | |||
f598f7030f | |||
3ea9f999b7 | |||
79f3c7324a | |||
23af170229 | |||
b32d1da421 | |||
6f0362b956 | |||
60972228ef | |||
6ea1eabb2d | |||
283a37dccc | |||
acf0cdfba3 | |||
a01002aa5d | |||
b52f19254b | |||
79615e47e4 | |||
70f575396d | |||
ad57e6713e | |||
e6130263ef | |||
6895dbcc81 | |||
23f8e5cb41 | |||
879223f38f | |||
8a44c498c5 | |||
a891769a02 | |||
df97c582d7 | |||
4b5e3e70f7 | |||
bbe21e7e89 | |||
2823420c46 | |||
6dd6f28db0 | |||
d791fc87b7 | |||
16f2fa9327 | |||
927041209b | |||
bac8b40880 | |||
caf78835b2 | |||
b6ed45a85c | |||
ddc1cdb1f5 | |||
543daaa95a | |||
38c87fdeb2 | |||
5ca5fe4040 | |||
1b7e0371c3 | |||
d4ade5e885 | |||
fec5f83f4f | |||
17262a1da9 | |||
b5d6b9745f | |||
60639f56dc | |||
3aa0bbde68 | |||
97bc71a3ff | |||
06577ed78a | |||
b27f3b84aa | |||
9509847b84 | |||
45b51f9ac8 | |||
d5ff6da40b | |||
e498136273 | |||
47d158156b | |||
d63c01b96f | |||
3b497dbb8d | |||
bf733162eb | |||
73f0b9c0dc | |||
b5e55f64b0 | |||
7ca6d1a695 | |||
cc3210f366 | |||
155d66e534 | |||
d4c76a7e46 | |||
dba3c27b99 | |||
202cfc6dbb | |||
84f95e8d76 | |||
6de4798805 | |||
82a645deba | |||
8b1c277c58 | |||
5f23f709cc | |||
a7cb2d4354 | |||
7571987a1d | |||
d6c1041133 | |||
3c53e2c259 | |||
45f0d7fd45 | |||
aebab4c73c | |||
c3c2e1c0dd | |||
4e6c1cb72a | |||
e2eb6a46b6 | |||
75c56280ad | |||
0ccaf27fcb | |||
e05e203c83 | |||
ac036b2a70 | |||
2d9216ba19 | |||
2fed161eff | |||
4cf2a384f3 | |||
27267b7cb0 | |||
505e00c067 | |||
68225586d2 | |||
6d825a1aa6 | |||
fa73ad6731 | |||
331aa9442d | |||
28b28b5684 | |||
afd3a942e2 | |||
729bcc4aaf | |||
6e0b90696d | |||
eacb4ac407 | |||
09c1918c1f | |||
123f2ff360 | |||
7ce2c1b624 | |||
4747e54c5d | |||
2e230daa14 | |||
e909c6b6f7 | |||
d88d7c938f | |||
389641f8fd | |||
b440c30223 | |||
3966b656e9 | |||
3a5881a0cb | |||
1e982ec00b | |||
701135e2a6 | |||
19f8e41c7f | |||
c4a055986c | |||
d74a373f1d | |||
cf69af4e7e | |||
508979d32d | |||
0d66569687 | |||
a5871ed0b1 | |||
a12e98d948 | |||
bd05afbddd | |||
b3482eba24 | |||
9e92afbf07 | |||
0d6d44f72f | |||
81f5b0c3bf | |||
062e93fd88 | |||
c20bf31d5d | |||
3c06d2dbbb | |||
018d814f29 | |||
c0648a789b | |||
9579e94a71 | |||
235fd79dfb | |||
83635d3667 | |||
581ae4c990 | |||
32a9e0c704 | |||
940c53eba6 | |||
0d4bd856bd | |||
b7f6a6961b | |||
a910a05541 | |||
973996e102 | |||
b3aee76d91 | |||
b3151a0ba0 | |||
fca48257b7 | |||
8f95b03e6a | |||
527dba9a9d | |||
22cd38fffd | |||
1a518109d0 | |||
8030d9ac1b | |||
992c05df56 | |||
6698d283b6 | |||
33386550cf | |||
3a65c0db91 | |||
41614303d7 | |||
783176848a | |||
07cb980e06 | |||
d8c5bd125e |
8
.gitignore
vendored
8
.gitignore
vendored
@ -1,6 +1,14 @@
|
|||||||
|
# PyCharm and CLion
|
||||||
|
/.idea/*
|
||||||
|
!/.idea/runConfigurations
|
||||||
|
!/.idea/cmake.xml
|
||||||
|
!/.idea/codeStyles
|
||||||
|
|
||||||
|
# Eclipse
|
||||||
.cproject
|
.cproject
|
||||||
.project
|
.project
|
||||||
.settings
|
.settings
|
||||||
.metadata
|
.metadata
|
||||||
|
|
||||||
/build*
|
/build*
|
||||||
|
/cmake-build*
|
||||||
|
14
.idea/codeStyles/Project.xml
generated
Normal file
14
.idea/codeStyles/Project.xml
generated
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
|
<code_scheme name="Project" version="173">
|
||||||
|
<clangFormatSettings>
|
||||||
|
<option name="ENABLED" value="true" />
|
||||||
|
</clangFormatSettings>
|
||||||
|
<codeStyleSettings language="CMake">
|
||||||
|
<indentOptions>
|
||||||
|
<option name="INDENT_SIZE" value="2" />
|
||||||
|
<option name="CONTINUATION_INDENT_SIZE" value="0" />
|
||||||
|
<option name="TAB_SIZE" value="2" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
</code_scheme>
|
||||||
|
</component>
|
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
|
<state>
|
||||||
|
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||||
|
</state>
|
||||||
|
</component>
|
131
CHANGELOG.md
131
CHANGELOG.md
@ -8,25 +8,24 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
|
|
||||||
# [unreleased]
|
# [unreleased]
|
||||||
|
|
||||||
# [v5.0.0]
|
# [v5.0.0] 25.07.2022
|
||||||
|
|
||||||
## Changes
|
## Changes
|
||||||
|
|
||||||
|
- Renamed auto-formatting script to `auto-formatter.sh` and made it more robust.
|
||||||
|
If `cmake-format` is installed, it will also auto-format the `CMakeLists.txt` files now.
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/625
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/626
|
||||||
- Bump C++ required version to C++17. Every project which uses the FSFW and every modern
|
- Bump C++ required version to C++17. Every project which uses the FSFW and every modern
|
||||||
compiler supports it
|
compiler supports it
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/622
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/622
|
||||||
- HAL Linux SPI: Set the Clock Default State when setting new SPI speed
|
|
||||||
and mode
|
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/573
|
|
||||||
- GPIO HAL: `Direction`, `GpioOperation` and `Levels` are enum classes now, which prevents
|
|
||||||
name clashes with Windows defines.
|
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/572
|
|
||||||
- New CMake option `FSFW_HAL_LINUX_ADD_LIBGPIOD` to specifically exclude `gpiod` code.
|
- New CMake option `FSFW_HAL_LINUX_ADD_LIBGPIOD` to specifically exclude `gpiod` code.
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/572
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/572
|
||||||
- HAL Devicehandlers: Periodic printout is run-time configurable now
|
- HAL Devicehandlers: Periodic printout is run-time configurable now
|
||||||
- `oneShotAction` flag in the `TestTask` class is not static anymore
|
- `oneShotAction` flag in the `TestTask` class is not static anymore
|
||||||
- HAL Linux Uart: Baudrate and bits per word are enums now, avoiding misconfigurations
|
- `SimpleRingBuffer::writeData` now checks if the amount is larger than the total size of the
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/585
|
Buffer and rejects such writeData calls with `HasReturnvaluesIF::RETURN_FAILED`
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/586
|
||||||
- Major update for version handling, using `git describe` to fetch version information with git.
|
- Major update for version handling, using `git describe` to fetch version information with git.
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/601
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/601
|
||||||
- Add helper functions provided by [`cmake-modules`](https://github.com/bilke/cmake-modules)
|
- Add helper functions provided by [`cmake-modules`](https://github.com/bilke/cmake-modules)
|
||||||
@ -44,12 +43,74 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
creation call. It allows passing context information and an arbitrary user argument into
|
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
|
the message queue. Also streamlined and simplified `MessageQueue` implementation for all OSALs
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/583
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/583
|
||||||
- Clock:
|
- Internal API change: Moved the `fsfw_hal` to the `src` folder and integration and internal
|
||||||
- `timeval` to `TimeOfDay_t`
|
tests part of `fsfw_tests` to `src`. Unittests are now in a dedicated folder called `unittests`
|
||||||
- Added Mutex for gmtime calls: (compare http://www.opengate.at/blog/2020/01/timeless/)
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/653
|
||||||
- Moved the statics used by Clock in ClockCommon.cpp to this file
|
|
||||||
- Better check for leap seconds
|
### Task Module Refactoring
|
||||||
- Added Unittests for Clock (only getter)
|
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/636
|
||||||
|
|
||||||
|
**Refactoring general task code**
|
||||||
|
|
||||||
|
- There was a lot of duplicate/boilerplate code inside the individual task IF OSAL implementations.
|
||||||
|
Remove it by introducing base classes `PeriodicTaskBase` and `FixedTimeslotTaskBase`.
|
||||||
|
|
||||||
|
**Refactor PeriodicTaskIF**
|
||||||
|
|
||||||
|
- Convert `virtual ReturnValue_t addComponent(object_id_t object)` to
|
||||||
|
`virtual ReturnValue_t addComponent(object_id_t object, uint8_t opCode = 0)`, allowing to pass
|
||||||
|
the operation code passed to `performOperation`. Updated API taking
|
||||||
|
an `ExecutableObjectIF` accordingly
|
||||||
|
|
||||||
|
**Refactor FixedTimeslotTaskIF**
|
||||||
|
|
||||||
|
- Add additional `addSlot` function which takes an `ExecutableObjectIF` pointer and its Object ID
|
||||||
|
|
||||||
|
**Refactor FixedSequenceSlot**
|
||||||
|
|
||||||
|
- Introduce typedef `CustomCheckFunc` for `ReturnValue_t (*customCheckFunction)(const SlotList&)`.
|
||||||
|
- Convert `ReturnValue_t (*customCheckFunction)(const SlotList&)` to
|
||||||
|
`ReturnValue_t (*customCheckFunction)(const SlotList&, void*)`, allowing arbitrary user arguments
|
||||||
|
for the custom checker
|
||||||
|
|
||||||
|
**Linux Task Module**
|
||||||
|
|
||||||
|
- Use composition instead of inheritance for the `PeriodicPosixTask` and make the `PosixTask` a
|
||||||
|
member of the class
|
||||||
|
|
||||||
|
### HAL
|
||||||
|
|
||||||
|
- HAL Linux Uart: Baudrate and bits per word are enums now, avoiding misconfigurations
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/585
|
||||||
|
- 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
|
||||||
|
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
|
||||||
|
|
||||||
@ -59,14 +120,52 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
|
|
||||||
## Additions
|
## Additions
|
||||||
|
|
||||||
- Linux HAL: Add wiretapping option for I2C. Enabled with `FSFW_HAL_I2C_WIRETAPPING` defined to 1
|
- New constructor for PoolEntry which allows to simply specify the length of the pool entry.
|
||||||
|
This is also the new default constructor for scalar value with 0 as an initial value
|
||||||
|
- Added options for CI/CD builds: `FSFW_CICD_BUILD`. This allows the source code to know
|
||||||
|
whether it is running in CI/CD
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/623
|
||||||
|
- Basic `clion` support: Update `.gitignore` and add some basic run configurations
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/625
|
||||||
|
- LTO support: Allow using LTO/IPO by setting `FSFW_ENABLE_LTO=1`. CMake is able to detect whether
|
||||||
|
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
|
||||||
- Dedicated Version class and constant `fsfw::FSFW_VERSION` containing version information
|
- Dedicated Version class and constant `fsfw::FSFW_VERSION` containing version information
|
||||||
inside `fsfw/version.h`
|
inside `fsfw/version.h`
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/559
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/559
|
||||||
|
- Added generic PUS TC Scheduler Service 11. It depends on the new added Emebeded Template Library
|
||||||
|
(ETL) dependency.
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/594
|
||||||
- Added ETL dependency and improved library dependency management
|
- Added ETL dependency and improved library dependency management
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/592
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/592
|
||||||
|
- Add a `DummyPowerSwitcher` module which can be useful for test setups when no PCDU is available
|
||||||
|
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
|
- `Subsystem`: New API to add table and sequence entries
|
||||||
|
|
||||||
|
## HAL
|
||||||
|
|
||||||
|
- SPI: Cache the SPI device in the communication interface. Architecturally, this makes a
|
||||||
|
lot more sense because each ComIF should be responsible for one SPI bus.
|
||||||
|
- SPI: Move the empty transfer to update the line polarity to separate function. This means
|
||||||
|
it is not automatically called when calling the setter function for SPI speed and mode.
|
||||||
|
The user should call this function after locking the CS mutex if multiple SPI devices with
|
||||||
|
differing speeds and modes are attached to one bus.
|
||||||
|
- SPI: Getter functions for SPI speed and mode.
|
||||||
|
- I2C: Add wiretapping option for I2C. Enabled with `FSFW_HAL_I2C_WIRETAPPING` defined to 1.
|
||||||
|
|
||||||
## Fixed
|
## Fixed
|
||||||
|
|
||||||
- TCP TMTC Server: `MutexGuard` was not created properly in
|
- TCP TMTC Server: `MutexGuard` was not created properly in
|
||||||
|
653
CMakeLists.txt
653
CMakeLists.txt
@ -3,90 +3,113 @@ cmake_minimum_required(VERSION 3.13)
|
|||||||
set(MSG_PREFIX "fsfw |")
|
set(MSG_PREFIX "fsfw |")
|
||||||
|
|
||||||
# Add the cmake folder so the FindSphinx module is found
|
# Add the cmake folder so the FindSphinx module is found
|
||||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" )
|
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake-modules/bilke")
|
list(APPEND CMAKE_MODULE_PATH
|
||||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake-modules/rpavlik")
|
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake-modules/bilke")
|
||||||
|
list(APPEND CMAKE_MODULE_PATH
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake-modules/rpavlik")
|
||||||
|
|
||||||
##########################
|
# ##############################################################################
|
||||||
# Version file handling #
|
# Version file handling #
|
||||||
##########################
|
# ##############################################################################
|
||||||
|
|
||||||
set(FSFW_VERSION_IF_GIT_FAILS 4)
|
set(FSFW_VERSION_IF_GIT_FAILS 5)
|
||||||
set(FSFW_SUBVERSION_IF_GIT_FAILS 0)
|
set(FSFW_SUBVERSION_IF_GIT_FAILS 0)
|
||||||
set(FSFW_REVISION_IF_GIT_FAILS 0)
|
set(FSFW_REVISION_IF_GIT_FAILS 0)
|
||||||
|
|
||||||
set(FSFW_GIT_VER_HANDLING_OK FALSE)
|
set(FSFW_GIT_VER_HANDLING_OK FALSE)
|
||||||
# Version handling
|
# Version handling
|
||||||
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git)
|
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git)
|
||||||
message(STATUS "${MSG_PREFIX} Determining version information with git")
|
message(STATUS "${MSG_PREFIX} Determining version information with git")
|
||||||
include(FsfwHelpers)
|
include(FsfwHelpers)
|
||||||
determine_version_with_git("--exclude" "docker_*")
|
determine_version_with_git("--exclude" "docker_*")
|
||||||
if(GIT_INFO)
|
if(GIT_INFO)
|
||||||
set(FSFW_GIT_INFO ${GIT_INFO} CACHE STRING "Version information retrieved with git describe")
|
set(FSFW_GIT_INFO
|
||||||
list(GET FSFW_GIT_INFO 1 FSFW_VERSION)
|
${GIT_INFO}
|
||||||
list(GET FSFW_GIT_INFO 2 FSFW_SUBVERSION)
|
CACHE STRING "Version information retrieved with git describe")
|
||||||
list(GET FSFW_GIT_INFO 3 FSFW_REVISION)
|
list(GET FSFW_GIT_INFO 1 FSFW_VERSION)
|
||||||
list(GET FSFW_GIT_INFO 4 FSFW_VCS_INFO)
|
list(GET FSFW_GIT_INFO 2 FSFW_SUBVERSION)
|
||||||
if(NOT FSFW_VERSION)
|
list(GET FSFW_GIT_INFO 3 FSFW_REVISION)
|
||||||
set(FSFW_VERSION ${FSFW_VERSION_IF_GIT_FAILS})
|
list(GET FSFW_GIT_INFO 4 FSFW_VCS_INFO)
|
||||||
endif()
|
if(NOT FSFW_VERSION)
|
||||||
if(NOT FSFW_SUBVERSION)
|
set(FSFW_VERSION ${FSFW_VERSION_IF_GIT_FAILS})
|
||||||
set(FSFW_SUBVERSION ${FSFW_SUBVERSION_IF_GIT_FAILS})
|
endif()
|
||||||
endif()
|
if(NOT FSFW_SUBVERSION)
|
||||||
if(NOT FSFW_REVISION)
|
set(FSFW_SUBVERSION ${FSFW_SUBVERSION_IF_GIT_FAILS})
|
||||||
set(FSFW_REVISION ${FSFW_REVISION_IF_GIT_FAILS})
|
endif()
|
||||||
endif()
|
if(NOT FSFW_REVISION)
|
||||||
set(FSFW_GIT_VER_HANDLING_OK TRUE)
|
set(FSFW_REVISION ${FSFW_REVISION_IF_GIT_FAILS})
|
||||||
else()
|
endif()
|
||||||
set(FSFW_GIT_VER_HANDLING_OK FALSE)
|
set(FSFW_GIT_VER_HANDLING_OK TRUE)
|
||||||
endif()
|
else()
|
||||||
|
set(FSFW_GIT_VER_HANDLING_OK FALSE)
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
if(NOT FSFW_GIT_VER_HANDLING_OK)
|
if(NOT FSFW_GIT_VER_HANDLING_OK)
|
||||||
set(FSFW_VERSION ${FSFW_VERSION_IF_GIT_FAILS})
|
set(FSFW_VERSION ${FSFW_VERSION_IF_GIT_FAILS})
|
||||||
set(FSFW_SUBVERSION ${FSFW_SUBVERSION_IF_GIT_FAILS})
|
set(FSFW_SUBVERSION ${FSFW_SUBVERSION_IF_GIT_FAILS})
|
||||||
set(FSFW_REVISION ${FSFW_REVISION_IF_GIT_FAILS})
|
set(FSFW_REVISION ${FSFW_REVISION_IF_GIT_FAILS})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(LIB_FSFW_NAME fsfw)
|
set(LIB_FSFW_NAME fsfw)
|
||||||
project(${LIB_FSFW_NAME} VERSION ${FSFW_VERSION}.${FSFW_SUBVERSION}.${FSFW_REVISION})
|
project(${LIB_FSFW_NAME}
|
||||||
|
VERSION ${FSFW_VERSION}.${FSFW_SUBVERSION}.${FSFW_REVISION})
|
||||||
|
|
||||||
if(NOT CMAKE_CXX_STANDARD)
|
if(NOT CMAKE_CXX_STANDARD)
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||||
elseif(${CMAKE_CXX_STANDARD} LESS 17)
|
elseif(${CMAKE_CXX_STANDARD} LESS 17)
|
||||||
message(FATAL_ERROR "${MSG_PREFIX} Compiling the FSFW requires a minimum of C++17 support")
|
message(
|
||||||
|
FATAL_ERROR
|
||||||
|
"${MSG_PREFIX} Compiling the FSFW requires a minimum of C++17 support")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(FSFW_SOURCES_DIR "${CMAKE_SOURCE_DIR}/src/fsfw")
|
set(FSFW_SOURCES_DIR "${CMAKE_SOURCE_DIR}/src/fsfw")
|
||||||
|
|
||||||
set(FSFW_ETL_LIB_MAJOR_VERSION 20 CACHE STRING
|
set(FSFW_ETL_LIB_NAME etl)
|
||||||
"ETL library major version requirement"
|
set(FSFW_ETL_LINK_TARGET etl::etl)
|
||||||
)
|
set(FSFW_ETL_LIB_MAJOR_VERSION
|
||||||
set(FSFW_ETL_LIB_VERSION ${FSFW_ETL_LIB_MAJOR_VERSION}.27.3 CACHE STRING
|
20
|
||||||
"ETL library exact version requirement"
|
CACHE STRING "ETL library major version requirement")
|
||||||
)
|
set(FSFW_ETL_LIB_VERSION
|
||||||
|
${FSFW_ETL_LIB_MAJOR_VERSION}.28.0
|
||||||
|
CACHE STRING "ETL library exact version requirement")
|
||||||
set(FSFW_ETL_LINK_TARGET etl::etl)
|
set(FSFW_ETL_LINK_TARGET etl::etl)
|
||||||
|
|
||||||
set(FSFW_CATCH2_LIB_MAJOR_VERSION 3 CACHE STRING
|
set(FSFW_CATCH2_LIB_MAJOR_VERSION
|
||||||
"Catch2 library major version requirement"
|
3
|
||||||
)
|
CACHE STRING "Catch2 library major version requirement")
|
||||||
set(FSFW_CATCH2_LIB_VERSION v${FSFW_CATCH2_LIB_MAJOR_VERSION}.0.0-preview5 CACHE STRING
|
set(FSFW_CATCH2_LIB_VERSION
|
||||||
"Catch2 library exact version requirement"
|
v${FSFW_CATCH2_LIB_MAJOR_VERSION}.0.0-preview5
|
||||||
)
|
CACHE STRING "Catch2 library exact version requirement")
|
||||||
|
|
||||||
set(FSFW_ETL_LIB_NAME etl)
|
# Keep this off by default for now. See PR:
|
||||||
|
# https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/616 for information which
|
||||||
option(FSFW_GENERATE_SECTIONS
|
# keeping this on by default is problematic
|
||||||
"Generate function and data sections. Required to remove unused code" ON
|
option(
|
||||||
)
|
FSFW_ENABLE_IPO
|
||||||
if(FSFW_GENERATE_SECTIONS)
|
"Enable interprocedural optimization or link-time optimization if available"
|
||||||
option(FSFW_REMOVE_UNUSED_CODE "Remove unused code" ON)
|
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()
|
endif()
|
||||||
|
|
||||||
option(FSFW_BUILD_UNITTESTS "Build unittest binary in addition to static library" OFF)
|
option(FSFW_GENERATE_SECTIONS
|
||||||
|
"Generate function and data sections. Required to remove unused code" ON)
|
||||||
|
if(FSFW_GENERATE_SECTIONS)
|
||||||
|
option(FSFW_REMOVE_UNUSED_CODE "Remove unused code" ON)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
option(FSFW_BUILD_TESTS "Build unittest binary in addition to static library"
|
||||||
|
OFF)
|
||||||
|
option(FSFW_CICD_BUILD "Build for CI/CD. This can disable problematic test" OFF)
|
||||||
option(FSFW_BUILD_DOCS "Build documentation with Sphinx and Doxygen" OFF)
|
option(FSFW_BUILD_DOCS "Build documentation with Sphinx and Doxygen" OFF)
|
||||||
if(FSFW_BUILD_UNITTESTS)
|
if(FSFW_BUILD_TESTS)
|
||||||
option(FSFW_TESTS_GEN_COV "Generate coverage data for unittests" ON)
|
option(FSFW_TESTS_GEN_COV "Generate coverage data for unittests" ON)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
option(FSFW_WARNING_SHADOW_LOCAL_GCC "Enable -Wshadow=local warning in GCC" ON)
|
option(FSFW_WARNING_SHADOW_LOCAL_GCC "Enable -Wshadow=local warning in GCC" ON)
|
||||||
@ -95,6 +118,11 @@ option(FSFW_ADD_INTERNAL_TESTS "Add internal unit tests" ON)
|
|||||||
option(FSFW_ADD_UNITTESTS "Add regular unittests. Requires Catch2" OFF)
|
option(FSFW_ADD_UNITTESTS "Add regular unittests. Requires Catch2" OFF)
|
||||||
option(FSFW_ADD_HAL "Add Hardware Abstraction Layer" ON)
|
option(FSFW_ADD_HAL "Add Hardware Abstraction Layer" ON)
|
||||||
|
|
||||||
|
if(UNIX)
|
||||||
|
option(FSFW_HAL_LINUX_ADD_PERIPHERAL_DRIVERS "Add Linux peripheral drivers" OFF)
|
||||||
|
option(FSFW_HAL_LINUX_ADD_LIBGPIOD "Attempt to add Linux GPIOD drivers" OFF)
|
||||||
|
endif()
|
||||||
|
|
||||||
# Optional sources
|
# Optional sources
|
||||||
option(FSFW_ADD_PUS "Compile with PUS sources" ON)
|
option(FSFW_ADD_PUS "Compile with PUS sources" ON)
|
||||||
option(FSFW_ADD_MONITORING "Compile with monitoring components" ON)
|
option(FSFW_ADD_MONITORING "Compile with monitoring components" ON)
|
||||||
@ -107,82 +135,95 @@ 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(FSFW_TEST_TGT fsfw-tests)
|
set(FSFW_TEST_TGT fsfw-tests)
|
||||||
set(FSFW_DUMMY_TGT fsfw-dummy)
|
set(FSFW_DUMMY_TGT fsfw-dummy)
|
||||||
|
|
||||||
add_library(${LIB_FSFW_NAME})
|
add_library(${LIB_FSFW_NAME})
|
||||||
|
|
||||||
|
if(IPO_SUPPORTED AND FSFW_ENABLE_IPO)
|
||||||
if(FSFW_BUILD_UNITTESTS)
|
set_property(TARGET ${LIB_FSFW_NAME} PROPERTY INTERPROCEDURAL_OPTIMIZATION
|
||||||
message(STATUS "${MSG_PREFIX} Building the FSFW unittests in addition to the static library")
|
TRUE)
|
||||||
# Check whether the user has already installed Catch2 first
|
|
||||||
find_package(Catch2 ${FSFW_CATCH2_LIB_MAJOR_VERSION})
|
|
||||||
# Not installed, so use FetchContent to download and provide Catch2
|
|
||||||
if(NOT Catch2_FOUND)
|
|
||||||
message(STATUS "${MSG_PREFIX} Catch2 installation not found. Downloading Catch2 library with FetchContent")
|
|
||||||
include(FetchContent)
|
|
||||||
|
|
||||||
FetchContent_Declare(
|
|
||||||
Catch2
|
|
||||||
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
|
|
||||||
GIT_TAG ${FSFW_CATCH2_LIB_VERSION}
|
|
||||||
)
|
|
||||||
|
|
||||||
list(APPEND FSFW_FETCH_CONTENT_TARGETS Catch2)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
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/TestsConfig.h.in tests/TestsConfig.h)
|
|
||||||
|
|
||||||
project(${FSFW_TEST_TGT} CXX C)
|
|
||||||
add_executable(${FSFW_TEST_TGT})
|
|
||||||
|
|
||||||
if(FSFW_TESTS_GEN_COV)
|
|
||||||
message(STATUS "${MSG_PREFIX} Generating coverage data for the library")
|
|
||||||
message(STATUS "${MSG_PREFIX} Targets linking against ${LIB_FSFW_NAME} "
|
|
||||||
"will be compiled with coverage data as well"
|
|
||||||
)
|
|
||||||
set(CMAKE_BUILD_TYPE "Debug")
|
|
||||||
include(CodeCoverage)
|
|
||||||
endif()
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
message(STATUS "${MSG_PREFIX} Finding and/or providing ETL library")
|
if(FSFW_BUILD_TESTS)
|
||||||
|
message(
|
||||||
# Check whether the user has already installed ETL first
|
STATUS
|
||||||
find_package(${FSFW_ETL_LIB_NAME} ${FSFW_ETL_LIB_MAJOR_VERSION} QUIET)
|
"${MSG_PREFIX} Building the FSFW unittests in addition to the static library"
|
||||||
# Not installed, so use FetchContent to download and provide etl
|
)
|
||||||
if(NOT ${FSFW_ETL_LIB_NAME}_FOUND)
|
# Check whether the user has already installed Catch2 first
|
||||||
message(STATUS
|
find_package(Catch2 ${FSFW_CATCH2_LIB_MAJOR_VERSION})
|
||||||
"No ETL installation was found with find_package. Installing and providing "
|
# Not installed, so use FetchContent to download and provide Catch2
|
||||||
"etl with FindPackage"
|
if(NOT Catch2_FOUND)
|
||||||
|
message(
|
||||||
|
STATUS
|
||||||
|
"${MSG_PREFIX} Catch2 installation not found. Downloading Catch2 library with FetchContent"
|
||||||
)
|
)
|
||||||
include(FetchContent)
|
include(FetchContent)
|
||||||
|
|
||||||
FetchContent_Declare(
|
FetchContent_Declare(
|
||||||
${FSFW_ETL_LIB_NAME}
|
Catch2
|
||||||
GIT_REPOSITORY https://github.com/ETLCPP/etl
|
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
|
||||||
GIT_TAG ${FSFW_ETL_LIB_VERSION}
|
GIT_TAG ${FSFW_CATCH2_LIB_VERSION})
|
||||||
)
|
|
||||||
|
|
||||||
list(APPEND FSFW_FETCH_CONTENT_TARGETS ${FSFW_ETL_LIB_NAME})
|
list(APPEND FSFW_FETCH_CONTENT_TARGETS Catch2)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(FSFW_CONFIG_PATH unittests/testcfg)
|
||||||
|
configure_file(unittests/testcfg/FSFWConfig.h.in FSFWConfig.h)
|
||||||
|
configure_file(unittests/testcfg/TestsConfig.h.in tests/TestsConfig.h)
|
||||||
|
|
||||||
|
project(${FSFW_TEST_TGT} CXX C)
|
||||||
|
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)
|
||||||
|
message(STATUS "${MSG_PREFIX} Generating coverage data for the library")
|
||||||
|
message(STATUS "${MSG_PREFIX} Targets linking against ${LIB_FSFW_NAME} "
|
||||||
|
"will be compiled with coverage data as well")
|
||||||
|
set(CMAKE_BUILD_TYPE "Debug")
|
||||||
|
include(CodeCoverage)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
message(
|
||||||
|
STATUS
|
||||||
|
"${MSG_PREFIX} Finding and/or providing etl library with version ${FSFW_ETL_LIB_MAJOR_VERSION}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Check whether the user has already installed ETL first
|
||||||
|
find_package(${FSFW_ETL_LIB_NAME} ${FSFW_ETL_LIB_MAJOR_VERSION} CONFIG QUIET)
|
||||||
|
# Not installed, so use FetchContent to download and provide etl
|
||||||
|
if(NOT ${FSFW_ETL_LIB_NAME}_FOUND)
|
||||||
|
message(
|
||||||
|
STATUS
|
||||||
|
"${MSG_PREFIX} 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()
|
endif()
|
||||||
|
|
||||||
# The documentation for FetchContent recommends declaring all the dependencies
|
# The documentation for FetchContent recommends declaring all the dependencies
|
||||||
# before making them available. We make all declared dependency available here
|
# before making them available. We make all declared dependency available here
|
||||||
# after their declaration
|
# after their declaration
|
||||||
if(FSFW_FETCH_CONTENT_TARGETS)
|
if(FSFW_FETCH_CONTENT_TARGETS)
|
||||||
FetchContent_MakeAvailable(${FSFW_FETCH_CONTENT_TARGETS})
|
FetchContent_MakeAvailable(${FSFW_FETCH_CONTENT_TARGETS})
|
||||||
if(TARGET ${FSFW_ETL_LIB_NAME})
|
if(TARGET ${FSFW_ETL_LIB_NAME})
|
||||||
add_library(${FSFW_ETL_LINK_TARGET} ALIAS ${FSFW_ETL_LIB_NAME})
|
add_library(${FSFW_ETL_LINK_TARGET} ALIAS ${FSFW_ETL_LIB_NAME})
|
||||||
endif()
|
endif()
|
||||||
if(TARGET Catch2)
|
if(TARGET Catch2)
|
||||||
# Fixes regression -preview4, to be confirmed in later releases
|
# Fixes regression -preview4, to be confirmed in later releases Related
|
||||||
# Related GitHub issue: https://github.com/catchorg/Catch2/issues/2417
|
# GitHub issue: https://github.com/catchorg/Catch2/issues/2417
|
||||||
set_target_properties(Catch2 PROPERTIES DEBUG_POSTFIX "")
|
set_target_properties(Catch2 PROPERTIES DEBUG_POSTFIX "")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(FSFW_CORE_INC_PATH "inc")
|
set(FSFW_CORE_INC_PATH "inc")
|
||||||
@ -190,275 +231,241 @@ 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}
|
|
||||||
)
|
|
||||||
|
|
||||||
# Backwards comptability
|
# Backwards comptability
|
||||||
if(OS_FSFW AND NOT FSFW_OSAL)
|
if(OS_FSFW AND NOT FSFW_OSAL)
|
||||||
message(WARNING "${MSG_PREFIX} Please pass the FSFW OSAL as FSFW_OSAL instead of OS_FSFW")
|
message(
|
||||||
set(FSFW_OSAL OS_FSFW)
|
WARNING
|
||||||
|
"${MSG_PREFIX} Please pass the FSFW OSAL as FSFW_OSAL instead of OS_FSFW")
|
||||||
|
set(FSFW_OSAL OS_FSFW)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(NOT FSFW_OSAL)
|
if(NOT FSFW_OSAL)
|
||||||
message(STATUS "${MSG_PREFIX} 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
|
||||||
set(FSFW_OSAL "host"
|
"host"
|
||||||
CACHE STRING "OS abstraction layer used in the FSFW"
|
CACHE STRING "OS abstraction layer used in the FSFW")
|
||||||
)
|
endif()
|
||||||
endif()
|
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(FSFW_OSAL_DEFINITION FSFW_OSAL_HOST)
|
set(FSFW_OSAL_DEFINITION FSFW_OSAL_HOST)
|
||||||
|
|
||||||
if(FSFW_OSAL MATCHES host)
|
if(FSFW_OSAL MATCHES host)
|
||||||
set(FSFW_OS_NAME "Host")
|
set(FSFW_OS_NAME "Host")
|
||||||
set(FSFW_OSAL_HOST ON)
|
set(FSFW_OSAL_HOST ON)
|
||||||
elseif(FSFW_OSAL MATCHES linux)
|
elseif(FSFW_OSAL MATCHES linux)
|
||||||
set(FSFW_OS_NAME "Linux")
|
set(FSFW_OS_NAME "Linux")
|
||||||
set(FSFW_OSAL_LINUX ON)
|
set(FSFW_OSAL_LINUX ON)
|
||||||
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(
|
||||||
"${MSG_PREFIX} Invalid operating system for FSFW specified! Setting to host.."
|
WARNING
|
||||||
)
|
"${MSG_PREFIX} Invalid operating system for FSFW specified! Setting to host.."
|
||||||
set(FSFW_OS_NAME "Host")
|
)
|
||||||
set(OS_FSFW "host")
|
set(FSFW_OS_NAME "Host")
|
||||||
|
set(OS_FSFW "host")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
configure_file(src/fsfw/FSFW.h.in fsfw/FSFW.h)
|
configure_file(src/fsfw/FSFW.h.in fsfw/FSFW.h)
|
||||||
configure_file(src/fsfw/FSFWVersion.h.in fsfw/FSFWVersion.h)
|
configure_file(src/fsfw/FSFWVersion.h.in fsfw/FSFWVersion.h)
|
||||||
|
|
||||||
message(STATUS "${MSG_PREFIX} Compiling FSFW for the ${FSFW_OS_NAME} operating system")
|
message(
|
||||||
|
STATUS "${MSG_PREFIX} Compiling FSFW for the ${FSFW_OS_NAME} operating system"
|
||||||
|
)
|
||||||
|
|
||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
add_subdirectory(tests)
|
|
||||||
if(FSFW_ADD_HAL)
|
|
||||||
add_subdirectory(hal)
|
|
||||||
endif()
|
|
||||||
add_subdirectory(contrib)
|
add_subdirectory(contrib)
|
||||||
|
if(FSFW_BUILD_TESTS)
|
||||||
|
add_subdirectory(unittests)
|
||||||
|
endif()
|
||||||
if(FSFW_BUILD_DOCS)
|
if(FSFW_BUILD_DOCS)
|
||||||
add_subdirectory(docs)
|
add_subdirectory(docs)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(FSFW_BUILD_UNITTESTS)
|
if(FSFW_BUILD_TESTS)
|
||||||
if(FSFW_TESTS_GEN_COV)
|
if(FSFW_TESTS_GEN_COV)
|
||||||
if(CMAKE_COMPILER_IS_GNUCXX)
|
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||||
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/*")
|
||||||
)
|
elseif(UNIX)
|
||||||
set(COVERAGE_EXCLUDES
|
set(COVERAGE_EXCLUDES
|
||||||
"/c/msys64/mingw64/*" "*/fsfw_hal/*"
|
"/usr/include/*"
|
||||||
)
|
"/usr/bin/*"
|
||||||
elseif(UNIX)
|
"Catch2/*"
|
||||||
set(COVERAGE_EXCLUDES
|
"/usr/local/include/*"
|
||||||
"/usr/include/*" "/usr/bin/*" "Catch2/*"
|
"*/fsfw_tests/*"
|
||||||
"/usr/local/include/*" "*/fsfw_tests/*"
|
"*/catch2-src/*"
|
||||||
"*/catch2-src/*" "*/fsfw_hal/*"
|
"*/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()
|
||||||
)
|
setup_target_for_coverage_lcov(
|
||||||
else()
|
NAME ${FSFW_TEST_TGT}_coverage EXECUTABLE ${FSFW_TEST_TGT}
|
||||||
setup_target_for_coverage_lcov(
|
DEPENDENCIES ${FSFW_TEST_TGT})
|
||||||
NAME ${FSFW_TEST_TGT}_coverage
|
endif()
|
||||||
EXECUTABLE ${FSFW_TEST_TGT}
|
|
||||||
DEPENDENCIES ${FSFW_TEST_TGT}
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
endif()
|
endif()
|
||||||
target_link_libraries(${FSFW_TEST_TGT} PRIVATE Catch2::Catch2 ${LIB_FSFW_NAME})
|
endif()
|
||||||
|
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)
|
||||||
message(WARNING "${MSG_PREFIX} Flight Software Framework configuration path not set")
|
message(
|
||||||
message(WARNING "${MSG_PREFIX} Setting default configuration from ${DEF_CONF_PATH} ..")
|
WARNING
|
||||||
endif()
|
"${MSG_PREFIX} Flight Software Framework configuration path not set")
|
||||||
add_subdirectory(${DEF_CONF_PATH})
|
message(
|
||||||
set(FSFW_CONFIG_PATH ${DEF_CONF_PATH})
|
WARNING
|
||||||
|
"${MSG_PREFIX} Setting default configuration from ${DEF_CONF_PATH} ..")
|
||||||
|
endif()
|
||||||
|
add_subdirectory(${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)
|
||||||
message(STATUS "FSFW include path: ${CURR_ABS_INC_PATH}")
|
message(STATUS "FSFW include path: ${CURR_ABS_INC_PATH}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
list(APPEND FSFW_ADD_INC_PATHS_ABS ${CURR_ABS_INC_PATH})
|
list(APPEND FSFW_ADD_INC_PATHS_ABS ${CURR_ABS_INC_PATH})
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||||
if(NOT DEFINED FSFW_WARNING_FLAGS)
|
if(NOT DEFINED FSFW_WARNING_FLAGS)
|
||||||
set(FSFW_WARNING_FLAGS
|
set(FSFW_WARNING_FLAGS
|
||||||
-Wall
|
-Wall
|
||||||
-Wextra
|
-Wextra
|
||||||
-Wimplicit-fallthrough=1
|
-Wimplicit-fallthrough=1
|
||||||
-Wno-unused-parameter
|
-Wno-unused-parameter
|
||||||
-Wno-psabi
|
-Wno-psabi
|
||||||
-Wduplicated-cond # check for duplicate conditions
|
-Wduplicated-cond # check for duplicate conditions
|
||||||
-Wduplicated-branches # check for duplicate branches
|
-Wduplicated-branches # check for duplicate branches
|
||||||
-Wlogical-op # Search for bitwise operations instead of logical
|
-Wlogical-op # Search for bitwise operations instead of logical
|
||||||
-Wnull-dereference # Search for NULL dereference
|
-Wnull-dereference # Search for NULL dereference
|
||||||
-Wundef # Warn if undefind marcos are used
|
-Wundef # Warn if undefind marcos are used
|
||||||
-Wformat=2 # Format string problem detection
|
-Wformat=2 # Format string problem detection
|
||||||
-Wformat-overflow=2 # Formatting issues in printf
|
-Wformat-overflow=2 # Formatting issues in printf
|
||||||
-Wformat-truncation=2 # Formatting issues in printf
|
-Wformat-truncation=2 # Formatting issues in printf
|
||||||
-Wformat-security # Search for dangerous printf operations
|
-Wformat-security # Search for dangerous printf operations
|
||||||
-Wstrict-overflow=3 # Warn if integer overflows might happen
|
-Wstrict-overflow=3 # Warn if integer overflows might happen
|
||||||
-Warray-bounds=2 # Some array bounds violations will be found
|
-Warray-bounds=2 # Some array bounds violations will be found
|
||||||
-Wshift-overflow=2 # Search for bit left shift overflows (<c++14)
|
-Wshift-overflow=2 # Search for bit left shift overflows (<c++14)
|
||||||
-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)
|
||||||
|
target_link_options(${LIB_FSFW_NAME} PRIVATE "Wl,--gc-sections")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(FSFW_WARNING_SHADOW_LOCAL_GCC)
|
||||||
|
list(APPEND WARNING_FLAGS "-Wshadow=local")
|
||||||
|
endif()
|
||||||
|
|
||||||
if(FSFW_REMOVE_UNUSED_CODE)
|
|
||||||
target_link_options(${LIB_FSFW_NAME} PRIVATE
|
|
||||||
"Wl,--gc-sections"
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(FSFW_WARNING_SHADOW_LOCAL_GCC)
|
|
||||||
list(APPEND WARNING_FLAGS "-Wshadow=local")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
||||||
set(COMPILER_FLAGS "/permissive-")
|
set(COMPILER_FLAGS "/permissive-")
|
||||||
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_ADDITIONAL_LINK_LIBS})
|
||||||
${FSFW_ETL_LINK_TARGET}
|
target_link_libraries(${LIB_FSFW_NAME} PUBLIC ${FSFW_ETL_LINK_TARGET})
|
||||||
${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})
|
||||||
)
|
|
||||||
|
|
||||||
add_custom_command(
|
|
||||||
TARGET ${LIB_FSFW_NAME}
|
|
||||||
PRE_BUILD
|
|
||||||
COMMAND touch ${FSFW_SOURCES_DIR}/FSFWVersion.h.in
|
|
||||||
COMMENT "${MSG_PREFIX} Updating FSFWVersion.h"
|
|
||||||
)
|
|
||||||
|
13
README.md
13
README.md
@ -99,7 +99,7 @@ add and link against the FSFW library in general.
|
|||||||
|
|
||||||
4. Link against the FSFW library
|
4. Link against the FSFW library
|
||||||
|
|
||||||
```cmake
|
```sh
|
||||||
target_link_libraries(${YourProjectName} PRIVATE fsfw)
|
target_link_libraries(${YourProjectName} PRIVATE fsfw)
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -131,15 +131,15 @@ default. This can be disabled by setting the `FSFW_TESTS_COV_GEN` option to `OFF
|
|||||||
You can use the following commands inside the `fsfw` folder to set up the build system
|
You can use the following commands inside the `fsfw` folder to set up the build system
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
mkdir build-Unittest && cd build-Unittest
|
mkdir build-tests && cd build-tests
|
||||||
cmake -DFSFW_BUILD_UNITTESTS=ON -DFSFW_OSAL=host -DCMAKE_BUILD_TYPE=Debug ..
|
cmake -DFSFW_BUILD_TESTS=ON -DFSFW_OSAL=host -DCMAKE_BUILD_TYPE=Debug ..
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also use `-DFSFW_OSAL=linux` on Linux systems.
|
You can also use `-DFSFW_OSAL=linux` on Linux systems.
|
||||||
|
|
||||||
Coverage data in HTML format can be generated using the `CodeCoverage`
|
Coverage data in HTML format can be generated using the `CodeCoverage`
|
||||||
[CMake module](https://github.com/bilke/cmake-modules/tree/master).
|
[CMake module](https://github.com/bilke/cmake-modules/tree/master).
|
||||||
To build the unittests, run them and then generare the coverage data in this format,
|
To build the unittests, run them and then generate the coverage data in this format,
|
||||||
the following command can be used inside the build directory after the build system was set up
|
the following command can be used inside the build directory after the build system was set up
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
@ -188,7 +188,10 @@ and open the documentation conveniently. Try `helper.py -h for more information.
|
|||||||
|
|
||||||
The formatting is done by the `clang-format` tool. The configuration is contained within the
|
The formatting is done by the `clang-format` tool. The configuration is contained within the
|
||||||
`.clang-format` file in the repository root. As long as `clang-format` is installed, you
|
`.clang-format` file in the repository root. As long as `clang-format` is installed, you
|
||||||
can run the `apply-clang-format.sh` helper script to format all source files consistently.
|
can run the `auto-format.sh` helper script to format all source files consistently. Furthermore cmake-format is required to format CMake files which can be installed with:
|
||||||
|
````sh
|
||||||
|
sudo pip install cmakelang
|
||||||
|
````
|
||||||
|
|
||||||
## Index
|
## Index
|
||||||
|
|
||||||
|
@ -12,3 +12,9 @@ RUN git clone https://github.com/catchorg/Catch2.git && \
|
|||||||
git checkout v3.0.0-preview5 && \
|
git checkout v3.0.0-preview5 && \
|
||||||
cmake -Bbuild -H. -DBUILD_TESTING=OFF && \
|
cmake -Bbuild -H. -DBUILD_TESTING=OFF && \
|
||||||
cmake --build build/ --target install
|
cmake --build build/ --target install
|
||||||
|
|
||||||
|
RUN git clone https://github.com/ETLCPP/etl.git && \
|
||||||
|
cd etl && \
|
||||||
|
git checkout 20.28.0 && \
|
||||||
|
cmake -B build . && \
|
||||||
|
cmake --install build/
|
||||||
|
4
automation/Jenkinsfile
vendored
4
automation/Jenkinsfile
vendored
@ -3,7 +3,7 @@ pipeline {
|
|||||||
BUILDDIR = 'build-tests'
|
BUILDDIR = 'build-tests'
|
||||||
}
|
}
|
||||||
agent {
|
agent {
|
||||||
docker { image 'fsfw-ci:d2'}
|
docker { image 'fsfw-ci:d3'}
|
||||||
}
|
}
|
||||||
stages {
|
stages {
|
||||||
stage('Clean') {
|
stage('Clean') {
|
||||||
@ -14,7 +14,7 @@ pipeline {
|
|||||||
stage('Configure') {
|
stage('Configure') {
|
||||||
steps {
|
steps {
|
||||||
dir(BUILDDIR) {
|
dir(BUILDDIR) {
|
||||||
sh 'cmake -DFSFW_OSAL=host -DFSFW_BUILD_UNITTESTS=ON ..'
|
sh 'cmake -DFSFW_OSAL=host -DFSFW_BUILD_TESTS=ON -DFSFW_CICD_BUILD=ON ..'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -106,7 +106,7 @@ You can use the following commands inside the ``fsfw`` folder to set up the buil
|
|||||||
.. code-block:: console
|
.. code-block:: console
|
||||||
|
|
||||||
mkdir build-tests && cd build-tests
|
mkdir build-tests && cd build-tests
|
||||||
cmake -DFSFW_BUILD_UNITTESTS=ON -DFSFW_OSAL=host ..
|
cmake -DFSFW_BUILD_TESTS=ON -DFSFW_OSAL=host ..
|
||||||
|
|
||||||
|
|
||||||
You can also use ``-DFSFW_OSAL=linux`` on Linux systems.
|
You can also use ``-DFSFW_OSAL=linux`` on Linux systems.
|
||||||
|
@ -1,48 +0,0 @@
|
|||||||
cmake_minimum_required(VERSION 3.13)
|
|
||||||
|
|
||||||
# Can also be changed by upper CMakeLists.txt file
|
|
||||||
find_library(LIB_FSFW_NAME fsfw REQUIRED)
|
|
||||||
|
|
||||||
option(FSFW_HAL_ADD_LINUX "Add the Linux HAL to the sources. Requires gpiod library" OFF)
|
|
||||||
# On by default for now because I did not have an issue including and compiling those files
|
|
||||||
# and libraries on a Desktop Linux system and the primary target of the FSFW is still embedded
|
|
||||||
# Linux. The only exception from this is the gpiod library which requires a dedicated installation,
|
|
||||||
# but CMake is able to determine whether this library is installed with find_library.
|
|
||||||
option(FSFW_HAL_LINUX_ADD_PERIPHERAL_DRIVERS "Add peripheral drivers for embedded Linux" ON)
|
|
||||||
option(FSFW_HAL_LINUX_ADD_LIBGPIOD "Target implements libgpiod" ON)
|
|
||||||
|
|
||||||
option(FSFW_HAL_ADD_RASPBERRY_PI "Add Raspberry Pi specific code to the sources" OFF)
|
|
||||||
option(FSFW_HAL_ADD_STM32H7 "Add the STM32H7 HAL to the sources" OFF)
|
|
||||||
option(FSFW_HAL_WARNING_SHADOW_LOCAL_GCC "Enable -Wshadow=local warning in GCC" ON)
|
|
||||||
|
|
||||||
set(LINUX_HAL_PATH_NAME linux)
|
|
||||||
set(STM32H7_PATH_NAME stm32h7)
|
|
||||||
|
|
||||||
add_subdirectory(src)
|
|
||||||
|
|
||||||
foreach(INCLUDE_PATH ${FSFW_HAL_ADDITIONAL_INC_PATHS})
|
|
||||||
if(IS_ABSOLUTE ${INCLUDE_PATH})
|
|
||||||
set(CURR_ABS_INC_PATH "${INCLUDE_PATH}")
|
|
||||||
else()
|
|
||||||
get_filename_component(CURR_ABS_INC_PATH
|
|
||||||
${INCLUDE_PATH} REALPATH BASE_DIR ${CMAKE_SOURCE_DIR})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(CMAKE_VERBOSE)
|
|
||||||
message(STATUS "FSFW include path: ${CURR_ABS_INC_PATH}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
list(APPEND FSFW_HAL_ADD_INC_PATHS_ABS ${CURR_ABS_INC_PATH})
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
target_include_directories(${LIB_FSFW_NAME} PRIVATE
|
|
||||||
${FSFW_HAL_ADD_INC_PATHS_ABS}
|
|
||||||
)
|
|
||||||
|
|
||||||
target_compile_definitions(${LIB_FSFW_NAME} PRIVATE
|
|
||||||
${FSFW_HAL_DEFINES}
|
|
||||||
)
|
|
||||||
|
|
||||||
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
|
|
||||||
${FSFW_HAL_LINK_LIBS}
|
|
||||||
)
|
|
@ -1,9 +0,0 @@
|
|||||||
target_include_directories(${LIB_FSFW_NAME} PRIVATE
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}
|
|
||||||
)
|
|
||||||
|
|
||||||
target_include_directories(${LIB_FSFW_NAME} INTERFACE
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}
|
|
||||||
)
|
|
||||||
|
|
||||||
add_subdirectory(fsfw_hal)
|
|
@ -1,3 +0,0 @@
|
|||||||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
|
||||||
GpioCookie.cpp
|
|
||||||
)
|
|
@ -1,5 +0,0 @@
|
|||||||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
|
||||||
GyroL3GD20Handler.cpp
|
|
||||||
MgmRM3100Handler.cpp
|
|
||||||
MgmLIS3MDLHandler.cpp
|
|
||||||
)
|
|
@ -1,25 +0,0 @@
|
|||||||
if(FSFW_HAL_ADD_RASPBERRY_PI)
|
|
||||||
add_subdirectory(rpi)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
|
||||||
UnixFileGuard.cpp
|
|
||||||
CommandExecutor.cpp
|
|
||||||
utility.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
if(FSFW_HAL_LINUX_ADD_PERIPHERAL_DRIVERS)
|
|
||||||
if(FSFW_HAL_LINUX_ADD_LIBGPIOD)
|
|
||||||
add_subdirectory(gpio)
|
|
||||||
endif()
|
|
||||||
add_subdirectory(uart)
|
|
||||||
# Adding those does not really make sense on Apple systems which
|
|
||||||
# are generally host systems. It won't even compile as the headers
|
|
||||||
# are missing
|
|
||||||
if(NOT APPLE)
|
|
||||||
add_subdirectory(i2c)
|
|
||||||
add_subdirectory(spi)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
add_subdirectory(uio)
|
|
@ -1,16 +0,0 @@
|
|||||||
# This abstraction layer requires the gpiod library. You can install this library
|
|
||||||
# with "sudo apt-get install -y libgpiod-dev". If you are cross-compiling, you need
|
|
||||||
# to install the package before syncing the sysroot to your host computer.
|
|
||||||
find_library(LIB_GPIO gpiod)
|
|
||||||
|
|
||||||
if(${LIB_GPIO} MATCHES LIB_GPIO-NOTFOUND)
|
|
||||||
message(STATUS "gpiod library not found, not linking against it")
|
|
||||||
else()
|
|
||||||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
|
||||||
LinuxLibgpioIF.cpp
|
|
||||||
)
|
|
||||||
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
|
|
||||||
${LIB_GPIO}
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
|||||||
target_sources(${LIB_FSFW_NAME} PUBLIC
|
|
||||||
I2cComIF.cpp
|
|
||||||
I2cCookie.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
|||||||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
|
||||||
GpioRPi.cpp
|
|
||||||
)
|
|
@ -1,8 +0,0 @@
|
|||||||
target_sources(${LIB_FSFW_NAME} PUBLIC
|
|
||||||
SpiComIF.cpp
|
|
||||||
SpiCookie.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
|||||||
target_sources(${LIB_FSFW_NAME} PUBLIC
|
|
||||||
UartComIF.cpp
|
|
||||||
UartCookie.cpp
|
|
||||||
)
|
|
@ -1,3 +0,0 @@
|
|||||||
target_sources(${LIB_FSFW_NAME} PUBLIC
|
|
||||||
UioMapper.cpp
|
|
||||||
)
|
|
@ -1,3 +0,0 @@
|
|||||||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
|
||||||
GyroL3GD20H.cpp
|
|
||||||
)
|
|
@ -1,3 +0,0 @@
|
|||||||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
|
||||||
gpio.cpp
|
|
||||||
)
|
|
@ -1,2 +0,0 @@
|
|||||||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
|
||||||
)
|
|
@ -1,9 +0,0 @@
|
|||||||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
|
||||||
spiCore.cpp
|
|
||||||
spiDefinitions.cpp
|
|
||||||
spiInterrupts.cpp
|
|
||||||
mspInit.cpp
|
|
||||||
SpiCookie.cpp
|
|
||||||
SpiComIF.cpp
|
|
||||||
stm32h743zi.cpp
|
|
||||||
)
|
|
@ -1,2 +0,0 @@
|
|||||||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
|
||||||
)
|
|
@ -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
|
|
29
scripts/auto-formatter.sh
Executable file
29
scripts/auto-formatter.sh
Executable file
@ -0,0 +1,29 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
if [[ ! -f README.md ]]; then
|
||||||
|
cd ..
|
||||||
|
fi
|
||||||
|
|
||||||
|
folder_list=(
|
||||||
|
"./src"
|
||||||
|
"./unittests"
|
||||||
|
)
|
||||||
|
|
||||||
|
cmake_fmt="cmake-format"
|
||||||
|
file_selectors="-iname CMakeLists.txt"
|
||||||
|
if command -v ${cmake_fmt} &> /dev/null; then
|
||||||
|
${cmake_fmt} -i CMakeLists.txt
|
||||||
|
find ./src ${file_selectors} | xargs ${cmake_fmt} -i
|
||||||
|
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
|
||||||
|
for dir in ${folder_list[@]}; do
|
||||||
|
echo "Auto-formatting ${dir} recursively"
|
||||||
|
find ${dir} ${file_selectors} | xargs clang-format --style=file -i
|
||||||
|
done
|
||||||
|
else
|
||||||
|
echo "No ${cpp_format} tool found, not formatting C++/C files"
|
||||||
|
fi
|
@ -48,6 +48,20 @@ def main():
|
|||||||
action="store_true",
|
action="store_true",
|
||||||
help="Run valgrind on generated test binary",
|
help="Run valgrind on generated test binary",
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-g",
|
||||||
|
"--generators",
|
||||||
|
default = "Ninja",
|
||||||
|
action="store",
|
||||||
|
help="CMake generators",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-w",
|
||||||
|
"--windows",
|
||||||
|
default=False,
|
||||||
|
action="store_true",
|
||||||
|
help="Run on windows",
|
||||||
|
)
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
if args.all:
|
if args.all:
|
||||||
@ -115,14 +129,14 @@ def handle_tests_type(args, build_dir_list: list):
|
|||||||
if args.create:
|
if args.create:
|
||||||
if os.path.exists(UNITTEST_FOLDER_NAME):
|
if os.path.exists(UNITTEST_FOLDER_NAME):
|
||||||
shutil.rmtree(UNITTEST_FOLDER_NAME)
|
shutil.rmtree(UNITTEST_FOLDER_NAME)
|
||||||
create_tests_build_cfg()
|
create_tests_build_cfg(args)
|
||||||
build_directory = UNITTEST_FOLDER_NAME
|
build_directory = UNITTEST_FOLDER_NAME
|
||||||
elif len(build_dir_list) == 0:
|
elif len(build_dir_list) == 0:
|
||||||
print(
|
print(
|
||||||
"No valid CMake tests build directory found. "
|
"No valid CMake tests build directory found. "
|
||||||
"Trying to set up test build system"
|
"Trying to set up test build system"
|
||||||
)
|
)
|
||||||
create_tests_build_cfg()
|
create_tests_build_cfg(args)
|
||||||
build_directory = UNITTEST_FOLDER_NAME
|
build_directory = UNITTEST_FOLDER_NAME
|
||||||
elif len(build_dir_list) == 1:
|
elif len(build_dir_list) == 1:
|
||||||
build_directory = build_dir_list[0]
|
build_directory = build_dir_list[0]
|
||||||
@ -147,10 +161,15 @@ def handle_tests_type(args, build_dir_list: list):
|
|||||||
os.chdir("..")
|
os.chdir("..")
|
||||||
|
|
||||||
|
|
||||||
def create_tests_build_cfg():
|
def create_tests_build_cfg(args):
|
||||||
os.mkdir(UNITTEST_FOLDER_NAME)
|
os.mkdir(UNITTEST_FOLDER_NAME)
|
||||||
os.chdir(UNITTEST_FOLDER_NAME)
|
os.chdir(UNITTEST_FOLDER_NAME)
|
||||||
cmd_runner("cmake -DFSFW_OSAL=host -DFSFW_BUILD_UNITTESTS=ON ..")
|
if args.windows:
|
||||||
|
cmake_cmd = 'cmake -G "' + args.generators + '" -DFSFW_OSAL=host -DFSFW_BUILD_TESTS=ON \
|
||||||
|
-DGCOVR_PATH="py -m gcovr" ..'
|
||||||
|
else:
|
||||||
|
cmake_cmd = 'cmake -G "' + args.generators + '" -DFSFW_OSAL=host -DFSFW_BUILD_TESTS=ON ..'
|
||||||
|
cmd_runner(cmake_cmd)
|
||||||
os.chdir("..")
|
os.chdir("..")
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
target_include_directories(${LIB_FSFW_NAME} PRIVATE
|
target_include_directories(${LIB_FSFW_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}
|
|
||||||
)
|
|
||||||
|
|
||||||
target_include_directories(${LIB_FSFW_NAME} INTERFACE
|
target_include_directories(${LIB_FSFW_NAME}
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}
|
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
)
|
|
||||||
|
|
||||||
add_subdirectory(fsfw)
|
add_subdirectory(fsfw)
|
||||||
|
if(FSFW_ADD_HAL)
|
||||||
|
add_subdirectory(fsfw_hal)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_subdirectory(fsfw_tests)
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
target_sources(${LIB_FSFW_NAME} PRIVATE version.cpp)
|
||||||
version.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
# Core
|
# Core
|
||||||
|
|
||||||
@ -37,22 +35,22 @@ add_subdirectory(tmtcservices)
|
|||||||
# Optional
|
# Optional
|
||||||
|
|
||||||
if(FSFW_ADD_MONITORING)
|
if(FSFW_ADD_MONITORING)
|
||||||
add_subdirectory(monitoring)
|
add_subdirectory(monitoring)
|
||||||
endif()
|
endif()
|
||||||
if(FSFW_ADD_PUS)
|
if(FSFW_ADD_PUS)
|
||||||
add_subdirectory(pus)
|
add_subdirectory(pus)
|
||||||
endif()
|
endif()
|
||||||
if(FSFW_ADD_TMSTORAGE)
|
if(FSFW_ADD_TMSTORAGE)
|
||||||
add_subdirectory(tmstorage)
|
add_subdirectory(tmstorage)
|
||||||
endif()
|
endif()
|
||||||
if(FSFW_ADD_COORDINATES)
|
if(FSFW_ADD_COORDINATES)
|
||||||
add_subdirectory(coordinates)
|
add_subdirectory(coordinates)
|
||||||
endif()
|
endif()
|
||||||
if(FSFW_ADD_RMAP)
|
if(FSFW_ADD_RMAP)
|
||||||
add_subdirectory(rmap)
|
add_subdirectory(rmap)
|
||||||
endif()
|
endif()
|
||||||
if(FSFW_ADD_DATALINKLAYER)
|
if(FSFW_ADD_DATALINKLAYER)
|
||||||
add_subdirectory(datalinklayer)
|
add_subdirectory(datalinklayer)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# OSAL
|
# OSAL
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
ActionHelper::ActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue)
|
ActionHelper::ActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue)
|
||||||
: owner(setOwner), queueToUse(useThisQueue) {}
|
: owner(setOwner), queueToUse(useThisQueue) {}
|
||||||
|
|
||||||
ActionHelper::~ActionHelper() {}
|
ActionHelper::~ActionHelper() = default;
|
||||||
|
|
||||||
ReturnValue_t ActionHelper::handleActionMessage(CommandMessage* command) {
|
ReturnValue_t ActionHelper::handleActionMessage(CommandMessage* command) {
|
||||||
if (command->getCommand() == ActionMessage::EXECUTE_ACTION) {
|
if (command->getCommand() == ActionMessage::EXECUTE_ACTION) {
|
||||||
@ -59,7 +59,7 @@ void ActionHelper::setQueueToUse(MessageQueueIF* queue) { queueToUse = queue; }
|
|||||||
|
|
||||||
void ActionHelper::prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId,
|
void ActionHelper::prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId,
|
||||||
store_address_t dataAddress) {
|
store_address_t dataAddress) {
|
||||||
const uint8_t* dataPtr = NULL;
|
const uint8_t* dataPtr = nullptr;
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size);
|
ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size);
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
#ifndef FSFW_ACTION_ACTIONHELPER_H_
|
#ifndef FSFW_ACTION_ACTIONHELPER_H_
|
||||||
#define FSFW_ACTION_ACTIONHELPER_H_
|
#define FSFW_ACTION_ACTIONHELPER_H_
|
||||||
|
|
||||||
#include "../ipc/MessageQueueIF.h"
|
|
||||||
#include "../serialize/SerializeIF.h"
|
|
||||||
#include "ActionMessage.h"
|
#include "ActionMessage.h"
|
||||||
|
#include "fsfw/ipc/MessageQueueIF.h"
|
||||||
|
#include "fsfw/serialize/SerializeIF.h"
|
||||||
/**
|
/**
|
||||||
* @brief Action Helper is a helper class which handles action messages
|
* @brief Action Helper is a helper class which handles action messages
|
||||||
*
|
*
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
#include "fsfw/objectmanager/ObjectManager.h"
|
#include "fsfw/objectmanager/ObjectManager.h"
|
||||||
#include "fsfw/storagemanager/StorageManagerIF.h"
|
#include "fsfw/storagemanager/StorageManagerIF.h"
|
||||||
|
|
||||||
ActionMessage::ActionMessage() {}
|
ActionMessage::ActionMessage() = default;
|
||||||
|
|
||||||
ActionMessage::~ActionMessage() {}
|
ActionMessage::~ActionMessage() = default;
|
||||||
|
|
||||||
void ActionMessage::setCommand(CommandMessage* message, ActionId_t fid,
|
void ActionMessage::setCommand(CommandMessage* message, ActionId_t fid,
|
||||||
store_address_t parameters) {
|
store_address_t parameters) {
|
||||||
@ -64,9 +64,8 @@ void ActionMessage::clear(CommandMessage* message) {
|
|||||||
switch (message->getCommand()) {
|
switch (message->getCommand()) {
|
||||||
case EXECUTE_ACTION:
|
case EXECUTE_ACTION:
|
||||||
case DATA_REPLY: {
|
case DATA_REPLY: {
|
||||||
StorageManagerIF* ipcStore =
|
auto* ipcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::IPC_STORE);
|
||||||
ObjectManager::instance()->get<StorageManagerIF>(objects::IPC_STORE);
|
if (ipcStore != nullptr) {
|
||||||
if (ipcStore != NULL) {
|
|
||||||
ipcStore->deleteData(getStoreId(message));
|
ipcStore->deleteData(getStoreId(message));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1,7 +1,3 @@
|
|||||||
target_sources(${LIB_FSFW_NAME}
|
target_sources(
|
||||||
PRIVATE
|
${LIB_FSFW_NAME} PRIVATE ActionHelper.cpp ActionMessage.cpp
|
||||||
ActionHelper.cpp
|
CommandActionHelper.cpp SimpleActionHelper.cpp)
|
||||||
ActionMessage.cpp
|
|
||||||
CommandActionHelper.cpp
|
|
||||||
SimpleActionHelper.cpp
|
|
||||||
)
|
|
||||||
|
@ -2,14 +2,14 @@
|
|||||||
#include "fsfw/objectmanager/ObjectManager.h"
|
#include "fsfw/objectmanager/ObjectManager.h"
|
||||||
|
|
||||||
CommandActionHelper::CommandActionHelper(CommandsActionsIF *setOwner)
|
CommandActionHelper::CommandActionHelper(CommandsActionsIF *setOwner)
|
||||||
: owner(setOwner), queueToUse(NULL), ipcStore(NULL), commandCount(0), lastTarget(0) {}
|
: owner(setOwner), queueToUse(nullptr), ipcStore(nullptr), commandCount(0), lastTarget(0) {}
|
||||||
|
|
||||||
CommandActionHelper::~CommandActionHelper() {}
|
CommandActionHelper::~CommandActionHelper() = default;
|
||||||
|
|
||||||
ReturnValue_t CommandActionHelper::commandAction(object_id_t commandTo, ActionId_t actionId,
|
ReturnValue_t CommandActionHelper::commandAction(object_id_t commandTo, ActionId_t actionId,
|
||||||
SerializeIF *data) {
|
SerializeIF *data) {
|
||||||
HasActionsIF *receiver = ObjectManager::instance()->get<HasActionsIF>(commandTo);
|
auto *receiver = ObjectManager::instance()->get<HasActionsIF>(commandTo);
|
||||||
if (receiver == NULL) {
|
if (receiver == nullptr) {
|
||||||
return CommandsActionsIF::OBJECT_HAS_NO_FUNCTIONS;
|
return CommandsActionsIF::OBJECT_HAS_NO_FUNCTIONS;
|
||||||
}
|
}
|
||||||
store_address_t storeId;
|
store_address_t storeId;
|
||||||
@ -29,11 +29,8 @@ ReturnValue_t CommandActionHelper::commandAction(object_id_t commandTo, ActionId
|
|||||||
|
|
||||||
ReturnValue_t CommandActionHelper::commandAction(object_id_t commandTo, ActionId_t actionId,
|
ReturnValue_t CommandActionHelper::commandAction(object_id_t commandTo, ActionId_t actionId,
|
||||||
const uint8_t *data, uint32_t size) {
|
const uint8_t *data, uint32_t size) {
|
||||||
// if (commandCount != 0) {
|
auto *receiver = ObjectManager::instance()->get<HasActionsIF>(commandTo);
|
||||||
// return CommandsFunctionsIF::ALREADY_COMMANDING;
|
if (receiver == nullptr) {
|
||||||
// }
|
|
||||||
HasActionsIF *receiver = ObjectManager::instance()->get<HasActionsIF>(commandTo);
|
|
||||||
if (receiver == NULL) {
|
|
||||||
return CommandsActionsIF::OBJECT_HAS_NO_FUNCTIONS;
|
return CommandsActionsIF::OBJECT_HAS_NO_FUNCTIONS;
|
||||||
}
|
}
|
||||||
store_address_t storeId;
|
store_address_t storeId;
|
||||||
@ -59,12 +56,12 @@ ReturnValue_t CommandActionHelper::sendCommand(MessageQueueId_t queueId, ActionI
|
|||||||
|
|
||||||
ReturnValue_t CommandActionHelper::initialize() {
|
ReturnValue_t CommandActionHelper::initialize() {
|
||||||
ipcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::IPC_STORE);
|
ipcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::IPC_STORE);
|
||||||
if (ipcStore == NULL) {
|
if (ipcStore == nullptr) {
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
queueToUse = owner->getCommandQueuePtr();
|
queueToUse = owner->getCommandQueuePtr();
|
||||||
if (queueToUse == NULL) {
|
if (queueToUse == nullptr) {
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
}
|
}
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
@ -104,7 +101,7 @@ ReturnValue_t CommandActionHelper::handleReply(CommandMessage *reply) {
|
|||||||
uint8_t CommandActionHelper::getCommandCount() const { return commandCount; }
|
uint8_t CommandActionHelper::getCommandCount() const { return commandCount; }
|
||||||
|
|
||||||
void CommandActionHelper::extractDataForOwner(ActionId_t actionId, store_address_t storeId) {
|
void CommandActionHelper::extractDataForOwner(ActionId_t actionId, store_address_t storeId) {
|
||||||
const uint8_t *data = NULL;
|
const uint8_t *data = nullptr;
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
ReturnValue_t result = ipcStore->getData(storeId, &data, &size);
|
ReturnValue_t result = ipcStore->getData(storeId, &data, &size);
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
@ -14,14 +14,14 @@ class CommandActionHelper {
|
|||||||
friend class CommandsActionsIF;
|
friend class CommandsActionsIF;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CommandActionHelper(CommandsActionsIF* owner);
|
explicit CommandActionHelper(CommandsActionsIF* owner);
|
||||||
virtual ~CommandActionHelper();
|
virtual ~CommandActionHelper();
|
||||||
ReturnValue_t commandAction(object_id_t commandTo, ActionId_t actionId, const uint8_t* data,
|
ReturnValue_t commandAction(object_id_t commandTo, ActionId_t actionId,
|
||||||
uint32_t size);
|
const uint8_t* data = nullptr, uint32_t size = 0);
|
||||||
ReturnValue_t commandAction(object_id_t commandTo, ActionId_t actionId, SerializeIF* data);
|
ReturnValue_t commandAction(object_id_t commandTo, ActionId_t actionId, SerializeIF* data);
|
||||||
ReturnValue_t initialize();
|
ReturnValue_t initialize();
|
||||||
ReturnValue_t handleReply(CommandMessage* reply);
|
ReturnValue_t handleReply(CommandMessage* reply);
|
||||||
uint8_t getCommandCount() const;
|
[[nodiscard]] uint8_t getCommandCount() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CommandsActionsIF* owner;
|
CommandsActionsIF* owner;
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
#ifndef FSFW_ACTION_COMMANDSACTIONSIF_H_
|
#ifndef FSFW_ACTION_COMMANDSACTIONSIF_H_
|
||||||
#define FSFW_ACTION_COMMANDSACTIONSIF_H_
|
#define FSFW_ACTION_COMMANDSACTIONSIF_H_
|
||||||
|
|
||||||
#include "../ipc/MessageQueueIF.h"
|
|
||||||
#include "../returnvalues/HasReturnvaluesIF.h"
|
|
||||||
#include "CommandActionHelper.h"
|
#include "CommandActionHelper.h"
|
||||||
|
#include "fsfw/ipc/MessageQueueIF.h"
|
||||||
|
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface to separate commanding actions of other objects.
|
* Interface to separate commanding actions of other objects.
|
||||||
@ -21,7 +21,7 @@ class CommandsActionsIF {
|
|||||||
static const uint8_t INTERFACE_ID = CLASS_ID::COMMANDS_ACTIONS_IF;
|
static const uint8_t INTERFACE_ID = CLASS_ID::COMMANDS_ACTIONS_IF;
|
||||||
static const ReturnValue_t OBJECT_HAS_NO_FUNCTIONS = MAKE_RETURN_CODE(1);
|
static const ReturnValue_t OBJECT_HAS_NO_FUNCTIONS = MAKE_RETURN_CODE(1);
|
||||||
static const ReturnValue_t ALREADY_COMMANDING = MAKE_RETURN_CODE(2);
|
static const ReturnValue_t ALREADY_COMMANDING = MAKE_RETURN_CODE(2);
|
||||||
virtual ~CommandsActionsIF() {}
|
virtual ~CommandsActionsIF() = default;
|
||||||
virtual MessageQueueIF* getCommandQueuePtr() = 0;
|
virtual MessageQueueIF* getCommandQueuePtr() = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
#ifndef FSFW_ACTION_HASACTIONSIF_H_
|
#ifndef FSFW_ACTION_HASACTIONSIF_H_
|
||||||
#define FSFW_ACTION_HASACTIONSIF_H_
|
#define FSFW_ACTION_HASACTIONSIF_H_
|
||||||
|
|
||||||
#include "../ipc/MessageQueueIF.h"
|
|
||||||
#include "../returnvalues/HasReturnvaluesIF.h"
|
|
||||||
#include "ActionHelper.h"
|
#include "ActionHelper.h"
|
||||||
#include "ActionMessage.h"
|
#include "ActionMessage.h"
|
||||||
#include "SimpleActionHelper.h"
|
#include "SimpleActionHelper.h"
|
||||||
|
#include "fsfw/ipc/MessageQueueIF.h"
|
||||||
|
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief
|
* @brief
|
||||||
@ -40,12 +40,12 @@ class HasActionsIF {
|
|||||||
static const ReturnValue_t INVALID_PARAMETERS = MAKE_RETURN_CODE(2);
|
static const ReturnValue_t INVALID_PARAMETERS = MAKE_RETURN_CODE(2);
|
||||||
static const ReturnValue_t EXECUTION_FINISHED = MAKE_RETURN_CODE(3);
|
static const ReturnValue_t EXECUTION_FINISHED = MAKE_RETURN_CODE(3);
|
||||||
static const ReturnValue_t INVALID_ACTION_ID = MAKE_RETURN_CODE(4);
|
static const ReturnValue_t INVALID_ACTION_ID = MAKE_RETURN_CODE(4);
|
||||||
virtual ~HasActionsIF() {}
|
virtual ~HasActionsIF() = default;
|
||||||
/**
|
/**
|
||||||
* Function to get the MessageQueueId_t of the implementing object
|
* Function to get the MessageQueueId_t of the implementing object
|
||||||
* @return MessageQueueId_t of the object
|
* @return MessageQueueId_t of the object
|
||||||
*/
|
*/
|
||||||
virtual MessageQueueId_t getCommandQueue() const = 0;
|
[[nodiscard]] virtual MessageQueueId_t getCommandQueue() const = 0;
|
||||||
/**
|
/**
|
||||||
* Execute or initialize the execution of a certain function.
|
* Execute or initialize the execution of a certain function.
|
||||||
* The ActionHelpers will execute this function and behave differently
|
* The ActionHelpers will execute this function and behave differently
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
SimpleActionHelper::SimpleActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue)
|
SimpleActionHelper::SimpleActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue)
|
||||||
: ActionHelper(setOwner, useThisQueue), isExecuting(false) {}
|
: ActionHelper(setOwner, useThisQueue), isExecuting(false) {}
|
||||||
|
|
||||||
SimpleActionHelper::~SimpleActionHelper() {}
|
SimpleActionHelper::~SimpleActionHelper() = default;
|
||||||
|
|
||||||
void SimpleActionHelper::step(ReturnValue_t result) {
|
void SimpleActionHelper::step(ReturnValue_t result) {
|
||||||
// STEP_OFFESET is subtracted to compensate for adding offset in base
|
// STEP_OFFESET is subtracted to compensate for adding offset in base
|
||||||
@ -38,7 +38,7 @@ void SimpleActionHelper::prepareExecution(MessageQueueId_t commandedBy, ActionId
|
|||||||
ActionMessage::setStepReply(&reply, actionId, 0, HasActionsIF::IS_BUSY);
|
ActionMessage::setStepReply(&reply, actionId, 0, HasActionsIF::IS_BUSY);
|
||||||
queueToUse->sendMessage(commandedBy, &reply);
|
queueToUse->sendMessage(commandedBy, &reply);
|
||||||
}
|
}
|
||||||
const uint8_t* dataPtr = NULL;
|
const uint8_t* dataPtr = nullptr;
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size);
|
ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size);
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
@ -11,15 +11,15 @@
|
|||||||
class SimpleActionHelper : public ActionHelper {
|
class SimpleActionHelper : public ActionHelper {
|
||||||
public:
|
public:
|
||||||
SimpleActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue);
|
SimpleActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue);
|
||||||
virtual ~SimpleActionHelper();
|
~SimpleActionHelper() override;
|
||||||
void step(ReturnValue_t result = HasReturnvaluesIF::RETURN_OK);
|
void step(ReturnValue_t result = HasReturnvaluesIF::RETURN_OK);
|
||||||
void finish(ReturnValue_t result = HasReturnvaluesIF::RETURN_OK);
|
void finish(ReturnValue_t result = HasReturnvaluesIF::RETURN_OK);
|
||||||
ReturnValue_t reportData(SerializeIF* data);
|
ReturnValue_t reportData(SerializeIF* data);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId,
|
void prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId,
|
||||||
store_address_t dataAddress);
|
store_address_t dataAddress) override;
|
||||||
virtual void resetHelper();
|
void resetHelper() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool isExecuting;
|
bool isExecuting;
|
||||||
@ -28,4 +28,4 @@ class SimpleActionHelper : public ActionHelper {
|
|||||||
uint8_t stepCount = 0;
|
uint8_t stepCount = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* SIMPLEACTIONHELPER_H_ */
|
#endif /* FSFW_ACTION_SIMPLEACTIONHELPER_H_ */
|
||||||
|
@ -12,7 +12,9 @@ object_id_t CFDPHandler::packetDestination = 0;
|
|||||||
|
|
||||||
CFDPHandler::CFDPHandler(object_id_t setObjectId, CFDPDistributor* dist)
|
CFDPHandler::CFDPHandler(object_id_t setObjectId, CFDPDistributor* dist)
|
||||||
: SystemObject(setObjectId) {
|
: SystemObject(setObjectId) {
|
||||||
requestQueue = QueueFactory::instance()->createMessageQueue(CFDP_HANDLER_MAX_RECEPTION);
|
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
|
||||||
|
requestQueue = QueueFactory::instance()->createMessageQueue(
|
||||||
|
CFDP_HANDLER_MAX_RECEPTION, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||||
distributor = dist;
|
distributor = dist;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,4 @@
|
|||||||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
target_sources(${LIB_FSFW_NAME} PRIVATE CFDPHandler.cpp CFDPMessage.cpp)
|
||||||
CFDPHandler.cpp
|
|
||||||
CFDPMessage.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
add_subdirectory(pdu)
|
add_subdirectory(pdu)
|
||||||
add_subdirectory(tlv)
|
add_subdirectory(tlv)
|
||||||
|
@ -1,32 +1,30 @@
|
|||||||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
target_sources(
|
||||||
PduConfig.cpp
|
${LIB_FSFW_NAME}
|
||||||
VarLenField.cpp
|
PRIVATE PduConfig.cpp
|
||||||
HeaderSerializer.cpp
|
VarLenField.cpp
|
||||||
HeaderDeserializer.cpp
|
HeaderSerializer.cpp
|
||||||
FileDirectiveDeserializer.cpp
|
HeaderDeserializer.cpp
|
||||||
FileDirectiveSerializer.cpp
|
FileDirectiveDeserializer.cpp
|
||||||
|
FileDirectiveSerializer.cpp
|
||||||
AckInfo.cpp
|
AckInfo.cpp
|
||||||
AckPduSerializer.cpp
|
AckPduSerializer.cpp
|
||||||
AckPduDeserializer.cpp
|
AckPduDeserializer.cpp
|
||||||
EofInfo.cpp
|
EofInfo.cpp
|
||||||
EofPduSerializer.cpp
|
EofPduSerializer.cpp
|
||||||
EofPduDeserializer.cpp
|
EofPduDeserializer.cpp
|
||||||
NakInfo.cpp
|
NakInfo.cpp
|
||||||
NakPduSerializer.cpp
|
NakPduSerializer.cpp
|
||||||
NakPduDeserializer.cpp
|
NakPduDeserializer.cpp
|
||||||
FinishedInfo.cpp
|
FinishedInfo.cpp
|
||||||
FinishedPduSerializer.cpp
|
FinishedPduSerializer.cpp
|
||||||
FinishedPduDeserializer.cpp
|
FinishedPduDeserializer.cpp
|
||||||
MetadataInfo.cpp
|
MetadataInfo.cpp
|
||||||
MetadataPduSerializer.cpp
|
MetadataPduSerializer.cpp
|
||||||
MetadataPduDeserializer.cpp
|
MetadataPduDeserializer.cpp
|
||||||
KeepAlivePduSerializer.cpp
|
KeepAlivePduSerializer.cpp
|
||||||
KeepAlivePduDeserializer.cpp
|
KeepAlivePduDeserializer.cpp
|
||||||
PromptPduSerializer.cpp
|
PromptPduSerializer.cpp
|
||||||
PromptPduDeserializer.cpp
|
PromptPduDeserializer.cpp
|
||||||
|
FileDataSerializer.cpp
|
||||||
FileDataSerializer.cpp
|
FileDataDeserializer.cpp
|
||||||
FileDataDeserializer.cpp
|
FileDataInfo.cpp)
|
||||||
FileDataInfo.cpp
|
|
||||||
)
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
target_sources(
|
||||||
EntityIdTlv.cpp
|
${LIB_FSFW_NAME}
|
||||||
FilestoreRequestTlv.cpp
|
PRIVATE EntityIdTlv.cpp
|
||||||
FilestoreResponseTlv.cpp
|
FilestoreRequestTlv.cpp
|
||||||
Lv.cpp
|
FilestoreResponseTlv.cpp
|
||||||
Tlv.cpp
|
Lv.cpp
|
||||||
FlowLabelTlv.cpp
|
Tlv.cpp
|
||||||
MessageToUserTlv.cpp
|
FlowLabelTlv.cpp
|
||||||
FaultHandlerOverrideTlv.cpp
|
MessageToUserTlv.cpp
|
||||||
)
|
FaultHandlerOverrideTlv.cpp)
|
||||||
|
@ -1,5 +1,2 @@
|
|||||||
target_sources(${LIB_FSFW_NAME}
|
target_sources(${LIB_FSFW_NAME} PRIVATE SharedRingBuffer.cpp
|
||||||
PRIVATE
|
SimpleRingBuffer.cpp)
|
||||||
SharedRingBuffer.cpp
|
|
||||||
SimpleRingBuffer.cpp
|
|
||||||
)
|
|
||||||
|
@ -5,89 +5,88 @@
|
|||||||
#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;
|
||||||
} else {
|
} else {
|
||||||
values[writeIndex] = value;
|
values[writeIndex] = value;
|
||||||
writeIndex = next(writeIndex);
|
writeIndex = next(writeIndex);
|
||||||
++currentSize;
|
++currentSize;
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
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];
|
|
||||||
readIndex = next(readIndex);
|
|
||||||
--currentSize;
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
}
|
||||||
|
*value = values[readIndex];
|
||||||
|
readIndex = next(readIndex);
|
||||||
|
--currentSize;
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
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];
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
}
|
||||||
|
*value = values[readIndex];
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
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) {
|
||||||
current = 0;
|
current = 0;
|
||||||
}
|
}
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -12,6 +12,7 @@ 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> {
|
||||||
static_assert(MAX_SIZE <= std::numeric_limits<count_t>::max(),
|
static_assert(MAX_SIZE <= std::numeric_limits<count_t>::max(),
|
||||||
"count_t is not large enough to hold MAX_SIZE");
|
"count_t is not large enough to hold MAX_SIZE");
|
||||||
|
|
||||||
private:
|
private:
|
||||||
T data[MAX_SIZE];
|
T data[MAX_SIZE];
|
||||||
|
|
||||||
|
@ -1,109 +1,109 @@
|
|||||||
#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;
|
||||||
if (storedValue != nullptr) {
|
if (storedValue != nullptr) {
|
||||||
*storedValue = Iterator(&theMap[position]);
|
*storedValue = Iterator(&theMap[position]);
|
||||||
}
|
}
|
||||||
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) {
|
||||||
result = HasReturnvaluesIF::RETURN_OK;
|
result = HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
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) {
|
||||||
return KEY_DOES_NOT_EXIST;
|
return KEY_DOES_NOT_EXIST;
|
||||||
}
|
}
|
||||||
removeFromPosition(i);
|
removeFromPosition(i);
|
||||||
if (*iter != begin()) {
|
if (*iter != begin()) {
|
||||||
(*iter)--;
|
(*iter)--;
|
||||||
} else {
|
} else {
|
||||||
*iter = begin();
|
*iter = begin();
|
||||||
}
|
}
|
||||||
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) {
|
||||||
return KEY_DOES_NOT_EXIST;
|
return KEY_DOES_NOT_EXIST;
|
||||||
}
|
}
|
||||||
do {
|
do {
|
||||||
removeFromPosition(i);
|
removeFromPosition(i);
|
||||||
i = findFirstIndex(key, i);
|
i = findFirstIndex(key, i);
|
||||||
} while (i < _size);
|
} while (i < _size);
|
||||||
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) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
*value = &theMap[findFirstIndex(key)].second;
|
*value = &theMap[findFirstIndex(key)].second;
|
||||||
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,
|
||||||
if (startAt >= _size) {
|
size_t startAt) const {
|
||||||
return startAt + 1;
|
if (startAt >= _size) {
|
||||||
|
return startAt + 1;
|
||||||
|
}
|
||||||
|
size_t i = startAt;
|
||||||
|
for (i = startAt; i < _size; ++i) {
|
||||||
|
if (theMap[i].first == key) {
|
||||||
|
return i;
|
||||||
}
|
}
|
||||||
size_t i = startAt;
|
}
|
||||||
for (i = startAt; i < _size; ++i) {
|
return i;
|
||||||
if (theMap[i].first == key) {
|
|
||||||
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) {
|
||||||
if (myComp(key, theMap[i].first)) {
|
if (myComp(key, theMap[i].first)) {
|
||||||
return i;
|
return i;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
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_ */
|
||||||
|
@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
#include "fsfw/FSFW.h"
|
||||||
|
#include "fsfw/serviceinterface.h"
|
||||||
|
|
||||||
SimpleRingBuffer::SimpleRingBuffer(const size_t size, bool overwriteOld, size_t maxExcessBytes)
|
SimpleRingBuffer::SimpleRingBuffer(const size_t size, bool overwriteOld, size_t maxExcessBytes)
|
||||||
: RingBufferBase<>(0, size, overwriteOld), maxExcessBytes(maxExcessBytes) {
|
: RingBufferBase<>(0, size, overwriteOld), maxExcessBytes(maxExcessBytes) {
|
||||||
if (maxExcessBytes > size) {
|
if (maxExcessBytes > size) {
|
||||||
@ -48,6 +51,19 @@ void SimpleRingBuffer::confirmBytesWritten(size_t amount) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t SimpleRingBuffer::writeData(const uint8_t* data, size_t amount) {
|
ReturnValue_t SimpleRingBuffer::writeData(const uint8_t* data, size_t amount) {
|
||||||
|
if (data == nullptr) {
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
if (amount > getMaxSize()) {
|
||||||
|
#if FSFW_VERBOSE_LEVEL >= 1
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::error << "SimpleRingBuffer::writeData: Amount of data too large" << std::endl;
|
||||||
|
#else
|
||||||
|
sif::printError("SimpleRingBuffer::writeData: Amount of data too large\n");
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
if (availableWriteSpace() >= amount or overwriteOld) {
|
if (availableWriteSpace() >= amount or overwriteOld) {
|
||||||
size_t amountTillWrap = writeTillWrap();
|
size_t amountTillWrap = writeTillWrap();
|
||||||
if (amountTillWrap >= amount) {
|
if (amountTillWrap >= amount) {
|
||||||
|
@ -1,4 +1,2 @@
|
|||||||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
target_sources(${LIB_FSFW_NAME} PRIVATE ControllerBase.cpp
|
||||||
ControllerBase.cpp
|
ExtendedControllerBase.cpp)
|
||||||
ExtendedControllerBase.cpp
|
|
||||||
)
|
|
||||||
|
@ -13,7 +13,9 @@ ControllerBase::ControllerBase(object_id_t setObjectId, object_id_t parentId,
|
|||||||
submode(SUBMODE_NONE),
|
submode(SUBMODE_NONE),
|
||||||
modeHelper(this),
|
modeHelper(this),
|
||||||
healthHelper(this, setObjectId) {
|
healthHelper(this, setObjectId) {
|
||||||
commandQueue = QueueFactory::instance()->createMessageQueue(commandQueueDepth);
|
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
|
||||||
|
commandQueue = QueueFactory::instance()->createMessageQueue(
|
||||||
|
commandQueueDepth, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
ControllerBase::~ControllerBase() { QueueFactory::instance()->deleteMessageQueue(commandQueue); }
|
ControllerBase::~ControllerBase() { QueueFactory::instance()->deleteMessageQueue(commandQueue); }
|
||||||
@ -26,7 +28,7 @@ ReturnValue_t ControllerBase::initialize() {
|
|||||||
|
|
||||||
MessageQueueId_t parentQueue = 0;
|
MessageQueueId_t parentQueue = 0;
|
||||||
if (parentId != objects::NO_OBJECT) {
|
if (parentId != objects::NO_OBJECT) {
|
||||||
SubsystemBase* parent = ObjectManager::instance()->get<SubsystemBase>(parentId);
|
auto* parent = ObjectManager::instance()->get<SubsystemBase>(parentId);
|
||||||
if (parent == nullptr) {
|
if (parent == nullptr) {
|
||||||
return RETURN_FAILED;
|
return RETURN_FAILED;
|
||||||
}
|
}
|
||||||
@ -52,7 +54,7 @@ MessageQueueId_t ControllerBase::getCommandQueue() const { return commandQueue->
|
|||||||
|
|
||||||
void ControllerBase::handleQueue() {
|
void ControllerBase::handleQueue() {
|
||||||
CommandMessage command;
|
CommandMessage command;
|
||||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
ReturnValue_t result;
|
||||||
for (result = commandQueue->receiveMessage(&command); result == RETURN_OK;
|
for (result = commandQueue->receiveMessage(&command); result == RETURN_OK;
|
||||||
result = commandQueue->receiveMessage(&command)) {
|
result = commandQueue->receiveMessage(&command)) {
|
||||||
result = modeHelper.handleModeCommand(&command);
|
result = modeHelper.handleModeCommand(&command);
|
||||||
@ -73,20 +75,20 @@ void ControllerBase::handleQueue() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ControllerBase::startTransition(Mode_t mode, Submode_t submode) {
|
void ControllerBase::startTransition(Mode_t mode_, Submode_t submode_) {
|
||||||
changeHK(this->mode, this->submode, false);
|
changeHK(this->mode, this->submode, false);
|
||||||
triggerEvent(CHANGING_MODE, mode, submode);
|
triggerEvent(CHANGING_MODE, mode, submode);
|
||||||
this->mode = mode;
|
mode = mode_;
|
||||||
this->submode = submode;
|
submode = submode_;
|
||||||
modeHelper.modeChanged(mode, submode);
|
modeHelper.modeChanged(mode, submode);
|
||||||
modeChanged(mode, submode);
|
modeChanged(mode, submode);
|
||||||
announceMode(false);
|
announceMode(false);
|
||||||
changeHK(this->mode, this->submode, true);
|
changeHK(this->mode, this->submode, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ControllerBase::getMode(Mode_t* mode, Submode_t* submode) {
|
void ControllerBase::getMode(Mode_t* mode_, Submode_t* submode_) {
|
||||||
*mode = this->mode;
|
*mode_ = this->mode;
|
||||||
*submode = this->submode;
|
*submode_ = this->submode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ControllerBase::setToExternalControl() { healthHelper.setHealth(EXTERNAL_CONTROL); }
|
void ControllerBase::setToExternalControl() { healthHelper.setHealth(EXTERNAL_CONTROL); }
|
||||||
@ -99,7 +101,7 @@ ReturnValue_t ControllerBase::performOperation(uint8_t opCode) {
|
|||||||
return RETURN_OK;
|
return RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ControllerBase::modeChanged(Mode_t mode, Submode_t submode) { return; }
|
void ControllerBase::modeChanged(Mode_t mode_, Submode_t submode_) {}
|
||||||
|
|
||||||
ReturnValue_t ControllerBase::setHealth(HealthState health) {
|
ReturnValue_t ControllerBase::setHealth(HealthState health) {
|
||||||
switch (health) {
|
switch (health) {
|
||||||
@ -115,6 +117,6 @@ ReturnValue_t ControllerBase::setHealth(HealthState health) {
|
|||||||
HasHealthIF::HealthState ControllerBase::getHealth() { return healthHelper.getHealth(); }
|
HasHealthIF::HealthState ControllerBase::getHealth() { return healthHelper.getHealth(); }
|
||||||
void ControllerBase::setTaskIF(PeriodicTaskIF* task_) { executingTask = task_; }
|
void ControllerBase::setTaskIF(PeriodicTaskIF* task_) { executingTask = task_; }
|
||||||
|
|
||||||
void ControllerBase::changeHK(Mode_t mode, Submode_t submode, bool enable) {}
|
void ControllerBase::changeHK(Mode_t mode_, Submode_t submode_, bool enable) {}
|
||||||
|
|
||||||
ReturnValue_t ControllerBase::initializeAfterTaskCreation() { return HasReturnvaluesIF::RETURN_OK; }
|
ReturnValue_t ControllerBase::initializeAfterTaskCreation() { return HasReturnvaluesIF::RETURN_OK; }
|
||||||
|
@ -24,21 +24,21 @@ class ControllerBase : public HasModesIF,
|
|||||||
static const Mode_t MODE_NORMAL = 2;
|
static const Mode_t MODE_NORMAL = 2;
|
||||||
|
|
||||||
ControllerBase(object_id_t setObjectId, object_id_t parentId, size_t commandQueueDepth = 3);
|
ControllerBase(object_id_t setObjectId, object_id_t parentId, size_t commandQueueDepth = 3);
|
||||||
virtual ~ControllerBase();
|
~ControllerBase() override;
|
||||||
|
|
||||||
/** SystemObject override */
|
/** SystemObject override */
|
||||||
virtual ReturnValue_t initialize() override;
|
ReturnValue_t initialize() override;
|
||||||
|
|
||||||
virtual MessageQueueId_t getCommandQueue() const override;
|
[[nodiscard]] MessageQueueId_t getCommandQueue() const override;
|
||||||
|
|
||||||
/** HasHealthIF overrides */
|
/** HasHealthIF overrides */
|
||||||
virtual ReturnValue_t setHealth(HealthState health) override;
|
ReturnValue_t setHealth(HealthState health) override;
|
||||||
virtual HasHealthIF::HealthState getHealth() override;
|
HasHealthIF::HealthState getHealth() override;
|
||||||
|
|
||||||
/** ExecutableObjectIF overrides */
|
/** ExecutableObjectIF overrides */
|
||||||
virtual ReturnValue_t performOperation(uint8_t opCode) override;
|
ReturnValue_t performOperation(uint8_t opCode) override;
|
||||||
virtual void setTaskIF(PeriodicTaskIF *task) override;
|
void setTaskIF(PeriodicTaskIF *task) override;
|
||||||
virtual ReturnValue_t initializeAfterTaskCreation() override;
|
ReturnValue_t initializeAfterTaskCreation() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
@ -54,8 +54,8 @@ class ControllerBase : public HasModesIF,
|
|||||||
*/
|
*/
|
||||||
virtual void performControlOperation() = 0;
|
virtual void performControlOperation() = 0;
|
||||||
|
|
||||||
virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
|
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
|
||||||
uint32_t *msToReachTheMode) override = 0;
|
uint32_t *msToReachTheMode) override = 0;
|
||||||
|
|
||||||
const object_id_t parentId;
|
const object_id_t parentId;
|
||||||
|
|
||||||
@ -80,10 +80,10 @@ 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) override;
|
void startTransition(Mode_t mode, Submode_t submode) override;
|
||||||
virtual void getMode(Mode_t *mode, Submode_t *submode) override;
|
void getMode(Mode_t *mode, Submode_t *submode) override;
|
||||||
virtual void setToExternalControl() override;
|
void setToExternalControl() override;
|
||||||
virtual void announceMode(bool recursive);
|
void announceMode(bool recursive) override;
|
||||||
/** 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);
|
||||||
};
|
};
|
||||||
|
@ -6,7 +6,7 @@ ExtendedControllerBase::ExtendedControllerBase(object_id_t objectId, object_id_t
|
|||||||
poolManager(this, commandQueue),
|
poolManager(this, commandQueue),
|
||||||
actionHelper(this, commandQueue) {}
|
actionHelper(this, commandQueue) {}
|
||||||
|
|
||||||
ExtendedControllerBase::~ExtendedControllerBase() {}
|
ExtendedControllerBase::~ExtendedControllerBase() = default;
|
||||||
|
|
||||||
ReturnValue_t ExtendedControllerBase::executeAction(ActionId_t actionId,
|
ReturnValue_t ExtendedControllerBase::executeAction(ActionId_t actionId,
|
||||||
MessageQueueId_t commandedBy,
|
MessageQueueId_t commandedBy,
|
||||||
@ -31,7 +31,7 @@ ReturnValue_t ExtendedControllerBase::handleCommandMessage(CommandMessage *messa
|
|||||||
|
|
||||||
void ExtendedControllerBase::handleQueue() {
|
void ExtendedControllerBase::handleQueue() {
|
||||||
CommandMessage command;
|
CommandMessage command;
|
||||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
ReturnValue_t result;
|
||||||
for (result = commandQueue->receiveMessage(&command); result == RETURN_OK;
|
for (result = commandQueue->receiveMessage(&command); result == RETURN_OK;
|
||||||
result = commandQueue->receiveMessage(&command)) {
|
result = commandQueue->receiveMessage(&command)) {
|
||||||
result = actionHelper.handleActionMessage(&command);
|
result = actionHelper.handleActionMessage(&command);
|
||||||
|
@ -18,16 +18,16 @@ class ExtendedControllerBase : public ControllerBase,
|
|||||||
public HasLocalDataPoolIF {
|
public HasLocalDataPoolIF {
|
||||||
public:
|
public:
|
||||||
ExtendedControllerBase(object_id_t objectId, object_id_t parentId, size_t commandQueueDepth = 3);
|
ExtendedControllerBase(object_id_t objectId, object_id_t parentId, size_t commandQueueDepth = 3);
|
||||||
virtual ~ExtendedControllerBase();
|
~ExtendedControllerBase() override;
|
||||||
|
|
||||||
/* SystemObjectIF overrides */
|
/* SystemObjectIF overrides */
|
||||||
virtual ReturnValue_t initialize() override;
|
ReturnValue_t initialize() override;
|
||||||
|
|
||||||
virtual MessageQueueId_t getCommandQueue() const override;
|
[[nodiscard]] MessageQueueId_t getCommandQueue() const override;
|
||||||
|
|
||||||
/* ExecutableObjectIF overrides */
|
/* ExecutableObjectIF overrides */
|
||||||
virtual ReturnValue_t performOperation(uint8_t opCode) override;
|
ReturnValue_t performOperation(uint8_t opCode) override;
|
||||||
virtual ReturnValue_t initializeAfterTaskCreation() override;
|
ReturnValue_t initializeAfterTaskCreation() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
LocalDataPoolManager poolManager;
|
LocalDataPoolManager poolManager;
|
||||||
@ -39,32 +39,32 @@ class ExtendedControllerBase : public ControllerBase,
|
|||||||
* @param message
|
* @param message
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
virtual ReturnValue_t handleCommandMessage(CommandMessage* message) = 0;
|
ReturnValue_t handleCommandMessage(CommandMessage* message) override = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Periodic helper from ControllerBase, implemented by child class.
|
* Periodic helper from ControllerBase, implemented by child class.
|
||||||
*/
|
*/
|
||||||
virtual void performControlOperation() = 0;
|
void performControlOperation() override = 0;
|
||||||
|
|
||||||
/* Handle the four messages mentioned above */
|
/* Handle the four messages mentioned above */
|
||||||
void handleQueue() override;
|
void handleQueue() override;
|
||||||
|
|
||||||
/* HasActionsIF overrides */
|
/* HasActionsIF overrides */
|
||||||
virtual ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
|
ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
|
||||||
const uint8_t* data, size_t size) override;
|
const uint8_t* data, size_t size) override;
|
||||||
|
|
||||||
/* HasLocalDatapoolIF overrides */
|
/* HasLocalDatapoolIF overrides */
|
||||||
virtual LocalDataPoolManager* getHkManagerHandle() override;
|
LocalDataPoolManager* getHkManagerHandle() override;
|
||||||
virtual object_id_t getObjectId() const override;
|
[[nodiscard]] object_id_t getObjectId() const override;
|
||||||
virtual uint32_t getPeriodicOperationFrequency() const override;
|
[[nodiscard]] uint32_t getPeriodicOperationFrequency() const override;
|
||||||
|
|
||||||
virtual ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
|
ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
|
||||||
LocalDataPoolManager& poolManager) override = 0;
|
LocalDataPoolManager& poolManager) override = 0;
|
||||||
virtual LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override = 0;
|
LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override = 0;
|
||||||
|
|
||||||
// Mode abstract functions
|
// Mode abstract functions
|
||||||
virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
|
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
|
||||||
uint32_t* msToReachTheMode) override = 0;
|
uint32_t* msToReachTheMode) override = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* FSFW_CONTROLLER_EXTENDEDCONTROLLERBASE_H_ */
|
#endif /* FSFW_CONTROLLER_EXTENDEDCONTROLLERBASE_H_ */
|
||||||
|
@ -1,5 +1,2 @@
|
|||||||
target_sources(${LIB_FSFW_NAME}
|
target_sources(${LIB_FSFW_NAME} PRIVATE CoordinateTransformations.cpp
|
||||||
PRIVATE
|
Sgp4Propagator.cpp)
|
||||||
CoordinateTransformations.cpp
|
|
||||||
Sgp4Propagator.cpp
|
|
||||||
)
|
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
target_sources(${LIB_FSFW_NAME}
|
target_sources(
|
||||||
PRIVATE
|
${LIB_FSFW_NAME}
|
||||||
Clcw.cpp
|
PRIVATE Clcw.cpp
|
||||||
DataLinkLayer.cpp
|
DataLinkLayer.cpp
|
||||||
Farm1StateLockout.cpp
|
Farm1StateLockout.cpp
|
||||||
Farm1StateOpen.cpp
|
Farm1StateOpen.cpp
|
||||||
Farm1StateWait.cpp
|
Farm1StateWait.cpp
|
||||||
MapPacketExtraction.cpp
|
MapPacketExtraction.cpp
|
||||||
TcTransferFrame.cpp
|
TcTransferFrame.cpp
|
||||||
TcTransferFrameLocal.cpp
|
TcTransferFrameLocal.cpp
|
||||||
VirtualChannelReception.cpp
|
VirtualChannelReception.cpp)
|
||||||
)
|
|
||||||
|
@ -1,4 +1 @@
|
|||||||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
target_sources(${LIB_FSFW_NAME} PRIVATE PoolDataSetBase.cpp PoolEntry.cpp)
|
||||||
PoolDataSetBase.cpp
|
|
||||||
PoolEntry.cpp
|
|
||||||
)
|
|
||||||
|
@ -7,24 +7,26 @@
|
|||||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
PoolEntry<T>::PoolEntry(std::initializer_list<T> initValue, bool setValid)
|
PoolEntry<T>::PoolEntry(uint8_t len, bool setValid) : length(len), valid(setValid) {
|
||||||
: length(static_cast<uint8_t>(initValue.size())), valid(setValid) {
|
this->address = new T[this->length]();
|
||||||
this->address = new T[this->length];
|
std::memset(this->address, 0, this->getByteSize());
|
||||||
if (initValue.size() == 0) {
|
}
|
||||||
std::memset(this->address, 0, this->getByteSize());
|
|
||||||
} else {
|
template <typename T>
|
||||||
std::copy(initValue.begin(), initValue.end(), this->address);
|
PoolEntry<T>::PoolEntry(std::initializer_list<T> initValues, bool setValid)
|
||||||
|
: length(static_cast<uint8_t>(initValues.size())), valid(setValid) {
|
||||||
|
this->address = new T[this->length]();
|
||||||
|
if (initValues.size() > 0) {
|
||||||
|
std::copy(initValues.begin(), initValues.end(), this->address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
PoolEntry<T>::PoolEntry(T* initValue, uint8_t setLength, bool setValid)
|
PoolEntry<T>::PoolEntry(const T* initValue, uint8_t setLength, bool setValid)
|
||||||
: length(setLength), valid(setValid) {
|
: length(setLength), valid(setValid) {
|
||||||
this->address = new T[this->length];
|
this->address = new T[this->length]();
|
||||||
if (initValue != nullptr) {
|
if (initValue != nullptr) {
|
||||||
std::memcpy(this->address, initValue, this->getByteSize());
|
std::memcpy(this->address, initValue, this->getByteSize());
|
||||||
} else {
|
|
||||||
std::memset(this->address, 0, this->getByteSize());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,6 +33,9 @@ class PoolEntry : public PoolEntryIF {
|
|||||||
"instead! The ECSS standard defines a boolean as a one bit "
|
"instead! The ECSS standard defines a boolean as a one bit "
|
||||||
"field. Therefore it is preferred to store a boolean as an "
|
"field. Therefore it is preferred to store a boolean as an "
|
||||||
"uint8_t");
|
"uint8_t");
|
||||||
|
|
||||||
|
PoolEntry(uint8_t len = 1, bool setValid = false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief In the classe's constructor, space is allocated on the heap and
|
* @brief In the classe's constructor, space is allocated on the heap and
|
||||||
* potential initialization values are copied to that space.
|
* potential initialization values are copied to that space.
|
||||||
@ -49,7 +52,7 @@ class PoolEntry : public PoolEntryIF {
|
|||||||
* @param setValid
|
* @param setValid
|
||||||
* Sets the initialization flag. It is invalid by default.
|
* Sets the initialization flag. It is invalid by default.
|
||||||
*/
|
*/
|
||||||
PoolEntry(std::initializer_list<T> initValue = {0}, bool setValid = false);
|
PoolEntry(std::initializer_list<T> initValue, bool setValid = false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief In the classe's constructor, space is allocated on the heap and
|
* @brief In the classe's constructor, space is allocated on the heap and
|
||||||
@ -62,7 +65,7 @@ class PoolEntry : public PoolEntryIF {
|
|||||||
* @param setValid
|
* @param setValid
|
||||||
* Sets the initialization flag. It is invalid by default.
|
* Sets the initialization flag. It is invalid by default.
|
||||||
*/
|
*/
|
||||||
PoolEntry(T* initValue, uint8_t setLength = 1, bool setValid = false);
|
PoolEntry(const T* initValue, uint8_t setLength = 1, bool setValid = false);
|
||||||
|
|
||||||
//! Explicitely deleted copy ctor, copying is not allowed.
|
//! Explicitely deleted copy ctor, copying is not allowed.
|
||||||
PoolEntry(const PoolEntry&) = delete;
|
PoolEntry(const PoolEntry&) = delete;
|
||||||
|
@ -1,10 +1,6 @@
|
|||||||
target_sources(${LIB_FSFW_NAME}
|
target_sources(
|
||||||
PRIVATE
|
${LIB_FSFW_NAME}
|
||||||
LocalDataPoolManager.cpp
|
PRIVATE LocalDataPoolManager.cpp LocalDataSet.cpp LocalPoolDataSetBase.cpp
|
||||||
LocalDataSet.cpp
|
LocalPoolObjectBase.cpp SharedLocalDataSet.cpp)
|
||||||
LocalPoolDataSetBase.cpp
|
|
||||||
LocalPoolObjectBase.cpp
|
|
||||||
SharedLocalDataSet.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
add_subdirectory(internal)
|
add_subdirectory(internal)
|
||||||
|
@ -577,6 +577,10 @@ ReturnValue_t LocalDataPoolManager::handleHousekeepingMessage(CommandMessage* me
|
|||||||
|
|
||||||
CommandMessage reply;
|
CommandMessage reply;
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
if (result == WRONG_HK_PACKET_TYPE) {
|
||||||
|
printWarningOrError(sif::OutputTypes::OUT_WARNING, "handleHousekeepingMessage",
|
||||||
|
WRONG_HK_PACKET_TYPE);
|
||||||
|
}
|
||||||
HousekeepingMessage::setHkRequestFailureReply(&reply, sid, result);
|
HousekeepingMessage::setHkRequestFailureReply(&reply, sid, result);
|
||||||
} else {
|
} else {
|
||||||
HousekeepingMessage::setHkRequestSuccessReply(&reply, sid);
|
HousekeepingMessage::setHkRequestSuccessReply(&reply, sid);
|
||||||
@ -696,9 +700,10 @@ void LocalDataPoolManager::performPeriodicHkGeneration(HkReceiver& receiver) {
|
|||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
/* Configuration error */
|
/* Configuration error */
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::warning << "LocalDataPoolManager::performHkOperation: HK generation failed." << std::endl;
|
sif::warning << "LocalDataPoolManager::performPeriodicHkOperation: HK generation failed."
|
||||||
|
<< std::endl;
|
||||||
#else
|
#else
|
||||||
sif::printWarning("LocalDataPoolManager::performHkOperation: HK generation failed.\n");
|
sif::printWarning("LocalDataPoolManager::performPeriodicHkOperation: HK generation failed.\n");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -834,6 +839,8 @@ void LocalDataPoolManager::printWarningOrError(sif::OutputTypes outputType,
|
|||||||
errorPrint = "Dataset not found";
|
errorPrint = "Dataset not found";
|
||||||
} else if (error == POOLOBJECT_NOT_FOUND) {
|
} else if (error == POOLOBJECT_NOT_FOUND) {
|
||||||
errorPrint = "Pool Object not found";
|
errorPrint = "Pool Object not found";
|
||||||
|
} else if (error == WRONG_HK_PACKET_TYPE) {
|
||||||
|
errorPrint = "Wrong Packet Type";
|
||||||
} else if (error == HasReturnvaluesIF::RETURN_FAILED) {
|
} else if (error == HasReturnvaluesIF::RETURN_FAILED) {
|
||||||
if (outputType == sif::OutputTypes::OUT_WARNING) {
|
if (outputType == sif::OutputTypes::OUT_WARNING) {
|
||||||
errorPrint = "Generic Warning";
|
errorPrint = "Generic Warning";
|
||||||
|
@ -162,6 +162,7 @@ class LocalPoolDataSetBase : public PoolDataSetBase, public MarkChangedIF {
|
|||||||
object_id_t getCreatorObjectId();
|
object_id_t getCreatorObjectId();
|
||||||
|
|
||||||
bool getReportingEnabled() const;
|
bool getReportingEnabled() const;
|
||||||
|
void setReportingEnabled(bool enabled);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the current periodic HK generation interval this set
|
* Returns the current periodic HK generation interval this set
|
||||||
@ -189,7 +190,6 @@ class LocalPoolDataSetBase : public PoolDataSetBase, public MarkChangedIF {
|
|||||||
* Used for periodic generation.
|
* Used for periodic generation.
|
||||||
*/
|
*/
|
||||||
bool reportingEnabled = false;
|
bool reportingEnabled = false;
|
||||||
void setReportingEnabled(bool enabled);
|
|
||||||
|
|
||||||
void initializePeriodicHelper(float collectionInterval, dur_millis_t minimumPeriodicInterval,
|
void initializePeriodicHelper(float collectionInterval, dur_millis_t minimumPeriodicInterval,
|
||||||
uint8_t nonDiagIntervalFactor = 5);
|
uint8_t nonDiagIntervalFactor = 5);
|
||||||
|
@ -5,205 +5,189 @@
|
|||||||
#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){}
|
return readWithoutLock();
|
||||||
|
}
|
||||||
|
MutexIF* mutex = LocalDpManagerAttorney::getMutexHandle(*hkManager);
|
||||||
template<typename T>
|
ReturnValue_t result = mutex->lockMutex(timeoutType, timeoutMs);
|
||||||
inline ReturnValue_t LocalPoolVariable<T>::read(
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) {
|
|
||||||
if(hkManager == nullptr) {
|
|
||||||
return readWithoutLock();
|
|
||||||
}
|
|
||||||
MutexIF* mutex = LocalDpManagerAttorney::getMutexHandle(*hkManager);
|
|
||||||
ReturnValue_t result = mutex->lockMutex(timeoutType, timeoutMs);
|
|
||||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
result = readWithoutLock();
|
|
||||||
mutex->unlockMutex();
|
|
||||||
return result;
|
return result;
|
||||||
|
}
|
||||||
|
result = readWithoutLock();
|
||||||
|
mutex->unlockMutex();
|
||||||
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
this->value = *(poolEntry->getDataPtr());
|
|
||||||
this->valid = poolEntry->getValid();
|
|
||||||
return RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline ReturnValue_t LocalPoolVariable<T>::commit(bool setValid,
|
|
||||||
MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) {
|
|
||||||
this->setValid(setValid);
|
|
||||||
return commit(timeoutType, timeoutMs);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline ReturnValue_t LocalPoolVariable<T>::commit(
|
|
||||||
MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) {
|
|
||||||
if(hkManager == nullptr) {
|
|
||||||
return commitWithoutLock();
|
|
||||||
}
|
|
||||||
MutexIF* mutex = LocalDpManagerAttorney::getMutexHandle(*hkManager);
|
|
||||||
ReturnValue_t result = mutex->lockMutex(timeoutType, timeoutMs);
|
|
||||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
result = commitWithoutLock();
|
|
||||||
mutex->unlockMutex();
|
|
||||||
return result;
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->value = *(poolEntry->getDataPtr());
|
||||||
|
this->valid = poolEntry->getValid();
|
||||||
|
return RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
|
inline ReturnValue_t LocalPoolVariable<T>::commit(bool setValid, MutexIF::TimeoutType timeoutType,
|
||||||
|
uint32_t timeoutMs) {
|
||||||
|
this->setValid(setValid);
|
||||||
|
return commit(timeoutType, timeoutMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline ReturnValue_t LocalPoolVariable<T>::commit(MutexIF::TimeoutType timeoutType,
|
||||||
|
uint32_t timeoutMs) {
|
||||||
|
if (hkManager == nullptr) {
|
||||||
|
return commitWithoutLock();
|
||||||
|
}
|
||||||
|
MutexIF* mutex = LocalDpManagerAttorney::getMutexHandle(*hkManager);
|
||||||
|
ReturnValue_t result = mutex->lockMutex(timeoutType, timeoutMs);
|
||||||
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
result = commitWithoutLock();
|
||||||
|
mutex->unlockMutex();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
*(poolEntry->getDataPtr()) = this->value;
|
*(poolEntry->getDataPtr()) = this->value;
|
||||||
poolEntry->setValid(this->valid);
|
poolEntry->setValid(this->valid);
|
||||||
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 <(
|
return this->value < other.value;
|
||||||
const LocalPoolVariable<T> &other) const {
|
|
||||||
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_ */
|
||||||
|
@ -5,174 +5,172 @@
|
|||||||
#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());
|
this->valid = poolEntry->getValid();
|
||||||
this->valid = poolEntry->getValid();
|
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,
|
||||||
this->setValid(valid);
|
uint32_t timeoutMs) {
|
||||||
return commit(timeoutType, timeoutMs);
|
this->setValid(valid);
|
||||||
|
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 =
|
||||||
ReturnValue_t result = LocalDpManagerAttorney::fetchPoolEntry(*hkManager, localPoolId,
|
LocalDpManagerAttorney::fetchPoolEntry(*hkManager, localPoolId, &poolEntry);
|
||||||
&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, localPoolId);
|
||||||
reportReadCommitError("LocalPoolVector", result, false, targetObjectId,
|
|
||||||
localPoolId);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
std::memcpy(poolEntry->getDataPtr(), this->value, poolEntry->getByteSize());
|
|
||||||
poolEntry->setValid(this->valid);
|
|
||||||
return RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, uint16_t vectorSize>
|
|
||||||
inline T& LocalPoolVector<T, vectorSize>::operator [](size_t i) {
|
|
||||||
if(i < vectorSize) {
|
|
||||||
return value[i];
|
|
||||||
}
|
|
||||||
// If this happens, I have to set some value. I consider this
|
|
||||||
// a configuration error, but I wont exit here.
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::warning << "LocalPoolVector: Invalid index. Setting or returning"
|
|
||||||
" last value!" << std::endl;
|
|
||||||
#else
|
|
||||||
sif::printWarning("LocalPoolVector: Invalid index. Setting or returning"
|
|
||||||
" last value!\n");
|
|
||||||
#endif
|
|
||||||
return value[vectorSize - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, uint16_t vectorSize>
|
|
||||||
inline const T& LocalPoolVector<T, vectorSize>::operator [](size_t i) const {
|
|
||||||
if(i < vectorSize) {
|
|
||||||
return value[i];
|
|
||||||
}
|
|
||||||
// If this happens, I have to set some value. I consider this
|
|
||||||
// a configuration error, but I wont exit here.
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::warning << "LocalPoolVector: Invalid index. Setting or returning"
|
|
||||||
" last value!" << std::endl;
|
|
||||||
#else
|
|
||||||
sif::printWarning("LocalPoolVector: Invalid index. Setting or returning"
|
|
||||||
" last value!\n");
|
|
||||||
#endif
|
|
||||||
return value[vectorSize - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, uint16_t vectorSize>
|
|
||||||
inline ReturnValue_t LocalPoolVector<T, vectorSize>::serialize(uint8_t** buffer,
|
|
||||||
size_t* size, size_t maxSize,
|
|
||||||
SerializeIF::Endianness streamEndianness) const {
|
|
||||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED;
|
|
||||||
for (uint16_t i = 0; i < vectorSize; i++) {
|
|
||||||
result = SerializeAdapter::serialize(&(value[i]), buffer, size,
|
|
||||||
maxSize, streamEndianness);
|
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
|
}
|
||||||
|
std::memcpy(poolEntry->getDataPtr(), this->value, poolEntry->getByteSize());
|
||||||
|
poolEntry->setValid(this->valid);
|
||||||
|
return RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, uint16_t vectorSize>
|
template <typename T, uint16_t vectorSize>
|
||||||
|
inline T& LocalPoolVector<T, vectorSize>::operator[](size_t i) {
|
||||||
|
if (i < vectorSize) {
|
||||||
|
return value[i];
|
||||||
|
}
|
||||||
|
// If this happens, I have to set some value. I consider this
|
||||||
|
// a configuration error, but I wont exit here.
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::warning << "LocalPoolVector: Invalid index. Setting or returning"
|
||||||
|
" last value!"
|
||||||
|
<< std::endl;
|
||||||
|
#else
|
||||||
|
sif::printWarning(
|
||||||
|
"LocalPoolVector: Invalid index. Setting or returning"
|
||||||
|
" last value!\n");
|
||||||
|
#endif
|
||||||
|
return value[vectorSize - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, uint16_t vectorSize>
|
||||||
|
inline const T& LocalPoolVector<T, vectorSize>::operator[](size_t i) const {
|
||||||
|
if (i < vectorSize) {
|
||||||
|
return value[i];
|
||||||
|
}
|
||||||
|
// If this happens, I have to set some value. I consider this
|
||||||
|
// a configuration error, but I wont exit here.
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::warning << "LocalPoolVector: Invalid index. Setting or returning"
|
||||||
|
" last value!"
|
||||||
|
<< std::endl;
|
||||||
|
#else
|
||||||
|
sif::printWarning(
|
||||||
|
"LocalPoolVector: Invalid index. Setting or returning"
|
||||||
|
" last value!\n");
|
||||||
|
#endif
|
||||||
|
return value[vectorSize - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, uint16_t vectorSize>
|
||||||
|
inline ReturnValue_t LocalPoolVector<T, vectorSize>::serialize(
|
||||||
|
uint8_t** buffer, size_t* size, size_t maxSize,
|
||||||
|
SerializeIF::Endianness streamEndianness) const {
|
||||||
|
ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
for (uint16_t i = 0; i < vectorSize; i++) {
|
||||||
|
result = SerializeAdapter::serialize(&(value[i]), buffer, size, maxSize, streamEndianness);
|
||||||
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
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, streamEndianness);
|
||||||
result = SerializeAdapter::deSerialize(&(value[i]), buffer, size,
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
streamEndianness);
|
break;
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return result;
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#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 << ", ";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
out << "]";
|
}
|
||||||
return out;
|
out << "]";
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1,5 +1,2 @@
|
|||||||
target_sources(${LIB_FSFW_NAME}
|
target_sources(${LIB_FSFW_NAME} PRIVATE HasLocalDpIFUserAttorney.cpp
|
||||||
PRIVATE
|
HasLocalDpIFManagerAttorney.cpp)
|
||||||
HasLocalDpIFUserAttorney.cpp
|
|
||||||
HasLocalDpIFManagerAttorney.cpp
|
|
||||||
)
|
|
||||||
|
@ -26,11 +26,7 @@ void AssemblyBase::performChildOperation() {
|
|||||||
|
|
||||||
void AssemblyBase::startTransition(Mode_t mode, Submode_t submode) {
|
void AssemblyBase::startTransition(Mode_t mode, Submode_t submode) {
|
||||||
doStartTransition(mode, submode);
|
doStartTransition(mode, submode);
|
||||||
if (modeHelper.isForced()) {
|
triggerModeHelperEvents(mode, submode);
|
||||||
triggerEvent(FORCING_MODE, mode, submode);
|
|
||||||
} else {
|
|
||||||
triggerEvent(CHANGING_MODE, mode, submode);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssemblyBase::doStartTransition(Mode_t mode, Submode_t submode) {
|
void AssemblyBase::doStartTransition(Mode_t mode, Submode_t submode) {
|
||||||
@ -77,9 +73,10 @@ bool AssemblyBase::handleChildrenChangedHealth() {
|
|||||||
}
|
}
|
||||||
HealthState healthState = healthHelper.healthTable->getHealth(iter->first);
|
HealthState healthState = healthHelper.healthTable->getHealth(iter->first);
|
||||||
if (healthState == HasHealthIF::NEEDS_RECOVERY) {
|
if (healthState == HasHealthIF::NEEDS_RECOVERY) {
|
||||||
triggerEvent(TRYING_RECOVERY);
|
triggerEvent(TRYING_RECOVERY, iter->first, 0);
|
||||||
recoveryState = RECOVERY_STARTED;
|
recoveryState = RECOVERY_STARTED;
|
||||||
recoveringDevice = iter;
|
recoveringDevice = iter;
|
||||||
|
// The user needs to take care of commanding the children off in commandChildren
|
||||||
doStartTransition(targetMode, targetSubmode);
|
doStartTransition(targetMode, targetSubmode);
|
||||||
} else {
|
} else {
|
||||||
triggerEvent(CHILD_CHANGED_HEALTH);
|
triggerEvent(CHILD_CHANGED_HEALTH);
|
||||||
@ -228,6 +225,9 @@ ReturnValue_t AssemblyBase::handleHealthReply(CommandMessage* message) {
|
|||||||
bool AssemblyBase::checkAndHandleRecovery() {
|
bool AssemblyBase::checkAndHandleRecovery() {
|
||||||
switch (recoveryState) {
|
switch (recoveryState) {
|
||||||
case RECOVERY_STARTED:
|
case RECOVERY_STARTED:
|
||||||
|
// The recovery was already start in #handleChildrenChangedHealth and we just need
|
||||||
|
// to wait for an off time period.
|
||||||
|
// TODO: make time period configurable
|
||||||
recoveryState = RECOVERY_WAIT;
|
recoveryState = RECOVERY_WAIT;
|
||||||
recoveryOffTimer.resetTimer();
|
recoveryOffTimer.resetTimer();
|
||||||
return true;
|
return true;
|
||||||
@ -266,3 +266,11 @@ void AssemblyBase::overwriteDeviceHealth(object_id_t objectId, HasHealthIF::Heal
|
|||||||
modeHelper.setForced(true);
|
modeHelper.setForced(true);
|
||||||
sendHealthCommand(childrenMap[objectId].commandQueue, EXTERNAL_CONTROL);
|
sendHealthCommand(childrenMap[objectId].commandQueue, EXTERNAL_CONTROL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AssemblyBase::triggerModeHelperEvents(Mode_t mode, Submode_t submode) {
|
||||||
|
if (modeHelper.isForced()) {
|
||||||
|
triggerEvent(FORCING_MODE, mode, submode);
|
||||||
|
} else {
|
||||||
|
triggerEvent(CHANGING_MODE, mode, submode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -12,7 +12,8 @@
|
|||||||
* Documentation: Dissertation Baetz p.156, 157.
|
* Documentation: Dissertation Baetz p.156, 157.
|
||||||
*
|
*
|
||||||
* This class reduces the complexity of controller components which would
|
* This class reduces the complexity of controller components which would
|
||||||
* otherwise be needed for the handling of redundant devices.
|
* otherwise be needed for the handling of redundant devices. However, it can also be used to
|
||||||
|
* manage the mode keeping and recovery of non-redundant devices
|
||||||
*
|
*
|
||||||
* The template class monitors mode and health state of its children
|
* The template class monitors mode and health state of its children
|
||||||
* and checks availability of devices on every detected change.
|
* and checks availability of devices on every detected change.
|
||||||
@ -26,11 +27,9 @@
|
|||||||
*
|
*
|
||||||
* Important:
|
* Important:
|
||||||
*
|
*
|
||||||
* The implementation must call registerChild(object_id_t child)
|
* The implementation must call #registerChild for all commanded children during initialization.
|
||||||
* for all commanded children during initialization.
|
|
||||||
* The implementation must call the initialization function of the base class.
|
* The implementation must call the initialization function of the base class.
|
||||||
* (This will call the function in SubsystemBase)
|
* (This will call the function in SubsystemBase)
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
class AssemblyBase : public SubsystemBase {
|
class AssemblyBase : public SubsystemBase {
|
||||||
public:
|
public:
|
||||||
@ -47,13 +46,14 @@ class AssemblyBase : public SubsystemBase {
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* Command children to reach [mode,submode] combination
|
* Command children to reach [mode,submode] combination. Can be done by setting
|
||||||
* Can be done by setting #commandsOutstanding correctly,
|
* #commandsOutstanding correctly, or using #executeTable. In case of an FDIR recovery,
|
||||||
* or using executeTable()
|
* the user needs to ensure that the target devices are healthy. If a device is not healthy,
|
||||||
|
* a recovery might be on-going and the device needs to be commanded to off first.
|
||||||
* @param mode
|
* @param mode
|
||||||
* @param submode
|
* @param submode
|
||||||
* @return
|
* @return
|
||||||
* - @c RETURN_OK if ok
|
* - @c RETURN_OK if OK
|
||||||
* - @c NEED_SECOND_STEP if children need to be commanded again
|
* - @c NEED_SECOND_STEP if children need to be commanded again
|
||||||
*/
|
*/
|
||||||
virtual ReturnValue_t commandChildren(Mode_t mode, Submode_t submode) = 0;
|
virtual ReturnValue_t commandChildren(Mode_t mode, Submode_t submode) = 0;
|
||||||
@ -120,8 +120,19 @@ class AssemblyBase : public SubsystemBase {
|
|||||||
|
|
||||||
virtual ReturnValue_t handleHealthReply(CommandMessage *message);
|
virtual ReturnValue_t handleHealthReply(CommandMessage *message);
|
||||||
|
|
||||||
virtual void performChildOperation();
|
/**
|
||||||
|
* @brief Default periodic handler
|
||||||
|
* @details
|
||||||
|
* This is the default periodic handler which will be called by the SubsystemBase
|
||||||
|
* performOperation. It performs the child transitions or reacts to changed health/mode states
|
||||||
|
* of children objects
|
||||||
|
*/
|
||||||
|
virtual void performChildOperation() override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function handles changed mode or health states of children
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
bool handleChildrenChanged();
|
bool handleChildrenChanged();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -134,12 +145,37 @@ class AssemblyBase : public SubsystemBase {
|
|||||||
|
|
||||||
bool handleChildrenChangedHealth();
|
bool handleChildrenChangedHealth();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Core transition handler. The default implementation will only do something if
|
||||||
|
* #commandsOutstanding is smaller or equal to zero, which means that all mode commands
|
||||||
|
* from the #doPerformTransition call were executed successfully.
|
||||||
|
*
|
||||||
|
* Unless a second step was requested, the function will then use #checkChildrenState to
|
||||||
|
* determine whether the target mode was reached.
|
||||||
|
*
|
||||||
|
* There is some special handling for certain (internal) modes:
|
||||||
|
* - A second step is necessary. #commandChildren will be performed again
|
||||||
|
* - The device health was overwritten. #commandChildren will be called
|
||||||
|
* - A recovery is ongoing. #checkAndHandleRecovery will be called.
|
||||||
|
*/
|
||||||
virtual void handleChildrenTransition();
|
virtual void handleChildrenTransition();
|
||||||
|
|
||||||
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, uint32_t *msToReachTheMode);
|
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, uint32_t *msToReachTheMode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calls #doStartTransition and triggers an informative event as well that the mode will
|
||||||
|
* change
|
||||||
|
* @param mode
|
||||||
|
* @param submode
|
||||||
|
*/
|
||||||
virtual void startTransition(Mode_t mode, Submode_t submode);
|
virtual void startTransition(Mode_t mode, Submode_t submode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function starts the transition by setting the internal #targetSubmode and #targetMode
|
||||||
|
* variables and then calling the #commandChildren function.
|
||||||
|
* @param mode
|
||||||
|
* @param submode
|
||||||
|
*/
|
||||||
virtual void doStartTransition(Mode_t mode, Submode_t submode);
|
virtual void doStartTransition(Mode_t mode, Submode_t submode);
|
||||||
|
|
||||||
virtual bool isInTransition();
|
virtual bool isInTransition();
|
||||||
@ -160,7 +196,7 @@ class AssemblyBase : public SubsystemBase {
|
|||||||
* Manages recovery of a device
|
* Manages recovery of a device
|
||||||
* @return true if recovery is still ongoing, false else.
|
* @return true if recovery is still ongoing, false else.
|
||||||
*/
|
*/
|
||||||
bool checkAndHandleRecovery();
|
virtual bool checkAndHandleRecovery();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper method to overwrite health state of one of the children.
|
* Helper method to overwrite health state of one of the children.
|
||||||
@ -168,6 +204,8 @@ class AssemblyBase : public SubsystemBase {
|
|||||||
* @param objectId Must be a registered child.
|
* @param objectId Must be a registered child.
|
||||||
*/
|
*/
|
||||||
void overwriteDeviceHealth(object_id_t objectId, HasHealthIF::HealthState oldHealth);
|
void overwriteDeviceHealth(object_id_t objectId, HasHealthIF::HealthState oldHealth);
|
||||||
|
|
||||||
|
void triggerModeHelperEvents(Mode_t mode, Submode_t submode);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* FSFW_DEVICEHANDLERS_ASSEMBLYBASE_H_ */
|
#endif /* FSFW_DEVICEHANDLERS_ASSEMBLYBASE_H_ */
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
target_sources(${LIB_FSFW_NAME}
|
target_sources(
|
||||||
PRIVATE
|
${LIB_FSFW_NAME}
|
||||||
AssemblyBase.cpp
|
PRIVATE AssemblyBase.cpp
|
||||||
ChildHandlerBase.cpp
|
ChildHandlerBase.cpp
|
||||||
ChildHandlerFDIR.cpp
|
ChildHandlerFDIR.cpp
|
||||||
DeviceHandlerBase.cpp
|
DeviceHandlerBase.cpp
|
||||||
DeviceHandlerFailureIsolation.cpp
|
DeviceHandlerFailureIsolation.cpp
|
||||||
DeviceHandlerMessage.cpp
|
DeviceHandlerMessage.cpp
|
||||||
DeviceTmReportingWrapper.cpp
|
DeviceTmReportingWrapper.cpp
|
||||||
HealthDevice.cpp
|
HealthDevice.cpp)
|
||||||
)
|
|
||||||
|
@ -39,8 +39,9 @@ DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, object_id_t device
|
|||||||
childTransitionDelay(5000),
|
childTransitionDelay(5000),
|
||||||
transitionSourceMode(_MODE_POWER_DOWN),
|
transitionSourceMode(_MODE_POWER_DOWN),
|
||||||
transitionSourceSubMode(SUBMODE_NONE) {
|
transitionSourceSubMode(SUBMODE_NONE) {
|
||||||
|
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
|
||||||
commandQueue = QueueFactory::instance()->createMessageQueue(
|
commandQueue = QueueFactory::instance()->createMessageQueue(
|
||||||
cmdQueueSize, MessageQueueMessage::MAX_MESSAGE_SIZE);
|
cmdQueueSize, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||||
insertInCommandMap(RAW_COMMAND_ID);
|
insertInCommandMap(RAW_COMMAND_ID);
|
||||||
cookieInfo.state = COOKIE_UNUSED;
|
cookieInfo.state = COOKIE_UNUSED;
|
||||||
cookieInfo.pendingCommand = deviceCommandMap.end();
|
cookieInfo.pendingCommand = deviceCommandMap.end();
|
||||||
@ -48,9 +49,6 @@ DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, object_id_t device
|
|||||||
printWarningOrError(sif::OutputTypes::OUT_ERROR, "DeviceHandlerBase",
|
printWarningOrError(sif::OutputTypes::OUT_ERROR, "DeviceHandlerBase",
|
||||||
HasReturnvaluesIF::RETURN_FAILED, "Invalid cookie");
|
HasReturnvaluesIF::RETURN_FAILED, "Invalid cookie");
|
||||||
}
|
}
|
||||||
if (this->fdirInstance == nullptr) {
|
|
||||||
this->fdirInstance = new DeviceHandlerFailureIsolation(setObjectId, defaultFdirParentId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeviceHandlerBase::setHkDestination(object_id_t hkDestination) {
|
void DeviceHandlerBase::setHkDestination(object_id_t hkDestination) {
|
||||||
@ -65,7 +63,9 @@ void DeviceHandlerBase::setThermalStateRequestPoolIds(lp_id_t thermalStatePoolId
|
|||||||
}
|
}
|
||||||
|
|
||||||
DeviceHandlerBase::~DeviceHandlerBase() {
|
DeviceHandlerBase::~DeviceHandlerBase() {
|
||||||
delete comCookie;
|
if (comCookie != nullptr) {
|
||||||
|
delete comCookie;
|
||||||
|
}
|
||||||
if (defaultFDIRUsed) {
|
if (defaultFDIRUsed) {
|
||||||
delete fdirInstance;
|
delete fdirInstance;
|
||||||
}
|
}
|
||||||
@ -126,6 +126,18 @@ ReturnValue_t DeviceHandlerBase::initialize() {
|
|||||||
if (result != RETURN_OK) {
|
if (result != RETURN_OK) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
if (this->fdirInstance == nullptr) {
|
||||||
|
this->fdirInstance =
|
||||||
|
new DeviceHandlerFailureIsolation(this->getObjectId(), defaultFdirParentId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->parent != objects::NO_OBJECT) {
|
||||||
|
HasModesIF* modeIF = ObjectManager::instance()->get<HasModesIF>(this->parent);
|
||||||
|
HasHealthIF* healthIF = ObjectManager::instance()->get<HasHealthIF>(this->parent);
|
||||||
|
if (modeIF != nullptr and healthIF != nullptr) {
|
||||||
|
setParentQueue(modeIF->getCommandQueue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
communicationInterface =
|
communicationInterface =
|
||||||
ObjectManager::instance()->get<DeviceCommunicationIF>(deviceCommunicationId);
|
ObjectManager::instance()->get<DeviceCommunicationIF>(deviceCommunicationId);
|
||||||
@ -233,17 +245,26 @@ ReturnValue_t DeviceHandlerBase::initialize() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DeviceHandlerBase::decrementDeviceReplyMap() {
|
void DeviceHandlerBase::decrementDeviceReplyMap() {
|
||||||
|
bool timedOut = false;
|
||||||
for (std::pair<const DeviceCommandId_t, DeviceReplyInfo>& replyPair : deviceReplyMap) {
|
for (std::pair<const DeviceCommandId_t, DeviceReplyInfo>& replyPair : deviceReplyMap) {
|
||||||
if (replyPair.second.delayCycles != 0) {
|
if (replyPair.second.countdown != nullptr && replyPair.second.active) {
|
||||||
|
if (replyPair.second.countdown->hasTimedOut()) {
|
||||||
|
resetTimeoutControlledReply(&replyPair.second);
|
||||||
|
timedOut = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (replyPair.second.delayCycles != 0 && replyPair.second.countdown == nullptr) {
|
||||||
replyPair.second.delayCycles--;
|
replyPair.second.delayCycles--;
|
||||||
if (replyPair.second.delayCycles == 0) {
|
if (replyPair.second.delayCycles == 0) {
|
||||||
if (replyPair.second.periodic) {
|
resetDelayCyclesControlledReply(&replyPair.second);
|
||||||
replyPair.second.delayCycles = replyPair.second.maxDelayCycles;
|
timedOut = true;
|
||||||
}
|
|
||||||
replyToReply(replyPair.first, replyPair.second, TIMEOUT);
|
|
||||||
missedReply(replyPair.first);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (timedOut) {
|
||||||
|
replyToReply(replyPair.first, replyPair.second, TIMEOUT);
|
||||||
|
missedReply(replyPair.first);
|
||||||
|
timedOut = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -352,14 +373,12 @@ void DeviceHandlerBase::doStateMachine() {
|
|||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case _MODE_WAIT_OFF: {
|
case _MODE_WAIT_OFF: {
|
||||||
uint32_t currentUptime;
|
|
||||||
Clock::getUptime(¤tUptime);
|
|
||||||
|
|
||||||
if (powerSwitcher == nullptr) {
|
if (powerSwitcher == nullptr) {
|
||||||
setMode(MODE_OFF);
|
setMode(MODE_OFF);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
uint32_t currentUptime;
|
||||||
|
Clock::getUptime(¤tUptime);
|
||||||
if (currentUptime - timeoutStart >= powerSwitcher->getSwitchDelayMs()) {
|
if (currentUptime - timeoutStart >= powerSwitcher->getSwitchDelayMs()) {
|
||||||
triggerEvent(MODE_TRANSITION_FAILED, PowerSwitchIF::SWITCH_TIMEOUT, 0);
|
triggerEvent(MODE_TRANSITION_FAILED, PowerSwitchIF::SWITCH_TIMEOUT, 0);
|
||||||
setMode(MODE_ERROR_ON);
|
setMode(MODE_ERROR_ON);
|
||||||
@ -408,20 +427,22 @@ ReturnValue_t DeviceHandlerBase::isModeCombinationValid(Mode_t mode, Submode_t s
|
|||||||
|
|
||||||
ReturnValue_t DeviceHandlerBase::insertInCommandAndReplyMap(
|
ReturnValue_t DeviceHandlerBase::insertInCommandAndReplyMap(
|
||||||
DeviceCommandId_t deviceCommand, uint16_t maxDelayCycles, LocalPoolDataSetBase* replyDataSet,
|
DeviceCommandId_t deviceCommand, uint16_t maxDelayCycles, LocalPoolDataSetBase* replyDataSet,
|
||||||
size_t replyLen, bool periodic, bool hasDifferentReplyId, DeviceCommandId_t replyId) {
|
size_t replyLen, bool periodic, bool hasDifferentReplyId, DeviceCommandId_t replyId,
|
||||||
|
Countdown* countdown) {
|
||||||
// No need to check, as we may try to insert multiple times.
|
// No need to check, as we may try to insert multiple times.
|
||||||
insertInCommandMap(deviceCommand, hasDifferentReplyId, replyId);
|
insertInCommandMap(deviceCommand, hasDifferentReplyId, replyId);
|
||||||
if (hasDifferentReplyId) {
|
if (hasDifferentReplyId) {
|
||||||
return insertInReplyMap(replyId, maxDelayCycles, replyDataSet, replyLen, periodic);
|
return insertInReplyMap(replyId, maxDelayCycles, replyDataSet, replyLen, periodic, countdown);
|
||||||
} else {
|
} else {
|
||||||
return insertInReplyMap(deviceCommand, maxDelayCycles, replyDataSet, replyLen, periodic);
|
return insertInReplyMap(deviceCommand, maxDelayCycles, replyDataSet, replyLen, periodic,
|
||||||
|
countdown);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t DeviceHandlerBase::insertInReplyMap(DeviceCommandId_t replyId,
|
ReturnValue_t DeviceHandlerBase::insertInReplyMap(DeviceCommandId_t replyId,
|
||||||
uint16_t maxDelayCycles,
|
uint16_t maxDelayCycles,
|
||||||
LocalPoolDataSetBase* dataSet, size_t replyLen,
|
LocalPoolDataSetBase* dataSet, size_t replyLen,
|
||||||
bool periodic) {
|
bool periodic, Countdown* countdown) {
|
||||||
DeviceReplyInfo info;
|
DeviceReplyInfo info;
|
||||||
info.maxDelayCycles = maxDelayCycles;
|
info.maxDelayCycles = maxDelayCycles;
|
||||||
info.periodic = periodic;
|
info.periodic = periodic;
|
||||||
@ -429,6 +450,7 @@ ReturnValue_t DeviceHandlerBase::insertInReplyMap(DeviceCommandId_t replyId,
|
|||||||
info.replyLen = replyLen;
|
info.replyLen = replyLen;
|
||||||
info.dataSet = dataSet;
|
info.dataSet = dataSet;
|
||||||
info.command = deviceCommandMap.end();
|
info.command = deviceCommandMap.end();
|
||||||
|
info.countdown = countdown;
|
||||||
auto resultPair = deviceReplyMap.emplace(replyId, info);
|
auto resultPair = deviceReplyMap.emplace(replyId, info);
|
||||||
if (resultPair.second) {
|
if (resultPair.second) {
|
||||||
return RETURN_OK;
|
return RETURN_OK;
|
||||||
@ -464,7 +486,8 @@ size_t DeviceHandlerBase::getNextReplyLength(DeviceCommandId_t commandId) {
|
|||||||
}
|
}
|
||||||
DeviceReplyIter iter = deviceReplyMap.find(replyId);
|
DeviceReplyIter iter = deviceReplyMap.find(replyId);
|
||||||
if (iter != deviceReplyMap.end()) {
|
if (iter != deviceReplyMap.end()) {
|
||||||
if (iter->second.delayCycles != 0) {
|
if ((iter->second.delayCycles != 0 && iter->second.countdown == nullptr) ||
|
||||||
|
(iter->second.active && iter->second.countdown != nullptr)) {
|
||||||
return iter->second.replyLen;
|
return iter->second.replyLen;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -500,9 +523,19 @@ ReturnValue_t DeviceHandlerBase::updatePeriodicReply(bool enable, DeviceCommandI
|
|||||||
return COMMAND_NOT_SUPPORTED;
|
return COMMAND_NOT_SUPPORTED;
|
||||||
}
|
}
|
||||||
if (enable) {
|
if (enable) {
|
||||||
info->delayCycles = info->maxDelayCycles;
|
info->active = true;
|
||||||
|
if (info->countdown != nullptr) {
|
||||||
|
info->delayCycles = info->maxDelayCycles;
|
||||||
|
} else {
|
||||||
|
info->countdown->resetTimer();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
info->delayCycles = 0;
|
info->active = false;
|
||||||
|
if (info->countdown != nullptr) {
|
||||||
|
info->delayCycles = 0;
|
||||||
|
} else {
|
||||||
|
info->countdown->timeOut();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
@ -546,6 +579,9 @@ void DeviceHandlerBase::setMode(Mode_t newMode, uint8_t newSubmode) {
|
|||||||
mode = newMode;
|
mode = newMode;
|
||||||
modeChanged();
|
modeChanged();
|
||||||
setNormalDatapoolEntriesInvalid();
|
setNormalDatapoolEntriesInvalid();
|
||||||
|
if (newMode == MODE_OFF) {
|
||||||
|
disableCommandsAndReplies();
|
||||||
|
}
|
||||||
if (!isTransitionalMode()) {
|
if (!isTransitionalMode()) {
|
||||||
modeHelper.modeChanged(newMode, newSubmode);
|
modeHelper.modeChanged(newMode, newSubmode);
|
||||||
announceMode(false);
|
announceMode(false);
|
||||||
@ -808,17 +844,18 @@ void DeviceHandlerBase::handleReply(const uint8_t* receivedData, DeviceCommandId
|
|||||||
|
|
||||||
DeviceReplyInfo* info = &(iter->second);
|
DeviceReplyInfo* info = &(iter->second);
|
||||||
|
|
||||||
if (info->delayCycles != 0) {
|
if ((info->delayCycles != 0 && info->countdown == nullptr) ||
|
||||||
|
(info->active && info->countdown != nullptr)) {
|
||||||
result = interpretDeviceReply(foundId, receivedData);
|
result = interpretDeviceReply(foundId, receivedData);
|
||||||
|
|
||||||
if (result == IGNORE_REPLY_DATA) {
|
if (result == IGNORE_REPLY_DATA) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info->periodic) {
|
if (info->active && info->countdown != nullptr) {
|
||||||
info->delayCycles = info->maxDelayCycles;
|
resetTimeoutControlledReply(info);
|
||||||
} else {
|
} else if (info->delayCycles != 0) {
|
||||||
info->delayCycles = 0;
|
resetDelayCyclesControlledReply(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result != RETURN_OK) {
|
if (result != RETURN_OK) {
|
||||||
@ -837,6 +874,24 @@ void DeviceHandlerBase::handleReply(const uint8_t* receivedData, DeviceCommandId
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DeviceHandlerBase::resetTimeoutControlledReply(DeviceReplyInfo* info) {
|
||||||
|
if (info->periodic) {
|
||||||
|
info->countdown->resetTimer();
|
||||||
|
} else {
|
||||||
|
info->active = false;
|
||||||
|
info->countdown->timeOut();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceHandlerBase::resetDelayCyclesControlledReply(DeviceReplyInfo* info) {
|
||||||
|
if (info->periodic) {
|
||||||
|
info->delayCycles = info->maxDelayCycles;
|
||||||
|
} else {
|
||||||
|
info->delayCycles = 0;
|
||||||
|
info->active = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ReturnValue_t DeviceHandlerBase::getStorageData(store_address_t storageAddress, uint8_t** data,
|
ReturnValue_t DeviceHandlerBase::getStorageData(store_address_t storageAddress, uint8_t** data,
|
||||||
size_t* len) {
|
size_t* len) {
|
||||||
size_t lenTmp;
|
size_t lenTmp;
|
||||||
@ -959,9 +1014,15 @@ ReturnValue_t DeviceHandlerBase::enableReplyInReplyMap(DeviceCommandMap::iterato
|
|||||||
}
|
}
|
||||||
if (iter != deviceReplyMap.end()) {
|
if (iter != deviceReplyMap.end()) {
|
||||||
DeviceReplyInfo* info = &(iter->second);
|
DeviceReplyInfo* info = &(iter->second);
|
||||||
|
// If a countdown has been set, the delay cycles will be ignored and the reply times out
|
||||||
|
// as soon as the countdown has expired
|
||||||
info->delayCycles = info->maxDelayCycles;
|
info->delayCycles = info->maxDelayCycles;
|
||||||
info->command = command;
|
info->command = command;
|
||||||
command->second.expectedReplies = expectedReplies;
|
command->second.expectedReplies = expectedReplies;
|
||||||
|
if (info->countdown != nullptr) {
|
||||||
|
info->countdown->resetTimer();
|
||||||
|
}
|
||||||
|
info->active = true;
|
||||||
return RETURN_OK;
|
return RETURN_OK;
|
||||||
} else {
|
} else {
|
||||||
return NO_REPLY_EXPECTED;
|
return NO_REPLY_EXPECTED;
|
||||||
@ -1196,7 +1257,8 @@ void DeviceHandlerBase::setParentQueue(MessageQueueId_t parentQueueId) {
|
|||||||
bool DeviceHandlerBase::isAwaitingReply() {
|
bool DeviceHandlerBase::isAwaitingReply() {
|
||||||
std::map<DeviceCommandId_t, DeviceReplyInfo>::iterator iter;
|
std::map<DeviceCommandId_t, DeviceReplyInfo>::iterator iter;
|
||||||
for (iter = deviceReplyMap.begin(); iter != deviceReplyMap.end(); ++iter) {
|
for (iter = deviceReplyMap.begin(); iter != deviceReplyMap.end(); ++iter) {
|
||||||
if (iter->second.delayCycles != 0) {
|
if ((iter->second.delayCycles != 0 && iter->second.countdown == nullptr) ||
|
||||||
|
(iter->second.active && iter->second.countdown != nullptr)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1351,6 +1413,13 @@ uint8_t DeviceHandlerBase::getReplyDelayCycles(DeviceCommandId_t deviceCommand)
|
|||||||
DeviceReplyMap::iterator iter = deviceReplyMap.find(deviceCommand);
|
DeviceReplyMap::iterator iter = deviceReplyMap.find(deviceCommand);
|
||||||
if (iter == deviceReplyMap.end()) {
|
if (iter == deviceReplyMap.end()) {
|
||||||
return 0;
|
return 0;
|
||||||
|
} else if (iter->second.countdown != nullptr) {
|
||||||
|
// fake a useful return value for legacy code
|
||||||
|
if (iter->second.active) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return iter->second.delayCycles;
|
return iter->second.delayCycles;
|
||||||
}
|
}
|
||||||
@ -1399,6 +1468,8 @@ void DeviceHandlerBase::setTaskIF(PeriodicTaskIF* task) { executingTask = task;
|
|||||||
void DeviceHandlerBase::debugInterface(uint8_t positionTracker, object_id_t objectId,
|
void DeviceHandlerBase::debugInterface(uint8_t positionTracker, object_id_t objectId,
|
||||||
uint32_t parameter) {}
|
uint32_t parameter) {}
|
||||||
|
|
||||||
|
Submode_t DeviceHandlerBase::getInitialSubmode() { return SUBMODE_NONE; }
|
||||||
|
|
||||||
void DeviceHandlerBase::performOperationHook() {}
|
void DeviceHandlerBase::performOperationHook() {}
|
||||||
|
|
||||||
ReturnValue_t DeviceHandlerBase::initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
|
ReturnValue_t DeviceHandlerBase::initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
|
||||||
@ -1421,7 +1492,7 @@ ReturnValue_t DeviceHandlerBase::initializeAfterTaskCreation() {
|
|||||||
this->poolManager.initializeAfterTaskCreation();
|
this->poolManager.initializeAfterTaskCreation();
|
||||||
|
|
||||||
if (setStartupImmediately) {
|
if (setStartupImmediately) {
|
||||||
startTransition(MODE_ON, SUBMODE_NONE);
|
startTransition(MODE_ON, getInitialSubmode());
|
||||||
}
|
}
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
@ -1505,3 +1576,29 @@ MessageQueueId_t DeviceHandlerBase::getCommanderQueueId(DeviceCommandId_t replyI
|
|||||||
}
|
}
|
||||||
return commandIter->second.sendReplyTo;
|
return commandIter->second.sendReplyTo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DeviceHandlerBase::setCustomFdir(FailureIsolationBase* fdir) { this->fdirInstance = fdir; }
|
||||||
|
|
||||||
|
void DeviceHandlerBase::setParent(object_id_t parent) { this->parent = parent; }
|
||||||
|
|
||||||
|
void DeviceHandlerBase::setPowerSwitcher(PowerSwitchIF* switcher) {
|
||||||
|
this->powerSwitcher = switcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceHandlerBase::disableCommandsAndReplies() {
|
||||||
|
for (auto& command : deviceCommandMap) {
|
||||||
|
if (command.second.isExecuting) {
|
||||||
|
command.second.isExecuting = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto& reply : deviceReplyMap) {
|
||||||
|
if (!reply.second.periodic) {
|
||||||
|
if (reply.second.countdown != nullptr) {
|
||||||
|
reply.second.countdown->timeOut();
|
||||||
|
} else {
|
||||||
|
reply.second.delayCycles = 0;
|
||||||
|
}
|
||||||
|
reply.second.active = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -103,6 +103,9 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||||||
DeviceHandlerBase(object_id_t setObjectId, object_id_t deviceCommunication, CookieIF *comCookie,
|
DeviceHandlerBase(object_id_t setObjectId, object_id_t deviceCommunication, CookieIF *comCookie,
|
||||||
FailureIsolationBase *fdirInstance = nullptr, size_t cmdQueueSize = 20);
|
FailureIsolationBase *fdirInstance = nullptr, size_t cmdQueueSize = 20);
|
||||||
|
|
||||||
|
void setCustomFdir(FailureIsolationBase *fdir);
|
||||||
|
void setParent(object_id_t parent);
|
||||||
|
void setPowerSwitcher(PowerSwitchIF *switcher);
|
||||||
void setHkDestination(object_id_t hkDestination);
|
void setHkDestination(object_id_t hkDestination);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -448,6 +451,9 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||||||
* by the device repeatedly without request) or not. Default is aperiodic (0).
|
* by the device repeatedly without request) or not. Default is aperiodic (0).
|
||||||
* Please note that periodic replies are disabled by default. You can enable them with
|
* Please note that periodic replies are disabled by default. You can enable them with
|
||||||
* #updatePeriodicReply
|
* #updatePeriodicReply
|
||||||
|
* @param countdown Instead of using maxDelayCycles to timeout a device reply it is also possible
|
||||||
|
* to provide a pointer to a Countdown object which will signal the timeout
|
||||||
|
* when expired
|
||||||
* @return - @c RETURN_OK when the command was successfully inserted,
|
* @return - @c RETURN_OK when the command was successfully inserted,
|
||||||
* - @c RETURN_FAILED else.
|
* - @c RETURN_FAILED else.
|
||||||
*/
|
*/
|
||||||
@ -455,22 +461,35 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||||||
LocalPoolDataSetBase *replyDataSet = nullptr,
|
LocalPoolDataSetBase *replyDataSet = nullptr,
|
||||||
size_t replyLen = 0, bool periodic = false,
|
size_t replyLen = 0, bool periodic = false,
|
||||||
bool hasDifferentReplyId = false,
|
bool hasDifferentReplyId = false,
|
||||||
DeviceCommandId_t replyId = 0);
|
DeviceCommandId_t replyId = 0,
|
||||||
|
Countdown *countdown = nullptr);
|
||||||
/**
|
/**
|
||||||
* @brief This is a helper method to insert replies in the reply map.
|
* @brief This is a helper method to insert replies in the reply map.
|
||||||
* @param deviceCommand Identifier of the reply to add.
|
* @param deviceCommand Identifier of the reply to add.
|
||||||
* @param maxDelayCycles The maximum number of delay cycles the reply waits
|
* @param maxDelayCycles The maximum number of delay cycles the reply waits
|
||||||
* until it times out.
|
* until it times out.
|
||||||
* @param periodic Indicates if the command is periodic (i.e. it is sent
|
* @param periodic Indicates if the command is periodic (i.e. it is sent
|
||||||
|
<<<<<<< HEAD
|
||||||
|
* by the device repeatedly without request) or not. Default is aperiodic (0).
|
||||||
|
* Please note that periodic replies are disabled by default. You can enable them with
|
||||||
|
* #updatePeriodicReply
|
||||||
|
* @param countdown Instead of using maxDelayCycles to timeout a device reply it is also possible
|
||||||
|
* to provide a pointer to a Countdown object which will signal the timeout
|
||||||
|
* when expired
|
||||||
|
=======
|
||||||
* by the device repeatedly without request) or not. Default is aperiodic (0).
|
* by the device repeatedly without request) or not. Default is aperiodic (0).
|
||||||
* Please note that periodic replies are disabled by default. You can enable them with
|
* Please note that periodic replies are disabled by default. You can enable them with
|
||||||
* #updatePeriodicReply
|
* #updatePeriodicReply
|
||||||
|
* @param countdown Instead of using maxDelayCycles to timeout a device reply it is also possible
|
||||||
|
* to provide a pointer to a Countdown object which will signal the timeout
|
||||||
|
* when expired
|
||||||
|
>>>>>>> upstream/development
|
||||||
* @return - @c RETURN_OK when the command was successfully inserted,
|
* @return - @c RETURN_OK when the command was successfully inserted,
|
||||||
* - @c RETURN_FAILED else.
|
* - @c RETURN_FAILED else.
|
||||||
*/
|
*/
|
||||||
ReturnValue_t insertInReplyMap(DeviceCommandId_t deviceCommand, uint16_t maxDelayCycles,
|
ReturnValue_t insertInReplyMap(DeviceCommandId_t deviceCommand, uint16_t maxDelayCycles,
|
||||||
LocalPoolDataSetBase *dataSet = nullptr, size_t replyLen = 0,
|
LocalPoolDataSetBase *dataSet = nullptr, size_t replyLen = 0,
|
||||||
bool periodic = false);
|
bool periodic = false, Countdown *countdown = nullptr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A simple command to add a command to the commandList.
|
* @brief A simple command to add a command to the commandList.
|
||||||
@ -649,6 +668,12 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||||||
virtual void debugInterface(uint8_t positionTracker = 0, object_id_t objectId = 0,
|
virtual void debugInterface(uint8_t positionTracker = 0, object_id_t objectId = 0,
|
||||||
uint32_t parameter = 0);
|
uint32_t parameter = 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Can be overwritten by a child to specify the initial submode when device has been set
|
||||||
|
* to startup immediately.
|
||||||
|
*/
|
||||||
|
virtual Submode_t getInitialSubmode();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_BASE;
|
static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_BASE;
|
||||||
|
|
||||||
@ -767,11 +792,18 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||||||
* This is used to keep track of pending replies.
|
* This is used to keep track of pending replies.
|
||||||
*/
|
*/
|
||||||
struct DeviceReplyInfo {
|
struct DeviceReplyInfo {
|
||||||
|
//! For Command-Reply combinations:
|
||||||
//! The maximum number of cycles the handler should wait for a reply
|
//! The maximum number of cycles the handler should wait for a reply
|
||||||
//! to this command.
|
//! to this command.
|
||||||
|
//!
|
||||||
|
//! Reply Only:
|
||||||
|
//! For periodic replies, this variable will be the number of delay cycles between the replies.
|
||||||
|
//! For the non-periodic variant, this variable is not used as there is no meaningful
|
||||||
|
//! definition for delay
|
||||||
uint16_t maxDelayCycles;
|
uint16_t maxDelayCycles;
|
||||||
//! The currently remaining cycles the handler should wait for a reply,
|
//! This variable will be set to #maxDelayCycles if a reply is expected.
|
||||||
//! 0 means there is no reply expected
|
//! For non-periodic replies without a command, this variable is unused.
|
||||||
|
//! A runtime value of 0 means there is no reply is currently expected.
|
||||||
uint16_t delayCycles;
|
uint16_t delayCycles;
|
||||||
size_t replyLen = 0; //!< Expected size of the reply.
|
size_t replyLen = 0; //!< Expected size of the reply.
|
||||||
//! if this is !=0, the delayCycles will not be reset to 0 but to
|
//! if this is !=0, the delayCycles will not be reset to 0 but to
|
||||||
@ -783,6 +815,11 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||||||
LocalPoolDataSetBase *dataSet = nullptr;
|
LocalPoolDataSetBase *dataSet = nullptr;
|
||||||
//! The command that expects this reply.
|
//! The command that expects this reply.
|
||||||
DeviceCommandMap::iterator command;
|
DeviceCommandMap::iterator command;
|
||||||
|
//! Instead of using delayCycles to specify the maximum time to wait for the device reply, it
|
||||||
|
//! is also possible specify a countdown
|
||||||
|
Countdown *countdown = nullptr;
|
||||||
|
//! will be set to true when reply is enabled
|
||||||
|
bool active = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
using DeviceReplyMap = std::map<DeviceCommandId_t, DeviceReplyInfo>;
|
using DeviceReplyMap = std::map<DeviceCommandId_t, DeviceReplyInfo>;
|
||||||
@ -822,6 +859,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||||||
/** Pointer to the used FDIR instance. If not provided by child,
|
/** Pointer to the used FDIR instance. If not provided by child,
|
||||||
* default class is instantiated. */
|
* default class is instantiated. */
|
||||||
FailureIsolationBase *fdirInstance;
|
FailureIsolationBase *fdirInstance;
|
||||||
|
object_id_t parent = objects::NO_OBJECT;
|
||||||
|
|
||||||
//! To correctly delete the default instance.
|
//! To correctly delete the default instance.
|
||||||
bool defaultFDIRUsed;
|
bool defaultFDIRUsed;
|
||||||
@ -1244,6 +1282,17 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||||||
*/
|
*/
|
||||||
void doGetRead(void);
|
void doGetRead(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Resets replies which use a timeout to detect missed replies.
|
||||||
|
*/
|
||||||
|
void resetTimeoutControlledReply(DeviceReplyInfo *info);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Resets replies which use a number of maximum delay cycles to detect
|
||||||
|
* missed replies.
|
||||||
|
*/
|
||||||
|
void resetDelayCyclesControlledReply(DeviceReplyInfo *info);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrive data from the #IPCStore.
|
* Retrive data from the #IPCStore.
|
||||||
*
|
*
|
||||||
@ -1285,6 +1334,11 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||||||
void printWarningOrError(sif::OutputTypes errorType, const char *functionName,
|
void printWarningOrError(sif::OutputTypes errorType, const char *functionName,
|
||||||
ReturnValue_t errorCode = HasReturnvaluesIF::RETURN_FAILED,
|
ReturnValue_t errorCode = HasReturnvaluesIF::RETURN_FAILED,
|
||||||
const char *errorPrint = nullptr);
|
const char *errorPrint = nullptr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Disables all commands and replies when device is set to MODE_OFF
|
||||||
|
*/
|
||||||
|
void disableCommandsAndReplies();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* FSFW_DEVICEHANDLERS_DEVICEHANDLERBASE_H_ */
|
#endif /* FSFW_DEVICEHANDLERS_DEVICEHANDLERBASE_H_ */
|
||||||
|
@ -29,6 +29,7 @@ ReturnValue_t DeviceHandlerFailureIsolation::eventReceived(EventMessage* event)
|
|||||||
switch (event->getEvent()) {
|
switch (event->getEvent()) {
|
||||||
case HasModesIF::MODE_TRANSITION_FAILED:
|
case HasModesIF::MODE_TRANSITION_FAILED:
|
||||||
case HasModesIF::OBJECT_IN_INVALID_MODE:
|
case HasModesIF::OBJECT_IN_INVALID_MODE:
|
||||||
|
case DeviceHandlerIF::DEVICE_WANTS_HARD_REBOOT:
|
||||||
// We'll try a recovery as long as defined in MAX_REBOOT.
|
// We'll try a recovery as long as defined in MAX_REBOOT.
|
||||||
// Might cause some AssemblyBase cycles, so keep number low.
|
// Might cause some AssemblyBase cycles, so keep number low.
|
||||||
handleRecovery(event->getEvent());
|
handleRecovery(event->getEvent());
|
||||||
|
@ -109,6 +109,7 @@ class DeviceHandlerIF {
|
|||||||
static const Event INVALID_DEVICE_COMMAND = MAKE_EVENT(8, severity::LOW);
|
static const Event INVALID_DEVICE_COMMAND = MAKE_EVENT(8, severity::LOW);
|
||||||
static const Event MONITORING_LIMIT_EXCEEDED = MAKE_EVENT(9, severity::LOW);
|
static const Event MONITORING_LIMIT_EXCEEDED = MAKE_EVENT(9, severity::LOW);
|
||||||
static const Event MONITORING_AMBIGUOUS = MAKE_EVENT(10, severity::HIGH);
|
static const Event MONITORING_AMBIGUOUS = MAKE_EVENT(10, severity::HIGH);
|
||||||
|
static const Event DEVICE_WANTS_HARD_REBOOT = MAKE_EVENT(11, severity::HIGH);
|
||||||
|
|
||||||
static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_IF;
|
static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_IF;
|
||||||
|
|
||||||
|
@ -8,7 +8,9 @@ HealthDevice::HealthDevice(object_id_t setObjectId, MessageQueueId_t parentQueue
|
|||||||
parentQueue(parentQueue),
|
parentQueue(parentQueue),
|
||||||
commandQueue(),
|
commandQueue(),
|
||||||
healthHelper(this, setObjectId) {
|
healthHelper(this, setObjectId) {
|
||||||
commandQueue = QueueFactory::instance()->createMessageQueue(3);
|
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
|
||||||
|
commandQueue = QueueFactory::instance()->createMessageQueue(
|
||||||
|
3, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
HealthDevice::~HealthDevice() { QueueFactory::instance()->deleteMessageQueue(commandQueue); }
|
HealthDevice::~HealthDevice() { QueueFactory::instance()->deleteMessageQueue(commandQueue); }
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
target_sources(${LIB_FSFW_NAME} PRIVATE EventManager.cpp EventMessage.cpp)
|
||||||
EventManager.cpp
|
|
||||||
EventMessage.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
add_subdirectory(eventmatching)
|
add_subdirectory(eventmatching)
|
||||||
|
@ -18,8 +18,9 @@ const LocalPool::LocalPoolConfig EventManager::poolConfig = {
|
|||||||
EventManager::EventManager(object_id_t setObjectId)
|
EventManager::EventManager(object_id_t setObjectId)
|
||||||
: SystemObject(setObjectId), factoryBackend(0, poolConfig, false, true) {
|
: SystemObject(setObjectId), factoryBackend(0, poolConfig, false, true) {
|
||||||
mutex = MutexFactory::instance()->createMutex();
|
mutex = MutexFactory::instance()->createMutex();
|
||||||
eventReportQueue = QueueFactory::instance()->createMessageQueue(MAX_EVENTS_PER_CYCLE,
|
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
|
||||||
EventMessage::EVENT_MESSAGE_SIZE);
|
eventReportQueue = QueueFactory::instance()->createMessageQueue(
|
||||||
|
MAX_EVENTS_PER_CYCLE, EventMessage::EVENT_MESSAGE_SIZE, &mqArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
EventManager::~EventManager() {
|
EventManager::~EventManager() {
|
||||||
@ -46,9 +47,20 @@ ReturnValue_t EventManager::performOperation(uint8_t opCode) {
|
|||||||
|
|
||||||
void EventManager::notifyListeners(EventMessage* message) {
|
void EventManager::notifyListeners(EventMessage* message) {
|
||||||
lockMutex();
|
lockMutex();
|
||||||
for (auto iter = listenerList.begin(); iter != listenerList.end(); ++iter) {
|
for (auto& listener : listenerList) {
|
||||||
if (iter->second.match(message)) {
|
if (listener.second.match(message)) {
|
||||||
MessageQueueSenderIF::sendMessage(iter->first, message, message->getSender());
|
ReturnValue_t result =
|
||||||
|
MessageQueueSenderIF::sendMessage(listener.first, message, message->getSender());
|
||||||
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::error << std::hex << "EventManager::notifyListeners: MSG to 0x" << std::setfill('0')
|
||||||
|
<< std::setw(8) << listener.first << " failed with result 0x" << std::setw(4)
|
||||||
|
<< result << std::setfill(' ') << std::endl;
|
||||||
|
#else
|
||||||
|
sif::printError("Sending message to listener 0x%08x failed with result %04x\n",
|
||||||
|
listener.first, result);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unlockMutex();
|
unlockMutex();
|
||||||
@ -88,6 +100,11 @@ ReturnValue_t EventManager::subscribeToEventRange(MessageQueueId_t listener, Eve
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ReturnValue_t EventManager::unsubscribeFromAllEvents(MessageQueueId_t listener,
|
||||||
|
object_id_t object) {
|
||||||
|
return unsubscribeFromEventRange(listener, 0, 0, true, object);
|
||||||
|
}
|
||||||
|
|
||||||
ReturnValue_t EventManager::unsubscribeFromEventRange(MessageQueueId_t listener, EventId_t idFrom,
|
ReturnValue_t EventManager::unsubscribeFromEventRange(MessageQueueId_t listener, EventId_t idFrom,
|
||||||
EventId_t idTo, bool idInverted,
|
EventId_t idTo, bool idInverted,
|
||||||
object_id_t reporterFrom,
|
object_id_t reporterFrom,
|
||||||
@ -189,4 +206,19 @@ void EventManager::printUtility(sif::OutputTypes printType, EventMessage* messag
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EventManager::printListeners() {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::info << "Event manager listener MQ IDs:" << std::setfill('0') << std::hex << std::endl;
|
||||||
|
for (auto& listener : listenerList) {
|
||||||
|
sif::info << "0x" << std::setw(8) << listener.first << std::endl;
|
||||||
|
}
|
||||||
|
sif::info << std::dec << std::setfill(' ');
|
||||||
|
#else
|
||||||
|
sif::printInfo("Event manager listener MQ IDs:\n");
|
||||||
|
for (auto& listener : listenerList) {
|
||||||
|
sif::printInfo("0x%08x\n", listener.first);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* FSFW_OBJ_EVENT_TRANSLATION == 1 */
|
#endif /* FSFW_OBJ_EVENT_TRANSLATION == 1 */
|
||||||
|
@ -37,11 +37,13 @@ class EventManager : public EventManagerIF, public ExecutableObjectIF, public Sy
|
|||||||
EventId_t idTo = 0, bool idInverted = false,
|
EventId_t idTo = 0, bool idInverted = false,
|
||||||
object_id_t reporterFrom = 0, object_id_t reporterTo = 0,
|
object_id_t reporterFrom = 0, object_id_t reporterTo = 0,
|
||||||
bool reporterInverted = false);
|
bool reporterInverted = false);
|
||||||
|
ReturnValue_t unsubscribeFromAllEvents(MessageQueueId_t listener, object_id_t object);
|
||||||
ReturnValue_t unsubscribeFromEventRange(MessageQueueId_t listener, EventId_t idFrom = 0,
|
ReturnValue_t unsubscribeFromEventRange(MessageQueueId_t listener, EventId_t idFrom = 0,
|
||||||
EventId_t idTo = 0, bool idInverted = false,
|
EventId_t idTo = 0, bool idInverted = false,
|
||||||
object_id_t reporterFrom = 0, object_id_t reporterTo = 0,
|
object_id_t reporterFrom = 0, object_id_t reporterTo = 0,
|
||||||
bool reporterInverted = false);
|
bool reporterInverted = false);
|
||||||
ReturnValue_t performOperation(uint8_t opCode);
|
ReturnValue_t performOperation(uint8_t opCode);
|
||||||
|
void printListeners();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
MessageQueueIF* eventReportQueue = nullptr;
|
MessageQueueIF* eventReportQueue = nullptr;
|
||||||
|
@ -20,6 +20,7 @@ class EventManagerIF {
|
|||||||
bool forwardAllButSelected = false) = 0;
|
bool forwardAllButSelected = false) = 0;
|
||||||
virtual ReturnValue_t subscribeToEvent(MessageQueueId_t listener, EventId_t event) = 0;
|
virtual ReturnValue_t subscribeToEvent(MessageQueueId_t listener, EventId_t event) = 0;
|
||||||
virtual ReturnValue_t subscribeToAllEventsFrom(MessageQueueId_t listener, object_id_t object) = 0;
|
virtual ReturnValue_t subscribeToAllEventsFrom(MessageQueueId_t listener, object_id_t object) = 0;
|
||||||
|
virtual ReturnValue_t unsubscribeFromAllEvents(MessageQueueId_t listener, object_id_t object) = 0;
|
||||||
virtual ReturnValue_t subscribeToEventRange(MessageQueueId_t listener, EventId_t idFrom = 0,
|
virtual ReturnValue_t subscribeToEventRange(MessageQueueId_t listener, EventId_t idFrom = 0,
|
||||||
EventId_t idTo = 0, bool idInverted = false,
|
EventId_t idTo = 0, bool idInverted = false,
|
||||||
object_id_t reporterFrom = 0,
|
object_id_t reporterFrom = 0,
|
||||||
|
@ -1,7 +1,3 @@
|
|||||||
target_sources(${LIB_FSFW_NAME}
|
target_sources(
|
||||||
PRIVATE
|
${LIB_FSFW_NAME} PRIVATE EventIdRangeMatcher.cpp EventMatchTree.cpp
|
||||||
EventIdRangeMatcher.cpp
|
ReporterRangeMatcher.cpp SeverityRangeMatcher.cpp)
|
||||||
EventMatchTree.cpp
|
|
||||||
ReporterRangeMatcher.cpp
|
|
||||||
SeverityRangeMatcher.cpp
|
|
||||||
)
|
|
||||||
|
@ -27,6 +27,7 @@ enum : uint8_t {
|
|||||||
PUS_SERVICE_6 = 86,
|
PUS_SERVICE_6 = 86,
|
||||||
PUS_SERVICE_8 = 88,
|
PUS_SERVICE_8 = 88,
|
||||||
PUS_SERVICE_9 = 89,
|
PUS_SERVICE_9 = 89,
|
||||||
|
PUS_SERVICE_11 = 91,
|
||||||
PUS_SERVICE_17 = 97,
|
PUS_SERVICE_17 = 97,
|
||||||
PUS_SERVICE_23 = 103,
|
PUS_SERVICE_23 = 103,
|
||||||
MGM_LIS3MDL = 106,
|
MGM_LIS3MDL = 106,
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
target_sources(${LIB_FSFW_NAME}
|
target_sources(
|
||||||
PRIVATE
|
${LIB_FSFW_NAME} PRIVATE EventCorrelation.cpp FailureIsolationBase.cpp
|
||||||
EventCorrelation.cpp
|
FaultCounter.cpp)
|
||||||
FailureIsolationBase.cpp
|
|
||||||
FaultCounter.cpp
|
|
||||||
)
|
|
||||||
|
@ -9,11 +9,22 @@
|
|||||||
FailureIsolationBase::FailureIsolationBase(object_id_t owner, object_id_t parent,
|
FailureIsolationBase::FailureIsolationBase(object_id_t owner, object_id_t parent,
|
||||||
uint8_t messageDepth, uint8_t parameterDomainBase)
|
uint8_t messageDepth, uint8_t parameterDomainBase)
|
||||||
: ownerId(owner), faultTreeParent(parent), parameterDomainBase(parameterDomainBase) {
|
: ownerId(owner), faultTreeParent(parent), parameterDomainBase(parameterDomainBase) {
|
||||||
eventQueue =
|
auto mqArgs = MqArgs(owner, static_cast<void*>(this));
|
||||||
QueueFactory::instance()->createMessageQueue(messageDepth, EventMessage::EVENT_MESSAGE_SIZE);
|
eventQueue = QueueFactory::instance()->createMessageQueue(
|
||||||
|
messageDepth, EventMessage::EVENT_MESSAGE_SIZE, &mqArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
FailureIsolationBase::~FailureIsolationBase() {
|
FailureIsolationBase::~FailureIsolationBase() {
|
||||||
|
EventManagerIF* manager = ObjectManager::instance()->get<EventManagerIF>(objects::EVENT_MANAGER);
|
||||||
|
if (manager == nullptr) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::error << "FailureIsolationBase::~FailureIsolationBase: Event Manager has not"
|
||||||
|
" been initialized!"
|
||||||
|
<< std::endl;
|
||||||
|
#endif
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
manager->unsubscribeFromAllEvents(eventQueue->getId(), ownerId);
|
||||||
QueueFactory::instance()->deleteMessageQueue(eventQueue);
|
QueueFactory::instance()->deleteMessageQueue(eventQueue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,11 +62,12 @@ ReturnValue_t FailureIsolationBase::initialize() {
|
|||||||
ObjectManager::instance()->get<ConfirmsFailuresIF>(faultTreeParent);
|
ObjectManager::instance()->get<ConfirmsFailuresIF>(faultTreeParent);
|
||||||
if (parentIF == nullptr) {
|
if (parentIF == nullptr) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::error << "FailureIsolationBase::intialize: Parent object"
|
sif::error << "FailureIsolationBase::intialize: Parent object "
|
||||||
<< "invalid." << std::endl;
|
<< "invalid" << std::endl;
|
||||||
#endif
|
sif::error << "Make sure it implements ConfirmsFailuresIF" << std::endl;
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#else
|
||||||
sif::error << "Make sure it implements ConfirmsFailuresIF." << std::endl;
|
sif::printError("FailureIsolationBase::intialize: Parent object invalid\n");
|
||||||
|
sif::printError("Make sure it implements ConfirmsFailuresIF\n");
|
||||||
#endif
|
#endif
|
||||||
return ObjectManagerIF::CHILD_INIT_FAILED;
|
return ObjectManagerIF::CHILD_INIT_FAILED;
|
||||||
return RETURN_FAILED;
|
return RETURN_FAILED;
|
||||||
|
@ -14,13 +14,12 @@ class FailureIsolationBase : public HasReturnvaluesIF,
|
|||||||
public HasParametersIF {
|
public HasParametersIF {
|
||||||
public:
|
public:
|
||||||
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::FDIR_1;
|
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::FDIR_1;
|
||||||
static const Event FDIR_CHANGED_STATE =
|
//! FDIR has an internal state, which changed from par2 (oldState) to par1 (newState).
|
||||||
MAKE_EVENT(1, severity::INFO); //!< FDIR has an internal state, which changed from par2
|
static const Event FDIR_CHANGED_STATE = MAKE_EVENT(1, severity::INFO);
|
||||||
//!< (oldState) to par1 (newState).
|
//! FDIR tries to restart device. Par1: event that caused recovery.
|
||||||
static const Event FDIR_STARTS_RECOVERY = MAKE_EVENT(
|
static const Event FDIR_STARTS_RECOVERY = MAKE_EVENT(2, severity::MEDIUM);
|
||||||
2, severity::MEDIUM); //!< FDIR tries to restart device. Par1: event that caused recovery.
|
//! FDIR turns off device. Par1: event that caused recovery.
|
||||||
static const Event FDIR_TURNS_OFF_DEVICE = MAKE_EVENT(
|
static const Event FDIR_TURNS_OFF_DEVICE = MAKE_EVENT(3, severity::MEDIUM);
|
||||||
3, severity::MEDIUM); //!< FDIR turns off device. Par1: event that caused recovery.
|
|
||||||
|
|
||||||
FailureIsolationBase(object_id_t owner, object_id_t parent = objects::NO_OBJECT,
|
FailureIsolationBase(object_id_t owner, object_id_t parent = objects::NO_OBJECT,
|
||||||
uint8_t messageDepth = 10, uint8_t parameterDomainBase = 0xF0);
|
uint8_t messageDepth = 10, uint8_t parameterDomainBase = 0xF0);
|
||||||
|
@ -60,14 +60,14 @@ ReturnValue_t FaultCounter::getParameter(uint8_t domainId, uint8_t uniqueId,
|
|||||||
return INVALID_DOMAIN_ID;
|
return INVALID_DOMAIN_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (uniqueId) {
|
switch (static_cast<ParameterIds>(uniqueId)) {
|
||||||
case 0:
|
case ParameterIds::FAILURE_THRESHOLD:
|
||||||
parameterWrapper->set(failureThreshold);
|
parameterWrapper->set(failureThreshold);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case ParameterIds::FAULT_COUNT:
|
||||||
parameterWrapper->set(faultCount);
|
parameterWrapper->set(faultCount);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case ParameterIds::TIMEOUT:
|
||||||
parameterWrapper->set(timer.timeout);
|
parameterWrapper->set(timer.timeout);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
class FaultCounter : public HasParametersIF {
|
class FaultCounter : public HasParametersIF {
|
||||||
public:
|
public:
|
||||||
|
enum class ParameterIds { FAILURE_THRESHOLD, FAULT_COUNT, TIMEOUT };
|
||||||
|
|
||||||
FaultCounter();
|
FaultCounter();
|
||||||
FaultCounter(uint32_t failureThreshold, uint32_t decrementAfterMs,
|
FaultCounter(uint32_t failureThreshold, uint32_t decrementAfterMs,
|
||||||
uint8_t setParameterDomain = 0);
|
uint8_t setParameterDomain = 0);
|
||||||
@ -25,7 +27,8 @@ class FaultCounter : public HasParametersIF {
|
|||||||
|
|
||||||
virtual ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueId,
|
virtual ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueId,
|
||||||
ParameterWrapper *parameterWrapper,
|
ParameterWrapper *parameterWrapper,
|
||||||
const ParameterWrapper *newValues, uint16_t startAtIndex);
|
const ParameterWrapper *newValues = nullptr,
|
||||||
|
uint16_t startAtIndex = 0);
|
||||||
|
|
||||||
void setParameterDomain(uint8_t domain);
|
void setParameterDomain(uint8_t domain);
|
||||||
|
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
target_sources(${LIB_FSFW_NAME}
|
target_sources(
|
||||||
PRIVATE
|
${LIB_FSFW_NAME}
|
||||||
arrayprinter.cpp
|
PRIVATE arrayprinter.cpp
|
||||||
AsciiConverter.cpp
|
AsciiConverter.cpp
|
||||||
CRC.cpp
|
CRC.cpp
|
||||||
DleEncoder.cpp
|
DleEncoder.cpp
|
||||||
PeriodicOperationDivider.cpp
|
DleParser.cpp
|
||||||
timevalOperations.cpp
|
PeriodicOperationDivider.cpp
|
||||||
Type.cpp
|
timevalOperations.cpp
|
||||||
bitutility.cpp
|
Type.cpp
|
||||||
)
|
bitutility.cpp)
|
||||||
|
|
||||||
add_subdirectory(math)
|
add_subdirectory(math)
|
||||||
|
230
src/fsfw/globalfunctions/DleParser.cpp
Normal file
230
src/fsfw/globalfunctions/DleParser.cpp
Normal file
@ -0,0 +1,230 @@
|
|||||||
|
#include "DleParser.h"
|
||||||
|
|
||||||
|
#include <fsfw/serviceinterface/ServiceInterface.h>
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
DleParser::DleParser(SimpleRingBuffer& decodeRingBuf, DleEncoder& decoder, BufPair encodedBuf,
|
||||||
|
BufPair decodedBuf, UserHandler handler, void* args)
|
||||||
|
: decodeRingBuf(decodeRingBuf),
|
||||||
|
decoder(decoder),
|
||||||
|
encodedBuf(encodedBuf),
|
||||||
|
decodedBuf(decodedBuf),
|
||||||
|
handler(handler),
|
||||||
|
ctx(args) {
|
||||||
|
if (handler == nullptr) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::error << "DleParser::DleParser: Invalid user handler" << std::endl;
|
||||||
|
#else
|
||||||
|
sif::printError("DleParser::DleParser: Invalid user handler\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t DleParser::passData(uint8_t* data, size_t len) {
|
||||||
|
if (data == nullptr or len == 0 or handler == nullptr) {
|
||||||
|
return RETURN_FAILED;
|
||||||
|
}
|
||||||
|
size_t copyIntoRingBufFromHere = 0;
|
||||||
|
size_t copyAmount = len;
|
||||||
|
size_t startIdx = 0;
|
||||||
|
ReturnValue_t result = RETURN_OK;
|
||||||
|
bool startFoundInThisPacket = false;
|
||||||
|
for (size_t idx = 0; idx < len; idx++) {
|
||||||
|
if (data[idx] == DleEncoder::STX_CHAR) {
|
||||||
|
if (not startFound and not startFoundInThisPacket) {
|
||||||
|
startIdx = idx;
|
||||||
|
copyIntoRingBufFromHere = idx;
|
||||||
|
copyAmount = len - idx;
|
||||||
|
} else {
|
||||||
|
// Maybe print warning, should not happen
|
||||||
|
decodeRingBuf.clear();
|
||||||
|
ErrorInfo info;
|
||||||
|
info.len = idx;
|
||||||
|
prepareErrorContext(ErrorTypes::CONSECUTIVE_STX_CHARS, info);
|
||||||
|
handler(ctx);
|
||||||
|
copyIntoRingBufFromHere = idx;
|
||||||
|
copyAmount = len - idx;
|
||||||
|
}
|
||||||
|
startFound = true;
|
||||||
|
startFoundInThisPacket = true;
|
||||||
|
} else if (data[idx] == DleEncoder::ETX_CHAR) {
|
||||||
|
if (startFoundInThisPacket) {
|
||||||
|
size_t readLen = 0;
|
||||||
|
size_t decodedLen = 0;
|
||||||
|
result = decoder.decode(data + startIdx, idx + 1 - startIdx, &readLen, decodedBuf.first,
|
||||||
|
decodedBuf.second, &decodedLen);
|
||||||
|
if (result == HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
ctx.setType(ContextType::PACKET_FOUND);
|
||||||
|
ctx.decodedPacket.first = decodedBuf.first;
|
||||||
|
ctx.decodedPacket.second = decodedLen;
|
||||||
|
this->handler(ctx);
|
||||||
|
} else if (result == DleEncoder::STREAM_TOO_SHORT) {
|
||||||
|
ErrorInfo info;
|
||||||
|
info.res = result;
|
||||||
|
prepareErrorContext(ErrorTypes::DECODING_BUF_TOO_SMALL, info);
|
||||||
|
handler(ctx);
|
||||||
|
} else {
|
||||||
|
ErrorInfo info;
|
||||||
|
info.res = result;
|
||||||
|
prepareErrorContext(ErrorTypes::DECODING_BUF_TOO_SMALL, info);
|
||||||
|
handler(ctx);
|
||||||
|
}
|
||||||
|
decodeRingBuf.clear();
|
||||||
|
if ((idx + 1) < len) {
|
||||||
|
copyIntoRingBufFromHere = idx + 1;
|
||||||
|
copyAmount = len - idx - 1;
|
||||||
|
} else {
|
||||||
|
copyAmount = 0;
|
||||||
|
}
|
||||||
|
} else if (startFound) {
|
||||||
|
// ETX found but STX was found in another mini packet. Reconstruct the full packet
|
||||||
|
// to decode it
|
||||||
|
result = decodeRingBuf.writeData(data, idx + 1);
|
||||||
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
ErrorInfo info;
|
||||||
|
info.res = result;
|
||||||
|
prepareErrorContext(ErrorTypes::RING_BUF_ERROR, info);
|
||||||
|
handler(ctx);
|
||||||
|
}
|
||||||
|
size_t fullEncodedLen = decodeRingBuf.getAvailableReadData();
|
||||||
|
if (fullEncodedLen > encodedBuf.second) {
|
||||||
|
ErrorInfo info;
|
||||||
|
info.len = fullEncodedLen;
|
||||||
|
prepareErrorContext(ErrorTypes::ENCODED_BUF_TOO_SMALL, info);
|
||||||
|
handler(ctx);
|
||||||
|
decodeRingBuf.clear();
|
||||||
|
} else {
|
||||||
|
size_t decodedLen = 0;
|
||||||
|
size_t readLen = 0;
|
||||||
|
decodeRingBuf.readData(encodedBuf.first, fullEncodedLen, true);
|
||||||
|
result = decoder.decode(encodedBuf.first, fullEncodedLen, &readLen, decodedBuf.first,
|
||||||
|
decodedBuf.second, &decodedLen);
|
||||||
|
if (result == HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
if (this->handler != nullptr) {
|
||||||
|
ctx.setType(ContextType::PACKET_FOUND);
|
||||||
|
ctx.decodedPacket.first = decodedBuf.first;
|
||||||
|
ctx.decodedPacket.second = decodedLen;
|
||||||
|
this->handler(ctx);
|
||||||
|
}
|
||||||
|
} else if (result == DleEncoder::STREAM_TOO_SHORT) {
|
||||||
|
ErrorInfo info;
|
||||||
|
info.res = result;
|
||||||
|
prepareErrorContext(ErrorTypes::DECODING_BUF_TOO_SMALL, info);
|
||||||
|
handler(ctx);
|
||||||
|
} else {
|
||||||
|
ErrorInfo info;
|
||||||
|
info.res = result;
|
||||||
|
prepareErrorContext(ErrorTypes::DECODE_ERROR, info);
|
||||||
|
handler(ctx);
|
||||||
|
}
|
||||||
|
decodeRingBuf.clear();
|
||||||
|
startFound = false;
|
||||||
|
startFoundInThisPacket = false;
|
||||||
|
if ((idx + 1) < len) {
|
||||||
|
copyIntoRingBufFromHere = idx + 1;
|
||||||
|
copyAmount = len - idx - 1;
|
||||||
|
} else {
|
||||||
|
copyAmount = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// End data without preceeding STX
|
||||||
|
ErrorInfo info;
|
||||||
|
info.len = idx + 1;
|
||||||
|
prepareErrorContext(ErrorTypes::CONSECUTIVE_ETX_CHARS, info);
|
||||||
|
handler(ctx);
|
||||||
|
decodeRingBuf.clear();
|
||||||
|
if ((idx + 1) < len) {
|
||||||
|
copyIntoRingBufFromHere = idx + 1;
|
||||||
|
copyAmount = len - idx - 1;
|
||||||
|
} else {
|
||||||
|
copyAmount = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
startFoundInThisPacket = false;
|
||||||
|
startFound = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (copyAmount > 0) {
|
||||||
|
result = decodeRingBuf.writeData(data + copyIntoRingBufFromHere, copyAmount);
|
||||||
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
ErrorInfo info;
|
||||||
|
info.res = result;
|
||||||
|
prepareErrorContext(ErrorTypes::RING_BUF_ERROR, info);
|
||||||
|
handler(ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DleParser::defaultFoundPacketHandler(uint8_t* packet, size_t len, void* args) {
|
||||||
|
#if FSFW_VERBOSE_LEVEL >= 1
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::info << "DleParserBase::handleFoundPacket: Detected DLE packet with " << len << " bytes"
|
||||||
|
<< std::endl;
|
||||||
|
#else
|
||||||
|
sif::printInfo("DleParserBase::handleFoundPacket: Detected DLE packet with %d bytes\n", len);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void DleParser::defaultErrorHandler(ErrorTypes err, ErrorInfo ctx) {
|
||||||
|
switch (err) {
|
||||||
|
case (ErrorTypes::NONE): {
|
||||||
|
errorPrinter("No error");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case (ErrorTypes::DECODE_ERROR): {
|
||||||
|
errorPrinter("Decode Error");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case (ErrorTypes::RING_BUF_ERROR): {
|
||||||
|
errorPrinter("Ring Buffer Error");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case (ErrorTypes::ENCODED_BUF_TOO_SMALL):
|
||||||
|
case (ErrorTypes::DECODING_BUF_TOO_SMALL): {
|
||||||
|
char opt[64];
|
||||||
|
snprintf(opt, sizeof(opt), ": Too small for packet with length %zu", ctx.len);
|
||||||
|
if (err == ErrorTypes::ENCODED_BUF_TOO_SMALL) {
|
||||||
|
errorPrinter("Encoded buf too small", opt);
|
||||||
|
} else {
|
||||||
|
errorPrinter("Decoding buf too small", opt);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case (ErrorTypes::CONSECUTIVE_STX_CHARS): {
|
||||||
|
errorPrinter("Consecutive STX chars detected");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case (ErrorTypes::CONSECUTIVE_ETX_CHARS): {
|
||||||
|
errorPrinter("Consecutive ETX chars detected");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DleParser::errorPrinter(const char* str, const char* opt) {
|
||||||
|
if (opt == nullptr) {
|
||||||
|
opt = "";
|
||||||
|
}
|
||||||
|
#if FSFW_VERBOSE_LEVEL >= 1
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::info << "DleParserBase::handleParseError: " << str << opt << std::endl;
|
||||||
|
#else
|
||||||
|
sif::printInfo("DleParserBase::handleParseError: %s%s\n", str, opt);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void DleParser::prepareErrorContext(ErrorTypes err, ErrorInfo info) {
|
||||||
|
ctx.setType(ContextType::ERROR);
|
||||||
|
ctx.error.first = err;
|
||||||
|
ctx.error.second = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DleParser::reset() {
|
||||||
|
startFound = false;
|
||||||
|
decodeRingBuf.clear();
|
||||||
|
}
|
124
src/fsfw/globalfunctions/DleParser.h
Normal file
124
src/fsfw/globalfunctions/DleParser.h
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <fsfw/container/SimpleRingBuffer.h>
|
||||||
|
#include <fsfw/globalfunctions/DleEncoder.h>
|
||||||
|
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This base helper class can be used to extract DLE encoded packets from a data stream
|
||||||
|
* @details
|
||||||
|
* The core API of the parser takes received packets which can contains DLE packets. The parser
|
||||||
|
* can deal with DLE packets split across multiple packets. It does so by using a dedicated
|
||||||
|
* decoding ring buffer. The user can process received packets and detect errors by
|
||||||
|
* overriding two provided virtual methods. This also allows detecting multiple DLE packets
|
||||||
|
* inside one passed packet.
|
||||||
|
*/
|
||||||
|
class DleParser : public HasReturnvaluesIF {
|
||||||
|
public:
|
||||||
|
using BufPair = std::pair<uint8_t*, size_t>;
|
||||||
|
|
||||||
|
enum class ContextType { PACKET_FOUND, ERROR };
|
||||||
|
|
||||||
|
enum class ErrorTypes {
|
||||||
|
NONE,
|
||||||
|
ENCODED_BUF_TOO_SMALL,
|
||||||
|
DECODING_BUF_TOO_SMALL,
|
||||||
|
DECODE_ERROR,
|
||||||
|
RING_BUF_ERROR,
|
||||||
|
CONSECUTIVE_STX_CHARS,
|
||||||
|
CONSECUTIVE_ETX_CHARS
|
||||||
|
};
|
||||||
|
|
||||||
|
union ErrorInfo {
|
||||||
|
size_t len;
|
||||||
|
ReturnValue_t res;
|
||||||
|
};
|
||||||
|
|
||||||
|
using ErrorPair = std::pair<ErrorTypes, ErrorInfo>;
|
||||||
|
|
||||||
|
struct Context {
|
||||||
|
public:
|
||||||
|
Context(void* args) : userArgs(args) { setType(ContextType::PACKET_FOUND); }
|
||||||
|
|
||||||
|
void setType(ContextType type) {
|
||||||
|
if (type == ContextType::PACKET_FOUND) {
|
||||||
|
error.first = ErrorTypes::NONE;
|
||||||
|
error.second.len = 0;
|
||||||
|
} else {
|
||||||
|
decodedPacket.first = nullptr;
|
||||||
|
decodedPacket.second = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ContextType getType() const { return type; }
|
||||||
|
|
||||||
|
BufPair decodedPacket = {};
|
||||||
|
ErrorPair error;
|
||||||
|
void* userArgs;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ContextType type;
|
||||||
|
};
|
||||||
|
|
||||||
|
using UserHandler = void (*)(const Context& ctx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class constructor
|
||||||
|
* @param decodeRingBuf Ring buffer used to store multiple packets to allow detecting DLE packets
|
||||||
|
* split across multiple packets
|
||||||
|
* @param decoder Decoder instance
|
||||||
|
* @param encodedBuf Buffer used to store encoded packets. It has to be large enough to hold
|
||||||
|
* the largest expected encoded DLE packet size
|
||||||
|
* @param decodedBuf Buffer used to store decoded packets. It has to be large enough to hold the
|
||||||
|
* largest expected decoded DLE packet size
|
||||||
|
* @param handler Function which will be called on a found packet
|
||||||
|
* @param args Arbitrary user argument
|
||||||
|
*/
|
||||||
|
DleParser(SimpleRingBuffer& decodeRingBuf, DleEncoder& decoder, BufPair encodedBuf,
|
||||||
|
BufPair decodedBuf, UserHandler handler, void* args);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function allows to pass new data into the parser. It then scans for DLE packets
|
||||||
|
* automatically and inserts (part of) the packet into a ring buffer if necessary.
|
||||||
|
* @param data
|
||||||
|
* @param len
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
ReturnValue_t passData(uint8_t* data, size_t len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Example found packet handler
|
||||||
|
* function call
|
||||||
|
* @param packet Decoded packet
|
||||||
|
* @param len Length of detected packet
|
||||||
|
*/
|
||||||
|
void defaultFoundPacketHandler(uint8_t* packet, size_t len, void* args);
|
||||||
|
/**
|
||||||
|
* Will be called if an error occured in the #passData call
|
||||||
|
* @param err
|
||||||
|
* @param ctx Context information depending on the error type
|
||||||
|
* - For buffer length errors, will be set to the detected packet length which is too large
|
||||||
|
* - For decode or ring buffer errors, will be set to the result returned from the failed call
|
||||||
|
*/
|
||||||
|
static void defaultErrorHandler(ErrorTypes err, ErrorInfo ctx);
|
||||||
|
|
||||||
|
static void errorPrinter(const char* str, const char* opt = nullptr);
|
||||||
|
|
||||||
|
void prepareErrorContext(ErrorTypes err, ErrorInfo ctx);
|
||||||
|
/**
|
||||||
|
* Resets the parser by resetting the internal states and clearing the decoding ring buffer
|
||||||
|
*/
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
private:
|
||||||
|
SimpleRingBuffer& decodeRingBuf;
|
||||||
|
DleEncoder& decoder;
|
||||||
|
BufPair encodedBuf;
|
||||||
|
BufPair decodedBuf;
|
||||||
|
UserHandler handler = nullptr;
|
||||||
|
Context ctx;
|
||||||
|
bool startFound = false;
|
||||||
|
};
|
@ -1,4 +1 @@
|
|||||||
target_sources(${LIB_FSFW_NAME}
|
target_sources(${LIB_FSFW_NAME} PRIVATE QuaternionOperations.cpp)
|
||||||
PRIVATE
|
|
||||||
QuaternionOperations.cpp
|
|
||||||
)
|
|
||||||
|
@ -1,6 +1,2 @@
|
|||||||
target_sources(${LIB_FSFW_NAME}
|
target_sources(${LIB_FSFW_NAME} PRIVATE HealthHelper.cpp HealthMessage.cpp
|
||||||
PRIVATE
|
HealthTable.cpp)
|
||||||
HealthHelper.cpp
|
|
||||||
HealthMessage.cpp
|
|
||||||
HealthTable.cpp
|
|
||||||
)
|
|
||||||
|
@ -16,26 +16,27 @@ class HasHealthIF {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const uint8_t INTERFACE_ID = CLASS_ID::HAS_HEALTH_IF;
|
static const uint8_t INTERFACE_ID = CLASS_ID::HAS_HEALTH_IF;
|
||||||
static const ReturnValue_t OBJECT_NOT_HEALTHY = MAKE_RETURN_CODE(1);
|
static constexpr ReturnValue_t OBJECT_NOT_HEALTHY =
|
||||||
static const ReturnValue_t INVALID_HEALTH_STATE = MAKE_RETURN_CODE(2);
|
HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 1);
|
||||||
|
static constexpr ReturnValue_t INVALID_HEALTH_STATE =
|
||||||
|
HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 2);
|
||||||
|
static constexpr ReturnValue_t IS_EXTERNALLY_CONTROLLED =
|
||||||
|
HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 3);
|
||||||
|
|
||||||
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::SYSTEM_MANAGER_1;
|
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::SYSTEM_MANAGER_1;
|
||||||
|
//! P1: New Health, P2: Old Health
|
||||||
static const Event HEALTH_INFO = MAKE_EVENT(6, severity::INFO);
|
static const Event HEALTH_INFO = MAKE_EVENT(6, severity::INFO);
|
||||||
static const Event CHILD_CHANGED_HEALTH = MAKE_EVENT(7, severity::INFO);
|
static const Event CHILD_CHANGED_HEALTH = MAKE_EVENT(7, severity::INFO);
|
||||||
static const Event CHILD_PROBLEMS = MAKE_EVENT(8, severity::LOW);
|
static const Event CHILD_PROBLEMS = MAKE_EVENT(8, severity::LOW);
|
||||||
static const Event OVERWRITING_HEALTH =
|
//! Assembly overwrites health information of children to keep satellite alive.
|
||||||
MAKE_EVENT(9, severity::LOW); //!< Assembly overwrites health information of children to keep
|
static const Event OVERWRITING_HEALTH = MAKE_EVENT(9, severity::LOW);
|
||||||
//!< satellite alive.
|
//! Someone starts a recovery of a component (typically power-cycle). No parameters.
|
||||||
static const Event TRYING_RECOVERY =
|
static const Event TRYING_RECOVERY = MAKE_EVENT(10, severity::MEDIUM);
|
||||||
MAKE_EVENT(10, severity::MEDIUM); //!< Someone starts a recovery of a component (typically
|
//! Recovery is ongoing. Comes twice during recovery.
|
||||||
//!< power-cycle). No parameters.
|
//! P1: 0 for the first, 1 for the second event. P2: 0
|
||||||
static const Event RECOVERY_STEP =
|
static const Event RECOVERY_STEP = MAKE_EVENT(11, severity::MEDIUM);
|
||||||
MAKE_EVENT(11, severity::MEDIUM); //!< Recovery is ongoing. Comes twice during recovery. P1:
|
//! Recovery was completed. Not necessarily successful. No parameters.
|
||||||
//!< 0 for the first, 1 for the second event. P2: 0
|
static const Event RECOVERY_DONE = MAKE_EVENT(12, severity::MEDIUM);
|
||||||
static const Event RECOVERY_DONE = MAKE_EVENT(
|
|
||||||
12,
|
|
||||||
severity::MEDIUM); //!< Recovery was completed. Not necessarily successful. No parameters.
|
|
||||||
|
|
||||||
virtual ~HasHealthIF() {}
|
virtual ~HasHealthIF() {}
|
||||||
|
|
||||||
virtual MessageQueueId_t getCommandQueue() const = 0;
|
virtual MessageQueueId_t getCommandQueue() const = 0;
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
HealthHelper::HealthHelper(HasHealthIF* owner, object_id_t objectId)
|
HealthHelper::HealthHelper(HasHealthIF* owner, object_id_t objectId)
|
||||||
: objectId(objectId), owner(owner) {}
|
: objectId(objectId), owner(owner) {}
|
||||||
|
|
||||||
HealthHelper::~HealthHelper() {}
|
HealthHelper::~HealthHelper() { healthTable->removeObject(objectId); }
|
||||||
|
|
||||||
ReturnValue_t HealthHelper::handleHealthCommand(CommandMessage* message) {
|
ReturnValue_t HealthHelper::handleHealthCommand(CommandMessage* message) {
|
||||||
switch (message->getCommand()) {
|
switch (message->getCommand()) {
|
||||||
|
@ -27,6 +27,15 @@ ReturnValue_t HealthTable::registerObject(object_id_t object,
|
|||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ReturnValue_t HealthTable::removeObject(object_id_t object) {
|
||||||
|
mapIterator = healthMap.find(object);
|
||||||
|
if (mapIterator == healthMap.end()) {
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
healthMap.erase(mapIterator);
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
void HealthTable::setHealth(object_id_t object, HasHealthIF::HealthState newState) {
|
void HealthTable::setHealth(object_id_t object, HasHealthIF::HealthState newState) {
|
||||||
MutexGuard(mutex, timeoutType, mutexTimeoutMs);
|
MutexGuard(mutex, timeoutType, mutexTimeoutMs);
|
||||||
HealthMap::iterator iter = healthMap.find(object);
|
HealthMap::iterator iter = healthMap.find(object);
|
||||||
|
@ -17,6 +17,7 @@ class HealthTable : public HealthTableIF, public SystemObject {
|
|||||||
/** HealthTableIF overrides */
|
/** HealthTableIF overrides */
|
||||||
virtual ReturnValue_t registerObject(
|
virtual ReturnValue_t registerObject(
|
||||||
object_id_t object, HasHealthIF::HealthState initilialState = HasHealthIF::HEALTHY) override;
|
object_id_t object, HasHealthIF::HealthState initilialState = HasHealthIF::HEALTHY) override;
|
||||||
|
ReturnValue_t removeObject(object_id_t object) override;
|
||||||
virtual size_t getPrintSize() override;
|
virtual size_t getPrintSize() override;
|
||||||
virtual void printAll(uint8_t* pointer, size_t maxSize) override;
|
virtual void printAll(uint8_t* pointer, size_t maxSize) override;
|
||||||
|
|
||||||
|
@ -14,6 +14,8 @@ class HealthTableIF : public ManagesHealthIF {
|
|||||||
virtual ReturnValue_t registerObject(
|
virtual ReturnValue_t registerObject(
|
||||||
object_id_t object, HasHealthIF::HealthState initilialState = HasHealthIF::HEALTHY) = 0;
|
object_id_t object, HasHealthIF::HealthState initilialState = HasHealthIF::HEALTHY) = 0;
|
||||||
|
|
||||||
|
virtual ReturnValue_t removeObject(object_id_t objectId) = 0;
|
||||||
|
|
||||||
virtual size_t getPrintSize() = 0;
|
virtual size_t getPrintSize() = 0;
|
||||||
virtual void printAll(uint8_t *pointer, size_t maxSize) = 0;
|
virtual void printAll(uint8_t *pointer, size_t maxSize) = 0;
|
||||||
|
|
||||||
|
@ -1,5 +1,2 @@
|
|||||||
target_sources(${LIB_FSFW_NAME}
|
target_sources(${LIB_FSFW_NAME} PRIVATE HousekeepingMessage.cpp
|
||||||
PRIVATE
|
PeriodicHousekeepingHelper.cpp)
|
||||||
HousekeepingMessage.cpp
|
|
||||||
PeriodicHousekeepingHelper.cpp
|
|
||||||
)
|
|
||||||
|
@ -1,4 +1 @@
|
|||||||
target_sources(${LIB_FSFW_NAME}
|
target_sources(${LIB_FSFW_NAME} PRIVATE InternalErrorReporter.cpp)
|
||||||
PRIVATE
|
|
||||||
InternalErrorReporter.cpp
|
|
||||||
)
|
|
||||||
|
@ -7,11 +7,13 @@
|
|||||||
|
|
||||||
InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId, uint32_t messageQueueDepth)
|
InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId, uint32_t messageQueueDepth)
|
||||||
: SystemObject(setObjectId),
|
: SystemObject(setObjectId),
|
||||||
commandQueue(QueueFactory::instance()->createMessageQueue(messageQueueDepth)),
|
|
||||||
poolManager(this, commandQueue),
|
poolManager(this, commandQueue),
|
||||||
internalErrorSid(setObjectId, InternalErrorDataset::ERROR_SET_ID),
|
internalErrorSid(setObjectId, InternalErrorDataset::ERROR_SET_ID),
|
||||||
internalErrorDataset(this) {
|
internalErrorDataset(this) {
|
||||||
mutex = MutexFactory::instance()->createMutex();
|
mutex = MutexFactory::instance()->createMutex();
|
||||||
|
auto mqArgs = MqArgs(setObjectId, static_cast<void *>(this));
|
||||||
|
commandQueue = QueueFactory::instance()->createMessageQueue(
|
||||||
|
messageQueueDepth, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
InternalErrorReporter::~InternalErrorReporter() { MutexFactory::instance()->deleteMutex(mutex); }
|
InternalErrorReporter::~InternalErrorReporter() { MutexFactory::instance()->deleteMutex(mutex); }
|
||||||
@ -36,15 +38,14 @@ ReturnValue_t InternalErrorReporter::performOperation(uint8_t opCode) {
|
|||||||
if ((newQueueHits > 0) or (newTmHits > 0) or (newStoreHits > 0)) {
|
if ((newQueueHits > 0) or (newTmHits > 0) or (newStoreHits > 0)) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::debug << "InternalErrorReporter::performOperation: Errors "
|
sif::debug << "InternalErrorReporter::performOperation: Errors "
|
||||||
<< "occured!" << std::endl;
|
<< "occured: Queue | TM | Store : " << newQueueHits << " | " << newTmHits << " | "
|
||||||
sif::debug << "Queue errors: " << newQueueHits << std::endl;
|
<< newStoreHits << std::endl;
|
||||||
sif::debug << "TM errors: " << newTmHits << std::endl;
|
|
||||||
sif::debug << "Store errors: " << newStoreHits << std::endl;
|
|
||||||
#else
|
#else
|
||||||
sif::printDebug("InternalErrorReporter::performOperation: Errors occured!\n");
|
sif::printDebug(
|
||||||
sif::printDebug("Queue errors: %lu\n", static_cast<unsigned int>(newQueueHits));
|
"InternalErrorReporter::performOperation: Errors occured: Queue | TM | Store: %lu | %lu "
|
||||||
sif::printDebug("TM errors: %lu\n", static_cast<unsigned int>(newTmHits));
|
"| %lu\n",
|
||||||
sif::printDebug("Store errors: %lu\n", static_cast<unsigned int>(newStoreHits));
|
static_cast<unsigned int>(newQueueHits), static_cast<unsigned int>(newTmHits),
|
||||||
|
static_cast<unsigned int>(newStoreHits));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
target_sources(
|
||||||
CommandMessage.cpp
|
${LIB_FSFW_NAME} PRIVATE CommandMessage.cpp CommandMessageCleaner.cpp
|
||||||
CommandMessageCleaner.cpp
|
MessageQueueMessage.cpp MessageQueueBase.cpp)
|
||||||
MessageQueueMessage.cpp
|
|
||||||
MessageQueueBase.cpp
|
|
||||||
)
|
|
||||||
|
@ -34,7 +34,7 @@ class CommandMessageIF {
|
|||||||
static const Command_t CMD_NONE = MAKE_COMMAND_ID(0);
|
static const Command_t CMD_NONE = MAKE_COMMAND_ID(0);
|
||||||
static const Command_t REPLY_COMMAND_OK = MAKE_COMMAND_ID(1);
|
static const Command_t REPLY_COMMAND_OK = MAKE_COMMAND_ID(1);
|
||||||
//! Reply indicating that the current command was rejected,
|
//! Reply indicating that the current command was rejected,
|
||||||
//! par1 should contain the error code
|
//! Parameter 1 should contain the error code
|
||||||
static const Command_t REPLY_REJECTED = MAKE_COMMAND_ID(2);
|
static const Command_t REPLY_REJECTED = MAKE_COMMAND_ID(2);
|
||||||
|
|
||||||
virtual ~CommandMessageIF(){};
|
virtual ~CommandMessageIF(){};
|
||||||
|
@ -1,5 +1,2 @@
|
|||||||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
target_sources(${LIB_FSFW_NAME} PRIVATE MemoryHelper.cpp MemoryMessage.cpp
|
||||||
MemoryHelper.cpp
|
GenericFileSystemMessage.cpp)
|
||||||
MemoryMessage.cpp
|
|
||||||
GenericFileSystemMessage.cpp
|
|
||||||
)
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user