Compare commits
691 Commits
irini
...
mueller/ua
Author | SHA1 | Date | |
---|---|---|---|
40e7b2dc31 | |||
b9d0ff8fb7 | |||
227535c461 | |||
c47bed0760 | |||
9927dbb2e4 | |||
14a48fe41d | |||
c932e51818 | |||
2ca8d72e83 | |||
03e1a93250 | |||
6d2f44a432 | |||
808e3e0462 | |||
79ab0c4aa5 | |||
72172a972b | |||
b4b11ebd3b | |||
c5b24f2516 | |||
e2c1158337 | |||
95aac7dc8d | |||
3d2fc28468 | |||
1898b4f2db | |||
c38088c64b | |||
7eb63d6d79 | |||
6f8ccf83e7 | |||
67f1cd0b5f | |||
1d54507517 | |||
ef9ed95fd1 | |||
ed68268c0c | |||
c549914efb | |||
753d5ff39e | |||
36ca35da77 | |||
54762232a4 | |||
4fb7375492 | |||
2fee2fdff5 | |||
47df9e8b5b | |||
954c749de0 | |||
131e3ff1e3 | |||
423a9540ed | |||
7e0a5d5a9e | |||
ee1c6a3f04 | |||
86aafe4422 | |||
e585c1d84a | |||
1a833e2d45 | |||
8df6d934d7 | |||
5363868120 | |||
36cf59cc8e | |||
97fec909f2 | |||
1db77753e3 | |||
8501477a78 | |||
9a181aa6a8 | |||
655c944c0e | |||
2e310fca8d | |||
37390dfc74 | |||
75ddfdc65d | |||
1efc0d2855 | |||
e063b44899 | |||
b3c0e24611 | |||
ab7c3480f5 | |||
237e29cc59 | |||
0849c8a08d | |||
723f8749d4 | |||
dbaeed83af | |||
2e27a85c95 | |||
385a0ffd73 | |||
73f1917c81 | |||
3a52454949 | |||
ac7dc55fc1 | |||
389d804735 | |||
44615c150b | |||
bd594123a2 | |||
0ce568ad26 | |||
6970068d56 | |||
af282c7d3e | |||
21a9d89fb3 | |||
3257935150 | |||
f34cf9095d | |||
24ecf125a3 | |||
6451a16888 | |||
4dadef34fd | |||
382543fc59 | |||
fa5605c959 | |||
a1ea671e2f | |||
8e835be55f | |||
9bd600c488 | |||
9c7248e78e | |||
ecf51b2913 | |||
8bbde05413 | |||
d79b5348d8 | |||
92e3ab04f3 | |||
003a6d00fa | |||
26b3e5a013 | |||
3e9b47d3a2 | |||
9ee1896553 | |||
a5b5523111 | |||
62cd39e573 | |||
278ed36db8 | |||
aed30d54ef | |||
1126db2c8a | |||
a64a04d7fe | |||
80467bf097 | |||
6a6aa7fdd6 | |||
7e379d2159 | |||
6ae709acc3 | |||
34dd478848 | |||
b73754dfd6 | |||
ec1e07b466 | |||
d52f335455 | |||
c87667c03f | |||
683cf8a047 | |||
11a4b27642 | |||
770463e618 | |||
04b619a15c | |||
282704e0fd | |||
8971eb386e | |||
c54caf134a | |||
aebd401d5b | |||
67439b4285 | |||
07ef9a0ec3 | |||
af851165b4 | |||
94c9800fae | |||
ba046cebd9 | |||
428da017ba | |||
806ae9b41a | |||
7b97c8a182 | |||
2e4cdb7366 | |||
5a3f05fa79 | |||
80464f2a81 | |||
16688316a8 | |||
ead22c8bd6 | |||
3583e30ee6 | |||
61db018a74 | |||
1e395dc402 | |||
afc48726b9 | |||
ece5ae59e4 | |||
a5d1c38b22 | |||
f5421e9abd | |||
4c3f9feb93 | |||
b7ed8ff390 | |||
75dc7a405d | |||
b7a1f79d5b | |||
f0b7a103d4 | |||
fb96250e36 | |||
ee93f4a4ca | |||
d64ad71529 | |||
5ce1e76723 | |||
26bc80964e | |||
eb03bf52a6 | |||
52802f127b | |||
d2c4d546c3 | |||
0dd2b5ddd4 | |||
3dfc882226 | |||
b984128de5 | |||
134d5a1411 | |||
3147f67fbd | |||
108e7737e2 | |||
c90d1c8071 | |||
eae75b29e7 | |||
dc79b7ba00 | |||
db84dcd3ce | |||
80355910ee | |||
04800df31e | |||
1e85cdadfd | |||
ebc02673dd | |||
935f35a40d | |||
348af0124b | |||
9202c6c17f | |||
5f8c549993 | |||
04bff7a522 | |||
5c20cc804e | |||
eb8e236cd4 | |||
7dec45ccf2 | |||
2b01e86f9c | |||
60fd3d43c0 | |||
67980cb592 | |||
3010f2f925 | |||
01651f0521 | |||
cf8fe7ea72 | |||
c7f300671f | |||
7d3223d766 | |||
7ae82a5cb4 | |||
28ecd0e5c6 | |||
496dac89e4 | |||
7345c18b04 | |||
cfca27542a | |||
0de7b66218 | |||
2fa76d3663 | |||
158007fa7f | |||
726f44cafe | |||
ab719a3e59 | |||
141dcb1f14 | |||
6ebd6a965b | |||
20f0707813 | |||
8d1777fa0c | |||
21ac86619e | |||
eedf57624f | |||
64a7fde301 | |||
ae40543e3a | |||
9131ca688b | |||
efd2994dc5 | |||
3ebebbd493 | |||
a8c066dccc | |||
4d17f1c4bb | |||
d4ed528426 | |||
e10e71cee9 | |||
d675a789a2 | |||
6b8c83be29 | |||
093052604a | |||
192255df1c | |||
bdd79d060d | |||
8e6cee7761 | |||
c756297e5c | |||
3a47062f2a | |||
0f27c7e7e7 | |||
20d42add03 | |||
a9277622ce | |||
80e8511a43 | |||
4a06f11582 | |||
32c53b932d | |||
aea9db75cb | |||
9fedd03ed8 | |||
10fc4dd89d | |||
0cc8af5eb0 | |||
92d65aa3a5 | |||
342a56410c | |||
2cab73d972 | |||
9a9085b9e6 | |||
cb23911ccd | |||
b499dedd76 | |||
1bb487373d | |||
3bffb4f968 | |||
6bcb208968 | |||
6c2b5ab39e | |||
a7039bad41 | |||
6605ffb6b1 | |||
e2e0190cae | |||
fd278e410b | |||
9a590a3fcd | |||
2a75440b32 | |||
ff4cbea571 | |||
81a7c21cd1 | |||
f5866ddace | |||
f91ad84bdc | |||
267466be9d | |||
2c730c8632 | |||
eb29b79467 | |||
26ea6606bf | |||
b1bd631322 | |||
9441b4a70e | |||
95457b1760 | |||
a46d8c34d9 | |||
d12c59c8ac | |||
9e5dddf79c | |||
ba5c6410d6 | |||
52f8c5038b | |||
10f34e5a48 | |||
dab1b1d067 | |||
8c8d1cfa84 | |||
2a4ab0af7b | |||
7c59df3f1c | |||
3b33b429e6 | |||
ff6de8e378 | |||
7881f5bab8 | |||
11a699c3ce | |||
6930656d4e | |||
0bb82e0da2 | |||
12c452e7ce | |||
23f514039a | |||
34c714eb17 | |||
7205885357 | |||
42c5881c50 | |||
cdd0ca70ed | |||
e3648b6e30 | |||
2e52d7a31d | |||
239d053562 | |||
875174c4ad | |||
8fd8a37f59 | |||
d815f422c3 | |||
217276d50c | |||
d2ac3603a5 | |||
f63f3fa564 | |||
d975958120 | |||
fc34d56239 | |||
1037102349 | |||
221361eb9c | |||
7f9269b387 | |||
4224c3d009 | |||
62fe75ee40 | |||
c57e95c698 | |||
e76e109bdb | |||
9e064fe800 | |||
2339c48756 | |||
d7ec04bf4b | |||
4d82d0e4c1 | |||
adcc375f25 | |||
94a718ff19 | |||
4a10f76784 | |||
57ce5d1f34 | |||
90963b3940 | |||
71ed95b09a | |||
7ac4f1c64d | |||
9d64b96e9a | |||
5de2c6af66 | |||
ca2efb6021 | |||
3b000d924a | |||
deeeef553b | |||
0e7ec79af9 | |||
007f958a0b | |||
d022ce82c5 | |||
d3cabd8984 | |||
8efe85cb15 | |||
b28091e05b | |||
f4c4f9946c | |||
7f89022f5b | |||
b28c26b288 | |||
8b4253bc46 | |||
fdcfd89ed2 | |||
03fa77e2b3 | |||
8970a7379a | |||
c12492df03 | |||
8aaabc5d73 | |||
e796e025b6 | |||
20eee2c469 | |||
aca8b53a59 | |||
3df1161560 | |||
ea6e5d9971 | |||
46a4203d00 | |||
c86adf8e10 | |||
a2e0646ed4 | |||
28c8248f26 | |||
3e1fd15613 | |||
e45a99143c | |||
96dfe46e25 | |||
507c6ddff1 | |||
0cb15e901e | |||
d45108e3c2 | |||
8c059f8f32 | |||
5bea92d2a4 | |||
bba2d883b6 | |||
7a20412305 | |||
dce1ebcf65 | |||
4ee01e395b | |||
7f9401cf63 | |||
dba3f9960e | |||
eccb629ba8 | |||
7fb906a0ac | |||
9796abfc7d | |||
0d26a0f54b | |||
192956c2c7 | |||
22e1555f50 | |||
bddf5bded1 | |||
1c0b778848 | |||
c832bffdb0 | |||
2f8020baac | |||
06bea2f621 | |||
4f1fe39182 | |||
904abfba28 | |||
202d9341d8 | |||
37c60d1dd0 | |||
43fb6ef5cb | |||
65a47c7c57 | |||
fdb0cc0e44 | |||
e6957de166 | |||
cc56b00df3 | |||
269a3052ca | |||
c6a7a0fec8 | |||
acf5c2a56d | |||
7fb9e14555 | |||
b20e8a9679 | |||
29bcaee196 | |||
cc98512caf | |||
60ea9a9a7c | |||
df690b9628 | |||
b0c479cab9 | |||
a426aef7c7 | |||
43048c852a | |||
19817bd3a5 | |||
1db04cf20c | |||
902a4bfa9c | |||
52ee50ba8c | |||
bf540ebb49 | |||
aa978205d8 | |||
4334106ad1 | |||
458fe460eb | |||
83d71548ec | |||
f4beef8c9f | |||
c7b4dc349a | |||
96f092ef75 | |||
f75379fceb | |||
4a4d23573d | |||
cd4d92b12c | |||
47e148af8f | |||
c9bec03f00 | |||
6c5c59cad8 | |||
03e12a2388 | |||
6c5bbfa080 | |||
da106fd96f | |||
fc3412fa35 | |||
8f6f0e1d45 | |||
1b5fa2a8fa | |||
cb118176a0 | |||
30ba9ab916 | |||
fb4ba487b5 | |||
72bc5d4d60 | |||
5355e63711 | |||
b11cdf6184 | |||
dc31358d52 | |||
b485afea57 | |||
5bb7023ff3 | |||
85dbef20b0 | |||
93acac02f5 | |||
7e8afcc12f | |||
f03b7cd660 | |||
d641d63531 | |||
4e571e5082 | |||
356d778743 | |||
0a38d2e22d | |||
234ccdf764 | |||
f591b9793c | |||
c5ad9b5fa9 | |||
083d08ae2a | |||
740644f2c8 | |||
059fb10558 | |||
86692e202d | |||
064b195c75 | |||
18ee2ab903 | |||
9eb652e585 | |||
e7d9979078 | |||
681738dcc6 | |||
152c01b2ec | |||
8bf0fb9885 | |||
1954ce0ea4 | |||
d98b79cf5e | |||
f14c812aff | |||
146a0e3828 | |||
75c824ec80 | |||
332e9dbfd5 | |||
f1c37203a4 | |||
500a5602bd | |||
4ed028000d | |||
88ebb67c8d | |||
b827bd8370 | |||
bdf71d4e66 | |||
e48b6f1432 | |||
747243684d | |||
db33f9cc7e | |||
c12669fe50 | |||
6d00fc65c0 | |||
7d87274844 | |||
c83f75c515 | |||
586993c081 | |||
a88f767cca | |||
935e135f1c | |||
6d0fa36f8a | |||
8f07133e2c | |||
f11433e50f | |||
5fd5d488ff | |||
edc5a314b8 | |||
f80be9e9fa | |||
f3af88ae40 | |||
380f1d0206 | |||
54fc35eae7 | |||
05d4162f5b | |||
e030878023 | |||
9ee6da47e9 | |||
1a7d7b172b | |||
36e3956efb | |||
180210dc38 | |||
ca1e921b94 | |||
2a34c831b1 | |||
e2ad37e3e6 | |||
973d4ee8a5 | |||
899d021e00 | |||
4989bd0f02 | |||
832367fb30 | |||
63ee88af17 | |||
4921527022 | |||
f0c8fd2688 | |||
c96e304b68 | |||
d474c4a7ee | |||
3708df2423 | |||
f629d60aaf | |||
b809f90e72 | |||
f2bf4b463e | |||
b66fd63cb4 | |||
fd55de9e95 | |||
8e05fc0417 | |||
55a238d553 | |||
9ccd9fd775 | |||
ddad97033d | |||
99aaf7068d | |||
c9d37e8d62 | |||
42a1d6cccd | |||
133894f4ba | |||
cb05329dd9 | |||
b350018cad | |||
2dfbce6174 | |||
cecaec6007 | |||
f28b9ea61b | |||
9275ccb79b | |||
67776241de | |||
bfee4fd90a | |||
0dfaba81f9 | |||
affde6bad5 | |||
0981ee6f7e | |||
61bc867bed | |||
5af3138e81 | |||
08e0b0f1a0 | |||
23f264096c | |||
e5ee96259d | |||
9bbe1dc716 | |||
d8b6cb39ac | |||
be35bd53a6 | |||
9860061fc6 | |||
d80941514f | |||
6c636661b6 | |||
5fffbd4a90 | |||
95b476d4bd | |||
3d2af203f2 | |||
74794bb71b | |||
ddf38b65c3 | |||
490a80e49f | |||
6f751c2cf9 | |||
9a2e68b37e | |||
91067cde98 | |||
428018e4f1 | |||
e4d7182d93 | |||
8b6dd3f868 | |||
f6ede7cd3e | |||
4da18172b3 | |||
6e5239e9a0 | |||
7e2fdc06cd | |||
3c72a42ce1 | |||
78b09ed0c9 | |||
fdf35232ee | |||
8465670374 | |||
0c5f623780 | |||
d7a2eada94 | |||
546e173cef | |||
0a7f2c6646 | |||
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 | |||
d47a908117 | |||
fce95e04a8 | |||
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 | |||
c697d0f8ab | |||
940fd6f465 | |||
8e9d4b451c | |||
d871f55a89 | |||
816550b69c | |||
1611a4e1f0 | |||
8a12a5097e | |||
87e4a57ef7 | |||
0375ee1881 | |||
c8e034d975 | |||
2708b71d77 | |||
6366283ce2 | |||
8dc640c162 | |||
ff40a71582 | |||
2e4b9bcd7c | |||
e1604b292c | |||
aacaf52fd9 | |||
89f83f4e3d | |||
39b7976056 | |||
7afe30ea88 | |||
d3e7037759 | |||
0aee86442e | |||
951c077abc | |||
755dcf66a3 | |||
b7ffd2653b | |||
7a5ce57bbc | |||
adfefdd93f | |||
b7a316008a | |||
f598f7030f | |||
70f575396d | |||
ad57e6713e | |||
23f8e5cb41 | |||
879223f38f | |||
8a44c498c5 | |||
a891769a02 | |||
df97c582d7 |
8
.gitignore
vendored
8
.gitignore
vendored
@ -1,6 +1,14 @@
|
||||
# PyCharm and CLion
|
||||
/.idea/*
|
||||
!/.idea/runConfigurations
|
||||
!/.idea/cmake.xml
|
||||
!/.idea/codeStyles
|
||||
|
||||
# Eclipse
|
||||
.cproject
|
||||
.project
|
||||
.settings
|
||||
.metadata
|
||||
|
||||
/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>
|
138
CHANGELOG.md
138
CHANGELOG.md
@ -8,23 +8,105 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
# [unreleased]
|
||||
|
||||
# [v5.0.0]
|
||||
# [v6.0.0]
|
||||
|
||||
## Fixes
|
||||
|
||||
- Bugfix for Serial Buffer Stream: Setting `doActive` to false now
|
||||
actually fully disables printing.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/680
|
||||
- `TcpTmTcServer.cpp`: The server was actually not able to handle
|
||||
CCSDS packets which were clumped together. This has been fixed now.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/673
|
||||
|
||||
## Added
|
||||
|
||||
- DHB TM handler `handleDeviceTM` renamed to `handleDeviceTm` and now takes
|
||||
`util::DataWrapper` as the data input argument. This allows more flexibility in the possible
|
||||
types of telemetry.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/669
|
||||
- Add `util::DataWrapper` class inside the `util` module. This is a tagged union which allows
|
||||
to specify raw data either as a classic C-style raw pointer and size or as a `SerializeIF`
|
||||
pointer.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/668
|
||||
- Add new `UnsignedByteField` class
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/660
|
||||
|
||||
## Changes
|
||||
|
||||
- Remove default secondary header argument for
|
||||
`uint16_t getTcSpacePacketIdFromApid(uint16_t apid, bool secondaryHeaderFlag)` and
|
||||
`uint16_t getTmSpacePacketIdFromApid(uint16_t apid, bool secondaryHeaderFlag)`
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/689
|
||||
- Removed `HasReturnvaluesIF` class in favor of `returnvalue` namespace with `OK` and `FAILED`
|
||||
constants.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/659
|
||||
- Overhaul of the TMTC stack, including various changes and improvements
|
||||
for other modules
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/655
|
||||
which also includes a migration guide
|
||||
- Bump Catch2 dependency to regular version `v3.1.0`
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/678
|
||||
- `SerialBufferAdapter`: Rename `setBuffer` to `setConstBuffer` and update
|
||||
API to expect `const uint8_t*` accordingly.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/677
|
||||
- Remove the following user includes from `fsfw/events/Event.h` and
|
||||
`fsfw/returnvalues/returnvalue.h`:
|
||||
- `#include "events/subsystemIdRanges.h"`
|
||||
- `#include "returnvalues/classIds.h"`
|
||||
The user has to include those themselves now
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/675
|
||||
- `DeviceHandlerBase`: Set command sender before calling `buildCommandFromCommand`.
|
||||
This allows finishing action commands immediately inside the function.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/672
|
||||
- `DeviceHandlerBase`: New signature of `handleDeviceTm` which expects
|
||||
a `const SerializeIF&` and additional helper variant which expects `const uint8_t*`
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/671
|
||||
- Improvements for `AcceptsTelemetryIF` and `AcceptsTelecommandsIF`:
|
||||
- Make functions `const` where it makes sense
|
||||
- Add `const char* getName const` abstract function
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/684
|
||||
- Move some generic `StorageManagerIF` implementations from `LocalPool` to
|
||||
interface itself so it can be re-used more easily. Also add new
|
||||
abstract function `bool hasDataAtId(store_address_t storeId) const`.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/685
|
||||
|
||||
## CFDP
|
||||
|
||||
- Refactoring of CFDP stack which was done during implementation of the CFDP source and destination
|
||||
handlers.
|
||||
- New filesystem module, changes for filesystem abstraction `HasFileSystemIF` to better
|
||||
fit requirements of CFDP
|
||||
- New `HostFilesystem` implementation of the `HasFileSystemIF`
|
||||
- New `cfdp::UserBase` class which is the abstraction for the CFDP user in an OBSW context.
|
||||
- mib module for the CFDP stack
|
||||
- PDU classes renamed from `...Serializer`/`...Deserializer` to `...Creator`/`...Reader`
|
||||
respetively
|
||||
- Renamed `TcDistributor` to `TcDistributorBase` to prevent confusion
|
||||
- Refactored `TcDisitributorBase` to be more flexible and usable for CFDP distribution
|
||||
- Renamed `CCSDSDistributor` to `CcsdsDistributor` and add feature which allows it
|
||||
to remove the CCSDS header when routing a packet. This allows CCSDS agnostic receiver
|
||||
implementation without an extra component
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/682
|
||||
|
||||
# [v5.0.0] 25.07.2022
|
||||
|
||||
## 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
|
||||
compiler supports it
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/622
|
||||
- HAL Linux SPI: Set the Clock Default State when setting new SPI speed
|
||||
and mode
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/573
|
||||
- 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.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/572
|
||||
- HAL Devicehandlers: Periodic printout is run-time configurable now
|
||||
- `oneShotAction` flag in the `TestTask` class is not static anymore
|
||||
- `SimpleRingBuffer::writeData` now checks if the amount is larger than the total size of the
|
||||
Buffer and rejects such writeData calls with `returnvalue::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.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/601
|
||||
- Add helper functions provided by [`cmake-modules`](https://github.com/bilke/cmake-modules)
|
||||
@ -42,6 +124,41 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
creation call. It allows passing context information and an arbitrary user argument into
|
||||
the message queue. Also streamlined and simplified `MessageQueue` implementation for all OSALs
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/583
|
||||
- Internal API change: Moved the `fsfw_hal` to the `src` folder and integration and internal
|
||||
tests part of `fsfw_tests` to `src`. Unittests are now in a dedicated folder called `unittests`
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/653
|
||||
|
||||
### Task Module Refactoring
|
||||
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/636
|
||||
|
||||
**Refactoring general task code**
|
||||
|
||||
- There was a lot of duplicate/boilerplate code inside the individual task IF OSAL implementations.
|
||||
Remove it by introducing base classes `PeriodicTaskBase` and `FixedTimeslotTaskBase`.
|
||||
|
||||
**Refactor PeriodicTaskIF**
|
||||
|
||||
- Convert `virtual ReturnValue_t addComponent(object_id_t object)` to
|
||||
`virtual ReturnValue_t addComponent(object_id_t object, uint8_t opCode = 0)`, allowing to pass
|
||||
the operation code passed to `performOperation`. Updated API taking
|
||||
an `ExecutableObjectIF` accordingly
|
||||
|
||||
**Refactor FixedTimeslotTaskIF**
|
||||
|
||||
- Add additional `addSlot` function which takes an `ExecutableObjectIF` pointer and its Object ID
|
||||
|
||||
**Refactor FixedSequenceSlot**
|
||||
|
||||
- Introduce typedef `CustomCheckFunc` for `ReturnValue_t (*customCheckFunction)(const SlotList&)`.
|
||||
- Convert `ReturnValue_t (*customCheckFunction)(const SlotList&)` to
|
||||
`ReturnValue_t (*customCheckFunction)(const SlotList&, void*)`, allowing arbitrary user arguments
|
||||
for the custom checker
|
||||
|
||||
**Linux Task Module**
|
||||
|
||||
- Use composition instead of inheritance for the `PeriodicPosixTask` and make the `PosixTask` a
|
||||
member of the class
|
||||
|
||||
### HAL
|
||||
|
||||
@ -84,6 +201,13 @@ https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/593
|
||||
|
||||
## Additions
|
||||
|
||||
- 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.
|
||||
|
@ -13,7 +13,7 @@ list(APPEND CMAKE_MODULE_PATH
|
||||
# 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_REVISION_IF_GIT_FAILS 0)
|
||||
|
||||
@ -67,11 +67,12 @@ endif()
|
||||
set(FSFW_SOURCES_DIR "${CMAKE_SOURCE_DIR}/src/fsfw")
|
||||
|
||||
set(FSFW_ETL_LIB_NAME etl)
|
||||
set(FSFW_ETL_LINK_TARGET etl::etl)
|
||||
set(FSFW_ETL_LIB_MAJOR_VERSION
|
||||
20
|
||||
CACHE STRING "ETL library major version requirement")
|
||||
set(FSFW_ETL_LIB_VERSION
|
||||
${FSFW_ETL_LIB_MAJOR_VERSION}.27.3
|
||||
${FSFW_ETL_LIB_MAJOR_VERSION}.28.0
|
||||
CACHE STRING "ETL library exact version requirement")
|
||||
set(FSFW_ETL_LINK_TARGET etl::etl)
|
||||
|
||||
@ -79,7 +80,7 @@ set(FSFW_CATCH2_LIB_MAJOR_VERSION
|
||||
3
|
||||
CACHE STRING "Catch2 library major version requirement")
|
||||
set(FSFW_CATCH2_LIB_VERSION
|
||||
v${FSFW_CATCH2_LIB_MAJOR_VERSION}.0.0-preview5
|
||||
v${FSFW_CATCH2_LIB_MAJOR_VERSION}.1.0
|
||||
CACHE STRING "Catch2 library exact version requirement")
|
||||
|
||||
# Keep this off by default for now. See PR:
|
||||
@ -103,19 +104,26 @@ if(FSFW_GENERATE_SECTIONS)
|
||||
option(FSFW_REMOVE_UNUSED_CODE "Remove unused code" ON)
|
||||
endif()
|
||||
|
||||
option(FSFW_BUILD_UNITTESTS
|
||||
"Build unittest binary in addition to static library" OFF)
|
||||
option(FSFW_BUILD_TESTS
|
||||
"Build unittest binary in addition to static library. Requires Catch2"
|
||||
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)
|
||||
if(FSFW_BUILD_UNITTESTS)
|
||||
if(FSFW_BUILD_TESTS)
|
||||
option(FSFW_TESTS_GEN_COV "Generate coverage data for unittests" ON)
|
||||
endif()
|
||||
|
||||
option(FSFW_WARNING_SHADOW_LOCAL_GCC "Enable -Wshadow=local warning in GCC" ON)
|
||||
# Options to exclude parts of the FSFW from compilation.
|
||||
option(FSFW_ADD_INTERNAL_TESTS "Add internal unit tests" ON)
|
||||
option(FSFW_ADD_UNITTESTS "Add regular unittests. Requires Catch2" OFF)
|
||||
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
|
||||
option(FSFW_ADD_PUS "Compile with PUS sources" ON)
|
||||
option(FSFW_ADD_MONITORING "Compile with monitoring components" ON)
|
||||
@ -138,7 +146,7 @@ if(IPO_SUPPORTED AND FSFW_ENABLE_IPO)
|
||||
TRUE)
|
||||
endif()
|
||||
|
||||
if(FSFW_BUILD_UNITTESTS)
|
||||
if(FSFW_BUILD_TESTS)
|
||||
message(
|
||||
STATUS
|
||||
"${MSG_PREFIX} Building the FSFW unittests in addition to the static library"
|
||||
@ -161,10 +169,9 @@ if(FSFW_BUILD_UNITTESTS)
|
||||
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)
|
||||
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})
|
||||
@ -182,7 +189,10 @@ if(FSFW_BUILD_UNITTESTS)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
message(STATUS "${MSG_PREFIX} Finding and/or providing etl library with version ${FSFW_ETL_LIB_MAJOR_VERSION}")
|
||||
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)
|
||||
@ -280,16 +290,15 @@ message(
|
||||
)
|
||||
|
||||
add_subdirectory(src)
|
||||
add_subdirectory(tests)
|
||||
if(FSFW_ADD_HAL)
|
||||
add_subdirectory(hal)
|
||||
endif()
|
||||
add_subdirectory(contrib)
|
||||
if(FSFW_BUILD_TESTS)
|
||||
add_subdirectory(unittests)
|
||||
endif()
|
||||
if(FSFW_BUILD_DOCS)
|
||||
add_subdirectory(docs)
|
||||
endif()
|
||||
|
||||
if(FSFW_BUILD_UNITTESTS)
|
||||
if(FSFW_BUILD_TESTS)
|
||||
if(FSFW_TESTS_GEN_COV)
|
||||
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||
include(CodeCoverage)
|
||||
@ -351,7 +360,8 @@ if(NOT FSFW_CONFIG_PATH)
|
||||
if(NOT FSFW_BUILD_DOCS)
|
||||
message(
|
||||
WARNING
|
||||
"${MSG_PREFIX} Flight Software Framework configuration path not set")
|
||||
"${MSG_PREFIX} Flight Software Framework configuration path FSFW_CONFIG_PATH not set"
|
||||
)
|
||||
message(
|
||||
WARNING
|
||||
"${MSG_PREFIX} Setting default configuration from ${DEF_CONF_PATH} ..")
|
||||
@ -446,8 +456,8 @@ target_include_directories(
|
||||
target_compile_options(${LIB_FSFW_NAME} PRIVATE ${FSFW_WARNING_FLAGS}
|
||||
${COMPILER_FLAGS})
|
||||
|
||||
target_link_libraries(${LIB_FSFW_NAME} PRIVATE ${FSFW_ETL_LINK_TARGET}
|
||||
${FSFW_ADDITIONAL_LINK_LIBS})
|
||||
target_link_libraries(${LIB_FSFW_NAME} PRIVATE ${FSFW_ADDITIONAL_LINK_LIBS})
|
||||
target_link_libraries(${LIB_FSFW_NAME} PUBLIC ${FSFW_ETL_LINK_TARGET})
|
||||
|
||||
string(
|
||||
CONCAT
|
||||
|
15
README.md
15
README.md
@ -99,7 +99,7 @@ add and link against the FSFW library in general.
|
||||
|
||||
4. Link against the FSFW library
|
||||
|
||||
```cmake
|
||||
```sh
|
||||
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
|
||||
|
||||
```sh
|
||||
mkdir build-Unittest && cd build-Unittest
|
||||
cmake -DFSFW_BUILD_UNITTESTS=ON -DFSFW_OSAL=host -DCMAKE_BUILD_TYPE=Debug ..
|
||||
mkdir build-tests && cd build-tests
|
||||
cmake -DFSFW_BUILD_TESTS=ON -DFSFW_OSAL=host -DCMAKE_BUILD_TYPE=Debug ..
|
||||
```
|
||||
|
||||
You can also use `-DFSFW_OSAL=linux` on Linux systems.
|
||||
|
||||
Coverage data in HTML format can be generated using the `CodeCoverage`
|
||||
[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
|
||||
|
||||
```sh
|
||||
@ -175,7 +175,7 @@ cmake -DFSFW_BUILD_DOCS=ON -DFSFW_OSAL=host ..
|
||||
Then you can generate the documentation using
|
||||
|
||||
```sh
|
||||
cmake --build . -j
|
||||
cmake --build . -- Sphinx -j
|
||||
```
|
||||
|
||||
You can find the generated documentation inside the `docs/sphinx` folder inside the build
|
||||
@ -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
|
||||
`.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
|
||||
|
||||
|
@ -5,10 +5,21 @@ RUN apt-get --yes upgrade
|
||||
|
||||
#tzdata is a dependency, won't install otherwise
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
RUN apt-get --yes install gcc g++ cmake make lcov git valgrind nano iputils-ping
|
||||
RUN apt-get --yes install gcc g++ cmake make lcov git valgrind nano iputils-ping python3 pip doxygen graphviz
|
||||
|
||||
RUN python3 -m pip install sphinx breathe
|
||||
|
||||
RUN git clone https://github.com/catchorg/Catch2.git && \
|
||||
cd Catch2 && \
|
||||
git checkout v3.0.0-preview5 && \
|
||||
cmake -Bbuild -H. -DBUILD_TESTING=OFF && \
|
||||
cmake --build build/ --target install
|
||||
cd Catch2 && \
|
||||
git checkout v3.1.0 && \
|
||||
cmake -Bbuild -H. -DBUILD_TESTING=OFF && \
|
||||
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/
|
||||
|
||||
#ssh needs a valid user to work
|
||||
RUN adduser --uid 114 jenkins
|
||||
|
52
automation/Jenkinsfile
vendored
52
automation/Jenkinsfile
vendored
@ -1,9 +1,13 @@
|
||||
pipeline {
|
||||
environment {
|
||||
BUILDDIR = 'build-tests'
|
||||
BUILDDIR = 'cmake-build-tests'
|
||||
DOCDDIR = 'cmake-build-documentation'
|
||||
}
|
||||
agent {
|
||||
docker { image 'fsfw-ci:d2'}
|
||||
docker {
|
||||
image 'fsfw-ci:d5'
|
||||
args '--network host'
|
||||
}
|
||||
}
|
||||
stages {
|
||||
stage('Clean') {
|
||||
@ -14,7 +18,7 @@ pipeline {
|
||||
stage('Configure') {
|
||||
steps {
|
||||
dir(BUILDDIR) {
|
||||
sh 'cmake -DFSFW_OSAL=host -DFSFW_BUILD_UNITTESTS=ON ..'
|
||||
sh 'cmake -DFSFW_OSAL=host -DFSFW_BUILD_TESTS=ON -DFSFW_CICD_BUILD=ON ..'
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -39,5 +43,47 @@ pipeline {
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Documentation') {
|
||||
when {
|
||||
branch 'development'
|
||||
}
|
||||
steps {
|
||||
dir(DOCDDIR) {
|
||||
sh 'cmake -DFSFW_BUILD_DOCS=ON -DFSFW_OSAL=host ..'
|
||||
sh 'make Sphinx'
|
||||
sshagent(credentials: ['documentation-buildfix']) {
|
||||
sh 'ssh -o StrictHostKeyChecking=no buildfix@documentation.intra.irs.uni-stuttgart.de rm -rf /mnt/data/www/html/fsfw/development/*'
|
||||
sh 'scp -o StrictHostKeyChecking=no -r docs/sphinx/* buildfix@documentation.intra.irs.uni-stuttgart.de:/mnt/data/www/html/fsfw/development'
|
||||
}
|
||||
}
|
||||
dir(BUILDDIR) {
|
||||
sshagent(credentials: ['documentation-buildfix']) {
|
||||
sh 'ssh -o StrictHostKeyChecking=no buildfix@documentation.intra.irs.uni-stuttgart.de rm -rf /mnt/data/www/html/fsfw/coverage/development/*'
|
||||
sh 'scp -o StrictHostKeyChecking=no -r fsfw-tests_coverage/* buildfix@documentation.intra.irs.uni-stuttgart.de:/mnt/data/www/html/fsfw/coverage/development'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Master Documentation') {
|
||||
when {
|
||||
branch 'master'
|
||||
}
|
||||
steps {
|
||||
dir(DOCDDIR) {
|
||||
sh 'cmake -DFSFW_BUILD_DOCS=ON -DFSFW_OSAL=host ..'
|
||||
sh 'make Sphinx'
|
||||
sshagent(credentials: ['documentation-buildfix']) {
|
||||
sh 'ssh -o StrictHostKeyChecking=no buildfix@documentation.intra.irs.uni-stuttgart.de rm -rf /mnt/data/www/html/fsfw/master/*'
|
||||
sh 'scp -o StrictHostKeyChecking=no -r docs/sphinx/* buildfix@documentation.intra.irs.uni-stuttgart.de:/mnt/data/www/html/fsfw/master'
|
||||
}
|
||||
}
|
||||
dir(BUILDDIR) {
|
||||
sshagent(credentials: ['documentation-buildfix']) {
|
||||
sh 'ssh -o StrictHostKeyChecking=no buildfix@documentation.intra.irs.uni-stuttgart.de rm -rf /mnt/data/www/html/fsfw/coverage/master/*'
|
||||
sh 'scp -o StrictHostKeyChecking=no -r fsfw-tests_coverage/* buildfix@documentation.intra.irs.uni-stuttgart.de:/mnt/data/www/html/fsfw/coverage/master'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ FSFW to achieve that. The fsfw uses run-time type information but exceptions are
|
||||
# Failure Handling
|
||||
|
||||
Functions should return a defined `ReturnValue_t` to signal to the caller that something has
|
||||
gone wrong. Returnvalues must be unique. For this the function `HasReturnvaluesIF::makeReturnCode`
|
||||
gone wrong. Returnvalues must be unique. For this the function `returnvalue::makeCode`
|
||||
or the macro `MAKE_RETURN` can be used. The `CLASS_ID` is a unique id for that type of object.
|
||||
See `returnvalues/FwClassIds` folder. The user can add custom `CLASS_ID`s via the
|
||||
`fsfwconfig` folder.
|
||||
|
@ -144,7 +144,7 @@ ReturnValue_t GyroHandler::initializeLocalDataPool(localpool::DataPool &localDat
|
||||
new PoolEntry<uint8_t>({0}));
|
||||
|
||||
poolManager.subscribeForPeriodicPacket(gyroData.getSid(), false, 4.0, false);
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
return returnvalue::OK;
|
||||
}
|
||||
```
|
||||
|
||||
@ -154,7 +154,7 @@ in any case:
|
||||
|
||||
```cpp
|
||||
PoolReadGuard readHelper(&gyroData);
|
||||
if(readHelper.getReadResult() == HasReturnvaluesIF::RETURN_OK) {
|
||||
if(readHelper.getReadResult() == returnvalue::OK) {
|
||||
if(not gyroData.isValid()) {
|
||||
gyroData.setValidity(true, true);
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ API
|
||||
.. toctree::
|
||||
:maxdepth: 4
|
||||
|
||||
api/cfdp
|
||||
api/objectmanager
|
||||
api/task
|
||||
api/ipc
|
||||
|
8
docs/api/cfdp.rst
Normal file
8
docs/api/cfdp.rst
Normal file
@ -0,0 +1,8 @@
|
||||
CFDP API
|
||||
=================
|
||||
|
||||
``UserBase``
|
||||
-----------------
|
||||
|
||||
.. doxygenclass:: cfdp::UserBase
|
||||
:members:
|
@ -3,7 +3,7 @@
|
||||
Returnvalue API
|
||||
==================
|
||||
|
||||
.. doxygenfile:: HasReturnvaluesIF.h
|
||||
.. doxygenfile:: returnvalue.h
|
||||
|
||||
.. _fwclassids:
|
||||
|
||||
|
18
docs/conf.py
18
docs/conf.py
@ -17,12 +17,12 @@
|
||||
|
||||
# -- Project information -----------------------------------------------------
|
||||
|
||||
project = 'Flight Software Framework'
|
||||
copyright = '2021, Institute of Space Systems (IRS)'
|
||||
author = 'Institute of Space Systems (IRS)'
|
||||
project = "Flight Software Framework"
|
||||
copyright = "2021, Institute of Space Systems (IRS)"
|
||||
author = "Institute of Space Systems (IRS)"
|
||||
|
||||
# The full version, including alpha/beta/rc tags
|
||||
release = '2.0.1'
|
||||
release = "5.0.0"
|
||||
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
@ -30,17 +30,17 @@ release = '2.0.1'
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = [ "breathe" ]
|
||||
extensions = ["breathe"]
|
||||
|
||||
breathe_default_project = "fsfw"
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
templates_path = ["_templates"]
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This pattern also affects html_static_path and html_extra_path.
|
||||
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
||||
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
|
||||
|
||||
|
||||
# -- Options for HTML output -------------------------------------------------
|
||||
@ -48,9 +48,9 @@ exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
html_theme = 'alabaster'
|
||||
html_theme = "alabaster"
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = []
|
||||
html_static_path = []
|
||||
|
@ -75,11 +75,11 @@ and the respective source file with sensible default return values:
|
||||
void TestDeviceHandler::doShutDown() {}
|
||||
|
||||
ReturnValue_t TestDeviceHandler::buildNormalDeviceCommand(DeviceCommandId_t* id) {
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
ReturnValue_t TestDeviceHandler::buildTransitionDeviceCommand(DeviceCommandId_t* id) {
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
void TestDeviceHandler::fillCommandAndReplyMap() {}
|
||||
@ -87,17 +87,17 @@ and the respective source file with sensible default return values:
|
||||
ReturnValue_t TestDeviceHandler::buildCommandFromCommand(DeviceCommandId_t deviceCommand,
|
||||
const uint8_t* commandData,
|
||||
size_t commandDataLen) {
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
ReturnValue_t TestDeviceHandler::scanForReply(const uint8_t* start, size_t remainingSize,
|
||||
DeviceCommandId_t* foundId, size_t* foundLen) {
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
ReturnValue_t TestDeviceHandler::interpretDeviceReply(DeviceCommandId_t id,
|
||||
const uint8_t* packet) {
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
uint32_t TestDeviceHandler::getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo) {
|
||||
@ -106,5 +106,5 @@ and the respective source file with sensible default return values:
|
||||
|
||||
ReturnValue_t TestDeviceHandler::initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
|
||||
LocalDataPoolManager& poolManager) {
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
@ -106,7 +106,7 @@ You can use the following commands inside the ``fsfw`` folder to set up the buil
|
||||
.. code-block:: console
|
||||
|
||||
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.
|
||||
|
@ -7,18 +7,20 @@ Structure
|
||||
----------
|
||||
|
||||
The general structure is driven by the usage of interfaces provided by objects.
|
||||
The FSFW uses C++11 as baseline. The intention behind this is that this C++ Standard should be
|
||||
widely available, even with older compilers.
|
||||
The FSFW uses dynamic allocation during the initialization but provides static containers during runtime.
|
||||
This simplifies the instantiation of objects and allows the usage of some standard containers.
|
||||
Dynamic Allocation after initialization is discouraged and different solutions are provided in the
|
||||
FSFW to achieve that. The fsfw uses run-time type information but exceptions are not allowed.
|
||||
The FSFW uses C++17 as baseline.
|
||||
It also uses dynamic allocation during the initialization but provides
|
||||
static containers during runtime.
|
||||
This simplifies the instantiation of objects and allows the usage of some
|
||||
standard containers.
|
||||
Dynamic Allocation after initialization is discouraged and different solutions
|
||||
are provided in the FSFW to achieve that. The fsfw uses run-time type
|
||||
information but will not throw exceptions.
|
||||
|
||||
Failure Handling
|
||||
-----------------
|
||||
|
||||
Functions should return a defined :cpp:type:`ReturnValue_t` to signal to the caller that something has
|
||||
gone wrong. Returnvalues must be unique. For this the function :cpp:func:`HasReturnvaluesIF::makeReturnCode`
|
||||
gone wrong. Returnvalues must be unique. For this the function :cpp:func:`returnvalue::makeCode`
|
||||
or the :ref:`macro MAKE_RETURN_CODE <retvalapi>` can be used. The ``CLASS_ID`` is a unique ID for that type of object.
|
||||
See the :ref:`FSFW Class IDs file <fwclassids>`. The user can add custom ``CLASS_ID``\s via the
|
||||
``fsfwconfig`` folder.
|
||||
|
@ -150,7 +150,7 @@ with a housekeeping service command.
|
||||
new PoolEntry<uint8_t>({0}));
|
||||
|
||||
poolManager.subscribeForPeriodicPacket(gyroData.getSid(), false, 4.0, false);
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
Now, if we receive some sensor data and converted them into the right format,
|
||||
@ -160,7 +160,7 @@ in any case:
|
||||
.. code-block:: cpp
|
||||
|
||||
PoolReadGuard readHelper(&gyroData);
|
||||
if(readHelper.getReadResult() == HasReturnvaluesIF::RETURN_OK) {
|
||||
if(readHelper.getReadResult() == returnvalue::OK) {
|
||||
if(not gyroData.isValid()) {
|
||||
gyroData.setValidity(true, true);
|
||||
}
|
||||
|
@ -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 +0,0 @@
|
||||
add_subdirectory(gpio)
|
@ -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 +0,0 @@
|
||||
|
@ -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
|
||||
)
|
@ -4,6 +4,10 @@
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
// It is assumed the user has a subsystem and class ID list in some user header files.
|
||||
// #include "events/subsystemIdRanges.h"
|
||||
// #include "returnvalues/classIds.h"
|
||||
|
||||
//! Used to determine whether C++ ostreams are used which can increase
|
||||
//! the binary size significantly. If this is disabled,
|
||||
//! the C stdio functions can be used alternatively
|
||||
|
@ -4,7 +4,6 @@
|
||||
#include <fsfw/devicehandlers/DeviceHandlerBase.h>
|
||||
#include <fsfw/events/EventManager.h>
|
||||
#include <fsfw/health/HealthTable.h>
|
||||
#include <fsfw/tmtcpacket/pus/tm/TmPacketStored.h>
|
||||
#include <fsfw/tmtcservices/CommandingServiceBase.h>
|
||||
#include <fsfw/tmtcservices/PusServiceBase.h>
|
||||
#include <fsfw/internalerror/InternalErrorReporter.h>
|
||||
@ -35,19 +34,15 @@ void Factory::produceFsfwObjects(void) {
|
||||
}
|
||||
|
||||
void Factory::setStaticFrameworkObjectIds() {
|
||||
PusServiceBase::packetSource = objects::NO_OBJECT;
|
||||
PusServiceBase::packetDestination = objects::NO_OBJECT;
|
||||
PusServiceBase::PUS_DISTRIBUTOR = objects::NO_OBJECT;
|
||||
PusServiceBase::PACKET_DESTINATION = objects::NO_OBJECT;
|
||||
|
||||
CommandingServiceBase::defaultPacketSource = objects::NO_OBJECT;
|
||||
CommandingServiceBase::defaultPacketDestination = objects::NO_OBJECT;
|
||||
|
||||
VerificationReporter::messageReceiver = objects::PUS_SERVICE_1_VERIFICATION;
|
||||
|
||||
DeviceHandlerBase::powerSwitcherId = objects::NO_OBJECT;
|
||||
DeviceHandlerBase::rawDataReceiverId = objects::PUS_SERVICE_2_DEVICE_ACCESS;
|
||||
|
||||
DeviceHandlerFailureIsolation::powerConfirmationId = objects::NO_OBJECT;
|
||||
|
||||
TmPacketBase::timeStamperId = objects::NO_OBJECT;
|
||||
}
|
||||
|
||||
|
@ -11,15 +11,15 @@ ReturnValue_t pst::pollingSequenceInitDefault(
|
||||
|
||||
/* Add polling sequence table here */
|
||||
|
||||
if (thisSequence->checkSequence() == HasReturnvaluesIF::RETURN_OK) {
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
if (thisSequence->checkSequence() == returnvalue::OK) {
|
||||
return returnvalue::OK;
|
||||
}
|
||||
else {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "pst::pollingSequenceInitDefault: Sequence invalid!"
|
||||
<< std::endl;
|
||||
#endif
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
#ifndef POLLINGSEQUENCEFACTORY_H_
|
||||
#define POLLINGSEQUENCEFACTORY_H_
|
||||
|
||||
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
|
||||
#include <fsfw/returnvalues/returnvalue.h>
|
||||
|
||||
class FixedTimeslotTaskIF;
|
||||
|
||||
|
@ -5,15 +5,15 @@ fi
|
||||
|
||||
folder_list=(
|
||||
"./src"
|
||||
"./hal"
|
||||
"./tests"
|
||||
"./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
|
||||
find ./src ${file_selectors} | xargs ${cmake_fmt} -i
|
||||
find ./unittests ${file_selectors} | xargs ${cmake_fmt} -i
|
||||
else
|
||||
echo "No ${cmake_fmt} tool found, not formatting CMake files"
|
||||
fi
|
||||
|
@ -13,7 +13,7 @@ from shutil import which
|
||||
from typing import List
|
||||
|
||||
|
||||
UNITTEST_FOLDER_NAME = "build-tests"
|
||||
UNITTEST_FOLDER_NAME = "cmake-build-tests"
|
||||
DOCS_FOLDER_NAME = "build-docs"
|
||||
|
||||
|
||||
@ -48,6 +48,20 @@ def main():
|
||||
action="store_true",
|
||||
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()
|
||||
if args.all:
|
||||
@ -115,14 +129,14 @@ def handle_tests_type(args, build_dir_list: list):
|
||||
if args.create:
|
||||
if os.path.exists(UNITTEST_FOLDER_NAME):
|
||||
shutil.rmtree(UNITTEST_FOLDER_NAME)
|
||||
create_tests_build_cfg()
|
||||
create_tests_build_cfg(args)
|
||||
build_directory = UNITTEST_FOLDER_NAME
|
||||
elif len(build_dir_list) == 0:
|
||||
print(
|
||||
"No valid CMake tests build directory found. "
|
||||
"Trying to set up test build system"
|
||||
)
|
||||
create_tests_build_cfg()
|
||||
create_tests_build_cfg(args)
|
||||
build_directory = UNITTEST_FOLDER_NAME
|
||||
elif len(build_dir_list) == 1:
|
||||
build_directory = build_dir_list[0]
|
||||
@ -147,10 +161,23 @@ def handle_tests_type(args, build_dir_list: list):
|
||||
os.chdir("..")
|
||||
|
||||
|
||||
def create_tests_build_cfg():
|
||||
def create_tests_build_cfg(args):
|
||||
os.mkdir(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("..")
|
||||
|
||||
|
||||
|
@ -4,3 +4,8 @@ target_include_directories(${LIB_FSFW_NAME}
|
||||
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
add_subdirectory(fsfw)
|
||||
if(FSFW_ADD_HAL)
|
||||
add_subdirectory(fsfw_hal)
|
||||
endif()
|
||||
|
||||
add_subdirectory(fsfw_tests)
|
||||
|
@ -31,6 +31,7 @@ add_subdirectory(thermal)
|
||||
add_subdirectory(timemanager)
|
||||
add_subdirectory(tmtcpacket)
|
||||
add_subdirectory(tmtcservices)
|
||||
add_subdirectory(filesystem)
|
||||
|
||||
# Optional
|
||||
|
||||
|
@ -6,13 +6,13 @@
|
||||
ActionHelper::ActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue)
|
||||
: owner(setOwner), queueToUse(useThisQueue) {}
|
||||
|
||||
ActionHelper::~ActionHelper() {}
|
||||
ActionHelper::~ActionHelper() = default;
|
||||
|
||||
ReturnValue_t ActionHelper::handleActionMessage(CommandMessage* command) {
|
||||
if (command->getCommand() == ActionMessage::EXECUTE_ACTION) {
|
||||
ActionId_t currentAction = ActionMessage::getActionId(command);
|
||||
prepareExecution(command->getSender(), currentAction, ActionMessage::getStoreId(command));
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
return returnvalue::OK;
|
||||
} else {
|
||||
return CommandMessage::UNKNOWN_COMMAND;
|
||||
}
|
||||
@ -21,7 +21,7 @@ ReturnValue_t ActionHelper::handleActionMessage(CommandMessage* command) {
|
||||
ReturnValue_t ActionHelper::initialize(MessageQueueIF* queueToUse_) {
|
||||
ipcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::IPC_STORE);
|
||||
if (ipcStore == nullptr) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
if (queueToUse_ != nullptr) {
|
||||
setQueueToUse(queueToUse_);
|
||||
@ -35,10 +35,10 @@ ReturnValue_t ActionHelper::initialize(MessageQueueIF* queueToUse_) {
|
||||
sif::printWarning("ActionHelper::initialize: No queue set\n");
|
||||
#endif
|
||||
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
void ActionHelper::step(uint8_t step, MessageQueueId_t reportTo, ActionId_t commandId,
|
||||
@ -59,10 +59,10 @@ void ActionHelper::setQueueToUse(MessageQueueIF* queue) { queueToUse = queue; }
|
||||
|
||||
void ActionHelper::prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId,
|
||||
store_address_t dataAddress) {
|
||||
const uint8_t* dataPtr = NULL;
|
||||
const uint8_t* dataPtr = nullptr;
|
||||
size_t size = 0;
|
||||
ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
if (result != returnvalue::OK) {
|
||||
CommandMessage reply;
|
||||
ActionMessage::setStepReply(&reply, actionId, 0, result);
|
||||
queueToUse->sendMessage(commandedBy, &reply);
|
||||
@ -75,7 +75,7 @@ void ActionHelper::prepareExecution(MessageQueueId_t commandedBy, ActionId_t act
|
||||
ActionMessage::setCompletionReply(&reply, actionId, true, result);
|
||||
queueToUse->sendMessage(commandedBy, &reply);
|
||||
}
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
if (result != returnvalue::OK) {
|
||||
CommandMessage reply;
|
||||
ActionMessage::setStepReply(&reply, actionId, 0, result);
|
||||
queueToUse->sendMessage(commandedBy, &reply);
|
||||
@ -91,11 +91,11 @@ ReturnValue_t ActionHelper::reportData(MessageQueueId_t reportTo, ActionId_t rep
|
||||
size_t maxSize = data->getSerializedSize();
|
||||
if (maxSize == 0) {
|
||||
/* No error, there's simply nothing to report. */
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
return returnvalue::OK;
|
||||
}
|
||||
size_t size = 0;
|
||||
ReturnValue_t result = ipcStore->getFreeElement(&storeAddress, maxSize, &dataPtr);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
if (result != returnvalue::OK) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "ActionHelper::reportData: Getting free element from IPC store failed!"
|
||||
<< std::endl;
|
||||
@ -107,7 +107,7 @@ ReturnValue_t ActionHelper::reportData(MessageQueueId_t reportTo, ActionId_t rep
|
||||
return result;
|
||||
}
|
||||
result = data->serialize(&dataPtr, &size, maxSize, SerializeIF::Endianness::BIG);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
if (result != returnvalue::OK) {
|
||||
ipcStore->deleteData(storeAddress);
|
||||
return result;
|
||||
}
|
||||
@ -124,7 +124,7 @@ ReturnValue_t ActionHelper::reportData(MessageQueueId_t reportTo, ActionId_t rep
|
||||
result = queueToUse->sendMessage(reportTo, &reply);
|
||||
}
|
||||
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
if (result != returnvalue::OK) {
|
||||
ipcStore->deleteData(storeAddress);
|
||||
}
|
||||
return result;
|
||||
@ -137,7 +137,7 @@ ReturnValue_t ActionHelper::reportData(MessageQueueId_t reportTo, ActionId_t rep
|
||||
CommandMessage reply;
|
||||
store_address_t storeAddress;
|
||||
ReturnValue_t result = ipcStore->addData(&storeAddress, data, dataSize);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
if (result != returnvalue::OK) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "ActionHelper::reportData: Adding data to IPC store failed!" << std::endl;
|
||||
#else
|
||||
@ -158,7 +158,7 @@ ReturnValue_t ActionHelper::reportData(MessageQueueId_t reportTo, ActionId_t rep
|
||||
result = queueToUse->sendMessage(reportTo, &reply);
|
||||
}
|
||||
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
if (result != returnvalue::OK) {
|
||||
ipcStore->deleteData(storeAddress);
|
||||
}
|
||||
return result;
|
||||
|
@ -1,9 +1,9 @@
|
||||
#ifndef FSFW_ACTION_ACTIONHELPER_H_
|
||||
#define FSFW_ACTION_ACTIONHELPER_H_
|
||||
|
||||
#include "../ipc/MessageQueueIF.h"
|
||||
#include "../serialize/SerializeIF.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
|
||||
*
|
||||
@ -36,7 +36,7 @@ class ActionHelper {
|
||||
* send to the sender of the message automatically.
|
||||
*
|
||||
* @param command Pointer to a command message received by the owner
|
||||
* @return HasReturnvaluesIF::RETURN_OK if the message is a action message,
|
||||
* @return returnvalue::OK if the message is a action message,
|
||||
* CommandMessage::UNKNOW_COMMAND if this message ID is unkown
|
||||
*/
|
||||
ReturnValue_t handleActionMessage(CommandMessage* command);
|
||||
@ -45,7 +45,7 @@ class ActionHelper {
|
||||
* helper function
|
||||
* @param queueToUse_ Pointer to the messageQueue to be used, optional
|
||||
* if queue was set in constructor
|
||||
* @return Returns RETURN_OK if successful
|
||||
* @return Returns returnvalue::OK if successful
|
||||
*/
|
||||
ReturnValue_t initialize(MessageQueueIF* queueToUse_ = nullptr);
|
||||
/**
|
||||
@ -58,7 +58,7 @@ class ActionHelper {
|
||||
* @param result Result of the execution
|
||||
*/
|
||||
void step(uint8_t step, MessageQueueId_t reportTo, ActionId_t commandId,
|
||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK);
|
||||
ReturnValue_t result = returnvalue::OK);
|
||||
/**
|
||||
* Function to be called by the owner to send a action completion message
|
||||
* @param success Specify whether action was completed successfully or not.
|
||||
@ -67,7 +67,7 @@ class ActionHelper {
|
||||
* @param result Result of the execution
|
||||
*/
|
||||
void finish(bool success, MessageQueueId_t reportTo, ActionId_t commandId,
|
||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK);
|
||||
ReturnValue_t result = returnvalue::OK);
|
||||
/**
|
||||
* Function to be called by the owner if an action does report data.
|
||||
* Takes a SerializeIF* pointer and serializes it into the IPC store.
|
||||
@ -75,7 +75,7 @@ class ActionHelper {
|
||||
* message to
|
||||
* @param replyId ID of the executed command
|
||||
* @param data Pointer to the data
|
||||
* @return Returns RETURN_OK if successful, otherwise failure code
|
||||
* @return Returns returnvalue::OK if successful, otherwise failure code
|
||||
*/
|
||||
ReturnValue_t reportData(MessageQueueId_t reportTo, ActionId_t replyId, SerializeIF* data,
|
||||
bool hideSender = false);
|
||||
@ -86,7 +86,7 @@ class ActionHelper {
|
||||
* message to
|
||||
* @param replyId ID of the executed command
|
||||
* @param data Pointer to the data
|
||||
* @return Returns RETURN_OK if successful, otherwise failure code
|
||||
* @return Returns returnvalue::OK if successful, otherwise failure code
|
||||
*/
|
||||
ReturnValue_t reportData(MessageQueueId_t reportTo, ActionId_t replyId, const uint8_t* data,
|
||||
size_t dataSize, bool hideSender = false);
|
||||
|
@ -2,9 +2,9 @@
|
||||
#include "fsfw/objectmanager/ObjectManager.h"
|
||||
#include "fsfw/storagemanager/StorageManagerIF.h"
|
||||
|
||||
ActionMessage::ActionMessage() {}
|
||||
ActionMessage::ActionMessage() = default;
|
||||
|
||||
ActionMessage::~ActionMessage() {}
|
||||
ActionMessage::~ActionMessage() = default;
|
||||
|
||||
void ActionMessage::setCommand(CommandMessage* message, ActionId_t fid,
|
||||
store_address_t parameters) {
|
||||
@ -25,7 +25,7 @@ store_address_t ActionMessage::getStoreId(const CommandMessage* message) {
|
||||
|
||||
void ActionMessage::setStepReply(CommandMessage* message, ActionId_t fid, uint8_t step,
|
||||
ReturnValue_t result) {
|
||||
if (result == HasReturnvaluesIF::RETURN_OK) {
|
||||
if (result == returnvalue::OK) {
|
||||
message->setCommand(STEP_SUCCESS);
|
||||
} else {
|
||||
message->setCommand(STEP_FAILED);
|
||||
@ -64,9 +64,8 @@ void ActionMessage::clear(CommandMessage* message) {
|
||||
switch (message->getCommand()) {
|
||||
case EXECUTE_ACTION:
|
||||
case DATA_REPLY: {
|
||||
StorageManagerIF* ipcStore =
|
||||
ObjectManager::instance()->get<StorageManagerIF>(objects::IPC_STORE);
|
||||
if (ipcStore != NULL) {
|
||||
auto* ipcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::IPC_STORE);
|
||||
if (ipcStore != nullptr) {
|
||||
ipcStore->deleteData(getStoreId(message));
|
||||
}
|
||||
break;
|
||||
|
@ -33,12 +33,12 @@ class ActionMessage {
|
||||
static store_address_t getStoreId(const CommandMessage* message);
|
||||
|
||||
static void setStepReply(CommandMessage* message, ActionId_t fid, uint8_t step,
|
||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK);
|
||||
ReturnValue_t result = returnvalue::OK);
|
||||
static uint8_t getStep(const CommandMessage* message);
|
||||
static ReturnValue_t getReturnCode(const CommandMessage* message);
|
||||
static void setDataReply(CommandMessage* message, ActionId_t actionId, store_address_t data);
|
||||
static void setCompletionReply(CommandMessage* message, ActionId_t fid, bool success,
|
||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK);
|
||||
ReturnValue_t result = returnvalue::OK);
|
||||
|
||||
static void clear(CommandMessage* message);
|
||||
};
|
||||
|
@ -2,26 +2,26 @@
|
||||
#include "fsfw/objectmanager/ObjectManager.h"
|
||||
|
||||
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,
|
||||
SerializeIF *data) {
|
||||
HasActionsIF *receiver = ObjectManager::instance()->get<HasActionsIF>(commandTo);
|
||||
if (receiver == NULL) {
|
||||
auto *receiver = ObjectManager::instance()->get<HasActionsIF>(commandTo);
|
||||
if (receiver == nullptr) {
|
||||
return CommandsActionsIF::OBJECT_HAS_NO_FUNCTIONS;
|
||||
}
|
||||
store_address_t storeId;
|
||||
uint8_t *storePointer;
|
||||
size_t maxSize = data->getSerializedSize();
|
||||
ReturnValue_t result = ipcStore->getFreeElement(&storeId, maxSize, &storePointer);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
size_t size = 0;
|
||||
result = data->serialize(&storePointer, &size, maxSize, SerializeIF::Endianness::BIG);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
return sendCommand(receiver->getCommandQueue(), actionId, storeId);
|
||||
@ -29,16 +29,13 @@ ReturnValue_t CommandActionHelper::commandAction(object_id_t commandTo, ActionId
|
||||
|
||||
ReturnValue_t CommandActionHelper::commandAction(object_id_t commandTo, ActionId_t actionId,
|
||||
const uint8_t *data, uint32_t size) {
|
||||
// if (commandCount != 0) {
|
||||
// return CommandsFunctionsIF::ALREADY_COMMANDING;
|
||||
// }
|
||||
HasActionsIF *receiver = ObjectManager::instance()->get<HasActionsIF>(commandTo);
|
||||
if (receiver == NULL) {
|
||||
auto *receiver = ObjectManager::instance()->get<HasActionsIF>(commandTo);
|
||||
if (receiver == nullptr) {
|
||||
return CommandsActionsIF::OBJECT_HAS_NO_FUNCTIONS;
|
||||
}
|
||||
store_address_t storeId;
|
||||
ReturnValue_t result = ipcStore->addData(&storeId, data, size);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
return sendCommand(receiver->getCommandQueue(), actionId, storeId);
|
||||
@ -49,7 +46,7 @@ ReturnValue_t CommandActionHelper::sendCommand(MessageQueueId_t queueId, ActionI
|
||||
CommandMessage command;
|
||||
ActionMessage::setCommand(&command, actionId, storeId);
|
||||
ReturnValue_t result = queueToUse->sendMessage(queueId, &command);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
if (result != returnvalue::OK) {
|
||||
ipcStore->deleteData(storeId);
|
||||
}
|
||||
lastTarget = queueId;
|
||||
@ -59,55 +56,55 @@ ReturnValue_t CommandActionHelper::sendCommand(MessageQueueId_t queueId, ActionI
|
||||
|
||||
ReturnValue_t CommandActionHelper::initialize() {
|
||||
ipcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::IPC_STORE);
|
||||
if (ipcStore == NULL) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
if (ipcStore == nullptr) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
|
||||
queueToUse = owner->getCommandQueuePtr();
|
||||
if (queueToUse == NULL) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
if (queueToUse == nullptr) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
ReturnValue_t CommandActionHelper::handleReply(CommandMessage *reply) {
|
||||
if (reply->getSender() != lastTarget) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
switch (reply->getCommand()) {
|
||||
case ActionMessage::COMPLETION_SUCCESS:
|
||||
commandCount--;
|
||||
owner->completionSuccessfulReceived(ActionMessage::getActionId(reply));
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
return returnvalue::OK;
|
||||
case ActionMessage::COMPLETION_FAILED:
|
||||
commandCount--;
|
||||
owner->completionFailedReceived(ActionMessage::getActionId(reply),
|
||||
ActionMessage::getReturnCode(reply));
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
return returnvalue::OK;
|
||||
case ActionMessage::STEP_SUCCESS:
|
||||
owner->stepSuccessfulReceived(ActionMessage::getActionId(reply),
|
||||
ActionMessage::getStep(reply));
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
return returnvalue::OK;
|
||||
case ActionMessage::STEP_FAILED:
|
||||
commandCount--;
|
||||
owner->stepFailedReceived(ActionMessage::getActionId(reply), ActionMessage::getStep(reply),
|
||||
ActionMessage::getReturnCode(reply));
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
return returnvalue::OK;
|
||||
case ActionMessage::DATA_REPLY:
|
||||
extractDataForOwner(ActionMessage::getActionId(reply), ActionMessage::getStoreId(reply));
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
return returnvalue::OK;
|
||||
default:
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t CommandActionHelper::getCommandCount() const { return commandCount; }
|
||||
|
||||
void CommandActionHelper::extractDataForOwner(ActionId_t actionId, store_address_t storeId) {
|
||||
const uint8_t *data = NULL;
|
||||
const uint8_t *data = nullptr;
|
||||
size_t size = 0;
|
||||
ReturnValue_t result = ipcStore->getData(storeId, &data, &size);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
if (result != returnvalue::OK) {
|
||||
return;
|
||||
}
|
||||
owner->dataReceived(actionId, data, size);
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include "ActionMessage.h"
|
||||
#include "fsfw/ipc/MessageQueueIF.h"
|
||||
#include "fsfw/objectmanager/ObjectManagerIF.h"
|
||||
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
|
||||
#include "fsfw/returnvalues/returnvalue.h"
|
||||
#include "fsfw/serialize/SerializeIF.h"
|
||||
#include "fsfw/storagemanager/StorageManagerIF.h"
|
||||
|
||||
@ -14,14 +14,14 @@ class CommandActionHelper {
|
||||
friend class CommandsActionsIF;
|
||||
|
||||
public:
|
||||
CommandActionHelper(CommandsActionsIF* owner);
|
||||
explicit CommandActionHelper(CommandsActionsIF* owner);
|
||||
virtual ~CommandActionHelper();
|
||||
ReturnValue_t commandAction(object_id_t commandTo, ActionId_t actionId,
|
||||
const uint8_t* data = nullptr, uint32_t size = 0);
|
||||
ReturnValue_t commandAction(object_id_t commandTo, ActionId_t actionId, SerializeIF* data);
|
||||
ReturnValue_t initialize();
|
||||
ReturnValue_t handleReply(CommandMessage* reply);
|
||||
uint8_t getCommandCount() const;
|
||||
[[nodiscard]] uint8_t getCommandCount() const;
|
||||
|
||||
private:
|
||||
CommandsActionsIF* owner;
|
||||
|
@ -1,9 +1,9 @@
|
||||
#ifndef FSFW_ACTION_COMMANDSACTIONSIF_H_
|
||||
#define FSFW_ACTION_COMMANDSACTIONSIF_H_
|
||||
|
||||
#include "../ipc/MessageQueueIF.h"
|
||||
#include "../returnvalues/HasReturnvaluesIF.h"
|
||||
#include "CommandActionHelper.h"
|
||||
#include "fsfw/ipc/MessageQueueIF.h"
|
||||
#include "fsfw/returnvalues/returnvalue.h"
|
||||
|
||||
/**
|
||||
* 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 ReturnValue_t OBJECT_HAS_NO_FUNCTIONS = MAKE_RETURN_CODE(1);
|
||||
static const ReturnValue_t ALREADY_COMMANDING = MAKE_RETURN_CODE(2);
|
||||
virtual ~CommandsActionsIF() {}
|
||||
virtual ~CommandsActionsIF() = default;
|
||||
virtual MessageQueueIF* getCommandQueuePtr() = 0;
|
||||
|
||||
protected:
|
||||
|
@ -1,11 +1,11 @@
|
||||
#ifndef FSFW_ACTION_HASACTIONSIF_H_
|
||||
#define FSFW_ACTION_HASACTIONSIF_H_
|
||||
|
||||
#include "../ipc/MessageQueueIF.h"
|
||||
#include "../returnvalues/HasReturnvaluesIF.h"
|
||||
#include "ActionHelper.h"
|
||||
#include "ActionMessage.h"
|
||||
#include "SimpleActionHelper.h"
|
||||
#include "fsfw/ipc/MessageQueueIF.h"
|
||||
#include "fsfw/returnvalues/returnvalue.h"
|
||||
|
||||
/**
|
||||
* @brief
|
||||
@ -40,12 +40,12 @@ class HasActionsIF {
|
||||
static const ReturnValue_t INVALID_PARAMETERS = MAKE_RETURN_CODE(2);
|
||||
static const ReturnValue_t EXECUTION_FINISHED = MAKE_RETURN_CODE(3);
|
||||
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
|
||||
* @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.
|
||||
* The ActionHelpers will execute this function and behave differently
|
||||
@ -53,7 +53,7 @@ class HasActionsIF {
|
||||
*
|
||||
* @return
|
||||
* -@c EXECUTION_FINISHED Finish reply will be generated
|
||||
* -@c Not RETURN_OK Step failure reply will be generated
|
||||
* -@c Not returnvalue::OK Step failure reply will be generated
|
||||
*/
|
||||
virtual ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
|
||||
const uint8_t* data, size_t size) = 0;
|
||||
|
@ -3,13 +3,13 @@
|
||||
SimpleActionHelper::SimpleActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue)
|
||||
: ActionHelper(setOwner, useThisQueue), isExecuting(false) {}
|
||||
|
||||
SimpleActionHelper::~SimpleActionHelper() {}
|
||||
SimpleActionHelper::~SimpleActionHelper() = default;
|
||||
|
||||
void SimpleActionHelper::step(ReturnValue_t result) {
|
||||
// STEP_OFFESET is subtracted to compensate for adding offset in base
|
||||
// method, which is not necessary here.
|
||||
ActionHelper::step(stepCount - STEP_OFFSET, lastCommander, lastAction, result);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
if (result != returnvalue::OK) {
|
||||
resetHelper();
|
||||
}
|
||||
}
|
||||
@ -38,10 +38,10 @@ void SimpleActionHelper::prepareExecution(MessageQueueId_t commandedBy, ActionId
|
||||
ActionMessage::setStepReply(&reply, actionId, 0, HasActionsIF::IS_BUSY);
|
||||
queueToUse->sendMessage(commandedBy, &reply);
|
||||
}
|
||||
const uint8_t* dataPtr = NULL;
|
||||
const uint8_t* dataPtr = nullptr;
|
||||
size_t size = 0;
|
||||
ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
if (result != returnvalue::OK) {
|
||||
ActionMessage::setStepReply(&reply, actionId, 0, result);
|
||||
queueToUse->sendMessage(commandedBy, &reply);
|
||||
return;
|
||||
@ -51,12 +51,12 @@ void SimpleActionHelper::prepareExecution(MessageQueueId_t commandedBy, ActionId
|
||||
result = owner->executeAction(actionId, commandedBy, dataPtr, size);
|
||||
ipcStore->deleteData(dataAddress);
|
||||
switch (result) {
|
||||
case HasReturnvaluesIF::RETURN_OK:
|
||||
case returnvalue::OK:
|
||||
isExecuting = true;
|
||||
stepCount++;
|
||||
break;
|
||||
case HasActionsIF::EXECUTION_FINISHED:
|
||||
ActionMessage::setCompletionReply(&reply, actionId, true, HasReturnvaluesIF::RETURN_OK);
|
||||
ActionMessage::setCompletionReply(&reply, actionId, true, returnvalue::OK);
|
||||
queueToUse->sendMessage(commandedBy, &reply);
|
||||
break;
|
||||
default:
|
||||
|
@ -11,15 +11,15 @@
|
||||
class SimpleActionHelper : public ActionHelper {
|
||||
public:
|
||||
SimpleActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue);
|
||||
virtual ~SimpleActionHelper();
|
||||
void step(ReturnValue_t result = HasReturnvaluesIF::RETURN_OK);
|
||||
void finish(ReturnValue_t result = HasReturnvaluesIF::RETURN_OK);
|
||||
~SimpleActionHelper() override;
|
||||
void step(ReturnValue_t result = returnvalue::OK);
|
||||
void finish(ReturnValue_t result = returnvalue::OK);
|
||||
ReturnValue_t reportData(SerializeIF* data);
|
||||
|
||||
protected:
|
||||
void prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId,
|
||||
store_address_t dataAddress);
|
||||
virtual void resetHelper();
|
||||
store_address_t dataAddress) override;
|
||||
void resetHelper() override;
|
||||
|
||||
private:
|
||||
bool isExecuting;
|
||||
@ -28,4 +28,4 @@ class SimpleActionHelper : public ActionHelper {
|
||||
uint8_t stepCount = 0;
|
||||
};
|
||||
|
||||
#endif /* SIMPLEACTIONHELPER_H_ */
|
||||
#endif /* FSFW_ACTION_SIMPLEACTIONHELPER_H_ */
|
||||
|
13
src/fsfw/cfdp.h
Normal file
13
src/fsfw/cfdp.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef FSFW_CFDP_H
|
||||
#define FSFW_CFDP_H
|
||||
|
||||
#include "cfdp/definitions.h"
|
||||
#include "cfdp/handler/CfdpHandler.h"
|
||||
#include "cfdp/handler/DestHandler.h"
|
||||
#include "cfdp/handler/FaultHandlerBase.h"
|
||||
#include "cfdp/helpers.h"
|
||||
#include "cfdp/tlv/Lv.h"
|
||||
#include "cfdp/tlv/StringLv.h"
|
||||
#include "cfdp/tlv/Tlv.h"
|
||||
|
||||
#endif // FSFW_CFDP_H
|
@ -1,59 +0,0 @@
|
||||
#include "fsfw/cfdp/CFDPHandler.h"
|
||||
|
||||
#include "fsfw/cfdp/CFDPMessage.h"
|
||||
#include "fsfw/ipc/CommandMessage.h"
|
||||
#include "fsfw/ipc/QueueFactory.h"
|
||||
#include "fsfw/objectmanager/ObjectManager.h"
|
||||
#include "fsfw/storagemanager/storeAddress.h"
|
||||
#include "fsfw/tmtcservices/AcceptsTelemetryIF.h"
|
||||
|
||||
object_id_t CFDPHandler::packetSource = 0;
|
||||
object_id_t CFDPHandler::packetDestination = 0;
|
||||
|
||||
CFDPHandler::CFDPHandler(object_id_t setObjectId, CFDPDistributor* dist)
|
||||
: SystemObject(setObjectId) {
|
||||
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
|
||||
requestQueue = QueueFactory::instance()->createMessageQueue(
|
||||
CFDP_HANDLER_MAX_RECEPTION, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||
distributor = dist;
|
||||
}
|
||||
|
||||
CFDPHandler::~CFDPHandler() {}
|
||||
|
||||
ReturnValue_t CFDPHandler::initialize() {
|
||||
ReturnValue_t result = SystemObject::initialize();
|
||||
if (result != RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
this->distributor->registerHandler(this);
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t CFDPHandler::handleRequest(store_address_t storeId) {
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::debug << "CFDPHandler::handleRequest" << std::endl;
|
||||
#else
|
||||
sif::printDebug("CFDPHandler::handleRequest\n");
|
||||
#endif /* !FSFW_CPP_OSTREAM_ENABLED == 1 */
|
||||
#endif
|
||||
|
||||
// TODO read out packet from store using storeId
|
||||
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t CFDPHandler::performOperation(uint8_t opCode) {
|
||||
ReturnValue_t status = RETURN_OK;
|
||||
CommandMessage currentMessage;
|
||||
for (status = this->requestQueue->receiveMessage(¤tMessage); status == RETURN_OK;
|
||||
status = this->requestQueue->receiveMessage(¤tMessage)) {
|
||||
store_address_t storeId = CFDPMessage::getStoreId(¤tMessage);
|
||||
this->handleRequest(storeId);
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
uint16_t CFDPHandler::getIdentifier() { return 0; }
|
||||
|
||||
MessageQueueId_t CFDPHandler::getRequestQueue() { return this->requestQueue->getId(); }
|
@ -1,63 +0,0 @@
|
||||
#ifndef FSFW_CFDP_CFDPHANDLER_H_
|
||||
#define FSFW_CFDP_CFDPHANDLER_H_
|
||||
|
||||
#include "fsfw/ipc/MessageQueueIF.h"
|
||||
#include "fsfw/objectmanager/SystemObject.h"
|
||||
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
|
||||
#include "fsfw/tasks/ExecutableObjectIF.h"
|
||||
#include "fsfw/tcdistribution/CFDPDistributor.h"
|
||||
#include "fsfw/tmtcservices/AcceptsTelecommandsIF.h"
|
||||
|
||||
namespace Factory {
|
||||
void setStaticFrameworkObjectIds();
|
||||
}
|
||||
|
||||
class CFDPHandler : public ExecutableObjectIF,
|
||||
public AcceptsTelecommandsIF,
|
||||
public SystemObject,
|
||||
public HasReturnvaluesIF {
|
||||
friend void(Factory::setStaticFrameworkObjectIds)();
|
||||
|
||||
public:
|
||||
CFDPHandler(object_id_t setObjectId, CFDPDistributor* distributor);
|
||||
/**
|
||||
* The destructor is empty.
|
||||
*/
|
||||
virtual ~CFDPHandler();
|
||||
|
||||
virtual ReturnValue_t handleRequest(store_address_t storeId);
|
||||
|
||||
virtual ReturnValue_t initialize() override;
|
||||
virtual uint16_t getIdentifier() override;
|
||||
MessageQueueId_t getRequestQueue() override;
|
||||
ReturnValue_t performOperation(uint8_t opCode) override;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* This is a complete instance of the telecommand reception queue
|
||||
* of the class. It is initialized on construction of the class.
|
||||
*/
|
||||
MessageQueueIF* requestQueue = nullptr;
|
||||
|
||||
CFDPDistributor* distributor = nullptr;
|
||||
|
||||
/**
|
||||
* The current CFDP packet to be processed.
|
||||
* It is deleted after handleRequest was executed.
|
||||
*/
|
||||
CFDPPacketStored currentPacket;
|
||||
|
||||
static object_id_t packetSource;
|
||||
|
||||
static object_id_t packetDestination;
|
||||
|
||||
private:
|
||||
/**
|
||||
* This constant sets the maximum number of packets accepted per call.
|
||||
* Remember that one packet must be completely handled in one
|
||||
* #handleRequest call.
|
||||
*/
|
||||
static const uint8_t CFDP_HANDLER_MAX_RECEPTION = 100;
|
||||
};
|
||||
|
||||
#endif /* FSFW_CFDP_CFDPHANDLER_H_ */
|
@ -1,17 +0,0 @@
|
||||
#include "CFDPMessage.h"
|
||||
|
||||
CFDPMessage::CFDPMessage() {}
|
||||
|
||||
CFDPMessage::~CFDPMessage() {}
|
||||
|
||||
void CFDPMessage::setCommand(CommandMessage *message, store_address_t cfdpPacket) {
|
||||
message->setParameter(cfdpPacket.raw);
|
||||
}
|
||||
|
||||
store_address_t CFDPMessage::getStoreId(const CommandMessage *message) {
|
||||
store_address_t storeAddressCFDPPacket;
|
||||
storeAddressCFDPPacket = message->getParameter();
|
||||
return storeAddressCFDPPacket;
|
||||
}
|
||||
|
||||
void CFDPMessage::clear(CommandMessage *message) {}
|
@ -1,4 +1,6 @@
|
||||
target_sources(${LIB_FSFW_NAME} PRIVATE CFDPHandler.cpp CFDPMessage.cpp)
|
||||
target_sources(${LIB_FSFW_NAME} PRIVATE CfdpMessage.cpp CfdpDistributor.cpp
|
||||
VarLenFields.cpp helpers.cpp)
|
||||
|
||||
add_subdirectory(pdu)
|
||||
add_subdirectory(tlv)
|
||||
add_subdirectory(handler)
|
||||
|
55
src/fsfw/cfdp/CfdpDistributor.cpp
Normal file
55
src/fsfw/cfdp/CfdpDistributor.cpp
Normal file
@ -0,0 +1,55 @@
|
||||
#include "CfdpDistributor.h"
|
||||
|
||||
#include "fsfw/tcdistribution/definitions.h"
|
||||
|
||||
CfdpDistributor::CfdpDistributor(CfdpDistribCfg cfg)
|
||||
: TcDistributorBase(cfg.objectId, cfg.tcQueue), cfg(cfg) {}
|
||||
|
||||
ReturnValue_t CfdpDistributor::registerTcDestination(const cfdp::EntityId& address,
|
||||
AcceptsTelecommandsIF& tcDest) {
|
||||
for (const auto& dest : tcDestinations) {
|
||||
if (dest.id == address) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
}
|
||||
tcDestinations.emplace_back(address, tcDest.getName(), tcDest.getRequestQueue());
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
ReturnValue_t CfdpDistributor::selectDestination(MessageQueueId_t& destId) {
|
||||
auto accessorPair = cfg.tcStore.getData(currentMessage.getStorageId());
|
||||
if (accessorPair.first != returnvalue::OK) {
|
||||
return accessorPair.first;
|
||||
}
|
||||
ReturnValue_t result =
|
||||
pduReader.setReadOnlyData(accessorPair.second.data(), accessorPair.second.size());
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
result = pduReader.parseData();
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
cfdp::EntityId foundId;
|
||||
pduReader.getDestId(foundId);
|
||||
bool destFound = false;
|
||||
for (const auto& dest : tcDestinations) {
|
||||
if (dest.id == foundId) {
|
||||
destId = dest.queueId;
|
||||
destFound = true;
|
||||
}
|
||||
}
|
||||
if (not destFound) {
|
||||
// TODO: Warning and event?
|
||||
return tmtcdistrib::NO_DESTINATION_FOUND;
|
||||
}
|
||||
// Packet was forwarded successfully, so do not delete it.
|
||||
accessorPair.second.release();
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
const char* CfdpDistributor::getName() const { return "CFDP Distributor"; }
|
||||
|
||||
uint32_t CfdpDistributor::getIdentifier() const { return 0; }
|
||||
|
||||
MessageQueueId_t CfdpDistributor::getRequestQueue() const { return tcQueue->getId(); }
|
76
src/fsfw/cfdp/CfdpDistributor.h
Normal file
76
src/fsfw/cfdp/CfdpDistributor.h
Normal file
@ -0,0 +1,76 @@
|
||||
#ifndef FSFW_TCDISTRIBUTION_CFDPDISTRIBUTOR_H_
|
||||
#define FSFW_TCDISTRIBUTION_CFDPDISTRIBUTOR_H_
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "fsfw/cfdp/pdu/PduHeaderReader.h"
|
||||
#include "fsfw/returnvalues/returnvalue.h"
|
||||
#include "fsfw/tcdistribution/CfdpPacketChecker.h"
|
||||
#include "fsfw/tcdistribution/TcDistributorBase.h"
|
||||
#include "fsfw/tmtcpacket/cfdp/CfdpPacketStored.h"
|
||||
#include "fsfw/tmtcservices/AcceptsTelecommandsIF.h"
|
||||
#include "fsfw/tmtcservices/VerificationReporter.h"
|
||||
|
||||
struct CfdpDistribCfg {
|
||||
CfdpDistribCfg(object_id_t objectId, StorageManagerIF& tcStore, MessageQueueIF* tcQueue)
|
||||
: objectId(objectId), tcStore(tcStore), tcQueue(tcQueue) {}
|
||||
|
||||
object_id_t objectId;
|
||||
StorageManagerIF& tcStore;
|
||||
MessageQueueIF* tcQueue;
|
||||
};
|
||||
|
||||
/**
|
||||
* This will be the primary component to perform PDU forwading procedures. This includes forwarding
|
||||
* CFDP TC packets to registered source or destination handlers, and forwarding all telemetry
|
||||
* generated by them to registered TM sinks.
|
||||
* @ingroup tc_distribution
|
||||
*/
|
||||
class CfdpDistributor : public TcDistributorBase, public AcceptsTelecommandsIF {
|
||||
public:
|
||||
/**
|
||||
* The ctor passes @c set_apid to the checker class and calls the
|
||||
* TcDistribution ctor with a certain object id.
|
||||
* @param setApid The APID of this receiving Application.
|
||||
* @param setObjectId Object ID of the distributor itself
|
||||
* @param setPacketSource Object ID of the source of TC packets.
|
||||
* Must implement CcsdsDistributorIF.
|
||||
*/
|
||||
explicit CfdpDistributor(CfdpDistribCfg cfg);
|
||||
|
||||
[[nodiscard]] const char* getName() const override;
|
||||
[[nodiscard]] uint32_t getIdentifier() const override;
|
||||
[[nodiscard]] MessageQueueId_t getRequestQueue() const override;
|
||||
|
||||
/**
|
||||
* Register a new CFDP entity which can receive PDUs.
|
||||
* @param address
|
||||
* @param tcDest
|
||||
* @return
|
||||
* - @c RETURN_FAILED: Entry already exists for the given address
|
||||
*/
|
||||
ReturnValue_t registerTcDestination(const cfdp::EntityId& address, AcceptsTelecommandsIF& tcDest);
|
||||
|
||||
protected:
|
||||
struct EntityInfo {
|
||||
EntityInfo(cfdp::EntityId id, const char* name, MessageQueueId_t queueId)
|
||||
: id(std::move(id)), name(name), queueId(queueId) {}
|
||||
cfdp::EntityId id;
|
||||
const char* name;
|
||||
MessageQueueId_t queueId;
|
||||
};
|
||||
PduHeaderReader pduReader;
|
||||
ReturnValue_t lastTcError = returnvalue::OK;
|
||||
ReturnValue_t lastTmError = returnvalue::OK;
|
||||
// I don't think a regular OBSW will have more than 1 or 2 of these destinations, so I think
|
||||
// it is okay to accept the overhead here
|
||||
std::vector<EntityInfo> tcDestinations;
|
||||
CfdpDistribCfg cfg;
|
||||
|
||||
ReturnValue_t selectDestination(MessageQueueId_t& destId) override;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
#endif /* FSFW_TCDISTRIBUTION_CFDPDISTRIBUTOR_H_ */
|
17
src/fsfw/cfdp/CfdpMessage.cpp
Normal file
17
src/fsfw/cfdp/CfdpMessage.cpp
Normal file
@ -0,0 +1,17 @@
|
||||
#include "CfdpMessage.h"
|
||||
|
||||
CfdpMessage::CfdpMessage() = default;
|
||||
|
||||
CfdpMessage::~CfdpMessage() = default;
|
||||
|
||||
void CfdpMessage::setCommand(CommandMessage *message, store_address_t cfdpPacket) {
|
||||
message->setParameter(cfdpPacket.raw);
|
||||
}
|
||||
|
||||
store_address_t CfdpMessage::getStoreId(const CommandMessage *message) {
|
||||
store_address_t storeId;
|
||||
storeId = static_cast<store_address_t>(message->getParameter());
|
||||
return storeId;
|
||||
}
|
||||
|
||||
void CfdpMessage::clear(CommandMessage *message) {}
|
@ -5,14 +5,14 @@
|
||||
#include "fsfw/objectmanager/ObjectManagerIF.h"
|
||||
#include "fsfw/storagemanager/StorageManagerIF.h"
|
||||
|
||||
class CFDPMessage {
|
||||
class CfdpMessage {
|
||||
private:
|
||||
CFDPMessage();
|
||||
CfdpMessage();
|
||||
|
||||
public:
|
||||
static const uint8_t MESSAGE_ID = messagetypes::CFDP;
|
||||
|
||||
virtual ~CFDPMessage();
|
||||
virtual ~CfdpMessage();
|
||||
static void setCommand(CommandMessage* message, store_address_t cfdpPacket);
|
||||
|
||||
static store_address_t getStoreId(const CommandMessage* message);
|
@ -1,5 +1,7 @@
|
||||
#ifndef FSFW_SRC_FSFW_CFDP_FILESIZE_H_
|
||||
#define FSFW_SRC_FSFW_CFDP_FILESIZE_H_
|
||||
#ifndef FSFW_CFDP_FILESIZE_H_
|
||||
#define FSFW_CFDP_FILESIZE_H_
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "fsfw/serialize/SerializeAdapter.h"
|
||||
#include "fsfw/serialize/SerializeIF.h"
|
||||
@ -8,9 +10,11 @@ namespace cfdp {
|
||||
|
||||
struct FileSize : public SerializeIF {
|
||||
public:
|
||||
FileSize() : largeFile(false){};
|
||||
FileSize() = default;
|
||||
|
||||
FileSize(uint64_t fileSize, bool isLarge = false) { setFileSize(fileSize, isLarge); };
|
||||
explicit FileSize(uint64_t fileSize, bool isLarge = false) { setFileSize(fileSize, isLarge); };
|
||||
|
||||
[[nodiscard]] uint64_t value() const { return fileSize; }
|
||||
|
||||
ReturnValue_t serialize(bool isLarge, uint8_t **buffer, size_t *size, size_t maxSize,
|
||||
Endianness streamEndianness) {
|
||||
@ -27,7 +31,7 @@ struct FileSize : public SerializeIF {
|
||||
return SerializeAdapter::serialize(&fileSize, buffer, size, maxSize, streamEndianness);
|
||||
}
|
||||
|
||||
size_t getSerializedSize() const override {
|
||||
[[nodiscard]] size_t getSerializedSize() const override {
|
||||
if (largeFile) {
|
||||
return 8;
|
||||
} else {
|
||||
@ -43,27 +47,29 @@ struct FileSize : public SerializeIF {
|
||||
uint32_t sizeTmp = 0;
|
||||
ReturnValue_t result =
|
||||
SerializeAdapter::deSerialize(&sizeTmp, buffer, size, streamEndianness);
|
||||
if (result == HasReturnvaluesIF::RETURN_OK) {
|
||||
if (result == returnvalue::OK) {
|
||||
fileSize = sizeTmp;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t setFileSize(uint64_t fileSize, bool largeFile) {
|
||||
ReturnValue_t setFileSize(uint64_t fileSize_, std::optional<bool> largeFile_) {
|
||||
if (largeFile_) {
|
||||
largeFile = largeFile_.value();
|
||||
}
|
||||
if (not largeFile and fileSize > UINT32_MAX) {
|
||||
// TODO: emit warning here
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
this->fileSize = fileSize;
|
||||
this->largeFile = largeFile;
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
this->fileSize = fileSize_;
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
bool isLargeFile() const { return largeFile; }
|
||||
uint64_t getSize(bool *largeFile = nullptr) const {
|
||||
if (largeFile != nullptr) {
|
||||
*largeFile = this->largeFile;
|
||||
[[nodiscard]] bool isLargeFile() const { return largeFile; }
|
||||
uint64_t getSize(bool *largeFile_ = nullptr) const {
|
||||
if (largeFile_ != nullptr) {
|
||||
*largeFile_ = this->largeFile;
|
||||
}
|
||||
return fileSize;
|
||||
}
|
||||
@ -75,4 +81,4 @@ struct FileSize : public SerializeIF {
|
||||
|
||||
} // namespace cfdp
|
||||
|
||||
#endif /* FSFW_SRC_FSFW_CFDP_FILESIZE_H_ */
|
||||
#endif /* FSFW_CFDP_FILESIZE_H_ */
|
||||
|
@ -1,12 +1,11 @@
|
||||
#include "VarLenField.h"
|
||||
#include "VarLenFields.h"
|
||||
|
||||
#include "fsfw/FSFW.h"
|
||||
#include "fsfw/serialize/SerializeAdapter.h"
|
||||
#include "fsfw/serviceinterface.h"
|
||||
|
||||
cfdp::VarLenField::VarLenField(cfdp::WidthInBytes width, size_t value) : VarLenField() {
|
||||
ReturnValue_t result = this->setValue(width, value);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
if (result != returnvalue::OK) {
|
||||
#if FSFW_DISABLE_PRINTOUT == 0
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "cfdp::VarLenField: Setting value failed" << std::endl;
|
||||
@ -21,27 +20,27 @@ cfdp::VarLenField::VarLenField() : width(cfdp::WidthInBytes::ONE_BYTE) { value.o
|
||||
|
||||
cfdp::WidthInBytes cfdp::VarLenField::getWidth() const { return width; }
|
||||
|
||||
ReturnValue_t cfdp::VarLenField::setValue(cfdp::WidthInBytes widthInBytes, size_t value) {
|
||||
ReturnValue_t cfdp::VarLenField::setValue(cfdp::WidthInBytes widthInBytes, size_t value_) {
|
||||
switch (widthInBytes) {
|
||||
case (cfdp::WidthInBytes::ONE_BYTE): {
|
||||
if (value > UINT8_MAX) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
if (value_ > UINT8_MAX) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
this->value.oneByte = value;
|
||||
this->value.oneByte = value_;
|
||||
break;
|
||||
}
|
||||
case (cfdp::WidthInBytes::TWO_BYTES): {
|
||||
if (value > UINT16_MAX) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
if (value_ > UINT16_MAX) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
this->value.twoBytes = value;
|
||||
this->value.twoBytes = value_;
|
||||
break;
|
||||
}
|
||||
case (cfdp::WidthInBytes::FOUR_BYTES): {
|
||||
if (value > UINT32_MAX) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
if (value_ > UINT32_MAX) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
this->value.fourBytes = value;
|
||||
this->value.fourBytes = value_;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@ -49,7 +48,7 @@ ReturnValue_t cfdp::VarLenField::setValue(cfdp::WidthInBytes widthInBytes, size_
|
||||
}
|
||||
}
|
||||
this->width = widthInBytes;
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
size_t cfdp::VarLenField::getValue() const {
|
||||
@ -77,7 +76,7 @@ ReturnValue_t cfdp::VarLenField::serialize(uint8_t **buffer, size_t *size, size_
|
||||
**buffer = value.oneByte;
|
||||
*size += 1;
|
||||
*buffer += 1;
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
return returnvalue::OK;
|
||||
}
|
||||
case (cfdp::WidthInBytes::TWO_BYTES): {
|
||||
return SerializeAdapter::serialize(&value.twoBytes, buffer, size, maxSize, streamEndianness);
|
||||
@ -86,16 +85,16 @@ ReturnValue_t cfdp::VarLenField::serialize(uint8_t **buffer, size_t *size, size_
|
||||
return SerializeAdapter::serialize(&value.fourBytes, buffer, size, maxSize, streamEndianness);
|
||||
}
|
||||
default: {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t cfdp::VarLenField::getSerializedSize() const { return width; }
|
||||
|
||||
ReturnValue_t cfdp::VarLenField::deSerialize(cfdp::WidthInBytes width, const uint8_t **buffer,
|
||||
ReturnValue_t cfdp::VarLenField::deSerialize(cfdp::WidthInBytes width_, const uint8_t **buffer,
|
||||
size_t *size, Endianness streamEndianness) {
|
||||
this->width = width;
|
||||
this->width = width_;
|
||||
return deSerialize(buffer, size, streamEndianness);
|
||||
}
|
||||
|
||||
@ -105,7 +104,7 @@ ReturnValue_t cfdp::VarLenField::deSerialize(const uint8_t **buffer, size_t *siz
|
||||
case (cfdp::WidthInBytes::ONE_BYTE): {
|
||||
value.oneByte = **buffer;
|
||||
*size += 1;
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
return returnvalue::OK;
|
||||
}
|
||||
case (cfdp::WidthInBytes::TWO_BYTES): {
|
||||
return SerializeAdapter::deSerialize(&value.twoBytes, buffer, size, streamEndianness);
|
||||
@ -114,7 +113,25 @@ ReturnValue_t cfdp::VarLenField::deSerialize(const uint8_t **buffer, size_t *siz
|
||||
return SerializeAdapter::deSerialize(&value.fourBytes, buffer, size, streamEndianness);
|
||||
}
|
||||
default: {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool cfdp::VarLenField::operator<(const cfdp::VarLenField &other) const {
|
||||
if (getWidth() < other.getWidth()) {
|
||||
return true;
|
||||
} else if (getWidth() == other.getWidth()) {
|
||||
return getValue() < other.getValue();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool cfdp::VarLenField::operator==(const cfdp::VarLenField &other) const {
|
||||
return getWidth() == other.getWidth() and getValue() == other.getValue();
|
||||
}
|
||||
|
||||
bool cfdp::VarLenField::operator!=(const cfdp::VarLenField &other) const {
|
||||
return not(*this == other);
|
||||
}
|
107
src/fsfw/cfdp/VarLenFields.h
Normal file
107
src/fsfw/cfdp/VarLenFields.h
Normal file
@ -0,0 +1,107 @@
|
||||
#ifndef FSFW_CFDP_PDU_VARLENFIELD_H_
|
||||
#define FSFW_CFDP_PDU_VARLENFIELD_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
|
||||
#include "fsfw/cfdp/definitions.h"
|
||||
#include "fsfw/serialize/SerializeIF.h"
|
||||
#include "fsfw/serviceinterface.h"
|
||||
#include "fsfw/util/UnsignedByteField.h"
|
||||
|
||||
namespace cfdp {
|
||||
|
||||
class VarLenField : public SerializeIF {
|
||||
public:
|
||||
union LengthFieldLen {
|
||||
uint8_t oneByte;
|
||||
uint16_t twoBytes;
|
||||
uint32_t fourBytes;
|
||||
uint64_t eightBytes;
|
||||
};
|
||||
|
||||
VarLenField();
|
||||
template <typename T>
|
||||
explicit VarLenField(UnsignedByteField<T> byteField);
|
||||
|
||||
VarLenField(cfdp::WidthInBytes width, size_t value);
|
||||
|
||||
bool operator==(const VarLenField &other) const;
|
||||
bool operator!=(const VarLenField &other) const;
|
||||
bool operator<(const VarLenField &other) const;
|
||||
|
||||
ReturnValue_t setValue(cfdp::WidthInBytes, size_t value);
|
||||
|
||||
ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize,
|
||||
Endianness streamEndianness) const override;
|
||||
|
||||
[[nodiscard]] size_t getSerializedSize() const override;
|
||||
|
||||
ReturnValue_t deSerialize(cfdp::WidthInBytes width, const uint8_t **buffer, size_t *size,
|
||||
Endianness streamEndianness);
|
||||
|
||||
[[nodiscard]] cfdp::WidthInBytes getWidth() const;
|
||||
[[nodiscard]] size_t getValue() const;
|
||||
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
friend std::ostream &operator<<(std::ostream &os, const VarLenField &id) {
|
||||
os << "dec: " << id.getValue() << ", hex: " << std::hex << std::setw(id.getWidth())
|
||||
<< std::setfill('0') << id.getValue() << std::dec << std::setfill('0');
|
||||
return os;
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size,
|
||||
Endianness streamEndianness) override;
|
||||
|
||||
cfdp::WidthInBytes width;
|
||||
LengthFieldLen value{};
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
cfdp::VarLenField::VarLenField(UnsignedByteField<T> byteField)
|
||||
: width(static_cast<cfdp::WidthInBytes>(sizeof(T))) {
|
||||
static_assert((sizeof(T) % 2) == 0);
|
||||
setValue(width, byteField.getValue());
|
||||
}
|
||||
|
||||
struct EntityId : public VarLenField {
|
||||
public:
|
||||
EntityId() : VarLenField() {}
|
||||
template <typename T>
|
||||
explicit EntityId(UnsignedByteField<T> byteField) : VarLenField(byteField) {}
|
||||
EntityId(cfdp::WidthInBytes width, size_t entityId) : VarLenField(width, entityId) {}
|
||||
};
|
||||
|
||||
struct TransactionSeqNum : public VarLenField {
|
||||
public:
|
||||
TransactionSeqNum() : VarLenField() {}
|
||||
template <typename T>
|
||||
explicit TransactionSeqNum(UnsignedByteField<T> byteField) : VarLenField(byteField) {}
|
||||
TransactionSeqNum(cfdp::WidthInBytes width, size_t seqNum) : VarLenField(width, seqNum) {}
|
||||
};
|
||||
|
||||
struct TransactionId {
|
||||
TransactionId() = default;
|
||||
TransactionId(EntityId entityId, TransactionSeqNum seqNum)
|
||||
: entityId(std::move(entityId)), seqNum(std::move(seqNum)) {}
|
||||
|
||||
bool operator==(const TransactionId &other) const {
|
||||
return entityId == other.entityId and seqNum == other.seqNum;
|
||||
}
|
||||
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
friend std::ostream &operator<<(std::ostream &os, const TransactionId &id) {
|
||||
os << "Source ID { " << id.entityId << " }, Sequence Number " << id.seqNum.getValue();
|
||||
return os;
|
||||
}
|
||||
#endif
|
||||
EntityId entityId;
|
||||
TransactionSeqNum seqNum;
|
||||
};
|
||||
|
||||
} // namespace cfdp
|
||||
|
||||
#endif /* FSFW_CFDP_PDU_VARLENFIELD_H_ */
|
@ -7,36 +7,37 @@
|
||||
#include <cstdint>
|
||||
|
||||
#include "fsfw/returnvalues/FwClassIds.h"
|
||||
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
|
||||
#include "fsfw/returnvalues/returnvalue.h"
|
||||
|
||||
namespace cfdp {
|
||||
|
||||
static constexpr uint8_t VERSION_BITS = 0b00100000;
|
||||
static constexpr char CFDP_VERSION_2_NAME[] = "CCSDS 727.0-B-5";
|
||||
|
||||
// Second version of the protocol, only this one is supported here
|
||||
static constexpr uint8_t CFDP_VERSION_2 = 0b001;
|
||||
static constexpr uint8_t VERSION_BITS = CFDP_VERSION_2 << 5;
|
||||
|
||||
static constexpr uint8_t CFDP_CLASS_ID = CLASS_ID::CFDP;
|
||||
|
||||
static constexpr ReturnValue_t INVALID_TLV_TYPE =
|
||||
HasReturnvaluesIF::makeReturnCode(CFDP_CLASS_ID, 1);
|
||||
static constexpr ReturnValue_t INVALID_DIRECTIVE_FIELDS =
|
||||
HasReturnvaluesIF::makeReturnCode(CFDP_CLASS_ID, 2);
|
||||
static constexpr ReturnValue_t INVALID_PDU_DATAFIELD_LEN =
|
||||
HasReturnvaluesIF::makeReturnCode(CFDP_CLASS_ID, 3);
|
||||
static constexpr ReturnValue_t INVALID_TLV_TYPE = returnvalue::makeCode(CFDP_CLASS_ID, 1);
|
||||
static constexpr ReturnValue_t INVALID_DIRECTIVE_FIELD = returnvalue::makeCode(CFDP_CLASS_ID, 2);
|
||||
static constexpr ReturnValue_t INVALID_PDU_DATAFIELD_LEN = returnvalue::makeCode(CFDP_CLASS_ID, 3);
|
||||
static constexpr ReturnValue_t INVALID_ACK_DIRECTIVE_FIELDS =
|
||||
HasReturnvaluesIF::makeReturnCode(CFDP_CLASS_ID, 4);
|
||||
returnvalue::makeCode(CFDP_CLASS_ID, 4);
|
||||
//! Can not parse options. This can also occur because there are options
|
||||
//! available but the user did not pass a valid options array
|
||||
static constexpr ReturnValue_t METADATA_CANT_PARSE_OPTIONS =
|
||||
HasReturnvaluesIF::makeReturnCode(CFDP_CLASS_ID, 5);
|
||||
static constexpr ReturnValue_t NAK_CANT_PARSE_OPTIONS =
|
||||
HasReturnvaluesIF::makeReturnCode(CFDP_CLASS_ID, 6);
|
||||
returnvalue::makeCode(CFDP_CLASS_ID, 5);
|
||||
static constexpr ReturnValue_t NAK_CANT_PARSE_OPTIONS = returnvalue::makeCode(CFDP_CLASS_ID, 6);
|
||||
static constexpr ReturnValue_t FINISHED_CANT_PARSE_FS_RESPONSES =
|
||||
HasReturnvaluesIF::makeReturnCode(CFDP_CLASS_ID, 6);
|
||||
returnvalue::makeCode(CFDP_CLASS_ID, 7);
|
||||
static constexpr ReturnValue_t FILESTORE_REQUIRES_SECOND_FILE =
|
||||
HasReturnvaluesIF::makeReturnCode(CFDP_CLASS_ID, 8);
|
||||
returnvalue::makeCode(CFDP_CLASS_ID, 8);
|
||||
//! Can not parse filestore response because user did not pass a valid instance
|
||||
//! or remaining size is invalid
|
||||
static constexpr ReturnValue_t FILESTORE_RESPONSE_CANT_PARSE_FS_MESSAGE =
|
||||
HasReturnvaluesIF::makeReturnCode(CFDP_CLASS_ID, 9);
|
||||
returnvalue::makeCode(CFDP_CLASS_ID, 9);
|
||||
static constexpr ReturnValue_t INVALID_PDU_FORMAT = returnvalue::makeCode(CFDP_CLASS_ID, 10);
|
||||
|
||||
//! Checksum types according to the SANA Checksum Types registry
|
||||
//! https://sanaregistry.org/r/checksum_identifiers/
|
||||
@ -49,17 +50,17 @@ enum ChecksumType {
|
||||
NULL_CHECKSUM = 15
|
||||
};
|
||||
|
||||
enum PduType : bool { FILE_DIRECTIVE = 0, FILE_DATA = 1 };
|
||||
enum PduType : uint8_t { FILE_DIRECTIVE = 0, FILE_DATA = 1 };
|
||||
|
||||
enum TransmissionModes : bool { ACKNOWLEDGED = 0, UNACKNOWLEDGED = 1 };
|
||||
enum TransmissionMode : uint8_t { ACKNOWLEDGED = 0, UNACKNOWLEDGED = 1 };
|
||||
|
||||
enum SegmentMetadataFlag : bool { NOT_PRESENT = 0, PRESENT = 1 };
|
||||
enum SegmentMetadataFlag : bool { NOT_PRESENT = false, PRESENT = true };
|
||||
|
||||
enum Direction : bool { TOWARDS_RECEIVER = 0, TOWARDS_SENDER = 1 };
|
||||
enum Direction : uint8_t { TOWARDS_RECEIVER = 0, TOWARDS_SENDER = 1 };
|
||||
|
||||
enum SegmentationControl : bool {
|
||||
NO_RECORD_BOUNDARIES_PRESERVATION = 0,
|
||||
RECORD_BOUNDARIES_PRESERVATION = 1
|
||||
NO_RECORD_BOUNDARIES_PRESERVATION = false,
|
||||
RECORD_BOUNDARIES_PRESERVATION = true
|
||||
};
|
||||
|
||||
enum WidthInBytes : uint8_t {
|
||||
@ -69,8 +70,9 @@ enum WidthInBytes : uint8_t {
|
||||
FOUR_BYTES = 4,
|
||||
};
|
||||
|
||||
enum FileDirectives : uint8_t {
|
||||
enum FileDirective : uint8_t {
|
||||
INVALID_DIRECTIVE = 0x0f,
|
||||
// The _DIRECTIVE suffix is mandatory here because of some nameclash!
|
||||
EOF_DIRECTIVE = 0x04,
|
||||
FINISH = 0x05,
|
||||
ACK = 0x06,
|
||||
@ -97,6 +99,14 @@ enum ConditionCode : uint8_t {
|
||||
CANCEL_REQUEST_RECEIVED = 0b1111
|
||||
};
|
||||
|
||||
enum FaultHandlerCode {
|
||||
RESERVED = 0b0000,
|
||||
NOTICE_OF_CANCELLATION = 0b0001,
|
||||
NOTICE_OF_SUSPENSION = 0b0010,
|
||||
IGNORE_ERROR = 0b0011,
|
||||
ABANDON_TRANSACTION = 0b0100
|
||||
};
|
||||
|
||||
enum AckTransactionStatus {
|
||||
UNDEFINED = 0b00,
|
||||
ACTIVE = 0b01,
|
||||
@ -104,18 +114,18 @@ enum AckTransactionStatus {
|
||||
UNRECOGNIZED = 0b11
|
||||
};
|
||||
|
||||
enum FinishedDeliveryCode { DATA_COMPLETE = 0, DATA_INCOMPLETE = 1 };
|
||||
enum FileDeliveryCode { DATA_COMPLETE = 0, DATA_INCOMPLETE = 1 };
|
||||
|
||||
enum FinishedFileStatus {
|
||||
enum FileDeliveryStatus {
|
||||
DISCARDED_DELIBERATELY = 0,
|
||||
DISCARDED_FILESTORE_REJECTION = 1,
|
||||
RETAINED_IN_FILESTORE = 2,
|
||||
FILE_STATUS_UNREPORTED = 3
|
||||
};
|
||||
|
||||
enum PromptResponseRequired : bool { PROMPT_NAK = 0, PROMPT_KEEP_ALIVE = 1 };
|
||||
enum PromptResponseRequired : uint8_t { PROMPT_NAK = 0, PROMPT_KEEP_ALIVE = 1 };
|
||||
|
||||
enum TlvTypes : uint8_t {
|
||||
enum TlvType : uint8_t {
|
||||
FILESTORE_REQUEST = 0x00,
|
||||
FILESTORE_RESPONSE = 0x01,
|
||||
MSG_TO_USER = 0x02,
|
||||
|
3
src/fsfw/cfdp/handler/CMakeLists.txt
Normal file
3
src/fsfw/cfdp/handler/CMakeLists.txt
Normal file
@ -0,0 +1,3 @@
|
||||
target_sources(
|
||||
${LIB_FSFW_NAME} PRIVATE SourceHandler.cpp DestHandler.cpp
|
||||
FaultHandlerBase.cpp UserBase.cpp CfdpHandler.cpp)
|
134
src/fsfw/cfdp/handler/CfdpHandler.cpp
Normal file
134
src/fsfw/cfdp/handler/CfdpHandler.cpp
Normal file
@ -0,0 +1,134 @@
|
||||
#include "CfdpHandler.h"
|
||||
|
||||
#include "fsfw/cfdp/pdu/AckPduReader.h"
|
||||
#include "fsfw/cfdp/pdu/PduHeaderReader.h"
|
||||
#include "fsfw/globalfunctions/arrayprinter.h"
|
||||
#include "fsfw/ipc/QueueFactory.h"
|
||||
#include "fsfw/tmtcservices/TmTcMessage.h"
|
||||
|
||||
using namespace returnvalue;
|
||||
using namespace cfdp;
|
||||
|
||||
CfdpHandler::CfdpHandler(const FsfwHandlerParams& fsfwParams, const CfdpHandlerCfg& cfdpCfg)
|
||||
: SystemObject(fsfwParams.objectId),
|
||||
msgQueue(fsfwParams.msgQueue),
|
||||
destHandler(
|
||||
DestHandlerParams(LocalEntityCfg(cfdpCfg.id, cfdpCfg.indicCfg, cfdpCfg.faultHandler),
|
||||
cfdpCfg.userHandler, cfdpCfg.remoteCfgProvider, cfdpCfg.packetInfoList,
|
||||
cfdpCfg.lostSegmentsList),
|
||||
FsfwParams(fsfwParams.packetDest, nullptr, this, fsfwParams.tcStore,
|
||||
fsfwParams.tmStore)) {
|
||||
destHandler.setMsgQueue(msgQueue);
|
||||
}
|
||||
|
||||
[[nodiscard]] const char* CfdpHandler::getName() const { return "CFDP Handler"; }
|
||||
|
||||
[[nodiscard]] uint32_t CfdpHandler::getIdentifier() const {
|
||||
return destHandler.getDestHandlerParams().cfg.localId.getValue();
|
||||
}
|
||||
|
||||
[[nodiscard]] MessageQueueId_t CfdpHandler::getRequestQueue() const { return msgQueue.getId(); }
|
||||
|
||||
ReturnValue_t CfdpHandler::initialize() {
|
||||
ReturnValue_t result = destHandler.initialize();
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
tcStore = destHandler.getTcStore();
|
||||
tmStore = destHandler.getTmStore();
|
||||
|
||||
return SystemObject::initialize();
|
||||
}
|
||||
|
||||
ReturnValue_t CfdpHandler::performOperation(uint8_t operationCode) {
|
||||
// TODO: Receive TC packets and route them to source and dest handler, depending on which is
|
||||
// correct or more appropriate
|
||||
ReturnValue_t status;
|
||||
ReturnValue_t result = OK;
|
||||
TmTcMessage tmtcMsg;
|
||||
for (status = msgQueue.receiveMessage(&tmtcMsg); status == returnvalue::OK;
|
||||
status = msgQueue.receiveMessage(&tmtcMsg)) {
|
||||
result = handleCfdpPacket(tmtcMsg);
|
||||
if (result != OK) {
|
||||
status = result;
|
||||
}
|
||||
}
|
||||
auto& fsmRes = destHandler.performStateMachine();
|
||||
// TODO: Error handling?
|
||||
while (fsmRes.callStatus == CallStatus::CALL_AGAIN) {
|
||||
destHandler.performStateMachine();
|
||||
// TODO: Error handling?
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
ReturnValue_t CfdpHandler::handleCfdpPacket(TmTcMessage& msg) {
|
||||
auto accessorPair = tcStore->getData(msg.getStorageId());
|
||||
if (accessorPair.first != OK) {
|
||||
return accessorPair.first;
|
||||
}
|
||||
PduHeaderReader reader(accessorPair.second.data(), accessorPair.second.size());
|
||||
ReturnValue_t result = reader.parseData();
|
||||
if (result != returnvalue::OK) {
|
||||
return INVALID_PDU_FORMAT;
|
||||
}
|
||||
// The CFDP distributor should have taken care of ensuring the destination ID is correct
|
||||
PduType type = reader.getPduType();
|
||||
// Only the destination handler can process these PDUs
|
||||
if (type == PduType::FILE_DATA) {
|
||||
// Disable auto-deletion of packet
|
||||
accessorPair.second.release();
|
||||
PacketInfo info(type, msg.getStorageId());
|
||||
result = destHandler.passPacket(info);
|
||||
} else {
|
||||
// Route depending on PDU type and directive type if applicable. It retrieves directive type
|
||||
// from the raw stream for better performance (with sanity and directive code check).
|
||||
// The routing is based on section 4.5 of the CFDP standard which specifies the PDU forwarding
|
||||
// procedure.
|
||||
|
||||
// PDU header only. Invalid supplied data. A directive packet should have a valid data field
|
||||
// with at least one byte being the directive code
|
||||
const uint8_t* pduDataField = reader.getPduDataField();
|
||||
if (pduDataField == nullptr) {
|
||||
return INVALID_PDU_FORMAT;
|
||||
}
|
||||
if (not FileDirectiveReader::checkFileDirective(pduDataField[0])) {
|
||||
return INVALID_DIRECTIVE_FIELD;
|
||||
}
|
||||
auto directive = static_cast<FileDirective>(pduDataField[0]);
|
||||
|
||||
auto passToDestHandler = [&]() {
|
||||
accessorPair.second.release();
|
||||
PacketInfo info(type, msg.getStorageId(), directive);
|
||||
result = destHandler.passPacket(info);
|
||||
};
|
||||
auto passToSourceHandler = [&]() {
|
||||
|
||||
};
|
||||
if (directive == FileDirective::METADATA or directive == FileDirective::EOF_DIRECTIVE or
|
||||
directive == FileDirective::PROMPT) {
|
||||
// Section b) of 4.5.3: These PDUs should always be targeted towards the file receiver a.k.a.
|
||||
// the destination handler
|
||||
passToDestHandler();
|
||||
} else if (directive == FileDirective::FINISH or directive == FileDirective::NAK or
|
||||
directive == FileDirective::KEEP_ALIVE) {
|
||||
// Section c) of 4.5.3: These PDUs should always be targeted towards the file sender a.k.a.
|
||||
// the source handler
|
||||
passToSourceHandler();
|
||||
} else if (directive == FileDirective::ACK) {
|
||||
// Section a): Recipient depends of the type of PDU that is being acknowledged. We can simply
|
||||
// extract the PDU type from the raw stream. If it is an EOF PDU, this packet is passed to
|
||||
// the source handler, for a Finished PDU, it is passed to the destination handler.
|
||||
FileDirective ackedDirective;
|
||||
if (not AckPduReader::checkAckedDirectiveField(pduDataField[1], ackedDirective)) {
|
||||
return INVALID_ACK_DIRECTIVE_FIELDS;
|
||||
}
|
||||
if (ackedDirective == FileDirective::EOF_DIRECTIVE) {
|
||||
passToSourceHandler();
|
||||
} else if (ackedDirective == FileDirective::FINISH) {
|
||||
passToDestHandler();
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
71
src/fsfw/cfdp/handler/CfdpHandler.h
Normal file
71
src/fsfw/cfdp/handler/CfdpHandler.h
Normal file
@ -0,0 +1,71 @@
|
||||
#ifndef FSFW_EXAMPLE_HOSTED_CFDPHANDLER_H
|
||||
#define FSFW_EXAMPLE_HOSTED_CFDPHANDLER_H
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "fsfw/cfdp/handler/DestHandler.h"
|
||||
#include "fsfw/objectmanager/SystemObject.h"
|
||||
#include "fsfw/tasks/ExecutableObjectIF.h"
|
||||
#include "fsfw/tmtcservices/AcceptsTelecommandsIF.h"
|
||||
#include "fsfw/tmtcservices/TmTcMessage.h"
|
||||
|
||||
struct FsfwHandlerParams {
|
||||
FsfwHandlerParams(object_id_t objectId, HasFileSystemIF& vfs, AcceptsTelemetryIF& packetDest,
|
||||
StorageManagerIF& tcStore, StorageManagerIF& tmStore, MessageQueueIF& msgQueue)
|
||||
: objectId(objectId),
|
||||
vfs(vfs),
|
||||
packetDest(packetDest),
|
||||
tcStore(tcStore),
|
||||
tmStore(tmStore),
|
||||
msgQueue(msgQueue) {}
|
||||
object_id_t objectId{};
|
||||
HasFileSystemIF& vfs;
|
||||
AcceptsTelemetryIF& packetDest;
|
||||
StorageManagerIF& tcStore;
|
||||
StorageManagerIF& tmStore;
|
||||
MessageQueueIF& msgQueue;
|
||||
};
|
||||
|
||||
struct CfdpHandlerCfg {
|
||||
CfdpHandlerCfg(cfdp::EntityId localId, cfdp::IndicationCfg indicationCfg,
|
||||
cfdp::UserBase& userHandler, cfdp::FaultHandlerBase& userFaultHandler,
|
||||
cfdp::PacketInfoListBase& packetInfo, cfdp::LostSegmentsListBase& lostSegmentsList,
|
||||
cfdp::RemoteConfigTableIF& remoteCfgProvider)
|
||||
: id(std::move(localId)),
|
||||
indicCfg(indicationCfg),
|
||||
packetInfoList(packetInfo),
|
||||
lostSegmentsList(lostSegmentsList),
|
||||
remoteCfgProvider(remoteCfgProvider),
|
||||
userHandler(userHandler),
|
||||
faultHandler(userFaultHandler) {}
|
||||
|
||||
cfdp::EntityId id;
|
||||
cfdp::IndicationCfg indicCfg;
|
||||
cfdp::PacketInfoListBase& packetInfoList;
|
||||
cfdp::LostSegmentsListBase& lostSegmentsList;
|
||||
cfdp::RemoteConfigTableIF& remoteCfgProvider;
|
||||
cfdp::UserBase& userHandler;
|
||||
cfdp::FaultHandlerBase& faultHandler;
|
||||
};
|
||||
|
||||
class CfdpHandler : public SystemObject, public ExecutableObjectIF, public AcceptsTelecommandsIF {
|
||||
public:
|
||||
explicit CfdpHandler(const FsfwHandlerParams& fsfwParams, const CfdpHandlerCfg& cfdpCfg);
|
||||
|
||||
[[nodiscard]] const char* getName() const override;
|
||||
[[nodiscard]] uint32_t getIdentifier() const override;
|
||||
[[nodiscard]] MessageQueueId_t getRequestQueue() const override;
|
||||
|
||||
ReturnValue_t initialize() override;
|
||||
ReturnValue_t performOperation(uint8_t operationCode) override;
|
||||
|
||||
private:
|
||||
MessageQueueIF& msgQueue;
|
||||
cfdp::DestHandler destHandler;
|
||||
StorageManagerIF* tcStore = nullptr;
|
||||
StorageManagerIF* tmStore = nullptr;
|
||||
|
||||
ReturnValue_t handleCfdpPacket(TmTcMessage& msg);
|
||||
};
|
||||
|
||||
#endif // FSFW_EXAMPLE_HOSTED_CFDPHANDLER_H
|
480
src/fsfw/cfdp/handler/DestHandler.cpp
Normal file
480
src/fsfw/cfdp/handler/DestHandler.cpp
Normal file
@ -0,0 +1,480 @@
|
||||
#include "DestHandler.h"
|
||||
|
||||
#include <etl/crc32.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "fsfw/FSFW.h"
|
||||
#include "fsfw/cfdp/pdu/EofPduReader.h"
|
||||
#include "fsfw/cfdp/pdu/FileDataReader.h"
|
||||
#include "fsfw/cfdp/pdu/FinishedPduCreator.h"
|
||||
#include "fsfw/cfdp/pdu/PduHeaderReader.h"
|
||||
#include "fsfw/objectmanager.h"
|
||||
#include "fsfw/tmtcservices/TmTcMessage.h"
|
||||
|
||||
using namespace returnvalue;
|
||||
|
||||
cfdp::DestHandler::DestHandler(DestHandlerParams params, FsfwParams fsfwParams)
|
||||
: tlvVec(params.maxTlvsInOnePdu),
|
||||
userTlvVec(params.maxTlvsInOnePdu),
|
||||
dp(std::move(params)),
|
||||
fp(fsfwParams),
|
||||
tp(params.maxFilenameLen) {
|
||||
tp.pduConf.direction = cfdp::Direction::TOWARDS_SENDER;
|
||||
}
|
||||
|
||||
const cfdp::DestHandler::FsmResult& cfdp::DestHandler::performStateMachine() {
|
||||
ReturnValue_t result;
|
||||
uint8_t errorIdx = 0;
|
||||
fsmRes.resetOfIteration();
|
||||
if (fsmRes.step == TransactionStep::IDLE) {
|
||||
for (auto infoIter = dp.packetListRef.begin(); infoIter != dp.packetListRef.end();) {
|
||||
if (infoIter->pduType == PduType::FILE_DIRECTIVE and
|
||||
infoIter->directiveType == FileDirective::METADATA) {
|
||||
result = handleMetadataPdu(*infoIter);
|
||||
checkAndHandleError(result, errorIdx);
|
||||
// Store data was deleted in PDU handler because a store guard is used
|
||||
dp.packetListRef.erase(infoIter++);
|
||||
} else {
|
||||
infoIter++;
|
||||
}
|
||||
}
|
||||
if (fsmRes.step == TransactionStep::IDLE) {
|
||||
// To decrease the already high complexity of the software, all packets arriving before
|
||||
// a metadata PDU are deleted.
|
||||
for (auto infoIter = dp.packetListRef.begin(); infoIter != dp.packetListRef.end();) {
|
||||
fp.tcStore->deleteData(infoIter->storeId);
|
||||
infoIter++;
|
||||
}
|
||||
dp.packetListRef.clear();
|
||||
}
|
||||
|
||||
if (fsmRes.step != TransactionStep::IDLE) {
|
||||
fsmRes.callStatus = CallStatus::CALL_AGAIN;
|
||||
}
|
||||
return updateFsmRes(errorIdx);
|
||||
}
|
||||
if (fsmRes.state == CfdpStates::BUSY_CLASS_1_NACKED) {
|
||||
if (fsmRes.step == TransactionStep::RECEIVING_FILE_DATA_PDUS) {
|
||||
for (auto infoIter = dp.packetListRef.begin(); infoIter != dp.packetListRef.end();) {
|
||||
if (infoIter->pduType == PduType::FILE_DATA) {
|
||||
result = handleFileDataPdu(*infoIter);
|
||||
checkAndHandleError(result, errorIdx);
|
||||
// Store data was deleted in PDU handler because a store guard is used
|
||||
dp.packetListRef.erase(infoIter++);
|
||||
} else if (infoIter->pduType == PduType::FILE_DIRECTIVE and
|
||||
infoIter->directiveType == FileDirective::EOF_DIRECTIVE) {
|
||||
// TODO: Support for check timer missing
|
||||
result = handleEofPdu(*infoIter);
|
||||
checkAndHandleError(result, errorIdx);
|
||||
// Store data was deleted in PDU handler because a store guard is used
|
||||
dp.packetListRef.erase(infoIter++);
|
||||
} else {
|
||||
infoIter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fsmRes.step == TransactionStep::TRANSFER_COMPLETION) {
|
||||
result = handleTransferCompletion();
|
||||
checkAndHandleError(result, errorIdx);
|
||||
}
|
||||
if (fsmRes.step == TransactionStep::SENDING_FINISHED_PDU) {
|
||||
result = sendFinishedPdu();
|
||||
checkAndHandleError(result, errorIdx);
|
||||
finish();
|
||||
}
|
||||
return updateFsmRes(errorIdx);
|
||||
}
|
||||
if (fsmRes.state == CfdpStates::BUSY_CLASS_2_ACKED) {
|
||||
// TODO: Will be implemented at a later stage
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "CFDP state machine for acknowledged mode not implemented yet" << std::endl;
|
||||
#endif
|
||||
}
|
||||
return updateFsmRes(errorIdx);
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::passPacket(PacketInfo packet) {
|
||||
if (dp.packetListRef.full()) {
|
||||
return FAILED;
|
||||
}
|
||||
dp.packetListRef.push_back(packet);
|
||||
return OK;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::initialize() {
|
||||
if (fp.tmStore == nullptr) {
|
||||
fp.tmStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TM_STORE);
|
||||
if (fp.tmStore == nullptr) {
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
if (fp.tcStore == nullptr) {
|
||||
fp.tcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TC_STORE);
|
||||
if (fp.tcStore == nullptr) {
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
if (fp.msgQueue == nullptr) {
|
||||
return FAILED;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::handleMetadataPdu(const PacketInfo& info) {
|
||||
// Process metadata PDU
|
||||
auto constAccessorPair = fp.tcStore->getData(info.storeId);
|
||||
if (constAccessorPair.first != OK) {
|
||||
// TODO: This is not a CFDP error. Event and/or warning?
|
||||
return constAccessorPair.first;
|
||||
}
|
||||
cfdp::StringLv sourceFileName;
|
||||
cfdp::StringLv destFileName;
|
||||
MetadataInfo metadataInfo(tp.fileSize, sourceFileName, destFileName);
|
||||
cfdp::Tlv* tlvArrayAsPtr = tlvVec.data();
|
||||
metadataInfo.setOptionsArray(&tlvArrayAsPtr, std::nullopt, tlvVec.size());
|
||||
MetadataPduReader reader(constAccessorPair.second.data(), constAccessorPair.second.size(),
|
||||
metadataInfo);
|
||||
ReturnValue_t result = reader.parseData();
|
||||
// TODO: The standard does not really specify what happens if this kind of error happens
|
||||
// I think it might be a good idea to cache some sort of error code, which
|
||||
// is translated into a warning and/or event by an upper layer
|
||||
if (result != OK) {
|
||||
return handleMetadataParseError(result, constAccessorPair.second.data(),
|
||||
constAccessorPair.second.size());
|
||||
}
|
||||
return startTransaction(reader, metadataInfo);
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::handleFileDataPdu(const cfdp::PacketInfo& info) {
|
||||
// Process file data PDU
|
||||
auto constAccessorPair = fp.tcStore->getData(info.storeId);
|
||||
if (constAccessorPair.first != OK) {
|
||||
// TODO: This is not a CFDP error. Event and/or warning?
|
||||
return constAccessorPair.first;
|
||||
}
|
||||
cfdp::FileSize offset;
|
||||
FileDataInfo fdInfo(offset);
|
||||
FileDataReader reader(constAccessorPair.second.data(), constAccessorPair.second.size(), fdInfo);
|
||||
ReturnValue_t result = reader.parseData();
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
size_t fileSegmentLen = 0;
|
||||
const uint8_t* fileData = fdInfo.getFileData(&fileSegmentLen);
|
||||
FileOpParams fileOpParams(tp.destName.data(), fileSegmentLen);
|
||||
fileOpParams.offset = offset.value();
|
||||
if (dp.cfg.indicCfg.fileSegmentRecvIndicRequired) {
|
||||
FileSegmentRecvdParams segParams;
|
||||
segParams.offset = offset.value();
|
||||
segParams.id = tp.transactionId;
|
||||
segParams.length = fileSegmentLen;
|
||||
segParams.recContState = fdInfo.getRecordContinuationState();
|
||||
size_t segmentMetadatLen = 0;
|
||||
auto* segMetadata = fdInfo.getSegmentMetadata(&segmentMetadatLen);
|
||||
segParams.segmentMetadata = {segMetadata, segmentMetadatLen};
|
||||
dp.user.fileSegmentRecvdIndication(segParams);
|
||||
}
|
||||
result = dp.user.vfs.writeToFile(fileOpParams, fileData);
|
||||
if (offset.value() + fileSegmentLen > tp.progress) {
|
||||
tp.progress = offset.value() + fileSegmentLen;
|
||||
}
|
||||
if (result != returnvalue::OK) {
|
||||
// TODO: Proper Error handling
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "File write error" << std::endl;
|
||||
#endif
|
||||
} else {
|
||||
tp.deliveryStatus = FileDeliveryStatus::RETAINED_IN_FILESTORE;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::handleEofPdu(const cfdp::PacketInfo& info) {
|
||||
// Process EOF PDU
|
||||
auto constAccessorPair = fp.tcStore->getData(info.storeId);
|
||||
if (constAccessorPair.first != OK) {
|
||||
// TODO: This is not a CFDP error. Event and/or warning?
|
||||
return constAccessorPair.first;
|
||||
}
|
||||
EofInfo eofInfo(nullptr);
|
||||
EofPduReader reader(constAccessorPair.second.data(), constAccessorPair.second.size(), eofInfo);
|
||||
ReturnValue_t result = reader.parseData();
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
// TODO: Error handling
|
||||
if (eofInfo.getConditionCode() == ConditionCode::NO_ERROR) {
|
||||
tp.crc = eofInfo.getChecksum();
|
||||
uint64_t fileSizeFromEof = eofInfo.getFileSize().value();
|
||||
// CFDP 4.6.1.2.9: Declare file size error if progress exceeds file size
|
||||
if (fileSizeFromEof > tp.progress) {
|
||||
// TODO: File size error
|
||||
}
|
||||
tp.fileSize.setFileSize(fileSizeFromEof, std::nullopt);
|
||||
}
|
||||
if (dp.cfg.indicCfg.eofRecvIndicRequired) {
|
||||
dp.user.eofRecvIndication(getTransactionId());
|
||||
}
|
||||
if (fsmRes.step == TransactionStep::RECEIVING_FILE_DATA_PDUS) {
|
||||
if (fsmRes.state == CfdpStates::BUSY_CLASS_1_NACKED) {
|
||||
fsmRes.step = TransactionStep::TRANSFER_COMPLETION;
|
||||
} else if (fsmRes.state == CfdpStates::BUSY_CLASS_2_ACKED) {
|
||||
fsmRes.step = TransactionStep::SENDING_ACK_PDU;
|
||||
}
|
||||
}
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::handleMetadataParseError(ReturnValue_t result,
|
||||
const uint8_t* rawData, size_t maxSize) {
|
||||
// TODO: try to extract destination ID for error
|
||||
// TODO: Invalid metadata PDU.
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "Parsing Metadata PDU failed with code " << result << std::endl;
|
||||
#else
|
||||
#endif
|
||||
PduHeaderReader headerReader(rawData, maxSize);
|
||||
result = headerReader.parseData();
|
||||
if (result != OK) {
|
||||
// TODO: Now this really should not happen. Warning or error,
|
||||
// yield or cache appropriate returnvalue
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "Parsing Header failed" << std::endl;
|
||||
#else
|
||||
#endif
|
||||
// TODO: Trigger appropriate event
|
||||
return result;
|
||||
}
|
||||
cfdp::EntityId destId;
|
||||
headerReader.getDestId(destId);
|
||||
RemoteEntityCfg* remoteCfg;
|
||||
if (not dp.remoteCfgTable.getRemoteCfg(destId, &remoteCfg)) {
|
||||
// TODO: No remote config for dest ID. I consider this a configuration error, which is not
|
||||
// covered by the standard.
|
||||
// Warning or error, yield or cache appropriate returnvalue
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "No remote config exists for destination ID" << std::endl;
|
||||
#else
|
||||
#endif
|
||||
// TODO: Trigger appropriate event
|
||||
}
|
||||
// TODO: Appropriate returnvalue?
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::startTransaction(MetadataPduReader& reader, MetadataInfo& info) {
|
||||
if (fsmRes.state != CfdpStates::IDLE) {
|
||||
// According to standard, discard metadata PDU if we are busy
|
||||
return OK;
|
||||
}
|
||||
ReturnValue_t result = OK;
|
||||
fsmRes.step = TransactionStep::TRANSACTION_START;
|
||||
if (reader.getTransmissionMode() == TransmissionMode::UNACKNOWLEDGED) {
|
||||
fsmRes.state = CfdpStates::BUSY_CLASS_1_NACKED;
|
||||
} else if (reader.getTransmissionMode() == TransmissionMode::ACKNOWLEDGED) {
|
||||
fsmRes.state = CfdpStates::BUSY_CLASS_2_ACKED;
|
||||
}
|
||||
tp.checksumType = info.getChecksumType();
|
||||
tp.closureRequested = info.isClosureRequested();
|
||||
size_t sourceNameSize = 0;
|
||||
const uint8_t* sourceNamePtr = info.getSourceFileName().getValue(&sourceNameSize);
|
||||
if (sourceNameSize > tp.sourceName.size()) {
|
||||
// TODO: Warning, event etc.
|
||||
return FAILED;
|
||||
}
|
||||
std::memcpy(tp.sourceName.data(), sourceNamePtr, sourceNameSize);
|
||||
tp.sourceName[sourceNameSize] = '\0';
|
||||
size_t destNameSize = 0;
|
||||
const uint8_t* destNamePtr = info.getDestFileName().getValue(&destNameSize);
|
||||
if (destNameSize > tp.destName.size()) {
|
||||
// TODO: Warning, event etc.
|
||||
return FAILED;
|
||||
}
|
||||
std::memcpy(tp.destName.data(), destNamePtr, destNameSize);
|
||||
tp.destName[destNameSize] = '\0';
|
||||
reader.fillConfig(tp.pduConf);
|
||||
tp.pduConf.direction = Direction::TOWARDS_SENDER;
|
||||
tp.transactionId.entityId = tp.pduConf.sourceId;
|
||||
tp.transactionId.seqNum = tp.pduConf.seqNum;
|
||||
if (not dp.remoteCfgTable.getRemoteCfg(tp.pduConf.sourceId, &tp.remoteCfg)) {
|
||||
// TODO: Warning, event etc.
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "cfdp::DestHandler" << __func__
|
||||
<< ": No remote configuration found for destination ID "
|
||||
<< tp.pduConf.sourceId.getValue() << std::endl;
|
||||
#endif
|
||||
return FAILED;
|
||||
}
|
||||
// If both dest name size and source name size are 0, we are dealing with a metadata only PDU,
|
||||
// so there is no need to create a file or truncate an existing file
|
||||
if (destNameSize > 0 and sourceNameSize > 0) {
|
||||
FilesystemParams fparams(tp.destName.data());
|
||||
// TODO: Filesystem errors?
|
||||
if (dp.user.vfs.fileExists(fparams)) {
|
||||
dp.user.vfs.truncateFile(fparams);
|
||||
} else {
|
||||
result = dp.user.vfs.createFile(fparams);
|
||||
if (result != OK) {
|
||||
// TODO: Handle FS error. This is probably a case for the filestore rejection mechanism of
|
||||
// CFDP.
|
||||
// In any case, it does not really make sense to continue here
|
||||
}
|
||||
}
|
||||
}
|
||||
fsmRes.step = TransactionStep::RECEIVING_FILE_DATA_PDUS;
|
||||
MetadataRecvdParams params(tp.transactionId, tp.pduConf.sourceId);
|
||||
params.fileSize = tp.fileSize.getSize();
|
||||
params.destFileName = tp.destName.data();
|
||||
params.sourceFileName = tp.sourceName.data();
|
||||
params.msgsToUserArray = dynamic_cast<MessageToUserTlv*>(userTlvVec.data());
|
||||
params.msgsToUserLen = info.getOptionsLen();
|
||||
dp.user.metadataRecvdIndication(params);
|
||||
return result;
|
||||
}
|
||||
|
||||
cfdp::CfdpStates cfdp::DestHandler::getCfdpState() const { return fsmRes.state; }
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::handleTransferCompletion() {
|
||||
ReturnValue_t result;
|
||||
if (tp.checksumType != ChecksumType::NULL_CHECKSUM) {
|
||||
result = checksumVerification();
|
||||
if (result != OK) {
|
||||
// TODO: Warning / error handling?
|
||||
}
|
||||
} else {
|
||||
tp.conditionCode = ConditionCode::NO_ERROR;
|
||||
}
|
||||
result = noticeOfCompletion();
|
||||
if (result != OK) {
|
||||
}
|
||||
if (fsmRes.state == CfdpStates::BUSY_CLASS_1_NACKED) {
|
||||
if (tp.closureRequested) {
|
||||
fsmRes.step = TransactionStep::SENDING_FINISHED_PDU;
|
||||
} else {
|
||||
finish();
|
||||
}
|
||||
} else if (fsmRes.state == CfdpStates::BUSY_CLASS_2_ACKED) {
|
||||
fsmRes.step = TransactionStep::SENDING_FINISHED_PDU;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
void cfdp::DestHandler::finish() {
|
||||
tp.reset();
|
||||
dp.packetListRef.clear();
|
||||
fsmRes.state = CfdpStates::IDLE;
|
||||
fsmRes.step = TransactionStep::IDLE;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::checksumVerification() {
|
||||
std::array<uint8_t, 1024> buf{};
|
||||
// TODO: Checksum verification and notice of completion
|
||||
etl::crc32 crcCalc;
|
||||
uint64_t currentOffset = 0;
|
||||
FileOpParams params(tp.destName.data(), tp.fileSize.value());
|
||||
while (currentOffset < tp.fileSize.value()) {
|
||||
uint64_t readLen;
|
||||
if (currentOffset + buf.size() > tp.fileSize.value()) {
|
||||
readLen = tp.fileSize.value() - currentOffset;
|
||||
} else {
|
||||
readLen = buf.size();
|
||||
}
|
||||
if (readLen > 0) {
|
||||
params.offset = currentOffset;
|
||||
params.size = readLen;
|
||||
auto result = dp.user.vfs.readFromFile(params, buf.data(), buf.size());
|
||||
if (result != OK) {
|
||||
// TODO: I think this is a case for a filestore rejection, but it might sense to print
|
||||
// a warning or trigger an event because this should generally not happen
|
||||
return FAILED;
|
||||
}
|
||||
crcCalc.add(buf.begin(), buf.begin() + readLen);
|
||||
}
|
||||
currentOffset += readLen;
|
||||
}
|
||||
|
||||
uint32_t value = crcCalc.value();
|
||||
if (value == tp.crc) {
|
||||
tp.conditionCode = ConditionCode::NO_ERROR;
|
||||
tp.deliveryCode = FileDeliveryCode::DATA_COMPLETE;
|
||||
} else {
|
||||
// TODO: Proper error handling
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "CRC check for file " << tp.destName.data() << " failed" << std::endl;
|
||||
#endif
|
||||
tp.conditionCode = ConditionCode::FILE_CHECKSUM_FAILURE;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::noticeOfCompletion() {
|
||||
if (dp.cfg.indicCfg.transactionFinishedIndicRequired) {
|
||||
TransactionFinishedParams params(tp.transactionId, tp.conditionCode, tp.deliveryCode,
|
||||
tp.deliveryStatus);
|
||||
dp.user.transactionFinishedIndication(params);
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::sendFinishedPdu() {
|
||||
FinishedInfo info(tp.conditionCode, tp.deliveryCode, tp.deliveryStatus);
|
||||
FinishPduCreator finishedPdu(tp.pduConf, info);
|
||||
store_address_t storeId;
|
||||
uint8_t* dataPtr = nullptr;
|
||||
ReturnValue_t result =
|
||||
fp.tcStore->getFreeElement(&storeId, finishedPdu.getSerializedSize(), &dataPtr);
|
||||
if (result != OK) {
|
||||
// TODO: Error handling and event, this is a non CFDP specific error (most likely store is full)
|
||||
return result;
|
||||
}
|
||||
size_t serLen = 0;
|
||||
result = finishedPdu.serialize(dataPtr, serLen, finishedPdu.getSerializedSize());
|
||||
if (result != OK) {
|
||||
// TODO: Error printout, this really should not happen
|
||||
return result;
|
||||
}
|
||||
TmTcMessage msg(storeId);
|
||||
result = fp.msgQueue->sendMessage(fp.packetDest.getReportReceptionQueue(), &msg);
|
||||
if (result != OK) {
|
||||
// TODO: Error handling and event, this is a non CFDP specific error (most likely store is full)
|
||||
return result;
|
||||
}
|
||||
fsmRes.packetsSent++;
|
||||
return OK;
|
||||
}
|
||||
|
||||
cfdp::DestHandler::TransactionStep cfdp::DestHandler::getTransactionStep() const {
|
||||
return fsmRes.step;
|
||||
}
|
||||
|
||||
const cfdp::DestHandler::FsmResult& cfdp::DestHandler::updateFsmRes(uint8_t errors) {
|
||||
fsmRes.errors = errors;
|
||||
fsmRes.result = OK;
|
||||
if (fsmRes.errors > 0) {
|
||||
fsmRes.result = FAILED;
|
||||
}
|
||||
return fsmRes;
|
||||
}
|
||||
|
||||
const cfdp::TransactionId& cfdp::DestHandler::getTransactionId() const { return tp.transactionId; }
|
||||
|
||||
void cfdp::DestHandler::checkAndHandleError(ReturnValue_t result, uint8_t& errorIdx) {
|
||||
if (result != OK and errorIdx < 3) {
|
||||
fsmRes.errorCodes[errorIdx] = result;
|
||||
errorIdx++;
|
||||
}
|
||||
}
|
||||
|
||||
void cfdp::DestHandler::setMsgQueue(MessageQueueIF& queue) { fp.msgQueue = &queue; }
|
||||
|
||||
void cfdp::DestHandler::setEventReporter(EventReportingProxyIF& reporter) {
|
||||
fp.eventReporter = &reporter;
|
||||
}
|
||||
|
||||
const cfdp::DestHandlerParams& cfdp::DestHandler::getDestHandlerParams() const { return dp; }
|
||||
|
||||
StorageManagerIF* cfdp::DestHandler::getTmStore() const { return fp.tmStore; }
|
||||
StorageManagerIF* cfdp::DestHandler::getTcStore() const { return fp.tcStore; }
|
202
src/fsfw/cfdp/handler/DestHandler.h
Normal file
202
src/fsfw/cfdp/handler/DestHandler.h
Normal file
@ -0,0 +1,202 @@
|
||||
#ifndef FSFW_CFDP_CFDPDESTHANDLER_H
|
||||
#define FSFW_CFDP_CFDPDESTHANDLER_H
|
||||
|
||||
#include <etl/list.h>
|
||||
#include <etl/set.h>
|
||||
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
|
||||
#include "RemoteConfigTableIF.h"
|
||||
#include "UserBase.h"
|
||||
#include "defs.h"
|
||||
#include "fsfw/cfdp/handler/mib.h"
|
||||
#include "fsfw/cfdp/pdu/MetadataPduReader.h"
|
||||
#include "fsfw/cfdp/pdu/PduConfig.h"
|
||||
#include "fsfw/container/DynamicFIFO.h"
|
||||
#include "fsfw/storagemanager/StorageManagerIF.h"
|
||||
#include "fsfw/storagemanager/storeAddress.h"
|
||||
#include "fsfw/tmtcservices/AcceptsTelemetryIF.h"
|
||||
|
||||
namespace cfdp {
|
||||
|
||||
struct PacketInfo {
|
||||
PacketInfo(PduType type, store_address_t storeId,
|
||||
std::optional<FileDirective> directive = std::nullopt)
|
||||
: pduType(type), directiveType(directive), storeId(storeId) {}
|
||||
|
||||
PduType pduType = PduType::FILE_DATA;
|
||||
std::optional<FileDirective> directiveType = FileDirective::INVALID_DIRECTIVE;
|
||||
store_address_t storeId = store_address_t::invalid();
|
||||
PacketInfo() = default;
|
||||
};
|
||||
|
||||
template <size_t SIZE>
|
||||
using LostSegmentsList = etl::set<etl::pair<uint64_t, uint64_t>, SIZE>;
|
||||
template <size_t SIZE>
|
||||
using PacketInfoList = etl::list<PacketInfo, SIZE>;
|
||||
using LostSegmentsListBase = etl::iset<etl::pair<uint64_t, uint64_t>>;
|
||||
using PacketInfoListBase = etl::ilist<PacketInfo>;
|
||||
|
||||
struct DestHandlerParams {
|
||||
DestHandlerParams(LocalEntityCfg cfg, UserBase& user, RemoteConfigTableIF& remoteCfgTable,
|
||||
PacketInfoListBase& packetList,
|
||||
// TODO: This container can potentially take tons of space. For a better
|
||||
// memory efficient implementation, an additional abstraction could be
|
||||
// be used so users can use uint32_t as the pair type
|
||||
LostSegmentsListBase& lostSegmentsContainer)
|
||||
: cfg(std::move(cfg)),
|
||||
user(user),
|
||||
remoteCfgTable(remoteCfgTable),
|
||||
packetListRef(packetList),
|
||||
lostSegmentsContainer(lostSegmentsContainer) {}
|
||||
|
||||
LocalEntityCfg cfg;
|
||||
UserBase& user;
|
||||
RemoteConfigTableIF& remoteCfgTable;
|
||||
|
||||
PacketInfoListBase& packetListRef;
|
||||
LostSegmentsListBase& lostSegmentsContainer;
|
||||
uint8_t maxTlvsInOnePdu = 10;
|
||||
size_t maxFilenameLen = 255;
|
||||
};
|
||||
|
||||
struct FsfwParams {
|
||||
FsfwParams(AcceptsTelemetryIF& packetDest, MessageQueueIF* msgQueue,
|
||||
EventReportingProxyIF* eventReporter, StorageManagerIF& tcStore,
|
||||
StorageManagerIF& tmStore)
|
||||
: FsfwParams(packetDest, msgQueue, eventReporter) {
|
||||
this->tcStore = &tcStore;
|
||||
this->tmStore = &tmStore;
|
||||
}
|
||||
|
||||
FsfwParams(AcceptsTelemetryIF& packetDest, MessageQueueIF* msgQueue,
|
||||
EventReportingProxyIF* eventReporter)
|
||||
: packetDest(packetDest), msgQueue(msgQueue), eventReporter(eventReporter) {}
|
||||
AcceptsTelemetryIF& packetDest;
|
||||
MessageQueueIF* msgQueue;
|
||||
EventReportingProxyIF* eventReporter = nullptr;
|
||||
StorageManagerIF* tcStore = nullptr;
|
||||
StorageManagerIF* tmStore = nullptr;
|
||||
};
|
||||
|
||||
enum class CallStatus { DONE, CALL_AFTER_DELAY, CALL_AGAIN };
|
||||
|
||||
class DestHandler {
|
||||
public:
|
||||
enum class TransactionStep {
|
||||
IDLE = 0,
|
||||
TRANSACTION_START = 1,
|
||||
RECEIVING_FILE_DATA_PDUS = 2,
|
||||
SENDING_ACK_PDU = 3,
|
||||
TRANSFER_COMPLETION = 4,
|
||||
SENDING_FINISHED_PDU = 5
|
||||
};
|
||||
|
||||
struct FsmResult {
|
||||
public:
|
||||
ReturnValue_t result = returnvalue::OK;
|
||||
CallStatus callStatus = CallStatus::CALL_AFTER_DELAY;
|
||||
TransactionStep step = TransactionStep::IDLE;
|
||||
CfdpStates state = CfdpStates::IDLE;
|
||||
uint32_t packetsSent = 0;
|
||||
uint8_t errors = 0;
|
||||
std::array<ReturnValue_t, 3> errorCodes = {};
|
||||
void resetOfIteration() {
|
||||
result = returnvalue::OK;
|
||||
callStatus = CallStatus::CALL_AFTER_DELAY;
|
||||
packetsSent = 0;
|
||||
errors = 0;
|
||||
errorCodes.fill(returnvalue::OK);
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Will be returned if it is advisable to call the state machine operation call again
|
||||
*/
|
||||
ReturnValue_t PARTIAL_SUCCESS = returnvalue::makeCode(0, 2);
|
||||
ReturnValue_t FAILURE = returnvalue::makeCode(0, 3);
|
||||
explicit DestHandler(DestHandlerParams handlerParams, FsfwParams fsfwParams);
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
* - @c returnvalue::OK State machine OK for this execution cycle
|
||||
* - @c CALL_FSM_AGAIN State machine should be called again.
|
||||
*/
|
||||
const FsmResult& performStateMachine();
|
||||
void setMsgQueue(MessageQueueIF& queue);
|
||||
void setEventReporter(EventReportingProxyIF& reporter);
|
||||
|
||||
ReturnValue_t passPacket(PacketInfo packet);
|
||||
|
||||
ReturnValue_t initialize();
|
||||
|
||||
[[nodiscard]] CfdpStates getCfdpState() const;
|
||||
[[nodiscard]] TransactionStep getTransactionStep() const;
|
||||
[[nodiscard]] const TransactionId& getTransactionId() const;
|
||||
[[nodiscard]] const DestHandlerParams& getDestHandlerParams() const;
|
||||
[[nodiscard]] StorageManagerIF* getTcStore() const;
|
||||
[[nodiscard]] StorageManagerIF* getTmStore() const;
|
||||
|
||||
private:
|
||||
struct TransactionParams {
|
||||
// Initialize char vectors with length + 1 for 0 termination
|
||||
explicit TransactionParams(size_t maxFileNameLen)
|
||||
: sourceName(maxFileNameLen + 1), destName(maxFileNameLen + 1) {}
|
||||
|
||||
void reset() {
|
||||
pduConf = PduConfig();
|
||||
transactionId = TransactionId();
|
||||
std::fill(sourceName.begin(), sourceName.end(), '\0');
|
||||
std::fill(destName.begin(), destName.end(), '\0');
|
||||
fileSize.setFileSize(0, false);
|
||||
conditionCode = ConditionCode::NO_ERROR;
|
||||
deliveryCode = FileDeliveryCode::DATA_INCOMPLETE;
|
||||
deliveryStatus = FileDeliveryStatus::DISCARDED_DELIBERATELY;
|
||||
crc = 0;
|
||||
progress = 0;
|
||||
remoteCfg = nullptr;
|
||||
closureRequested = false;
|
||||
checksumType = ChecksumType::NULL_CHECKSUM;
|
||||
}
|
||||
|
||||
ChecksumType checksumType = ChecksumType::NULL_CHECKSUM;
|
||||
bool closureRequested = false;
|
||||
std::vector<char> sourceName;
|
||||
std::vector<char> destName;
|
||||
cfdp::FileSize fileSize;
|
||||
TransactionId transactionId;
|
||||
PduConfig pduConf;
|
||||
ConditionCode conditionCode = ConditionCode::NO_ERROR;
|
||||
FileDeliveryCode deliveryCode = FileDeliveryCode::DATA_INCOMPLETE;
|
||||
FileDeliveryStatus deliveryStatus = FileDeliveryStatus::DISCARDED_DELIBERATELY;
|
||||
uint32_t crc = 0;
|
||||
uint64_t progress = 0;
|
||||
RemoteEntityCfg* remoteCfg = nullptr;
|
||||
};
|
||||
|
||||
std::vector<cfdp::Tlv> tlvVec;
|
||||
std::vector<cfdp::Tlv> userTlvVec;
|
||||
DestHandlerParams dp;
|
||||
FsfwParams fp;
|
||||
TransactionParams tp;
|
||||
FsmResult fsmRes;
|
||||
|
||||
ReturnValue_t startTransaction(MetadataPduReader& reader, MetadataInfo& info);
|
||||
ReturnValue_t handleMetadataPdu(const PacketInfo& info);
|
||||
ReturnValue_t handleFileDataPdu(const PacketInfo& info);
|
||||
ReturnValue_t handleEofPdu(const PacketInfo& info);
|
||||
ReturnValue_t handleMetadataParseError(ReturnValue_t result, const uint8_t* rawData,
|
||||
size_t maxSize);
|
||||
ReturnValue_t handleTransferCompletion();
|
||||
ReturnValue_t sendFinishedPdu();
|
||||
ReturnValue_t noticeOfCompletion();
|
||||
ReturnValue_t checksumVerification();
|
||||
const FsmResult& updateFsmRes(uint8_t errors);
|
||||
void checkAndHandleError(ReturnValue_t result, uint8_t& errorIdx);
|
||||
void finish();
|
||||
};
|
||||
|
||||
} // namespace cfdp
|
||||
|
||||
#endif // FSFW_CFDP_CFDPDESTHANDLER_H
|
51
src/fsfw/cfdp/handler/FaultHandlerBase.cpp
Normal file
51
src/fsfw/cfdp/handler/FaultHandlerBase.cpp
Normal file
@ -0,0 +1,51 @@
|
||||
#include "FaultHandlerBase.h"
|
||||
|
||||
namespace cfdp {
|
||||
|
||||
FaultHandlerBase::FaultHandlerBase() = default;
|
||||
FaultHandlerBase::~FaultHandlerBase() = default;
|
||||
|
||||
bool FaultHandlerBase::getFaultHandler(cfdp::ConditionCode code,
|
||||
cfdp::FaultHandlerCode& handler) const {
|
||||
auto iter = faultHandlerMap.find(code);
|
||||
if (iter == faultHandlerMap.end()) {
|
||||
return false;
|
||||
}
|
||||
handler = iter->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FaultHandlerBase::setFaultHandler(cfdp::ConditionCode code, cfdp::FaultHandlerCode handler) {
|
||||
if (not faultHandlerMap.contains(code)) {
|
||||
return false;
|
||||
}
|
||||
if (handler != FaultHandlerCode::NOTICE_OF_SUSPENSION and
|
||||
handler != FaultHandlerCode::ABANDON_TRANSACTION and
|
||||
handler != FaultHandlerCode::NOTICE_OF_CANCELLATION and
|
||||
handler != FaultHandlerCode::IGNORE_ERROR) {
|
||||
return false;
|
||||
}
|
||||
faultHandlerMap[code] = handler;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FaultHandlerBase::reportFault(cfdp::TransactionId& id, cfdp::ConditionCode code) {
|
||||
if (not faultHandlerMap.contains(code)) {
|
||||
return false;
|
||||
}
|
||||
cfdp::FaultHandlerCode fh = faultHandlerMap[code];
|
||||
if (fh == cfdp::FaultHandlerCode::IGNORE_ERROR) {
|
||||
ignoreCb(id, code);
|
||||
} else if (fh == cfdp::FaultHandlerCode::ABANDON_TRANSACTION) {
|
||||
abandonCb(id, code);
|
||||
} else if (fh == cfdp::FaultHandlerCode::NOTICE_OF_CANCELLATION) {
|
||||
noticeOfCancellationCb(id, code);
|
||||
} else if (fh == cfdp::FaultHandlerCode::NOTICE_OF_SUSPENSION) {
|
||||
noticeOfSuspensionCb(id, code);
|
||||
} else {
|
||||
// Should never happen, but use defensive programming
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} // namespace cfdp
|
77
src/fsfw/cfdp/handler/FaultHandlerBase.h
Normal file
77
src/fsfw/cfdp/handler/FaultHandlerBase.h
Normal file
@ -0,0 +1,77 @@
|
||||
#ifndef FSFW_CFDP_FAULTHANDLERBASE_H
|
||||
#define FSFW_CFDP_FAULTHANDLERBASE_H
|
||||
|
||||
#include <etl/flat_map.h>
|
||||
|
||||
#include "fsfw/cfdp/VarLenFields.h"
|
||||
#include "fsfw/cfdp/definitions.h"
|
||||
|
||||
namespace cfdp {
|
||||
|
||||
/**
|
||||
* @brief Provides a way to implement the fault handling procedures as specified
|
||||
* in chapter 4.8 of the CFDP standard.
|
||||
*
|
||||
* @details
|
||||
* It is passed into the CFDP handlers as part of the local entity configuration and provides
|
||||
* a way to specify custom user error handlers.
|
||||
*
|
||||
* It does so by mapping each applicable CFDP condition code to a fault handler which
|
||||
* is denoted by the four @cfdp::FaultHandlerCodes. This code is used to dispatch
|
||||
* to a user-provided callback function:
|
||||
*
|
||||
* 1. @FaultHandlerCodes::IGNORE_ERROR -> @ignore_cb
|
||||
* 2. @FaultHandlerCodes::NOTICE_OF_CANCELLATION` -> @notice_of_cancellation_cb
|
||||
* 3. @FaultHandlerCodes::NOTICE_OF_SUSPENSION` -> @notice_of_suspension_cb
|
||||
* 4. @FaultHandlerCodes::ABANDON_TRANSACTION` -> @abandon_transaction_cb
|
||||
*
|
||||
* For each error reported by @reportError, the appropriate fault handler callback
|
||||
* will be called. The user provides the callbacks by providing a custom class which implements
|
||||
* these base class and all abstract fault handler callbacks.
|
||||
*/
|
||||
class FaultHandlerBase {
|
||||
public:
|
||||
virtual ~FaultHandlerBase();
|
||||
FaultHandlerBase();
|
||||
|
||||
/**
|
||||
* Get the fault handler code for the given condition code
|
||||
* @param code
|
||||
* @param handler [out] Will be set to the approrpiate handler for the condition code if
|
||||
* it is valid
|
||||
* @return
|
||||
* - true if the condition code is valid
|
||||
* - false otherwise
|
||||
*/
|
||||
bool getFaultHandler(cfdp::ConditionCode code, cfdp::FaultHandlerCode& handler) const;
|
||||
|
||||
bool setFaultHandler(cfdp::ConditionCode code, cfdp::FaultHandlerCode handler);
|
||||
|
||||
bool reportFault(cfdp::TransactionId& id, cfdp::ConditionCode code);
|
||||
|
||||
virtual void noticeOfSuspensionCb(cfdp::TransactionId& id, cfdp::ConditionCode code) = 0;
|
||||
virtual void noticeOfCancellationCb(cfdp::TransactionId& id, cfdp::ConditionCode code) = 0;
|
||||
virtual void abandonCb(cfdp::TransactionId& id, cfdp::ConditionCode code) = 0;
|
||||
virtual void ignoreCb(cfdp::TransactionId& id, cfdp::ConditionCode code) = 0;
|
||||
|
||||
private:
|
||||
etl::flat_map<cfdp::ConditionCode, cfdp::FaultHandlerCode, 10> faultHandlerMap = {
|
||||
etl::pair{cfdp::ConditionCode::POSITIVE_ACK_LIMIT_REACHED,
|
||||
cfdp::FaultHandlerCode::IGNORE_ERROR},
|
||||
etl::pair{cfdp::ConditionCode::KEEP_ALIVE_LIMIT_REACHED,
|
||||
cfdp::FaultHandlerCode::IGNORE_ERROR},
|
||||
etl::pair{cfdp::ConditionCode::INVALID_TRANSMISSION_MODE,
|
||||
cfdp::FaultHandlerCode::IGNORE_ERROR},
|
||||
etl::pair{cfdp::ConditionCode::FILE_CHECKSUM_FAILURE, cfdp::FaultHandlerCode::IGNORE_ERROR},
|
||||
etl::pair{cfdp::ConditionCode::FILE_SIZE_ERROR, cfdp::FaultHandlerCode::IGNORE_ERROR},
|
||||
etl::pair{cfdp::ConditionCode::NAK_LIMIT_REACHED, cfdp::FaultHandlerCode::IGNORE_ERROR},
|
||||
etl::pair{cfdp::ConditionCode::INACTIVITY_DETECTED, cfdp::FaultHandlerCode::IGNORE_ERROR},
|
||||
etl::pair{cfdp::ConditionCode::UNSUPPORTED_CHECKSUM_TYPE,
|
||||
cfdp::FaultHandlerCode::IGNORE_ERROR},
|
||||
etl::pair{cfdp::ConditionCode::FILESTORE_REJECTION, cfdp::FaultHandlerCode::IGNORE_ERROR},
|
||||
etl::pair{cfdp::ConditionCode::CHECK_LIMIT_REACHED, cfdp::FaultHandlerCode::IGNORE_ERROR}};
|
||||
};
|
||||
|
||||
} // namespace cfdp
|
||||
|
||||
#endif // FSFW_CFDP_FAULTHANDLERBASE_H
|
35
src/fsfw/cfdp/handler/RemoteConfigTableIF.h
Normal file
35
src/fsfw/cfdp/handler/RemoteConfigTableIF.h
Normal file
@ -0,0 +1,35 @@
|
||||
#ifndef FSFW_CFDP_HANDLER_REMOTECONFIGTABLEIF_H
|
||||
#define FSFW_CFDP_HANDLER_REMOTECONFIGTABLEIF_H
|
||||
|
||||
#include "fsfw/cfdp/handler/mib.h"
|
||||
|
||||
namespace cfdp {
|
||||
|
||||
class RemoteConfigTableIF {
|
||||
public:
|
||||
virtual ~RemoteConfigTableIF() = default;
|
||||
virtual bool getRemoteCfg(const cfdp::EntityId& remoteId, cfdp::RemoteEntityCfg** cfg) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper class for the common case that there is exactly one remote entity
|
||||
*/
|
||||
class OneRemoteConfigProvider : public RemoteConfigTableIF {
|
||||
public:
|
||||
explicit OneRemoteConfigProvider(RemoteEntityCfg cfg) : cfg(std::move(cfg)) {}
|
||||
|
||||
bool getRemoteCfg(const EntityId& remoteId, cfdp::RemoteEntityCfg** cfg_) override {
|
||||
if (remoteId != cfg.remoteId) {
|
||||
return false;
|
||||
}
|
||||
*cfg_ = &cfg;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
RemoteEntityCfg cfg;
|
||||
};
|
||||
|
||||
} // namespace cfdp
|
||||
|
||||
#endif // FSFW_CFDP_HANDLER_REMOTECONFIGTABLEIF_H
|
1
src/fsfw/cfdp/handler/SourceHandler.cpp
Normal file
1
src/fsfw/cfdp/handler/SourceHandler.cpp
Normal file
@ -0,0 +1 @@
|
||||
#include "SourceHandler.h"
|
6
src/fsfw/cfdp/handler/SourceHandler.h
Normal file
6
src/fsfw/cfdp/handler/SourceHandler.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef FSFW_CFDP_CFDPSOURCEHANDLER_H
|
||||
#define FSFW_CFDP_CFDPSOURCEHANDLER_H
|
||||
|
||||
class SourceHandler {};
|
||||
|
||||
#endif // FSFW_CFDP_CFDPSOURCEHANDLER_H
|
12
src/fsfw/cfdp/handler/StatusReportIF.h
Normal file
12
src/fsfw/cfdp/handler/StatusReportIF.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef FSFW_CFDP_HANDLER_STATUSREPORTIF_H
|
||||
#define FSFW_CFDP_HANDLER_STATUSREPORTIF_H
|
||||
|
||||
namespace cfdp {
|
||||
|
||||
class StatusReportIF {
|
||||
virtual ~StatusReportIF() = default;
|
||||
};
|
||||
|
||||
} // namespace cfdp
|
||||
|
||||
#endif // FSFW_CFDP_HANDLER_STATUSREPORTIF_H
|
3
src/fsfw/cfdp/handler/UserBase.cpp
Normal file
3
src/fsfw/cfdp/handler/UserBase.cpp
Normal file
@ -0,0 +1,3 @@
|
||||
#include "UserBase.h"
|
||||
|
||||
cfdp::UserBase::UserBase(HasFileSystemIF& vfs) : vfs(vfs) {}
|
101
src/fsfw/cfdp/handler/UserBase.h
Normal file
101
src/fsfw/cfdp/handler/UserBase.h
Normal file
@ -0,0 +1,101 @@
|
||||
#ifndef FSFW_CFDP_USERBASE_H
|
||||
#define FSFW_CFDP_USERBASE_H
|
||||
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "StatusReportIF.h"
|
||||
#include "fsfw/cfdp/VarLenFields.h"
|
||||
#include "fsfw/cfdp/tlv/FilestoreResponseTlv.h"
|
||||
#include "fsfw/cfdp/tlv/MessageToUserTlv.h"
|
||||
#include "fsfw/filesystem/HasFileSystemIF.h"
|
||||
|
||||
namespace cfdp {
|
||||
|
||||
struct TransactionFinishedParams {
|
||||
TransactionFinishedParams(const TransactionId& id, ConditionCode code, FileDeliveryCode delivCode,
|
||||
FileDeliveryStatus status)
|
||||
: id(id), condCode(code), status(status), deliveryCode(delivCode) {}
|
||||
|
||||
const TransactionId& id;
|
||||
ConditionCode condCode;
|
||||
FileDeliveryStatus status;
|
||||
FileDeliveryCode deliveryCode;
|
||||
std::vector<FilestoreResponseTlv*> fsResponses;
|
||||
StatusReportIF* statusReport = nullptr;
|
||||
};
|
||||
|
||||
struct MetadataRecvdParams {
|
||||
MetadataRecvdParams(const TransactionId& id, const EntityId& sourceId)
|
||||
: id(id), sourceId(sourceId) {}
|
||||
const TransactionId& id;
|
||||
const EntityId& sourceId;
|
||||
uint64_t fileSize = 0;
|
||||
const char* sourceFileName = "";
|
||||
const char* destFileName = "";
|
||||
size_t msgsToUserLen = 0;
|
||||
const MessageToUserTlv* msgsToUserArray = nullptr;
|
||||
};
|
||||
|
||||
struct FileSegmentRecvdParams {
|
||||
TransactionId id;
|
||||
size_t offset;
|
||||
size_t length;
|
||||
std::optional<RecordContinuationState> recContState = std::nullopt;
|
||||
std::pair<const uint8_t*, size_t> segmentMetadata;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Base class which provides a user interface to interact with CFDP handlers.
|
||||
*
|
||||
* @details
|
||||
* This class is also used to pass the Virtual Filestore (VFS) Implementation to the CFDP
|
||||
* handlers so the filestore operations can be mapped to the underlying filestore.
|
||||
*
|
||||
* It is used by implementing it in a child class and then passing it to the CFDP
|
||||
* handler objects. The base class provides default implementation for the user indication
|
||||
* primitives specified in the CFDP standard. The user can override these implementations
|
||||
* to provide custom indication handlers.
|
||||
*
|
||||
* Please note that for all indication callbacks, the passed transaction ID reference will
|
||||
* become invalid shortly after the function has been executed. If the transaction ID is to be
|
||||
* cached or used, create an own copy of it.
|
||||
* @param vfs Virtual Filestore Object. Will be used for all file operations
|
||||
*/
|
||||
class UserBase {
|
||||
friend class DestHandler;
|
||||
|
||||
public:
|
||||
explicit UserBase(HasFileSystemIF& vfs);
|
||||
|
||||
virtual void transactionIndication(const TransactionId& id) = 0;
|
||||
virtual void eofSentIndication(const TransactionId& id) = 0;
|
||||
virtual void transactionFinishedIndication(const TransactionFinishedParams& params) = 0;
|
||||
/**
|
||||
* Will be called if metadata was received.
|
||||
*
|
||||
* IMPORTANT: The passed struct contains the messages to the user in form of a raw C array.
|
||||
* The TLVs in these arrays are zero-copy types, which means that they point to the raw data
|
||||
* inside the metadata packet directly. The metadata packet will be deleted from the TC store
|
||||
* shortly after it was processed. If some of the data is to be cached and/or used after the
|
||||
* function call, it needs to be copied into another user-provided buffer.
|
||||
* @param params
|
||||
*/
|
||||
virtual void metadataRecvdIndication(const MetadataRecvdParams& params) = 0;
|
||||
virtual void fileSegmentRecvdIndication(const FileSegmentRecvdParams& params) = 0;
|
||||
virtual void reportIndication(const TransactionId& id, StatusReportIF& report) = 0;
|
||||
virtual void suspendedIndication(const TransactionId& id, ConditionCode code) = 0;
|
||||
virtual void resumedIndication(const TransactionId& id, size_t progress) = 0;
|
||||
virtual void faultIndication(const TransactionId& id, ConditionCode code, size_t progress) = 0;
|
||||
virtual void abandonedIndication(const TransactionId& id, ConditionCode code,
|
||||
size_t progress) = 0;
|
||||
virtual void eofRecvIndication(const TransactionId& id) = 0;
|
||||
|
||||
private:
|
||||
HasFileSystemIF& vfs;
|
||||
};
|
||||
|
||||
} // namespace cfdp
|
||||
|
||||
#endif // FSFW_CFDP_USERBASE_H
|
9
src/fsfw/cfdp/handler/defs.h
Normal file
9
src/fsfw/cfdp/handler/defs.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef FSFW_CFDP_HANDLER_DEFS_H
|
||||
#define FSFW_CFDP_HANDLER_DEFS_H
|
||||
|
||||
namespace cfdp {
|
||||
|
||||
enum class CfdpStates { IDLE, BUSY_CLASS_1_NACKED, BUSY_CLASS_2_ACKED, SUSPENDED };
|
||||
|
||||
}
|
||||
#endif // FSFW_CFDP_HANDLER_DEFS_H
|
42
src/fsfw/cfdp/handler/mib.h
Normal file
42
src/fsfw/cfdp/handler/mib.h
Normal file
@ -0,0 +1,42 @@
|
||||
#ifndef FSFW_CFDP_MIB_H
|
||||
#define FSFW_CFDP_MIB_H
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "FaultHandlerBase.h"
|
||||
#include "fsfw/cfdp/pdu/PduConfig.h"
|
||||
|
||||
namespace cfdp {
|
||||
|
||||
struct IndicationCfg {
|
||||
bool eofSentIndicRequired = true;
|
||||
bool eofRecvIndicRequired = true;
|
||||
bool fileSegmentRecvIndicRequired = true;
|
||||
bool transactionFinishedIndicRequired = true;
|
||||
bool suspendedIndicRequired = true;
|
||||
bool resumedIndicRequired = true;
|
||||
};
|
||||
|
||||
struct LocalEntityCfg {
|
||||
LocalEntityCfg(EntityId localId, IndicationCfg indicationCfg, FaultHandlerBase& fhBase)
|
||||
: localId(std::move(localId)), indicCfg(indicationCfg), fhBase(fhBase) {}
|
||||
|
||||
EntityId localId;
|
||||
IndicationCfg indicCfg;
|
||||
FaultHandlerBase& fhBase;
|
||||
};
|
||||
|
||||
struct RemoteEntityCfg {
|
||||
explicit RemoteEntityCfg(EntityId id) : remoteId(std::move(id)) {}
|
||||
EntityId remoteId;
|
||||
size_t maxFileSegmentLen = 2048;
|
||||
bool closureRequested = false;
|
||||
bool crcOnTransmission = false;
|
||||
TransmissionMode defaultTransmissionMode = TransmissionMode::UNACKNOWLEDGED;
|
||||
ChecksumType defaultChecksum = ChecksumType::NULL_CHECKSUM;
|
||||
const uint8_t version = CFDP_VERSION_2;
|
||||
};
|
||||
|
||||
} // namespace cfdp
|
||||
|
||||
#endif // FSFW_CFDP_MIB_H
|
50
src/fsfw/cfdp/helpers.cpp
Normal file
50
src/fsfw/cfdp/helpers.cpp
Normal file
@ -0,0 +1,50 @@
|
||||
#include "helpers.h"
|
||||
|
||||
const char* COND_CODE_STRINGS[14] = {"Unknown",
|
||||
"No Error",
|
||||
"Positive ACK Limit Reached",
|
||||
"Keep Alive Limit Reached",
|
||||
"Invalid Transmission Mode",
|
||||
"Filestore Rejection",
|
||||
"File Checksum Failure",
|
||||
"File Size Error",
|
||||
"NAK limit reached",
|
||||
"Inactivity Detected",
|
||||
"Check Limit Reached",
|
||||
"Unsupported Checksum Type",
|
||||
"Suspend Request Received",
|
||||
"Cancel Request Received"};
|
||||
|
||||
const char* cfdp::getConditionCodeString(cfdp::ConditionCode code) {
|
||||
switch (code) {
|
||||
case NO_CONDITION_FIELD:
|
||||
return COND_CODE_STRINGS[0];
|
||||
case NO_ERROR:
|
||||
return COND_CODE_STRINGS[1];
|
||||
case POSITIVE_ACK_LIMIT_REACHED:
|
||||
return COND_CODE_STRINGS[2];
|
||||
case KEEP_ALIVE_LIMIT_REACHED:
|
||||
return COND_CODE_STRINGS[3];
|
||||
case INVALID_TRANSMISSION_MODE:
|
||||
return COND_CODE_STRINGS[4];
|
||||
case FILESTORE_REJECTION:
|
||||
return COND_CODE_STRINGS[5];
|
||||
case FILE_CHECKSUM_FAILURE:
|
||||
return COND_CODE_STRINGS[6];
|
||||
case FILE_SIZE_ERROR:
|
||||
return COND_CODE_STRINGS[7];
|
||||
case NAK_LIMIT_REACHED:
|
||||
return COND_CODE_STRINGS[8];
|
||||
case INACTIVITY_DETECTED:
|
||||
return COND_CODE_STRINGS[9];
|
||||
case CHECK_LIMIT_REACHED:
|
||||
return COND_CODE_STRINGS[10];
|
||||
case UNSUPPORTED_CHECKSUM_TYPE:
|
||||
return COND_CODE_STRINGS[11];
|
||||
case SUSPEND_REQUEST_RECEIVED:
|
||||
return COND_CODE_STRINGS[12];
|
||||
case CANCEL_REQUEST_RECEIVED:
|
||||
return COND_CODE_STRINGS[13];
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
11
src/fsfw/cfdp/helpers.h
Normal file
11
src/fsfw/cfdp/helpers.h
Normal file
@ -0,0 +1,11 @@
|
||||
#ifndef FSFW_EXAMPLE_HOSTED_HELPER_H
|
||||
#define FSFW_EXAMPLE_HOSTED_HELPER_H
|
||||
|
||||
#include "definitions.h"
|
||||
|
||||
namespace cfdp {
|
||||
|
||||
const char* getConditionCodeString(cfdp::ConditionCode code);
|
||||
|
||||
}
|
||||
#endif // FSFW_EXAMPLE_HOSTED_HELPER_H
|
@ -1,12 +1,12 @@
|
||||
#include "AckInfo.h"
|
||||
|
||||
AckInfo::AckInfo(cfdp::FileDirectives ackedDirective, cfdp::ConditionCode ackedConditionCode,
|
||||
AckInfo::AckInfo(cfdp::FileDirective ackedDirective, cfdp::ConditionCode ackedConditionCode,
|
||||
cfdp::AckTransactionStatus transactionStatus, uint8_t directiveSubtypeCode)
|
||||
: ackedDirective(ackedDirective),
|
||||
ackedConditionCode(ackedConditionCode),
|
||||
transactionStatus(transactionStatus),
|
||||
directiveSubtypeCode(directiveSubtypeCode) {
|
||||
if (ackedDirective == cfdp::FileDirectives::FINISH) {
|
||||
if (ackedDirective == cfdp::FileDirective::FINISH) {
|
||||
this->directiveSubtypeCode = 0b0001;
|
||||
} else {
|
||||
this->directiveSubtypeCode = 0b0000;
|
||||
@ -17,16 +17,16 @@ cfdp::ConditionCode AckInfo::getAckedConditionCode() const { return ackedConditi
|
||||
|
||||
void AckInfo::setAckedConditionCode(cfdp::ConditionCode ackedConditionCode) {
|
||||
this->ackedConditionCode = ackedConditionCode;
|
||||
if (ackedDirective == cfdp::FileDirectives::FINISH) {
|
||||
if (ackedDirective == cfdp::FileDirective::FINISH) {
|
||||
this->directiveSubtypeCode = 0b0001;
|
||||
} else {
|
||||
this->directiveSubtypeCode = 0b0000;
|
||||
}
|
||||
}
|
||||
|
||||
cfdp::FileDirectives AckInfo::getAckedDirective() const { return ackedDirective; }
|
||||
cfdp::FileDirective AckInfo::getAckedDirective() const { return ackedDirective; }
|
||||
|
||||
void AckInfo::setAckedDirective(cfdp::FileDirectives ackedDirective) {
|
||||
void AckInfo::setAckedDirective(cfdp::FileDirective ackedDirective) {
|
||||
this->ackedDirective = ackedDirective;
|
||||
}
|
||||
|
||||
|
@ -6,14 +6,14 @@
|
||||
class AckInfo {
|
||||
public:
|
||||
AckInfo();
|
||||
AckInfo(cfdp::FileDirectives ackedDirective, cfdp::ConditionCode ackedConditionCode,
|
||||
AckInfo(cfdp::FileDirective ackedDirective, cfdp::ConditionCode ackedConditionCode,
|
||||
cfdp::AckTransactionStatus transactionStatus, uint8_t directiveSubtypeCode = 0);
|
||||
|
||||
cfdp::ConditionCode getAckedConditionCode() const;
|
||||
void setAckedConditionCode(cfdp::ConditionCode ackedConditionCode);
|
||||
|
||||
cfdp::FileDirectives getAckedDirective() const;
|
||||
void setAckedDirective(cfdp::FileDirectives ackedDirective);
|
||||
cfdp::FileDirective getAckedDirective() const;
|
||||
void setAckedDirective(cfdp::FileDirective ackedDirective);
|
||||
|
||||
uint8_t getDirectiveSubtypeCode() const;
|
||||
void setDirectiveSubtypeCode(uint8_t directiveSubtypeCode);
|
||||
@ -22,7 +22,7 @@ class AckInfo {
|
||||
void setTransactionStatus(cfdp::AckTransactionStatus transactionStatus);
|
||||
|
||||
private:
|
||||
cfdp::FileDirectives ackedDirective = cfdp::FileDirectives::INVALID_DIRECTIVE;
|
||||
cfdp::FileDirective ackedDirective = cfdp::FileDirective::INVALID_DIRECTIVE;
|
||||
cfdp::ConditionCode ackedConditionCode = cfdp::ConditionCode::NO_CONDITION_FIELD;
|
||||
cfdp::AckTransactionStatus transactionStatus = cfdp::AckTransactionStatus::UNDEFINED;
|
||||
uint8_t directiveSubtypeCode = 0;
|
||||
|
33
src/fsfw/cfdp/pdu/AckPduCreator.cpp
Normal file
33
src/fsfw/cfdp/pdu/AckPduCreator.cpp
Normal file
@ -0,0 +1,33 @@
|
||||
#include "AckPduCreator.h"
|
||||
|
||||
AckPduCreator::AckPduCreator(AckInfo &ackInfo, PduConfig &pduConf)
|
||||
: FileDirectiveCreator(pduConf, cfdp::FileDirective::ACK, 2), ackInfo(ackInfo) {}
|
||||
|
||||
size_t AckPduCreator::getSerializedSize() const { return FileDirectiveCreator::getWholePduSize(); }
|
||||
|
||||
ReturnValue_t AckPduCreator::serialize(uint8_t **buffer, size_t *size, size_t maxSize,
|
||||
Endianness streamEndianness) const {
|
||||
ReturnValue_t result = FileDirectiveCreator::serialize(buffer, size, maxSize, streamEndianness);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
cfdp::FileDirective ackedDirective = ackInfo.getAckedDirective();
|
||||
uint8_t directiveSubtypeCode = ackInfo.getDirectiveSubtypeCode();
|
||||
cfdp::ConditionCode ackedConditionCode = ackInfo.getAckedConditionCode();
|
||||
cfdp::AckTransactionStatus transactionStatus = ackInfo.getTransactionStatus();
|
||||
if (ackedDirective != cfdp::FileDirective::FINISH and
|
||||
ackedDirective != cfdp::FileDirective::EOF_DIRECTIVE) {
|
||||
// TODO: better returncode
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
if (*size + 2 > maxSize) {
|
||||
return SerializeIF::BUFFER_TOO_SHORT;
|
||||
}
|
||||
**buffer = ackedDirective << 4 | directiveSubtypeCode;
|
||||
*buffer += 1;
|
||||
*size += 1;
|
||||
**buffer = ackedConditionCode << 4 | transactionStatus;
|
||||
*buffer += 1;
|
||||
*size += 1;
|
||||
return returnvalue::OK;
|
||||
}
|
@ -1,11 +1,11 @@
|
||||
#ifndef FSFW_SRC_FSFW_CFDP_PDU_ACKPDUSERIALIZER_H_
|
||||
#define FSFW_SRC_FSFW_CFDP_PDU_ACKPDUSERIALIZER_H_
|
||||
#ifndef FSFW_CFDP_PDU_ACKPDUSERIALIZER_H_
|
||||
#define FSFW_CFDP_PDU_ACKPDUSERIALIZER_H_
|
||||
|
||||
#include "AckInfo.h"
|
||||
#include "FileDirectiveDeserializer.h"
|
||||
#include "FileDirectiveSerializer.h"
|
||||
#include "FileDirectiveCreator.h"
|
||||
#include "FileDirectiveReader.h"
|
||||
|
||||
class AckPduSerializer : public FileDirectiveSerializer {
|
||||
class AckPduCreator : public FileDirectiveCreator {
|
||||
public:
|
||||
/**
|
||||
* @brief Serializer to pack ACK PDUs
|
||||
@ -16,9 +16,9 @@ class AckPduSerializer : public FileDirectiveSerializer {
|
||||
* @param transactionStatus
|
||||
* @param pduConf
|
||||
*/
|
||||
AckPduSerializer(AckInfo& ackInfo, PduConfig& pduConf);
|
||||
AckPduCreator(AckInfo& ackInfo, PduConfig& pduConf);
|
||||
|
||||
size_t getSerializedSize() const override;
|
||||
[[nodiscard]] size_t getSerializedSize() const override;
|
||||
|
||||
ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
||||
Endianness streamEndianness) const override;
|
||||
@ -27,4 +27,4 @@ class AckPduSerializer : public FileDirectiveSerializer {
|
||||
AckInfo& ackInfo;
|
||||
};
|
||||
|
||||
#endif /* FSFW_SRC_FSFW_CFDP_PDU_ACKPDUSERIALIZER_H_ */
|
||||
#endif /* FSFW_CFDP_PDU_ACKPDUSERIALIZER_H_ */
|
@ -1,37 +0,0 @@
|
||||
#include "AckPduDeserializer.h"
|
||||
|
||||
AckPduDeserializer::AckPduDeserializer(const uint8_t* pduBuf, size_t maxSize, AckInfo& info)
|
||||
: FileDirectiveDeserializer(pduBuf, maxSize), info(info) {}
|
||||
|
||||
ReturnValue_t AckPduDeserializer::parseData() {
|
||||
ReturnValue_t result = FileDirectiveDeserializer::parseData();
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
size_t currentIdx = FileDirectiveDeserializer::getHeaderSize();
|
||||
if (currentIdx + 2 > this->maxSize) {
|
||||
return SerializeIF::BUFFER_TOO_SHORT;
|
||||
}
|
||||
if (not checkAndSetCodes(rawPtr[currentIdx], rawPtr[currentIdx + 1])) {
|
||||
return cfdp::INVALID_ACK_DIRECTIVE_FIELDS;
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
bool AckPduDeserializer::checkAndSetCodes(uint8_t firstByte, uint8_t secondByte) {
|
||||
uint8_t ackedDirective = static_cast<cfdp::FileDirectives>(firstByte >> 4);
|
||||
|
||||
if (ackedDirective != cfdp::FileDirectives::EOF_DIRECTIVE and
|
||||
ackedDirective != cfdp::FileDirectives::FINISH) {
|
||||
return false;
|
||||
}
|
||||
this->info.setAckedDirective(static_cast<cfdp::FileDirectives>(ackedDirective));
|
||||
uint8_t directiveSubtypeCode = firstByte & 0x0f;
|
||||
if (directiveSubtypeCode != 0b0000 and directiveSubtypeCode != 0b0001) {
|
||||
return false;
|
||||
}
|
||||
this->info.setDirectiveSubtypeCode(directiveSubtypeCode);
|
||||
this->info.setAckedConditionCode(static_cast<cfdp::ConditionCode>(secondByte >> 4));
|
||||
this->info.setTransactionStatus(static_cast<cfdp::AckTransactionStatus>(secondByte & 0x0f));
|
||||
return true;
|
||||
}
|
45
src/fsfw/cfdp/pdu/AckPduReader.cpp
Normal file
45
src/fsfw/cfdp/pdu/AckPduReader.cpp
Normal file
@ -0,0 +1,45 @@
|
||||
#include "AckPduReader.h"
|
||||
|
||||
AckPduReader::AckPduReader(const uint8_t* pduBuf, size_t maxSize, AckInfo& info)
|
||||
: FileDirectiveReader(pduBuf, maxSize), info(info) {}
|
||||
|
||||
ReturnValue_t AckPduReader::parseData() {
|
||||
ReturnValue_t result = FileDirectiveReader::parseData();
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
size_t currentIdx = FileDirectiveReader::getHeaderSize();
|
||||
if (currentIdx + 2 > this->maxSize) {
|
||||
return SerializeIF::BUFFER_TOO_SHORT;
|
||||
}
|
||||
if (not checkAndSetCodes(pointers.rawPtr[currentIdx], pointers.rawPtr[currentIdx + 1])) {
|
||||
return cfdp::INVALID_ACK_DIRECTIVE_FIELDS;
|
||||
}
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
bool AckPduReader::checkAndSetCodes(uint8_t firstByte, uint8_t secondByte) {
|
||||
cfdp::FileDirective directive;
|
||||
if (not checkAckedDirectiveField(firstByte, directive)) {
|
||||
return false;
|
||||
}
|
||||
this->info.setAckedDirective(directive);
|
||||
uint8_t directiveSubtypeCode = firstByte & 0x0f;
|
||||
if (directiveSubtypeCode != 0b0000 and directiveSubtypeCode != 0b0001) {
|
||||
return false;
|
||||
}
|
||||
this->info.setDirectiveSubtypeCode(directiveSubtypeCode);
|
||||
this->info.setAckedConditionCode(static_cast<cfdp::ConditionCode>(secondByte >> 4));
|
||||
this->info.setTransactionStatus(static_cast<cfdp::AckTransactionStatus>(secondByte & 0x0f));
|
||||
return true;
|
||||
}
|
||||
bool AckPduReader::checkAckedDirectiveField(uint8_t firstPduDataByte,
|
||||
cfdp::FileDirective& ackedDirective) {
|
||||
uint8_t ackedDirectiveRaw = static_cast<cfdp::FileDirective>(firstPduDataByte >> 4);
|
||||
if (ackedDirectiveRaw != cfdp::FileDirective::EOF_DIRECTIVE and
|
||||
ackedDirectiveRaw != cfdp::FileDirective::FINISH) {
|
||||
return false;
|
||||
}
|
||||
ackedDirective = (static_cast<cfdp::FileDirective>(ackedDirectiveRaw));
|
||||
return true;
|
||||
}
|
@ -2,18 +2,21 @@
|
||||
#define FSFW_SRC_FSFW_CFDP_PDU_ACKPDUDESERIALIZER_H_
|
||||
|
||||
#include "AckInfo.h"
|
||||
#include "fsfw/cfdp/pdu/FileDirectiveDeserializer.h"
|
||||
#include "fsfw/cfdp/pdu/FileDirectiveReader.h"
|
||||
|
||||
class AckPduDeserializer : public FileDirectiveDeserializer {
|
||||
class AckPduReader : public FileDirectiveReader {
|
||||
public:
|
||||
AckPduDeserializer(const uint8_t* pduBuf, size_t maxSize, AckInfo& info);
|
||||
AckPduReader(const uint8_t* pduBuf, size_t maxSize, AckInfo& info);
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
* - cfdp::INVALID_DIRECTIVE_FIELDS: Invalid fields
|
||||
*/
|
||||
ReturnValue_t parseData();
|
||||
ReturnValue_t parseData() override;
|
||||
|
||||
static bool checkAckedDirectiveField(uint8_t firstPduDataByte,
|
||||
cfdp::FileDirective& ackedDirective);
|
||||
|
||||
private:
|
||||
bool checkAndSetCodes(uint8_t rawAckedByte, uint8_t rawAckedConditionCode);
|
@ -1,36 +0,0 @@
|
||||
#include "AckPduSerializer.h"
|
||||
|
||||
AckPduSerializer::AckPduSerializer(AckInfo &ackInfo, PduConfig &pduConf)
|
||||
: FileDirectiveSerializer(pduConf, cfdp::FileDirectives::ACK, 2), ackInfo(ackInfo) {}
|
||||
|
||||
size_t AckPduSerializer::getSerializedSize() const {
|
||||
return FileDirectiveSerializer::getWholePduSize();
|
||||
}
|
||||
|
||||
ReturnValue_t AckPduSerializer::serialize(uint8_t **buffer, size_t *size, size_t maxSize,
|
||||
Endianness streamEndianness) const {
|
||||
ReturnValue_t result =
|
||||
FileDirectiveSerializer::serialize(buffer, size, maxSize, streamEndianness);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
cfdp::FileDirectives ackedDirective = ackInfo.getAckedDirective();
|
||||
uint8_t directiveSubtypeCode = ackInfo.getDirectiveSubtypeCode();
|
||||
cfdp::ConditionCode ackedConditionCode = ackInfo.getAckedConditionCode();
|
||||
cfdp::AckTransactionStatus transactionStatus = ackInfo.getTransactionStatus();
|
||||
if (ackedDirective != cfdp::FileDirectives::FINISH and
|
||||
ackedDirective != cfdp::FileDirectives::EOF_DIRECTIVE) {
|
||||
// TODO: better returncode
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
if (*size + 2 > maxSize) {
|
||||
return SerializeIF::BUFFER_TOO_SHORT;
|
||||
}
|
||||
**buffer = ackedDirective << 4 | directiveSubtypeCode;
|
||||
*buffer += 1;
|
||||
*size += 1;
|
||||
**buffer = ackedConditionCode << 4 | transactionStatus;
|
||||
*buffer += 1;
|
||||
*size += 1;
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
@ -1,30 +1,29 @@
|
||||
target_sources(
|
||||
${LIB_FSFW_NAME}
|
||||
PRIVATE PduConfig.cpp
|
||||
VarLenField.cpp
|
||||
HeaderSerializer.cpp
|
||||
HeaderDeserializer.cpp
|
||||
FileDirectiveDeserializer.cpp
|
||||
FileDirectiveSerializer.cpp
|
||||
HeaderCreator.cpp
|
||||
HeaderReader.cpp
|
||||
FileDirectiveReader.cpp
|
||||
FileDirectiveCreator.cpp
|
||||
AckInfo.cpp
|
||||
AckPduSerializer.cpp
|
||||
AckPduDeserializer.cpp
|
||||
AckPduCreator.cpp
|
||||
AckPduReader.cpp
|
||||
EofInfo.cpp
|
||||
EofPduSerializer.cpp
|
||||
EofPduDeserializer.cpp
|
||||
EofPduCreator.cpp
|
||||
EofPduReader.cpp
|
||||
NakInfo.cpp
|
||||
NakPduSerializer.cpp
|
||||
NakPduDeserializer.cpp
|
||||
NakPduCreator.cpp
|
||||
NakPduReader.cpp
|
||||
FinishedInfo.cpp
|
||||
FinishedPduSerializer.cpp
|
||||
FinishedPduDeserializer.cpp
|
||||
FinishedPduCreator.cpp
|
||||
FinishedPduReader.cpp
|
||||
MetadataInfo.cpp
|
||||
MetadataPduSerializer.cpp
|
||||
MetadataPduDeserializer.cpp
|
||||
KeepAlivePduSerializer.cpp
|
||||
KeepAlivePduDeserializer.cpp
|
||||
PromptPduSerializer.cpp
|
||||
PromptPduDeserializer.cpp
|
||||
FileDataSerializer.cpp
|
||||
FileDataDeserializer.cpp
|
||||
MetadataPduCreator.cpp
|
||||
MetadataPduReader.cpp
|
||||
KeepAlivePduCreator.cpp
|
||||
KeepAlivePduReader.cpp
|
||||
PromptPduCreator.cpp
|
||||
PromptPduReader.cpp
|
||||
FileDataCreator.cpp
|
||||
FileDataReader.cpp
|
||||
FileDataInfo.cpp)
|
||||
|
@ -7,16 +7,16 @@
|
||||
|
||||
struct EofInfo {
|
||||
public:
|
||||
EofInfo(EntityIdTlv* faultLoc = nullptr);
|
||||
explicit EofInfo(EntityIdTlv* faultLoc = nullptr);
|
||||
EofInfo(cfdp::ConditionCode conditionCode, uint32_t checksum, cfdp::FileSize fileSize,
|
||||
EntityIdTlv* faultLoc = nullptr);
|
||||
|
||||
size_t getSerializedSize(bool fssLarge = false);
|
||||
|
||||
uint32_t getChecksum() const;
|
||||
cfdp::ConditionCode getConditionCode() const;
|
||||
[[nodiscard]] uint32_t getChecksum() const;
|
||||
[[nodiscard]] cfdp::ConditionCode getConditionCode() const;
|
||||
|
||||
EntityIdTlv* getFaultLoc() const;
|
||||
[[nodiscard]] EntityIdTlv* getFaultLoc() const;
|
||||
cfdp::FileSize& getFileSize();
|
||||
void setChecksum(uint32_t checksum);
|
||||
void setConditionCode(cfdp::ConditionCode conditionCode);
|
||||
|
@ -1,22 +1,18 @@
|
||||
#include "EofPduSerializer.h"
|
||||
#include "EofPduCreator.h"
|
||||
|
||||
#include "fsfw/FSFW.h"
|
||||
#include "fsfw/serviceinterface.h"
|
||||
|
||||
EofPduSerializer::EofPduSerializer(PduConfig &conf, EofInfo &info)
|
||||
: FileDirectiveSerializer(conf, cfdp::FileDirectives::EOF_DIRECTIVE, 9), info(info) {
|
||||
setDirectiveDataFieldLen(info.getSerializedSize(getLargeFileFlag()));
|
||||
EofPduCreator::EofPduCreator(PduConfig &conf, EofInfo &info)
|
||||
: FileDirectiveCreator(conf, cfdp::FileDirective::EOF_DIRECTIVE, 9), info(info) {
|
||||
setDirectiveDataFieldLen(info.getSerializedSize(HeaderCreator::getLargeFileFlag()));
|
||||
}
|
||||
|
||||
size_t EofPduSerializer::getSerializedSize() const {
|
||||
return FileDirectiveSerializer::getWholePduSize();
|
||||
}
|
||||
size_t EofPduCreator::getSerializedSize() const { return FileDirectiveCreator::getWholePduSize(); }
|
||||
|
||||
ReturnValue_t EofPduSerializer::serialize(uint8_t **buffer, size_t *size, size_t maxSize,
|
||||
Endianness streamEndianness) const {
|
||||
ReturnValue_t result =
|
||||
FileDirectiveSerializer::serialize(buffer, size, maxSize, streamEndianness);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
ReturnValue_t EofPduCreator::serialize(uint8_t **buffer, size_t *size, size_t maxSize,
|
||||
Endianness streamEndianness) const {
|
||||
ReturnValue_t result = FileDirectiveCreator::serialize(buffer, size, maxSize, streamEndianness);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
if (*size + 1 > maxSize) {
|
||||
@ -27,7 +23,7 @@ ReturnValue_t EofPduSerializer::serialize(uint8_t **buffer, size_t *size, size_t
|
||||
*size += 1;
|
||||
uint32_t checksum = info.getChecksum();
|
||||
result = SerializeAdapter::serialize(&checksum, buffer, size, maxSize, streamEndianness);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
if (info.getFileSize().isLargeFile()) {
|
@ -2,18 +2,20 @@
|
||||
#define FSFW_SRC_FSFW_CFDP_PDU_EOFPDUSERIALIZER_H_
|
||||
|
||||
#include "EofInfo.h"
|
||||
#include "fsfw/cfdp/pdu/FileDirectiveSerializer.h"
|
||||
#include "fsfw/cfdp/pdu/FileDirectiveCreator.h"
|
||||
#include "fsfw/cfdp/tlv/EntityIdTlv.h"
|
||||
|
||||
class EofPduSerializer : public FileDirectiveSerializer {
|
||||
class EofPduCreator : public FileDirectiveCreator {
|
||||
public:
|
||||
EofPduSerializer(PduConfig& conf, EofInfo& info);
|
||||
EofPduCreator(PduConfig& conf, EofInfo& info);
|
||||
|
||||
size_t getSerializedSize() const override;
|
||||
[[nodiscard]] size_t getSerializedSize() const override;
|
||||
|
||||
ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
||||
Endianness streamEndianness) const override;
|
||||
|
||||
using FileDirectiveCreator::serialize;
|
||||
|
||||
private:
|
||||
EofInfo& info;
|
||||
};
|
@ -1,17 +0,0 @@
|
||||
#ifndef FSFW_SRC_FSFW_CFDP_PDU_EOFPDUDESERIALIZER_H_
|
||||
#define FSFW_SRC_FSFW_CFDP_PDU_EOFPDUDESERIALIZER_H_
|
||||
|
||||
#include "EofInfo.h"
|
||||
#include "fsfw/cfdp/pdu/FileDirectiveDeserializer.h"
|
||||
|
||||
class EofPduDeserializer : public FileDirectiveDeserializer {
|
||||
public:
|
||||
EofPduDeserializer(const uint8_t* pduBuf, size_t maxSize, EofInfo& eofInfo);
|
||||
|
||||
virtual ReturnValue_t parseData() override;
|
||||
|
||||
private:
|
||||
EofInfo& info;
|
||||
};
|
||||
|
||||
#endif /* FSFW_SRC_FSFW_CFDP_PDU_EOFPDUDESERIALIZER_H_ */
|
@ -1,23 +1,23 @@
|
||||
#include "EofPduDeserializer.h"
|
||||
#include "EofPduReader.h"
|
||||
|
||||
#include "fsfw/FSFW.h"
|
||||
#include "fsfw/serviceinterface.h"
|
||||
|
||||
EofPduDeserializer::EofPduDeserializer(const uint8_t* pduBuf, size_t maxSize, EofInfo& eofInfo)
|
||||
: FileDirectiveDeserializer(pduBuf, maxSize), info(eofInfo) {}
|
||||
EofPduReader::EofPduReader(const uint8_t* pduBuf, size_t maxSize, EofInfo& eofInfo)
|
||||
: FileDirectiveReader(pduBuf, maxSize), info(eofInfo) {}
|
||||
|
||||
ReturnValue_t EofPduDeserializer::parseData() {
|
||||
ReturnValue_t result = FileDirectiveDeserializer::parseData();
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
ReturnValue_t EofPduReader::parseData() {
|
||||
ReturnValue_t result = FileDirectiveReader::parseData();
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
const uint8_t* bufPtr = rawPtr;
|
||||
const uint8_t* bufPtr = pointers.rawPtr;
|
||||
size_t expectedFileFieldLen = 4;
|
||||
if (this->getLargeFileFlag()) {
|
||||
expectedFileFieldLen = 8;
|
||||
}
|
||||
size_t currentIdx = FileDirectiveDeserializer::getHeaderSize();
|
||||
size_t currentIdx = FileDirectiveReader::getHeaderSize();
|
||||
size_t deserLen = maxSize;
|
||||
if (maxSize < currentIdx + 5 + expectedFileFieldLen) {
|
||||
return SerializeIF::STREAM_TOO_SHORT;
|
||||
@ -31,7 +31,7 @@ ReturnValue_t EofPduDeserializer::parseData() {
|
||||
uint32_t checksum = 0;
|
||||
auto endianness = getEndianness();
|
||||
result = SerializeAdapter::deSerialize(&checksum, &bufPtr, &deserLen, endianness);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
info.setChecksum(checksum);
|
||||
@ -44,7 +44,7 @@ ReturnValue_t EofPduDeserializer::parseData() {
|
||||
result = SerializeAdapter::deSerialize(&fileSizeValue, &bufPtr, &deserLen, endianness);
|
||||
info.setFileSize(fileSizeValue, false);
|
||||
}
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
if (info.getConditionCode() != cfdp::ConditionCode::NO_ERROR) {
|
||||
@ -61,7 +61,7 @@ ReturnValue_t EofPduDeserializer::parseData() {
|
||||
" given TLV pointer invalid");
|
||||
#endif
|
||||
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
result = tlvPtr->deSerialize(&bufPtr, &deserLen, endianness);
|
||||
}
|
17
src/fsfw/cfdp/pdu/EofPduReader.h
Normal file
17
src/fsfw/cfdp/pdu/EofPduReader.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef FSFW_SRC_FSFW_CFDP_PDU_EOFPDUDESERIALIZER_H_
|
||||
#define FSFW_SRC_FSFW_CFDP_PDU_EOFPDUDESERIALIZER_H_
|
||||
|
||||
#include "EofInfo.h"
|
||||
#include "fsfw/cfdp/pdu/FileDirectiveReader.h"
|
||||
|
||||
class EofPduReader : public FileDirectiveReader {
|
||||
public:
|
||||
EofPduReader(const uint8_t* pduBuf, size_t maxSize, EofInfo& eofInfo);
|
||||
|
||||
ReturnValue_t parseData() override;
|
||||
|
||||
private:
|
||||
EofInfo& info;
|
||||
};
|
||||
|
||||
#endif /* FSFW_SRC_FSFW_CFDP_PDU_EOFPDUDESERIALIZER_H_ */
|
@ -1,28 +1,31 @@
|
||||
#include "FileDataSerializer.h"
|
||||
#include "FileDataCreator.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
FileDataSerializer::FileDataSerializer(PduConfig& conf, FileDataInfo& info)
|
||||
: HeaderSerializer(conf, cfdp::PduType::FILE_DATA, 0, info.getSegmentMetadataFlag()),
|
||||
info(info) {
|
||||
FileDataCreator::FileDataCreator(PduConfig& conf, FileDataInfo& info)
|
||||
: HeaderCreator(conf, cfdp::PduType::FILE_DATA, 0, info.getSegmentMetadataFlag()), info(info) {
|
||||
update();
|
||||
}
|
||||
|
||||
void FileDataSerializer::update() {
|
||||
void FileDataCreator::update() {
|
||||
this->setSegmentMetadataFlag(info.getSegmentMetadataFlag());
|
||||
this->setSegmentationControl(info.getSegmentationControl());
|
||||
setPduDataFieldLen(info.getSerializedSize(this->getLargeFileFlag()));
|
||||
}
|
||||
|
||||
ReturnValue_t FileDataSerializer::serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
||||
Endianness streamEndianness) const {
|
||||
ReturnValue_t result = HeaderSerializer::serialize(buffer, size, maxSize, streamEndianness);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
ReturnValue_t FileDataCreator::serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
||||
Endianness streamEndianness) const {
|
||||
if (buffer == nullptr or size == nullptr) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
if (*size + this->getSerializedSize() > maxSize) {
|
||||
if (*size + getSerializedSize() > maxSize) {
|
||||
return SerializeIF::BUFFER_TOO_SHORT;
|
||||
}
|
||||
ReturnValue_t result = HeaderCreator::serialize(buffer, size, maxSize, streamEndianness);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
const uint8_t* readOnlyPtr = nullptr;
|
||||
if (this->hasSegmentMetadataFlag()) {
|
||||
size_t segmentMetadataLen = info.getSegmentMetadataLen();
|
||||
@ -36,7 +39,7 @@ ReturnValue_t FileDataSerializer::serialize(uint8_t** buffer, size_t* size, size
|
||||
}
|
||||
cfdp::FileSize& offset = info.getOffset();
|
||||
result = offset.serialize(this->getLargeFileFlag(), buffer, size, maxSize, streamEndianness);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
size_t fileSize = 0;
|
||||
@ -47,9 +50,9 @@ ReturnValue_t FileDataSerializer::serialize(uint8_t** buffer, size_t* size, size
|
||||
std::memcpy(*buffer, readOnlyPtr, fileSize);
|
||||
*buffer += fileSize;
|
||||
*size += fileSize;
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
size_t FileDataSerializer::getSerializedSize() const {
|
||||
return HeaderSerializer::getSerializedSize() + info.getSerializedSize(this->getLargeFileFlag());
|
||||
size_t FileDataCreator::getSerializedSize() const {
|
||||
return HeaderCreator::getSerializedSize() + info.getSerializedSize(this->getLargeFileFlag());
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user