Compare commits
2004 Commits
ASTP_1.0.0
...
master
Author | SHA1 | Date | |
---|---|---|---|
e73b9ff72c | |||
dc7afc5415 | |||
9bf3ff95b7 | |||
61562b18ab | |||
d76d97a36b | |||
76b377c4c0 | |||
3562bf11b9 | |||
fffb2b61e5 | |||
94e5f62331 | |||
0a9c563bbc | |||
fa7675897d | |||
3a2393885f | |||
c752b6d143 | |||
b676040c7c | |||
010509efb4 | |||
dfb1633f00 | |||
5f7172e130 | |||
0c6465cd95 | |||
f94987c46d | |||
1809ce359b | |||
8c712441ab | |||
f1b0ca7cff | |||
000df85556 | |||
1fffcc2229 | |||
a419806a05 | |||
6445debfa1 | |||
8014e4adf9 | |||
134d908f26 | |||
40a9e12416 | |||
f39054edd4 | |||
5adf89b911 | |||
c2e6a22dec | |||
c8e065a713 | |||
3ed49dbae3 | |||
4cf52d5dfe | |||
539d7aac9e | |||
0a23f2c85a | |||
46230e6c6d | |||
b22d439300 | |||
7e7b3bbbc9 | |||
5b92247fbd | |||
e2b66df72e | |||
d9da55fdab | |||
7b828f233a | |||
c3d1000cd5 | |||
8e0e57714d | |||
066f7a6f9b | |||
cc9e54ea6b | |||
31465a4e0f | |||
c0e5d1eb99 | |||
3bc5d4a2e0 | |||
b1e9dd9e4a | |||
ab86599db3 | |||
034eb34c2e | |||
4374c7c4f4 | |||
5343844be5 | |||
e300490b93 | |||
0f811777a7 | |||
e93137939e | |||
c1f42618db | |||
1f88c006d9 | |||
7e94baceef | |||
61df451dd8 | |||
29ea89044e | |||
e487f5be87 | |||
9b05e8f274 | |||
eb223dae88 | |||
3656662d88 | |||
fe71978467 | |||
b646717a76 | |||
99d8c845f2 | |||
0e7c6b117f | |||
d16c5024dc | |||
a4531e4ced | |||
97c629ad84 | |||
bf12f284fa | |||
ba62c28b64 | |||
7adb47aecb | |||
8589f4d63a | |||
ca80589233 | |||
f2ebaed092 | |||
f0b89e98df | |||
5557d95994 | |||
fc24c9b5d8 | |||
7ef69c839c | |||
9b798d798e | |||
b13453f46b | |||
d0e322d7e2 | |||
ecde164f68 | |||
50930b41ba | |||
d6ee2ed400 | |||
f2150ff9c2 | |||
1b9c98f3fe | |||
742152b28e | |||
bf4ca56658 | |||
16ffa00155 | |||
14c681c93a | |||
0958c3a00e | |||
d699d16307 | |||
3b0fed733f | |||
23d3812fe3 | |||
dec7db3ae2 | |||
65a5abab49 | |||
0129783e34 | |||
cabe0868ec | |||
f05295bada | |||
b85ca64690 | |||
3bc3da5a8d | |||
f8c07ec9cf | |||
8199b8f359 | |||
cbc8dbcdd4 | |||
d31a5306f0 | |||
a236a5ec50 | |||
03620970e2 | |||
8fe8d810e9 | |||
9483c2809d | |||
fe3d6bd432 | |||
2a842666d5 | |||
c013fcc1f5 | |||
1b8fc2af19 | |||
72d7c43445 | |||
ab9b6c8c89 | |||
69d338f9bb | |||
68223869d5 | |||
93fda71989 | |||
7b0db08962 | |||
0956fbc740 | |||
b48e0fdc0d | |||
1d084ee22f | |||
1bea2344f6 | |||
d7e16a67a7 | |||
6021d897b8 | |||
83a6f0b5f8 | |||
a9c6c088f2 | |||
b6a3c206cc | |||
5b352978c5 | |||
819a298b19 | |||
16246d6ece | |||
5c84f12440 | |||
83c2c4825c | |||
c913fe40bf | |||
70ec08bf1d | |||
ef23665d9c | |||
eefc122292 | |||
bee33526a1 | |||
f715b65d6e | |||
c11af63015 | |||
11a22577be | |||
dc1583c932 | |||
94f1f1f908 | |||
81a7de2814 | |||
d26f230bee | |||
4db124c680 | |||
955579c856 | |||
2df66c9304 | |||
54ad6b3016 | |||
73e313c35b | |||
c6585c8645 | |||
dd2f42d22b | |||
d8a4675842 | |||
1164c21ddd | |||
77b1a85b47 | |||
652c31a683 | |||
bfe120636c | |||
a8041f220f | |||
dd636b186b | |||
3349fc36f8 | |||
f3e9277e59 | |||
d592f1ecbc | |||
6ec18171a8 | |||
518dcdef4b | |||
d9730032fd | |||
b3ac72b7db | |||
cd0cb43412 | |||
32c12b3dbf | |||
3e9acf476e | |||
99101ce2bf | |||
6b991045f7 | |||
df06064df0 | |||
337cb0d6c9 | |||
c283e0c988 | |||
448d20f3bd | |||
2316728d74 | |||
6f562e5f3e | |||
176f243194 | |||
d964fa2107 | |||
7b5ae6a445 | |||
8e362a000c | |||
7877776e24 | |||
3de0ae5a48 | |||
e0c780f21c | |||
876815b1c9 | |||
b0ecf87580 | |||
68ce8b5b08 | |||
fe03da6def | |||
95ac53c417 | |||
62f638a3d2 | |||
bd64591f30 | |||
e6a877f048 | |||
ea8c557ee8 | |||
0bdd780f82 | |||
9ec397c8b7 | |||
c54d9d7ba6 | |||
30c03c110c | |||
69f1be263a | |||
c7b5309dcb | |||
775d5632de | |||
4f3361eb2b | |||
9e6c1d60e5 | |||
12d0c23c13 | |||
5c3bb13834 | |||
292fe3e5e4 | |||
33530f2819 | |||
c0000a8635 | |||
5488ee715f | |||
0fea22d031 | |||
3b8ca09299 | |||
9a2146fa2d | |||
558550ecb9 | |||
72172a972b | |||
b4b11ebd3b | |||
6f8ccf83e7 | |||
67f1cd0b5f | |||
54762232a4 | |||
2fee2fdff5 | |||
954c749de0 | |||
bcbbc9763a | |||
0042372cb6 | |||
8dea13742f | |||
0f027d29d2 | |||
131e3ff1e3 | |||
423a9540ed | |||
ce7146e468 | |||
a681a4a797 | |||
e585c1d84a | |||
83b7b8707c | |||
4002b74ea2 | |||
4f7f8310c9 | |||
1a833e2d45 | |||
8df6d934d7 | |||
5363868120 | |||
36cf59cc8e | |||
97fec909f2 | |||
1db77753e3 | |||
8501477a78 | |||
6eea711d9f | |||
9a181aa6a8 | |||
655c944c0e | |||
2e310fca8d | |||
37390dfc74 | |||
75ddfdc65d | |||
1efc0d2855 | |||
e063b44899 | |||
b3c0e24611 | |||
ab7c3480f5 | |||
237e29cc59 | |||
0849c8a08d | |||
9d626e0a5d | |||
723f8749d4 | |||
2e27a85c95 | |||
73f1917c81 | |||
3a52454949 | |||
ac7dc55fc1 | |||
389d804735 | |||
44615c150b | |||
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 | |||
c7f300671f | |||
7d3223d766 | |||
7ae82a5cb4 | |||
28ecd0e5c6 | |||
7345c18b04 | |||
0de7b66218 | |||
158007fa7f | |||
ab719a3e59 | |||
64a7fde301 | |||
9131ca688b | |||
8e6cee7761 | |||
c756297e5c | |||
0f27c7e7e7 | |||
20d42add03 | |||
a9277622ce | |||
80e8511a43 | |||
4a06f11582 | |||
32c53b932d | |||
aea9db75cb | |||
9fedd03ed8 | |||
10fc4dd89d | |||
0cc8af5eb0 | |||
92d65aa3a5 | |||
342a56410c | |||
2cab73d972 | |||
9a9085b9e6 | |||
cb23911ccd | |||
b499dedd76 | |||
1bb487373d | |||
3bffb4f968 | |||
6bcb208968 | |||
6c2b5ab39e | |||
a7039bad41 | |||
6605ffb6b1 | |||
e2e0190cae | |||
fd278e410b | |||
ff4cbea571 | |||
81a7c21cd1 | |||
267466be9d | |||
2c730c8632 | |||
eb29b79467 | |||
26ea6606bf | |||
b1bd631322 | |||
9441b4a70e | |||
95457b1760 | |||
a46d8c34d9 | |||
d12c59c8ac | |||
9e5dddf79c | |||
ba5c6410d6 | |||
52f8c5038b | |||
10f34e5a48 | |||
dab1b1d067 | |||
8c8d1cfa84 | |||
2a4ab0af7b | |||
7c59df3f1c | |||
3b33b429e6 | |||
ff6de8e378 | |||
11a699c3ce | |||
6930656d4e | |||
0bb82e0da2 | |||
12c452e7ce | |||
23f514039a | |||
2e52d7a31d | |||
239d053562 | |||
875174c4ad | |||
8fd8a37f59 | |||
217276d50c | |||
d2ac3603a5 | |||
f63f3fa564 | |||
fc34d56239 | |||
1037102349 | |||
221361eb9c | |||
7f9269b387 | |||
4224c3d009 | |||
62fe75ee40 | |||
e76e109bdb | |||
9e064fe800 | |||
2339c48756 | |||
d7ec04bf4b | |||
adcc375f25 | |||
94a718ff19 | |||
4a10f76784 | |||
57ce5d1f34 | |||
90963b3940 | |||
71ed95b09a | |||
7ac4f1c64d | |||
9d64b96e9a | |||
5de2c6af66 | |||
ca2efb6021 | |||
3b000d924a | |||
deeeef553b | |||
0e7ec79af9 | |||
d3cabd8984 | |||
8efe85cb15 | |||
b28c26b288 | |||
8b4253bc46 | |||
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 | |||
14bac9a418 | |||
3bef73708f | |||
fef6ddceff | |||
5a9db72814 | |||
5cccd5caba | |||
7de56f189b | |||
df97bbc691 | |||
2d2f65bf89 | |||
3e9ae62b28 | |||
2ebefdffae | |||
45792e86b9 | |||
541f563683 | |||
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 | |||
c7cf8e710d | |||
7dddcdfd55 | |||
261eea381e | |||
e59f1f26bf | |||
f7cde80088 | |||
e60a665de4 | |||
34658ef7db | |||
940fd6f465 | |||
f288d5120d | |||
5a425a1c58 | |||
5e62258aa6 | |||
0b53b4873f | |||
8e2597f609 | |||
dac700b80a | |||
d0fc360697 | |||
576414438c | |||
13cda86d23 | |||
e1dd27b9dd | |||
8e9d4b451c | |||
d871f55a89 | |||
816550b69c | |||
7fee852dbd | |||
1e7032f89c | |||
f0debecbbc | |||
ef9d7aa7d3 | |||
b8fd2db434 | |||
878e32cbe8 | |||
4821706561 | |||
![]() |
1611a4e1f0 | ||
eed6a64597 | |||
5736023ffa | |||
8a12a5097e | |||
87e4a57ef7 | |||
0375ee1881 | |||
c8e034d975 | |||
e98aa005cb | |||
52310f7d32 | |||
e3d1308205 | |||
970f039e85 | |||
99c72fd00b | |||
2708b71d77 | |||
5a4539def4 | |||
13a34cd677 | |||
811287aac8 | |||
23fb06578b | |||
c86e99e6dc | |||
4092de911c | |||
00952e15b0 | |||
6366283ce2 | |||
01ebf0f4d3 | |||
99fe6487c8 | |||
d4a6f987bc | |||
57bac4f262 | |||
cfa6843c8f | |||
b6b3221b22 | |||
8dc640c162 | |||
deee4c43c0 | |||
ad0b6f1ed1 | |||
ec03a674bd | |||
9e3d5b6a0c | |||
994c7299b9 | |||
57a830cb46 | |||
ff40a71582 | |||
271057ca6b | |||
861335212e | |||
038e47a46e | |||
c215508a12 | |||
ccadbb5942 | |||
171c48495c | |||
a83b86ccd2 | |||
2e4b9bcd7c | |||
3046822e88 | |||
6442dd0c38 | |||
9b6fa646ed | |||
e77bde459b | |||
2d9d83a1c5 | |||
c561271070 | |||
70d4fc1e0a | |||
b8cfb36426 | |||
e5c140e0ae | |||
b99160e850 | |||
c4c340fde1 | |||
9a4c7589cc | |||
d11f898f70 | |||
e1604b292c | |||
34e124f2db | |||
e05c72b062 | |||
377c3325d2 | |||
2ca8523215 | |||
25775614de | |||
efb3d982f3 | |||
0410ecd9e3 | |||
dd986fefd3 | |||
b38329aa0e | |||
0fe1b70bae | |||
c5b4499d98 | |||
458aa5c265 | |||
4499c9bf04 | |||
eb0223bc51 | |||
be6a492022 | |||
d8bd08dd8c | |||
18c2847b08 | |||
d45cda93b2 | |||
3448292e8a | |||
d983305ea5 | |||
c83cc492c0 | |||
ece32f88f4 | |||
dd9e28fca1 | |||
46cfe65321 | |||
7b7f5d7e0a | |||
fd112ed597 | |||
96eb8fc21f | |||
88fa4f1d9d | |||
5989c88c88 | |||
da8a108cb7 | |||
75132c1e39 | |||
eb494707af | |||
736f8d0238 | |||
f1acf8e18b | |||
281f91ec5d | |||
15352b539d | |||
4015e85506 | |||
aacaf52fd9 | |||
118f1da8dd | |||
89f83f4e3d | |||
39b7976056 | |||
8b0508d50a | |||
8a40878eb5 | |||
220469a2dd | |||
83de5b4ec1 | |||
fe1c51ae6d | |||
10cc954d27 | |||
73ff9b97db | |||
b0d71597f0 | |||
226f28dc7b | |||
![]() |
7afe30ea88 | ||
6308427d03 | |||
398d04dc50 | |||
80a5ed3c5b | |||
5d5a355110 | |||
c78b7c432b | |||
6bfdace512 | |||
16e55a98ce | |||
79f17843d8 | |||
e5e163bdbf | |||
4e4820af05 | |||
637512ad77 | |||
a4bd5a2aaa | |||
a943e4eebb | |||
cb0c80d8dc | |||
3332f68ce7 | |||
2fbf847367 | |||
54feb77770 | |||
1a07864a5f | |||
3e9d6bdbb9 | |||
c295539c79 | |||
57e6c46e72 | |||
cddf16f941 | |||
a3dee05fe3 | |||
a3617cad11 | |||
8edf4c3c8d | |||
7801c6effe | |||
8cc94a55ab | |||
b62c19a364 | |||
daffb6b666 | |||
7cfb1e6076 | |||
cc36baff78 | |||
4c65109ac0 | |||
861bd15eda | |||
7b979eadff | |||
16714ceb40 | |||
fea301bcc9 | |||
77450eb4b7 | |||
28015c4735 | |||
7d61e67d20 | |||
afcbc8be0a | |||
7a2269262b | |||
![]() |
9731dc1e61 | ||
bf2e0f2d73 | |||
e98857fab4 | |||
29b0a352fc | |||
8642b13fd1 | |||
6aa72892ed | |||
70f0a72f1b | |||
b5d890eedd | |||
50b1b48678 | |||
0e0dbc74aa | |||
8c34051d8b | |||
b00d83cb1a | |||
17e609c3a5 | |||
64f0166b64 | |||
c80f06fbcb | |||
70eb8325a0 | |||
8e4ad10627 | |||
496bc665d6 | |||
2c8531ea48 | |||
d3e7037759 | |||
e796f82203 | |||
5b7ca8c13c | |||
![]() |
0aee86442e | ||
![]() |
951c077abc | ||
031739ef51 | |||
b94685e045 | |||
572d602b72 | |||
88051c9302 | |||
80be937d9d | |||
d62ee6a611 | |||
![]() |
91ef4ff30b | ||
b8516b15cb | |||
755dcf66a3 | |||
4032228005 | |||
50ce13d596 | |||
![]() |
68302e7c5e | ||
ac5a54b5da | |||
b7ffd2653b | |||
29015b340b | |||
64274acbeb | |||
ff98c42514 | |||
126ac52975 | |||
70d3197212 | |||
dd90980520 | |||
18f9958332 | |||
68231db9a1 | |||
85e849ca00 | |||
617d41c7d5 | |||
cccdced74d | |||
750369b0a6 | |||
539e01deee | |||
4079edc80e | |||
a569990ca2 | |||
9c7eba4431 | |||
513ae9dc10 | |||
effecd4662 | |||
b951cb736a | |||
7e1aed6ad9 | |||
07155e2546 | |||
8c6c8ad3c0 | |||
![]() |
352ab43c1f | ||
![]() |
35f257800e | ||
07f5dbb9ac | |||
97e98eae24 | |||
5ac88f2b15 | |||
7a5ce57bbc | |||
b03a6684f9 | |||
afce942bf8 | |||
![]() |
7c2e50b665 | ||
c04ca704d2 | |||
![]() |
6aa54fe1d4 | ||
a1d7a56dfa | |||
cb78fefbb3 | |||
![]() |
c55925959b | ||
![]() |
4f0669c574 | ||
f0d996ffd2 | |||
![]() |
d0b7c22afc | ||
![]() |
a18bc15cbb | ||
f4d05c2c9c | |||
d1151ca707 | |||
82f46992f6 | |||
4ed9cc933f | |||
7af1c86f1c | |||
bd0b7aa230 | |||
72e0938f9a | |||
dd1b0a9380 | |||
9947a648df | |||
c0f80680ef | |||
7761b66fe2 | |||
acc4c8d975 | |||
fe739aa81a | |||
![]() |
adfefdd93f | ||
afe006e234 | |||
95f018a0b0 | |||
8c2105ae0a | |||
ed2c2af4a0 | |||
17771c0497 | |||
82df132e7d | |||
a02619e5a2 | |||
a011e70665 | |||
c05184e1c4 | |||
4dee913d51 | |||
![]() |
b2252bdc0b | ||
7e61ce1ed2 | |||
b764194ed0 | |||
2d0e4ba951 | |||
0d549b687d | |||
738f572043 | |||
cab508fd64 | |||
c7daf697a8 | |||
c20be13733 | |||
fcb6437388 | |||
![]() |
6c1db8473b | ||
b42987059a | |||
82fc7f33a8 | |||
bfa77cf810 | |||
a3930dafc5 | |||
4f9797af3b | |||
1a530633ca | |||
8037e8074b | |||
d07e0e5576 | |||
5525466b52 | |||
c2a89bf709 | |||
8dd0b2608d | |||
05495077ec | |||
8ff9eadf30 | |||
082c86ea18 | |||
2800d6f28c | |||
b4effe7a46 | |||
e6e71436c2 | |||
4be45adae6 | |||
a887f852c8 | |||
0d7d2203d2 | |||
cde184f428 | |||
0b3255e463 | |||
df3794dfd8 | |||
b7a316008a | |||
d02d5c351d | |||
f598f7030f | |||
631a531212 | |||
febecd4b30 | |||
964e311d8b | |||
d43caa8296 | |||
916ed3f56a | |||
23af170229 | |||
b32d1da421 | |||
6f0362b956 | |||
665d8cd479 | |||
10398855a9 | |||
70f575396d | |||
ad57e6713e | |||
d0fec93dc3 | |||
59ab54b2fb | |||
7095999bd2 | |||
7ffb4107d2 | |||
d9d9a28ef8 | |||
23f8e5cb41 | |||
879223f38f | |||
![]() |
d95582b81b | ||
![]() |
8a44c498c5 | ||
c60aa68d00 | |||
a891769a02 | |||
df97c582d7 | |||
9ce59d3c75 | |||
a0dfdfab2c | |||
3e17011087 | |||
f441505476 | |||
7c64797f03 | |||
e08bdd3e35 | |||
d2dd16aef3 | |||
b7a617dab3 | |||
bc95e7c886 | |||
fca43b3d34 | |||
48c5c3fbd5 | |||
b694aea100 | |||
6998626ad4 | |||
24ad858b64 | |||
288d453978 | |||
522cbc7f3d | |||
ce5bcc5897 | |||
97c93afeff | |||
8704b9ab06 | |||
5a1585bd00 | |||
5d6de90859 | |||
378c6c8006 | |||
f4922a8686 | |||
0bdcb40609 | |||
e684680d60 | |||
aa5d1042f0 | |||
14ac852b7e | |||
6b1a81ee92 | |||
3779b44813 | |||
949549178a | |||
7daa9812ff | |||
ca508bfe61 | |||
345a799031 | |||
445d5dd6f0 | |||
238baa8597 | |||
7932afc315 | |||
d1e3dc4d49 | |||
77e5fba7fd | |||
ca70c8c614 | |||
14620fdd72 | |||
89c1878622 | |||
d6856fc54a | |||
e5a9cab34e | |||
a4f97a7ba7 | |||
8b1af232c3 | |||
983fa346b3 | |||
32f420c4f0 | |||
41a82e923c | |||
5ddac36314 | |||
d06eecf9b0 | |||
5912ddd2a2 | |||
7db11588b4 | |||
c88b931ef1 | |||
10ffa2f44a | |||
dbe31dd339 | |||
14b44f8bb2 | |||
117747970d | |||
c6540650e2 | |||
f659f13759 | |||
95078e1103 | |||
8920255565 | |||
2d12618c96 | |||
68ca6fd122 | |||
33e9592659 | |||
19d217e3b9 | |||
af286d3bc6 | |||
20928732ec | |||
a8426750f2 | |||
2635f39344 | |||
89327463e3 | |||
cf45eca100 | |||
c0fa365f8f | |||
9d9f19781d | |||
f4520ea346 | |||
bbacdc5cac | |||
a6c0f3fef5 | |||
0e8328fca3 | |||
1ef3dae72e | |||
32381a7872 | |||
09815f5cce | |||
f6357b4531 | |||
a10e5c6ed4 | |||
d6d13eec95 | |||
457bc6609e | |||
e75155c329 | |||
d4e48006f2 | |||
d6508e23b6 | |||
2cb254a556 | |||
f99f5ed730 | |||
5f7e384442 | |||
56d0c8c616 | |||
5ff0f8ea10 | |||
fdc8a3d4f7 | |||
e5e85bcff9 | |||
4862edfdb5 | |||
a50b52df51 | |||
eac7e6db07 | |||
0c4835bfb5 | |||
aebd4817b8 | |||
9c2ceb4a9f | |||
68ace0b74a | |||
d119479c0a | |||
6739890d53 | |||
90b8ad1e6d | |||
025f79fcb4 | |||
6fb64f9ada | |||
2f1b923009 | |||
45ea09291a | |||
b7f3eff742 | |||
a274d6598e | |||
c3d78120ea | |||
f24de22e9b | |||
918783774f | |||
6744a55b9b | |||
a612fb446c | |||
a5adeb333c | |||
7788cada54 | |||
074ef29b86 | |||
d4f059d639 | |||
22bc300902 | |||
0d38ac62d8 | |||
d81257a91c | |||
d53c7e1190 | |||
e312cd094a | |||
9e958e752e | |||
3bcd71598d | |||
2602d4fed1 | |||
805538ec6e | |||
![]() |
120750f22a | ||
![]() |
9897f51307 | ||
4f87e24f60 | |||
2dcf896cca | |||
cdf2a90f90 | |||
b25555a533 | |||
bc0100ee08 | |||
c6d152a01d | |||
f4f1174849 | |||
9df8722c10 | |||
7208139630 | |||
54f3d7bd2d | |||
7a83289b3d | |||
136524424f | |||
793b97f651 | |||
2e4cd80556 | |||
a4f57a38fa | |||
6dc34fc1f0 | |||
9e6948a8d7 | |||
9b17b282c6 | |||
5f48d77c64 | |||
8ab8c57f9c | |||
c7b9df5e40 | |||
7b8019c621 | |||
baddbf7340 | |||
80a610141a | |||
f93c173715 | |||
620841a9e5 | |||
bd29688307 | |||
43b7a314b6 | |||
1b41153ee6 | |||
![]() |
f08d291e3e | ||
![]() |
06ffe27fcc | ||
![]() |
e9b0951a95 | ||
![]() |
348274c145 | ||
![]() |
40329a33b2 | ||
![]() |
2d52042ed6 | ||
![]() |
79936a3335 | ||
51add8a8ad | |||
ad5bb4c694 | |||
bf5a11cbd3 | |||
ddcac2bbac | |||
70b593df65 | |||
e5cc7069a6 | |||
98dbaf03e0 | |||
e0c50477cb | |||
30687f84c8 | |||
fed39defd3 | |||
acbc2cd749 | |||
368481f88b | |||
d2b561ba2f | |||
990e8672a8 | |||
![]() |
9cde8c7f45 | ||
![]() |
751de7accc | ||
74ae3f1371 | |||
02ac92a6b3 | |||
b83b2e8f89 | |||
8a39971a1c | |||
1ead156c64 | |||
5b968f7e5a | |||
b98127cea6 | |||
eba9abfc9a | |||
![]() |
bf7fabd7ba | ||
![]() |
cf3d4d8de3 | ||
![]() |
8414c9d471 | ||
![]() |
386843e3e7 | ||
441b3b83c8 | |||
c453af5911 | |||
fe95c3337a | |||
bc5a6b4a51 | |||
371ff931bf | |||
6c63d82f5c | |||
78ddce249c | |||
2a268e14d1 | |||
d93f2c5055 | |||
bd64a43819 | |||
d0c7878da4 | |||
2bd1e6acbd | |||
9697575f50 | |||
cec44ad44c | |||
![]() |
661b7b44e0 | ||
d39e0c8bb6 | |||
e952a82b65 | |||
7a84dff7d6 | |||
6a6f6011ba | |||
602fa3a956 | |||
c3a0aabfb8 | |||
cbcfa8fe56 | |||
32ba4301e4 | |||
4a5204d6f6 | |||
5907f8ee9d | |||
df45f02c39 | |||
15dddd7fc4 | |||
fd7581f8ba | |||
c2bf09d506 | |||
bf31248a50 | |||
9fadc9b830 | |||
8c17c7e1a7 | |||
9c5e3565c6 | |||
ecc7f1d691 | |||
00dced31ee | |||
ab7117d81e | |||
05c4f4fadc | |||
186b3565e0 | |||
e688105073 | |||
f7c6ec329b | |||
30217aa42b | |||
0176c07886 | |||
6d5eb5b387 | |||
9a38106b57 | |||
75e16e0b7b | |||
87a15910fe | |||
9ad215c9a3 | |||
2ca7a84e86 | |||
fbeb578d1c | |||
58d4525e8a | |||
8d004e9621 | |||
a53992fdc9 | |||
c6bbc19b85 | |||
36aaf3d758 | |||
7c855592d0 | |||
cb7399b999 | |||
d675621b73 | |||
3448a8c01b | |||
42458725e8 | |||
cc7250fcf5 | |||
da42edcc0c | |||
b02f737418 | |||
1923b339e9 | |||
3c41472649 | |||
da19764232 | |||
2126e6e375 | |||
5f8adc63b7 | |||
81bae85825 | |||
e263f2fbdc | |||
8d34561137 | |||
19f9b0280c | |||
e86319707f | |||
0e653378c3 | |||
a506b94d7e | |||
7bff632042 | |||
07a0dd5331 | |||
f16dcebf6b | |||
dc6ed40bfb | |||
a5a306ff66 | |||
7122c37511 | |||
dacec0c1f6 | |||
84cd010a25 | |||
a077a1b587 | |||
b94baf838d | |||
084a3daec6 | |||
b23ed11c7e | |||
9d7d22510b | |||
76d12e3db1 | |||
cee42f9b70 | |||
afe8fe6605 | |||
6e97bd4db4 | |||
7694decaaa | |||
113c992f99 | |||
0738a0b6a4 | |||
4251ccacf9 | |||
5d31a54fba | |||
cadf97de88 | |||
01f5dfe6b4 | |||
cae3feb5da | |||
2180c47f4f | |||
c46bde417e | |||
4924da1667 | |||
f8e9042943 | |||
e6a7108614 | |||
08926f9b70 | |||
52f0c29e99 | |||
060b3a3b2c | |||
348975ba5f | |||
e8927d6aa8 | |||
b2b648c4aa | |||
fc9101cd8f | |||
d2371b3e71 | |||
ffa38a81b7 | |||
ae689408f3 | |||
155432663b | |||
ecdbf98ca4 | |||
54a6c1b0aa | |||
9efe9e78d8 | |||
d4bb9397ee | |||
bf5590ce26 | |||
460941c225 | |||
3d6f28c48d | |||
bb9ae86159 | |||
306a4b647f | |||
19061c3d50 | |||
22dbabba38 | |||
ac8df112b1 | |||
ad744fb593 | |||
6c75b56054 | |||
fb67df6d7f | |||
1b6fa9822b | |||
5798aa1e3a | |||
b00f61445d | |||
ad117e07e0 | |||
c26c2a5a96 | |||
e02ac05097 | |||
a827ec6a92 | |||
12321a5d49 | |||
ad3238aa19 | |||
f67868516c | |||
1ddf9c0f11 | |||
![]() |
9bcd701a50 | ||
![]() |
6ad7f51297 | ||
12983a7143 | |||
27a3598526 | |||
dd1631a456 | |||
cd6d616806 | |||
ade15ad16d | |||
76416f523d | |||
5749e159e4 | |||
85a90a6ec5 | |||
80b41e937b | |||
ab906fa534 | |||
146e1e3282 | |||
857a1624c6 | |||
f11957d827 | |||
a977302a53 | |||
198fdbba62 | |||
53400c8bfa | |||
f2d0a0d9ee | |||
9e12f59707 | |||
2439613f21 | |||
1c8f86364d | |||
4e1c52f465 | |||
c7c6d78f4b | |||
9f856761e2 | |||
2f119f102d | |||
afb472996c | |||
f76f462022 | |||
0f90d50065 | |||
b0cbd40e64 | |||
1c1433e797 | |||
7671c93095 | |||
0df5491193 | |||
897d8b37ad | |||
ba4249d658 | |||
de7542c9c1 | |||
5a30dd969f | |||
05ed25d397 | |||
0a2c912f29 | |||
65f4433fad | |||
febe3cc4d4 | |||
f388878b99 | |||
faa7e1e24f | |||
9002c12cf1 | |||
2b15f9e644 | |||
42b5f8a79d | |||
0a6a32a130 | |||
cffd77ed32 | |||
b1a9c90087 | |||
a619087fef | |||
32b5060c62 | |||
936bac5abd | |||
bf02f14772 | |||
358ee0fbf2 | |||
4f08b2d342 | |||
1622e23f1c | |||
a4d6421510 | |||
f02852d8d2 | |||
bbea5e33bc | |||
e536918804 | |||
09299802f0 | |||
4b62c8aa81 | |||
1b38f84edc | |||
5064d44999 | |||
322c14d4bb | |||
8ec35f158c | |||
9a25f08fef | |||
f3caa122ae | |||
6e88f8f400 | |||
01762ad222 | |||
71d66c406f | |||
42df77ff32 | |||
85c04dee23 | |||
4c96db847d | |||
0246dccbe9 | |||
423f7c8281 | |||
59feaa4b5c | |||
a84e60a37a | |||
061d79bb62 | |||
a37b6184fc | |||
![]() |
f6b03dee6a | ||
a6bd7c0d6e | |||
f2bc374f0f | |||
52b3d9473e | |||
fc9b85d5db | |||
bfae25ff2d | |||
ea3812fbbd | |||
f40f783cb4 | |||
9429f6b868 | |||
39c909946b | |||
01c833f001 | |||
7c21980ece | |||
599ff6b45a | |||
0ddce61175 | |||
576a7293cb | |||
1732359f72 | |||
3e3c38e459 | |||
a6e4eb9ad4 | |||
e5db64cbb9 | |||
21b5eaa891 | |||
23c562bb67 | |||
5193294d25 | |||
a986b22345 | |||
646b1139a6 | |||
d9e2fd92fb | |||
ca65daab1a | |||
b3e0eeb14e | |||
2837d6e0dd | |||
cd82bebe78 | |||
1148adb43d | |||
ae27a4bb6c | |||
741d96d7ed | |||
596a056622 | |||
9c9b251322 | |||
0e0989db95 | |||
ba7acac215 | |||
af133a2928 | |||
abacfbf2d5 | |||
dae27a8e10 | |||
d36d849e69 | |||
7c7a8a5df7 | |||
134deb3f43 | |||
11a3c8c21f | |||
c9bfc8464a | |||
a88e97bc09 | |||
ea573b0523 | |||
3d336c08f2 | |||
d05eb23ea7 | |||
35b53e9a17 | |||
b5063117f6 | |||
29abef40a4 | |||
dfc44fce07 | |||
38afa494ce | |||
c42eb59d2e | |||
0a56441510 | |||
879d1f71c5 | |||
e226f19ca8 | |||
6ccf4bee49 | |||
7bf66dc401 | |||
a6d744c9c8 | |||
98e3ed897c | |||
b6aebb3061 | |||
5dcf0e44b6 | |||
3cec9f5f80 | |||
845c00044e | |||
8780c5ddcd | |||
654b23869f | |||
28f2db2c11 | |||
5fcac4d85b | |||
ece7dce6f7 | |||
4b72e246c3 | |||
92d3f0743b | |||
fa14ebbe1f | |||
db3284c2b8 | |||
517d52f55d | |||
6e9a0ddcf4 | |||
cfb8bc5dfd | |||
a18706ec53 | |||
eecb69d230 | |||
14a30f30db | |||
ccaa0aa24f | |||
d92a796705 | |||
1fa59c5cae | |||
83b5ade6b7 | |||
62873c3118 | |||
1301988892 | |||
1c3770ce96 | |||
![]() |
20adc1c981 | ||
90a1571707 | |||
2706b8fa24 | |||
8b39248a33 | |||
ec00a84b29 | |||
4d9c07a1ec | |||
c3fbe04fc6 | |||
466f1e000f | |||
f1f167c2d1 | |||
6f816b2592 | |||
0e5cfcf28f | |||
dee063e259 | |||
aabc729e77 | |||
c0591c3d24 | |||
5bbe16081f | |||
490ab440e5 | |||
0b207b2b1a | |||
e1f92b3da4 | |||
b75c815361 | |||
a94725c423 | |||
2d667cfb95 | |||
![]() |
3d80d5d036 | ||
![]() |
ebc9d99022 | ||
![]() |
2489276350 | ||
3895806a2b | |||
7b500eb0ed | |||
![]() |
a918c672a5 | ||
1515d59432 | |||
ab6c616cdb | |||
ee4449b74d | |||
10e81fdfb8 | |||
ce93b9220e | |||
d4f5c31881 | |||
d47906e833 | |||
7849b8e391 | |||
08364e2dca | |||
4b03db38eb | |||
ac146339a2 | |||
cbdf92a775 | |||
4c41cb1f71 | |||
16ed5e3270 | |||
baf3d4da47 | |||
e93230d0ef | |||
0b45e5c89a | |||
6d2bfaeb3b | |||
68498f6b74 | |||
291a8d4ea3 | |||
a65a184083 | |||
21ac5afd35 | |||
aafccd191e | |||
1db5c950b8 | |||
d11e54dc0a | |||
3c364604ac | |||
8db0ca861a | |||
e2da68795b | |||
243cf42dc4 | |||
0b0e2e5f75 | |||
516e3c0f9f | |||
62e0465b3d | |||
f19f3681ca | |||
a3e6b1018b | |||
fbdff5d0b4 | |||
22693eee50 | |||
e5807c396c | |||
704193eeaf | |||
3c4289335e | |||
df1d5e5005 | |||
5f0a3f3baa | |||
f6d1b8981c | |||
8f1a54aa19 | |||
376617f9f9 | |||
82299c7e3e | |||
4803fb2cbd | |||
d5dfffda2d | |||
66a79cb86c | |||
a6de52e212 | |||
936d0e9f0c | |||
ca297a7dcd | |||
3a9add82fe | |||
eee84f9318 | |||
f14d5edf42 | |||
f15352bb2f | |||
bdb8b0a757 | |||
5adb5cce95 | |||
f427c87270 | |||
8189435b94 | |||
ff63a34384 | |||
afebe15dc2 | |||
8035af28b9 | |||
c9156e1219 | |||
da8a447073 | |||
323577cdc6 | |||
eef2fd3b7a | |||
![]() |
5e960f118f | ||
c2b8507d29 | |||
b00bfe4bda | |||
38f2f69c78 | |||
2b2899e100 | |||
b52644dd2a | |||
c0c4a3190f | |||
1015cdbe88 | |||
cae69d5400 | |||
47af5260a2 | |||
1e380fe562 | |||
bd7c13ff7e | |||
2684e82c7f | |||
66d1d14ae3 | |||
5f9a6bb155 | |||
8a5a3c0243 | |||
2ccc0dbb00 | |||
cfbdb10a55 | |||
ee89a2f00d | |||
dbfcf8b271 | |||
717971f69c | |||
b0a69d4c9d | |||
ecb03b8a6d | |||
b1f6252e30 | |||
05edb7a00c | |||
0cde65f5a1 | |||
fbbc640f4d | |||
03e1a3e945 | |||
cc5c8ca698 | |||
996fbf134e | |||
1c7c532ef6 | |||
41e3a6b54b | |||
aa1bfcbb96 | |||
0f484abcaa | |||
c371cf4851 | |||
ad191409f4 | |||
398250c959 | |||
4b248740f3 | |||
21d213f35f | |||
105a498b93 | |||
0a0c5592f3 | |||
aa33ff2f48 | |||
3076c423c0 | |||
5f27fe6392 | |||
af99303eac | |||
1d2dabb4b4 | |||
eead2a8a49 | |||
a7068acca7 | |||
99b007f37e | |||
7cf4aa0d5a | |||
b1e3a1b2b5 | |||
56d2af9d25 | |||
dadba69272 | |||
40a8c9a495 | |||
8dc66784a8 | |||
d0f37b851b | |||
1b6759020a | |||
537a30a4de | |||
a993872884 | |||
d700fb551c | |||
73bae057bd | |||
589e64fc46 | |||
1630682548 | |||
4b095eea89 | |||
fb7b059137 | |||
bc151983b5 | |||
40b2979ce8 | |||
7030d3e108 | |||
41cb8cb8ae | |||
75adf52d28 | |||
0157681471 | |||
b6b144bcdb | |||
145dd33fb1 | |||
50fac22f54 | |||
8b83541264 | |||
57699cccb7 | |||
33e7c635c5 | |||
070c3f3bbf | |||
3891014340 | |||
c3be4cdee6 | |||
6b9747ee0b | |||
ad820fbe99 | |||
722a7b3240 | |||
442b9370ae | |||
54e60f4ddc | |||
e961f3f038 | |||
c9836abf03 | |||
404c3821e6 | |||
567699954c | |||
43d4953e4a | |||
e6059812b5 | |||
f0a7b1cad2 | |||
e46615e830 | |||
e7ac2c7009 | |||
95c6a24437 | |||
237ba8112b | |||
aab3fd828b | |||
46cfe7452a | |||
e6868464bf | |||
e15f03fb0a | |||
59e7f0caae | |||
a2deac3441 | |||
5eadcaf10d | |||
2bf5a972e1 | |||
5d2c62e75d | |||
5ac68f731e | |||
7fa0443725 | |||
f4cb63c53c | |||
0cde6f317d | |||
2737bc390c | |||
07ba05b209 | |||
f3d9fb645e | |||
e9adaf672f | |||
fc4e65b2fc | |||
36030ef87c | |||
b7060a9c78 | |||
e147d5a4f5 | |||
a8c0d96c39 | |||
ed27d388d5 | |||
e2ae9756f3 | |||
c07672f9b4 | |||
6db2efc20d | |||
94062c67d3 | |||
9e0146f579 | |||
d3423b30b0 | |||
58a532fc4d | |||
ac027e3ff2 | |||
ff6b4134a5 | |||
5847081a24 | |||
0bc124fd21 | |||
1e9c789287 | |||
b06113993c | |||
4fa56a2f1d | |||
a320e3e1ef | |||
4095be449a | |||
d20f0c5da1 | |||
9496ed42e2 | |||
14027e449c | |||
1626b266d7 | |||
d27f49c968 | |||
a6dd2d5dcb | |||
8293e6b0c7 | |||
d81c6f40fb | |||
5b23b928cf | |||
cd016c8281 | |||
e1c91f82b7 | |||
9d0155d9ae | |||
d807998f4d | |||
8b17c40aa6 | |||
d7d24bd9aa | |||
c1d30aad13 | |||
126def219b | |||
08b9e92d25 | |||
86431c854b | |||
f3530d3c7e | |||
0a76c5b0b5 | |||
6ede3f9ba2 | |||
097244bf8b | |||
5c9b1769c1 | |||
413ff0d1b9 | |||
5273ffa721 | |||
e7c00b5633 | |||
f2ab07c782 | |||
ff33a1274d | |||
e7cfd324ae | |||
52b549b97c | |||
cac9a0eecd | |||
56d43f5b49 | |||
10e7e42388 | |||
fc34e7fd75 | |||
18a9729c75 | |||
763347f203 | |||
1ff52e43a0 | |||
7f1cbaef23 | |||
3356ccc9d4 | |||
3f91803422 | |||
5759c2cbe6 | |||
e45b8bc739 | |||
dcd72d421e | |||
cc8c3aef3d | |||
9352e15405 | |||
1cceda8e63 | |||
8c4381eca6 | |||
29a05eb113 | |||
534b4850df | |||
a66fc53396 | |||
5471030c32 | |||
770356f8b6 | |||
62e409a9f2 | |||
cf8a9996a7 | |||
fc7e401ddc | |||
ed186b04df | |||
f906605097 | |||
9a2fbefc9f | |||
07f1216316 | |||
4faa5b0685 | |||
ae1dab1fce | |||
9a5f717169 | |||
d7d52439d7 | |||
5d93cf12f7 | |||
438049bb80 | |||
6e6fb62b3c | |||
7b8928ef47 | |||
924ea420a9 | |||
fbe860c6a5 | |||
8b266aa542 | |||
5144cbd789 | |||
720ce59680 | |||
f1ffa88e07 | |||
d4b26825af | |||
7e249db15e | |||
83e7dbb1f0 | |||
2e417c787d | |||
316310e993 | |||
6db0725aa4 | |||
e0d39b1feb | |||
d9a0a4f2ea | |||
b8c7a65709 | |||
d3c3a9147a | |||
40cc3c383b | |||
d92a20a669 | |||
c1f4ae08fb | |||
2b84ab018c | |||
9e881b6a16 | |||
905d525aa2 | |||
e6a1a7cc2d | |||
dd367bf083 | |||
8f4ab6d7ed | |||
b30a3aaa38 | |||
efb7c8760a | |||
bddd8720b2 | |||
00d9a4f3ed | |||
f988271be4 | |||
38d929c2a8 | |||
e799e45198 | |||
9ee1bd15c4 | |||
cbeb78f089 | |||
80aab5f461 | |||
43ddb44573 | |||
9f8a345e35 | |||
3ff5484415 | |||
7322a7d0f5 | |||
0e76333d33 | |||
dea2205908 | |||
d1a256cbf6 | |||
f2da31239c | |||
42720e6f7d | |||
83d0db8242 | |||
533d164cac | |||
0e92fa4046 | |||
32b289cbec | |||
fa108f0a3b | |||
f82cc1bca4 | |||
778ef4ef23 | |||
17b8d3fed0 | |||
d57955ade7 | |||
18e40d6248 | |||
41e30dcb6c | |||
92f249dc62 | |||
f3cc664d4f | |||
91f69aa34f | |||
8b561d073c | |||
c55cf8f279 | |||
c5b2c47af4 | |||
f0178a8f73 | |||
e1b57424f8 | |||
8d7d4c639a | |||
a3d245f5a0 | |||
1ccfb74709 | |||
939fa16d1a |
7
.clang-format
Normal file
7
.clang-format
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
BasedOnStyle: Google
|
||||||
|
IndentWidth: 2
|
||||||
|
---
|
||||||
|
Language: Cpp
|
||||||
|
ColumnLimit: 100
|
||||||
|
---
|
10
.gitignore
vendored
10
.gitignore
vendored
@ -1,4 +1,14 @@
|
|||||||
|
# PyCharm and CLion
|
||||||
|
/.idea/*
|
||||||
|
!/.idea/runConfigurations
|
||||||
|
!/.idea/cmake.xml
|
||||||
|
!/.idea/codeStyles
|
||||||
|
|
||||||
|
# Eclipse
|
||||||
.cproject
|
.cproject
|
||||||
.project
|
.project
|
||||||
.settings
|
.settings
|
||||||
.metadata
|
.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>
|
98
CHANGELOG
98
CHANGELOG
@ -1,98 +0,0 @@
|
|||||||
## Changes from ASTP 0.0.1 to 1.0.0
|
|
||||||
|
|
||||||
### Host OSAL
|
|
||||||
|
|
||||||
- Bugfix in MessageQueue, which caused the sender not to be set properly
|
|
||||||
|
|
||||||
### FreeRTOS OSAL
|
|
||||||
|
|
||||||
- vRequestContextSwitchFromISR is declared extern "C" so it can be defined in
|
|
||||||
a C file without issues
|
|
||||||
|
|
||||||
### PUS Services
|
|
||||||
|
|
||||||
- It is now possible to change the message queue depth for the telecommand verification service (PUS1)
|
|
||||||
- The same is possible for the event reporting service (PUS5)
|
|
||||||
- PUS Health Service added, which allows to command and retrieve health via PUS packets
|
|
||||||
|
|
||||||
|
|
||||||
### EnhancedControllerBase
|
|
||||||
|
|
||||||
- New base class for a controller which also implements HasActionsIF and HasLocalDataPoolIF
|
|
||||||
|
|
||||||
### Local Pool
|
|
||||||
|
|
||||||
- Interface of LocalPools has changed. LocalPool is not a template anymore. Instead the size and
|
|
||||||
bucket number of the pools per page and the number of pages are passed to the ctor instead of
|
|
||||||
two ctor arguments and a template parameter
|
|
||||||
|
|
||||||
### Parameter Service
|
|
||||||
|
|
||||||
- The API of the parameter service has been changed to prevent inconsistencies
|
|
||||||
between documentation and actual code and to clarify usage.
|
|
||||||
- The parameter ID now consists of:
|
|
||||||
1. Domain ID (1 byte)
|
|
||||||
2. Unique Identifier (1 byte)
|
|
||||||
3. Linear Index (2 bytes)
|
|
||||||
The linear index can be used for arrays as well as matrices.
|
|
||||||
The parameter load command now explicitely expects the ECSS PTC and PFC
|
|
||||||
information as well as the rows and column number. Rows and column will
|
|
||||||
default to one, which is equivalent to one scalar parameter (the most
|
|
||||||
important use-case)
|
|
||||||
|
|
||||||
### File System Interface
|
|
||||||
|
|
||||||
- A new interfaces specifies the functions for a software object which exposes the file system of
|
|
||||||
a given hardware to use message based file handling (e.g. PUS commanding)
|
|
||||||
|
|
||||||
### Internal Error Reporter
|
|
||||||
|
|
||||||
- The new internal error reporter uses the local data pools. The pool IDs for
|
|
||||||
the exisiting three error values and the new error set will be hardcoded for
|
|
||||||
now, the the constructor for the internal error reporter just takes an object
|
|
||||||
ID for now.
|
|
||||||
|
|
||||||
### Device Handler Base
|
|
||||||
|
|
||||||
- There is an additional `PERFORM_OPERATION` step for the device handler base. It is important
|
|
||||||
that DHB users adapt their polling sequence tables to perform this step. This steps allows for
|
|
||||||
a clear distinction between operation and communication steps
|
|
||||||
- setNormalDatapoolEntriesInvalid is not an abstract method and a default implementation was provided
|
|
||||||
- getTransitionDelayMs is now an abstract method
|
|
||||||
|
|
||||||
### DeviceHandlerIF
|
|
||||||
|
|
||||||
- Typo for UNKNOWN_DEVICE_REPLY
|
|
||||||
|
|
||||||
### Events
|
|
||||||
|
|
||||||
- makeEvent function: Now takes three input parameters instead of two and
|
|
||||||
allows setting a unique ID. Event.cpp source file removed, functions now
|
|
||||||
defined in header directly. Namespaces renamed. Functions declared `constexpr`
|
|
||||||
now
|
|
||||||
|
|
||||||
### Commanding Service Base
|
|
||||||
|
|
||||||
- CSB uses the new fsfwconfig::FSFW_CSB_FIFO_DEPTH variable to determine the FIFO depth for each
|
|
||||||
CSB instance. This variable has to be set in the FSFWConfig.h file
|
|
||||||
|
|
||||||
### Service Interface
|
|
||||||
|
|
||||||
- Proper printf support contained in ServiceInterfacePrinter.h
|
|
||||||
- CPP ostream support now optional (can reduce executable size by 150 - 250 kB)
|
|
||||||
- Amalagated header which determines automatically which service interface to use depending on FSFWConfig.h configuration.
|
|
||||||
Users can just use #include <fsfw/serviceinterface/ServiceInterface.h>
|
|
||||||
- If CPP streams are excluded, sif:: calls won't work anymore and need to be replaced by their printf counterparts.
|
|
||||||
For the fsfw, this can be done by checking the processor define FSFW_CPP_OSTREAM_ENABLED from FSFWConfig.h.
|
|
||||||
For mission code, developers need to replace sif:: calls by the printf counterparts, but only if the CPP stream are excluded.
|
|
||||||
If this is not the case, everything should work as usual.
|
|
||||||
|
|
||||||
### ActionHelper and ActionMessage
|
|
||||||
|
|
||||||
- ActionHelper finish function and ActionMessage::setCompletionReply now expects explicit
|
|
||||||
information whether to report a success or failure message instead of deriving it implicitely
|
|
||||||
from returnvalue
|
|
||||||
|
|
||||||
### PUS Parameter Service 20
|
|
||||||
|
|
||||||
Added PUS parameter service 20 (only custom subservices available).
|
|
749
CHANGELOG.md
Normal file
749
CHANGELOG.md
Normal file
@ -0,0 +1,749 @@
|
|||||||
|
Change Log
|
||||||
|
=======
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
||||||
|
and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
|
|
||||||
|
# [unreleased]
|
||||||
|
|
||||||
|
# [v6.0.0] 2023-02-10
|
||||||
|
|
||||||
|
## Fixes
|
||||||
|
|
||||||
|
- Mode Service: Add allowed subservice
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/739
|
||||||
|
- `CService200ModeManagement`: Various bugfixes which lead to now execution complete being generated
|
||||||
|
on mode announcements, duplicate mode reply generated on announce commands, and the mode read
|
||||||
|
subservice not working properly.
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/736
|
||||||
|
- Memory leak fixes for the TCP/IP TMTC bridge.
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/737
|
||||||
|
- `Service9TimeManagement`: Fix the time dump at the `SET_TIME` subservice: Include clock timeval
|
||||||
|
seconds instead of uptime.
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/726
|
||||||
|
- HAL MGM3100 Handler: Use axis specific gain/scaling factors. Previously,
|
||||||
|
only the X scaling factor was used.
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/724
|
||||||
|
- HAL MGM3100 Handler: Z value was previously calculated with bytes of the X value.
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/733
|
||||||
|
- DHB `setNormalDatapoolEntriesInvalid`: The default implementation did not set the validity
|
||||||
|
to false correctly because the `read` and `write` calls were missing.
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/728
|
||||||
|
- PUS TMTC creator module: Sequence flags were set to continuation segment (0b00) instead
|
||||||
|
of the correct unsegmented flags (0b11) as specified in the standard.
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/727
|
||||||
|
- TC Scheduler Service 11: Add size and CRC check for contained TC.
|
||||||
|
Bug: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/issues/719
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/720
|
||||||
|
- Only delete health table entry in `HealthHelper` destructor if
|
||||||
|
health table was set.
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/710
|
||||||
|
- I2C Bugfixes: Do not keep iterator as member and fix some incorrect handling with the iterator.
|
||||||
|
Also properly reset the reply size for successfull transfers and erroneous transfers.
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/700
|
||||||
|
- 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
|
||||||
|
- `CServiceHealthCommanding`: Add announce all health info implementation
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/725
|
||||||
|
- various fixes related to linux Unittests and memory leaks
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/715
|
||||||
|
- small fix to allow teardown handling
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/713
|
||||||
|
- fix compiler warning for fixed array list copy ctor
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/704
|
||||||
|
- missing include
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/703
|
||||||
|
- defaultconfig did not build anymore
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/702
|
||||||
|
- hotfix
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/699
|
||||||
|
- small fix for helper
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/698
|
||||||
|
- missing retval conv
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/697
|
||||||
|
- DHB Countdown Bug
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/693
|
||||||
|
- doc corrections
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/687
|
||||||
|
- better error printout
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/686
|
||||||
|
- include correction
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/683
|
||||||
|
- better warning for missing include paths
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/676
|
||||||
|
- Service 11 regression
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/670
|
||||||
|
|
||||||
|
## Added
|
||||||
|
|
||||||
|
- Empty constructor for `CdsShortTimeStamper` which does not do an object manager registration.
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/730
|
||||||
|
- `Service9TimeManagement`: Add `DUMP_TIME` (129) subservice.
|
||||||
|
- `TcpTmTcServer`: Allow setting the `SO_REUSEADDR` and `SO_REUSEPORT`
|
||||||
|
option on the TCP server. CTOR prototype has changed and expects an explicit
|
||||||
|
TCP configuration struct to be passed.
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/722
|
||||||
|
- `DleParser` helper class to parse DLE encoded packets from a byte stream.
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/711
|
||||||
|
- `UioMapper` is able to resolve symlinks now.
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/709
|
||||||
|
- Add new `UnsignedByteField` class
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/660
|
||||||
|
- publish documentation for development and master branch
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/681
|
||||||
|
- Add Linux HAL options
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/663
|
||||||
|
- Expand SerializeIF
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/656
|
||||||
|
- PUS Service 11: Additional Safety Check
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/666
|
||||||
|
- improvements for auto-formatter script
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/665
|
||||||
|
- provide a weak print char impl
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/674
|
||||||
|
|
||||||
|
## Removed
|
||||||
|
|
||||||
|
- now that doc server is up, remove markdown files
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/688
|
||||||
|
- remove bsp specific code
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/679
|
||||||
|
|
||||||
|
## Changes
|
||||||
|
|
||||||
|
- `CService201HealthCommanding` renamed to `CServiceHealthCommanding`,
|
||||||
|
service ID customizable now. `CServiceHealthCommanding` expects configuration struct
|
||||||
|
`HealthServiceCfg` now
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/725
|
||||||
|
- `AcceptsTelemetryIF`: `getReportReceptionQueue` is const now
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/712
|
||||||
|
- Moved some container returnvalues to dedicated header and namespace
|
||||||
|
so they can be used without template specification.
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/707
|
||||||
|
- 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
|
||||||
|
- Generic TMTC Bridge Update
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/734
|
||||||
|
- comment tweak to event parser can read everything
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/732
|
||||||
|
- CMakeLists file updates
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/731
|
||||||
|
- improve srv20 error messages
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/723
|
||||||
|
- I2C Linux: remove duplicate printout
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/718
|
||||||
|
- printout handling improvements
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/717
|
||||||
|
- vec getter, reset for content
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/716
|
||||||
|
- updates for source sequence counter
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/714
|
||||||
|
- SP reader getPacketData is const now
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/708
|
||||||
|
- refactoring of serial drivers for linux
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/705
|
||||||
|
- Local Pool Update Remove Add Data Ignore Fault Argument
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/701
|
||||||
|
- Switch to new documentation server
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/694
|
||||||
|
- Windows Tweaks
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/691
|
||||||
|
- Refactor Local Pool API
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/667
|
||||||
|
- group MGM data in local pool vectors
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/664
|
||||||
|
|
||||||
|
|
||||||
|
## 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] 2022-07-25
|
||||||
|
|
||||||
|
## 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
|
||||||
|
- 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)
|
||||||
|
manually now. Those should not change too often and only a small subset is needed
|
||||||
|
- Separate folder for easier update and for distinction
|
||||||
|
- LICENSE file included
|
||||||
|
- use `int` for version numbers to allow unset or uninitialized version
|
||||||
|
- Initialize Version object with numbers set to -1
|
||||||
|
- Instead of hardcoding the git hash, it is now retrieved from git
|
||||||
|
- `Version` now allows specifying additional version information like the git SHA1 hash and the
|
||||||
|
versions since the last tag
|
||||||
|
- Additional information is set to the last part of the git describe output for `FSFW_VERSION` now.
|
||||||
|
- Version still need to be hand-updated if the FSFW is not included as a submodule for now.
|
||||||
|
- IPC Message Queue Handling: Allow passing an optional `MqArgs` argument into the MessageQueue
|
||||||
|
creation call. It allows passing context information and an arbitrary user argument into
|
||||||
|
the message queue. Also streamlined and simplified `MessageQueue` implementation for all OSALs
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/583
|
||||||
|
- 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
|
||||||
|
|
||||||
|
- HAL Linux Uart: Baudrate and bits per word are enums now, avoiding misconfigurations
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/585
|
||||||
|
- HAL Linux SPI: Set the Clock Default State when setting new SPI speed
|
||||||
|
and mode
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/573
|
||||||
|
- GPIO HAL: `Direction`, `GpioOperation` and `Levels` are enum classes now, which prevents
|
||||||
|
name clashes with Windows defines.
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/572
|
||||||
|
- HAL Linux Uart: Baudrate and bits per word are enums now, avoiding misconfigurations
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/585
|
||||||
|
|
||||||
|
### Time
|
||||||
|
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/584 and
|
||||||
|
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/593
|
||||||
|
|
||||||
|
- `timeval` to `TimeOfDay_t`
|
||||||
|
- Added Mutex for gmtime calls: (compare http://www.opengate.at/blog/2020/01/timeless/)
|
||||||
|
- Moved the statics used by Clock in ClockCommon.cpp to this file
|
||||||
|
- Better check for leap seconds
|
||||||
|
- Added Unittests for Clock (only getter)
|
||||||
|
|
||||||
|
### Power
|
||||||
|
|
||||||
|
- `PowerSwitchIF`: Remove `const` specifier from `sendSwitchCommand` and `sendFuseOnCommand` and
|
||||||
|
also specify a `ReturnValue_t` return type
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/590
|
||||||
|
- Extend `PowerSwitcher` module to optionally check current state when calling `turnOn` or
|
||||||
|
`turnOff`. Tis can be helpful to avoid commanding switches which do not need commanding
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/590
|
||||||
|
|
||||||
|
## Removed
|
||||||
|
|
||||||
|
- Removed the `HkSwitchHelper`. This module should not be needed anymore, now that the local
|
||||||
|
datapools have been implemented.
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/557
|
||||||
|
|
||||||
|
## 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.
|
||||||
|
After some more research:
|
||||||
|
Enabling LTO will actually cause the compiler to only produce thin LTO by adding
|
||||||
|
`-flto -fno-fat-lto-objects` to the compiler options. I am not sure this is an ideal choice
|
||||||
|
because if an application linking against the FSFW does not use LTO, there can be compile
|
||||||
|
issues (e.g. observed when compiling the FSFW tests without LTO). This is a known issue as
|
||||||
|
can be seen in the multiple CMake issues for it:
|
||||||
|
- https://gitlab.kitware.com/cmake/cmake/-/issues/22913,
|
||||||
|
- https://gitlab.kitware.com/cmake/cmake/-/issues/16808,
|
||||||
|
- https://gitlab.kitware.com/cmake/cmake/-/issues/21696
|
||||||
|
Easiest solution for now: Keep this option OFF by default.
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/616
|
||||||
|
- Linux HAL: Add wiretapping option for I2C. Enabled with `FSFW_HAL_I2C_WIRETAPPING` defined to 1
|
||||||
|
- Dedicated Version class and constant `fsfw::FSFW_VERSION` containing version information
|
||||||
|
inside `fsfw/version.h`
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/559
|
||||||
|
- Added generic PUS TC Scheduler Service 11. It depends on the new added Emebeded Template Library
|
||||||
|
(ETL) dependency.
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/594
|
||||||
|
- Added ETL dependency and improved library dependency management
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/592
|
||||||
|
- Add a `DummyPowerSwitcher` module which can be useful for test setups when no PCDU is available
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/590
|
||||||
|
- New typedef for switcher type
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/590
|
||||||
|
- `Subsystem`: New API to add table and sequence entries
|
||||||
|
|
||||||
|
## Fixed
|
||||||
|
|
||||||
|
- TCP TMTC Server: `MutexGuard` was not created properly in
|
||||||
|
`TcpTmTcServer::handleTmSending(socket_t connSocket, bool& tmSent)` call.
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/618
|
||||||
|
- Fix infinite recursion in `prepareHealthSetReply` of PUS Health Service 201.
|
||||||
|
Is not currently used right now but might be used in the future
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/617
|
||||||
|
- Move some CMake directives further up top so they are not ignored
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/621
|
||||||
|
- Small bugfix in STM32 HAL for SPI
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/599
|
||||||
|
- HAL GPIO: Improved error checking in `LinuxLibgpioIF::configureGpios(...)`. If a GPIO
|
||||||
|
configuration fails, the function will exit prematurely with a dedicated error code
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/602
|
||||||
|
|
||||||
|
# [v4.0.0]
|
||||||
|
|
||||||
|
## Additions
|
||||||
|
|
||||||
|
- CFDP Packet Stack and related tests added. It also refactors the existing TMTC infastructure to
|
||||||
|
allow sending of CFDP packets to the CCSDS handlers.
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/528
|
||||||
|
- added virtual function to print datasets
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/544
|
||||||
|
- doSendRead Hook
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/545
|
||||||
|
- Dockumentation for DHB
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/551
|
||||||
|
|
||||||
|
### HAL additions
|
||||||
|
|
||||||
|
- Linux Command Executor, which can execute shell commands in blocking and non-blocking mode
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/536
|
||||||
|
- uio Mapper
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/543
|
||||||
|
|
||||||
|
## Changes
|
||||||
|
|
||||||
|
- Applied the `clang-format` auto-formatter to all source code
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/534
|
||||||
|
- Updated Catch2 to v3.0.0-preview4
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/538
|
||||||
|
- Changed CI to use prebuilt docker image
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/549
|
||||||
|
|
||||||
|
## Bugfix
|
||||||
|
|
||||||
|
- CMake fixes in PR https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/533 , was problematic
|
||||||
|
if the uppermost user `CMakeLists.txt` did not have the include paths set up properly, which
|
||||||
|
could lead to compile errors that `#include "fsfw/FSFW.h"` was not found.
|
||||||
|
- Fix for build regression in Catch2 v3.0.0-preview4
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/548
|
||||||
|
- Fix in unittest which failed on CI
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/552
|
||||||
|
- Fix in helper script
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/553
|
||||||
|
|
||||||
|
## API Changes
|
||||||
|
|
||||||
|
- Aforementioned changes to existing TMTC stack
|
||||||
|
|
||||||
|
## Known bugs
|
||||||
|
|
||||||
|
-
|
||||||
|
|
||||||
|
# [v3.0.1]
|
||||||
|
|
||||||
|
## API Changes
|
||||||
|
|
||||||
|
*
|
||||||
|
|
||||||
|
## Bugfixes
|
||||||
|
|
||||||
|
* Version number was not updated for v3.0.0 #542
|
||||||
|
|
||||||
|
## Enhancement
|
||||||
|
|
||||||
|
*
|
||||||
|
|
||||||
|
## Known bugs
|
||||||
|
|
||||||
|
*
|
||||||
|
|
||||||
|
# [v3.0.0]
|
||||||
|
|
||||||
|
## API Changes
|
||||||
|
|
||||||
|
#### TCP Socket Changes
|
||||||
|
|
||||||
|
* Keep Open TCP Implementation #496
|
||||||
|
* The socket will now kept open after disconnect. This allows reconnecting.
|
||||||
|
* Only one connection is allowed
|
||||||
|
* No internal influence but clients need to change their Code.
|
||||||
|
|
||||||
|
### GPIO IF
|
||||||
|
|
||||||
|
* Add feature to open GPIO by line name #506
|
||||||
|
|
||||||
|
### Bitutil
|
||||||
|
|
||||||
|
* Unittests for Op Divider and Bitutility #510
|
||||||
|
|
||||||
|
### Filesystem IF changed
|
||||||
|
|
||||||
|
* Filesystem Base Interface: Use IF instead of void pointer #511
|
||||||
|
|
||||||
|
### STM32
|
||||||
|
|
||||||
|
* STM32 SPI Updates #518
|
||||||
|
|
||||||
|
## Bugfixes
|
||||||
|
|
||||||
|
* Small bugfix for LIS3 handler #504
|
||||||
|
* Spelling fixed for function names #509
|
||||||
|
* CMakeLists fixes #517
|
||||||
|
* Out of bound reads and writes in unittests #519
|
||||||
|
* Bug in TmPacketStoredPusC (#478)
|
||||||
|
* Windows ifdef fixed #529
|
||||||
|
|
||||||
|
## Enhancement
|
||||||
|
|
||||||
|
* FSFW.h.in more default values #491
|
||||||
|
* Minor updates for PUS services #498
|
||||||
|
* HasReturnvaluesIF naming for parameter #499
|
||||||
|
* Tests can now be built as part of FSFW and versioning moved to CMake #500
|
||||||
|
* Added integration test code #508
|
||||||
|
* More printouts for rejected TC packets #505
|
||||||
|
* Arrayprinter format improvements #514
|
||||||
|
* Adding code for CI with docker and jenkins #520
|
||||||
|
* Added new function in SerializeAdapter #513
|
||||||
|
* Enables simple deSerialize if you keep track of the buffer position yourself
|
||||||
|
* `` static ReturnValue_t deSerialize(T *object, const uint8_t* buffer,
|
||||||
|
size_t* deserSize, SerializeIF::Endianness streamEndianness) ``
|
||||||
|
* Unittest helper scripts has a new Parameter to open the coverage html in the webrowser #525
|
||||||
|
* ``'-o', '--open', Open coverage data in webbrowser``
|
||||||
|
* Documentation updated. Sphinx Documentation can now be build with python script #526
|
||||||
|
|
||||||
|
## Known bugs
|
||||||
|
|
||||||
|
* Version number was not updated for v3.0.0 #542
|
||||||
|
|
||||||
|
|
||||||
|
All Pull Requests:
|
||||||
|
|
||||||
|
Milestone: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/milestone/19
|
||||||
|
|
||||||
|
# [v2.0.0]
|
||||||
|
|
||||||
|
## API Changes
|
||||||
|
|
||||||
|
|
||||||
|
### File Structure changed to fit more common structure
|
||||||
|
|
||||||
|
* See pull request (#445)
|
||||||
|
* HAL is now part of the main project
|
||||||
|
* **See Instructions below:**
|
||||||
|
|
||||||
|
#### Instruction how to update existing / user code
|
||||||
|
|
||||||
|
* Changes in `#include`:
|
||||||
|
* Rename `internalError` in includes to `internalerror`
|
||||||
|
* Rename `fsfw/hal` to `fsfw_hal`
|
||||||
|
* Rename `fsfw/tests` to `fsfw_tests`
|
||||||
|
* Rename `osal/FreeRTOS` to `osal/freertos`
|
||||||
|
|
||||||
|
* Changes in `CMakeLists.txt`:
|
||||||
|
* Rename `OS_FSFW` to `FSFW_OSAL`
|
||||||
|
|
||||||
|
* Changes in `DleEncoder.cpp`
|
||||||
|
* Create an instance of the `DleEncoder` first before calling the `encode` and `decode` functions
|
||||||
|
|
||||||
|
### Removed osal/linux/Timer (#486)
|
||||||
|
|
||||||
|
* Was redundant to timemanager/Countdown
|
||||||
|
|
||||||
|
#### Instruction how to update existing / user code
|
||||||
|
|
||||||
|
* Use timemanager/Countdown instead
|
||||||
|
|
||||||
|
## Bugfixes
|
||||||
|
|
||||||
|
### TM Stack
|
||||||
|
|
||||||
|
* Increased TM stack robustness by introducing `nullptr` checks and more printouts (#483)
|
||||||
|
|
||||||
|
#### Host OSAL / FreeRTOS
|
||||||
|
|
||||||
|
* QueueMapManager Bugfix (NO_QUEUE was used as MessageQueueId) (#444)
|
||||||
|
|
||||||
|
#### Events
|
||||||
|
|
||||||
|
* Event output is now consistent (#447)
|
||||||
|
|
||||||
|
#### DLE Encoder
|
||||||
|
|
||||||
|
* Fixed possible out of bounds access in DLE Encoder (#492)
|
||||||
|
|
||||||
|
## Enhancment
|
||||||
|
|
||||||
|
* HAL as major new feature, also includes three MEMS devicehandlers as part of #481
|
||||||
|
* Linux HAL updates (#456)
|
||||||
|
* FreeRTOS Header cleaning update and Cmake tweaks (#442)
|
||||||
|
* Printer updates (#453)
|
||||||
|
* New returnvalue for for empty PST (#485)
|
||||||
|
* TMTC Bridge: Increase limit of packets stored (#484)
|
||||||
|
|
||||||
|
## Known bugs
|
||||||
|
|
||||||
|
* Bug in TmPacketStoredPusC (#478)
|
||||||
|
|
||||||
|
|
||||||
|
All Pull Requests:
|
||||||
|
|
||||||
|
Milestone: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/milestone/5
|
||||||
|
|
||||||
|
# [v1.2.0]
|
||||||
|
|
||||||
|
## API Changes
|
||||||
|
|
||||||
|
### FSFW Architecture
|
||||||
|
|
||||||
|
- New src folder which contains all source files except the HAL, contributed code and test code
|
||||||
|
- External and internal API mostly stayed the same
|
||||||
|
- Folder names are now all smaller case: internalError was renamed to internalerror and
|
||||||
|
FreeRTOS was renamed to freertos
|
||||||
|
- Warning if optional headers are used but the modules was not added to the source files to compile
|
||||||
|
|
||||||
|
### HAL
|
||||||
|
|
||||||
|
- HAL added back into FSFW. It is tightly bound to the FSFW, and compiling it as a static library
|
||||||
|
made using it more complicated than necessary
|
||||||
|
|
||||||
|
## Bugfixes
|
||||||
|
|
||||||
|
### FreeRTOS QueueMapManager
|
||||||
|
|
||||||
|
- Fixed a bug which causes the first generated Queue ID to be invalid
|
||||||
|
|
||||||
|
## Enhancements
|
||||||
|
|
||||||
|
### FSFW Architecture
|
||||||
|
|
||||||
|
- See API changes chapter. This change will keep the internal API consistent in the future
|
||||||
|
|
||||||
|
# [v1.1.0]
|
||||||
|
|
||||||
|
## API Changes
|
||||||
|
|
||||||
|
### PUS
|
||||||
|
|
||||||
|
- Added PUS C support
|
||||||
|
- SUBSYSTEM_IDs added for PUS Services
|
||||||
|
- Added new Parameter which must be defined in config: fsfwconfig::FSFW_MAX_TM_PACKET_SIZE
|
||||||
|
|
||||||
|
### ObjectManager
|
||||||
|
|
||||||
|
- ObjectManager is now a singelton
|
||||||
|
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
|
||||||
|
- Additional configuration option fsfwconfig::FSFW_MAX_TM_PACKET_SIZE which
|
||||||
|
need to be specified in FSFWConfig.h
|
||||||
|
|
||||||
|
### CMake
|
||||||
|
|
||||||
|
- Changed Cmake FSFW_ADDITIONAL_INC_PATH to FSFW_ADDITIONAL_INC_PATHS
|
||||||
|
|
||||||
|
## Bugfixes
|
||||||
|
|
||||||
|
- timemanager/TimeStamperIF.h: Timestamp config was not used correctly, leading to different timestamp sizes than configured in fsfwconfig::FSFW_MISSION_TIMESTAMP_SIZE
|
||||||
|
- TCP server fixes
|
||||||
|
|
||||||
|
## Enhancements
|
||||||
|
|
||||||
|
### FreeRTOS Queue Handles
|
||||||
|
|
||||||
|
- Fixed an internal issue how FreeRTOS MessageQueues were handled
|
||||||
|
|
||||||
|
### Linux OSAL
|
||||||
|
|
||||||
|
- Better printf error messages
|
||||||
|
|
||||||
|
### CMake
|
||||||
|
|
||||||
|
- Check for C++11 as mininimum required Version
|
||||||
|
|
||||||
|
### Debug Output
|
||||||
|
|
||||||
|
- Changed Warning color to magenta, which is well readable on both dark and light mode IDEs
|
||||||
|
|
||||||
|
|
||||||
|
# Changes from ASTP 0.0.1 to 1.0.0
|
||||||
|
|
||||||
|
### Host OSAL
|
||||||
|
|
||||||
|
- Bugfix in MessageQueue, which caused the sender not to be set properly
|
||||||
|
|
||||||
|
### FreeRTOS OSAL
|
||||||
|
|
||||||
|
- vRequestContextSwitchFromISR is declared extern "C" so it can be defined in
|
||||||
|
a C file without issues
|
||||||
|
|
||||||
|
### PUS Services
|
||||||
|
|
||||||
|
- It is now possible to change the message queue depth for the telecommand verification service (PUS1)
|
||||||
|
- The same is possible for the event reporting service (PUS5)
|
||||||
|
- PUS Health Service added, which allows to command and retrieve health via PUS packets
|
||||||
|
|
||||||
|
|
||||||
|
### EnhancedControllerBase
|
||||||
|
|
||||||
|
- New base class for a controller which also implements HasActionsIF and HasLocalDataPoolIF
|
||||||
|
|
||||||
|
### Local Pool
|
||||||
|
|
||||||
|
- Interface of LocalPools has changed. LocalPool is not a template anymore. Instead the size and
|
||||||
|
bucket number of the pools per page and the number of pages are passed to the ctor instead of
|
||||||
|
two ctor arguments and a template parameter
|
||||||
|
|
||||||
|
### Parameter Service
|
||||||
|
|
||||||
|
- The API of the parameter service has been changed to prevent inconsistencies
|
||||||
|
between documentation and actual code and to clarify usage.
|
||||||
|
- The parameter ID now consists of:
|
||||||
|
1. Domain ID (1 byte)
|
||||||
|
2. Unique Identifier (1 byte)
|
||||||
|
3. Linear Index (2 bytes)
|
||||||
|
The linear index can be used for arrays as well as matrices.
|
||||||
|
The parameter load command now explicitely expects the ECSS PTC and PFC
|
||||||
|
information as well as the rows and column number. Rows and column will
|
||||||
|
default to one, which is equivalent to one scalar parameter (the most
|
||||||
|
important use-case)
|
||||||
|
|
||||||
|
### File System Interface
|
||||||
|
|
||||||
|
- A new interfaces specifies the functions for a software object which exposes the file system of
|
||||||
|
a given hardware to use message based file handling (e.g. PUS commanding)
|
||||||
|
|
||||||
|
### Internal Error Reporter
|
||||||
|
|
||||||
|
- The new internal error reporter uses the local data pools. The pool IDs for
|
||||||
|
the exisiting three error values and the new error set will be hardcoded for
|
||||||
|
now, the the constructor for the internal error reporter just takes an object
|
||||||
|
ID for now.
|
||||||
|
|
||||||
|
### Device Handler Base
|
||||||
|
|
||||||
|
- There is an additional `PERFORM_OPERATION` step for the device handler base. It is important
|
||||||
|
that DHB users adapt their polling sequence tables to perform this step. This steps allows for
|
||||||
|
a clear distinction between operation and communication steps
|
||||||
|
- setNormalDatapoolEntriesInvalid is not an abstract method and a default implementation was provided
|
||||||
|
- getTransitionDelayMs is now an abstract method
|
||||||
|
|
||||||
|
### DeviceHandlerIF
|
||||||
|
|
||||||
|
- Typo for UNKNOWN_DEVICE_REPLY
|
||||||
|
|
||||||
|
### Events
|
||||||
|
|
||||||
|
- makeEvent function: Now takes three input parameters instead of two and
|
||||||
|
allows setting a unique ID. Event.cpp source file removed, functions now
|
||||||
|
defined in header directly. Namespaces renamed. Functions declared `constexpr`
|
||||||
|
now
|
||||||
|
|
||||||
|
### Commanding Service Base
|
||||||
|
|
||||||
|
- CSB uses the new fsfwconfig::FSFW_CSB_FIFO_DEPTH variable to determine the FIFO depth for each
|
||||||
|
CSB instance. This variable has to be set in the FSFWConfig.h file
|
||||||
|
|
||||||
|
### Service Interface
|
||||||
|
|
||||||
|
- Proper printf support contained in ServiceInterfacePrinter.h
|
||||||
|
- CPP ostream support now optional (can reduce executable size by 150 - 250 kB)
|
||||||
|
- Amalagated header which determines automatically which service interface to use depending on FSFWConfig.h configuration.
|
||||||
|
Users can just use #include <fsfw/serviceinterface/ServiceInterface.h>
|
||||||
|
- If CPP streams are excluded, sif:: calls won't work anymore and need to be replaced by their printf counterparts.
|
||||||
|
For the fsfw, this can be done by checking the processor define FSFW_CPP_OSTREAM_ENABLED from FSFWConfig.h.
|
||||||
|
For mission code, developers need to replace sif:: calls by the printf counterparts, but only if the CPP stream are excluded.
|
||||||
|
If this is not the case, everything should work as usual.
|
||||||
|
|
||||||
|
### ActionHelper and ActionMessage
|
||||||
|
|
||||||
|
- ActionHelper finish function and ActionMessage::setCompletionReply now expects explicit
|
||||||
|
information whether to report a success or failure message instead of deriving it implicitely
|
||||||
|
from returnvalue
|
||||||
|
|
||||||
|
### PUS Parameter Service 20
|
||||||
|
|
||||||
|
Added PUS parameter service 20 (only custom subservices available).
|
594
CMakeLists.txt
594
CMakeLists.txt
@ -1,206 +1,482 @@
|
|||||||
cmake_minimum_required(VERSION 3.13)
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
|
||||||
option(FSFW_GENERATE_SECTIONS
|
set(MSG_PREFIX "fsfw |")
|
||||||
"Generate function and data sections. Required to remove unused code" ON
|
|
||||||
)
|
|
||||||
|
|
||||||
|
# Add the cmake folder so the FindSphinx module is found
|
||||||
|
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||||
|
list(APPEND CMAKE_MODULE_PATH
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake-modules/bilke")
|
||||||
|
list(APPEND CMAKE_MODULE_PATH
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake-modules/rpavlik")
|
||||||
|
|
||||||
|
# ##############################################################################
|
||||||
|
# Version file handling #
|
||||||
|
# ##############################################################################
|
||||||
|
|
||||||
|
set(FSFW_VERSION_IF_GIT_FAILS 6)
|
||||||
|
set(FSFW_SUBVERSION_IF_GIT_FAILS 0)
|
||||||
|
set(FSFW_REVISION_IF_GIT_FAILS 0)
|
||||||
|
|
||||||
|
set(FSFW_GIT_VER_HANDLING_OK FALSE)
|
||||||
|
# Version handling
|
||||||
|
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git)
|
||||||
|
message(STATUS "${MSG_PREFIX} Determining version information with git")
|
||||||
|
include(FsfwHelpers)
|
||||||
|
determine_version_with_git("--exclude" "docker_*")
|
||||||
|
if(GIT_INFO)
|
||||||
|
set(FSFW_GIT_INFO
|
||||||
|
${GIT_INFO}
|
||||||
|
CACHE STRING "Version information retrieved with git describe")
|
||||||
|
list(GET FSFW_GIT_INFO 1 FSFW_VERSION)
|
||||||
|
list(GET FSFW_GIT_INFO 2 FSFW_SUBVERSION)
|
||||||
|
list(GET FSFW_GIT_INFO 3 FSFW_REVISION)
|
||||||
|
list(GET FSFW_GIT_INFO 4 FSFW_VCS_INFO)
|
||||||
|
if(NOT FSFW_VERSION)
|
||||||
|
set(FSFW_VERSION ${FSFW_VERSION_IF_GIT_FAILS})
|
||||||
|
endif()
|
||||||
|
if(NOT FSFW_SUBVERSION)
|
||||||
|
set(FSFW_SUBVERSION ${FSFW_SUBVERSION_IF_GIT_FAILS})
|
||||||
|
endif()
|
||||||
|
if(NOT FSFW_REVISION)
|
||||||
|
set(FSFW_REVISION ${FSFW_REVISION_IF_GIT_FAILS})
|
||||||
|
endif()
|
||||||
|
set(FSFW_GIT_VER_HANDLING_OK TRUE)
|
||||||
|
else()
|
||||||
|
set(FSFW_GIT_VER_HANDLING_OK FALSE)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
if(NOT FSFW_GIT_VER_HANDLING_OK)
|
||||||
|
set(FSFW_VERSION ${FSFW_VERSION_IF_GIT_FAILS})
|
||||||
|
set(FSFW_SUBVERSION ${FSFW_SUBVERSION_IF_GIT_FAILS})
|
||||||
|
set(FSFW_REVISION ${FSFW_REVISION_IF_GIT_FAILS})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(LIB_FSFW_NAME fsfw)
|
||||||
|
project(${LIB_FSFW_NAME}
|
||||||
|
VERSION ${FSFW_VERSION}.${FSFW_SUBVERSION}.${FSFW_REVISION})
|
||||||
|
|
||||||
|
if(NOT CMAKE_CXX_STANDARD)
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||||
|
elseif(${CMAKE_CXX_STANDARD} LESS 17)
|
||||||
|
message(
|
||||||
|
FATAL_ERROR
|
||||||
|
"${MSG_PREFIX} Compiling the FSFW requires a minimum of C++17 support")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(FSFW_SOURCES_DIR "${CMAKE_SOURCE_DIR}/src/fsfw")
|
||||||
|
|
||||||
|
set(FSFW_ETL_LIB_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}.28.0
|
||||||
|
CACHE STRING "ETL library exact version requirement")
|
||||||
|
set(FSFW_ETL_LINK_TARGET etl::etl)
|
||||||
|
|
||||||
|
set(FSFW_CATCH2_LIB_MAJOR_VERSION
|
||||||
|
3
|
||||||
|
CACHE STRING "Catch2 library major version requirement")
|
||||||
|
set(FSFW_CATCH2_LIB_VERSION
|
||||||
|
v${FSFW_CATCH2_LIB_MAJOR_VERSION}.1.0
|
||||||
|
CACHE STRING "Catch2 library exact version requirement")
|
||||||
|
|
||||||
|
# Keep this off by default for now. See PR:
|
||||||
|
# https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/616 for information which
|
||||||
|
# keeping this on by default is problematic
|
||||||
|
option(
|
||||||
|
FSFW_ENABLE_IPO
|
||||||
|
"Enable interprocedural optimization or link-time optimization if available"
|
||||||
|
OFF)
|
||||||
|
if(FSFW_ENABLE_IPO)
|
||||||
|
include(CheckIPOSupported)
|
||||||
|
check_ipo_supported(RESULT IPO_SUPPORTED OUTPUT IPO_ERROR)
|
||||||
|
if(NOT IPO_SUPPORTED)
|
||||||
|
message(STATUS "FSFW | IPO/LTO not supported: ${IPO_ERROR}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
option(FSFW_GENERATE_SECTIONS
|
||||||
|
"Generate function and data sections. Required to remove unused code" ON)
|
||||||
if(FSFW_GENERATE_SECTIONS)
|
if(FSFW_GENERATE_SECTIONS)
|
||||||
option(FSFW_REMOVE_UNUSED_CODE "Remove unused code" ON)
|
option(FSFW_REMOVE_UNUSED_CODE "Remove unused code" ON)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
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_TESTS)
|
||||||
|
option(FSFW_TESTS_GEN_COV "Generate coverage data for unittests" ON)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
option(FSFW_WARNING_SHADOW_LOCAL_GCC "Enable -Wshadow=local warning in GCC" ON)
|
option(FSFW_WARNING_SHADOW_LOCAL_GCC "Enable -Wshadow=local warning in GCC" ON)
|
||||||
# Options to exclude parts of the FSFW from compilation.
|
# Options to exclude parts of the FSFW from compilation.
|
||||||
option(FSFW_USE_RMAP "Compile with RMAP" ON)
|
option(FSFW_ADD_INTERNAL_TESTS "Add internal unit tests" ON)
|
||||||
option(FSFW_USE_DATALINKLAYER "Compile with Data Link Layer" ON)
|
option(FSFW_ADD_HAL "Add Hardware Abstraction Layer" ON)
|
||||||
|
|
||||||
|
if(UNIX)
|
||||||
|
option(FSFW_HAL_LINUX_ADD_PERIPHERAL_DRIVERS "Add Linux peripheral drivers"
|
||||||
|
OFF)
|
||||||
|
option(FSFW_HAL_LINUX_ADD_LIBGPIOD "Attempt to add Linux GPIOD drivers" OFF)
|
||||||
|
option(FSFW_HAL_LINUX_ADD_SERIAL_DRIVERS "Add serial drivers" ON)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Optional sources
|
||||||
|
option(FSFW_ADD_PUS "Compile with PUS sources" ON)
|
||||||
|
option(FSFW_ADD_MONITORING "Compile with monitoring components" ON)
|
||||||
|
|
||||||
|
option(FSFW_ADD_RMAP "Compile with RMAP" OFF)
|
||||||
|
option(FSFW_ADD_DATALINKLAYER "Compile with Data Link Layer" OFF)
|
||||||
|
option(FSFW_ADD_COORDINATES "Compile with coordinate components" OFF)
|
||||||
|
option(FSFW_ADD_TMSTORAGE "Compile with tm storage components" OFF)
|
||||||
|
|
||||||
|
# Contrib sources
|
||||||
|
option(FSFW_ADD_SGP4_PROPAGATOR "Add SGP4 propagator code" OFF)
|
||||||
|
|
||||||
|
set(FSFW_TEST_TGT fsfw-tests)
|
||||||
|
set(FSFW_DUMMY_TGT fsfw-dummy)
|
||||||
|
|
||||||
set(LIB_FSFW_NAME fsfw)
|
|
||||||
add_library(${LIB_FSFW_NAME})
|
add_library(${LIB_FSFW_NAME})
|
||||||
|
|
||||||
set_property(CACHE OS_FSFW PROPERTY STRINGS host linux rtems freertos)
|
if(IPO_SUPPORTED AND FSFW_ENABLE_IPO)
|
||||||
|
set_property(TARGET ${LIB_FSFW_NAME} PROPERTY INTERPROCEDURAL_OPTIMIZATION
|
||||||
if(NOT OS_FSFW)
|
TRUE)
|
||||||
message(STATUS "No OS for FSFW via OS_FSFW set. Assuming host OS")
|
|
||||||
# Assume host OS and autodetermine from OS_FSFW
|
|
||||||
if(UNIX)
|
|
||||||
set(OS_FSFW "linux"
|
|
||||||
CACHE STRING
|
|
||||||
"OS abstraction layer used in the FSFW"
|
|
||||||
)
|
|
||||||
elseif(WIN32)
|
|
||||||
set(OS_FSFW "host"
|
|
||||||
CACHE STRING "OS abstraction layer used in the FSFW"
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(FSFW_OSAL_DEFINITION FSFW_HOST)
|
if(FSFW_BUILD_TESTS)
|
||||||
|
message(
|
||||||
|
STATUS
|
||||||
|
"${MSG_PREFIX} Building the FSFW unittests in addition to the static library"
|
||||||
|
)
|
||||||
|
# Check whether the user has already installed Catch2 first
|
||||||
|
find_package(Catch2 ${FSFW_CATCH2_LIB_MAJOR_VERSION} QUIET)
|
||||||
|
# Not installed, so use FetchContent to download and provide Catch2
|
||||||
|
if(NOT Catch2_FOUND)
|
||||||
|
message(
|
||||||
|
STATUS
|
||||||
|
"${MSG_PREFIX} Catch2 installation not found. Downloading Catch2 library with FetchContent."
|
||||||
|
)
|
||||||
|
include(FetchContent)
|
||||||
|
|
||||||
if(${OS_FSFW} STREQUAL host)
|
FetchContent_Declare(
|
||||||
set(OS_FSFW_NAME "Host")
|
Catch2
|
||||||
elseif(${OS_FSFW} STREQUAL linux)
|
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
|
||||||
set(OS_FSFW_NAME "Linux")
|
GIT_TAG ${FSFW_CATCH2_LIB_VERSION})
|
||||||
set(FSFW_OSAL_DEFINITION FSFW_LINUX)
|
|
||||||
elseif(${OS_FSFW} STREQUAL freertos)
|
list(APPEND FSFW_FETCH_CONTENT_TARGETS Catch2)
|
||||||
set(OS_FSFW_NAME "FreeRTOS")
|
endif()
|
||||||
set(FSFW_OSAL_DEFINITION FSFW_FREERTOS)
|
|
||||||
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
|
set(FSFW_CONFIG_PATH unittests/testcfg)
|
||||||
${LIB_OS_NAME}
|
configure_file(unittests/testcfg/FSFWConfig.h.in FSFWConfig.h)
|
||||||
)
|
configure_file(unittests/testcfg/TestsConfig.h.in tests/TestsConfig.h)
|
||||||
elseif(${OS_FSFW} STREQUAL rtems)
|
|
||||||
set(OS_FSFW_NAME "RTEMS")
|
project(${FSFW_TEST_TGT} CXX C)
|
||||||
set(FSFW_OSAL_DEFINITION FSFW_RTEMS)
|
add_executable(${FSFW_TEST_TGT})
|
||||||
|
if(IPO_SUPPORTED AND FSFW_ENABLE_IPO)
|
||||||
|
set_property(TARGET ${FSFW_TEST_TGT} PROPERTY INTERPROCEDURAL_OPTIMIZATION
|
||||||
|
TRUE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(FSFW_TESTS_GEN_COV)
|
||||||
|
message(STATUS "${MSG_PREFIX} Generating coverage data for the library")
|
||||||
|
message(STATUS "${MSG_PREFIX} Targets linking against ${LIB_FSFW_NAME} "
|
||||||
|
"will be compiled with coverage data as well")
|
||||||
|
set(CMAKE_BUILD_TYPE "Debug")
|
||||||
|
include(CodeCoverage)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
message(
|
||||||
|
STATUS
|
||||||
|
"${MSG_PREFIX} Finding and/or providing etl library with version ${FSFW_ETL_LIB_MAJOR_VERSION}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Check whether the user has already installed ETL first
|
||||||
|
find_package(${FSFW_ETL_LIB_NAME} ${FSFW_ETL_LIB_MAJOR_VERSION} QUIET)
|
||||||
|
# Not installed, so use FetchContent to download and provide etl
|
||||||
|
if(NOT ${FSFW_ETL_LIB_NAME}_FOUND)
|
||||||
|
message(
|
||||||
|
STATUS
|
||||||
|
"${MSG_PREFIX} ETL installation not found. Downloading ETL with FetchContent."
|
||||||
|
)
|
||||||
|
include(FetchContent)
|
||||||
|
|
||||||
|
FetchContent_Declare(
|
||||||
|
${FSFW_ETL_LIB_NAME}
|
||||||
|
GIT_REPOSITORY https://github.com/ETLCPP/etl
|
||||||
|
GIT_TAG ${FSFW_ETL_LIB_VERSION})
|
||||||
|
|
||||||
|
list(APPEND FSFW_FETCH_CONTENT_TARGETS ${FSFW_ETL_LIB_NAME})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# The documentation for FetchContent recommends declaring all the dependencies
|
||||||
|
# before making them available. We make all declared dependency available here
|
||||||
|
# after their declaration
|
||||||
|
if(FSFW_FETCH_CONTENT_TARGETS)
|
||||||
|
FetchContent_MakeAvailable(${FSFW_FETCH_CONTENT_TARGETS})
|
||||||
|
if(TARGET ${FSFW_ETL_LIB_NAME})
|
||||||
|
add_library(${FSFW_ETL_LINK_TARGET} ALIAS ${FSFW_ETL_LIB_NAME})
|
||||||
|
endif()
|
||||||
|
if(TARGET Catch2)
|
||||||
|
# Fixes regression -preview4, to be confirmed in later releases Related
|
||||||
|
# GitHub issue: https://github.com/catchorg/Catch2/issues/2417
|
||||||
|
set_target_properties(Catch2 PROPERTIES DEBUG_POSTFIX "")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(FSFW_CORE_INC_PATH "inc")
|
||||||
|
|
||||||
|
set_property(CACHE FSFW_OSAL PROPERTY STRINGS host linux rtems freertos)
|
||||||
|
|
||||||
|
# For configure files
|
||||||
|
target_include_directories(${LIB_FSFW_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
target_include_directories(${LIB_FSFW_NAME}
|
||||||
|
INTERFACE ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
||||||
|
# Backwards comptability
|
||||||
|
if(OS_FSFW AND NOT FSFW_OSAL)
|
||||||
|
message(
|
||||||
|
WARNING
|
||||||
|
"${MSG_PREFIX} Please pass the FSFW OSAL as FSFW_OSAL instead of OS_FSFW")
|
||||||
|
set(FSFW_OSAL OS_FSFW)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT FSFW_OSAL)
|
||||||
|
message(STATUS "No OS for FSFW via FSFW_OSAL set. Assuming host OS")
|
||||||
|
# Assume host OS and autodetermine from OS_FSFW
|
||||||
|
if(UNIX)
|
||||||
|
set(FSFW_OSAL
|
||||||
|
"linux"
|
||||||
|
CACHE STRING "OS abstraction layer used in the FSFW")
|
||||||
|
elseif(WIN32)
|
||||||
|
set(FSFW_OSAL
|
||||||
|
"host"
|
||||||
|
CACHE STRING "OS abstraction layer used in the FSFW")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(FSFW_OSAL_DEFINITION FSFW_OSAL_HOST)
|
||||||
|
|
||||||
|
if(FSFW_OSAL MATCHES host)
|
||||||
|
set(FSFW_OS_NAME "Host")
|
||||||
|
set(FSFW_OSAL_HOST ON)
|
||||||
|
elseif(FSFW_OSAL MATCHES linux)
|
||||||
|
set(FSFW_OS_NAME "Linux")
|
||||||
|
set(FSFW_OSAL_LINUX ON)
|
||||||
|
elseif(FSFW_OSAL MATCHES freertos)
|
||||||
|
set(FSFW_OS_NAME "FreeRTOS")
|
||||||
|
set(FSFW_OSAL_FREERTOS ON)
|
||||||
|
target_link_libraries(${LIB_FSFW_NAME} PRIVATE ${LIB_OS_NAME})
|
||||||
|
elseif(FSFW_OSAL STREQUAL rtems)
|
||||||
|
set(FSFW_OS_NAME "RTEMS")
|
||||||
|
set(FSFW_OSAL_RTEMS ON)
|
||||||
else()
|
else()
|
||||||
message(WARNING
|
message(
|
||||||
"Invalid operating system for FSFW specified! Setting to host.."
|
WARNING
|
||||||
)
|
"${MSG_PREFIX} Invalid operating system for FSFW specified! Setting to host.."
|
||||||
set(OS_FSFW_NAME "Host")
|
)
|
||||||
set(OS_FSFW "host")
|
set(FSFW_OS_NAME "Host")
|
||||||
|
set(OS_FSFW "host")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_compile_definitions(${LIB_FSFW_NAME} PRIVATE
|
configure_file(src/fsfw/FSFW.h.in fsfw/FSFW.h)
|
||||||
${FSFW_OSAL_DEFINITION}
|
configure_file(src/fsfw/FSFWVersion.h.in fsfw/FSFWVersion.h)
|
||||||
|
|
||||||
|
message(
|
||||||
|
STATUS "${MSG_PREFIX} Compiling FSFW for the ${FSFW_OS_NAME} operating system"
|
||||||
)
|
)
|
||||||
|
|
||||||
target_compile_definitions(${LIB_FSFW_NAME} INTERFACE
|
add_subdirectory(src)
|
||||||
${FSFW_OSAL_DEFINITION}
|
add_subdirectory(contrib)
|
||||||
)
|
if(FSFW_BUILD_TESTS)
|
||||||
|
add_subdirectory(unittests)
|
||||||
message(STATUS "Compiling FSFW for the ${OS_FSFW_NAME} operating system.")
|
endif()
|
||||||
|
if(FSFW_BUILD_DOCS)
|
||||||
add_subdirectory(action)
|
add_subdirectory(docs)
|
||||||
add_subdirectory(container)
|
|
||||||
add_subdirectory(controller)
|
|
||||||
add_subdirectory(coordinates)
|
|
||||||
|
|
||||||
if(FSFW_USE_DATALINKLAYER)
|
|
||||||
add_subdirectory(datalinklayer)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_subdirectory(datapool)
|
if(FSFW_BUILD_TESTS)
|
||||||
add_subdirectory(datapoollocal)
|
if(FSFW_TESTS_GEN_COV)
|
||||||
add_subdirectory(housekeeping)
|
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||||
add_subdirectory(devicehandlers)
|
include(CodeCoverage)
|
||||||
add_subdirectory(events)
|
|
||||||
add_subdirectory(fdir)
|
|
||||||
add_subdirectory(globalfunctions)
|
|
||||||
add_subdirectory(health)
|
|
||||||
add_subdirectory(internalError)
|
|
||||||
add_subdirectory(ipc)
|
|
||||||
add_subdirectory(memory)
|
|
||||||
add_subdirectory(modes)
|
|
||||||
add_subdirectory(monitoring)
|
|
||||||
add_subdirectory(objectmanager)
|
|
||||||
add_subdirectory(osal)
|
|
||||||
add_subdirectory(parameters)
|
|
||||||
add_subdirectory(power)
|
|
||||||
add_subdirectory(pus)
|
|
||||||
|
|
||||||
if(FSFW_USE_RMAP)
|
# Remove quotes.
|
||||||
add_subdirectory(rmap)
|
separate_arguments(COVERAGE_COMPILER_FLAGS NATIVE_COMMAND
|
||||||
|
"${COVERAGE_COMPILER_FLAGS}")
|
||||||
|
|
||||||
|
# Add compile options manually, we don't want coverage for Catch2
|
||||||
|
target_compile_options(${FSFW_TEST_TGT}
|
||||||
|
PRIVATE "${COVERAGE_COMPILER_FLAGS}")
|
||||||
|
target_compile_options(${LIB_FSFW_NAME}
|
||||||
|
PRIVATE "${COVERAGE_COMPILER_FLAGS}")
|
||||||
|
|
||||||
|
# Exclude directories here
|
||||||
|
if(WIN32)
|
||||||
|
set(GCOVR_ADDITIONAL_ARGS "--exclude-throw-branches"
|
||||||
|
"--exclude-unreachable-branches")
|
||||||
|
set(COVERAGE_EXCLUDES "/c/msys64/mingw64/*" "*/fsfw_hal/*")
|
||||||
|
elseif(UNIX)
|
||||||
|
set(COVERAGE_EXCLUDES
|
||||||
|
"/usr/include/*"
|
||||||
|
"/usr/bin/*"
|
||||||
|
"Catch2/*"
|
||||||
|
"/usr/local/include/*"
|
||||||
|
"*/fsfw_tests/*"
|
||||||
|
"*/catch2-src/*"
|
||||||
|
"*/fsfw_hal/*"
|
||||||
|
"unittests/*")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
target_link_options(${FSFW_TEST_TGT} PRIVATE -fprofile-arcs
|
||||||
|
-ftest-coverage)
|
||||||
|
target_link_options(${LIB_FSFW_NAME} PRIVATE -fprofile-arcs
|
||||||
|
-ftest-coverage)
|
||||||
|
# Need to specify this as an interface, otherwise there will the compile
|
||||||
|
# issues
|
||||||
|
target_link_options(${LIB_FSFW_NAME} INTERFACE -fprofile-arcs
|
||||||
|
-ftest-coverage)
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
setup_target_for_coverage_gcovr_html(
|
||||||
|
NAME ${FSFW_TEST_TGT}_coverage EXECUTABLE ${FSFW_TEST_TGT}
|
||||||
|
DEPENDENCIES ${FSFW_TEST_TGT})
|
||||||
|
else()
|
||||||
|
setup_target_for_coverage_lcov(
|
||||||
|
NAME
|
||||||
|
${FSFW_TEST_TGT}_coverage
|
||||||
|
EXECUTABLE
|
||||||
|
${FSFW_TEST_TGT}
|
||||||
|
DEPENDENCIES
|
||||||
|
${FSFW_TEST_TGT}
|
||||||
|
GENHTML_ARGS
|
||||||
|
--html-epilog
|
||||||
|
${CMAKE_SOURCE_DIR}/unittests/lcov_epilog.html)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
target_link_libraries(${FSFW_TEST_TGT} PRIVATE Catch2::Catch2
|
||||||
|
${LIB_FSFW_NAME})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_subdirectory(serialize)
|
# The project CMakeLists file has to set the FSFW_CONFIG_PATH and add it. If
|
||||||
add_subdirectory(serviceinterface)
|
# this is not given, we include the default configuration and emit a warning.
|
||||||
add_subdirectory(storagemanager)
|
|
||||||
add_subdirectory(subsystem)
|
|
||||||
add_subdirectory(tasks)
|
|
||||||
add_subdirectory(tcdistribution)
|
|
||||||
add_subdirectory(thermal)
|
|
||||||
add_subdirectory(timemanager)
|
|
||||||
add_subdirectory(tmstorage)
|
|
||||||
add_subdirectory(tmtcpacket)
|
|
||||||
add_subdirectory(tmtcservices)
|
|
||||||
add_subdirectory(unittest)
|
|
||||||
|
|
||||||
# The project CMakeLists file has to set the FSFW_CONFIG_PATH and add it.
|
|
||||||
# If this is not given, we include the default configuration and emit a warning.
|
|
||||||
if(NOT FSFW_CONFIG_PATH)
|
if(NOT FSFW_CONFIG_PATH)
|
||||||
message(WARNING "Flight Software Framework configuration path not set!")
|
set(DEF_CONF_PATH misc/defaultcfg/fsfwconfig)
|
||||||
message(WARNING "Setting default configuration!")
|
if(NOT FSFW_BUILD_DOCS)
|
||||||
add_subdirectory(defaultcfg/fsfwconfig)
|
message(
|
||||||
|
WARNING
|
||||||
|
"${MSG_PREFIX} Flight Software Framework configuration path FSFW_CONFIG_PATH not set"
|
||||||
|
)
|
||||||
|
message(
|
||||||
|
WARNING
|
||||||
|
"${MSG_PREFIX} Setting default configuration from ${DEF_CONF_PATH} ..")
|
||||||
|
endif()
|
||||||
|
add_subdirectory(${DEF_CONF_PATH})
|
||||||
|
set(FSFW_CONFIG_PATH ${DEF_CONF_PATH})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# FSFW might be part of a possibly complicated folder structure, so we
|
# FSFW might be part of a possibly complicated folder structure, so we extract
|
||||||
# extract the absolute path of the fsfwconfig folder.
|
# the absolute path of the fsfwconfig folder.
|
||||||
if(IS_ABSOLUTE ${FSFW_CONFIG_PATH})
|
if(IS_ABSOLUTE ${FSFW_CONFIG_PATH})
|
||||||
set(FSFW_CONFIG_PATH_ABSOLUTE ${FSFW_CONFIG_PATH})
|
set(FSFW_CONFIG_PATH_ABSOLUTE ${FSFW_CONFIG_PATH})
|
||||||
else()
|
else()
|
||||||
get_filename_component(FSFW_CONFIG_PATH_ABSOLUTE
|
get_filename_component(FSFW_CONFIG_PATH_ABSOLUTE ${FSFW_CONFIG_PATH} REALPATH
|
||||||
${FSFW_CONFIG_PATH} REALPATH BASE_DIR ${CMAKE_SOURCE_DIR}
|
BASE_DIR ${CMAKE_SOURCE_DIR})
|
||||||
)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
foreach(INCLUDE_PATH ${FSFW_ADDITIONAL_INC_PATH})
|
foreach(INCLUDE_PATH ${FSFW_ADDITIONAL_INC_PATHS})
|
||||||
if(IS_ABSOLUTE ${INCLUDE_PATH})
|
if(IS_ABSOLUTE ${INCLUDE_PATH})
|
||||||
set(CURR_ABS_INC_PATH "${FREERTOS_PATH}")
|
set(CURR_ABS_INC_PATH "${INCLUDE_PATH}")
|
||||||
else()
|
else()
|
||||||
get_filename_component(CURR_ABS_INC_PATH
|
get_filename_component(CURR_ABS_INC_PATH ${INCLUDE_PATH} REALPATH BASE_DIR
|
||||||
${INCLUDE_PATH} REALPATH BASE_DIR ${CMAKE_SOURCE_DIR})
|
${CMAKE_SOURCE_DIR})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(CMAKE_VERBOSE)
|
if(CMAKE_VERBOSE)
|
||||||
message(STATUS "FSFW include path: ${CURR_ABS_INC_PATH}")
|
message(STATUS "FSFW include path: ${CURR_ABS_INC_PATH}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
list(APPEND FSFW_ADD_INC_PATHS_ABS ${CURR_ABS_INC_PATH})
|
list(APPEND FSFW_ADD_INC_PATHS_ABS ${CURR_ABS_INC_PATH})
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||||
if(NOT DEFINED FSFW_WARNING_FLAGS)
|
if(NOT DEFINED FSFW_WARNING_FLAGS)
|
||||||
set(FSFW_WARNING_FLAGS
|
set(FSFW_WARNING_FLAGS
|
||||||
-Wall
|
-Wall
|
||||||
-Wextra
|
-Wextra
|
||||||
-Wimplicit-fallthrough=1
|
-Wimplicit-fallthrough=1
|
||||||
-Wno-unused-parameter
|
-Wno-unused-parameter
|
||||||
-Wno-psabi
|
-Wno-psabi
|
||||||
)
|
-Wduplicated-cond # check for duplicate conditions
|
||||||
endif()
|
-Wduplicated-branches # check for duplicate branches
|
||||||
|
-Wlogical-op # Search for bitwise operations instead of logical
|
||||||
|
-Wnull-dereference # Search for NULL dereference
|
||||||
|
-Wundef # Warn if undefind marcos are used
|
||||||
|
-Wformat=2 # Format string problem detection
|
||||||
|
-Wformat-overflow=2 # Formatting issues in printf
|
||||||
|
-Wformat-truncation=2 # Formatting issues in printf
|
||||||
|
-Wformat-security # Search for dangerous printf operations
|
||||||
|
-Wstrict-overflow=3 # Warn if integer overflows might happen
|
||||||
|
-Warray-bounds=2 # Some array bounds violations will be found
|
||||||
|
-Wshift-overflow=2 # Search for bit left shift overflows (<c++14)
|
||||||
|
-Wcast-qual # Warn if the constness is cast away
|
||||||
|
-Wstringop-overflow=4
|
||||||
|
# -Wstack-protector # Emits a few false positives for low level access
|
||||||
|
# -Wconversion # Creates many false positives -Warith-conversion # Use
|
||||||
|
# with Wconversion to find more implicit conversions -fanalyzer # Should
|
||||||
|
# be used to look through problems
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(FSFW_GENERATE_SECTIONS)
|
if(FSFW_GENERATE_SECTIONS)
|
||||||
target_compile_options(${LIB_FSFW_NAME} PRIVATE
|
target_compile_options(${LIB_FSFW_NAME} PRIVATE "-ffunction-sections"
|
||||||
"-ffunction-sections"
|
"-fdata-sections")
|
||||||
"-fdata-sections"
|
endif()
|
||||||
)
|
|
||||||
endif()
|
if(FSFW_REMOVE_UNUSED_CODE)
|
||||||
|
target_link_options(${LIB_FSFW_NAME} PRIVATE "Wl,--gc-sections")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(FSFW_WARNING_SHADOW_LOCAL_GCC)
|
||||||
|
list(APPEND WARNING_FLAGS "-Wshadow=local")
|
||||||
|
endif()
|
||||||
|
|
||||||
if(FSFW_REMOVE_UNUSED_CODE)
|
|
||||||
target_link_options(${LIB_FSFW_NAME} PRIVATE
|
|
||||||
"Wl,--gc-sections"
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(FSFW_WARNING_SHADOW_LOCAL_GCC)
|
|
||||||
list(APPEND WARNING_FLAGS "-Wshadow=local")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
||||||
set(COMPILER_FLAGS "/permissive-")
|
set(COMPILER_FLAGS "/permissive-")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Required include paths to compile the FSFW
|
# Required include paths to compile the FSFW
|
||||||
target_include_directories(${LIB_FSFW_NAME} INTERFACE
|
target_include_directories(
|
||||||
${CMAKE_SOURCE_DIR}
|
${LIB_FSFW_NAME} INTERFACE ${CMAKE_SOURCE_DIR} ${FSFW_CONFIG_PATH_ABSOLUTE}
|
||||||
${FSFW_CONFIG_PATH_ABSOLUTE}
|
${FSFW_CORE_INC_PATH} ${FSFW_ADD_INC_PATHS_ABS})
|
||||||
${FSFW_ADD_INC_PATHS_ABS}
|
|
||||||
)
|
|
||||||
|
|
||||||
# Includes path required to compile FSFW itself as well
|
# Includes path required to compile FSFW itself as well We assume that the
|
||||||
# We assume that the fsfwconfig folder uses include relative to the project
|
# fsfwconfig folder uses include relative to the project root here!
|
||||||
# root here!
|
target_include_directories(
|
||||||
target_include_directories(${LIB_FSFW_NAME} PRIVATE
|
${LIB_FSFW_NAME} PRIVATE ${CMAKE_SOURCE_DIR} ${FSFW_CONFIG_PATH_ABSOLUTE}
|
||||||
${CMAKE_SOURCE_DIR}
|
${FSFW_CORE_INC_PATH} ${FSFW_ADD_INC_PATHS_ABS})
|
||||||
${FSFW_CONFIG_PATH_ABSOLUTE}
|
|
||||||
${FSFW_ADD_INC_PATHS_ABS}
|
|
||||||
)
|
|
||||||
|
|
||||||
target_compile_options(${LIB_FSFW_NAME} PRIVATE
|
target_compile_options(${LIB_FSFW_NAME} PRIVATE ${FSFW_WARNING_FLAGS}
|
||||||
${FSFW_WARNING_FLAGS}
|
${COMPILER_FLAGS})
|
||||||
${COMPILER_FLAGS}
|
|
||||||
)
|
|
||||||
|
|
||||||
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
|
target_link_libraries(${LIB_FSFW_NAME} PRIVATE ${FSFW_ADDITIONAL_LINK_LIBS})
|
||||||
${FSFW_ADDITIONAL_LINK_LIBS}
|
target_link_libraries(${LIB_FSFW_NAME} PUBLIC ${FSFW_ETL_LINK_TARGET})
|
||||||
)
|
|
||||||
|
string(
|
||||||
|
CONCAT
|
||||||
|
POST_BUILD_COMMENT
|
||||||
|
"######################################################################\n"
|
||||||
|
"Built FSFW v${FSFW_VERSION}.${FSFW_SUBVERSION}.${FSFW_REVISION}, "
|
||||||
|
"Target OSAL: ${FSFW_OS_NAME}\n"
|
||||||
|
"######################################################################\n")
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
TARGET ${LIB_FSFW_NAME}
|
||||||
|
POST_BUILD
|
||||||
|
COMMENT ${POST_BUILD_COMMENT})
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
#ifndef FSFW_DEFAULTCFG_VERSION_H_
|
|
||||||
#define FSFW_DEFAULTCFG_VERSION_H_
|
|
||||||
|
|
||||||
const char* const FSFW_VERSION_NAME = "ASTP";
|
|
||||||
|
|
||||||
#define FSFW_VERSION 1
|
|
||||||
#define FSFW_SUBVERSION 0
|
|
||||||
#define FSFW_REVISION 0
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* FSFW_DEFAULTCFG_VERSION_H_ */
|
|
0
FSFWVersion.h.in
Normal file
0
FSFWVersion.h.in
Normal file
190
README.md
190
README.md
@ -1,4 +1,4 @@
|
|||||||

|

|
||||||
|
|
||||||
# Flight Software Framework (FSFW)
|
# Flight Software Framework (FSFW)
|
||||||
|
|
||||||
@ -11,9 +11,15 @@ with Airbus Defence and Space GmbH.
|
|||||||
|
|
||||||
## Quick facts
|
## Quick facts
|
||||||
|
|
||||||
The framework is designed for systems, which communicate with external devices, perform control loops, receive telecommands and send telemetry, and need to maintain a high level of availability. Therefore, a mode and health system provides control over the states of the software and the controlled devices. In addition, a simple mechanism of event based fault detection, isolation and recovery is implemented as well.
|
The framework is designed for systems, which communicate with external devices, perform control loops,
|
||||||
|
receive telecommands and send telemetry, and need to maintain a high level of availability. Therefore,
|
||||||
|
a mode and health system provides control over the states of the software and the controlled devices.
|
||||||
|
In addition, a simple mechanism of event based fault detection, isolation and recovery is implemented as well.
|
||||||
|
|
||||||
The FSFW provides abstraction layers for operating systems to provide a uniform operating system abstraction layer (OSAL). Some components of this OSAL are required internally by the FSFW but is also very useful for developers to implement the same application logic on different operating systems with a uniform interface.
|
The FSFW provides abstraction layers for operating systems to provide a uniform operating system
|
||||||
|
abstraction layer (OSAL). Some components of this OSAL are required internally by the FSFW but is
|
||||||
|
also very useful for developers to implement the same application logic on different operating
|
||||||
|
systems with a uniform interface.
|
||||||
|
|
||||||
Currently, the FSFW provides the following OSALs:
|
Currently, the FSFW provides the following OSALs:
|
||||||
|
|
||||||
@ -22,27 +28,181 @@ Currently, the FSFW provides the following OSALs:
|
|||||||
- FreeRTOS
|
- FreeRTOS
|
||||||
- RTEMS
|
- RTEMS
|
||||||
|
|
||||||
The recommended hardware is a microprocessor with more than 1 MB of RAM and 1 MB of non-volatile Memory. For reference, current applications use a Cobham Gaisler UT699 (LEON3FT), a ISISPACE IOBC or a Zynq-7020 SoC. The `fsfw` was also successfully run on the STM32H743ZI-Nucleo board and on a Raspberry Pi and is currently running on the active satellite mission Flying Laptop.
|
The recommended hardware is a microprocessor with more than 1 MB of RAM and 1 MB of non-volatile
|
||||||
|
memory. For reference, current applications use a Cobham Gaisler UT699 (LEON3FT), a
|
||||||
|
ISISPACE IOBC or a Zynq-7020 SoC. The `fsfw` was also successfully run on the
|
||||||
|
STM32H743ZI-Nucleo board and on a Raspberry Pi and is currently running on the active
|
||||||
|
satellite mission Flying Laptop.
|
||||||
|
|
||||||
## Getting started
|
## Getting started
|
||||||
|
|
||||||
The [FSFW example](https://egit.irs.uni-stuttgart.de/fsfw/fsfw_example) provides a good starting point and a demo to see the FSFW capabilities and build it with the Make or the CMake build system. It is recommended to evaluate the FSFW by building and playing around with the demo application.
|
The [Hosted FSFW example](https://egit.irs.uni-stuttgart.de/fsfw/fsfw-example-hosted) provides a
|
||||||
|
good starting point and a demo to see the FSFW capabilities.
|
||||||
|
It is recommended to get started by building and playing around with the demo application.
|
||||||
|
There are also other examples provided for all OSALs using the popular embedded platforms
|
||||||
|
Raspberry Pi, Beagle Bone Black and STM32H7.
|
||||||
|
|
||||||
Generally, the FSFW is included in a project by compiling the FSFW sources and providing
|
Generally, the FSFW is included in a project by providing
|
||||||
a configuration folder and adding it to the include path. There are some functions like `printChar` which are different depending on the target architecture and need to be implemented by the mission developer.
|
a configuration folder, building the static library and linking against it.
|
||||||
|
There are some functions like `printChar` which are different depending on the target architecture
|
||||||
|
and need to be implemented by the mission developer.
|
||||||
|
|
||||||
A template configuration folder was provided and can be copied into the project root to have
|
A template configuration folder was provided and can be copied into the project root to have
|
||||||
a starting point. The [configuration section](doc/README-config.md#top) provides more specific information about the possible options.
|
a starting point. The [configuration section](docs/README-config.md#top) provides more specific
|
||||||
|
information about the possible options.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
The Embedded Template Library (etl) is a dependency of the FSFW which is automatically
|
||||||
|
installed and provided by the build system unless the correction version was installed.
|
||||||
|
The current recommended version can be found inside the fsfw `CMakeLists.txt` file or by using
|
||||||
|
`ccmake` and looking up the `FSFW_ETL_LIB_MAJOR_VERSION` variable.
|
||||||
|
|
||||||
|
You can install the ETL library like this. On Linux, it might be necessary to add `sudo` before
|
||||||
|
the install call:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
git clone https://github.com/ETLCPP/etl
|
||||||
|
cd etl
|
||||||
|
git checkout <currentRecommendedVersion>
|
||||||
|
mkdir build && cd build
|
||||||
|
cmake ..
|
||||||
|
cmake --install .
|
||||||
|
```
|
||||||
|
|
||||||
|
It is recommended to install `20.27.2` or newer for the package version handling of
|
||||||
|
ETL to work.
|
||||||
|
|
||||||
|
## Adding the library
|
||||||
|
|
||||||
|
The following steps show how to add and use FSFW components. It is still recommended to
|
||||||
|
try out the example mentioned above to get started, but the following steps show how to
|
||||||
|
add and link against the FSFW library in general.
|
||||||
|
|
||||||
|
1. Add this repository as a submodule
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git submodule add https://egit.irs.uni-stuttgart.de/fsfw/fsfw.git fsfw
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Add the following directive inside the uppermost `CMakeLists.txt` file of your project
|
||||||
|
|
||||||
|
```cmake
|
||||||
|
add_subdirectory(fsfw)
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Make sure to provide a configuration folder and supply the path to that folder with
|
||||||
|
the `FSFW_CONFIG_PATH` CMake variable from the uppermost `CMakeLists.txt` file.
|
||||||
|
It is also necessary to provide the `printChar` function. You can find an example
|
||||||
|
implementation for a hosted build
|
||||||
|
[here](https://egit.irs.uni-stuttgart.de/fsfw/fsfw-example-hosted/src/branch/master/bsp_hosted/utility/printChar.c).
|
||||||
|
|
||||||
|
4. Link against the FSFW library
|
||||||
|
|
||||||
|
```sh
|
||||||
|
target_link_libraries(${YourProjectName} PRIVATE fsfw)
|
||||||
|
```
|
||||||
|
|
||||||
|
5. It should now be possible use the FSFW as a static library from the user code.
|
||||||
|
|
||||||
|
## Building the unittests
|
||||||
|
|
||||||
|
The FSFW also has unittests which use the [Catch2 library](https://github.com/catchorg/Catch2).
|
||||||
|
These are built by setting the CMake option `FSFW_BUILD_UNITTESTS` to `ON` or `TRUE`
|
||||||
|
from your project `CMakeLists.txt` file or from the command line.
|
||||||
|
|
||||||
|
You can install the Catch2 library, which prevents the build system to avoid re-downloading
|
||||||
|
the dependency if the unit tests are completely rebuilt. The current recommended version
|
||||||
|
can be found inside the fsfw `CMakeLists.txt` file or by using `ccmake` and looking up
|
||||||
|
the `FSFW_CATCH2_LIB_VERSION` variable.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git clone https://github.com/catchorg/Catch2.git
|
||||||
|
cd Catch2
|
||||||
|
git checkout <currentRecommendedVersion>
|
||||||
|
cmake -Bbuild -H. -DBUILD_TESTING=OFF
|
||||||
|
sudo cmake --build build/ --target install
|
||||||
|
```
|
||||||
|
|
||||||
|
The fsfw-tests binary will be built as part of the static library and dropped alongside it.
|
||||||
|
If the unittests are built, the library and the tests will be built with coverage information by
|
||||||
|
default. This can be disabled by setting the `FSFW_TESTS_COV_GEN` option to `OFF` or `FALSE`.
|
||||||
|
|
||||||
|
You can use the following commands inside the `fsfw` folder to set up the build system
|
||||||
|
|
||||||
|
```sh
|
||||||
|
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 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
|
||||||
|
cmake --build . -- fsfw-tests_coverage -j
|
||||||
|
```
|
||||||
|
|
||||||
|
The `coverage.py` script located in the `script` folder can also be used to do this conveniently.
|
||||||
|
|
||||||
|
## Building the documentations
|
||||||
|
|
||||||
|
The FSFW documentation is built using the tools Sphinx, doxygen and breathe based on the
|
||||||
|
instructions provided in [this blogpost](https://devblogs.microsoft.com/cppblog/clear-functional-c-documentation-with-sphinx-breathe-doxygen-cmake/). If you
|
||||||
|
want to do this locally, set up the prerequisites first. This requires a ``python3``
|
||||||
|
installation as well. Example here is for Ubuntu.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo apt-get install doxygen graphviz
|
||||||
|
```
|
||||||
|
|
||||||
|
And the following Python packages
|
||||||
|
|
||||||
|
```sh
|
||||||
|
python3 -m pip install sphinx breathe
|
||||||
|
```
|
||||||
|
|
||||||
|
You can set up a documentation build system using the following commands
|
||||||
|
|
||||||
|
```sh
|
||||||
|
mkdir build-docs && cd build-docs
|
||||||
|
cmake -DFSFW_BUILD_DOCS=ON -DFSFW_OSAL=host ..
|
||||||
|
```
|
||||||
|
|
||||||
|
Then you can generate the documentation using
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cmake --build . -- Sphinx -j
|
||||||
|
```
|
||||||
|
|
||||||
|
You can find the generated documentation inside the `docs/sphinx` folder inside the build
|
||||||
|
folder. Simply open the `index.html` in the webbrowser of your choice.
|
||||||
|
|
||||||
|
The `helper.py` script located in the script` folder can also be used to create, build
|
||||||
|
and open the documentation conveniently. Try `helper.py -h for more information.
|
||||||
|
|
||||||
|
## Formatting the sources
|
||||||
|
|
||||||
|
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 `auto-format.sh` helper script to format all source files consistently. Furthermore cmake-format is required to format CMake files which can be installed with:
|
||||||
|
````sh
|
||||||
|
sudo pip install cmakelang
|
||||||
|
````
|
||||||
|
|
||||||
## Index
|
## Index
|
||||||
|
|
||||||
[1. High-level overview](doc/README-highlevel.md#top) <br>
|
[1. High-level overview](docs/README-highlevel.md#top) <br>
|
||||||
[2. Core components](doc/README-core.md#top) <br>
|
[2. Core components](docs/README-core.md#top) <br>
|
||||||
[3. OSAL overview](doc/README-osal.md#top) <br>
|
[3. Configuration](docs/README-config.md#top) <br>
|
||||||
[4. PUS services](doc/README-pus.md#top) <br>
|
[4. OSAL overview](docs/README-osal.md#top) <br>
|
||||||
[5. Device Handler overview](doc/README-devicehandlers.md#top) <br>
|
[5. PUS services](docs/README-pus.md#top) <br>
|
||||||
[6. Controller overview](doc/README-controllers.md#top) <br>
|
[6. Device Handler overview](docs/README-devicehandlers.md#top) <br>
|
||||||
[7. Local Data Pools](doc/README-localpools.md#top) <br>
|
[7. Controller overview](docs/README-controllers.md#top) <br>
|
||||||
|
[8. Local Data Pools](docs/README-localpools.md#top) <br>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,167 +0,0 @@
|
|||||||
#include "ActionHelper.h"
|
|
||||||
#include "HasActionsIF.h"
|
|
||||||
|
|
||||||
#include "../ipc/MessageQueueSenderIF.h"
|
|
||||||
#include "../objectmanager/ObjectManagerIF.h"
|
|
||||||
#include "../serviceinterface/ServiceInterface.h"
|
|
||||||
|
|
||||||
ActionHelper::ActionHelper(HasActionsIF* setOwner,
|
|
||||||
MessageQueueIF* useThisQueue) :
|
|
||||||
owner(setOwner), queueToUse(useThisQueue) {
|
|
||||||
}
|
|
||||||
|
|
||||||
ActionHelper::~ActionHelper() {
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
} else {
|
|
||||||
return CommandMessage::UNKNOWN_COMMAND;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t ActionHelper::initialize(MessageQueueIF* queueToUse_) {
|
|
||||||
ipcStore = objectManager->get<StorageManagerIF>(objects::IPC_STORE);
|
|
||||||
if (ipcStore == nullptr) {
|
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
|
||||||
}
|
|
||||||
if(queueToUse_ != nullptr) {
|
|
||||||
setQueueToUse(queueToUse_);
|
|
||||||
}
|
|
||||||
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ActionHelper::step(uint8_t step, MessageQueueId_t reportTo,
|
|
||||||
ActionId_t commandId, ReturnValue_t result) {
|
|
||||||
CommandMessage reply;
|
|
||||||
ActionMessage::setStepReply(&reply, commandId, step + STEP_OFFSET, result);
|
|
||||||
queueToUse->sendMessage(reportTo, &reply);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ActionHelper::finish(bool success, MessageQueueId_t reportTo, ActionId_t commandId,
|
|
||||||
ReturnValue_t result) {
|
|
||||||
CommandMessage reply;
|
|
||||||
ActionMessage::setCompletionReply(&reply, commandId, success, result);
|
|
||||||
queueToUse->sendMessage(reportTo, &reply);
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
size_t size = 0;
|
|
||||||
ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size);
|
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
CommandMessage reply;
|
|
||||||
ActionMessage::setStepReply(&reply, actionId, 0, result);
|
|
||||||
queueToUse->sendMessage(commandedBy, &reply);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
result = owner->executeAction(actionId, commandedBy, dataPtr, size);
|
|
||||||
ipcStore->deleteData(dataAddress);
|
|
||||||
if(result == HasActionsIF::EXECUTION_FINISHED) {
|
|
||||||
CommandMessage reply;
|
|
||||||
ActionMessage::setCompletionReply(&reply, actionId, true, result);
|
|
||||||
queueToUse->sendMessage(commandedBy, &reply);
|
|
||||||
}
|
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
CommandMessage reply;
|
|
||||||
ActionMessage::setStepReply(&reply, actionId, 0, result);
|
|
||||||
queueToUse->sendMessage(commandedBy, &reply);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t ActionHelper::reportData(MessageQueueId_t reportTo,
|
|
||||||
ActionId_t replyId, SerializeIF* data, bool hideSender) {
|
|
||||||
CommandMessage reply;
|
|
||||||
store_address_t storeAddress;
|
|
||||||
uint8_t *dataPtr;
|
|
||||||
size_t maxSize = data->getSerializedSize();
|
|
||||||
if (maxSize == 0) {
|
|
||||||
/* No error, there's simply nothing to report. */
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
size_t size = 0;
|
|
||||||
ReturnValue_t result = ipcStore->getFreeElement(&storeAddress, maxSize,
|
|
||||||
&dataPtr);
|
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::warning << "ActionHelper::reportData: Getting free element from IPC store failed!" <<
|
|
||||||
std::endl;
|
|
||||||
#else
|
|
||||||
sif::printWarning("ActionHelper::reportData: Getting free element from IPC "
|
|
||||||
"store failed!\n");
|
|
||||||
#endif
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
result = data->serialize(&dataPtr, &size, maxSize,
|
|
||||||
SerializeIF::Endianness::BIG);
|
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
ipcStore->deleteData(storeAddress);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We don't need to report the objectId, as we receive REQUESTED data before the completion
|
|
||||||
success message. True aperiodic replies need to be reported with another dedicated message. */
|
|
||||||
ActionMessage::setDataReply(&reply, replyId, storeAddress);
|
|
||||||
|
|
||||||
/* If the sender needs to be hidden, for example to handle packet
|
|
||||||
as unrequested reply, this will be done here. */
|
|
||||||
if (hideSender) {
|
|
||||||
result = MessageQueueSenderIF::sendMessage(reportTo, &reply);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
result = queueToUse->sendMessage(reportTo, &reply);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK){
|
|
||||||
ipcStore->deleteData(storeAddress);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ActionHelper::resetHelper() {
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t ActionHelper::reportData(MessageQueueId_t reportTo,
|
|
||||||
ActionId_t replyId, const uint8_t *data, size_t dataSize,
|
|
||||||
bool hideSender) {
|
|
||||||
CommandMessage reply;
|
|
||||||
store_address_t storeAddress;
|
|
||||||
ReturnValue_t result = ipcStore->addData(&storeAddress, data, dataSize);
|
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::warning << "ActionHelper::reportData: Adding data to IPC store failed!" << std::endl;
|
|
||||||
#else
|
|
||||||
sif::printWarning("ActionHelper::reportData: Adding data to IPC store failed!\n");
|
|
||||||
#endif
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We don't need to report the objectId, as we receive REQUESTED data before the completion
|
|
||||||
success message. True aperiodic replies need to be reported with another dedicated message. */
|
|
||||||
ActionMessage::setDataReply(&reply, replyId, storeAddress);
|
|
||||||
|
|
||||||
/* If the sender needs to be hidden, for example to handle packet
|
|
||||||
as unrequested reply, this will be done here. */
|
|
||||||
if (hideSender) {
|
|
||||||
result = MessageQueueSenderIF::sendMessage(reportTo, &reply);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
result = queueToUse->sendMessage(reportTo, &reply);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
ipcStore->deleteData(storeAddress);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
@ -1,126 +0,0 @@
|
|||||||
#ifndef FSFW_ACTION_ACTIONHELPER_H_
|
|
||||||
#define FSFW_ACTION_ACTIONHELPER_H_
|
|
||||||
|
|
||||||
#include "ActionMessage.h"
|
|
||||||
#include "../serialize/SerializeIF.h"
|
|
||||||
#include "../ipc/MessageQueueIF.h"
|
|
||||||
/**
|
|
||||||
* @brief Action Helper is a helper class which handles action messages
|
|
||||||
*
|
|
||||||
* Components which use the HasActionIF this helper can be used to handle
|
|
||||||
* the action messages.
|
|
||||||
* It does handle step messages as well as other answers to action calls.
|
|
||||||
* It uses the executeAction function of its owner as callback.
|
|
||||||
* The call of the initialize function is mandatory and needs a
|
|
||||||
* valid MessageQueueIF pointer!
|
|
||||||
*/
|
|
||||||
class HasActionsIF;
|
|
||||||
|
|
||||||
class ActionHelper {
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Constructor of the action helper
|
|
||||||
* @param setOwner Pointer to the owner of the interface
|
|
||||||
* @param useThisQueue messageQueue to be used, can be set during
|
|
||||||
* initialize function as well.
|
|
||||||
*/
|
|
||||||
ActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue);
|
|
||||||
|
|
||||||
virtual ~ActionHelper();
|
|
||||||
/**
|
|
||||||
* Function to be called from the owner with a new command message
|
|
||||||
*
|
|
||||||
* If the message is a valid action message the helper will use the
|
|
||||||
* executeAction function from HasActionsIF.
|
|
||||||
* If the message is invalid or the callback fails a message reply will be
|
|
||||||
* 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,
|
|
||||||
* CommandMessage::UNKNOW_COMMAND if this message ID is unkown
|
|
||||||
*/
|
|
||||||
ReturnValue_t handleActionMessage(CommandMessage* command);
|
|
||||||
/**
|
|
||||||
* Helper initialize function. Must be called before use of any other
|
|
||||||
* helper function
|
|
||||||
* @param queueToUse_ Pointer to the messageQueue to be used, optional
|
|
||||||
* if queue was set in constructor
|
|
||||||
* @return Returns RETURN_OK if successful
|
|
||||||
*/
|
|
||||||
ReturnValue_t initialize(MessageQueueIF* queueToUse_ = nullptr);
|
|
||||||
/**
|
|
||||||
* Function to be called from the owner to send a step message.
|
|
||||||
* Success or failure will be determined by the result value.
|
|
||||||
*
|
|
||||||
* @param step Number of steps already done
|
|
||||||
* @param reportTo The messageQueueId to report the step message to
|
|
||||||
* @param commandId ID of the executed command
|
|
||||||
* @param result Result of the execution
|
|
||||||
*/
|
|
||||||
void step(uint8_t step, MessageQueueId_t reportTo,
|
|
||||||
ActionId_t commandId,
|
|
||||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK);
|
|
||||||
/**
|
|
||||||
* Function to be called by the owner to send a action completion message
|
|
||||||
* @param success Specify whether action was completed successfully or not.
|
|
||||||
* @param reportTo MessageQueueId_t to report the action completion message to
|
|
||||||
* @param commandId ID of the executed command
|
|
||||||
* @param result Result of the execution
|
|
||||||
*/
|
|
||||||
void finish(bool success, MessageQueueId_t reportTo, ActionId_t commandId,
|
|
||||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_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.
|
|
||||||
* @param reportTo MessageQueueId_t to report the action completion
|
|
||||||
* message to
|
|
||||||
* @param replyId ID of the executed command
|
|
||||||
* @param data Pointer to the data
|
|
||||||
* @return Returns RETURN_OK if successful, otherwise failure code
|
|
||||||
*/
|
|
||||||
ReturnValue_t reportData(MessageQueueId_t reportTo, ActionId_t replyId,
|
|
||||||
SerializeIF* data, bool hideSender = false);
|
|
||||||
/**
|
|
||||||
* Function to be called by the owner if an action does report data.
|
|
||||||
* Takes the raw data and writes it into the IPC store.
|
|
||||||
* @param reportTo MessageQueueId_t to report the action completion
|
|
||||||
* message to
|
|
||||||
* @param replyId ID of the executed command
|
|
||||||
* @param data Pointer to the data
|
|
||||||
* @return Returns RETURN_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);
|
|
||||||
/**
|
|
||||||
* Function to setup the MessageQueueIF* of the helper. Can be used to
|
|
||||||
* set the MessageQueueIF* if message queue is unavailable at construction
|
|
||||||
* and initialize but must be setup before first call of other functions.
|
|
||||||
* @param queue Queue to be used by the helper
|
|
||||||
*/
|
|
||||||
void setQueueToUse(MessageQueueIF *queue);
|
|
||||||
protected:
|
|
||||||
//! Increase of value of this per step
|
|
||||||
static const uint8_t STEP_OFFSET = 1;
|
|
||||||
//! Pointer to the owner
|
|
||||||
HasActionsIF* owner;
|
|
||||||
//! Queue to be used as response sender, has to be set in ctor or with
|
|
||||||
//! setQueueToUse
|
|
||||||
MessageQueueIF* queueToUse;
|
|
||||||
//! Pointer to an IPC Store, initialized during construction or
|
|
||||||
StorageManagerIF* ipcStore = nullptr;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal function called by handleActionMessage
|
|
||||||
* @param commandedBy MessageQueueID of Commander
|
|
||||||
* @param actionId ID of action to be done
|
|
||||||
* @param dataAddress Address of additional data in IPC Store
|
|
||||||
*/
|
|
||||||
virtual void prepareExecution(MessageQueueId_t commandedBy,
|
|
||||||
ActionId_t actionId, store_address_t dataAddress);
|
|
||||||
/**
|
|
||||||
* @brief Default implementation is empty.
|
|
||||||
*/
|
|
||||||
virtual void resetHelper();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* FSFW_ACTION_ACTIONHELPER_H_ */
|
|
@ -1,82 +0,0 @@
|
|||||||
#include "ActionMessage.h"
|
|
||||||
#include "HasActionsIF.h"
|
|
||||||
|
|
||||||
#include "../objectmanager/ObjectManagerIF.h"
|
|
||||||
#include "../storagemanager/StorageManagerIF.h"
|
|
||||||
|
|
||||||
ActionMessage::ActionMessage() {
|
|
||||||
}
|
|
||||||
|
|
||||||
ActionMessage::~ActionMessage() {
|
|
||||||
}
|
|
||||||
|
|
||||||
void ActionMessage::setCommand(CommandMessage* message, ActionId_t fid,
|
|
||||||
store_address_t parameters) {
|
|
||||||
message->setCommand(EXECUTE_ACTION);
|
|
||||||
message->setParameter(fid);
|
|
||||||
message->setParameter2(parameters.raw);
|
|
||||||
}
|
|
||||||
|
|
||||||
ActionId_t ActionMessage::getActionId(const CommandMessage* message) {
|
|
||||||
return ActionId_t(message->getParameter());
|
|
||||||
}
|
|
||||||
|
|
||||||
store_address_t ActionMessage::getStoreId(const CommandMessage* message) {
|
|
||||||
store_address_t temp;
|
|
||||||
temp.raw = message->getParameter2();
|
|
||||||
return temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ActionMessage::setStepReply(CommandMessage* message, ActionId_t fid, uint8_t step,
|
|
||||||
ReturnValue_t result) {
|
|
||||||
if (result == HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
message->setCommand(STEP_SUCCESS);
|
|
||||||
} else {
|
|
||||||
message->setCommand(STEP_FAILED);
|
|
||||||
}
|
|
||||||
message->setParameter(fid);
|
|
||||||
message->setParameter2((step << 16) + result);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t ActionMessage::getStep(const CommandMessage* message) {
|
|
||||||
return uint8_t((message->getParameter2() >> 16) & 0xFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t ActionMessage::getReturnCode(const CommandMessage* message) {
|
|
||||||
return message->getParameter2() & 0xFFFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ActionMessage::setDataReply(CommandMessage* message, ActionId_t actionId,
|
|
||||||
store_address_t data) {
|
|
||||||
message->setCommand(DATA_REPLY);
|
|
||||||
message->setParameter(actionId);
|
|
||||||
message->setParameter2(data.raw);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ActionMessage::setCompletionReply(CommandMessage* message,
|
|
||||||
ActionId_t fid, bool success, ReturnValue_t result) {
|
|
||||||
if (success) {
|
|
||||||
message->setCommand(COMPLETION_SUCCESS);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
message->setCommand(COMPLETION_FAILED);
|
|
||||||
}
|
|
||||||
message->setParameter(fid);
|
|
||||||
message->setParameter2(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ActionMessage::clear(CommandMessage* message) {
|
|
||||||
switch(message->getCommand()) {
|
|
||||||
case EXECUTE_ACTION:
|
|
||||||
case DATA_REPLY: {
|
|
||||||
StorageManagerIF *ipcStore = objectManager->get<StorageManagerIF>(
|
|
||||||
objects::IPC_STORE);
|
|
||||||
if (ipcStore != NULL) {
|
|
||||||
ipcStore->deleteData(getStoreId(message));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,47 +0,0 @@
|
|||||||
#ifndef FSFW_ACTION_ACTIONMESSAGE_H_
|
|
||||||
#define FSFW_ACTION_ACTIONMESSAGE_H_
|
|
||||||
|
|
||||||
#include "../ipc/CommandMessage.h"
|
|
||||||
#include "../objectmanager/ObjectManagerIF.h"
|
|
||||||
#include "../storagemanager/StorageManagerIF.h"
|
|
||||||
|
|
||||||
using ActionId_t = uint32_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief These messages are part of the action module of the FSFW.
|
|
||||||
* @details
|
|
||||||
* These messages are sent amongst objects implementing the HasActionsIF. Classes like the
|
|
||||||
* ActionHelper are able to process these messages.
|
|
||||||
*/
|
|
||||||
class ActionMessage {
|
|
||||||
private:
|
|
||||||
ActionMessage();
|
|
||||||
public:
|
|
||||||
static const uint8_t MESSAGE_ID = messagetypes::ACTION;
|
|
||||||
static const Command_t EXECUTE_ACTION = MAKE_COMMAND_ID(1);
|
|
||||||
static const Command_t STEP_SUCCESS = MAKE_COMMAND_ID(2);
|
|
||||||
static const Command_t STEP_FAILED = MAKE_COMMAND_ID(3);
|
|
||||||
static const Command_t DATA_REPLY = MAKE_COMMAND_ID(4);
|
|
||||||
static const Command_t COMPLETION_SUCCESS = MAKE_COMMAND_ID(5);
|
|
||||||
static const Command_t COMPLETION_FAILED = MAKE_COMMAND_ID(6);
|
|
||||||
|
|
||||||
virtual ~ActionMessage();
|
|
||||||
static void setCommand(CommandMessage* message, ActionId_t fid,
|
|
||||||
store_address_t parameters);
|
|
||||||
|
|
||||||
static ActionId_t getActionId(const CommandMessage* message );
|
|
||||||
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);
|
|
||||||
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);
|
|
||||||
|
|
||||||
static void clear(CommandMessage* message);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* FSFW_ACTION_ACTIONMESSAGE_H_ */
|
|
@ -1,7 +0,0 @@
|
|||||||
target_sources(${LIB_FSFW_NAME}
|
|
||||||
PRIVATE
|
|
||||||
ActionHelper.cpp
|
|
||||||
ActionMessage.cpp
|
|
||||||
CommandActionHelper.cpp
|
|
||||||
SimpleActionHelper.cpp
|
|
||||||
)
|
|
@ -1,127 +0,0 @@
|
|||||||
#include "ActionMessage.h"
|
|
||||||
#include "CommandActionHelper.h"
|
|
||||||
#include "CommandsActionsIF.h"
|
|
||||||
#include "HasActionsIF.h"
|
|
||||||
#include "../objectmanager/ObjectManagerIF.h"
|
|
||||||
|
|
||||||
CommandActionHelper::CommandActionHelper(CommandsActionsIF *setOwner) :
|
|
||||||
owner(setOwner), queueToUse(NULL), ipcStore(
|
|
||||||
NULL), commandCount(0), lastTarget(0) {
|
|
||||||
}
|
|
||||||
|
|
||||||
CommandActionHelper::~CommandActionHelper() {
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t CommandActionHelper::commandAction(object_id_t commandTo,
|
|
||||||
ActionId_t actionId, SerializeIF *data) {
|
|
||||||
HasActionsIF *receiver = objectManager->get<HasActionsIF>(commandTo);
|
|
||||||
if (receiver == NULL) {
|
|
||||||
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) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
size_t size = 0;
|
|
||||||
result = data->serialize(&storePointer, &size, maxSize,
|
|
||||||
SerializeIF::Endianness::BIG);
|
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
return sendCommand(receiver->getCommandQueue(), actionId, storeId);
|
|
||||||
}
|
|
||||||
|
|
||||||
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->get<HasActionsIF>(commandTo);
|
|
||||||
if (receiver == NULL) {
|
|
||||||
return CommandsActionsIF::OBJECT_HAS_NO_FUNCTIONS;
|
|
||||||
}
|
|
||||||
store_address_t storeId;
|
|
||||||
ReturnValue_t result = ipcStore->addData(&storeId, data, size);
|
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
return sendCommand(receiver->getCommandQueue(), actionId, storeId);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t CommandActionHelper::sendCommand(MessageQueueId_t queueId,
|
|
||||||
ActionId_t actionId, store_address_t storeId) {
|
|
||||||
CommandMessage command;
|
|
||||||
ActionMessage::setCommand(&command, actionId, storeId);
|
|
||||||
ReturnValue_t result = queueToUse->sendMessage(queueId, &command);
|
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
ipcStore->deleteData(storeId);
|
|
||||||
}
|
|
||||||
lastTarget = queueId;
|
|
||||||
commandCount++;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t CommandActionHelper::initialize() {
|
|
||||||
ipcStore = objectManager->get<StorageManagerIF>(objects::IPC_STORE);
|
|
||||||
if (ipcStore == NULL) {
|
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
queueToUse = owner->getCommandQueuePtr();
|
|
||||||
if (queueToUse == NULL) {
|
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
|
||||||
}
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t CommandActionHelper::handleReply(CommandMessage *reply) {
|
|
||||||
if (reply->getSender() != lastTarget) {
|
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
|
||||||
}
|
|
||||||
switch (reply->getCommand()) {
|
|
||||||
case ActionMessage::COMPLETION_SUCCESS:
|
|
||||||
commandCount--;
|
|
||||||
owner->completionSuccessfulReceived(ActionMessage::getActionId(reply));
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
case ActionMessage::COMPLETION_FAILED:
|
|
||||||
commandCount--;
|
|
||||||
owner->completionFailedReceived(ActionMessage::getActionId(reply),
|
|
||||||
ActionMessage::getReturnCode(reply));
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
case ActionMessage::STEP_SUCCESS:
|
|
||||||
owner->stepSuccessfulReceived(ActionMessage::getActionId(reply),
|
|
||||||
ActionMessage::getStep(reply));
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
case ActionMessage::STEP_FAILED:
|
|
||||||
commandCount--;
|
|
||||||
owner->stepFailedReceived(ActionMessage::getActionId(reply),
|
|
||||||
ActionMessage::getStep(reply),
|
|
||||||
ActionMessage::getReturnCode(reply));
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
case ActionMessage::DATA_REPLY:
|
|
||||||
extractDataForOwner(ActionMessage::getActionId(reply),
|
|
||||||
ActionMessage::getStoreId(reply));
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
default:
|
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t CommandActionHelper::getCommandCount() const {
|
|
||||||
return commandCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CommandActionHelper::extractDataForOwner(ActionId_t actionId, store_address_t storeId) {
|
|
||||||
const uint8_t * data = NULL;
|
|
||||||
size_t size = 0;
|
|
||||||
ReturnValue_t result = ipcStore->getData(storeId, &data, &size);
|
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
owner->dataReceived(actionId, data, size);
|
|
||||||
ipcStore->deleteData(storeId);
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
#ifndef COMMANDACTIONHELPER_H_
|
|
||||||
#define COMMANDACTIONHELPER_H_
|
|
||||||
|
|
||||||
#include "ActionMessage.h"
|
|
||||||
#include "../objectmanager/ObjectManagerIF.h"
|
|
||||||
#include "../returnvalues/HasReturnvaluesIF.h"
|
|
||||||
#include "../serialize/SerializeIF.h"
|
|
||||||
#include "../storagemanager/StorageManagerIF.h"
|
|
||||||
#include "../ipc/MessageQueueIF.h"
|
|
||||||
|
|
||||||
class CommandsActionsIF;
|
|
||||||
|
|
||||||
class CommandActionHelper {
|
|
||||||
friend class CommandsActionsIF;
|
|
||||||
public:
|
|
||||||
CommandActionHelper(CommandsActionsIF* owner);
|
|
||||||
virtual ~CommandActionHelper();
|
|
||||||
ReturnValue_t commandAction(object_id_t commandTo,
|
|
||||||
ActionId_t actionId, const uint8_t* data, uint32_t size);
|
|
||||||
ReturnValue_t commandAction(object_id_t commandTo,
|
|
||||||
ActionId_t actionId, SerializeIF* data);
|
|
||||||
ReturnValue_t initialize();
|
|
||||||
ReturnValue_t handleReply(CommandMessage* reply);
|
|
||||||
uint8_t getCommandCount() const;
|
|
||||||
private:
|
|
||||||
CommandsActionsIF* owner;
|
|
||||||
MessageQueueIF* queueToUse;
|
|
||||||
StorageManagerIF* ipcStore;
|
|
||||||
uint8_t commandCount;
|
|
||||||
MessageQueueId_t lastTarget;
|
|
||||||
void extractDataForOwner(ActionId_t actionId, store_address_t storeId);
|
|
||||||
ReturnValue_t sendCommand(MessageQueueId_t queueId, ActionId_t actionId,
|
|
||||||
store_address_t storeId);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* COMMANDACTIONHELPER_H_ */
|
|
@ -1,37 +0,0 @@
|
|||||||
#ifndef FSFW_ACTION_COMMANDSACTIONSIF_H_
|
|
||||||
#define FSFW_ACTION_COMMANDSACTIONSIF_H_
|
|
||||||
|
|
||||||
#include "CommandActionHelper.h"
|
|
||||||
#include "../returnvalues/HasReturnvaluesIF.h"
|
|
||||||
#include "../ipc/MessageQueueIF.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface to separate commanding actions of other objects.
|
|
||||||
* In next iteration, IF should be shortened to three calls:
|
|
||||||
* - dataReceived(data)
|
|
||||||
* - successReceived(id, step)
|
|
||||||
* - failureReceived(id, step, cause)
|
|
||||||
* or even
|
|
||||||
* - replyReceived(id, step, cause) (if cause == OK, it's a success).
|
|
||||||
*/
|
|
||||||
class CommandsActionsIF {
|
|
||||||
friend class CommandActionHelper;
|
|
||||||
public:
|
|
||||||
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 MessageQueueIF* getCommandQueuePtr() = 0;
|
|
||||||
protected:
|
|
||||||
virtual void stepSuccessfulReceived(ActionId_t actionId, uint8_t step) = 0;
|
|
||||||
virtual void stepFailedReceived(ActionId_t actionId, uint8_t step,
|
|
||||||
ReturnValue_t returnCode) = 0;
|
|
||||||
virtual void dataReceived(ActionId_t actionId, const uint8_t* data,
|
|
||||||
uint32_t size) = 0;
|
|
||||||
virtual void completionSuccessfulReceived(ActionId_t actionId) = 0;
|
|
||||||
virtual void completionFailedReceived(ActionId_t actionId,
|
|
||||||
ReturnValue_t returnCode) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* FSFW_ACTION_COMMANDSACTIONSIF_H_ */
|
|
@ -1,75 +0,0 @@
|
|||||||
#include "HasActionsIF.h"
|
|
||||||
#include "SimpleActionHelper.h"
|
|
||||||
|
|
||||||
SimpleActionHelper::SimpleActionHelper(HasActionsIF* setOwner,
|
|
||||||
MessageQueueIF* useThisQueue) :
|
|
||||||
ActionHelper(setOwner, useThisQueue), isExecuting(false) {
|
|
||||||
}
|
|
||||||
|
|
||||||
SimpleActionHelper::~SimpleActionHelper() {
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
|
||||||
resetHelper();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SimpleActionHelper::finish(ReturnValue_t result) {
|
|
||||||
ActionHelper::finish(lastCommander, lastAction, result);
|
|
||||||
resetHelper();
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t SimpleActionHelper::reportData(SerializeIF* data) {
|
|
||||||
return ActionHelper::reportData(lastCommander, lastAction, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SimpleActionHelper::resetHelper() {
|
|
||||||
stepCount = 0;
|
|
||||||
isExecuting = false;
|
|
||||||
lastAction = 0;
|
|
||||||
lastCommander = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SimpleActionHelper::prepareExecution(MessageQueueId_t commandedBy,
|
|
||||||
ActionId_t actionId, store_address_t dataAddress) {
|
|
||||||
CommandMessage reply;
|
|
||||||
if (isExecuting) {
|
|
||||||
ipcStore->deleteData(dataAddress);
|
|
||||||
ActionMessage::setStepReply(&reply, actionId, 0,
|
|
||||||
HasActionsIF::IS_BUSY);
|
|
||||||
queueToUse->sendMessage(commandedBy, &reply);
|
|
||||||
}
|
|
||||||
const uint8_t* dataPtr = NULL;
|
|
||||||
size_t size = 0;
|
|
||||||
ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size);
|
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
ActionMessage::setStepReply(&reply, actionId, 0, result);
|
|
||||||
queueToUse->sendMessage(commandedBy, &reply);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
lastCommander = commandedBy;
|
|
||||||
lastAction = actionId;
|
|
||||||
result = owner->executeAction(actionId, commandedBy, dataPtr, size);
|
|
||||||
ipcStore->deleteData(dataAddress);
|
|
||||||
switch (result) {
|
|
||||||
case HasReturnvaluesIF::RETURN_OK:
|
|
||||||
isExecuting = true;
|
|
||||||
stepCount++;
|
|
||||||
break;
|
|
||||||
case HasActionsIF::EXECUTION_FINISHED:
|
|
||||||
ActionMessage::setCompletionReply(&reply, actionId,
|
|
||||||
true, HasReturnvaluesIF::RETURN_OK);
|
|
||||||
queueToUse->sendMessage(commandedBy, &reply);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ActionMessage::setStepReply(&reply, actionId, 0, result);
|
|
||||||
queueToUse->sendMessage(commandedBy, &reply);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,30 +0,0 @@
|
|||||||
#ifndef FSFW_ACTION_SIMPLEACTIONHELPER_H_
|
|
||||||
#define FSFW_ACTION_SIMPLEACTIONHELPER_H_
|
|
||||||
|
|
||||||
#include "ActionHelper.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief This is an action helper which is only able to service one action
|
|
||||||
* at a time but remembers last commander and last action which
|
|
||||||
* simplifies usage
|
|
||||||
*/
|
|
||||||
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);
|
|
||||||
ReturnValue_t reportData(SerializeIF* data);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId,
|
|
||||||
store_address_t dataAddress);
|
|
||||||
virtual void resetHelper();
|
|
||||||
private:
|
|
||||||
bool isExecuting;
|
|
||||||
MessageQueueId_t lastCommander = MessageQueueIF::NO_QUEUE;
|
|
||||||
ActionId_t lastAction = 0;
|
|
||||||
uint8_t stepCount = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* SIMPLEACTIONHELPER_H_ */
|
|
29
automation/Dockerfile
Normal file
29
automation/Dockerfile
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
FROM ubuntu:focal
|
||||||
|
|
||||||
|
RUN apt-get update
|
||||||
|
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 python3 pip doxygen graphviz rsync
|
||||||
|
|
||||||
|
RUN python3 -m pip install sphinx breathe
|
||||||
|
|
||||||
|
RUN git clone https://github.com/catchorg/Catch2.git && \
|
||||||
|
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
|
||||||
|
|
||||||
|
#add documentation server to known hosts
|
||||||
|
RUN echo "|1|/LzCV4BuTmTb2wKnD146l9fTKgQ=|NJJtVjvWbtRt8OYqFgcYRnMQyVw= ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBNL8ssTonYtgiR/6RRlSIK9WU1ywOcJmxFTLcEblAwH7oifZzmYq3XRfwXrgfMpylEfMFYfCU8JRqtmi19xc21A=" >> /etc/ssh/ssh_known_hosts
|
||||||
|
RUN echo "|1|CcBvBc3EG03G+XM5rqRHs6gK/Gg=|oGeJQ+1I8NGI2THIkJsW92DpTzs= ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBNL8ssTonYtgiR/6RRlSIK9WU1ywOcJmxFTLcEblAwH7oifZzmYq3XRfwXrgfMpylEfMFYfCU8JRqtmi19xc21A=" >> /etc/ssh/ssh_known_hosts
|
127
automation/Jenkinsfile
vendored
Normal file
127
automation/Jenkinsfile
vendored
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
pipeline {
|
||||||
|
environment {
|
||||||
|
BUILDDIR_HOST = 'cmake-build-tests-host'
|
||||||
|
BUILDDIR_LINUX = 'cmake-build-tests-linux'
|
||||||
|
DOCDDIR = 'cmake-build-documentation'
|
||||||
|
}
|
||||||
|
agent {
|
||||||
|
docker {
|
||||||
|
image 'fsfw-ci:d6'
|
||||||
|
args '--network host --sysctl fs.mqueue.msg_max=100'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stages {
|
||||||
|
stage('Host') {
|
||||||
|
stages{
|
||||||
|
stage('Clean') {
|
||||||
|
steps {
|
||||||
|
sh 'rm -rf $BUILDDIR_HOST'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Configure') {
|
||||||
|
steps {
|
||||||
|
dir(BUILDDIR_HOST) {
|
||||||
|
sh 'cmake -DFSFW_OSAL=host -DFSFW_BUILD_TESTS=ON -DFSFW_CICD_BUILD=ON ..'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Build') {
|
||||||
|
steps {
|
||||||
|
dir(BUILDDIR_HOST) {
|
||||||
|
sh 'cmake --build . -j4'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Unittests') {
|
||||||
|
steps {
|
||||||
|
dir(BUILDDIR_HOST) {
|
||||||
|
sh 'cmake --build . -- fsfw-tests_coverage -j4'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Valgrind') {
|
||||||
|
steps {
|
||||||
|
dir(BUILDDIR_HOST) {
|
||||||
|
sh 'valgrind --leak-check=full --error-exitcode=1 ./fsfw-tests'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Linux') {
|
||||||
|
stages{
|
||||||
|
stage('Clean') {
|
||||||
|
steps {
|
||||||
|
sh 'rm -rf $BUILDDIR_LINUX'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Configure') {
|
||||||
|
steps {
|
||||||
|
dir(BUILDDIR_LINUX) {
|
||||||
|
sh 'cmake -DFSFW_OSAL=linux -DFSFW_BUILD_TESTS=ON -DFSFW_CICD_BUILD=ON ..'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Build') {
|
||||||
|
steps {
|
||||||
|
dir(BUILDDIR_LINUX) {
|
||||||
|
sh 'cmake --build . -j4'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Unittests') {
|
||||||
|
steps {
|
||||||
|
dir(BUILDDIR_LINUX) {
|
||||||
|
sh 'cmake --build . -- fsfw-tests_coverage -j4'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Valgrind') {
|
||||||
|
steps {
|
||||||
|
dir(BUILDDIR_LINUX) {
|
||||||
|
sh 'valgrind --leak-check=full --error-exitcode=1 ./fsfw-tests'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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 'rsync -r --delete docs/sphinx/* buildfix@documentation.irs.uni-stuttgart.de:/fsfw/development'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dir(BUILDDIR) {
|
||||||
|
sshagent(credentials: ['documentation-buildfix']) {
|
||||||
|
sh 'rsync -r --delete fsfw-tests_coverage/* buildfix@documentation.irs.uni-stuttgart.de:/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 'rsync -r --delete docs/sphinx/* buildfix@documentation.irs.uni-stuttgart.de:/fsfw/master'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dir(BUILDDIR) {
|
||||||
|
sshagent(credentials: ['documentation-buildfix']) {
|
||||||
|
sh 'rsync -r --delete fsfw-tests_coverage/* buildfix@documentation.irs.uni-stuttgart.de:/fsfw/coverage/master'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
13
cmake/FindSphinx.cmake
Normal file
13
cmake/FindSphinx.cmake
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# Look for an executable called sphinx-build
|
||||||
|
find_program(SPHINX_EXECUTABLE
|
||||||
|
NAMES sphinx-build
|
||||||
|
DOC "Path to sphinx-build executable")
|
||||||
|
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
|
||||||
|
# Handle standard arguments to find_package like REQUIRED and QUIET
|
||||||
|
find_package_handle_standard_args(
|
||||||
|
Sphinx
|
||||||
|
"Failed to find sphinx-build executable"
|
||||||
|
SPHINX_EXECUTABLE
|
||||||
|
)
|
28
cmake/FsfwHelpers.cmake
Normal file
28
cmake/FsfwHelpers.cmake
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# Determines the git version with git describe and returns it by setting
|
||||||
|
# the GIT_INFO list in the parent scope. The list has the following entries
|
||||||
|
# 1. Full version string
|
||||||
|
# 2. Major version
|
||||||
|
# 3. Minor version
|
||||||
|
# 4. Revision
|
||||||
|
# 5. git SHA hash and commits since tag
|
||||||
|
function(determine_version_with_git)
|
||||||
|
include(GetGitRevisionDescription)
|
||||||
|
git_describe(VERSION ${ARGN})
|
||||||
|
string(FIND ${VERSION} "." VALID_VERSION)
|
||||||
|
if(VALID_VERSION EQUAL -1)
|
||||||
|
message(WARNING "Version string ${VERSION} retrieved with git describe is invalid")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
# Parse the version information into pieces.
|
||||||
|
string(REGEX REPLACE "^v([0-9]+)\\..*" "\\1" _VERSION_MAJOR "${VERSION}")
|
||||||
|
string(REGEX REPLACE "^v[0-9]+\\.([0-9]+).*" "\\1" _VERSION_MINOR "${VERSION}")
|
||||||
|
string(REGEX REPLACE "^v[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" _VERSION_PATCH "${VERSION}")
|
||||||
|
string(REGEX REPLACE "^v[0-9]+\\.[0-9]+\\.[0-9]+-(.*)" "\\1" VERSION_SHA1 "${VERSION}")
|
||||||
|
set(GIT_INFO ${VERSION})
|
||||||
|
list(APPEND GIT_INFO ${_VERSION_MAJOR})
|
||||||
|
list(APPEND GIT_INFO ${_VERSION_MINOR})
|
||||||
|
list(APPEND GIT_INFO ${_VERSION_PATCH})
|
||||||
|
list(APPEND GIT_INFO ${VERSION_SHA1})
|
||||||
|
set(GIT_INFO ${GIT_INFO} PARENT_SCOPE)
|
||||||
|
message(STATUS "${MSG_PREFIX} Set git version info into GIT_INFO from the git tag ${VERSION}")
|
||||||
|
endfunction()
|
7
cmake/cmake-modules/README.md
Normal file
7
cmake/cmake-modules/README.md
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
The files in the `bilke` folder were manually copy and pasted from the
|
||||||
|
[cmake-modules repository](https://github.com/bilke/cmake-modules). It was decided to do
|
||||||
|
this because only a small subset of its provided functions are needed.
|
||||||
|
|
||||||
|
The files in the `rpavlik` folder were manually copy and pasted from the
|
||||||
|
[cmake-modules repository](https://github.com/rpavlik/cmake-modules). It was decided to do
|
||||||
|
this because only a small subset of its provided functions are needed.
|
719
cmake/cmake-modules/bilke/CodeCoverage.cmake
Normal file
719
cmake/cmake-modules/bilke/CodeCoverage.cmake
Normal file
@ -0,0 +1,719 @@
|
|||||||
|
# Copyright (c) 2012 - 2017, Lars Bilke
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
# are permitted provided that the following conditions are met:
|
||||||
|
#
|
||||||
|
# 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
# list of conditions and the following disclaimer.
|
||||||
|
#
|
||||||
|
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
# this list of conditions and the following disclaimer in the documentation
|
||||||
|
# and/or other materials provided with the distribution.
|
||||||
|
#
|
||||||
|
# 3. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
# may be used to endorse or promote products derived from this software without
|
||||||
|
# specific prior written permission.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||||
|
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#
|
||||||
|
# CHANGES:
|
||||||
|
#
|
||||||
|
# 2012-01-31, Lars Bilke
|
||||||
|
# - Enable Code Coverage
|
||||||
|
#
|
||||||
|
# 2013-09-17, Joakim Söderberg
|
||||||
|
# - Added support for Clang.
|
||||||
|
# - Some additional usage instructions.
|
||||||
|
#
|
||||||
|
# 2016-02-03, Lars Bilke
|
||||||
|
# - Refactored functions to use named parameters
|
||||||
|
#
|
||||||
|
# 2017-06-02, Lars Bilke
|
||||||
|
# - Merged with modified version from github.com/ufz/ogs
|
||||||
|
#
|
||||||
|
# 2019-05-06, Anatolii Kurotych
|
||||||
|
# - Remove unnecessary --coverage flag
|
||||||
|
#
|
||||||
|
# 2019-12-13, FeRD (Frank Dana)
|
||||||
|
# - Deprecate COVERAGE_LCOVR_EXCLUDES and COVERAGE_GCOVR_EXCLUDES lists in favor
|
||||||
|
# of tool-agnostic COVERAGE_EXCLUDES variable, or EXCLUDE setup arguments.
|
||||||
|
# - CMake 3.4+: All excludes can be specified relative to BASE_DIRECTORY
|
||||||
|
# - All setup functions: accept BASE_DIRECTORY, EXCLUDE list
|
||||||
|
# - Set lcov basedir with -b argument
|
||||||
|
# - Add automatic --demangle-cpp in lcovr, if 'c++filt' is available (can be
|
||||||
|
# overridden with NO_DEMANGLE option in setup_target_for_coverage_lcovr().)
|
||||||
|
# - Delete output dir, .info file on 'make clean'
|
||||||
|
# - Remove Python detection, since version mismatches will break gcovr
|
||||||
|
# - Minor cleanup (lowercase function names, update examples...)
|
||||||
|
#
|
||||||
|
# 2019-12-19, FeRD (Frank Dana)
|
||||||
|
# - Rename Lcov outputs, make filtered file canonical, fix cleanup for targets
|
||||||
|
#
|
||||||
|
# 2020-01-19, Bob Apthorpe
|
||||||
|
# - Added gfortran support
|
||||||
|
#
|
||||||
|
# 2020-02-17, FeRD (Frank Dana)
|
||||||
|
# - Make all add_custom_target()s VERBATIM to auto-escape wildcard characters
|
||||||
|
# in EXCLUDEs, and remove manual escaping from gcovr targets
|
||||||
|
#
|
||||||
|
# 2021-01-19, Robin Mueller
|
||||||
|
# - Add CODE_COVERAGE_VERBOSE option which will allow to print out commands which are run
|
||||||
|
# - Added the option for users to set the GCOVR_ADDITIONAL_ARGS variable to supply additional
|
||||||
|
# flags to the gcovr command
|
||||||
|
#
|
||||||
|
# 2020-05-04, Mihchael Davis
|
||||||
|
# - Add -fprofile-abs-path to make gcno files contain absolute paths
|
||||||
|
# - Fix BASE_DIRECTORY not working when defined
|
||||||
|
# - Change BYPRODUCT from folder to index.html to stop ninja from complaining about double defines
|
||||||
|
#
|
||||||
|
# 2021-05-10, Martin Stump
|
||||||
|
# - Check if the generator is multi-config before warning about non-Debug builds
|
||||||
|
#
|
||||||
|
# 2022-02-22, Marko Wehle
|
||||||
|
# - Change gcovr output from -o <filename> for --xml <filename> and --html <filename> output respectively.
|
||||||
|
# This will allow for Multiple Output Formats at the same time by making use of GCOVR_ADDITIONAL_ARGS, e.g. GCOVR_ADDITIONAL_ARGS "--txt".
|
||||||
|
#
|
||||||
|
# USAGE:
|
||||||
|
#
|
||||||
|
# 1. Copy this file into your cmake modules path.
|
||||||
|
#
|
||||||
|
# 2. Add the following line to your CMakeLists.txt (best inside an if-condition
|
||||||
|
# using a CMake option() to enable it just optionally):
|
||||||
|
# include(CodeCoverage)
|
||||||
|
#
|
||||||
|
# 3. Append necessary compiler flags for all supported source files:
|
||||||
|
# append_coverage_compiler_flags()
|
||||||
|
# Or for specific target:
|
||||||
|
# append_coverage_compiler_flags_to_target(YOUR_TARGET_NAME)
|
||||||
|
#
|
||||||
|
# 3.a (OPTIONAL) Set appropriate optimization flags, e.g. -O0, -O1 or -Og
|
||||||
|
#
|
||||||
|
# 4. If you need to exclude additional directories from the report, specify them
|
||||||
|
# using full paths in the COVERAGE_EXCLUDES variable before calling
|
||||||
|
# setup_target_for_coverage_*().
|
||||||
|
# Example:
|
||||||
|
# set(COVERAGE_EXCLUDES
|
||||||
|
# '${PROJECT_SOURCE_DIR}/src/dir1/*'
|
||||||
|
# '/path/to/my/src/dir2/*')
|
||||||
|
# Or, use the EXCLUDE argument to setup_target_for_coverage_*().
|
||||||
|
# Example:
|
||||||
|
# setup_target_for_coverage_lcov(
|
||||||
|
# NAME coverage
|
||||||
|
# EXECUTABLE testrunner
|
||||||
|
# EXCLUDE "${PROJECT_SOURCE_DIR}/src/dir1/*" "/path/to/my/src/dir2/*")
|
||||||
|
#
|
||||||
|
# 4.a NOTE: With CMake 3.4+, COVERAGE_EXCLUDES or EXCLUDE can also be set
|
||||||
|
# relative to the BASE_DIRECTORY (default: PROJECT_SOURCE_DIR)
|
||||||
|
# Example:
|
||||||
|
# set(COVERAGE_EXCLUDES "dir1/*")
|
||||||
|
# setup_target_for_coverage_gcovr_html(
|
||||||
|
# NAME coverage
|
||||||
|
# EXECUTABLE testrunner
|
||||||
|
# BASE_DIRECTORY "${PROJECT_SOURCE_DIR}/src"
|
||||||
|
# EXCLUDE "dir2/*")
|
||||||
|
#
|
||||||
|
# 5. Use the functions described below to create a custom make target which
|
||||||
|
# runs your test executable and produces a code coverage report.
|
||||||
|
#
|
||||||
|
# 6. Build a Debug build:
|
||||||
|
# cmake -DCMAKE_BUILD_TYPE=Debug ..
|
||||||
|
# make
|
||||||
|
# make my_coverage_target
|
||||||
|
#
|
||||||
|
|
||||||
|
include(CMakeParseArguments)
|
||||||
|
|
||||||
|
option(CODE_COVERAGE_VERBOSE "Verbose information" FALSE)
|
||||||
|
|
||||||
|
# Check prereqs
|
||||||
|
find_program( GCOV_PATH gcov )
|
||||||
|
find_program( LCOV_PATH NAMES lcov lcov.bat lcov.exe lcov.perl)
|
||||||
|
find_program( FASTCOV_PATH NAMES fastcov fastcov.py )
|
||||||
|
find_program( GENHTML_PATH NAMES genhtml genhtml.perl genhtml.bat )
|
||||||
|
find_program( GCOVR_PATH gcovr )
|
||||||
|
find_program( CPPFILT_PATH NAMES c++filt )
|
||||||
|
|
||||||
|
if(NOT GCOV_PATH)
|
||||||
|
message(FATAL_ERROR "gcov not found! Aborting...")
|
||||||
|
endif() # NOT GCOV_PATH
|
||||||
|
|
||||||
|
get_property(LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES)
|
||||||
|
list(GET LANGUAGES 0 LANG)
|
||||||
|
|
||||||
|
if("${CMAKE_${LANG}_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang")
|
||||||
|
if("${CMAKE_${LANG}_COMPILER_VERSION}" VERSION_LESS 3)
|
||||||
|
message(FATAL_ERROR "Clang version must be 3.0.0 or greater! Aborting...")
|
||||||
|
endif()
|
||||||
|
elseif(NOT CMAKE_COMPILER_IS_GNUCXX)
|
||||||
|
if("${CMAKE_Fortran_COMPILER_ID}" MATCHES "[Ff]lang")
|
||||||
|
# Do nothing; exit conditional without error if true
|
||||||
|
elseif("${CMAKE_Fortran_COMPILER_ID}" MATCHES "GNU")
|
||||||
|
# Do nothing; exit conditional without error if true
|
||||||
|
else()
|
||||||
|
message(FATAL_ERROR "Compiler is not GNU gcc! Aborting...")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(COVERAGE_COMPILER_FLAGS "-g -fprofile-arcs -ftest-coverage"
|
||||||
|
CACHE INTERNAL "")
|
||||||
|
if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)")
|
||||||
|
include(CheckCXXCompilerFlag)
|
||||||
|
check_cxx_compiler_flag(-fprofile-abs-path HAVE_fprofile_abs_path)
|
||||||
|
if(HAVE_fprofile_abs_path)
|
||||||
|
set(COVERAGE_COMPILER_FLAGS "${COVERAGE_COMPILER_FLAGS} -fprofile-abs-path")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(CMAKE_Fortran_FLAGS_COVERAGE
|
||||||
|
${COVERAGE_COMPILER_FLAGS}
|
||||||
|
CACHE STRING "Flags used by the Fortran compiler during coverage builds."
|
||||||
|
FORCE )
|
||||||
|
set(CMAKE_CXX_FLAGS_COVERAGE
|
||||||
|
${COVERAGE_COMPILER_FLAGS}
|
||||||
|
CACHE STRING "Flags used by the C++ compiler during coverage builds."
|
||||||
|
FORCE )
|
||||||
|
set(CMAKE_C_FLAGS_COVERAGE
|
||||||
|
${COVERAGE_COMPILER_FLAGS}
|
||||||
|
CACHE STRING "Flags used by the C compiler during coverage builds."
|
||||||
|
FORCE )
|
||||||
|
set(CMAKE_EXE_LINKER_FLAGS_COVERAGE
|
||||||
|
""
|
||||||
|
CACHE STRING "Flags used for linking binaries during coverage builds."
|
||||||
|
FORCE )
|
||||||
|
set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE
|
||||||
|
""
|
||||||
|
CACHE STRING "Flags used by the shared libraries linker during coverage builds."
|
||||||
|
FORCE )
|
||||||
|
mark_as_advanced(
|
||||||
|
CMAKE_Fortran_FLAGS_COVERAGE
|
||||||
|
CMAKE_CXX_FLAGS_COVERAGE
|
||||||
|
CMAKE_C_FLAGS_COVERAGE
|
||||||
|
CMAKE_EXE_LINKER_FLAGS_COVERAGE
|
||||||
|
CMAKE_SHARED_LINKER_FLAGS_COVERAGE )
|
||||||
|
|
||||||
|
get_property(GENERATOR_IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
||||||
|
if(NOT (CMAKE_BUILD_TYPE STREQUAL "Debug" OR GENERATOR_IS_MULTI_CONFIG))
|
||||||
|
message(WARNING "Code coverage results with an optimised (non-Debug) build may be misleading")
|
||||||
|
endif() # NOT (CMAKE_BUILD_TYPE STREQUAL "Debug" OR GENERATOR_IS_MULTI_CONFIG)
|
||||||
|
|
||||||
|
if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_Fortran_COMPILER_ID STREQUAL "GNU")
|
||||||
|
link_libraries(gcov)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Defines a target for running and collection code coverage information
|
||||||
|
# Builds dependencies, runs the given executable and outputs reports.
|
||||||
|
# NOTE! The executable should always have a ZERO as exit code otherwise
|
||||||
|
# the coverage generation will not complete.
|
||||||
|
#
|
||||||
|
# setup_target_for_coverage_lcov(
|
||||||
|
# NAME testrunner_coverage # New target name
|
||||||
|
# EXECUTABLE testrunner -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
|
||||||
|
# DEPENDENCIES testrunner # Dependencies to build first
|
||||||
|
# BASE_DIRECTORY "../" # Base directory for report
|
||||||
|
# # (defaults to PROJECT_SOURCE_DIR)
|
||||||
|
# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative
|
||||||
|
# # to BASE_DIRECTORY, with CMake 3.4+)
|
||||||
|
# NO_DEMANGLE # Don't demangle C++ symbols
|
||||||
|
# # even if c++filt is found
|
||||||
|
# )
|
||||||
|
function(setup_target_for_coverage_lcov)
|
||||||
|
|
||||||
|
set(options NO_DEMANGLE)
|
||||||
|
set(oneValueArgs BASE_DIRECTORY NAME)
|
||||||
|
set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES LCOV_ARGS GENHTML_ARGS)
|
||||||
|
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||||
|
|
||||||
|
if(NOT LCOV_PATH)
|
||||||
|
message(FATAL_ERROR "lcov not found! Aborting...")
|
||||||
|
endif() # NOT LCOV_PATH
|
||||||
|
|
||||||
|
if(NOT GENHTML_PATH)
|
||||||
|
message(FATAL_ERROR "genhtml not found! Aborting...")
|
||||||
|
endif() # NOT GENHTML_PATH
|
||||||
|
|
||||||
|
# Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR
|
||||||
|
if(DEFINED Coverage_BASE_DIRECTORY)
|
||||||
|
get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE)
|
||||||
|
else()
|
||||||
|
set(BASEDIR ${PROJECT_SOURCE_DIR})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Collect excludes (CMake 3.4+: Also compute absolute paths)
|
||||||
|
set(LCOV_EXCLUDES "")
|
||||||
|
foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_LCOV_EXCLUDES})
|
||||||
|
if(CMAKE_VERSION VERSION_GREATER 3.4)
|
||||||
|
get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR})
|
||||||
|
endif()
|
||||||
|
list(APPEND LCOV_EXCLUDES "${EXCLUDE}")
|
||||||
|
endforeach()
|
||||||
|
list(REMOVE_DUPLICATES LCOV_EXCLUDES)
|
||||||
|
|
||||||
|
# Conditional arguments
|
||||||
|
if(CPPFILT_PATH AND NOT ${Coverage_NO_DEMANGLE})
|
||||||
|
set(GENHTML_EXTRA_ARGS "--demangle-cpp")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Setting up commands which will be run to generate coverage data.
|
||||||
|
# Cleanup lcov
|
||||||
|
set(LCOV_CLEAN_CMD
|
||||||
|
${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -directory .
|
||||||
|
-b ${BASEDIR} --zerocounters
|
||||||
|
)
|
||||||
|
# Create baseline to make sure untouched files show up in the report
|
||||||
|
set(LCOV_BASELINE_CMD
|
||||||
|
${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -c -i -d . -b
|
||||||
|
${BASEDIR} -o ${Coverage_NAME}.base
|
||||||
|
)
|
||||||
|
# Run tests
|
||||||
|
set(LCOV_EXEC_TESTS_CMD
|
||||||
|
${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
|
||||||
|
)
|
||||||
|
# Capturing lcov counters and generating report
|
||||||
|
set(LCOV_CAPTURE_CMD
|
||||||
|
${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --directory . -b
|
||||||
|
${BASEDIR} --capture --output-file ${Coverage_NAME}.capture
|
||||||
|
)
|
||||||
|
# add baseline counters
|
||||||
|
set(LCOV_BASELINE_COUNT_CMD
|
||||||
|
${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -a ${Coverage_NAME}.base
|
||||||
|
-a ${Coverage_NAME}.capture --output-file ${Coverage_NAME}.total
|
||||||
|
)
|
||||||
|
# filter collected data to final coverage report
|
||||||
|
set(LCOV_FILTER_CMD
|
||||||
|
${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --remove
|
||||||
|
${Coverage_NAME}.total ${LCOV_EXCLUDES} --output-file ${Coverage_NAME}.info
|
||||||
|
)
|
||||||
|
# Generate HTML output
|
||||||
|
set(LCOV_GEN_HTML_CMD
|
||||||
|
${GENHTML_PATH} ${GENHTML_EXTRA_ARGS} ${Coverage_GENHTML_ARGS} -o
|
||||||
|
${Coverage_NAME} ${Coverage_NAME}.info
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if(CODE_COVERAGE_VERBOSE)
|
||||||
|
message(STATUS "Executed command report")
|
||||||
|
message(STATUS "Command to clean up lcov: ")
|
||||||
|
string(REPLACE ";" " " LCOV_CLEAN_CMD_SPACED "${LCOV_CLEAN_CMD}")
|
||||||
|
message(STATUS "${LCOV_CLEAN_CMD_SPACED}")
|
||||||
|
|
||||||
|
message(STATUS "Command to create baseline: ")
|
||||||
|
string(REPLACE ";" " " LCOV_BASELINE_CMD_SPACED "${LCOV_BASELINE_CMD}")
|
||||||
|
message(STATUS "${LCOV_BASELINE_CMD_SPACED}")
|
||||||
|
|
||||||
|
message(STATUS "Command to run the tests: ")
|
||||||
|
string(REPLACE ";" " " LCOV_EXEC_TESTS_CMD_SPACED "${LCOV_EXEC_TESTS_CMD}")
|
||||||
|
message(STATUS "${LCOV_EXEC_TESTS_CMD_SPACED}")
|
||||||
|
|
||||||
|
message(STATUS "Command to capture counters and generate report: ")
|
||||||
|
string(REPLACE ";" " " LCOV_CAPTURE_CMD_SPACED "${LCOV_CAPTURE_CMD}")
|
||||||
|
message(STATUS "${LCOV_CAPTURE_CMD_SPACED}")
|
||||||
|
|
||||||
|
message(STATUS "Command to add baseline counters: ")
|
||||||
|
string(REPLACE ";" " " LCOV_BASELINE_COUNT_CMD_SPACED "${LCOV_BASELINE_COUNT_CMD}")
|
||||||
|
message(STATUS "${LCOV_BASELINE_COUNT_CMD_SPACED}")
|
||||||
|
|
||||||
|
message(STATUS "Command to filter collected data: ")
|
||||||
|
string(REPLACE ";" " " LCOV_FILTER_CMD_SPACED "${LCOV_FILTER_CMD}")
|
||||||
|
message(STATUS "${LCOV_FILTER_CMD_SPACED}")
|
||||||
|
|
||||||
|
message(STATUS "Command to generate lcov HTML output: ")
|
||||||
|
string(REPLACE ";" " " LCOV_GEN_HTML_CMD_SPACED "${LCOV_GEN_HTML_CMD}")
|
||||||
|
message(STATUS "${LCOV_GEN_HTML_CMD_SPACED}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Setup target
|
||||||
|
add_custom_target(${Coverage_NAME}
|
||||||
|
COMMAND ${LCOV_CLEAN_CMD}
|
||||||
|
COMMAND ${LCOV_BASELINE_CMD}
|
||||||
|
COMMAND ${LCOV_EXEC_TESTS_CMD}
|
||||||
|
COMMAND ${LCOV_CAPTURE_CMD}
|
||||||
|
COMMAND ${LCOV_BASELINE_COUNT_CMD}
|
||||||
|
COMMAND ${LCOV_FILTER_CMD}
|
||||||
|
COMMAND ${LCOV_GEN_HTML_CMD}
|
||||||
|
|
||||||
|
# Set output files as GENERATED (will be removed on 'make clean')
|
||||||
|
BYPRODUCTS
|
||||||
|
${Coverage_NAME}.base
|
||||||
|
${Coverage_NAME}.capture
|
||||||
|
${Coverage_NAME}.total
|
||||||
|
${Coverage_NAME}.info
|
||||||
|
${Coverage_NAME}/index.html
|
||||||
|
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
|
||||||
|
DEPENDS ${Coverage_DEPENDENCIES}
|
||||||
|
VERBATIM # Protect arguments to commands
|
||||||
|
COMMENT "Resetting code coverage counters to zero.\nProcessing code coverage counters and generating report."
|
||||||
|
)
|
||||||
|
|
||||||
|
# Show where to find the lcov info report
|
||||||
|
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
|
||||||
|
COMMAND ;
|
||||||
|
COMMENT "Lcov code coverage info report saved in ${Coverage_NAME}.info."
|
||||||
|
)
|
||||||
|
|
||||||
|
# Show info where to find the report
|
||||||
|
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
|
||||||
|
COMMAND ;
|
||||||
|
COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report."
|
||||||
|
)
|
||||||
|
|
||||||
|
endfunction() # setup_target_for_coverage_lcov
|
||||||
|
|
||||||
|
# Defines a target for running and collection code coverage information
|
||||||
|
# Builds dependencies, runs the given executable and outputs reports.
|
||||||
|
# NOTE! The executable should always have a ZERO as exit code otherwise
|
||||||
|
# the coverage generation will not complete.
|
||||||
|
#
|
||||||
|
# setup_target_for_coverage_gcovr_xml(
|
||||||
|
# NAME ctest_coverage # New target name
|
||||||
|
# EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
|
||||||
|
# DEPENDENCIES executable_target # Dependencies to build first
|
||||||
|
# BASE_DIRECTORY "../" # Base directory for report
|
||||||
|
# # (defaults to PROJECT_SOURCE_DIR)
|
||||||
|
# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative
|
||||||
|
# # to BASE_DIRECTORY, with CMake 3.4+)
|
||||||
|
# )
|
||||||
|
# The user can set the variable GCOVR_ADDITIONAL_ARGS to supply additional flags to the
|
||||||
|
# GCVOR command.
|
||||||
|
function(setup_target_for_coverage_gcovr_xml)
|
||||||
|
|
||||||
|
set(options NONE)
|
||||||
|
set(oneValueArgs BASE_DIRECTORY NAME)
|
||||||
|
set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
|
||||||
|
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||||
|
|
||||||
|
if(NOT GCOVR_PATH)
|
||||||
|
message(FATAL_ERROR "gcovr not found! Aborting...")
|
||||||
|
endif() # NOT GCOVR_PATH
|
||||||
|
|
||||||
|
# Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR
|
||||||
|
if(DEFINED Coverage_BASE_DIRECTORY)
|
||||||
|
get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE)
|
||||||
|
else()
|
||||||
|
set(BASEDIR ${PROJECT_SOURCE_DIR})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Collect excludes (CMake 3.4+: Also compute absolute paths)
|
||||||
|
set(GCOVR_EXCLUDES "")
|
||||||
|
foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_GCOVR_EXCLUDES})
|
||||||
|
if(CMAKE_VERSION VERSION_GREATER 3.4)
|
||||||
|
get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR})
|
||||||
|
endif()
|
||||||
|
list(APPEND GCOVR_EXCLUDES "${EXCLUDE}")
|
||||||
|
endforeach()
|
||||||
|
list(REMOVE_DUPLICATES GCOVR_EXCLUDES)
|
||||||
|
|
||||||
|
# Combine excludes to several -e arguments
|
||||||
|
set(GCOVR_EXCLUDE_ARGS "")
|
||||||
|
foreach(EXCLUDE ${GCOVR_EXCLUDES})
|
||||||
|
list(APPEND GCOVR_EXCLUDE_ARGS "-e")
|
||||||
|
list(APPEND GCOVR_EXCLUDE_ARGS "${EXCLUDE}")
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
# Set up commands which will be run to generate coverage data
|
||||||
|
# Run tests
|
||||||
|
set(GCOVR_XML_EXEC_TESTS_CMD
|
||||||
|
${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
|
||||||
|
)
|
||||||
|
# Running gcovr
|
||||||
|
set(GCOVR_XML_CMD
|
||||||
|
${GCOVR_PATH} --xml ${Coverage_NAME}.xml -r ${BASEDIR} ${GCOVR_ADDITIONAL_ARGS}
|
||||||
|
${GCOVR_EXCLUDE_ARGS} --object-directory=${PROJECT_BINARY_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
if(CODE_COVERAGE_VERBOSE)
|
||||||
|
message(STATUS "Executed command report")
|
||||||
|
|
||||||
|
message(STATUS "Command to run tests: ")
|
||||||
|
string(REPLACE ";" " " GCOVR_XML_EXEC_TESTS_CMD_SPACED "${GCOVR_XML_EXEC_TESTS_CMD}")
|
||||||
|
message(STATUS "${GCOVR_XML_EXEC_TESTS_CMD_SPACED}")
|
||||||
|
|
||||||
|
message(STATUS "Command to generate gcovr XML coverage data: ")
|
||||||
|
string(REPLACE ";" " " GCOVR_XML_CMD_SPACED "${GCOVR_XML_CMD}")
|
||||||
|
message(STATUS "${GCOVR_XML_CMD_SPACED}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_custom_target(${Coverage_NAME}
|
||||||
|
COMMAND ${GCOVR_XML_EXEC_TESTS_CMD}
|
||||||
|
COMMAND ${GCOVR_XML_CMD}
|
||||||
|
|
||||||
|
BYPRODUCTS ${Coverage_NAME}.xml
|
||||||
|
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
|
||||||
|
DEPENDS ${Coverage_DEPENDENCIES}
|
||||||
|
VERBATIM # Protect arguments to commands
|
||||||
|
COMMENT "Running gcovr to produce Cobertura code coverage report."
|
||||||
|
)
|
||||||
|
|
||||||
|
# Show info where to find the report
|
||||||
|
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
|
||||||
|
COMMAND ;
|
||||||
|
COMMENT "Cobertura code coverage report saved in ${Coverage_NAME}.xml."
|
||||||
|
)
|
||||||
|
endfunction() # setup_target_for_coverage_gcovr_xml
|
||||||
|
|
||||||
|
# Defines a target for running and collection code coverage information
|
||||||
|
# Builds dependencies, runs the given executable and outputs reports.
|
||||||
|
# NOTE! The executable should always have a ZERO as exit code otherwise
|
||||||
|
# the coverage generation will not complete.
|
||||||
|
#
|
||||||
|
# setup_target_for_coverage_gcovr_html(
|
||||||
|
# NAME ctest_coverage # New target name
|
||||||
|
# EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
|
||||||
|
# DEPENDENCIES executable_target # Dependencies to build first
|
||||||
|
# BASE_DIRECTORY "../" # Base directory for report
|
||||||
|
# # (defaults to PROJECT_SOURCE_DIR)
|
||||||
|
# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative
|
||||||
|
# # to BASE_DIRECTORY, with CMake 3.4+)
|
||||||
|
# )
|
||||||
|
# The user can set the variable GCOVR_ADDITIONAL_ARGS to supply additional flags to the
|
||||||
|
# GCVOR command.
|
||||||
|
function(setup_target_for_coverage_gcovr_html)
|
||||||
|
|
||||||
|
set(options NONE)
|
||||||
|
set(oneValueArgs BASE_DIRECTORY NAME)
|
||||||
|
set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
|
||||||
|
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||||
|
|
||||||
|
if(NOT GCOVR_PATH)
|
||||||
|
message(FATAL_ERROR "gcovr not found! Aborting...")
|
||||||
|
endif() # NOT GCOVR_PATH
|
||||||
|
|
||||||
|
# Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR
|
||||||
|
if(DEFINED Coverage_BASE_DIRECTORY)
|
||||||
|
get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE)
|
||||||
|
else()
|
||||||
|
set(BASEDIR ${PROJECT_SOURCE_DIR})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Collect excludes (CMake 3.4+: Also compute absolute paths)
|
||||||
|
set(GCOVR_EXCLUDES "")
|
||||||
|
foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_GCOVR_EXCLUDES})
|
||||||
|
if(CMAKE_VERSION VERSION_GREATER 3.4)
|
||||||
|
get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR})
|
||||||
|
endif()
|
||||||
|
list(APPEND GCOVR_EXCLUDES "${EXCLUDE}")
|
||||||
|
endforeach()
|
||||||
|
list(REMOVE_DUPLICATES GCOVR_EXCLUDES)
|
||||||
|
|
||||||
|
# Combine excludes to several -e arguments
|
||||||
|
set(GCOVR_EXCLUDE_ARGS "")
|
||||||
|
foreach(EXCLUDE ${GCOVR_EXCLUDES})
|
||||||
|
list(APPEND GCOVR_EXCLUDE_ARGS "-e")
|
||||||
|
list(APPEND GCOVR_EXCLUDE_ARGS "${EXCLUDE}")
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
# Set up commands which will be run to generate coverage data
|
||||||
|
# Run tests
|
||||||
|
set(GCOVR_HTML_EXEC_TESTS_CMD
|
||||||
|
${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
|
||||||
|
)
|
||||||
|
# Create folder
|
||||||
|
set(GCOVR_HTML_FOLDER_CMD
|
||||||
|
${CMAKE_COMMAND} -E make_directory ${PROJECT_BINARY_DIR}/${Coverage_NAME}
|
||||||
|
)
|
||||||
|
# Running gcovr
|
||||||
|
set(GCOVR_HTML_CMD
|
||||||
|
${GCOVR_PATH} --html ${Coverage_NAME}/index.html --html-details -r ${BASEDIR} ${GCOVR_ADDITIONAL_ARGS}
|
||||||
|
${GCOVR_EXCLUDE_ARGS} --object-directory=${PROJECT_BINARY_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
if(CODE_COVERAGE_VERBOSE)
|
||||||
|
message(STATUS "Executed command report")
|
||||||
|
|
||||||
|
message(STATUS "Command to run tests: ")
|
||||||
|
string(REPLACE ";" " " GCOVR_HTML_EXEC_TESTS_CMD_SPACED "${GCOVR_HTML_EXEC_TESTS_CMD}")
|
||||||
|
message(STATUS "${GCOVR_HTML_EXEC_TESTS_CMD_SPACED}")
|
||||||
|
|
||||||
|
message(STATUS "Command to create a folder: ")
|
||||||
|
string(REPLACE ";" " " GCOVR_HTML_FOLDER_CMD_SPACED "${GCOVR_HTML_FOLDER_CMD}")
|
||||||
|
message(STATUS "${GCOVR_HTML_FOLDER_CMD_SPACED}")
|
||||||
|
|
||||||
|
message(STATUS "Command to generate gcovr HTML coverage data: ")
|
||||||
|
string(REPLACE ";" " " GCOVR_HTML_CMD_SPACED "${GCOVR_HTML_CMD}")
|
||||||
|
message(STATUS "${GCOVR_HTML_CMD_SPACED}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_custom_target(${Coverage_NAME}
|
||||||
|
COMMAND ${GCOVR_HTML_EXEC_TESTS_CMD}
|
||||||
|
COMMAND ${GCOVR_HTML_FOLDER_CMD}
|
||||||
|
COMMAND ${GCOVR_HTML_CMD}
|
||||||
|
|
||||||
|
BYPRODUCTS ${PROJECT_BINARY_DIR}/${Coverage_NAME}/index.html # report directory
|
||||||
|
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
|
||||||
|
DEPENDS ${Coverage_DEPENDENCIES}
|
||||||
|
VERBATIM # Protect arguments to commands
|
||||||
|
COMMENT "Running gcovr to produce HTML code coverage report."
|
||||||
|
)
|
||||||
|
|
||||||
|
# Show info where to find the report
|
||||||
|
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
|
||||||
|
COMMAND ;
|
||||||
|
COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report."
|
||||||
|
)
|
||||||
|
|
||||||
|
endfunction() # setup_target_for_coverage_gcovr_html
|
||||||
|
|
||||||
|
# Defines a target for running and collection code coverage information
|
||||||
|
# Builds dependencies, runs the given executable and outputs reports.
|
||||||
|
# NOTE! The executable should always have a ZERO as exit code otherwise
|
||||||
|
# the coverage generation will not complete.
|
||||||
|
#
|
||||||
|
# setup_target_for_coverage_fastcov(
|
||||||
|
# NAME testrunner_coverage # New target name
|
||||||
|
# EXECUTABLE testrunner -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
|
||||||
|
# DEPENDENCIES testrunner # Dependencies to build first
|
||||||
|
# BASE_DIRECTORY "../" # Base directory for report
|
||||||
|
# # (defaults to PROJECT_SOURCE_DIR)
|
||||||
|
# EXCLUDE "src/dir1/" "src/dir2/" # Patterns to exclude.
|
||||||
|
# NO_DEMANGLE # Don't demangle C++ symbols
|
||||||
|
# # even if c++filt is found
|
||||||
|
# SKIP_HTML # Don't create html report
|
||||||
|
# POST_CMD perl -i -pe s!${PROJECT_SOURCE_DIR}/!!g ctest_coverage.json # E.g. for stripping source dir from file paths
|
||||||
|
# )
|
||||||
|
function(setup_target_for_coverage_fastcov)
|
||||||
|
|
||||||
|
set(options NO_DEMANGLE SKIP_HTML)
|
||||||
|
set(oneValueArgs BASE_DIRECTORY NAME)
|
||||||
|
set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES FASTCOV_ARGS GENHTML_ARGS POST_CMD)
|
||||||
|
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||||
|
|
||||||
|
if(NOT FASTCOV_PATH)
|
||||||
|
message(FATAL_ERROR "fastcov not found! Aborting...")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT Coverage_SKIP_HTML AND NOT GENHTML_PATH)
|
||||||
|
message(FATAL_ERROR "genhtml not found! Aborting...")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR
|
||||||
|
if(Coverage_BASE_DIRECTORY)
|
||||||
|
get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE)
|
||||||
|
else()
|
||||||
|
set(BASEDIR ${PROJECT_SOURCE_DIR})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Collect excludes (Patterns, not paths, for fastcov)
|
||||||
|
set(FASTCOV_EXCLUDES "")
|
||||||
|
foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_FASTCOV_EXCLUDES})
|
||||||
|
list(APPEND FASTCOV_EXCLUDES "${EXCLUDE}")
|
||||||
|
endforeach()
|
||||||
|
list(REMOVE_DUPLICATES FASTCOV_EXCLUDES)
|
||||||
|
|
||||||
|
# Conditional arguments
|
||||||
|
if(CPPFILT_PATH AND NOT ${Coverage_NO_DEMANGLE})
|
||||||
|
set(GENHTML_EXTRA_ARGS "--demangle-cpp")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Set up commands which will be run to generate coverage data
|
||||||
|
set(FASTCOV_EXEC_TESTS_CMD ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS})
|
||||||
|
|
||||||
|
set(FASTCOV_CAPTURE_CMD ${FASTCOV_PATH} ${Coverage_FASTCOV_ARGS} --gcov ${GCOV_PATH}
|
||||||
|
--search-directory ${BASEDIR}
|
||||||
|
--process-gcno
|
||||||
|
--output ${Coverage_NAME}.json
|
||||||
|
--exclude ${FASTCOV_EXCLUDES}
|
||||||
|
--exclude ${FASTCOV_EXCLUDES}
|
||||||
|
)
|
||||||
|
|
||||||
|
set(FASTCOV_CONVERT_CMD ${FASTCOV_PATH}
|
||||||
|
-C ${Coverage_NAME}.json --lcov --output ${Coverage_NAME}.info
|
||||||
|
)
|
||||||
|
|
||||||
|
if(Coverage_SKIP_HTML)
|
||||||
|
set(FASTCOV_HTML_CMD ";")
|
||||||
|
else()
|
||||||
|
set(FASTCOV_HTML_CMD ${GENHTML_PATH} ${GENHTML_EXTRA_ARGS} ${Coverage_GENHTML_ARGS}
|
||||||
|
-o ${Coverage_NAME} ${Coverage_NAME}.info
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(FASTCOV_POST_CMD ";")
|
||||||
|
if(Coverage_POST_CMD)
|
||||||
|
set(FASTCOV_POST_CMD ${Coverage_POST_CMD})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(CODE_COVERAGE_VERBOSE)
|
||||||
|
message(STATUS "Code coverage commands for target ${Coverage_NAME} (fastcov):")
|
||||||
|
|
||||||
|
message(" Running tests:")
|
||||||
|
string(REPLACE ";" " " FASTCOV_EXEC_TESTS_CMD_SPACED "${FASTCOV_EXEC_TESTS_CMD}")
|
||||||
|
message(" ${FASTCOV_EXEC_TESTS_CMD_SPACED}")
|
||||||
|
|
||||||
|
message(" Capturing fastcov counters and generating report:")
|
||||||
|
string(REPLACE ";" " " FASTCOV_CAPTURE_CMD_SPACED "${FASTCOV_CAPTURE_CMD}")
|
||||||
|
message(" ${FASTCOV_CAPTURE_CMD_SPACED}")
|
||||||
|
|
||||||
|
message(" Converting fastcov .json to lcov .info:")
|
||||||
|
string(REPLACE ";" " " FASTCOV_CONVERT_CMD_SPACED "${FASTCOV_CONVERT_CMD}")
|
||||||
|
message(" ${FASTCOV_CONVERT_CMD_SPACED}")
|
||||||
|
|
||||||
|
if(NOT Coverage_SKIP_HTML)
|
||||||
|
message(" Generating HTML report: ")
|
||||||
|
string(REPLACE ";" " " FASTCOV_HTML_CMD_SPACED "${FASTCOV_HTML_CMD}")
|
||||||
|
message(" ${FASTCOV_HTML_CMD_SPACED}")
|
||||||
|
endif()
|
||||||
|
if(Coverage_POST_CMD)
|
||||||
|
message(" Running post command: ")
|
||||||
|
string(REPLACE ";" " " FASTCOV_POST_CMD_SPACED "${FASTCOV_POST_CMD}")
|
||||||
|
message(" ${FASTCOV_POST_CMD_SPACED}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Setup target
|
||||||
|
add_custom_target(${Coverage_NAME}
|
||||||
|
|
||||||
|
# Cleanup fastcov
|
||||||
|
COMMAND ${FASTCOV_PATH} ${Coverage_FASTCOV_ARGS} --gcov ${GCOV_PATH}
|
||||||
|
--search-directory ${BASEDIR}
|
||||||
|
--zerocounters
|
||||||
|
|
||||||
|
COMMAND ${FASTCOV_EXEC_TESTS_CMD}
|
||||||
|
COMMAND ${FASTCOV_CAPTURE_CMD}
|
||||||
|
COMMAND ${FASTCOV_CONVERT_CMD}
|
||||||
|
COMMAND ${FASTCOV_HTML_CMD}
|
||||||
|
COMMAND ${FASTCOV_POST_CMD}
|
||||||
|
|
||||||
|
# Set output files as GENERATED (will be removed on 'make clean')
|
||||||
|
BYPRODUCTS
|
||||||
|
${Coverage_NAME}.info
|
||||||
|
${Coverage_NAME}.json
|
||||||
|
${Coverage_NAME}/index.html # report directory
|
||||||
|
|
||||||
|
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
|
||||||
|
DEPENDS ${Coverage_DEPENDENCIES}
|
||||||
|
VERBATIM # Protect arguments to commands
|
||||||
|
COMMENT "Resetting code coverage counters to zero. Processing code coverage counters and generating report."
|
||||||
|
)
|
||||||
|
|
||||||
|
set(INFO_MSG "fastcov code coverage info report saved in ${Coverage_NAME}.info and ${Coverage_NAME}.json.")
|
||||||
|
if(NOT Coverage_SKIP_HTML)
|
||||||
|
string(APPEND INFO_MSG " Open ${PROJECT_BINARY_DIR}/${Coverage_NAME}/index.html in your browser to view the coverage report.")
|
||||||
|
endif()
|
||||||
|
# Show where to find the fastcov info report
|
||||||
|
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E echo ${INFO_MSG}
|
||||||
|
)
|
||||||
|
|
||||||
|
endfunction() # setup_target_for_coverage_fastcov
|
||||||
|
|
||||||
|
function(append_coverage_compiler_flags)
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
|
||||||
|
set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
|
||||||
|
message(STATUS "Appending code coverage compiler flags: ${COVERAGE_COMPILER_FLAGS}")
|
||||||
|
endfunction() # append_coverage_compiler_flags
|
||||||
|
|
||||||
|
# Setup coverage for specific library
|
||||||
|
function(append_coverage_compiler_flags_to_target name)
|
||||||
|
target_compile_options(${name}
|
||||||
|
PRIVATE ${COVERAGE_COMPILER_FLAGS})
|
||||||
|
endfunction()
|
23
cmake/cmake-modules/bilke/LICENSE_1_0.txt
Normal file
23
cmake/cmake-modules/bilke/LICENSE_1_0.txt
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
Boost Software License - Version 1.0 - August 17th, 2003
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person or organization
|
||||||
|
obtaining a copy of the software and accompanying documentation covered by
|
||||||
|
this license (the "Software") to use, reproduce, display, distribute,
|
||||||
|
execute, and transmit the Software, and to prepare derivative works of the
|
||||||
|
Software, and to permit third-parties to whom the Software is furnished to
|
||||||
|
do so, all subject to the following:
|
||||||
|
|
||||||
|
The copyright notices in the Software and this entire statement, including
|
||||||
|
the above license grant, this restriction and the following disclaimer,
|
||||||
|
must be included in all copies of the Software, in whole or in part, and
|
||||||
|
all derivative works of the Software, unless such copies or derivative
|
||||||
|
works are solely in the form of machine-executable object code generated by
|
||||||
|
a source language processor.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||||
|
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||||
|
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||||
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
284
cmake/cmake-modules/rpavlik/GetGitRevisionDescription.cmake
Normal file
284
cmake/cmake-modules/rpavlik/GetGitRevisionDescription.cmake
Normal file
@ -0,0 +1,284 @@
|
|||||||
|
# - Returns a version string from Git
|
||||||
|
#
|
||||||
|
# These functions force a re-configure on each git commit so that you can
|
||||||
|
# trust the values of the variables in your build system.
|
||||||
|
#
|
||||||
|
# get_git_head_revision(<refspecvar> <hashvar> [ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR])
|
||||||
|
#
|
||||||
|
# Returns the refspec and sha hash of the current head revision
|
||||||
|
#
|
||||||
|
# git_describe(<var> [<additional arguments to git describe> ...])
|
||||||
|
#
|
||||||
|
# Returns the results of git describe on the source tree, and adjusting
|
||||||
|
# the output so that it tests false if an error occurs.
|
||||||
|
#
|
||||||
|
# git_describe_working_tree(<var> [<additional arguments to git describe> ...])
|
||||||
|
#
|
||||||
|
# Returns the results of git describe on the working tree (--dirty option),
|
||||||
|
# and adjusting the output so that it tests false if an error occurs.
|
||||||
|
#
|
||||||
|
# git_get_exact_tag(<var> [<additional arguments to git describe> ...])
|
||||||
|
#
|
||||||
|
# Returns the results of git describe --exact-match on the source tree,
|
||||||
|
# and adjusting the output so that it tests false if there was no exact
|
||||||
|
# matching tag.
|
||||||
|
#
|
||||||
|
# git_local_changes(<var>)
|
||||||
|
#
|
||||||
|
# Returns either "CLEAN" or "DIRTY" with respect to uncommitted changes.
|
||||||
|
# Uses the return code of "git diff-index --quiet HEAD --".
|
||||||
|
# Does not regard untracked files.
|
||||||
|
#
|
||||||
|
# Requires CMake 2.6 or newer (uses the 'function' command)
|
||||||
|
#
|
||||||
|
# Original Author:
|
||||||
|
# 2009-2020 Ryan Pavlik <ryan.pavlik@gmail.com> <abiryan@ryand.net>
|
||||||
|
# http://academic.cleardefinition.com
|
||||||
|
#
|
||||||
|
# Copyright 2009-2013, Iowa State University.
|
||||||
|
# Copyright 2013-2020, Ryan Pavlik
|
||||||
|
# Copyright 2013-2020, Contributors
|
||||||
|
# SPDX-License-Identifier: BSL-1.0
|
||||||
|
# Distributed under the Boost Software License, Version 1.0.
|
||||||
|
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
# http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
if(__get_git_revision_description)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
set(__get_git_revision_description YES)
|
||||||
|
|
||||||
|
# We must run the following at "include" time, not at function call time,
|
||||||
|
# to find the path to this module rather than the path to a calling list file
|
||||||
|
get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH)
|
||||||
|
|
||||||
|
# Function _git_find_closest_git_dir finds the next closest .git directory
|
||||||
|
# that is part of any directory in the path defined by _start_dir.
|
||||||
|
# The result is returned in the parent scope variable whose name is passed
|
||||||
|
# as variable _git_dir_var. If no .git directory can be found, the
|
||||||
|
# function returns an empty string via _git_dir_var.
|
||||||
|
#
|
||||||
|
# Example: Given a path C:/bla/foo/bar and assuming C:/bla/.git exists and
|
||||||
|
# neither foo nor bar contain a file/directory .git. This wil return
|
||||||
|
# C:/bla/.git
|
||||||
|
#
|
||||||
|
function(_git_find_closest_git_dir _start_dir _git_dir_var)
|
||||||
|
set(cur_dir "${_start_dir}")
|
||||||
|
set(git_dir "${_start_dir}/.git")
|
||||||
|
while(NOT EXISTS "${git_dir}")
|
||||||
|
# .git dir not found, search parent directories
|
||||||
|
set(git_previous_parent "${cur_dir}")
|
||||||
|
get_filename_component(cur_dir "${cur_dir}" DIRECTORY)
|
||||||
|
if(cur_dir STREQUAL git_previous_parent)
|
||||||
|
# We have reached the root directory, we are not in git
|
||||||
|
set(${_git_dir_var}
|
||||||
|
""
|
||||||
|
PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
set(git_dir "${cur_dir}/.git")
|
||||||
|
endwhile()
|
||||||
|
set(${_git_dir_var}
|
||||||
|
"${git_dir}"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(get_git_head_revision _refspecvar _hashvar)
|
||||||
|
_git_find_closest_git_dir("${CMAKE_CURRENT_SOURCE_DIR}" GIT_DIR)
|
||||||
|
|
||||||
|
if("${ARGN}" STREQUAL "ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR")
|
||||||
|
set(ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR TRUE)
|
||||||
|
else()
|
||||||
|
set(ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR FALSE)
|
||||||
|
endif()
|
||||||
|
if(NOT "${GIT_DIR}" STREQUAL "")
|
||||||
|
file(RELATIVE_PATH _relative_to_source_dir "${CMAKE_SOURCE_DIR}"
|
||||||
|
"${GIT_DIR}")
|
||||||
|
if("${_relative_to_source_dir}" MATCHES "[.][.]" AND NOT ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR)
|
||||||
|
# We've gone above the CMake root dir.
|
||||||
|
set(GIT_DIR "")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
if("${GIT_DIR}" STREQUAL "")
|
||||||
|
set(${_refspecvar}
|
||||||
|
"GITDIR-NOTFOUND"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
set(${_hashvar}
|
||||||
|
"GITDIR-NOTFOUND"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Check if the current source dir is a git submodule or a worktree.
|
||||||
|
# In both cases .git is a file instead of a directory.
|
||||||
|
#
|
||||||
|
if(NOT IS_DIRECTORY ${GIT_DIR})
|
||||||
|
# The following git command will return a non empty string that
|
||||||
|
# points to the super project working tree if the current
|
||||||
|
# source dir is inside a git submodule.
|
||||||
|
# Otherwise the command will return an empty string.
|
||||||
|
#
|
||||||
|
execute_process(
|
||||||
|
COMMAND "${GIT_EXECUTABLE}" rev-parse
|
||||||
|
--show-superproject-working-tree
|
||||||
|
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
|
OUTPUT_VARIABLE out
|
||||||
|
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
if(NOT "${out}" STREQUAL "")
|
||||||
|
# If out is empty, GIT_DIR/CMAKE_CURRENT_SOURCE_DIR is in a submodule
|
||||||
|
file(READ ${GIT_DIR} submodule)
|
||||||
|
string(REGEX REPLACE "gitdir: (.*)$" "\\1" GIT_DIR_RELATIVE
|
||||||
|
${submodule})
|
||||||
|
string(STRIP ${GIT_DIR_RELATIVE} GIT_DIR_RELATIVE)
|
||||||
|
get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH)
|
||||||
|
get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE}
|
||||||
|
ABSOLUTE)
|
||||||
|
set(HEAD_SOURCE_FILE "${GIT_DIR}/HEAD")
|
||||||
|
else()
|
||||||
|
# GIT_DIR/CMAKE_CURRENT_SOURCE_DIR is in a worktree
|
||||||
|
file(READ ${GIT_DIR} worktree_ref)
|
||||||
|
# The .git directory contains a path to the worktree information directory
|
||||||
|
# inside the parent git repo of the worktree.
|
||||||
|
#
|
||||||
|
string(REGEX REPLACE "gitdir: (.*)$" "\\1" git_worktree_dir
|
||||||
|
${worktree_ref})
|
||||||
|
string(STRIP ${git_worktree_dir} git_worktree_dir)
|
||||||
|
_git_find_closest_git_dir("${git_worktree_dir}" GIT_DIR)
|
||||||
|
set(HEAD_SOURCE_FILE "${git_worktree_dir}/HEAD")
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
set(HEAD_SOURCE_FILE "${GIT_DIR}/HEAD")
|
||||||
|
endif()
|
||||||
|
set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data")
|
||||||
|
if(NOT EXISTS "${GIT_DATA}")
|
||||||
|
file(MAKE_DIRECTORY "${GIT_DATA}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT EXISTS "${HEAD_SOURCE_FILE}")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
set(HEAD_FILE "${GIT_DATA}/HEAD")
|
||||||
|
configure_file("${HEAD_SOURCE_FILE}" "${HEAD_FILE}" COPYONLY)
|
||||||
|
|
||||||
|
configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in"
|
||||||
|
"${GIT_DATA}/grabRef.cmake" @ONLY)
|
||||||
|
include("${GIT_DATA}/grabRef.cmake")
|
||||||
|
|
||||||
|
set(${_refspecvar}
|
||||||
|
"${HEAD_REF}"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
set(${_hashvar}
|
||||||
|
"${HEAD_HASH}"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(git_describe _var)
|
||||||
|
if(NOT GIT_FOUND)
|
||||||
|
find_package(Git QUIET)
|
||||||
|
endif()
|
||||||
|
get_git_head_revision(refspec hash)
|
||||||
|
if(NOT GIT_FOUND)
|
||||||
|
set(${_var}
|
||||||
|
"GIT-NOTFOUND"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
if(NOT hash)
|
||||||
|
set(${_var}
|
||||||
|
"HEAD-HASH-NOTFOUND"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# TODO sanitize
|
||||||
|
#if((${ARGN}" MATCHES "&&") OR
|
||||||
|
# (ARGN MATCHES "||") OR
|
||||||
|
# (ARGN MATCHES "\\;"))
|
||||||
|
# message("Please report the following error to the project!")
|
||||||
|
# message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}")
|
||||||
|
#endif()
|
||||||
|
|
||||||
|
#message(STATUS "Arguments to execute_process: ${ARGN}")
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND "${GIT_EXECUTABLE}" describe --tags --always ${hash} ${ARGN}
|
||||||
|
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
|
RESULT_VARIABLE res
|
||||||
|
OUTPUT_VARIABLE out
|
||||||
|
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
if(NOT res EQUAL 0)
|
||||||
|
set(out "${out}-${res}-NOTFOUND")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(${_var}
|
||||||
|
"${out}"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(git_describe_working_tree _var)
|
||||||
|
if(NOT GIT_FOUND)
|
||||||
|
find_package(Git QUIET)
|
||||||
|
endif()
|
||||||
|
if(NOT GIT_FOUND)
|
||||||
|
set(${_var}
|
||||||
|
"GIT-NOTFOUND"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND "${GIT_EXECUTABLE}" describe --dirty ${ARGN}
|
||||||
|
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
|
RESULT_VARIABLE res
|
||||||
|
OUTPUT_VARIABLE out
|
||||||
|
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
if(NOT res EQUAL 0)
|
||||||
|
set(out "${out}-${res}-NOTFOUND")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(${_var}
|
||||||
|
"${out}"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(git_get_exact_tag _var)
|
||||||
|
git_describe(out --exact-match ${ARGN})
|
||||||
|
set(${_var}
|
||||||
|
"${out}"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(git_local_changes _var)
|
||||||
|
if(NOT GIT_FOUND)
|
||||||
|
find_package(Git QUIET)
|
||||||
|
endif()
|
||||||
|
get_git_head_revision(refspec hash)
|
||||||
|
if(NOT GIT_FOUND)
|
||||||
|
set(${_var}
|
||||||
|
"GIT-NOTFOUND"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
if(NOT hash)
|
||||||
|
set(${_var}
|
||||||
|
"HEAD-HASH-NOTFOUND"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND "${GIT_EXECUTABLE}" diff-index --quiet HEAD --
|
||||||
|
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
|
RESULT_VARIABLE res
|
||||||
|
OUTPUT_VARIABLE out
|
||||||
|
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
if(res EQUAL 0)
|
||||||
|
set(${_var}
|
||||||
|
"CLEAN"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
else()
|
||||||
|
set(${_var}
|
||||||
|
"DIRTY"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
endif()
|
||||||
|
endfunction()
|
@ -0,0 +1,43 @@
|
|||||||
|
#
|
||||||
|
# Internal file for GetGitRevisionDescription.cmake
|
||||||
|
#
|
||||||
|
# Requires CMake 2.6 or newer (uses the 'function' command)
|
||||||
|
#
|
||||||
|
# Original Author:
|
||||||
|
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
|
||||||
|
# http://academic.cleardefinition.com
|
||||||
|
# Iowa State University HCI Graduate Program/VRAC
|
||||||
|
#
|
||||||
|
# Copyright 2009-2012, Iowa State University
|
||||||
|
# Copyright 2011-2015, Contributors
|
||||||
|
# Distributed under the Boost Software License, Version 1.0.
|
||||||
|
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
# http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
# SPDX-License-Identifier: BSL-1.0
|
||||||
|
|
||||||
|
set(HEAD_HASH)
|
||||||
|
|
||||||
|
file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024)
|
||||||
|
|
||||||
|
string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS)
|
||||||
|
if(HEAD_CONTENTS MATCHES "ref")
|
||||||
|
# named branch
|
||||||
|
string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}")
|
||||||
|
if(EXISTS "@GIT_DIR@/${HEAD_REF}")
|
||||||
|
configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
|
||||||
|
else()
|
||||||
|
configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY)
|
||||||
|
file(READ "@GIT_DATA@/packed-refs" PACKED_REFS)
|
||||||
|
if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}")
|
||||||
|
set(HEAD_HASH "${CMAKE_MATCH_1}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
# detached HEAD
|
||||||
|
configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT HEAD_HASH)
|
||||||
|
file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024)
|
||||||
|
string(STRIP "${HEAD_HASH}" HEAD_HASH)
|
||||||
|
endif()
|
26
cmake/cmake-modules/rpavlik/LICENSES/BSD-3-Clause.txt
Normal file
26
cmake/cmake-modules/rpavlik/LICENSES/BSD-3-Clause.txt
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
Copyright (c) <year> <owner>. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
3. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
may be used to endorse or promote products derived from this software without
|
||||||
|
specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||||
|
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
23
cmake/cmake-modules/rpavlik/LICENSES/BSL-1.0.txt
Normal file
23
cmake/cmake-modules/rpavlik/LICENSES/BSL-1.0.txt
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
Boost Software License - Version 1.0 - August 17th, 2003
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person or organization
|
||||||
|
obtaining a copy of the software and accompanying documentation covered by
|
||||||
|
this license (the "Software") to use, reproduce, display, distribute, execute,
|
||||||
|
and transmit the Software, and to prepare derivative works of the Software,
|
||||||
|
and to permit third-parties to whom the Software is furnished to do so, all
|
||||||
|
subject to the following:
|
||||||
|
|
||||||
|
The copyright notices in the Software and this entire statement, including
|
||||||
|
the above license grant, this restriction and the following disclaimer, must
|
||||||
|
be included in all copies of the Software, in whole or in part, and all derivative
|
||||||
|
works of the Software, unless such copies or derivative works are solely in
|
||||||
|
the form of machine-executable object code generated by a source language
|
||||||
|
processor.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES
|
||||||
|
OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
23
cmake/cmake-modules/rpavlik/LICENSE_1_0.txt
Normal file
23
cmake/cmake-modules/rpavlik/LICENSE_1_0.txt
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
Boost Software License - Version 1.0 - August 17th, 2003
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person or organization
|
||||||
|
obtaining a copy of the software and accompanying documentation covered by
|
||||||
|
this license (the "Software") to use, reproduce, display, distribute,
|
||||||
|
execute, and transmit the Software, and to prepare derivative works of the
|
||||||
|
Software, and to permit third-parties to whom the Software is furnished to
|
||||||
|
do so, all subject to the following:
|
||||||
|
|
||||||
|
The copyright notices in the Software and this entire statement, including
|
||||||
|
the above license grant, this restriction and the following disclaimer,
|
||||||
|
must be included in all copies of the Software, in whole or in part, and
|
||||||
|
all derivative works of the Software, unless such copies or derivative
|
||||||
|
works are solely in the form of machine-executable object code generated by
|
||||||
|
a source language processor.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||||
|
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||||
|
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||||
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
@ -1,253 +0,0 @@
|
|||||||
#ifndef FSFW_CONTAINER_ARRAYLIST_H_
|
|
||||||
#define FSFW_CONTAINER_ARRAYLIST_H_
|
|
||||||
|
|
||||||
#include "../returnvalues/HasReturnvaluesIF.h"
|
|
||||||
#include "../serialize/SerializeAdapter.h"
|
|
||||||
#include "../serialize/SerializeIF.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief A List that stores its values in an array.
|
|
||||||
* @details
|
|
||||||
* The underlying storage is an array that can be allocated by the class
|
|
||||||
* itself or supplied via ctor.
|
|
||||||
*
|
|
||||||
* @ingroup container
|
|
||||||
*/
|
|
||||||
template<typename T, typename count_t = uint8_t>
|
|
||||||
class ArrayList {
|
|
||||||
template<typename U, typename count> friend class SerialArrayListAdapter;
|
|
||||||
public:
|
|
||||||
static const uint8_t INTERFACE_ID = CLASS_ID::ARRAY_LIST;
|
|
||||||
static const ReturnValue_t FULL = MAKE_RETURN_CODE(0x01);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is the allocating constructor.
|
|
||||||
* It allocates an array of the specified size.
|
|
||||||
* @param maxSize
|
|
||||||
*/
|
|
||||||
ArrayList(count_t maxSize) :
|
|
||||||
size(0), maxSize_(maxSize), allocated(true) {
|
|
||||||
entries = new T[maxSize];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is the non-allocating constructor
|
|
||||||
*
|
|
||||||
* It expects a pointer to an array of a certain size and initializes
|
|
||||||
* itself to it.
|
|
||||||
*
|
|
||||||
* @param storage the array to use as backend
|
|
||||||
* @param maxSize size of storage
|
|
||||||
* @param size size of data already present in storage
|
|
||||||
*/
|
|
||||||
ArrayList(T *storage, count_t maxSize, count_t size = 0) :
|
|
||||||
size(size), entries(storage), maxSize_(maxSize), allocated(false) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copying is forbiden by declaring copy ctor and copy assignment deleted
|
|
||||||
* It is too ambigous in this case.
|
|
||||||
* (Allocate a new backend? Use the same? What to do in an modifying call?)
|
|
||||||
*/
|
|
||||||
ArrayList(const ArrayList& other) = delete;
|
|
||||||
const ArrayList& operator=(const ArrayList& other) = delete;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Number of Elements stored in this List
|
|
||||||
*/
|
|
||||||
count_t size;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destructor, if the allocating constructor was used, it deletes the array.
|
|
||||||
*/
|
|
||||||
virtual ~ArrayList() {
|
|
||||||
if (allocated) {
|
|
||||||
delete[] entries;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An Iterator to go trough an ArrayList
|
|
||||||
*
|
|
||||||
* It stores a pointer to an element and increments the
|
|
||||||
* pointer when incremented itself.
|
|
||||||
*/
|
|
||||||
class Iterator {
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Empty ctor, points to NULL
|
|
||||||
*/
|
|
||||||
Iterator(): value(0) {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes the Iterator to point to an element
|
|
||||||
*
|
|
||||||
* @param initialize
|
|
||||||
*/
|
|
||||||
Iterator(T *initialize) {
|
|
||||||
value = initialize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The current element the iterator points to
|
|
||||||
*/
|
|
||||||
T *value;
|
|
||||||
|
|
||||||
Iterator& operator++() {
|
|
||||||
value++;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Iterator operator++(int) {
|
|
||||||
Iterator tmp(*this);
|
|
||||||
operator++();
|
|
||||||
return tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
Iterator& operator--() {
|
|
||||||
value--;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Iterator operator--(int) {
|
|
||||||
Iterator tmp(*this);
|
|
||||||
operator--();
|
|
||||||
return tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
T& operator*() {
|
|
||||||
return *value;
|
|
||||||
}
|
|
||||||
|
|
||||||
const T& operator*() const {
|
|
||||||
return *value;
|
|
||||||
}
|
|
||||||
|
|
||||||
T *operator->() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
const T *operator->() const {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
friend bool operator==(const ArrayList::Iterator& lhs,
|
|
||||||
const ArrayList::Iterator& rhs) {
|
|
||||||
return (lhs.value == rhs.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
friend bool operator!=(const ArrayList::Iterator& lhs,
|
|
||||||
const ArrayList::Iterator& rhs) {
|
|
||||||
return not (lhs.value == rhs.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Iterator pointing to the first stored elmement
|
|
||||||
*
|
|
||||||
* @return Iterator to the first element
|
|
||||||
*/
|
|
||||||
Iterator begin() const {
|
|
||||||
return Iterator(&entries[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* returns an Iterator pointing to the element after the last stored entry
|
|
||||||
*
|
|
||||||
* @return Iterator to the element after the last entry
|
|
||||||
*/
|
|
||||||
Iterator end() const {
|
|
||||||
return Iterator(&entries[size]);
|
|
||||||
}
|
|
||||||
|
|
||||||
T & operator[](count_t i) const {
|
|
||||||
return entries[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The first element
|
|
||||||
*
|
|
||||||
* @return pointer to the first stored element
|
|
||||||
*/
|
|
||||||
T *front() {
|
|
||||||
return entries;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The last element
|
|
||||||
*
|
|
||||||
* does not return a valid pointer if called on an empty list.
|
|
||||||
*
|
|
||||||
* @return pointer to the last stored element
|
|
||||||
*/
|
|
||||||
T *back() {
|
|
||||||
return &entries[size - 1];
|
|
||||||
//Alternative solution
|
|
||||||
//return const_cast<T*>(static_cast<const T*>(*this).back());
|
|
||||||
}
|
|
||||||
|
|
||||||
const T* back() const{
|
|
||||||
return &entries[size-1];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The maximum number of elements this List can contain
|
|
||||||
*
|
|
||||||
* @return maximum number of elements
|
|
||||||
*/
|
|
||||||
size_t maxSize() const {
|
|
||||||
return this->maxSize_;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Insert a new element into the list.
|
|
||||||
*
|
|
||||||
* The new element is inserted after the last stored element.
|
|
||||||
*
|
|
||||||
* @param entry
|
|
||||||
* @return
|
|
||||||
* -@c FULL if the List is full
|
|
||||||
* -@c RETURN_OK else
|
|
||||||
*/
|
|
||||||
ReturnValue_t insert(T entry) {
|
|
||||||
if (size >= maxSize_) {
|
|
||||||
return FULL;
|
|
||||||
}
|
|
||||||
entries[size] = entry;
|
|
||||||
++size;
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* clear the List
|
|
||||||
*
|
|
||||||
* This does not actually clear all entries, it only sets the size to 0.
|
|
||||||
*/
|
|
||||||
void clear() {
|
|
||||||
size = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
count_t remaining() {
|
|
||||||
return (maxSize_ - size);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
/**
|
|
||||||
* pointer to the array in which the entries are stored
|
|
||||||
*/
|
|
||||||
T *entries;
|
|
||||||
/**
|
|
||||||
* remembering the maximum size
|
|
||||||
*/
|
|
||||||
size_t maxSize_;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* true if the array was allocated and needs to be deleted in the destructor.
|
|
||||||
*/
|
|
||||||
bool allocated;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* FSFW_CONTAINER_ARRAYLIST_H_ */
|
|
@ -1,153 +0,0 @@
|
|||||||
#ifndef FRAMEWORK_CONTAINER_BINARYTREE_H_
|
|
||||||
#define FRAMEWORK_CONTAINER_BINARYTREE_H_
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <map>
|
|
||||||
template<typename Tp>
|
|
||||||
class BinaryNode {
|
|
||||||
public:
|
|
||||||
BinaryNode(Tp* setValue) :
|
|
||||||
value(setValue), left(NULL), right(NULL), parent(NULL) {
|
|
||||||
}
|
|
||||||
Tp *value;
|
|
||||||
BinaryNode* left;
|
|
||||||
BinaryNode* right;
|
|
||||||
BinaryNode* parent;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename Tp>
|
|
||||||
class ExplicitNodeIterator {
|
|
||||||
public:
|
|
||||||
typedef ExplicitNodeIterator<Tp> _Self;
|
|
||||||
typedef BinaryNode<Tp> _Node;
|
|
||||||
typedef Tp value_type;
|
|
||||||
typedef Tp* pointer;
|
|
||||||
typedef Tp& reference;
|
|
||||||
ExplicitNodeIterator() :
|
|
||||||
element(NULL) {
|
|
||||||
}
|
|
||||||
ExplicitNodeIterator(_Node* node) :
|
|
||||||
element(node) {
|
|
||||||
}
|
|
||||||
BinaryNode<Tp>* element;
|
|
||||||
_Self up() {
|
|
||||||
return _Self(element->parent);
|
|
||||||
}
|
|
||||||
_Self left() {
|
|
||||||
if (element != NULL) {
|
|
||||||
return _Self(element->left);
|
|
||||||
} else {
|
|
||||||
return _Self(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
_Self right() {
|
|
||||||
if (element != NULL) {
|
|
||||||
return _Self(element->right);
|
|
||||||
} else {
|
|
||||||
return _Self(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
bool operator==(const _Self& __x) const {
|
|
||||||
return element == __x.element;
|
|
||||||
}
|
|
||||||
bool operator!=(const _Self& __x) const {
|
|
||||||
return element != __x.element;
|
|
||||||
}
|
|
||||||
pointer
|
|
||||||
operator->() const {
|
|
||||||
if (element != NULL) {
|
|
||||||
return element->value;
|
|
||||||
} else {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pointer operator*() const {
|
|
||||||
return this->operator->();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pretty rudimentary version of a simple binary tree (not a binary search tree!).
|
|
||||||
*/
|
|
||||||
template<typename Tp>
|
|
||||||
class BinaryTree {
|
|
||||||
public:
|
|
||||||
typedef ExplicitNodeIterator<Tp> iterator;
|
|
||||||
typedef BinaryNode<Tp> Node;
|
|
||||||
typedef std::pair<iterator, iterator> children;
|
|
||||||
BinaryTree() :
|
|
||||||
rootNode(NULL) {
|
|
||||||
}
|
|
||||||
BinaryTree(Node* rootNode) :
|
|
||||||
rootNode(rootNode) {
|
|
||||||
}
|
|
||||||
iterator begin() const {
|
|
||||||
return iterator(rootNode);
|
|
||||||
}
|
|
||||||
static iterator end() {
|
|
||||||
return iterator(NULL);
|
|
||||||
}
|
|
||||||
iterator insert(bool insertLeft, iterator parentNode, Node* newNode ) {
|
|
||||||
newNode->parent = parentNode.element;
|
|
||||||
if (parentNode.element != NULL) {
|
|
||||||
if (insertLeft) {
|
|
||||||
parentNode.element->left = newNode;
|
|
||||||
} else {
|
|
||||||
parentNode.element->right = newNode;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//Insert first element.
|
|
||||||
rootNode = newNode;
|
|
||||||
}
|
|
||||||
return iterator(newNode);
|
|
||||||
}
|
|
||||||
//No recursion to children. Needs to be done externally.
|
|
||||||
children erase(iterator node) {
|
|
||||||
if (node.element == rootNode) {
|
|
||||||
//We're root node
|
|
||||||
rootNode = NULL;
|
|
||||||
} else {
|
|
||||||
//Delete parent's reference
|
|
||||||
if (node.up().left() == node) {
|
|
||||||
node.up().element->left = NULL;
|
|
||||||
} else {
|
|
||||||
node.up().element->right = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return children(node.element->left, node.element->right);
|
|
||||||
}
|
|
||||||
static uint32_t countLeft(iterator start) {
|
|
||||||
if (start == end()) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
//We also count the start node itself.
|
|
||||||
uint32_t count = 1;
|
|
||||||
while (start.left() != end()) {
|
|
||||||
count++;
|
|
||||||
start = start.left();
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
static uint32_t countRight(iterator start) {
|
|
||||||
if (start == end()) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
//We also count the start node itself.
|
|
||||||
uint32_t count = 1;
|
|
||||||
while (start.right() != end()) {
|
|
||||||
count++;
|
|
||||||
start = start.right();
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
Node* rootNode;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* FRAMEWORK_CONTAINER_BINARYTREE_H_ */
|
|
@ -1,5 +0,0 @@
|
|||||||
target_sources(${LIB_FSFW_NAME}
|
|
||||||
PRIVATE
|
|
||||||
SharedRingBuffer.cpp
|
|
||||||
SimpleRingBuffer.cpp
|
|
||||||
)
|
|
@ -1,55 +0,0 @@
|
|||||||
#ifndef FSFW_CONTAINER_DYNAMICFIFO_H_
|
|
||||||
#define FSFW_CONTAINER_DYNAMICFIFO_H_
|
|
||||||
|
|
||||||
#include "FIFOBase.h"
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Simple First-In-First-Out data structure. The maximum size
|
|
||||||
* can be set in the constructor.
|
|
||||||
* @details
|
|
||||||
* The maximum capacity can be determined at run-time, so this container
|
|
||||||
* performs dynamic memory allocation!
|
|
||||||
* The public interface of FIFOBase exposes the user interface for the FIFO.
|
|
||||||
* @tparam T Entry Type
|
|
||||||
* @tparam capacity Maximum capacity
|
|
||||||
*/
|
|
||||||
template<typename T>
|
|
||||||
class DynamicFIFO: public FIFOBase<T> {
|
|
||||||
public:
|
|
||||||
DynamicFIFO(size_t maxCapacity): FIFOBase<T>(nullptr, maxCapacity),
|
|
||||||
fifoVector(maxCapacity) {
|
|
||||||
// trying to pass the pointer of the uninitialized vector
|
|
||||||
// to the FIFOBase constructor directly lead to a super evil bug.
|
|
||||||
// So we do it like this now.
|
|
||||||
this->setContainer(fifoVector.data());
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Custom copy constructor which prevents setting the
|
|
||||||
* underlying pointer wrong. This function allocates memory!
|
|
||||||
* @details This is a very heavy operation so try to avoid this!
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
DynamicFIFO(const DynamicFIFO& other): FIFOBase<T>(other),
|
|
||||||
fifoVector(other.maxCapacity) {
|
|
||||||
this->fifoVector = other.fifoVector;
|
|
||||||
this->setContainer(fifoVector.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Custom assignment operator
|
|
||||||
* @details This is a very heavy operation so try to avoid this!
|
|
||||||
* @param other DyamicFIFO to copy from
|
|
||||||
*/
|
|
||||||
DynamicFIFO& operator=(const DynamicFIFO& other){
|
|
||||||
FIFOBase<T>::operator=(other);
|
|
||||||
this->fifoVector = other.fifoVector;
|
|
||||||
this->setContainer(fifoVector.data());
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
std::vector<T> fifoVector;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* FSFW_CONTAINER_DYNAMICFIFO_H_ */
|
|
@ -1,47 +0,0 @@
|
|||||||
#ifndef FSFW_CONTAINER_FIFO_H_
|
|
||||||
#define FSFW_CONTAINER_FIFO_H_
|
|
||||||
|
|
||||||
#include "FIFOBase.h"
|
|
||||||
#include <array>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Simple First-In-First-Out data structure with size fixed at
|
|
||||||
* compile time
|
|
||||||
* @details
|
|
||||||
* Performs no dynamic memory allocation.
|
|
||||||
* The public interface of FIFOBase exposes the user interface for the FIFO.
|
|
||||||
* @tparam T Entry Type
|
|
||||||
* @tparam capacity Maximum capacity
|
|
||||||
*/
|
|
||||||
template<typename T, size_t capacity>
|
|
||||||
class FIFO: public FIFOBase<T> {
|
|
||||||
public:
|
|
||||||
FIFO(): FIFOBase<T>(nullptr, capacity) {
|
|
||||||
this->setContainer(fifoArray.data());
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Custom copy constructor to set pointer correctly.
|
|
||||||
* @param other
|
|
||||||
*/
|
|
||||||
FIFO(const FIFO& other): FIFOBase<T>(other) {
|
|
||||||
this->fifoArray = other.fifoArray;
|
|
||||||
this->setContainer(fifoArray.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Custom assignment operator
|
|
||||||
* @param other
|
|
||||||
*/
|
|
||||||
FIFO& operator=(const FIFO& other){
|
|
||||||
FIFOBase<T>::operator=(other);
|
|
||||||
this->fifoArray = other.fifoArray;
|
|
||||||
this->setContainer(fifoArray.data());
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::array<T, capacity> fifoArray;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* FSFW_CONTAINER_FIFO_H_ */
|
|
@ -1,79 +0,0 @@
|
|||||||
#ifndef FSFW_CONTAINER_FIFOBASE_H_
|
|
||||||
#define FSFW_CONTAINER_FIFOBASE_H_
|
|
||||||
|
|
||||||
#include "../returnvalues/HasReturnvaluesIF.h"
|
|
||||||
#include <cstddef>
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
class FIFOBase {
|
|
||||||
public:
|
|
||||||
static const uint8_t INTERFACE_ID = CLASS_ID::FIFO_CLASS;
|
|
||||||
static const ReturnValue_t FULL = MAKE_RETURN_CODE(1);
|
|
||||||
static const ReturnValue_t EMPTY = MAKE_RETURN_CODE(2);
|
|
||||||
|
|
||||||
/** Default ctor, takes pointer to first entry of underlying container
|
|
||||||
* and maximum capacity */
|
|
||||||
FIFOBase(T* values, const size_t maxCapacity);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Insert value into FIFO
|
|
||||||
* @param value
|
|
||||||
* @return RETURN_OK on success, FULL if full
|
|
||||||
*/
|
|
||||||
ReturnValue_t insert(T value);
|
|
||||||
/**
|
|
||||||
* Retrieve item from FIFO. This removes the item from the FIFO.
|
|
||||||
* @param value Must point to a valid T
|
|
||||||
* @return RETURN_OK on success, EMPTY if empty and FAILED if nullptr check failed
|
|
||||||
*/
|
|
||||||
ReturnValue_t retrieve(T *value);
|
|
||||||
/**
|
|
||||||
* Retrieve item from FIFO without removing it from FIFO.
|
|
||||||
* @param value Must point to a valid T
|
|
||||||
* @return RETURN_OK on success, EMPTY if empty and FAILED if nullptr check failed
|
|
||||||
*/
|
|
||||||
ReturnValue_t peek(T * value);
|
|
||||||
/**
|
|
||||||
* Remove item from FIFO.
|
|
||||||
* @return RETURN_OK on success, EMPTY if empty
|
|
||||||
*/
|
|
||||||
ReturnValue_t pop();
|
|
||||||
|
|
||||||
/***
|
|
||||||
* Check if FIFO is empty
|
|
||||||
* @return True if empty, False if not
|
|
||||||
*/
|
|
||||||
bool empty();
|
|
||||||
/***
|
|
||||||
* Check if FIFO is Full
|
|
||||||
* @return True if full, False if not
|
|
||||||
*/
|
|
||||||
bool full();
|
|
||||||
/***
|
|
||||||
* Current used size (elements) used
|
|
||||||
* @return size_t in elements
|
|
||||||
*/
|
|
||||||
size_t size();
|
|
||||||
/***
|
|
||||||
* Get maximal capacity of fifo
|
|
||||||
* @return size_t with max capacity of this fifo
|
|
||||||
*/
|
|
||||||
size_t getMaxCapacity() const;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void setContainer(T* data);
|
|
||||||
size_t maxCapacity = 0;
|
|
||||||
|
|
||||||
T* values;
|
|
||||||
|
|
||||||
size_t readIndex = 0;
|
|
||||||
size_t writeIndex = 0;
|
|
||||||
size_t currentSize = 0;
|
|
||||||
|
|
||||||
size_t next(size_t current);
|
|
||||||
};
|
|
||||||
|
|
||||||
#include "FIFOBase.tpp"
|
|
||||||
|
|
||||||
#endif /* FSFW_CONTAINER_FIFOBASE_H_ */
|
|
@ -1,93 +0,0 @@
|
|||||||
#ifndef FSFW_CONTAINER_FIFOBASE_TPP_
|
|
||||||
#define FSFW_CONTAINER_FIFOBASE_TPP_
|
|
||||||
|
|
||||||
#ifndef FSFW_CONTAINER_FIFOBASE_H_
|
|
||||||
#error Include FIFOBase.h before FIFOBase.tpp!
|
|
||||||
#endif
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline FIFOBase<T>::FIFOBase(T* values, const size_t maxCapacity):
|
|
||||||
maxCapacity(maxCapacity), values(values){};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline ReturnValue_t FIFOBase<T>::insert(T value) {
|
|
||||||
if (full()) {
|
|
||||||
return FULL;
|
|
||||||
} else {
|
|
||||||
values[writeIndex] = value;
|
|
||||||
writeIndex = next(writeIndex);
|
|
||||||
++currentSize;
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline ReturnValue_t FIFOBase<T>::retrieve(T* value) {
|
|
||||||
if (empty()) {
|
|
||||||
return EMPTY;
|
|
||||||
} else {
|
|
||||||
if (value == nullptr){
|
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
|
||||||
}
|
|
||||||
*value = values[readIndex];
|
|
||||||
readIndex = next(readIndex);
|
|
||||||
--currentSize;
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline ReturnValue_t FIFOBase<T>::peek(T* value) {
|
|
||||||
if(empty()) {
|
|
||||||
return EMPTY;
|
|
||||||
} else {
|
|
||||||
if (value == nullptr){
|
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
|
||||||
}
|
|
||||||
*value = values[readIndex];
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline ReturnValue_t FIFOBase<T>::pop() {
|
|
||||||
T value;
|
|
||||||
return this->retrieve(&value);
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline bool FIFOBase<T>::empty() {
|
|
||||||
return (currentSize == 0);
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline bool FIFOBase<T>::full() {
|
|
||||||
return (currentSize == maxCapacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline size_t FIFOBase<T>::size() {
|
|
||||||
return currentSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline size_t FIFOBase<T>::next(size_t current) {
|
|
||||||
++current;
|
|
||||||
if (current == maxCapacity) {
|
|
||||||
current = 0;
|
|
||||||
}
|
|
||||||
return current;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline size_t FIFOBase<T>::getMaxCapacity() const {
|
|
||||||
return maxCapacity;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline void FIFOBase<T>::setContainer(T *data) {
|
|
||||||
this->values = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,40 +0,0 @@
|
|||||||
#ifndef FIXEDARRAYLIST_H_
|
|
||||||
#define FIXEDARRAYLIST_H_
|
|
||||||
|
|
||||||
#include "ArrayList.h"
|
|
||||||
#include <cmath>
|
|
||||||
/**
|
|
||||||
* \ingroup container
|
|
||||||
*/
|
|
||||||
template<typename T, size_t MAX_SIZE, typename count_t = uint8_t>
|
|
||||||
class FixedArrayList: public ArrayList<T, count_t> {
|
|
||||||
#if !defined(_MSC_VER)
|
|
||||||
static_assert(MAX_SIZE <= (std::pow(2,sizeof(count_t)*8)-1), "count_t is not large enough to hold MAX_SIZE");
|
|
||||||
#endif
|
|
||||||
private:
|
|
||||||
T data[MAX_SIZE];
|
|
||||||
public:
|
|
||||||
FixedArrayList() :
|
|
||||||
ArrayList<T, count_t>(data, MAX_SIZE) {
|
|
||||||
}
|
|
||||||
|
|
||||||
FixedArrayList(const FixedArrayList& other) :
|
|
||||||
ArrayList<T, count_t>(data, MAX_SIZE) {
|
|
||||||
memcpy(this->data, other.data, sizeof(this->data));
|
|
||||||
this->entries = data;
|
|
||||||
this->size = other.size;
|
|
||||||
}
|
|
||||||
|
|
||||||
FixedArrayList& operator=(FixedArrayList other) {
|
|
||||||
memcpy(this->data, other.data, sizeof(this->data));
|
|
||||||
this->entries = data;
|
|
||||||
this->size = other.size;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~FixedArrayList() {
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* FIXEDARRAYLIST_H_ */
|
|
@ -1,230 +0,0 @@
|
|||||||
#ifndef FSFW_CONTAINER_FIXEDMAP_H_
|
|
||||||
#define FSFW_CONTAINER_FIXEDMAP_H_
|
|
||||||
|
|
||||||
#include "ArrayList.h"
|
|
||||||
#include "../returnvalues/HasReturnvaluesIF.h"
|
|
||||||
#include <utility>
|
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Map implementation for maps with a pre-defined size.
|
|
||||||
* @details
|
|
||||||
* Can be initialized with desired maximum size.
|
|
||||||
* Iterator is used to access <key,value> pair and iterate through map entries.
|
|
||||||
* Complexity O(n).
|
|
||||||
* @warning Iterators return a non-const key_t in the pair.
|
|
||||||
* @warning A User is not allowed to change the key, otherwise the map is corrupted.
|
|
||||||
* @ingroup container
|
|
||||||
*/
|
|
||||||
template<typename key_t, typename T>
|
|
||||||
class FixedMap: public SerializeIF {
|
|
||||||
static_assert (std::is_trivially_copyable<T>::value or
|
|
||||||
std::is_base_of<SerializeIF, T>::value,
|
|
||||||
"Types used in FixedMap must either be trivial copy-able or a "
|
|
||||||
"derived class from SerializeIF to be serialize-able");
|
|
||||||
public:
|
|
||||||
static const uint8_t INTERFACE_ID = CLASS_ID::FIXED_MAP;
|
|
||||||
static const ReturnValue_t KEY_ALREADY_EXISTS = MAKE_RETURN_CODE(0x01);
|
|
||||||
static const ReturnValue_t MAP_FULL = MAKE_RETURN_CODE(0x02);
|
|
||||||
static const ReturnValue_t KEY_DOES_NOT_EXIST = MAKE_RETURN_CODE(0x03);
|
|
||||||
|
|
||||||
private:
|
|
||||||
static const key_t EMPTY_SLOT = -1;
|
|
||||||
ArrayList<std::pair<key_t, T>, uint32_t> theMap;
|
|
||||||
uint32_t _size;
|
|
||||||
|
|
||||||
uint32_t findIndex(key_t key) const {
|
|
||||||
if (_size == 0) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
uint32_t i = 0;
|
|
||||||
for (i = 0; i < _size; ++i) {
|
|
||||||
if (theMap[i].first == key) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
public:
|
|
||||||
FixedMap(uint32_t maxSize) :
|
|
||||||
theMap(maxSize), _size(0) {
|
|
||||||
}
|
|
||||||
|
|
||||||
class Iterator: public ArrayList<std::pair<key_t, T>, uint32_t>::Iterator {
|
|
||||||
public:
|
|
||||||
Iterator() :
|
|
||||||
ArrayList<std::pair<key_t, T>, uint32_t>::Iterator() {
|
|
||||||
}
|
|
||||||
|
|
||||||
Iterator(std::pair<key_t, T> *pair) :
|
|
||||||
ArrayList<std::pair<key_t, T>, uint32_t>::Iterator(pair) {
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
friend bool operator==(const typename FixedMap::Iterator& lhs,
|
|
||||||
const typename FixedMap::Iterator& rhs) {
|
|
||||||
return (lhs.value == rhs.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
friend bool operator!=(const typename FixedMap::Iterator& lhs,
|
|
||||||
const typename FixedMap::Iterator& rhs) {
|
|
||||||
return not (lhs.value == rhs.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
Iterator begin() const {
|
|
||||||
return Iterator(&theMap[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
Iterator end() const {
|
|
||||||
return Iterator(&theMap[_size]);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t size() const {
|
|
||||||
return _size;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t insert(key_t key, T value, Iterator *storedValue = nullptr) {
|
|
||||||
if (exists(key) == HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
return KEY_ALREADY_EXISTS;
|
|
||||||
}
|
|
||||||
if (_size == theMap.maxSize()) {
|
|
||||||
return MAP_FULL;
|
|
||||||
}
|
|
||||||
theMap[_size].first = key;
|
|
||||||
theMap[_size].second = value;
|
|
||||||
if (storedValue != nullptr) {
|
|
||||||
*storedValue = Iterator(&theMap[_size]);
|
|
||||||
}
|
|
||||||
++_size;
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t insert(std::pair<key_t, T> pair) {
|
|
||||||
return insert(pair.first, pair.second);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t exists(key_t key) const {
|
|
||||||
ReturnValue_t result = KEY_DOES_NOT_EXIST;
|
|
||||||
if (findIndex(key) < _size) {
|
|
||||||
result = HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t erase(Iterator *iter) {
|
|
||||||
uint32_t i;
|
|
||||||
if ((i = findIndex((*iter).value->first)) >= _size) {
|
|
||||||
return KEY_DOES_NOT_EXIST;
|
|
||||||
}
|
|
||||||
theMap[i] = theMap[_size - 1];
|
|
||||||
--_size;
|
|
||||||
--((*iter).value);
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t erase(key_t key) {
|
|
||||||
uint32_t i;
|
|
||||||
if ((i = findIndex(key)) >= _size) {
|
|
||||||
return KEY_DOES_NOT_EXIST;
|
|
||||||
}
|
|
||||||
theMap[i] = theMap[_size - 1];
|
|
||||||
--_size;
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
T *findValue(key_t key) const {
|
|
||||||
return &theMap[findIndex(key)].second;
|
|
||||||
}
|
|
||||||
|
|
||||||
Iterator find(key_t key) const {
|
|
||||||
ReturnValue_t result = exists(key);
|
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
return end();
|
|
||||||
}
|
|
||||||
return Iterator(&theMap[findIndex(key)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t find(key_t key, T **value) const {
|
|
||||||
ReturnValue_t result = exists(key);
|
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
*value = &theMap[findIndex(key)].second;
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool empty() {
|
|
||||||
if(_size == 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool full() {
|
|
||||||
if(_size >= theMap.maxSize()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear() {
|
|
||||||
_size = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t maxSize() const {
|
|
||||||
return theMap.maxSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size,
|
|
||||||
size_t maxSize, Endianness streamEndianness) const {
|
|
||||||
ReturnValue_t result = SerializeAdapter::serialize(&this->_size,
|
|
||||||
buffer, size, maxSize, streamEndianness);
|
|
||||||
uint32_t i = 0;
|
|
||||||
while ((result == HasReturnvaluesIF::RETURN_OK) && (i < this->_size)) {
|
|
||||||
result = SerializeAdapter::serialize(&theMap[i].first, buffer,
|
|
||||||
size, maxSize, streamEndianness);
|
|
||||||
result = SerializeAdapter::serialize(&theMap[i].second, buffer, size,
|
|
||||||
maxSize, streamEndianness);
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual size_t getSerializedSize() const {
|
|
||||||
uint32_t printSize = sizeof(_size);
|
|
||||||
uint32_t i = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < _size; ++i) {
|
|
||||||
printSize += SerializeAdapter::getSerializedSize(
|
|
||||||
&theMap[i].first);
|
|
||||||
printSize += SerializeAdapter::getSerializedSize(&theMap[i].second);
|
|
||||||
}
|
|
||||||
|
|
||||||
return printSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
|
||||||
Endianness streamEndianness) {
|
|
||||||
ReturnValue_t result = SerializeAdapter::deSerialize(&this->_size,
|
|
||||||
buffer, size, streamEndianness);
|
|
||||||
if (this->_size > theMap.maxSize()) {
|
|
||||||
return SerializeIF::TOO_MANY_ELEMENTS;
|
|
||||||
}
|
|
||||||
uint32_t i = 0;
|
|
||||||
while ((result == HasReturnvaluesIF::RETURN_OK) && (i < this->_size)) {
|
|
||||||
result = SerializeAdapter::deSerialize(&theMap[i].first, buffer,
|
|
||||||
size, streamEndianness);
|
|
||||||
result = SerializeAdapter::deSerialize(&theMap[i].second, buffer, size,
|
|
||||||
streamEndianness);
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* FSFW_CONTAINER_FIXEDMAP_H_ */
|
|
@ -1,207 +0,0 @@
|
|||||||
#ifndef FSFW_CONTAINER_FIXEDORDEREDMULTIMAP_H_
|
|
||||||
#define FSFW_CONTAINER_FIXEDORDEREDMULTIMAP_H_
|
|
||||||
|
|
||||||
#include "ArrayList.h"
|
|
||||||
#include <cstring>
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief An associative container which allows multiple entries of the same key.
|
|
||||||
* @details
|
|
||||||
* Same keys are ordered by KEY_COMPARE function which is std::less<key_t> > by default.
|
|
||||||
*
|
|
||||||
* It uses the ArrayList, so technically this is not a real map, it is an array of pairs
|
|
||||||
* of type key_t, T. It is ordered by key_t as FixedMap but allows same keys. Thus it has a linear
|
|
||||||
* complexity O(n). As long as the number of entries remains low, this
|
|
||||||
* should not be an issue.
|
|
||||||
* The number of insertion and deletion operation should be minimized
|
|
||||||
* as those incur extensive memory move operations (the underlying container
|
|
||||||
* is not node based).
|
|
||||||
*
|
|
||||||
* Its of fixed size so no allocations are performed after the construction.
|
|
||||||
*
|
|
||||||
* The maximum size is given as first parameter of the constructor.
|
|
||||||
*
|
|
||||||
* It provides an iterator to do list iterations.
|
|
||||||
*
|
|
||||||
* The type T must have a copy constructor if it is not trivial copy-able.
|
|
||||||
*
|
|
||||||
* @warning Iterators return a non-const key_t in the pair.
|
|
||||||
* @warning A User is not allowed to change the key, otherwise the map is corrupted.
|
|
||||||
*
|
|
||||||
* \ingroup container
|
|
||||||
*/
|
|
||||||
template<typename key_t, typename T, typename KEY_COMPARE = std::less<key_t>>
|
|
||||||
class FixedOrderedMultimap {
|
|
||||||
public:
|
|
||||||
static const uint8_t INTERFACE_ID = CLASS_ID::FIXED_MULTIMAP;
|
|
||||||
static const ReturnValue_t MAP_FULL = MAKE_RETURN_CODE(0x01);
|
|
||||||
static const ReturnValue_t KEY_DOES_NOT_EXIST = MAKE_RETURN_CODE(0x02);
|
|
||||||
|
|
||||||
/***
|
|
||||||
* Constructor which needs a size_t for the maximum allowed size
|
|
||||||
*
|
|
||||||
* Can not be resized during runtime
|
|
||||||
*
|
|
||||||
* Allocates memory at construction
|
|
||||||
* @param maxSize size_t of Maximum allowed size
|
|
||||||
*/
|
|
||||||
FixedOrderedMultimap(size_t maxSize):theMap(maxSize), _size(0){
|
|
||||||
}
|
|
||||||
|
|
||||||
/***
|
|
||||||
* Virtual destructor frees Memory by deleting its member
|
|
||||||
*/
|
|
||||||
virtual ~FixedOrderedMultimap() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/***
|
|
||||||
* Special iterator for FixedOrderedMultimap
|
|
||||||
*/
|
|
||||||
class Iterator: public ArrayList<std::pair<key_t, T>, size_t>::Iterator {
|
|
||||||
public:
|
|
||||||
Iterator() :
|
|
||||||
ArrayList<std::pair<key_t, T>, size_t>::Iterator() {
|
|
||||||
}
|
|
||||||
|
|
||||||
Iterator(std::pair<key_t, T> *pair) :
|
|
||||||
ArrayList<std::pair<key_t, T>, size_t>::Iterator(pair) {
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/***
|
|
||||||
* Returns an iterator pointing to the first element
|
|
||||||
* @return Iterator pointing to first element
|
|
||||||
*/
|
|
||||||
Iterator begin() const {
|
|
||||||
return Iterator(&theMap[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an iterator pointing to one element past the end
|
|
||||||
* @return Iterator pointing to one element past the end
|
|
||||||
*/
|
|
||||||
Iterator end() const {
|
|
||||||
return Iterator(&theMap[_size]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/***
|
|
||||||
* Returns the current size of the map (not maximum size!)
|
|
||||||
* @return Current size
|
|
||||||
*/
|
|
||||||
size_t size() const{
|
|
||||||
return _size;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears the map, does not deallocate any memory
|
|
||||||
*/
|
|
||||||
void clear(){
|
|
||||||
_size = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the maximum size of the map
|
|
||||||
* @return Maximum size of the map
|
|
||||||
*/
|
|
||||||
size_t maxSize() const{
|
|
||||||
return theMap.maxSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
/***
|
|
||||||
* Used to insert a key and value separately.
|
|
||||||
*
|
|
||||||
* @param[in] key Key of the new element
|
|
||||||
* @param[in] value Value of the new element
|
|
||||||
* @param[in/out] (optional) storedValue On success this points to the new value, otherwise a nullptr
|
|
||||||
* @return RETURN_OK if insert was successful, MAP_FULL if no space is available
|
|
||||||
*/
|
|
||||||
ReturnValue_t insert(key_t key, T value, Iterator *storedValue = nullptr);
|
|
||||||
|
|
||||||
/***
|
|
||||||
* Used to insert new pair instead of single values
|
|
||||||
*
|
|
||||||
* @param pair Pair to be inserted
|
|
||||||
* @return RETURN_OK if insert was successful, MAP_FULL if no space is available
|
|
||||||
*/
|
|
||||||
ReturnValue_t insert(std::pair<key_t, T> pair);
|
|
||||||
|
|
||||||
/***
|
|
||||||
* Can be used to check if a certain key is in the map
|
|
||||||
* @param key Key to be checked
|
|
||||||
* @return RETURN_OK if the key exists KEY_DOES_NOT_EXIST otherwise
|
|
||||||
*/
|
|
||||||
ReturnValue_t exists(key_t key) const;
|
|
||||||
|
|
||||||
/***
|
|
||||||
* Used to delete the element in the iterator
|
|
||||||
*
|
|
||||||
* The iterator will point to the element before or begin(),
|
|
||||||
* but never to one element in front of the map.
|
|
||||||
*
|
|
||||||
* @warning The iterator needs to be valid and dereferenceable
|
|
||||||
* @param[in/out] iter Pointer to iterator to the element that needs to be ereased
|
|
||||||
* @return RETURN_OK if erased, KEY_DOES_NOT_EXIST if the there is no element like this
|
|
||||||
*/
|
|
||||||
ReturnValue_t erase(Iterator *iter);
|
|
||||||
|
|
||||||
/***
|
|
||||||
* Used to erase by key
|
|
||||||
* @param key Key to be erased
|
|
||||||
* @return RETURN_OK if erased, KEY_DOES_NOT_EXIST if the there is no element like this
|
|
||||||
*/
|
|
||||||
ReturnValue_t erase(key_t key);
|
|
||||||
|
|
||||||
/***
|
|
||||||
* Find returns the first appearance of the key
|
|
||||||
*
|
|
||||||
* If the key does not exist, it points to end()
|
|
||||||
*
|
|
||||||
* @param key Key to search for
|
|
||||||
* @return Iterator pointing to the first entry of key
|
|
||||||
*/
|
|
||||||
Iterator find(key_t key) const{
|
|
||||||
ReturnValue_t result = exists(key);
|
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
return end();
|
|
||||||
}
|
|
||||||
return Iterator(&theMap[findFirstIndex(key)]);
|
|
||||||
};
|
|
||||||
|
|
||||||
/***
|
|
||||||
* Finds first entry of the given key and returns a
|
|
||||||
* pointer to the value
|
|
||||||
*
|
|
||||||
* @param key Key to search for
|
|
||||||
* @param value Found value
|
|
||||||
* @return RETURN_OK if it points to the value,
|
|
||||||
* KEY_DOES_NOT_EXIST if the key is not in the map
|
|
||||||
*/
|
|
||||||
ReturnValue_t find(key_t key, T **value) const;
|
|
||||||
|
|
||||||
friend bool operator==(const typename FixedOrderedMultimap::Iterator& lhs,
|
|
||||||
const typename FixedOrderedMultimap::Iterator& rhs) {
|
|
||||||
return (lhs.value == rhs.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
friend bool operator!=(const typename FixedOrderedMultimap::Iterator& lhs,
|
|
||||||
const typename FixedOrderedMultimap::Iterator& rhs) {
|
|
||||||
return not (lhs.value == rhs.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
typedef KEY_COMPARE compare;
|
|
||||||
compare myComp;
|
|
||||||
ArrayList<std::pair<key_t, T>, size_t> theMap;
|
|
||||||
size_t _size;
|
|
||||||
|
|
||||||
size_t findFirstIndex(key_t key, size_t startAt = 0) const;
|
|
||||||
|
|
||||||
size_t findNicePlace(key_t key) const;
|
|
||||||
|
|
||||||
void removeFromPosition(size_t position);
|
|
||||||
};
|
|
||||||
|
|
||||||
#include "FixedOrderedMultimap.tpp"
|
|
||||||
|
|
||||||
#endif /* FSFW_CONTAINER_FIXEDORDEREDMULTIMAP_H_ */
|
|
@ -1,109 +0,0 @@
|
|||||||
#ifndef FRAMEWORK_CONTAINER_FIXEDORDEREDMULTIMAP_TPP_
|
|
||||||
#define FRAMEWORK_CONTAINER_FIXEDORDEREDMULTIMAP_TPP_
|
|
||||||
|
|
||||||
|
|
||||||
template<typename key_t, typename T, typename KEY_COMPARE>
|
|
||||||
inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::insert(key_t key, T value, Iterator *storedValue) {
|
|
||||||
if (_size == theMap.maxSize()) {
|
|
||||||
return MAP_FULL;
|
|
||||||
}
|
|
||||||
size_t position = findNicePlace(key);
|
|
||||||
memmove(static_cast<void*>(&theMap[position + 1]),static_cast<void*>(&theMap[position]),
|
|
||||||
(_size - position) * sizeof(std::pair<key_t,T>));
|
|
||||||
theMap[position].first = key;
|
|
||||||
theMap[position].second = value;
|
|
||||||
++_size;
|
|
||||||
if (storedValue != nullptr) {
|
|
||||||
*storedValue = Iterator(&theMap[position]);
|
|
||||||
}
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
template<typename key_t, typename T, typename KEY_COMPARE>
|
|
||||||
inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::insert(std::pair<key_t, T> pair) {
|
|
||||||
return insert(pair.first, pair.second);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename key_t, typename T, typename KEY_COMPARE>
|
|
||||||
inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::exists(key_t key) const {
|
|
||||||
ReturnValue_t result = KEY_DOES_NOT_EXIST;
|
|
||||||
if (findFirstIndex(key) < _size) {
|
|
||||||
result = HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename key_t, typename T, typename KEY_COMPARE>
|
|
||||||
inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::erase(Iterator *iter) {
|
|
||||||
size_t i;
|
|
||||||
if ((i = findFirstIndex((*iter).value->first)) >= _size) {
|
|
||||||
return KEY_DOES_NOT_EXIST;
|
|
||||||
}
|
|
||||||
removeFromPosition(i);
|
|
||||||
if (*iter != begin()) {
|
|
||||||
(*iter)--;
|
|
||||||
} else {
|
|
||||||
*iter = begin();
|
|
||||||
}
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename key_t, typename T, typename KEY_COMPARE>
|
|
||||||
inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::erase(key_t key) {
|
|
||||||
size_t i;
|
|
||||||
if ((i = findFirstIndex(key)) >= _size) {
|
|
||||||
return KEY_DOES_NOT_EXIST;
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
removeFromPosition(i);
|
|
||||||
i = findFirstIndex(key, i);
|
|
||||||
} while (i < _size);
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename key_t, typename T, typename KEY_COMPARE>
|
|
||||||
inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::find(key_t key, T **value) const {
|
|
||||||
ReturnValue_t result = exists(key);
|
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
*value = &theMap[findFirstIndex(key)].second;
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename key_t, typename T, typename KEY_COMPARE>
|
|
||||||
inline size_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::findFirstIndex(key_t key, size_t startAt) const {
|
|
||||||
if (startAt >= _size) {
|
|
||||||
return startAt + 1;
|
|
||||||
}
|
|
||||||
size_t i = startAt;
|
|
||||||
for (i = startAt; i < _size; ++i) {
|
|
||||||
if (theMap[i].first == key) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename key_t, typename T, typename KEY_COMPARE>
|
|
||||||
inline size_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::findNicePlace(key_t key) const {
|
|
||||||
size_t i = 0;
|
|
||||||
for (i = 0; i < _size; ++i) {
|
|
||||||
if (myComp(key, theMap[i].first)) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename key_t, typename T, typename KEY_COMPARE>
|
|
||||||
inline void FixedOrderedMultimap<key_t, T, KEY_COMPARE>::removeFromPosition(size_t position) {
|
|
||||||
if (_size <= position) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
memmove(static_cast<void*>(&theMap[position]), static_cast<void*>(&theMap[position + 1]),
|
|
||||||
(_size - position - 1) * sizeof(std::pair<key_t,T>));
|
|
||||||
--_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* FRAMEWORK_CONTAINER_FIXEDORDEREDMULTIMAP_TPP_ */
|
|
@ -1,90 +0,0 @@
|
|||||||
#ifndef FRAMEWORK_CONTAINER_HYBRIDITERATOR_H_
|
|
||||||
#define FRAMEWORK_CONTAINER_HYBRIDITERATOR_H_
|
|
||||||
|
|
||||||
#include "ArrayList.h"
|
|
||||||
#include "SinglyLinkedList.h"
|
|
||||||
|
|
||||||
template<typename T, typename count_t = uint8_t>
|
|
||||||
class HybridIterator: public LinkedElement<T>::Iterator,
|
|
||||||
public ArrayList<T, count_t>::Iterator {
|
|
||||||
public:
|
|
||||||
HybridIterator() {}
|
|
||||||
|
|
||||||
HybridIterator(typename LinkedElement<T>::Iterator *iter) :
|
|
||||||
LinkedElement<T>::Iterator(*iter), value(iter->value),
|
|
||||||
linked(true) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
HybridIterator(LinkedElement<T> *start) :
|
|
||||||
LinkedElement<T>::Iterator(start), value(start->value),
|
|
||||||
linked(true) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
HybridIterator(typename ArrayList<T, count_t>::Iterator start,
|
|
||||||
typename ArrayList<T, count_t>::Iterator end) :
|
|
||||||
ArrayList<T, count_t>::Iterator(start), value(start.value),
|
|
||||||
linked(false), end(end.value) {
|
|
||||||
if (value == this->end) {
|
|
||||||
value = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HybridIterator(T *firstElement, T *lastElement) :
|
|
||||||
ArrayList<T, count_t>::Iterator(firstElement), value(firstElement),
|
|
||||||
linked(false), end(++lastElement) {
|
|
||||||
if (value == end) {
|
|
||||||
value = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HybridIterator& operator++() {
|
|
||||||
if (linked) {
|
|
||||||
LinkedElement<T>::Iterator::operator++();
|
|
||||||
if (LinkedElement<T>::Iterator::value != nullptr) {
|
|
||||||
value = LinkedElement<T>::Iterator::value->value;
|
|
||||||
} else {
|
|
||||||
value = nullptr;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ArrayList<T, count_t>::Iterator::operator++();
|
|
||||||
value = ArrayList<T, count_t>::Iterator::value;
|
|
||||||
|
|
||||||
if (value == end) {
|
|
||||||
value = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
HybridIterator operator++(int) {
|
|
||||||
HybridIterator tmp(*this);
|
|
||||||
operator++();
|
|
||||||
return tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator==(const HybridIterator& other) const {
|
|
||||||
return value == other.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator!=(const HybridIterator& other) const {
|
|
||||||
return !(*this == other);
|
|
||||||
}
|
|
||||||
|
|
||||||
T operator*() {
|
|
||||||
return *value;
|
|
||||||
}
|
|
||||||
|
|
||||||
T *operator->() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
T* value = nullptr;
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool linked = false;
|
|
||||||
T *end = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* FRAMEWORK_CONTAINER_HYBRIDITERATOR_H_ */
|
|
@ -1,700 +0,0 @@
|
|||||||
#ifndef FRAMEWORK_CONTAINER_INDEXEDRINGMEMORY_H_
|
|
||||||
#define FRAMEWORK_CONTAINER_INDEXEDRINGMEMORY_H_
|
|
||||||
|
|
||||||
#include "ArrayList.h"
|
|
||||||
#include "../globalfunctions/CRC.h"
|
|
||||||
#include "../serviceinterface/ServiceInterfaceStream.h"
|
|
||||||
#include "../returnvalues/HasReturnvaluesIF.h"
|
|
||||||
#include "../serialize/SerialArrayListAdapter.h"
|
|
||||||
#include <cmath>
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
class Index: public SerializeIF{
|
|
||||||
/**
|
|
||||||
* Index is the Type used for the list of indices. The template parameter is the type which describes the index, it needs to be a child of SerializeIF to be able to make it persistent
|
|
||||||
*/
|
|
||||||
static_assert(std::is_base_of<SerializeIF,T>::value,"Wrong Type for Index, Type must implement SerializeIF");
|
|
||||||
public:
|
|
||||||
Index():blockStartAddress(0),size(0),storedPackets(0){}
|
|
||||||
|
|
||||||
Index(uint32_t startAddress):blockStartAddress(startAddress),size(0),storedPackets(0){
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void setBlockStartAddress(uint32_t newAddress){
|
|
||||||
this->blockStartAddress = newAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t getBlockStartAddress() const {
|
|
||||||
return blockStartAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
const T* getIndexType() const {
|
|
||||||
return &indexType;
|
|
||||||
}
|
|
||||||
|
|
||||||
T* modifyIndexType(){
|
|
||||||
return &indexType;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Updates the index Type. Uses = operator
|
|
||||||
* @param indexType Type to copy from
|
|
||||||
*/
|
|
||||||
void setIndexType(T* indexType) {
|
|
||||||
this->indexType = *indexType;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t getSize() const {
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setSize(uint32_t size) {
|
|
||||||
this->size = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
void addSize(uint32_t size){
|
|
||||||
this->size += size;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setStoredPackets(uint32_t newStoredPackets){
|
|
||||||
this->storedPackets = newStoredPackets;
|
|
||||||
}
|
|
||||||
|
|
||||||
void addStoredPackets(uint32_t packets){
|
|
||||||
this->storedPackets += packets;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t getStoredPackets() const{
|
|
||||||
return this->storedPackets;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t serialize(uint8_t** buffer, size_t* size,
|
|
||||||
size_t maxSize, Endianness streamEndianness) const {
|
|
||||||
ReturnValue_t result = SerializeAdapter::serialize(&blockStartAddress,buffer,size,maxSize,streamEndianness);
|
|
||||||
if(result != HasReturnvaluesIF::RETURN_OK){
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
result = indexType.serialize(buffer,size,maxSize,streamEndianness);
|
|
||||||
if(result != HasReturnvaluesIF::RETURN_OK){
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
result = SerializeAdapter::serialize(&this->size,buffer,size,maxSize,streamEndianness);
|
|
||||||
if(result != HasReturnvaluesIF::RETURN_OK){
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
result = SerializeAdapter::serialize(&this->storedPackets,buffer,size,maxSize,streamEndianness);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
|
||||||
Endianness streamEndianness){
|
|
||||||
ReturnValue_t result = SerializeAdapter::deSerialize(&blockStartAddress,buffer,size,streamEndianness);
|
|
||||||
if(result != HasReturnvaluesIF::RETURN_OK){
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
result = indexType.deSerialize(buffer,size,streamEndianness);
|
|
||||||
if(result != HasReturnvaluesIF::RETURN_OK){
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
result = SerializeAdapter::deSerialize(&this->size,buffer,size,streamEndianness);
|
|
||||||
if(result != HasReturnvaluesIF::RETURN_OK){
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
result = SerializeAdapter::deSerialize(&this->storedPackets,buffer,size,streamEndianness);
|
|
||||||
if(result != HasReturnvaluesIF::RETURN_OK){
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t getSerializedSize() const {
|
|
||||||
uint32_t size = SerializeAdapter::getSerializedSize(&blockStartAddress);
|
|
||||||
size += indexType.getSerializedSize();
|
|
||||||
size += SerializeAdapter::getSerializedSize(&this->size);
|
|
||||||
size += SerializeAdapter::getSerializedSize(&this->storedPackets);
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool operator==(const Index<T>& other){
|
|
||||||
return ((blockStartAddress == other.getBlockStartAddress()) && (size==other.getSize())) && (indexType == *(other.getIndexType()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
uint32_t blockStartAddress;
|
|
||||||
uint32_t size;
|
|
||||||
uint32_t storedPackets;
|
|
||||||
T indexType;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
class IndexedRingMemoryArray: public SerializeIF, public ArrayList<Index<T>, uint32_t>{
|
|
||||||
/**
|
|
||||||
* Indexed Ring Memory Array is a class for a ring memory with indices. It assumes that the newest data comes in last
|
|
||||||
* It uses the currentWriteBlock as pointer to the current writing position
|
|
||||||
* The currentReadBlock must be set manually
|
|
||||||
*/
|
|
||||||
public:
|
|
||||||
IndexedRingMemoryArray(uint32_t startAddress, uint32_t size, uint32_t bytesPerBlock, SerializeIF* additionalInfo,
|
|
||||||
bool overwriteOld) :ArrayList<Index<T>,uint32_t>(NULL,(uint32_t)10,(uint32_t)0),totalSize(size),indexAddress(startAddress),currentReadSize(0),currentReadBlockSizeCached(0),lastBlockToReadSize(0), additionalInfo(additionalInfo),overwriteOld(overwriteOld){
|
|
||||||
|
|
||||||
//Calculate the maximum number of indices needed for this blocksize
|
|
||||||
uint32_t maxNrOfIndices = floor(static_cast<double>(size)/static_cast<double>(bytesPerBlock));
|
|
||||||
|
|
||||||
//Calculate the Size needeed for the index itself
|
|
||||||
uint32_t serializedSize = 0;
|
|
||||||
if(additionalInfo!=NULL){
|
|
||||||
serializedSize += additionalInfo->getSerializedSize();
|
|
||||||
}
|
|
||||||
//Size of current iterator type
|
|
||||||
Index<T> tempIndex;
|
|
||||||
serializedSize += tempIndex.getSerializedSize();
|
|
||||||
|
|
||||||
//Add Size of Array
|
|
||||||
serializedSize += sizeof(uint32_t); //size of array
|
|
||||||
serializedSize += (tempIndex.getSerializedSize() * maxNrOfIndices); //size of elements
|
|
||||||
serializedSize += sizeof(uint16_t); //size of crc
|
|
||||||
|
|
||||||
//Calculate new size after index
|
|
||||||
if(serializedSize > totalSize){
|
|
||||||
error << "IndexedRingMemory: Store is too small for index" << std::endl;
|
|
||||||
}
|
|
||||||
uint32_t useableSize = totalSize - serializedSize;
|
|
||||||
//Update the totalSize for calculations
|
|
||||||
totalSize = useableSize;
|
|
||||||
|
|
||||||
//True StartAddress
|
|
||||||
uint32_t trueStartAddress = indexAddress + serializedSize;
|
|
||||||
|
|
||||||
//Calculate True number of Blocks and reset size of true Number of Blocks
|
|
||||||
uint32_t trueNumberOfBlocks = floor(static_cast<double>(totalSize) / static_cast<double>(bytesPerBlock));
|
|
||||||
|
|
||||||
//allocate memory now
|
|
||||||
this->entries = new Index<T>[trueNumberOfBlocks];
|
|
||||||
this->size = trueNumberOfBlocks;
|
|
||||||
this->maxSize_ = trueNumberOfBlocks;
|
|
||||||
this->allocated = true;
|
|
||||||
|
|
||||||
//Check trueNumberOfBlocks
|
|
||||||
if(trueNumberOfBlocks<1){
|
|
||||||
error << "IndexedRingMemory: Invalid Number of Blocks: " << trueNumberOfBlocks;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//Fill address into index
|
|
||||||
uint32_t address = trueStartAddress;
|
|
||||||
for (typename IndexedRingMemoryArray<T>::Iterator it = this->begin();it!=this->end();++it) {
|
|
||||||
it->setBlockStartAddress(address);
|
|
||||||
it->setSize(0);
|
|
||||||
it->setStoredPackets(0);
|
|
||||||
address += bytesPerBlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//Initialize iterators
|
|
||||||
currentWriteBlock = this->begin();
|
|
||||||
currentReadBlock = this->begin();
|
|
||||||
lastBlockToRead = this->begin();
|
|
||||||
|
|
||||||
//Check last blockSize
|
|
||||||
uint32_t lastBlockSize = (trueStartAddress + useableSize) - (this->back()->getBlockStartAddress());
|
|
||||||
if((lastBlockSize<bytesPerBlock) && (this->size > 1)){
|
|
||||||
//remove the last Block so the second last block has more size
|
|
||||||
this->size -= 1;
|
|
||||||
debug << "IndexedRingMemory: Last Block is smaller than bytesPerBlock, removed last block" << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resets the whole index, the iterators and executes the given reset function on every index type
|
|
||||||
* @param typeResetFnc static reset function which accepts a pointer to the index Type
|
|
||||||
*/
|
|
||||||
void reset(void (*typeResetFnc)(T*)){
|
|
||||||
currentReadBlock = this->begin();
|
|
||||||
currentWriteBlock = this->begin();
|
|
||||||
lastBlockToRead = this->begin();
|
|
||||||
currentReadSize = 0;
|
|
||||||
currentReadBlockSizeCached = 0;
|
|
||||||
lastBlockToReadSize = 0;
|
|
||||||
for(typename IndexedRingMemoryArray<T>::Iterator it = this->begin();it!=this->end();++it){
|
|
||||||
it->setSize(0);
|
|
||||||
it->setStoredPackets(0);
|
|
||||||
(*typeResetFnc)(it->modifyIndexType());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void resetBlock(typename IndexedRingMemoryArray<T>::Iterator it,void (*typeResetFnc)(T*)){
|
|
||||||
it->setSize(0);
|
|
||||||
it->setStoredPackets(0);
|
|
||||||
(*typeResetFnc)(it->modifyIndexType());
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Reading
|
|
||||||
*/
|
|
||||||
|
|
||||||
void setCurrentReadBlock(typename IndexedRingMemoryArray<T>::Iterator it){
|
|
||||||
currentReadBlock = it;
|
|
||||||
currentReadBlockSizeCached = it->getSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
void resetRead(){
|
|
||||||
currentReadBlock = this->begin();
|
|
||||||
currentReadSize = 0;
|
|
||||||
currentReadBlockSizeCached = this->begin()->getSize();
|
|
||||||
lastBlockToRead = currentWriteBlock;
|
|
||||||
lastBlockToReadSize = currentWriteBlock->getSize();
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Sets the last block to read to this iterator.
|
|
||||||
* Can be used to dump until block x
|
|
||||||
* @param it The iterator for the last read block
|
|
||||||
*/
|
|
||||||
void setLastBlockToRead(typename IndexedRingMemoryArray<T>::Iterator it){
|
|
||||||
lastBlockToRead = it;
|
|
||||||
lastBlockToReadSize = it->getSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the read pointer to the first written Block, which is the first non empty block in front of the write block
|
|
||||||
* Can be the currentWriteBlock as well
|
|
||||||
*/
|
|
||||||
void readOldest(){
|
|
||||||
resetRead();
|
|
||||||
currentReadBlock = getNextNonEmptyBlock();
|
|
||||||
currentReadBlockSizeCached = currentReadBlock->getSize();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the current read iterator to the next Block and resets the current read size
|
|
||||||
* The current size of the block will be cached to avoid race condition between write and read
|
|
||||||
* If the end of the ring is reached the read pointer will be set to the begin
|
|
||||||
*/
|
|
||||||
void readNext(){
|
|
||||||
currentReadSize = 0;
|
|
||||||
if((this->size != 0) && (currentReadBlock.value ==this->back())){
|
|
||||||
currentReadBlock = this->begin();
|
|
||||||
}else{
|
|
||||||
currentReadBlock++;
|
|
||||||
}
|
|
||||||
|
|
||||||
currentReadBlockSizeCached = currentReadBlock->getSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the address which is currently read from
|
|
||||||
* @return Address to read from
|
|
||||||
*/
|
|
||||||
uint32_t getCurrentReadAddress() const {
|
|
||||||
return getAddressOfCurrentReadBlock() + currentReadSize;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Adds readSize to the current size and checks if the read has no more data left and advances the read block
|
|
||||||
* @param readSize The size that was read
|
|
||||||
* @return Returns true if the read can go on
|
|
||||||
*/
|
|
||||||
bool addReadSize(uint32_t readSize) {
|
|
||||||
if(currentReadBlock == lastBlockToRead){
|
|
||||||
//The current read block is the last to read
|
|
||||||
if((currentReadSize+readSize)<lastBlockToReadSize){
|
|
||||||
//the block has more data -> return true
|
|
||||||
currentReadSize += readSize;
|
|
||||||
return true;
|
|
||||||
}else{
|
|
||||||
//Reached end of read -> return false
|
|
||||||
currentReadSize = lastBlockToReadSize;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
//We are not in the last Block
|
|
||||||
if((currentReadSize + readSize)<currentReadBlockSizeCached){
|
|
||||||
//The current Block has more data
|
|
||||||
currentReadSize += readSize;
|
|
||||||
return true;
|
|
||||||
}else{
|
|
||||||
//The current block is written completely
|
|
||||||
readNext();
|
|
||||||
if(currentReadBlockSizeCached==0){
|
|
||||||
//Next block is empty
|
|
||||||
typename IndexedRingMemoryArray<T>::Iterator it(currentReadBlock);
|
|
||||||
//Search if any block between this and the last block is not empty
|
|
||||||
for(;it!=lastBlockToRead;++it){
|
|
||||||
if(it == this->end()){
|
|
||||||
//This is the end, next block is the begin
|
|
||||||
it = this->begin();
|
|
||||||
if(it == lastBlockToRead){
|
|
||||||
//Break if the begin is the lastBlockToRead
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(it->getSize()!=0){
|
|
||||||
//This is a non empty block. Go on reading with this block
|
|
||||||
currentReadBlock = it;
|
|
||||||
currentReadBlockSizeCached = it->getSize();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//reached lastBlockToRead and every block was empty, check if the last block is also empty
|
|
||||||
if(lastBlockToReadSize!=0){
|
|
||||||
//go on with last Block
|
|
||||||
currentReadBlock = lastBlockToRead;
|
|
||||||
currentReadBlockSizeCached = lastBlockToReadSize;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
//There is no non empty block left
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
//Size is larger than 0
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
uint32_t getRemainigSizeOfCurrentReadBlock() const{
|
|
||||||
if(currentReadBlock == lastBlockToRead){
|
|
||||||
return (lastBlockToReadSize - currentReadSize);
|
|
||||||
}else{
|
|
||||||
return (currentReadBlockSizeCached - currentReadSize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t getAddressOfCurrentReadBlock() const {
|
|
||||||
return currentReadBlock->getBlockStartAddress();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the next non empty Block after the current write block,
|
|
||||||
* @return Returns the iterator to the block. If there is non, the current write block is returned
|
|
||||||
*/
|
|
||||||
typename IndexedRingMemoryArray<T>::Iterator getNextNonEmptyBlock() const {
|
|
||||||
for(typename IndexedRingMemoryArray<T>::Iterator it = getNextWrite();it!=currentWriteBlock;++it){
|
|
||||||
if(it == this->end()){
|
|
||||||
it = this->begin();
|
|
||||||
if(it == currentWriteBlock){
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(it->getSize()!=0){
|
|
||||||
return it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return currentWriteBlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a copy of the oldest Index type
|
|
||||||
* @return Type of Index
|
|
||||||
*/
|
|
||||||
T* getOldest(){
|
|
||||||
return (getNextNonEmptyBlock()->modifyIndexType());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Writing
|
|
||||||
*/
|
|
||||||
uint32_t getAddressOfCurrentWriteBlock() const{
|
|
||||||
return currentWriteBlock->getBlockStartAddress();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t getSizeOfCurrentWriteBlock() const{
|
|
||||||
return currentWriteBlock->getSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t getCurrentWriteAddress() const{
|
|
||||||
return getAddressOfCurrentWriteBlock() + getSizeOfCurrentWriteBlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void clearCurrentWriteBlock(){
|
|
||||||
currentWriteBlock->setSize(0);
|
|
||||||
currentWriteBlock->setStoredPackets(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void addCurrentWriteBlock(uint32_t size, uint32_t storedPackets){
|
|
||||||
currentWriteBlock->addSize(size);
|
|
||||||
currentWriteBlock->addStoredPackets(storedPackets);
|
|
||||||
}
|
|
||||||
|
|
||||||
T* modifyCurrentWriteBlockIndexType(){
|
|
||||||
return currentWriteBlock->modifyIndexType();
|
|
||||||
}
|
|
||||||
void updatePreviousWriteSize(uint32_t size, uint32_t storedPackets){
|
|
||||||
typename IndexedRingMemoryArray<T>::Iterator it = getPreviousBlock(currentWriteBlock);
|
|
||||||
it->addSize(size);
|
|
||||||
it->addStoredPackets(storedPackets);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the block has enough space for sizeToWrite
|
|
||||||
* @param sizeToWrite The data to be written in the Block
|
|
||||||
* @return Returns true if size to write is smaller the remaining size of the block
|
|
||||||
*/
|
|
||||||
bool hasCurrentWriteBlockEnoughSpace(uint32_t sizeToWrite){
|
|
||||||
typename IndexedRingMemoryArray<T>::Iterator next = getNextWrite();
|
|
||||||
uint32_t addressOfNextBlock = next->getBlockStartAddress();
|
|
||||||
uint32_t availableSize = ((addressOfNextBlock+totalSize) - (getAddressOfCurrentWriteBlock()+getSizeOfCurrentWriteBlock()))%totalSize;
|
|
||||||
return (sizeToWrite < availableSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the store is full if overwrite old is false
|
|
||||||
* @return Returns true if it is writeable and false if not
|
|
||||||
*/
|
|
||||||
bool isNextBlockWritable(){
|
|
||||||
//First check if this is the end of the list
|
|
||||||
typename IndexedRingMemoryArray<T>::Iterator next;
|
|
||||||
next = getNextWrite();
|
|
||||||
if((next->getSize()!=0) && (!overwriteOld)){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates current write Block Index Type
|
|
||||||
* @param infoOfNewBlock
|
|
||||||
*/
|
|
||||||
void updateCurrentBlock(T* infoOfNewBlock){
|
|
||||||
currentWriteBlock->setIndexType(infoOfNewBlock);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Succeed to next block, returns FAILED if overwrite is false and the store is full
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
ReturnValue_t writeNext(){
|
|
||||||
//Check Next Block
|
|
||||||
if(!isNextBlockWritable()){
|
|
||||||
//The Index is full and does not overwrite old
|
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
|
||||||
}
|
|
||||||
//Next block can be written, update Metadata
|
|
||||||
currentWriteBlock = getNextWrite();
|
|
||||||
currentWriteBlock->setSize(0);
|
|
||||||
currentWriteBlock->setStoredPackets(0);
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Serializes the Index and calculates the CRC.
|
|
||||||
* Parameters according to HasSerializeIF
|
|
||||||
* @param buffer
|
|
||||||
* @param size
|
|
||||||
* @param maxSize
|
|
||||||
* @param streamEndianness
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
ReturnValue_t serialize(uint8_t** buffer, size_t* size,
|
|
||||||
size_t maxSize, Endianness streamEndianness) const{
|
|
||||||
uint8_t* crcBuffer = *buffer;
|
|
||||||
uint32_t oldSize = *size;
|
|
||||||
if(additionalInfo!=NULL){
|
|
||||||
additionalInfo->serialize(buffer,size,maxSize,streamEndianness);
|
|
||||||
}
|
|
||||||
ReturnValue_t result = currentWriteBlock->serialize(buffer,size,maxSize,streamEndianness);
|
|
||||||
if(result != HasReturnvaluesIF::RETURN_OK){
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
result = SerializeAdapter::serialize(&this->size,buffer,size,maxSize,streamEndianness);
|
|
||||||
if(result != HasReturnvaluesIF::RETURN_OK){
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t i = 0;
|
|
||||||
while ((result == HasReturnvaluesIF::RETURN_OK) && (i < this->size)) {
|
|
||||||
result = SerializeAdapter::serialize(&this->entries[i], buffer, size,
|
|
||||||
maxSize, streamEndianness);
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
if(result != HasReturnvaluesIF::RETURN_OK){
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
uint16_t crc = Calculate_CRC(crcBuffer,(*size-oldSize));
|
|
||||||
result = SerializeAdapter::serialize(&crc,buffer,size,maxSize,streamEndianness);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the serialized Size of the index
|
|
||||||
* @return The serialized size of the index
|
|
||||||
*/
|
|
||||||
size_t getSerializedSize() const {
|
|
||||||
|
|
||||||
uint32_t size = 0;
|
|
||||||
if(additionalInfo!=NULL){
|
|
||||||
size += additionalInfo->getSerializedSize();
|
|
||||||
}
|
|
||||||
size += currentWriteBlock->getSerializedSize();
|
|
||||||
size += SerializeAdapter::getSerializedSize(&this->size);
|
|
||||||
size += (this->entries[0].getSerializedSize()) * this->size;
|
|
||||||
uint16_t crc = 0;
|
|
||||||
size += SerializeAdapter::getSerializedSize(&crc);
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* DeSerialize the Indexed Ring from a buffer, deSerializes the current write iterator
|
|
||||||
* CRC Has to be checked before!
|
|
||||||
* @param buffer
|
|
||||||
* @param size
|
|
||||||
* @param streamEndianness
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
|
|
||||||
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
|
||||||
Endianness streamEndianness){
|
|
||||||
|
|
||||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
|
||||||
if(additionalInfo!=NULL){
|
|
||||||
result = additionalInfo->deSerialize(buffer,size,streamEndianness);
|
|
||||||
}
|
|
||||||
if(result != HasReturnvaluesIF::RETURN_OK){
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
Index<T> tempIndex;
|
|
||||||
result = tempIndex.deSerialize(buffer,size,streamEndianness);
|
|
||||||
if(result != HasReturnvaluesIF::RETURN_OK){
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
uint32_t tempSize = 0;
|
|
||||||
result = SerializeAdapter::deSerialize(&tempSize,buffer,size,streamEndianness);
|
|
||||||
if(result != HasReturnvaluesIF::RETURN_OK){
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
if(this->size != tempSize){
|
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
|
||||||
}
|
|
||||||
uint32_t i = 0;
|
|
||||||
while ((result == HasReturnvaluesIF::RETURN_OK) && (i < this->size)) {
|
|
||||||
result = SerializeAdapter::deSerialize(
|
|
||||||
&this->entries[i], buffer, size,
|
|
||||||
streamEndianness);
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
if(result != HasReturnvaluesIF::RETURN_OK){
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
typename IndexedRingMemoryArray<T>::Iterator cmp(&tempIndex);
|
|
||||||
for(typename IndexedRingMemoryArray<T>::Iterator it= this->begin();it!=this->end();++it){
|
|
||||||
if(*(cmp.value) == *(it.value)){
|
|
||||||
currentWriteBlock = it;
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//Reached if current write block iterator is not found
|
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t getIndexAddress() const {
|
|
||||||
return indexAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Statistics
|
|
||||||
*/
|
|
||||||
uint32_t getStoredPackets() const {
|
|
||||||
uint32_t size = 0;
|
|
||||||
for(typename IndexedRingMemoryArray<T>::Iterator it= this->begin();it!=this->end();++it){
|
|
||||||
size += it->getStoredPackets();
|
|
||||||
}
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t getTotalSize() const {
|
|
||||||
return totalSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t getCurrentSize() const{
|
|
||||||
uint32_t size = 0;
|
|
||||||
for(typename IndexedRingMemoryArray<T>::Iterator it= this->begin();it!=this->end();++it){
|
|
||||||
size += it->getSize();
|
|
||||||
}
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isEmpty() const{
|
|
||||||
return getCurrentSize()==0;
|
|
||||||
}
|
|
||||||
|
|
||||||
double getPercentageFilled() const{
|
|
||||||
uint32_t filledSize = 0;
|
|
||||||
for(typename IndexedRingMemoryArray<T>::Iterator it= this->begin();it!=this->end();++it){
|
|
||||||
filledSize += it->getSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
return (double)filledSize/(double)this->totalSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
typename IndexedRingMemoryArray<T>::Iterator getCurrentWriteBlock() const{
|
|
||||||
return currentWriteBlock;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Get the next block of the currentWriteBlock.
|
|
||||||
* Returns the first one if currentWriteBlock is the last one
|
|
||||||
* @return Iterator pointing to the next block after currentWriteBlock
|
|
||||||
*/
|
|
||||||
typename IndexedRingMemoryArray<T>::Iterator getNextWrite() const{
|
|
||||||
typename IndexedRingMemoryArray<T>::Iterator next(currentWriteBlock);
|
|
||||||
if((this->size != 0) && (currentWriteBlock.value == this->back())){
|
|
||||||
next = this->begin();
|
|
||||||
}else{
|
|
||||||
++next;
|
|
||||||
}
|
|
||||||
return next;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Get the block in front of the Iterator
|
|
||||||
* Returns the last block if it is the first block
|
|
||||||
* @param it iterator which you want the previous block from
|
|
||||||
* @return pointing to the block before it
|
|
||||||
*/
|
|
||||||
typename IndexedRingMemoryArray<T>::Iterator getPreviousBlock(typename IndexedRingMemoryArray<T>::Iterator it) {
|
|
||||||
if(this->begin() == it){
|
|
||||||
typename IndexedRingMemoryArray<T>::Iterator next((this->back()));
|
|
||||||
return next;
|
|
||||||
}
|
|
||||||
typename IndexedRingMemoryArray<T>::Iterator next(it);
|
|
||||||
--next;
|
|
||||||
return next;
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
//The total size used by the blocks (without index)
|
|
||||||
uint32_t totalSize;
|
|
||||||
|
|
||||||
//The address of the index
|
|
||||||
const uint32_t indexAddress;
|
|
||||||
|
|
||||||
//The iterators for writing and reading
|
|
||||||
typename IndexedRingMemoryArray<T>::Iterator currentWriteBlock;
|
|
||||||
typename IndexedRingMemoryArray<T>::Iterator currentReadBlock;
|
|
||||||
|
|
||||||
//How much of the current read block is read already
|
|
||||||
uint32_t currentReadSize;
|
|
||||||
|
|
||||||
//Cached Size of current read block
|
|
||||||
uint32_t currentReadBlockSizeCached;
|
|
||||||
|
|
||||||
//Last block of current write (should be write block)
|
|
||||||
typename IndexedRingMemoryArray<T>::Iterator lastBlockToRead;
|
|
||||||
//current size of last Block to read
|
|
||||||
uint32_t lastBlockToReadSize;
|
|
||||||
|
|
||||||
//Additional Info to be serialized with the index
|
|
||||||
SerializeIF* additionalInfo;
|
|
||||||
|
|
||||||
//Does it overwrite old blocks?
|
|
||||||
const bool overwriteOld;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* FRAMEWORK_CONTAINER_INDEXEDRINGMEMORY_H_ */
|
|
@ -1,71 +0,0 @@
|
|||||||
#ifndef FRAMEWORK_CONTAINER_PLACEMENTFACTORY_H_
|
|
||||||
#define FRAMEWORK_CONTAINER_PLACEMENTFACTORY_H_
|
|
||||||
|
|
||||||
#include "../storagemanager/StorageManagerIF.h"
|
|
||||||
#include <utility>
|
|
||||||
/**
|
|
||||||
* The Placement Factory is used to create objects at runtime in a specific pool.
|
|
||||||
* In general, this should be avoided and it should only be used if you know what you are doing.
|
|
||||||
* You are not allowed to use this container with a type that allocates memory internally like ArrayList.
|
|
||||||
*
|
|
||||||
* Also, you have to check the returned pointer in generate against nullptr!
|
|
||||||
*
|
|
||||||
* A backend of Type StorageManagerIF must be given as a place to store the new objects.
|
|
||||||
* Therefore ThreadSafety is only provided by your StorageManager Implementation.
|
|
||||||
*
|
|
||||||
* Objects must be destroyed by the user with "destroy"! Otherwise the pool will not be cleared.
|
|
||||||
*
|
|
||||||
* The concept is based on the placement new operator.
|
|
||||||
*
|
|
||||||
* @warning Do not use with any Type that allocates memory internally!
|
|
||||||
* @ingroup container
|
|
||||||
*/
|
|
||||||
class PlacementFactory {
|
|
||||||
public:
|
|
||||||
PlacementFactory(StorageManagerIF* backend) :
|
|
||||||
dataBackend(backend) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/***
|
|
||||||
* Generates an object of type T in the backend storage.
|
|
||||||
*
|
|
||||||
* @warning Do not use with any Type that allocates memory internally!
|
|
||||||
*
|
|
||||||
* @tparam T Type of Object
|
|
||||||
* @param args Constructor Arguments to be passed
|
|
||||||
* @return A pointer to the new object or a nullptr in case of failure
|
|
||||||
*/
|
|
||||||
template<typename T, typename ... Args>
|
|
||||||
T* generate(Args&&... args) {
|
|
||||||
store_address_t tempId;
|
|
||||||
uint8_t* pData = nullptr;
|
|
||||||
ReturnValue_t result = dataBackend->getFreeElement(&tempId, sizeof(T),
|
|
||||||
&pData);
|
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
T* temp = new (pData) T(std::forward<Args>(args)...);
|
|
||||||
return temp;
|
|
||||||
}
|
|
||||||
/***
|
|
||||||
* Function to destroy the object allocated with generate and free space in backend.
|
|
||||||
* This must be called by the user.
|
|
||||||
*
|
|
||||||
* @param thisElement Element to be destroyed
|
|
||||||
* @return RETURN_OK if the element was destroyed, different errors on failure
|
|
||||||
*/
|
|
||||||
template<typename T>
|
|
||||||
ReturnValue_t destroy(T* thisElement) {
|
|
||||||
if (thisElement == nullptr){
|
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
|
||||||
}
|
|
||||||
//Need to call destructor first, in case something was allocated by the object (shouldn't do that, however).
|
|
||||||
thisElement->~T();
|
|
||||||
uint8_t* pointer = (uint8_t*) (thisElement);
|
|
||||||
return dataBackend->deleteData(pointer, sizeof(T));
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
StorageManagerIF* dataBackend;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* FRAMEWORK_CONTAINER_PLACEMENTFACTORY_H_ */
|
|
@ -1,113 +0,0 @@
|
|||||||
#ifndef FSFW_CONTAINER_RINGBUFFERBASE_H_
|
|
||||||
#define FSFW_CONTAINER_RINGBUFFERBASE_H_
|
|
||||||
|
|
||||||
#include "../returnvalues/HasReturnvaluesIF.h"
|
|
||||||
#include <cstddef>
|
|
||||||
|
|
||||||
template<uint8_t N_READ_PTRS = 1>
|
|
||||||
class RingBufferBase {
|
|
||||||
public:
|
|
||||||
RingBufferBase(size_t startAddress, const size_t size, bool overwriteOld) :
|
|
||||||
start(startAddress), write(startAddress), size(size),
|
|
||||||
overwriteOld(overwriteOld) {
|
|
||||||
for (uint8_t count = 0; count < N_READ_PTRS; count++) {
|
|
||||||
read[count] = startAddress;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~RingBufferBase() {}
|
|
||||||
|
|
||||||
bool isFull(uint8_t n = 0) {
|
|
||||||
return (availableWriteSpace(n) == 0);
|
|
||||||
}
|
|
||||||
bool isEmpty(uint8_t n = 0) {
|
|
||||||
return (getAvailableReadData(n) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t getAvailableReadData(uint8_t n = 0) const {
|
|
||||||
return ((write + size) - read[n]) % size;
|
|
||||||
}
|
|
||||||
size_t availableWriteSpace(uint8_t n = 0) const {
|
|
||||||
//One less to avoid ambiguous full/empty problem.
|
|
||||||
return (((read[n] + size) - write - 1) % size);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool overwritesOld() const {
|
|
||||||
return overwriteOld;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t getMaxSize() const {
|
|
||||||
return size - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear() {
|
|
||||||
write = start;
|
|
||||||
for (uint8_t count = 0; count < N_READ_PTRS; count++) {
|
|
||||||
read[count] = start;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t writeTillWrap() {
|
|
||||||
return (start + size) - write;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t readTillWrap(uint8_t n = 0) {
|
|
||||||
return (start + size) - read[n];
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t getStart() const {
|
|
||||||
return start;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
const size_t start;
|
|
||||||
size_t write;
|
|
||||||
size_t read[N_READ_PTRS];
|
|
||||||
const size_t size;
|
|
||||||
const bool overwriteOld;
|
|
||||||
|
|
||||||
void incrementWrite(uint32_t amount) {
|
|
||||||
write = ((write + amount - start) % size) + start;
|
|
||||||
}
|
|
||||||
void incrementRead(uint32_t amount, uint8_t n = 0) {
|
|
||||||
read[n] = ((read[n] + amount - start) % size) + start;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t readData(uint32_t amount, uint8_t n = 0) {
|
|
||||||
if (getAvailableReadData(n) >= amount) {
|
|
||||||
incrementRead(amount, n);
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
} else {
|
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t writeData(uint32_t amount) {
|
|
||||||
if (availableWriteSpace() >= amount or overwriteOld) {
|
|
||||||
incrementWrite(amount);
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
} else {
|
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t getRead(uint8_t n = 0) const {
|
|
||||||
return read[n];
|
|
||||||
}
|
|
||||||
|
|
||||||
void setRead(uint32_t read, uint8_t n = 0) {
|
|
||||||
if (read >= start && read < (start+size)) {
|
|
||||||
this->read[n] = read;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t getWrite() const {
|
|
||||||
return write;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setWrite(uint32_t write) {
|
|
||||||
this->write = write;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* FSFW_CONTAINER_RINGBUFFERBASE_H_ */
|
|
@ -1,60 +0,0 @@
|
|||||||
#include "SharedRingBuffer.h"
|
|
||||||
#include "../ipc/MutexFactory.h"
|
|
||||||
#include "../ipc/MutexGuard.h"
|
|
||||||
|
|
||||||
SharedRingBuffer::SharedRingBuffer(object_id_t objectId, const size_t size,
|
|
||||||
bool overwriteOld, size_t maxExcessBytes):
|
|
||||||
SystemObject(objectId), SimpleRingBuffer(size, overwriteOld,
|
|
||||||
maxExcessBytes) {
|
|
||||||
mutex = MutexFactory::instance()->createMutex();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
SharedRingBuffer::SharedRingBuffer(object_id_t objectId, uint8_t *buffer,
|
|
||||||
const size_t size, bool overwriteOld, size_t maxExcessBytes):
|
|
||||||
SystemObject(objectId), SimpleRingBuffer(buffer, size, overwriteOld,
|
|
||||||
maxExcessBytes) {
|
|
||||||
mutex = MutexFactory::instance()->createMutex();
|
|
||||||
}
|
|
||||||
|
|
||||||
SharedRingBuffer::~SharedRingBuffer() {
|
|
||||||
MutexFactory::instance()->deleteMutex(mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SharedRingBuffer::setToUseReceiveSizeFIFO(size_t fifoDepth) {
|
|
||||||
this->fifoDepth = fifoDepth;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t SharedRingBuffer::lockRingBufferMutex(
|
|
||||||
MutexIF::TimeoutType timeoutType, dur_millis_t timeout) {
|
|
||||||
return mutex->lockMutex(timeoutType, timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t SharedRingBuffer::unlockRingBufferMutex() {
|
|
||||||
return mutex->unlockMutex();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
MutexIF* SharedRingBuffer::getMutexHandle() const {
|
|
||||||
return mutex;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t SharedRingBuffer::initialize() {
|
|
||||||
if(fifoDepth > 0) {
|
|
||||||
receiveSizesFIFO = new DynamicFIFO<size_t>(fifoDepth);
|
|
||||||
}
|
|
||||||
return SystemObject::initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
DynamicFIFO<size_t>* SharedRingBuffer::getReceiveSizesFIFO() {
|
|
||||||
if(receiveSizesFIFO == nullptr) {
|
|
||||||
// Configuration error.
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::warning << "SharedRingBuffer::getReceiveSizesFIFO: Ring buffer"
|
|
||||||
<< " was not configured to have sizes FIFO, returning nullptr!"
|
|
||||||
<< std::endl;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
return receiveSizesFIFO;
|
|
||||||
}
|
|
@ -1,95 +0,0 @@
|
|||||||
#ifndef FSFW_CONTAINER_SHAREDRINGBUFFER_H_
|
|
||||||
#define FSFW_CONTAINER_SHAREDRINGBUFFER_H_
|
|
||||||
|
|
||||||
#include "SimpleRingBuffer.h"
|
|
||||||
#include "DynamicFIFO.h"
|
|
||||||
#include "../ipc/MutexIF.h"
|
|
||||||
#include "../objectmanager/SystemObject.h"
|
|
||||||
#include "../timemanager/Clock.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Ring buffer which can be shared among multiple objects
|
|
||||||
* @details
|
|
||||||
* This class offers a mutex to perform thread-safe operation on the ring
|
|
||||||
* buffer. It is still up to the developer to actually perform the lock
|
|
||||||
* and unlock operations.
|
|
||||||
*/
|
|
||||||
class SharedRingBuffer: public SystemObject,
|
|
||||||
public SimpleRingBuffer {
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* This constructor allocates a new internal buffer with the supplied size.
|
|
||||||
* @param size
|
|
||||||
* @param overwriteOld
|
|
||||||
* If the ring buffer is overflowing at a write operartion, the oldest data
|
|
||||||
* will be overwritten.
|
|
||||||
*/
|
|
||||||
SharedRingBuffer(object_id_t objectId, const size_t size,
|
|
||||||
bool overwriteOld, size_t maxExcessBytes);
|
|
||||||
/**
|
|
||||||
* This constructor takes an external buffer with the specified size.
|
|
||||||
* @param buffer
|
|
||||||
* @param size
|
|
||||||
* @param overwriteOld
|
|
||||||
* If the ring buffer is overflowing at a write operartion, the oldest data
|
|
||||||
* will be overwritten.
|
|
||||||
*/
|
|
||||||
SharedRingBuffer(object_id_t objectId, uint8_t* buffer, const size_t size,
|
|
||||||
bool overwriteOld, size_t maxExcessBytes);
|
|
||||||
|
|
||||||
virtual~ SharedRingBuffer();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief This function can be used to add an optional FIFO to the class
|
|
||||||
* @details
|
|
||||||
* This FIFO will be allocated in the initialize function (and will
|
|
||||||
* have a fixed maximum size after that). It can be used to store
|
|
||||||
* values like packet sizes, for example for a shared ring buffer
|
|
||||||
* used by producer/consumer tasks.
|
|
||||||
*/
|
|
||||||
void setToUseReceiveSizeFIFO(size_t fifoDepth);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unless a read-only constant value is read, all operations on the
|
|
||||||
* shared ring buffer should be protected by calling this function.
|
|
||||||
* @param timeoutType
|
|
||||||
* @param timeout
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
virtual ReturnValue_t lockRingBufferMutex(MutexIF::TimeoutType timeoutType,
|
|
||||||
dur_millis_t timeout);
|
|
||||||
/**
|
|
||||||
* Any locked mutex also has to be unlocked, otherwise, access to the
|
|
||||||
* shared ring buffer will be blocked.
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
virtual ReturnValue_t unlockRingBufferMutex();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The mutex handle can be accessed directly, for example to perform
|
|
||||||
* the lock with the #MutexGuard for a RAII compliant lock operation.
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
MutexIF* getMutexHandle() const;
|
|
||||||
|
|
||||||
ReturnValue_t initialize() override;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If the shared ring buffer was configured to have a sizes FIFO, a handle
|
|
||||||
* to that FIFO can be retrieved with this function.
|
|
||||||
* Do not forget to protect access with a lock if required!
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
DynamicFIFO<size_t>* getReceiveSizesFIFO();
|
|
||||||
private:
|
|
||||||
MutexIF* mutex = nullptr;
|
|
||||||
|
|
||||||
size_t fifoDepth = 0;
|
|
||||||
DynamicFIFO<size_t>* receiveSizesFIFO = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* FSFW_CONTAINER_SHAREDRINGBUFFER_H_ */
|
|
@ -1,131 +0,0 @@
|
|||||||
#include "SimpleRingBuffer.h"
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
SimpleRingBuffer::SimpleRingBuffer(const size_t size, bool overwriteOld,
|
|
||||||
size_t maxExcessBytes) :
|
|
||||||
RingBufferBase<>(0, size, overwriteOld),
|
|
||||||
maxExcessBytes(maxExcessBytes) {
|
|
||||||
if(maxExcessBytes > size) {
|
|
||||||
this->maxExcessBytes = size;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this->maxExcessBytes = maxExcessBytes;
|
|
||||||
}
|
|
||||||
buffer = new uint8_t[size + maxExcessBytes];
|
|
||||||
}
|
|
||||||
|
|
||||||
SimpleRingBuffer::SimpleRingBuffer(uint8_t *buffer, const size_t size,
|
|
||||||
bool overwriteOld, size_t maxExcessBytes):
|
|
||||||
RingBufferBase<>(0, size, overwriteOld), buffer(buffer) {
|
|
||||||
if(maxExcessBytes > size) {
|
|
||||||
this->maxExcessBytes = size;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this->maxExcessBytes = maxExcessBytes;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SimpleRingBuffer::~SimpleRingBuffer() {
|
|
||||||
delete[] buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t SimpleRingBuffer::getFreeElement(uint8_t **writePointer,
|
|
||||||
size_t amount) {
|
|
||||||
if (availableWriteSpace() >= amount or overwriteOld) {
|
|
||||||
size_t amountTillWrap = writeTillWrap();
|
|
||||||
if (amountTillWrap < amount) {
|
|
||||||
if((amount - amountTillWrap + excessBytes) > maxExcessBytes) {
|
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
|
||||||
}
|
|
||||||
excessBytes = amount - amountTillWrap;
|
|
||||||
}
|
|
||||||
*writePointer = &buffer[write];
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SimpleRingBuffer::confirmBytesWritten(size_t amount) {
|
|
||||||
if(getExcessBytes() > 0) {
|
|
||||||
moveExcessBytesToStart();
|
|
||||||
}
|
|
||||||
incrementWrite(amount);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t SimpleRingBuffer::writeData(const uint8_t* data,
|
|
||||||
size_t amount) {
|
|
||||||
if (availableWriteSpace() >= amount or overwriteOld) {
|
|
||||||
size_t amountTillWrap = writeTillWrap();
|
|
||||||
if (amountTillWrap >= amount) {
|
|
||||||
// remaining size in buffer is sufficient to fit full amount.
|
|
||||||
memcpy(&buffer[write], data, amount);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
memcpy(&buffer[write], data, amountTillWrap);
|
|
||||||
memcpy(buffer, data + amountTillWrap, amount - amountTillWrap);
|
|
||||||
}
|
|
||||||
incrementWrite(amount);
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
} else {
|
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t SimpleRingBuffer::readData(uint8_t* data, size_t amount,
|
|
||||||
bool incrementReadPtr, bool readRemaining, size_t* trueAmount) {
|
|
||||||
size_t availableData = getAvailableReadData(READ_PTR);
|
|
||||||
size_t amountTillWrap = readTillWrap(READ_PTR);
|
|
||||||
if (availableData < amount) {
|
|
||||||
if (readRemaining) {
|
|
||||||
// more data available than amount specified.
|
|
||||||
amount = availableData;
|
|
||||||
} else {
|
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (trueAmount != nullptr) {
|
|
||||||
*trueAmount = amount;
|
|
||||||
}
|
|
||||||
if (amountTillWrap >= amount) {
|
|
||||||
memcpy(data, &buffer[read[READ_PTR]], amount);
|
|
||||||
} else {
|
|
||||||
memcpy(data, &buffer[read[READ_PTR]], amountTillWrap);
|
|
||||||
memcpy(data + amountTillWrap, buffer, amount - amountTillWrap);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(incrementReadPtr) {
|
|
||||||
deleteData(amount, readRemaining);
|
|
||||||
}
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t SimpleRingBuffer::getExcessBytes() const {
|
|
||||||
return excessBytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SimpleRingBuffer::moveExcessBytesToStart() {
|
|
||||||
if(excessBytes > 0) {
|
|
||||||
std::memcpy(buffer, &buffer[size], excessBytes);
|
|
||||||
excessBytes = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t SimpleRingBuffer::deleteData(size_t amount,
|
|
||||||
bool deleteRemaining, size_t* trueAmount) {
|
|
||||||
size_t availableData = getAvailableReadData(READ_PTR);
|
|
||||||
if (availableData < amount) {
|
|
||||||
if (deleteRemaining) {
|
|
||||||
amount = availableData;
|
|
||||||
} else {
|
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (trueAmount != nullptr) {
|
|
||||||
*trueAmount = amount;
|
|
||||||
}
|
|
||||||
incrementRead(amount, READ_PTR);
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
@ -1,129 +0,0 @@
|
|||||||
#ifndef FSFW_CONTAINER_SIMPLERINGBUFFER_H_
|
|
||||||
#define FSFW_CONTAINER_SIMPLERINGBUFFER_H_
|
|
||||||
|
|
||||||
#include "RingBufferBase.h"
|
|
||||||
#include <cstddef>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Circular buffer implementation, useful for buffering
|
|
||||||
* into data streams.
|
|
||||||
* @details
|
|
||||||
* Note that the deleteData() has to be called to increment the read pointer.
|
|
||||||
* This class allocated dynamically, so
|
|
||||||
* @ingroup containers
|
|
||||||
*/
|
|
||||||
class SimpleRingBuffer: public RingBufferBase<> {
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* This constructor allocates a new internal buffer with the supplied size.
|
|
||||||
*
|
|
||||||
* @param size
|
|
||||||
* @param overwriteOld If the ring buffer is overflowing at a write
|
|
||||||
* operation, the oldest data will be overwritten.
|
|
||||||
* @param maxExcessBytes These additional bytes will be allocated in addtion
|
|
||||||
* to the specified size to accomodate contiguous write operations
|
|
||||||
* with getFreeElement.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
SimpleRingBuffer(const size_t size, bool overwriteOld,
|
|
||||||
size_t maxExcessBytes = 0);
|
|
||||||
/**
|
|
||||||
* This constructor takes an external buffer with the specified size.
|
|
||||||
* @param buffer
|
|
||||||
* @param size
|
|
||||||
* @param overwriteOld
|
|
||||||
* If the ring buffer is overflowing at a write operartion, the oldest data
|
|
||||||
* will be overwritten.
|
|
||||||
* @param maxExcessBytes
|
|
||||||
* If the buffer can accomodate additional bytes for contigous write
|
|
||||||
* operations with getFreeElement, this is the maximum allowed additional
|
|
||||||
* size
|
|
||||||
*/
|
|
||||||
SimpleRingBuffer(uint8_t* buffer, const size_t size, bool overwriteOld,
|
|
||||||
size_t maxExcessBytes = 0);
|
|
||||||
|
|
||||||
virtual ~SimpleRingBuffer();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write to circular buffer and increment write pointer by amount.
|
|
||||||
* @param data
|
|
||||||
* @param amount
|
|
||||||
* @return -@c RETURN_OK if write operation was successfull
|
|
||||||
* -@c RETURN_FAILED if
|
|
||||||
*/
|
|
||||||
ReturnValue_t writeData(const uint8_t* data, size_t amount);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a pointer to a free element. If the remaining buffer is
|
|
||||||
* not large enough, the data will be written past the actual size
|
|
||||||
* and the amount of excess bytes will be cached. This function
|
|
||||||
* does not increment the write pointer!
|
|
||||||
* @param writePointer Pointer to a pointer which can be used to write
|
|
||||||
* contiguous blocks into the ring buffer
|
|
||||||
* @param amount
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
ReturnValue_t getFreeElement(uint8_t** writePointer, size_t amount);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This increments the write pointer and also copies the excess bytes
|
|
||||||
* to the beginning. It should be called if the write operation
|
|
||||||
* conducted after calling getFreeElement() was performed.
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
void confirmBytesWritten(size_t amount);
|
|
||||||
|
|
||||||
virtual size_t getExcessBytes() const;
|
|
||||||
/**
|
|
||||||
* Helper functions which moves any excess bytes to the start
|
|
||||||
* of the ring buffer.
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
virtual void moveExcessBytesToStart();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read from circular buffer at read pointer.
|
|
||||||
* @param data
|
|
||||||
* @param amount
|
|
||||||
* @param incrementReadPtr
|
|
||||||
* If this is set to true, the read pointer will be incremented.
|
|
||||||
* If readRemaining is set to true, the read pointer will be incremented
|
|
||||||
* accordingly.
|
|
||||||
* @param readRemaining
|
|
||||||
* If this is set to true, the data will be read even if the amount
|
|
||||||
* specified exceeds the read data available.
|
|
||||||
* @param trueAmount [out]
|
|
||||||
* If readRemaining was set to true, the true amount read will be assigned
|
|
||||||
* to the passed value.
|
|
||||||
* @return
|
|
||||||
* - @c RETURN_OK if data was read successfully
|
|
||||||
* - @c RETURN_FAILED if not enough data was available and readRemaining
|
|
||||||
* was set to false.
|
|
||||||
*/
|
|
||||||
ReturnValue_t readData(uint8_t* data, size_t amount,
|
|
||||||
bool incrementReadPtr = false, bool readRemaining = false,
|
|
||||||
size_t* trueAmount = nullptr);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete data by incrementing read pointer.
|
|
||||||
* @param amount
|
|
||||||
* @param deleteRemaining
|
|
||||||
* If the amount specified is larger than the remaing size to read and this
|
|
||||||
* is set to true, the remaining amount will be deleted as well
|
|
||||||
* @param trueAmount [out]
|
|
||||||
* If deleteRemaining was set to true, the amount deleted will be assigned
|
|
||||||
* to the passed value.
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
ReturnValue_t deleteData(size_t amount, bool deleteRemaining = false,
|
|
||||||
size_t* trueAmount = nullptr);
|
|
||||||
|
|
||||||
private:
|
|
||||||
static const uint8_t READ_PTR = 0;
|
|
||||||
uint8_t* buffer = nullptr;
|
|
||||||
size_t maxExcessBytes;
|
|
||||||
size_t excessBytes = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* FSFW_CONTAINER_SIMPLERINGBUFFER_H_ */
|
|
||||||
|
|
@ -1,154 +0,0 @@
|
|||||||
#ifndef FRAMEWORK_CONTAINER_SINGLYLINKEDLIST_H_
|
|
||||||
#define FRAMEWORK_CONTAINER_SINGLYLINKEDLIST_H_
|
|
||||||
|
|
||||||
#include <cstddef>
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Linked list data structure,
|
|
||||||
* each entry has a pointer to the next entry (singly)
|
|
||||||
* @ingroup container
|
|
||||||
*/
|
|
||||||
template<typename T>
|
|
||||||
class LinkedElement {
|
|
||||||
public:
|
|
||||||
T *value;
|
|
||||||
class Iterator {
|
|
||||||
public:
|
|
||||||
LinkedElement<T> *value = nullptr;
|
|
||||||
Iterator() {}
|
|
||||||
|
|
||||||
Iterator(LinkedElement<T> *element) :
|
|
||||||
value(element) {
|
|
||||||
}
|
|
||||||
|
|
||||||
Iterator& operator++() {
|
|
||||||
value = value->getNext();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Iterator operator++(int) {
|
|
||||||
Iterator tmp(*this);
|
|
||||||
operator++();
|
|
||||||
return tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator==(Iterator other) {
|
|
||||||
return value == other.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator!=(Iterator other) {
|
|
||||||
return !(*this == other);
|
|
||||||
}
|
|
||||||
T *operator->() {
|
|
||||||
return value->value;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
LinkedElement(T* setElement, LinkedElement<T>* setNext = nullptr):
|
|
||||||
value(setElement), next(setNext) {}
|
|
||||||
|
|
||||||
virtual ~LinkedElement(){}
|
|
||||||
|
|
||||||
virtual LinkedElement* getNext() const {
|
|
||||||
return next;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void setNext(LinkedElement* next) {
|
|
||||||
this->next = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void setEnd() {
|
|
||||||
this->next = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
LinkedElement* begin() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
LinkedElement* end() {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
LinkedElement *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
class SinglyLinkedList {
|
|
||||||
public:
|
|
||||||
using ElementIterator = typename LinkedElement<T>::Iterator;
|
|
||||||
|
|
||||||
SinglyLinkedList() {}
|
|
||||||
|
|
||||||
SinglyLinkedList(ElementIterator start) :
|
|
||||||
start(start.value) {}
|
|
||||||
|
|
||||||
SinglyLinkedList(LinkedElement<T>* startElement) :
|
|
||||||
start(startElement) {}
|
|
||||||
|
|
||||||
ElementIterator begin() const {
|
|
||||||
return ElementIterator::Iterator(start);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns iterator to nulltr */
|
|
||||||
ElementIterator end() const {
|
|
||||||
return ElementIterator::Iterator();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns last element in singly linked list.
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
ElementIterator back() const {
|
|
||||||
LinkedElement<T> *element = start;
|
|
||||||
while (element->getNext() != nullptr) {
|
|
||||||
element = element->getNext();
|
|
||||||
}
|
|
||||||
return ElementIterator::Iterator(element);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t getSize() const {
|
|
||||||
size_t size = 0;
|
|
||||||
LinkedElement<T> *element = start;
|
|
||||||
while (element != nullptr) {
|
|
||||||
size++;
|
|
||||||
element = element->getNext();
|
|
||||||
}
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
void setStart(LinkedElement<T>* firstElement) {
|
|
||||||
start = firstElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setNext(LinkedElement<T>* currentElement,
|
|
||||||
LinkedElement<T>* nextElement) {
|
|
||||||
currentElement->setNext(nextElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setLast(LinkedElement<T>* lastElement) {
|
|
||||||
lastElement->setEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
void insertElement(LinkedElement<T>* element, size_t position) {
|
|
||||||
LinkedElement<T> *currentElement = start;
|
|
||||||
for(size_t count = 0; count < position; count++) {
|
|
||||||
if(currentElement == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
currentElement = currentElement->getNext();
|
|
||||||
}
|
|
||||||
LinkedElement<T>* elementAfterCurrent = currentElement->next;
|
|
||||||
currentElement->setNext(element);
|
|
||||||
if(elementAfterCurrent != nullptr) {
|
|
||||||
element->setNext(elementAfterCurrent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void insertBack(LinkedElement<T>* lastElement) {
|
|
||||||
back().value->setNext(lastElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
LinkedElement<T> *start = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* SINGLYLINKEDLIST_H_ */
|
|
9
contrib/CMakeLists.txt
Normal file
9
contrib/CMakeLists.txt
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
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_contrib)
|
11
contrib/fsfw_contrib/CMakeLists.txt
Normal file
11
contrib/fsfw_contrib/CMakeLists.txt
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
if(FSFW_ADD_SGP4_PROPAGATOR)
|
||||||
|
target_sources(${LIB_FSFW_NAME} PRIVATE
|
||||||
|
sgp4/sgp4unit.cpp
|
||||||
|
)
|
||||||
|
target_include_directories(${LIB_FSFW_NAME} PRIVATE
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/sgp4
|
||||||
|
)
|
||||||
|
target_include_directories(${LIB_FSFW_NAME} INTERFACE
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/sgp4
|
||||||
|
)
|
||||||
|
endif()
|
@ -1,4 +0,0 @@
|
|||||||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
|
||||||
ControllerBase.cpp
|
|
||||||
ExtendedControllerBase.cpp
|
|
||||||
)
|
|
@ -1,137 +0,0 @@
|
|||||||
#include "ControllerBase.h"
|
|
||||||
|
|
||||||
#include "../subsystem/SubsystemBase.h"
|
|
||||||
#include "../ipc/QueueFactory.h"
|
|
||||||
#include "../action/HasActionsIF.h"
|
|
||||||
|
|
||||||
ControllerBase::ControllerBase(object_id_t setObjectId, object_id_t parentId,
|
|
||||||
size_t commandQueueDepth) :
|
|
||||||
SystemObject(setObjectId), parentId(parentId), mode(MODE_OFF),
|
|
||||||
submode(SUBMODE_NONE), modeHelper(this),
|
|
||||||
healthHelper(this, setObjectId) {
|
|
||||||
commandQueue = QueueFactory::instance()->createMessageQueue(
|
|
||||||
commandQueueDepth);
|
|
||||||
}
|
|
||||||
|
|
||||||
ControllerBase::~ControllerBase() {
|
|
||||||
QueueFactory::instance()->deleteMessageQueue(commandQueue);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t ControllerBase::initialize() {
|
|
||||||
ReturnValue_t result = SystemObject::initialize();
|
|
||||||
if (result != RETURN_OK) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
MessageQueueId_t parentQueue = 0;
|
|
||||||
if (parentId != objects::NO_OBJECT) {
|
|
||||||
SubsystemBase *parent = objectManager->get<SubsystemBase>(parentId);
|
|
||||||
if (parent == nullptr) {
|
|
||||||
return RETURN_FAILED;
|
|
||||||
}
|
|
||||||
parentQueue = parent->getCommandQueue();
|
|
||||||
|
|
||||||
parent->registerChild(getObjectId());
|
|
||||||
}
|
|
||||||
|
|
||||||
result = healthHelper.initialize(parentQueue);
|
|
||||||
if (result != RETURN_OK) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = modeHelper.initialize(parentQueue);
|
|
||||||
if (result != RETURN_OK) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
MessageQueueId_t ControllerBase::getCommandQueue() const {
|
|
||||||
return commandQueue->getId();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ControllerBase::handleQueue() {
|
|
||||||
CommandMessage command;
|
|
||||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
|
||||||
for (result = commandQueue->receiveMessage(&command);
|
|
||||||
result == RETURN_OK;
|
|
||||||
result = commandQueue->receiveMessage(&command)) {
|
|
||||||
|
|
||||||
result = modeHelper.handleModeCommand(&command);
|
|
||||||
if (result == RETURN_OK) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = healthHelper.handleHealthCommand(&command);
|
|
||||||
if (result == RETURN_OK) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
result = handleCommandMessage(&command);
|
|
||||||
if (result == RETURN_OK) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
command.setToUnknownCommand();
|
|
||||||
commandQueue->reply(&command);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ControllerBase::startTransition(Mode_t mode, Submode_t submode) {
|
|
||||||
changeHK(this->mode, this->submode, false);
|
|
||||||
triggerEvent(CHANGING_MODE, mode, submode);
|
|
||||||
this->mode = mode;
|
|
||||||
this->submode = submode;
|
|
||||||
modeHelper.modeChanged(mode, submode);
|
|
||||||
modeChanged(mode, submode);
|
|
||||||
announceMode(false);
|
|
||||||
changeHK(this->mode, this->submode, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ControllerBase::getMode(Mode_t* mode, Submode_t* submode) {
|
|
||||||
*mode = this->mode;
|
|
||||||
*submode = this->submode;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ControllerBase::setToExternalControl() {
|
|
||||||
healthHelper.setHealth(EXTERNAL_CONTROL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ControllerBase::announceMode(bool recursive) {
|
|
||||||
triggerEvent(MODE_INFO, mode, submode);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t ControllerBase::performOperation(uint8_t opCode) {
|
|
||||||
handleQueue();
|
|
||||||
performControlOperation();
|
|
||||||
return RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ControllerBase::modeChanged(Mode_t mode, Submode_t submode) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t ControllerBase::setHealth(HealthState health) {
|
|
||||||
switch (health) {
|
|
||||||
case HEALTHY:
|
|
||||||
case EXTERNAL_CONTROL:
|
|
||||||
healthHelper.setHealth(health);
|
|
||||||
return RETURN_OK;
|
|
||||||
default:
|
|
||||||
return INVALID_HEALTH_STATE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HasHealthIF::HealthState ControllerBase::getHealth() {
|
|
||||||
return healthHelper.getHealth();
|
|
||||||
}
|
|
||||||
void ControllerBase::setTaskIF(PeriodicTaskIF* task_){
|
|
||||||
executingTask = task_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ControllerBase::changeHK(Mode_t mode, Submode_t submode, bool enable) {
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t ControllerBase::initializeAfterTaskCreation() {
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
@ -1,94 +0,0 @@
|
|||||||
#ifndef FSFW_CONTROLLER_CONTROLLERBASE_H_
|
|
||||||
#define FSFW_CONTROLLER_CONTROLLERBASE_H_
|
|
||||||
|
|
||||||
#include "../health/HasHealthIF.h"
|
|
||||||
#include "../health/HealthHelper.h"
|
|
||||||
#include "../modes/HasModesIF.h"
|
|
||||||
#include "../modes/ModeHelper.h"
|
|
||||||
#include "../objectmanager/SystemObject.h"
|
|
||||||
#include "../tasks/ExecutableObjectIF.h"
|
|
||||||
#include "../tasks/PeriodicTaskIF.h"
|
|
||||||
#include "../datapool/HkSwitchHelper.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Generic base class for controller classes
|
|
||||||
* @details
|
|
||||||
* Implements common interfaces for controllers, which generally have
|
|
||||||
* a mode and a health state. This avoids boilerplate code.
|
|
||||||
*/
|
|
||||||
class ControllerBase: public HasModesIF,
|
|
||||||
public HasHealthIF,
|
|
||||||
public ExecutableObjectIF,
|
|
||||||
public SystemObject,
|
|
||||||
public HasReturnvaluesIF {
|
|
||||||
public:
|
|
||||||
static const Mode_t MODE_NORMAL = 2;
|
|
||||||
|
|
||||||
ControllerBase(object_id_t setObjectId, object_id_t parentId,
|
|
||||||
size_t commandQueueDepth = 3);
|
|
||||||
virtual ~ControllerBase();
|
|
||||||
|
|
||||||
/** SystemObject override */
|
|
||||||
virtual ReturnValue_t initialize() override;
|
|
||||||
|
|
||||||
virtual MessageQueueId_t getCommandQueue() const override;
|
|
||||||
|
|
||||||
/** HasHealthIF overrides */
|
|
||||||
virtual ReturnValue_t setHealth(HealthState health) override;
|
|
||||||
virtual HasHealthIF::HealthState getHealth() override;
|
|
||||||
|
|
||||||
/** ExecutableObjectIF overrides */
|
|
||||||
virtual ReturnValue_t performOperation(uint8_t opCode) override;
|
|
||||||
virtual void setTaskIF(PeriodicTaskIF* task) override;
|
|
||||||
virtual ReturnValue_t initializeAfterTaskCreation() override;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implemented by child class. Handle command messages which are not
|
|
||||||
* mode or health messages.
|
|
||||||
* @param message
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
virtual ReturnValue_t handleCommandMessage(CommandMessage *message) = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Periodic helper, implemented by child class.
|
|
||||||
*/
|
|
||||||
virtual void performControlOperation() = 0;
|
|
||||||
|
|
||||||
virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
|
|
||||||
uint32_t *msToReachTheMode) = 0;
|
|
||||||
|
|
||||||
const object_id_t parentId;
|
|
||||||
|
|
||||||
Mode_t mode;
|
|
||||||
|
|
||||||
Submode_t submode;
|
|
||||||
|
|
||||||
MessageQueueIF* commandQueue = nullptr;
|
|
||||||
|
|
||||||
ModeHelper modeHelper;
|
|
||||||
|
|
||||||
HealthHelper healthHelper;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pointer to the task which executes this component,
|
|
||||||
* is invalid before setTaskIF was called.
|
|
||||||
*/
|
|
||||||
PeriodicTaskIF* executingTask = nullptr;
|
|
||||||
|
|
||||||
/** Handle mode and health messages */
|
|
||||||
virtual void handleQueue();
|
|
||||||
|
|
||||||
/** Mode helpers */
|
|
||||||
virtual void modeChanged(Mode_t mode, Submode_t submode);
|
|
||||||
virtual void startTransition(Mode_t mode, Submode_t submode);
|
|
||||||
virtual void getMode(Mode_t *mode, Submode_t *submode);
|
|
||||||
virtual void setToExternalControl();
|
|
||||||
virtual void announceMode(bool recursive);
|
|
||||||
/** HK helpers */
|
|
||||||
virtual void changeHK(Mode_t mode, Submode_t submode, bool enable);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* FSFW_CONTROLLER_CONTROLLERBASE_H_ */
|
|
@ -1,104 +0,0 @@
|
|||||||
#include "ExtendedControllerBase.h"
|
|
||||||
|
|
||||||
|
|
||||||
ExtendedControllerBase::ExtendedControllerBase(object_id_t objectId,
|
|
||||||
object_id_t parentId, size_t commandQueueDepth):
|
|
||||||
ControllerBase(objectId, parentId, commandQueueDepth),
|
|
||||||
poolManager(this, commandQueue),
|
|
||||||
actionHelper(this, commandQueue) {
|
|
||||||
}
|
|
||||||
|
|
||||||
ExtendedControllerBase::~ExtendedControllerBase() {
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t ExtendedControllerBase::executeAction(ActionId_t actionId,
|
|
||||||
MessageQueueId_t commandedBy, const uint8_t *data, size_t size) {
|
|
||||||
/* Needs to be overriden and implemented by child class. */
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
object_id_t ExtendedControllerBase::getObjectId() const {
|
|
||||||
return SystemObject::getObjectId();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t ExtendedControllerBase::getPeriodicOperationFrequency() const {
|
|
||||||
return this->executingTask->getPeriodMs();
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t ExtendedControllerBase::handleCommandMessage(
|
|
||||||
CommandMessage *message) {
|
|
||||||
ReturnValue_t result = actionHelper.handleActionMessage(message);
|
|
||||||
if(result == HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
return poolManager.handleHousekeepingMessage(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExtendedControllerBase::handleQueue() {
|
|
||||||
CommandMessage command;
|
|
||||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
|
||||||
for (result = commandQueue->receiveMessage(&command);
|
|
||||||
result == RETURN_OK;
|
|
||||||
result = commandQueue->receiveMessage(&command)) {
|
|
||||||
result = actionHelper.handleActionMessage(&command);
|
|
||||||
if (result == RETURN_OK) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = modeHelper.handleModeCommand(&command);
|
|
||||||
if (result == RETURN_OK) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = healthHelper.handleHealthCommand(&command);
|
|
||||||
if (result == RETURN_OK) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = poolManager.handleHousekeepingMessage(&command);
|
|
||||||
if (result == RETURN_OK) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = handleCommandMessage(&command);
|
|
||||||
if (result == RETURN_OK) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
command.setToUnknownCommand();
|
|
||||||
commandQueue->reply(&command);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t ExtendedControllerBase::initialize() {
|
|
||||||
ReturnValue_t result = ControllerBase::initialize();
|
|
||||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
result = actionHelper.initialize(commandQueue);
|
|
||||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return poolManager.initialize(commandQueue);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t ExtendedControllerBase::initializeAfterTaskCreation() {
|
|
||||||
return poolManager.initializeAfterTaskCreation();
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t ExtendedControllerBase::performOperation(uint8_t opCode) {
|
|
||||||
handleQueue();
|
|
||||||
performControlOperation();
|
|
||||||
/* We do this after performing control operation because variables will be set changed
|
|
||||||
in this function. */
|
|
||||||
poolManager.performHkOperation();
|
|
||||||
return RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
MessageQueueId_t ExtendedControllerBase::getCommandQueue() const {
|
|
||||||
return commandQueue->getId();
|
|
||||||
}
|
|
||||||
|
|
||||||
LocalDataPoolManager* ExtendedControllerBase::getHkManagerHandle() {
|
|
||||||
return &poolManager;
|
|
||||||
}
|
|
@ -1,73 +0,0 @@
|
|||||||
#ifndef FSFW_CONTROLLER_EXTENDEDCONTROLLERBASE_H_
|
|
||||||
#define FSFW_CONTROLLER_EXTENDEDCONTROLLERBASE_H_
|
|
||||||
|
|
||||||
#include "ControllerBase.h"
|
|
||||||
|
|
||||||
#include "../action/HasActionsIF.h"
|
|
||||||
#include "../datapoollocal/HasLocalDataPoolIF.h"
|
|
||||||
#include "../action/ActionHelper.h"
|
|
||||||
#include "../datapoollocal/LocalDataPoolManager.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Extendes the basic ControllerBase with the common components
|
|
||||||
* HasActionsIF for commandability and HasLocalDataPoolIF to keep
|
|
||||||
* a pool of local data pool variables.
|
|
||||||
* @details
|
|
||||||
* Default implementations required for the interfaces will be empty and have
|
|
||||||
* to be implemented by child class.
|
|
||||||
*/
|
|
||||||
class ExtendedControllerBase: public ControllerBase,
|
|
||||||
public HasActionsIF,
|
|
||||||
public HasLocalDataPoolIF {
|
|
||||||
public:
|
|
||||||
ExtendedControllerBase(object_id_t objectId, object_id_t parentId,
|
|
||||||
size_t commandQueueDepth = 3);
|
|
||||||
virtual ~ExtendedControllerBase();
|
|
||||||
|
|
||||||
/* SystemObjectIF overrides */
|
|
||||||
virtual ReturnValue_t initialize() override;
|
|
||||||
|
|
||||||
virtual MessageQueueId_t getCommandQueue() const override;
|
|
||||||
|
|
||||||
/* ExecutableObjectIF overrides */
|
|
||||||
virtual ReturnValue_t performOperation(uint8_t opCode) override;
|
|
||||||
virtual ReturnValue_t initializeAfterTaskCreation() override;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
LocalDataPoolManager poolManager;
|
|
||||||
ActionHelper actionHelper;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implemented by child class. Handle all command messages which are
|
|
||||||
* not health, mode, action or housekeeping messages.
|
|
||||||
* @param message
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
virtual ReturnValue_t handleCommandMessage(CommandMessage *message) = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Periodic helper from ControllerBase, implemented by child class.
|
|
||||||
*/
|
|
||||||
virtual void performControlOperation() = 0;
|
|
||||||
|
|
||||||
/* Handle the four messages mentioned above */
|
|
||||||
void handleQueue() override;
|
|
||||||
|
|
||||||
/* HasActionsIF overrides */
|
|
||||||
virtual ReturnValue_t executeAction(ActionId_t actionId,
|
|
||||||
MessageQueueId_t commandedBy, const uint8_t* data,
|
|
||||||
size_t size) override;
|
|
||||||
|
|
||||||
/* HasLocalDatapoolIF overrides */
|
|
||||||
virtual LocalDataPoolManager* getHkManagerHandle() override;
|
|
||||||
virtual object_id_t getObjectId() const override;
|
|
||||||
virtual uint32_t getPeriodicOperationFrequency() const override;
|
|
||||||
|
|
||||||
virtual ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
|
|
||||||
LocalDataPoolManager& poolManager) override = 0;
|
|
||||||
virtual LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* FSFW_CONTROLLER_EXTENDEDCONTROLLERBASE_H_ */
|
|
@ -1,5 +0,0 @@
|
|||||||
target_sources(${LIB_FSFW_NAME}
|
|
||||||
PRIVATE
|
|
||||||
CoordinateTransformations.cpp
|
|
||||||
Sgp4Propagator.cpp
|
|
||||||
)
|
|
@ -1,227 +0,0 @@
|
|||||||
#include "CoordinateTransformations.h"
|
|
||||||
#include "../globalfunctions/constants.h"
|
|
||||||
#include "../globalfunctions/math/MatrixOperations.h"
|
|
||||||
#include "../globalfunctions/math/VectorOperations.h"
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <cmath>
|
|
||||||
|
|
||||||
|
|
||||||
void CoordinateTransformations::positionEcfToEci(const double* ecfPosition,
|
|
||||||
double* eciPosition, timeval *timeUTC) {
|
|
||||||
ecfToEci(ecfPosition, eciPosition, NULL, timeUTC);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void CoordinateTransformations::velocityEcfToEci(const double* ecfVelocity,
|
|
||||||
const double* ecfPosition, double* eciVelocity, timeval *timeUTC) {
|
|
||||||
ecfToEci(ecfVelocity, eciVelocity, ecfPosition, timeUTC);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CoordinateTransformations::positionEciToEcf(const double* eciCoordinates, double* ecfCoordinates,timeval *timeUTC){
|
|
||||||
eciToEcf(eciCoordinates,ecfCoordinates,NULL,timeUTC);
|
|
||||||
};
|
|
||||||
|
|
||||||
void CoordinateTransformations::velocityEciToEcf(const double* eciVelocity,const double* eciPosition, double* ecfVelocity,timeval* timeUTC){
|
|
||||||
eciToEcf(eciVelocity,ecfVelocity,eciPosition,timeUTC);
|
|
||||||
}
|
|
||||||
|
|
||||||
double CoordinateTransformations::getEarthRotationAngle(timeval timeUTC) {
|
|
||||||
|
|
||||||
double jD2000UTC;
|
|
||||||
Clock::convertTimevalToJD2000(timeUTC, &jD2000UTC);
|
|
||||||
|
|
||||||
double TTt2000 = getJuleanCenturiesTT(timeUTC);
|
|
||||||
|
|
||||||
double theta = 2 * Math::PI
|
|
||||||
* (0.779057273264 + 1.00273781191135448 * jD2000UTC);
|
|
||||||
|
|
||||||
//Correct theta according to IAU 2000 precession-nutation model
|
|
||||||
theta = theta + 7.03270725817493E-008 + 0.0223603701 * TTt2000
|
|
||||||
+ 6.77128219501896E-006 * TTt2000 * TTt2000
|
|
||||||
+ 4.5300990362875E-010 * TTt2000 * TTt2000 * TTt2000
|
|
||||||
+ 9.12419347848147E-011 * TTt2000 * TTt2000 * TTt2000 * TTt2000;
|
|
||||||
return theta;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CoordinateTransformations::getEarthRotationMatrix(timeval timeUTC,
|
|
||||||
double matrix[][3]) {
|
|
||||||
double theta = getEarthRotationAngle(timeUTC);
|
|
||||||
|
|
||||||
matrix[0][0] = cos(theta);
|
|
||||||
matrix[0][1] = sin(theta);
|
|
||||||
matrix[0][2] = 0;
|
|
||||||
matrix[1][0] = -sin(theta);
|
|
||||||
matrix[1][1] = cos(theta);
|
|
||||||
matrix[1][2] = 0;
|
|
||||||
matrix[2][0] = 0;
|
|
||||||
matrix[2][1] = 0;
|
|
||||||
matrix[2][2] = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CoordinateTransformations::ecfToEci(const double* ecfCoordinates,
|
|
||||||
double* eciCoordinates,
|
|
||||||
const double* ecfPositionIfCoordinatesAreVelocity, timeval *timeUTCin) {
|
|
||||||
|
|
||||||
timeval timeUTC;
|
|
||||||
if (timeUTCin != NULL) {
|
|
||||||
timeUTC = *timeUTCin;
|
|
||||||
} else {
|
|
||||||
Clock::getClock_timeval(&timeUTC);
|
|
||||||
}
|
|
||||||
|
|
||||||
double Tfi[3][3];
|
|
||||||
double Tif[3][3];
|
|
||||||
getTransMatrixECITOECF(timeUTC,Tfi);
|
|
||||||
|
|
||||||
MatrixOperations<double>::transpose(Tfi[0], Tif[0], 3);
|
|
||||||
|
|
||||||
MatrixOperations<double>::multiply(Tif[0], ecfCoordinates, eciCoordinates,
|
|
||||||
3, 3, 1);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (ecfPositionIfCoordinatesAreVelocity != NULL) {
|
|
||||||
|
|
||||||
double Tdotfi[3][3];
|
|
||||||
double Tdotif[3][3];
|
|
||||||
double Trot[3][3] = { { 0, Earth::OMEGA, 0 },
|
|
||||||
{ 0 - Earth::OMEGA, 0, 0 }, { 0, 0, 0 } };
|
|
||||||
|
|
||||||
MatrixOperations<double>::multiply(Trot[0], Tfi[0], Tdotfi[0], 3, 3,
|
|
||||||
3);
|
|
||||||
|
|
||||||
MatrixOperations<double>::transpose(Tdotfi[0], Tdotif[0], 3);
|
|
||||||
|
|
||||||
double velocityCorrection[3];
|
|
||||||
|
|
||||||
MatrixOperations<double>::multiply(Tdotif[0],
|
|
||||||
ecfPositionIfCoordinatesAreVelocity, velocityCorrection, 3, 3,
|
|
||||||
1);
|
|
||||||
|
|
||||||
VectorOperations<double>::add(velocityCorrection, eciCoordinates,
|
|
||||||
eciCoordinates, 3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
double CoordinateTransformations::getJuleanCenturiesTT(timeval timeUTC) {
|
|
||||||
timeval timeTT;
|
|
||||||
Clock::convertUTCToTT(timeUTC, &timeTT);
|
|
||||||
double jD2000TT;
|
|
||||||
Clock::convertTimevalToJD2000(timeTT, &jD2000TT);
|
|
||||||
|
|
||||||
return jD2000TT / 36525.;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CoordinateTransformations::eciToEcf(const double* eciCoordinates,
|
|
||||||
double* ecfCoordinates,
|
|
||||||
const double* eciPositionIfCoordinatesAreVelocity,timeval *timeUTCin){
|
|
||||||
timeval timeUTC;
|
|
||||||
if (timeUTCin != NULL) {
|
|
||||||
timeUTC = *timeUTCin;
|
|
||||||
}else{
|
|
||||||
Clock::getClock_timeval(&timeUTC);
|
|
||||||
}
|
|
||||||
|
|
||||||
double Tfi[3][3];
|
|
||||||
|
|
||||||
getTransMatrixECITOECF(timeUTC,Tfi);
|
|
||||||
|
|
||||||
MatrixOperations<double>::multiply(Tfi[0],eciCoordinates,ecfCoordinates,3,3,1);
|
|
||||||
|
|
||||||
if (eciPositionIfCoordinatesAreVelocity != NULL) {
|
|
||||||
|
|
||||||
double Tdotfi[3][3];
|
|
||||||
double Trot[3][3] = { { 0, Earth::OMEGA, 0 },
|
|
||||||
{ 0 - Earth::OMEGA, 0, 0 }, { 0, 0, 0 } };
|
|
||||||
|
|
||||||
MatrixOperations<double>::multiply(Trot[0], Tfi[0], Tdotfi[0], 3, 3,
|
|
||||||
3);
|
|
||||||
|
|
||||||
double velocityCorrection[3];
|
|
||||||
|
|
||||||
MatrixOperations<double>::multiply(Tdotfi[0],
|
|
||||||
eciPositionIfCoordinatesAreVelocity, velocityCorrection, 3, 3,
|
|
||||||
1);
|
|
||||||
|
|
||||||
VectorOperations<double>::add(ecfCoordinates, velocityCorrection,
|
|
||||||
ecfCoordinates, 3);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void CoordinateTransformations::getTransMatrixECITOECF(timeval timeUTC,double Tfi[3][3]){
|
|
||||||
double TTt2000 = getJuleanCenturiesTT(timeUTC);
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////
|
|
||||||
// Calculate Precession Matrix
|
|
||||||
|
|
||||||
double zeta = 0.0111808609 * TTt2000
|
|
||||||
+ 1.46355554053347E-006 * TTt2000 * TTt2000
|
|
||||||
+ 8.72567663260943E-008 * TTt2000 * TTt2000 * TTt2000;
|
|
||||||
double theta_p = 0.0097171735 * TTt2000
|
|
||||||
- 2.06845757045384E-006 * TTt2000 * TTt2000
|
|
||||||
- 2.02812107218552E-007 * TTt2000 * TTt2000 * TTt2000;
|
|
||||||
double z = zeta + 3.8436028638364E-006 * TTt2000 * TTt2000
|
|
||||||
+ 0.000000001 * TTt2000 * TTt2000 * TTt2000;
|
|
||||||
|
|
||||||
double mPrecession[3][3];
|
|
||||||
|
|
||||||
mPrecession[0][0] = -sin(z) * sin(zeta) + cos(z) * cos(theta_p) * cos(zeta);
|
|
||||||
mPrecession[1][0] = cos(z) * sin(zeta) + sin(z) * cos(theta_p) * cos(zeta);
|
|
||||||
mPrecession[2][0] = sin(theta_p) * cos(zeta);
|
|
||||||
|
|
||||||
mPrecession[0][1] = -sin(z) * cos(zeta) - cos(z) * cos(theta_p) * sin(zeta);
|
|
||||||
mPrecession[1][1] = cos(z) * cos(zeta) - sin(z) * cos(theta_p) * sin(zeta);
|
|
||||||
mPrecession[2][1] = -sin(theta_p) * sin(zeta);
|
|
||||||
|
|
||||||
mPrecession[0][2] = -cos(z) * sin(theta_p);
|
|
||||||
mPrecession[1][2] = -sin(z) * sin(theta_p);
|
|
||||||
mPrecession[2][2] = cos(theta_p);
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////
|
|
||||||
// Calculate Nutation Matrix
|
|
||||||
|
|
||||||
double omega_moon = 2.1824386244 - 33.7570459338 * TTt2000
|
|
||||||
+ 3.61428599267159E-005 * TTt2000 * TTt2000
|
|
||||||
+ 3.87850944887629E-008 * TTt2000 * TTt2000 * TTt2000;
|
|
||||||
|
|
||||||
double deltaPsi = -0.000083388 * sin(omega_moon);
|
|
||||||
double deltaEpsilon = 4.46174030725106E-005 * cos(omega_moon);
|
|
||||||
|
|
||||||
double epsilon = 0.4090928042 - 0.0002269655 * TTt2000
|
|
||||||
- 2.86040071854626E-009 * TTt2000 * TTt2000
|
|
||||||
+ 8.78967203851589E-009 * TTt2000 * TTt2000 * TTt2000;
|
|
||||||
|
|
||||||
|
|
||||||
double mNutation[3][3];
|
|
||||||
|
|
||||||
mNutation[0][0] = cos(deltaPsi);
|
|
||||||
mNutation[1][0] = cos(epsilon + deltaEpsilon) * sin(deltaPsi);
|
|
||||||
mNutation[2][0] = sin(epsilon + deltaEpsilon) * sin(deltaPsi);
|
|
||||||
|
|
||||||
mNutation[0][1] = -cos(epsilon) * sin(deltaPsi);
|
|
||||||
mNutation[1][1] = cos(epsilon) * cos(epsilon + deltaEpsilon) * cos(deltaPsi)
|
|
||||||
+ sin(epsilon) * sin(epsilon + deltaEpsilon);
|
|
||||||
mNutation[2][1] = cos(epsilon) * sin(epsilon + deltaEpsilon) * cos(deltaPsi)
|
|
||||||
- sin(epsilon) * cos(epsilon + deltaEpsilon);
|
|
||||||
|
|
||||||
mNutation[0][2] = -sin(epsilon) * sin(deltaPsi);
|
|
||||||
mNutation[1][2] = sin(epsilon) * cos(epsilon + deltaEpsilon) * cos(deltaPsi)
|
|
||||||
- cos(epsilon) * sin(epsilon + deltaEpsilon);
|
|
||||||
mNutation[2][2] = sin(epsilon) * sin(epsilon + deltaEpsilon) * cos(deltaPsi)
|
|
||||||
+ cos(epsilon) * cos(epsilon + deltaEpsilon);
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////
|
|
||||||
// Calculate Earth rotation matrix
|
|
||||||
//calculate theta
|
|
||||||
|
|
||||||
double mTheta[3][3];
|
|
||||||
double Ttemp[3][3];
|
|
||||||
getEarthRotationMatrix(timeUTC, mTheta);
|
|
||||||
|
|
||||||
//polar motion is neglected
|
|
||||||
MatrixOperations<double>::multiply(mNutation[0], mPrecession[0], Ttemp[0],
|
|
||||||
3, 3, 3);
|
|
||||||
|
|
||||||
MatrixOperations<double>::multiply(mTheta[0], Ttemp[0], Tfi[0], 3, 3, 3);
|
|
||||||
};
|
|
@ -1,34 +0,0 @@
|
|||||||
#ifndef COORDINATETRANSFORMATIONS_H_
|
|
||||||
#define COORDINATETRANSFORMATIONS_H_
|
|
||||||
|
|
||||||
#include "../timemanager/Clock.h"
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
class CoordinateTransformations {
|
|
||||||
public:
|
|
||||||
static void positionEcfToEci(const double* ecfCoordinates, double* eciCoordinates, timeval *timeUTC = NULL);
|
|
||||||
|
|
||||||
static void velocityEcfToEci(const double* ecfVelocity,
|
|
||||||
const double* ecfPosition,
|
|
||||||
double* eciVelocity, timeval *timeUTC = NULL);
|
|
||||||
|
|
||||||
static void positionEciToEcf(const double* eciCoordinates, double* ecfCoordinates,timeval *timeUTC = NULL);
|
|
||||||
static void velocityEciToEcf(const double* eciVelocity,const double* eciPosition, double* ecfVelocity,timeval* timeUTC = NULL);
|
|
||||||
|
|
||||||
static double getEarthRotationAngle(timeval timeUTC);
|
|
||||||
|
|
||||||
static void getEarthRotationMatrix(timeval timeUTC, double matrix[][3]);
|
|
||||||
private:
|
|
||||||
CoordinateTransformations();
|
|
||||||
static void ecfToEci(const double* ecfCoordinates, double* eciCoordinates,
|
|
||||||
const double* ecfPositionIfCoordinatesAreVelocity, timeval *timeUTCin);
|
|
||||||
static void eciToEcf(const double* eciCoordinates,
|
|
||||||
double* ecfCoordinates,
|
|
||||||
const double* eciPositionIfCoordinatesAreVelocity,timeval *timeUTCin);
|
|
||||||
|
|
||||||
static double getJuleanCenturiesTT(timeval timeUTC);
|
|
||||||
static void getTransMatrixECITOECF(timeval time,double Tfi[3][3]);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* COORDINATETRANSFORMATIONS_H_ */
|
|
@ -1,180 +0,0 @@
|
|||||||
#ifndef FRAMEWORK_COORDINATES_JGM3MODEL_H_
|
|
||||||
#define FRAMEWORK_COORDINATES_JGM3MODEL_H_
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include "CoordinateTransformations.h"
|
|
||||||
#include "../globalfunctions/math/VectorOperations.h"
|
|
||||||
#include "../globalfunctions/timevalOperations.h"
|
|
||||||
#include "../globalfunctions/constants.h"
|
|
||||||
#include <memory.h>
|
|
||||||
|
|
||||||
|
|
||||||
template<uint8_t DEGREE,uint8_t ORDER>
|
|
||||||
class Jgm3Model {
|
|
||||||
public:
|
|
||||||
static const uint32_t factorialLookupTable[DEGREE+3]; //This table is used instead of factorial calculation, must be increased if order or degree is higher
|
|
||||||
|
|
||||||
Jgm3Model() {
|
|
||||||
y0[0] = 0;
|
|
||||||
y0[1] = 0;
|
|
||||||
y0[2] = 0;
|
|
||||||
y0[3] = 0;
|
|
||||||
y0[4] = 0;
|
|
||||||
y0[5] = 0;
|
|
||||||
|
|
||||||
lastExecutionTime.tv_sec = 0;
|
|
||||||
lastExecutionTime.tv_usec = 0;
|
|
||||||
}
|
|
||||||
virtual ~Jgm3Model(){};
|
|
||||||
|
|
||||||
//double acsNavOrbit(double posECF[3],double velECF[3],timeval gpsTime);
|
|
||||||
|
|
||||||
double y0[6]; //position and velocity at beginning of RK step in EC
|
|
||||||
timeval lastExecutionTime; //Time of last execution
|
|
||||||
|
|
||||||
|
|
||||||
void accelDegOrd(const double pos[3],const double S[ORDER+1][DEGREE+1],const double C[ORDER+1][DEGREE+1],double* accel){
|
|
||||||
//Get radius of this position
|
|
||||||
double r = VectorOperations<double>::norm(pos,3);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//Initialize the V and W matrix
|
|
||||||
double V[DEGREE+2][ORDER+2] = {{0}};
|
|
||||||
double W[DEGREE+2][ORDER+2] = {{0}};
|
|
||||||
|
|
||||||
for(uint8_t m=0;m<(ORDER+2);m++){
|
|
||||||
for(uint8_t n=m;n<(DEGREE+2);n++){
|
|
||||||
if((n==0) && (m==0)){
|
|
||||||
//Montenbruck "Satellite Orbits Eq.3.31"
|
|
||||||
V[0][0] = Earth::MEAN_RADIUS / r;
|
|
||||||
W[0][0] = 0;
|
|
||||||
}else{
|
|
||||||
if(n==m){
|
|
||||||
//Montenbruck "Satellite Orbits Eq.3.29"
|
|
||||||
V[m][m] = (2*m-1)* (pos[0]*Earth::MEAN_RADIUS/pow(r,2)*V[m-1][m-1] - pos[1]*Earth::MEAN_RADIUS/pow(r,2)*W[m-1][m-1]);
|
|
||||||
W[m][m] = (2*m-1)* (pos[0]*Earth::MEAN_RADIUS/pow(r,2)*W[m-1][m-1] + pos[1]*Earth::MEAN_RADIUS/pow(r,2)*V[m-1][m-1]);
|
|
||||||
}else{
|
|
||||||
//Montenbruck "Satellite Orbits Eq.3.30"
|
|
||||||
V[n][m] = ((2*n-1)/(double)(n-m))*pos[2]*Earth::MEAN_RADIUS / pow(r,2)*V[n-1][m];
|
|
||||||
W[n][m] = ((2*n-1)/(double)(n-m))*pos[2]*Earth::MEAN_RADIUS / pow(r,2)*W[n-1][m];
|
|
||||||
if(n!=(m+1)){
|
|
||||||
V[n][m] = V[n][m] - (((n+m-1)/(double)(n-m)) * (pow(Earth::MEAN_RADIUS,2) / pow(r,2)) * V[n-2][m]);
|
|
||||||
W[n][m] = W[n][m] - (((n+m-1)/(double)(n-m)) * (pow(Earth::MEAN_RADIUS,2) / pow(r,2)) * W[n-2][m]);
|
|
||||||
}//End of if(n!=(m+1))
|
|
||||||
}//End of if(n==m){
|
|
||||||
}//End of if(n==0 and m==0)
|
|
||||||
}//End of for(uint8_t n=0;n<(DEGREE+1);n++)
|
|
||||||
}//End of for(uint8_t m=0;m<(ORDER+1);m++)
|
|
||||||
|
|
||||||
|
|
||||||
//overwrite accel if not properly initialized
|
|
||||||
accel[0] = 0;
|
|
||||||
accel[1] = 0;
|
|
||||||
accel[2] = 0;
|
|
||||||
|
|
||||||
for(uint8_t m=0;m<(ORDER+1);m++){
|
|
||||||
for(uint8_t n=m;n<(DEGREE+1);n++){
|
|
||||||
//Use table lookup to get factorial
|
|
||||||
double partAccel[3] = {0};
|
|
||||||
double factor = Earth::STANDARD_GRAVITATIONAL_PARAMETER/pow(Earth::MEAN_RADIUS,2);
|
|
||||||
if(m==0){
|
|
||||||
//Montenbruck "Satellite Orbits Eq.3.33"
|
|
||||||
partAccel[0] = factor * (-C[n][0]*V[n+1][1]);
|
|
||||||
partAccel[1] = factor * (-C[n][0]*W[n+1][1]);
|
|
||||||
}else{
|
|
||||||
double factMN = static_cast<double>(factorialLookupTable[n-m+2]) / static_cast<double>(factorialLookupTable[n-m]);
|
|
||||||
partAccel[0] = factor * 0.5 * ((-C[n][m]*V[n+1][m+1]-S[n][m]*W[n+1][m+1])+factMN*(C[n][m]*V[n+1][m-1]+S[n][m]*W[n+1][m-1]));
|
|
||||||
partAccel[1] = factor * 0.5 * ((-C[n][m]*W[n+1][m+1]+S[n][m]*V[n+1][m+1])+factMN*(-C[n][m]*W[n+1][m-1]+S[n][m]*V[n+1][m-1]));
|
|
||||||
}
|
|
||||||
|
|
||||||
partAccel[2] = factor * ((n-m+1)*(-C[n][m]*V[n+1][m]-S[n][m]*W[n+1][m]));
|
|
||||||
|
|
||||||
|
|
||||||
accel[0] += partAccel[0];
|
|
||||||
accel[1] += partAccel[1];
|
|
||||||
accel[2] += partAccel[2];
|
|
||||||
}//End of for(uint8_t n=0;n<DEGREE;n++)
|
|
||||||
}//End of uint8_t m=0;m<ORDER;m++
|
|
||||||
}
|
|
||||||
|
|
||||||
void initializeNavOrbit(const double position[3],const double velocity[3], timeval timeUTC){
|
|
||||||
CoordinateTransformations::positionEcfToEci(position,&y0[0],&timeUTC);
|
|
||||||
CoordinateTransformations::velocityEcfToEci(velocity,position,&y0[3],&timeUTC);
|
|
||||||
lastExecutionTime = timeUTC;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void acsNavOrbit(timeval timeUTC, const double S[ORDER+1][DEGREE+1],const double C[ORDER+1][DEGREE+1], double outputPos[3],double outputVel[3]){
|
|
||||||
|
|
||||||
//RK4 Integration for this timestamp
|
|
||||||
double deltaT = timevalOperations::toDouble(timeUTC-lastExecutionTime);
|
|
||||||
|
|
||||||
double y0dot[6] = {0,0,0,0,0,0};
|
|
||||||
double yA[6] = {0,0,0,0,0,0};
|
|
||||||
double yAdot[6] = {0,0,0,0,0,0};
|
|
||||||
double yB[6] = {0,0,0,0,0,0};
|
|
||||||
double yBdot[6] = {0,0,0,0,0,0};
|
|
||||||
double yC[6] = {0,0,0,0,0,0};
|
|
||||||
double yCdot[6] = {0,0,0,0,0,0};
|
|
||||||
|
|
||||||
//Step One
|
|
||||||
rungeKuttaStep(y0,y0dot,lastExecutionTime,S,C);
|
|
||||||
|
|
||||||
//Step Two
|
|
||||||
VectorOperations<double>::mulScalar(y0dot,deltaT/2,yA,6);
|
|
||||||
VectorOperations<double>::add(y0,yA,yA,6);
|
|
||||||
rungeKuttaStep(yA,yAdot,lastExecutionTime,S,C);
|
|
||||||
|
|
||||||
//Step Three
|
|
||||||
VectorOperations<double>::mulScalar(yAdot,deltaT/2,yB,6);
|
|
||||||
VectorOperations<double>::add(y0,yB,yB,6);
|
|
||||||
rungeKuttaStep(yB,yBdot,lastExecutionTime,S,C);
|
|
||||||
|
|
||||||
//Step Four
|
|
||||||
VectorOperations<double>::mulScalar(yBdot,deltaT,yC,6);
|
|
||||||
VectorOperations<double>::add(y0,yC,yC,6);
|
|
||||||
rungeKuttaStep(yC,yCdot,lastExecutionTime,S,C);
|
|
||||||
|
|
||||||
//Calc new State
|
|
||||||
VectorOperations<double>::mulScalar(yAdot,2,yAdot,6);
|
|
||||||
VectorOperations<double>::mulScalar(yBdot,2,yBdot,6);
|
|
||||||
VectorOperations<double>::add(y0dot,yAdot,y0dot,6);
|
|
||||||
VectorOperations<double>::add(y0dot,yBdot,y0dot,6);
|
|
||||||
VectorOperations<double>::add(y0dot,yCdot,y0dot,6);
|
|
||||||
VectorOperations<double>::mulScalar(y0dot,1./6.*deltaT,y0dot,6);
|
|
||||||
VectorOperations<double>::add(y0,y0dot,y0,6);
|
|
||||||
|
|
||||||
CoordinateTransformations::positionEciToEcf(&y0[0],outputPos,&timeUTC);
|
|
||||||
CoordinateTransformations::velocityEciToEcf(&y0[3],&y0[0],outputVel,&timeUTC);
|
|
||||||
|
|
||||||
lastExecutionTime = timeUTC;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void rungeKuttaStep(const double* yIn,double* yOut,timeval time, const double S[ORDER+1][DEGREE+1],const double C[ORDER+1][DEGREE+1]){
|
|
||||||
double rECF[3] = {0,0,0};
|
|
||||||
double rDotECF[3] = {0,0,0};
|
|
||||||
double accelECF[3] = {0,0,0};
|
|
||||||
double accelECI[3] = {0,0,0};
|
|
||||||
|
|
||||||
|
|
||||||
CoordinateTransformations::positionEciToEcf(&yIn[0],rECF,&time);
|
|
||||||
CoordinateTransformations::velocityEciToEcf(&yIn[3],&yIn[0],rDotECF,&time);
|
|
||||||
accelDegOrd(rECF,S,C,accelECF);
|
|
||||||
//This is not correct, as the acceleration would have derived terms but we don't know the velocity and position at that time
|
|
||||||
//Tests showed that a wrong velocity does make the equation worse than neglecting it
|
|
||||||
CoordinateTransformations::positionEcfToEci(accelECF,accelECI,&time);
|
|
||||||
memcpy(&yOut[0],&yIn[3],sizeof(yOut[0])*3);
|
|
||||||
memcpy(&yOut[3],accelECI,sizeof(yOut[0])*3);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* FRAMEWORK_COORDINATES_JGM3MODEL_H_ */
|
|
@ -1,228 +0,0 @@
|
|||||||
#include "CoordinateTransformations.h"
|
|
||||||
#include "Sgp4Propagator.h"
|
|
||||||
#include "../globalfunctions/constants.h"
|
|
||||||
#include "../globalfunctions/math/MatrixOperations.h"
|
|
||||||
#include "../globalfunctions/math/VectorOperations.h"
|
|
||||||
#include "../globalfunctions/timevalOperations.h"
|
|
||||||
#include <cstring>
|
|
||||||
Sgp4Propagator::Sgp4Propagator() :
|
|
||||||
initialized(false), epoch({0, 0}), whichconst(wgs84) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Sgp4Propagator::~Sgp4Propagator() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void jday(int year, int mon, int day, int hr, int minute, double sec,
|
|
||||||
double& jd) {
|
|
||||||
jd = 367.0 * year - floor((7 * (year + floor((mon + 9) / 12.0))) * 0.25)
|
|
||||||
+ floor(275 * mon / 9.0) + day + 1721013.5
|
|
||||||
+ ((sec / 60.0 + minute) / 60.0 + hr) / 24.0; // ut in days
|
|
||||||
// - 0.5*sgn(100.0*year + mon - 190002.5) + 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
void days2mdhms(int year, double days, int& mon, int& day, int& hr, int& minute,
|
|
||||||
double& sec) {
|
|
||||||
int i, inttemp, dayofyr;
|
|
||||||
double temp;
|
|
||||||
int lmonth[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
|
||||||
|
|
||||||
dayofyr = (int) floor(days);
|
|
||||||
/* ----------------- find month and day of month ---------------- */
|
|
||||||
if ((year % 4) == 0)
|
|
||||||
lmonth[1] = 29;
|
|
||||||
|
|
||||||
i = 1;
|
|
||||||
inttemp = 0;
|
|
||||||
while ((dayofyr > inttemp + lmonth[i - 1]) && (i < 12)) {
|
|
||||||
inttemp = inttemp + lmonth[i - 1];
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
mon = i;
|
|
||||||
day = dayofyr - inttemp;
|
|
||||||
|
|
||||||
/* ----------------- find hours minutes and seconds ------------- */
|
|
||||||
temp = (days - dayofyr) * 24.0;
|
|
||||||
hr = (int) floor(temp);
|
|
||||||
temp = (temp - hr) * 60.0;
|
|
||||||
minute = (int) floor(temp);
|
|
||||||
sec = (temp - minute) * 60.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t Sgp4Propagator::initialize(const uint8_t* line1,
|
|
||||||
const uint8_t* line2) {
|
|
||||||
|
|
||||||
char longstr1[130];
|
|
||||||
char longstr2[130];
|
|
||||||
|
|
||||||
//need some space for decimal points
|
|
||||||
memcpy(longstr1, line1, 69);
|
|
||||||
memcpy(longstr2, line2, 69);
|
|
||||||
|
|
||||||
const double deg2rad = Math::PI / 180.0; // 0.0174532925199433
|
|
||||||
const double xpdotp = 1440.0 / (2.0 * Math::PI); // 229.1831180523293
|
|
||||||
|
|
||||||
double sec, mu, radiusearthkm, tumin, xke, j2, j3, j4, j3oj2;
|
|
||||||
int cardnumb, numb, j;
|
|
||||||
long revnum = 0, elnum = 0;
|
|
||||||
char classification, intldesg[11];
|
|
||||||
int year = 0;
|
|
||||||
int mon, day, hr, minute, nexp, ibexp;
|
|
||||||
|
|
||||||
getgravconst(whichconst, tumin, mu, radiusearthkm, xke, j2, j3, j4, j3oj2);
|
|
||||||
|
|
||||||
satrec.error = 0;
|
|
||||||
|
|
||||||
// set the implied decimal points since doing a formated read
|
|
||||||
// fixes for bad input data values (missing, ...)
|
|
||||||
for (j = 10; j <= 15; j++)
|
|
||||||
if (longstr1[j] == ' ')
|
|
||||||
longstr1[j] = '_';
|
|
||||||
|
|
||||||
if (longstr1[44] != ' ')
|
|
||||||
longstr1[43] = longstr1[44];
|
|
||||||
longstr1[44] = '.';
|
|
||||||
if (longstr1[7] == ' ')
|
|
||||||
longstr1[7] = 'U';
|
|
||||||
if (longstr1[9] == ' ')
|
|
||||||
longstr1[9] = '.';
|
|
||||||
for (j = 45; j <= 49; j++)
|
|
||||||
if (longstr1[j] == ' ')
|
|
||||||
longstr1[j] = '0';
|
|
||||||
if (longstr1[51] == ' ')
|
|
||||||
longstr1[51] = '0';
|
|
||||||
if (longstr1[53] != ' ')
|
|
||||||
longstr1[52] = longstr1[53];
|
|
||||||
longstr1[53] = '.';
|
|
||||||
longstr2[25] = '.';
|
|
||||||
for (j = 26; j <= 32; j++)
|
|
||||||
if (longstr2[j] == ' ')
|
|
||||||
longstr2[j] = '0';
|
|
||||||
if (longstr1[62] == ' ')
|
|
||||||
longstr1[62] = '0';
|
|
||||||
if (longstr1[68] == ' ')
|
|
||||||
longstr1[68] = '0';
|
|
||||||
|
|
||||||
sscanf(longstr1,
|
|
||||||
"%2d %5ld %1c %10s %2d %12lf %11lf %7lf %2d %7lf %2d %2d %6ld ",
|
|
||||||
&cardnumb, &satrec.satnum, &classification, intldesg,
|
|
||||||
&satrec.epochyr, &satrec.epochdays, &satrec.ndot, &satrec.nddot,
|
|
||||||
&nexp, &satrec.bstar, &ibexp, &numb, &elnum);
|
|
||||||
|
|
||||||
if (longstr2[52] == ' ') {
|
|
||||||
sscanf(longstr2, "%2d %5ld %9lf %9lf %8lf %9lf %9lf %10lf %6ld \n",
|
|
||||||
&cardnumb, &satrec.satnum, &satrec.inclo, &satrec.nodeo,
|
|
||||||
&satrec.ecco, &satrec.argpo, &satrec.mo, &satrec.no, &revnum);
|
|
||||||
} else {
|
|
||||||
sscanf(longstr2, "%2d %5ld %9lf %9lf %8lf %9lf %9lf %11lf %6ld \n",
|
|
||||||
&cardnumb, &satrec.satnum, &satrec.inclo, &satrec.nodeo,
|
|
||||||
&satrec.ecco, &satrec.argpo, &satrec.mo, &satrec.no, &revnum);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---- find no, ndot, nddot ----
|
|
||||||
satrec.no = satrec.no / xpdotp; //* rad/min
|
|
||||||
satrec.nddot = satrec.nddot * pow(10.0, nexp);
|
|
||||||
satrec.bstar = satrec.bstar * pow(10.0, ibexp);
|
|
||||||
|
|
||||||
// ---- convert to sgp4 units ----
|
|
||||||
satrec.a = pow(satrec.no * tumin, (-2.0 / 3.0));
|
|
||||||
satrec.ndot = satrec.ndot / (xpdotp * 1440.0); //* ? * minperday
|
|
||||||
satrec.nddot = satrec.nddot / (xpdotp * 1440.0 * 1440);
|
|
||||||
|
|
||||||
// ---- find standard orbital elements ----
|
|
||||||
satrec.inclo = satrec.inclo * deg2rad;
|
|
||||||
satrec.nodeo = satrec.nodeo * deg2rad;
|
|
||||||
satrec.argpo = satrec.argpo * deg2rad;
|
|
||||||
satrec.mo = satrec.mo * deg2rad;
|
|
||||||
|
|
||||||
satrec.alta = satrec.a * (1.0 + satrec.ecco) - 1.0;
|
|
||||||
satrec.altp = satrec.a * (1.0 - satrec.ecco) - 1.0;
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------
|
|
||||||
// find sgp4epoch time of element set
|
|
||||||
// remember that sgp4 uses units of days from 0 jan 1950 (sgp4epoch)
|
|
||||||
// and minutes from the epoch (time)
|
|
||||||
// ----------------------------------------------------------------
|
|
||||||
|
|
||||||
// ---------------- temp fix for years from 1957-2056 -------------------
|
|
||||||
// --------- correct fix will occur when year is 4-digit in tle ---------
|
|
||||||
if (satrec.epochyr < 57) {
|
|
||||||
year = satrec.epochyr + 2000;
|
|
||||||
} else {
|
|
||||||
year = satrec.epochyr + 1900;
|
|
||||||
}
|
|
||||||
|
|
||||||
days2mdhms(year, satrec.epochdays, mon, day, hr, minute, sec);
|
|
||||||
jday(year, mon, day, hr, minute, sec, satrec.jdsatepoch);
|
|
||||||
|
|
||||||
double unixSeconds = (satrec.jdsatepoch - 2451544.5) * 24 * 3600
|
|
||||||
+ 946684800;
|
|
||||||
|
|
||||||
epoch.tv_sec = unixSeconds;
|
|
||||||
double subseconds = unixSeconds - epoch.tv_sec;
|
|
||||||
epoch.tv_usec = subseconds * 1000000;
|
|
||||||
|
|
||||||
// ---------------- initialize the orbit at sgp4epoch -------------------
|
|
||||||
uint8_t result = sgp4init(whichconst, satrec.satnum,
|
|
||||||
satrec.jdsatepoch - 2433281.5, satrec.bstar, satrec.ecco,
|
|
||||||
satrec.argpo, satrec.inclo, satrec.mo, satrec.no, satrec.nodeo,
|
|
||||||
satrec);
|
|
||||||
|
|
||||||
if (result != 00) {
|
|
||||||
return MAKE_RETURN_CODE(result);
|
|
||||||
} else {
|
|
||||||
initialized = true;
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t Sgp4Propagator::propagate(double* position, double* velocity,
|
|
||||||
timeval time, uint8_t gpsUtcOffset) {
|
|
||||||
|
|
||||||
if (!initialized) {
|
|
||||||
return TLE_NOT_INITIALIZED;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Time since epoch in minutes
|
|
||||||
timeval timeSinceEpoch = time - epoch;
|
|
||||||
double minutesSinceEpoch = timeSinceEpoch.tv_sec / 60.
|
|
||||||
+ timeSinceEpoch.tv_usec / 60000000.;
|
|
||||||
|
|
||||||
double yearsSinceEpoch = minutesSinceEpoch / 60 / 24 / 365;
|
|
||||||
|
|
||||||
if ((yearsSinceEpoch > 1) || (yearsSinceEpoch < -1)) {
|
|
||||||
return TLE_TOO_OLD;
|
|
||||||
}
|
|
||||||
|
|
||||||
double positionTEME[3];
|
|
||||||
double velocityTEME[3];
|
|
||||||
|
|
||||||
uint8_t result = sgp4(whichconst, satrec, minutesSinceEpoch, positionTEME,
|
|
||||||
velocityTEME);
|
|
||||||
|
|
||||||
VectorOperations<double>::mulScalar(positionTEME, 1000, positionTEME, 3);
|
|
||||||
VectorOperations<double>::mulScalar(velocityTEME, 1000, velocityTEME, 3);
|
|
||||||
|
|
||||||
//Transform to ECF
|
|
||||||
double earthRotationMatrix[3][3];
|
|
||||||
CoordinateTransformations::getEarthRotationMatrix(time,
|
|
||||||
earthRotationMatrix);
|
|
||||||
|
|
||||||
MatrixOperations<double>::multiply(earthRotationMatrix[0], positionTEME,
|
|
||||||
position, 3, 3, 1);
|
|
||||||
MatrixOperations<double>::multiply(earthRotationMatrix[0], velocityTEME,
|
|
||||||
velocity, 3, 3, 1);
|
|
||||||
|
|
||||||
double omegaEarth[3] = { 0, 0, Earth::OMEGA };
|
|
||||||
double velocityCorrection[3];
|
|
||||||
VectorOperations<double>::cross(omegaEarth, position, velocityCorrection);
|
|
||||||
VectorOperations<double>::subtract(velocity, velocityCorrection, velocity);
|
|
||||||
|
|
||||||
if (result != 0) {
|
|
||||||
return MAKE_RETURN_CODE(result || 0xB0);
|
|
||||||
} else {
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,46 +0,0 @@
|
|||||||
#ifndef SGP4PROPAGATOR_H_
|
|
||||||
#define SGP4PROPAGATOR_H_
|
|
||||||
|
|
||||||
#ifndef WIN32
|
|
||||||
#include <sys/time.h>
|
|
||||||
#endif
|
|
||||||
#include "../contrib/sgp4/sgp4unit.h"
|
|
||||||
#include "../returnvalues/HasReturnvaluesIF.h"
|
|
||||||
|
|
||||||
class Sgp4Propagator {
|
|
||||||
public:
|
|
||||||
static const uint8_t INTERFACE_ID = CLASS_ID::SGP4PROPAGATOR_CLASS;
|
|
||||||
static const ReturnValue_t INVALID_ECCENTRICITY = MAKE_RETURN_CODE(0xA1);
|
|
||||||
static const ReturnValue_t INVALID_MEAN_MOTION = MAKE_RETURN_CODE(0xA2);
|
|
||||||
static const ReturnValue_t INVALID_PERTURBATION_ELEMENTS = MAKE_RETURN_CODE(0xA3);
|
|
||||||
static const ReturnValue_t INVALID_SEMI_LATUS_RECTUM = MAKE_RETURN_CODE(0xA4);
|
|
||||||
static const ReturnValue_t INVALID_EPOCH_ELEMENTS = MAKE_RETURN_CODE(0xA5);
|
|
||||||
static const ReturnValue_t SATELLITE_HAS_DECAYED = MAKE_RETURN_CODE(0xA6);
|
|
||||||
static const ReturnValue_t TLE_TOO_OLD = MAKE_RETURN_CODE(0xB1);
|
|
||||||
static const ReturnValue_t TLE_NOT_INITIALIZED = MAKE_RETURN_CODE(0xB2);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Sgp4Propagator();
|
|
||||||
virtual ~Sgp4Propagator();
|
|
||||||
|
|
||||||
ReturnValue_t initialize(const uint8_t *line1, const uint8_t *line2);
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param[out] position in ECF
|
|
||||||
* @param[out] velocity in ECF
|
|
||||||
* @param time to which to propagate
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
ReturnValue_t propagate(double *position, double *velocity, timeval time, uint8_t gpsUtcOffset);
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool initialized;
|
|
||||||
timeval epoch;
|
|
||||||
elsetrec satrec;
|
|
||||||
gravconsttype whichconst;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* SGP4PROPAGATOR_H_ */
|
|
@ -1,62 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file BCFrame.h
|
|
||||||
* @brief This file defines the BCFrame class.
|
|
||||||
* @date 24.04.2013
|
|
||||||
* @author baetz
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef BCFRAME_H_
|
|
||||||
#define BCFRAME_H_
|
|
||||||
|
|
||||||
#include "CCSDSReturnValuesIF.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Small helper class to identify a BcFrame.
|
|
||||||
* @ingroup ccsds_handling
|
|
||||||
*/
|
|
||||||
class BcFrame: public CCSDSReturnValuesIF {
|
|
||||||
private:
|
|
||||||
static const uint8_t UNLOCK_COMMAND = 0b00000000;//! Identifier for a certain BC Command.
|
|
||||||
static const uint8_t SET_V_R_1 = 0b10000010;//! Identifier for a certain BC Command.
|
|
||||||
static const uint8_t SET_V_R_2 = 0b00000000;//! Identifier for a certain BC Command.
|
|
||||||
|
|
||||||
public:
|
|
||||||
uint8_t byte1; //!< First content byte
|
|
||||||
uint8_t byte2; //!< Second content byte
|
|
||||||
uint8_t vR; //!< vR byte
|
|
||||||
/**
|
|
||||||
* Simple default constructor.
|
|
||||||
*/
|
|
||||||
BcFrame() :
|
|
||||||
byte1(0), byte2(0), vR(0) {
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Main and only useful method of the class.
|
|
||||||
* With the buffer and size information passed, the class passes the content
|
|
||||||
* and checks if it is one of the two valid BC Command Frames.
|
|
||||||
* @param inBuffer Content of the frame to check,
|
|
||||||
* @param inSize Size of the data to check.
|
|
||||||
* @return - #BC_ILLEGAL_COMMAND if it is no command.
|
|
||||||
* - #BC_IS_UNLOCK_COMMAND if it is an unlock command.
|
|
||||||
* - #BC_IS_SET_VR_COMMAND if it is such.
|
|
||||||
*/
|
|
||||||
ReturnValue_t initialize(const uint8_t* inBuffer, uint16_t inSize) {
|
|
||||||
ReturnValue_t returnValue = BC_ILLEGAL_COMMAND;
|
|
||||||
if (inSize == 1) {
|
|
||||||
byte1 = inBuffer[0];
|
|
||||||
if (byte1 == UNLOCK_COMMAND) {
|
|
||||||
returnValue = BC_IS_UNLOCK_COMMAND;
|
|
||||||
}
|
|
||||||
} else if (inSize == 3) {
|
|
||||||
byte1 = inBuffer[0];
|
|
||||||
byte2 = inBuffer[1];
|
|
||||||
vR = inBuffer[2];
|
|
||||||
if (byte1 == SET_V_R_1 && byte2 == SET_V_R_2) {
|
|
||||||
returnValue = BC_IS_SET_VR_COMMAND;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return returnValue;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* BCFRAME_H_ */
|
|
@ -1,56 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file CCSDSReturnValuesIF.h
|
|
||||||
* @brief This file defines the CCSDSReturnValuesIF class.
|
|
||||||
* @date 24.04.2013
|
|
||||||
* @author baetz
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef CCSDSRETURNVALUESIF_H_
|
|
||||||
#define CCSDSRETURNVALUESIF_H_
|
|
||||||
|
|
||||||
#include "../returnvalues/HasReturnvaluesIF.h"
|
|
||||||
/**
|
|
||||||
* This is a helper class to collect special return values that come up during CCSDS Handling.
|
|
||||||
* @ingroup ccsds_handling
|
|
||||||
*/
|
|
||||||
class CCSDSReturnValuesIF: public HasReturnvaluesIF {
|
|
||||||
public:
|
|
||||||
static const uint8_t INTERFACE_ID = CLASS_ID::CCSDS_HANDLER_IF; //!< Basic ID of the interface.
|
|
||||||
|
|
||||||
static const ReturnValue_t BC_IS_SET_VR_COMMAND = MAKE_RETURN_CODE( 0x01 ); //!< A value to describe a BC frame.
|
|
||||||
static const ReturnValue_t BC_IS_UNLOCK_COMMAND = MAKE_RETURN_CODE( 0x02 ); //!< A value to describe a BC frame.
|
|
||||||
static const ReturnValue_t BC_ILLEGAL_COMMAND = MAKE_RETURN_CODE( 0xB0 );//!< A value to describe an illegal BC frame.
|
|
||||||
static const ReturnValue_t BOARD_READING_NOT_FINISHED = MAKE_RETURN_CODE( 0xB1 ); //! The CCSDS Board is not yet finished reading, it requires another cycle.
|
|
||||||
|
|
||||||
static const ReturnValue_t NS_POSITIVE_W = MAKE_RETURN_CODE( 0xF0 );//!< NS is in the positive window
|
|
||||||
static const ReturnValue_t NS_NEGATIVE_W = MAKE_RETURN_CODE( 0xF1 );//!< NS is in the negative window
|
|
||||||
static const ReturnValue_t NS_LOCKOUT = MAKE_RETURN_CODE( 0xF2 ); //!< NS is in lockout state
|
|
||||||
static const ReturnValue_t FARM_IN_LOCKOUT = MAKE_RETURN_CODE( 0xF3 );//!< FARM-1 is currently in lockout state
|
|
||||||
static const ReturnValue_t FARM_IN_WAIT = MAKE_RETURN_CODE( 0xF4 ); //!< FARM-1 is currently in wait state
|
|
||||||
|
|
||||||
static const ReturnValue_t WRONG_SYMBOL = MAKE_RETURN_CODE( 0xE0 ); //!< An error code in the FrameFinder.
|
|
||||||
static const ReturnValue_t DOUBLE_START = MAKE_RETURN_CODE( 0xE1 ); //!< An error code in the FrameFinder.
|
|
||||||
static const ReturnValue_t START_SYMBOL_MISSED = MAKE_RETURN_CODE( 0xE2 );//!< An error code in the FrameFinder.
|
|
||||||
static const ReturnValue_t END_WITHOUT_START = MAKE_RETURN_CODE( 0xE3 );//!< An error code in the FrameFinder.
|
|
||||||
static const ReturnValue_t TOO_LARGE = MAKE_RETURN_CODE( 0xE4 );//!< An error code for a frame.
|
|
||||||
static const ReturnValue_t TOO_SHORT = MAKE_RETURN_CODE( 0xE5 );//!< An error code for a frame.
|
|
||||||
static const ReturnValue_t WRONG_TF_VERSION = MAKE_RETURN_CODE( 0xE6 ); //!< An error code for a frame.
|
|
||||||
static const ReturnValue_t WRONG_SPACECRAFT_ID = MAKE_RETURN_CODE( 0xE7 );//!< An error code for a frame.
|
|
||||||
static const ReturnValue_t NO_VALID_FRAME_TYPE = MAKE_RETURN_CODE( 0xE8 );//!< An error code for a frame.
|
|
||||||
static const ReturnValue_t CRC_FAILED = MAKE_RETURN_CODE( 0xE9 );//!< An error code for a frame.
|
|
||||||
static const ReturnValue_t VC_NOT_FOUND = MAKE_RETURN_CODE( 0xEA ); //!< An error code for a frame.
|
|
||||||
static const ReturnValue_t FORWARDING_FAILED = MAKE_RETURN_CODE( 0xEB );//!< An error code for a frame.
|
|
||||||
static const ReturnValue_t CONTENT_TOO_LARGE = MAKE_RETURN_CODE( 0xEC );//!< An error code for a frame.
|
|
||||||
static const ReturnValue_t RESIDUAL_DATA = MAKE_RETURN_CODE( 0xED );//!< An error code for a frame.
|
|
||||||
static const ReturnValue_t DATA_CORRUPTED = MAKE_RETURN_CODE( 0xEE );//!< An error code for a frame.
|
|
||||||
static const ReturnValue_t ILLEGAL_SEGMENTATION_FLAG = MAKE_RETURN_CODE( 0xEF );//!< An error code for a frame.
|
|
||||||
static const ReturnValue_t ILLEGAL_FLAG_COMBINATION = MAKE_RETURN_CODE( 0xD0 ); //!< An error code for a frame.
|
|
||||||
static const ReturnValue_t SHORTER_THAN_HEADER = MAKE_RETURN_CODE( 0xD1 ); //!< An error code for a frame.
|
|
||||||
static const ReturnValue_t TOO_SHORT_BLOCKED_PACKET = MAKE_RETURN_CODE( 0xD2 ); //!< An error code for a frame.
|
|
||||||
static const ReturnValue_t TOO_SHORT_MAP_EXTRACTION = MAKE_RETURN_CODE( 0xD3 ); //!< An error code for a frame.
|
|
||||||
|
|
||||||
virtual ~CCSDSReturnValuesIF() {
|
|
||||||
} //!< Empty virtual destructor
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* CCSDSRETURNVALUESIF_H_ */
|
|
@ -1,12 +0,0 @@
|
|||||||
target_sources(${LIB_FSFW_NAME}
|
|
||||||
PRIVATE
|
|
||||||
Clcw.cpp
|
|
||||||
DataLinkLayer.cpp
|
|
||||||
Farm1StateLockout.cpp
|
|
||||||
Farm1StateOpen.cpp
|
|
||||||
Farm1StateWait.cpp
|
|
||||||
MapPacketExtraction.cpp
|
|
||||||
TcTransferFrame.cpp
|
|
||||||
TcTransferFrameLocal.cpp
|
|
||||||
VirtualChannelReception.cpp
|
|
||||||
)
|
|
@ -1,65 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file Clcw.cpp
|
|
||||||
* @brief This file defines the Clcw class.
|
|
||||||
* @date 17.04.2013
|
|
||||||
* @author baetz
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include "Clcw.h"
|
|
||||||
#include "../serviceinterface/ServiceInterfaceStream.h"
|
|
||||||
|
|
||||||
Clcw::Clcw() {
|
|
||||||
content.raw = 0;
|
|
||||||
content.status = STATUS_FIELD_DEFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
Clcw::~Clcw() {
|
|
||||||
}
|
|
||||||
|
|
||||||
void Clcw::setVirtualChannel(uint8_t setChannel) {
|
|
||||||
content.virtualChannelIdSpare = ((setChannel & 0x3F) << 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Clcw::setLockoutFlag(bool lockout) {
|
|
||||||
content.flags = (content.flags & LOCKOUT_FLAG_MASK) | (lockout << LOCKOUT_FLAG_POSITION);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Clcw::setWaitFlag(bool waitFlag) {
|
|
||||||
content.flags = (content.flags & WAIT_FLAG_MASK) | (waitFlag << WAIT_FLAG_POSITION);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Clcw::setRetransmitFlag(bool retransmitFlag) {
|
|
||||||
content.flags = (content.flags & RETRANSMIT_FLAG_MASK) | (retransmitFlag << RETRANSMIT_FLAG_POSITION);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Clcw::setFarmBCount(uint8_t count) {
|
|
||||||
content.flags = (content.flags & FARM_B_COUNT_MASK) | ((count & 0x03) << 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Clcw::setReceiverFrameSequenceNumber(uint8_t vR) {
|
|
||||||
content.vRValue = vR;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t Clcw::getAsWhole() {
|
|
||||||
return content.raw;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Clcw::setRFAvailable(bool rfAvailable) {
|
|
||||||
content.flags = (content.flags & NO_RF_AVIALABLE_MASK) | (!rfAvailable << NO_RF_AVIALABLE_POSITION);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Clcw::setBitLock(bool bitLock) {
|
|
||||||
content.flags = (content.flags & NO_BIT_LOCK_MASK) | (!bitLock << NO_BIT_LOCK_POSITION);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Clcw::print() {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::debug << "Clcw::print: Clcw is: " << std::hex << getAsWhole() << std::dec << std::endl;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void Clcw::setWhole(uint32_t rawClcw) {
|
|
||||||
content.raw = rawClcw;
|
|
||||||
}
|
|
@ -1,66 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file Clcw.h
|
|
||||||
* @brief This file defines the Clcw class.
|
|
||||||
* @date 17.04.2013
|
|
||||||
* @author baetz
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef CLCW_H_
|
|
||||||
#define CLCW_H_
|
|
||||||
|
|
||||||
#include "ClcwIF.h"
|
|
||||||
/**
|
|
||||||
* Small helper method to handle the Clcw values.
|
|
||||||
* It has a content struct that manages the register and can be set externally.
|
|
||||||
* @ingroup ccsds_handling
|
|
||||||
*/
|
|
||||||
class Clcw : public ClcwIF {
|
|
||||||
private:
|
|
||||||
static const uint8_t STATUS_FIELD_DEFAULT = 0b00000001; //!< Default for the status field.
|
|
||||||
static const uint8_t NO_RF_AVIALABLE_POSITION = 7; //!< Position of a flag in the register (starting with 0).
|
|
||||||
static const uint8_t NO_BIT_LOCK_POSITION = 6; //!< Position of a flag in the register (starting with 0).
|
|
||||||
static const uint8_t LOCKOUT_FLAG_POSITION = 5; //!< Position of a flag in the register (starting with 0).
|
|
||||||
static const uint8_t WAIT_FLAG_POSITION = 4; //!< Position of a flag in the register (starting with 0).
|
|
||||||
static const uint8_t RETRANSMIT_FLAG_POSITION = 3; //!< Position of a flag in the register (starting with 0).
|
|
||||||
static const uint8_t NO_RF_AVIALABLE_MASK = 0xFF xor (1 << NO_RF_AVIALABLE_POSITION); //!< Mask for a flag in the register.
|
|
||||||
static const uint8_t NO_BIT_LOCK_MASK = 0xFF xor (1 << NO_BIT_LOCK_POSITION); //!< Mask for a flag in the register.
|
|
||||||
static const uint8_t LOCKOUT_FLAG_MASK = 0xFF xor (1 << LOCKOUT_FLAG_POSITION); //!< Mask for a flag in the register.
|
|
||||||
static const uint8_t WAIT_FLAG_MASK = 0xFF xor (1 << WAIT_FLAG_POSITION); //!< Mask for a flag in the register.
|
|
||||||
static const uint8_t RETRANSMIT_FLAG_MASK = 0xFF xor (1 << RETRANSMIT_FLAG_POSITION); //!< Mask for a flag in the register.
|
|
||||||
static const uint8_t FARM_B_COUNT_MASK = 0b11111001; //!< Mask for a counter in the register.
|
|
||||||
/**
|
|
||||||
* This is the data structure of the CLCW register.
|
|
||||||
*/
|
|
||||||
union clcwContent {
|
|
||||||
uint32_t raw;
|
|
||||||
struct {
|
|
||||||
uint8_t status;
|
|
||||||
uint8_t virtualChannelIdSpare;
|
|
||||||
uint8_t flags;
|
|
||||||
uint8_t vRValue;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
clcwContent content; //!< Represents the content of the register.
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* The constructor sets everything to default values.
|
|
||||||
*/
|
|
||||||
Clcw();
|
|
||||||
/**
|
|
||||||
* Nothing happens in the destructor.
|
|
||||||
*/
|
|
||||||
~Clcw();
|
|
||||||
void setVirtualChannel( uint8_t setChannel );
|
|
||||||
void setLockoutFlag( bool lockout );
|
|
||||||
void setWaitFlag( bool waitFlag );
|
|
||||||
void setRetransmitFlag( bool retransmitFlag );
|
|
||||||
void setFarmBCount( uint8_t count );
|
|
||||||
void setReceiverFrameSequenceNumber( uint8_t vR );
|
|
||||||
void setRFAvailable( bool rfAvailable );
|
|
||||||
void setBitLock( bool bitLock );
|
|
||||||
uint32_t getAsWhole();
|
|
||||||
void setWhole( uint32_t rawClcw );
|
|
||||||
void print();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* CLCW_H_ */
|
|
@ -1,70 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file ClcwIF.h
|
|
||||||
* @brief This file defines the ClcwIF class.
|
|
||||||
* @date 17.04.2013
|
|
||||||
* @author baetz
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef CLCWIF_H_
|
|
||||||
#define CLCWIF_H_
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface to manage a CLCW register.
|
|
||||||
* @ingroup ccsds_handling
|
|
||||||
*/
|
|
||||||
class ClcwIF {
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Empty virtual destructor.
|
|
||||||
*/
|
|
||||||
virtual ~ClcwIF() { }
|
|
||||||
/**
|
|
||||||
* Simple setter.
|
|
||||||
* @param setChannel The virtual channel id to set.
|
|
||||||
*/
|
|
||||||
virtual void setVirtualChannel( uint8_t setChannel ) = 0;
|
|
||||||
/**
|
|
||||||
* Simple setter.
|
|
||||||
* @param lockout status of the flag.
|
|
||||||
*/
|
|
||||||
virtual void setLockoutFlag( bool lockout ) = 0;
|
|
||||||
/**
|
|
||||||
* Simple setter.
|
|
||||||
* @param waitFlag status of the flag.
|
|
||||||
*/
|
|
||||||
virtual void setWaitFlag( bool waitFlag ) = 0;
|
|
||||||
/**
|
|
||||||
* Simple setter.
|
|
||||||
* @param retransmitFlag status of the flag.
|
|
||||||
*/
|
|
||||||
virtual void setRetransmitFlag( bool retransmitFlag ) = 0;
|
|
||||||
/**
|
|
||||||
* Sets the farm B count.
|
|
||||||
* @param count A full 8bit counter value can be passed. Only the last three bits are used.
|
|
||||||
*/
|
|
||||||
virtual void setFarmBCount( uint8_t count ) = 0;
|
|
||||||
/**
|
|
||||||
* Simple setter.
|
|
||||||
* @param vR Value of vR.
|
|
||||||
*/
|
|
||||||
virtual void setReceiverFrameSequenceNumber( uint8_t vR ) = 0;
|
|
||||||
/**
|
|
||||||
* Returns the register as a full 32bit value.
|
|
||||||
* @return The value.
|
|
||||||
*/
|
|
||||||
virtual uint32_t getAsWhole() = 0;
|
|
||||||
/**
|
|
||||||
* Sets the whole content to this value.
|
|
||||||
* @param rawClcw The value to set the content.
|
|
||||||
*/
|
|
||||||
virtual void setWhole( uint32_t rawClcw ) = 0;
|
|
||||||
/**
|
|
||||||
* Debug method to print the CLCW.
|
|
||||||
*/
|
|
||||||
virtual void print() = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* CLCWIF_H_ */
|
|
@ -1,143 +0,0 @@
|
|||||||
#include "DataLinkLayer.h"
|
|
||||||
#include "../globalfunctions/CRC.h"
|
|
||||||
#include "../serviceinterface/ServiceInterfaceStream.h"
|
|
||||||
|
|
||||||
DataLinkLayer::DataLinkLayer(uint8_t* set_frame_buffer, ClcwIF* setClcw,
|
|
||||||
uint8_t set_start_sequence_length, uint16_t set_scid) :
|
|
||||||
spacecraftId(set_scid), frameBuffer(set_frame_buffer), clcw(setClcw), receivedDataLength(0), currentFrame(
|
|
||||||
NULL), startSequenceLength(set_start_sequence_length) {
|
|
||||||
//Nothing to do except from setting the values above.
|
|
||||||
}
|
|
||||||
|
|
||||||
DataLinkLayer::~DataLinkLayer() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t DataLinkLayer::frameDelimitingAndFillRemoval() {
|
|
||||||
if ((receivedDataLength - startSequenceLength) < FRAME_PRIMARY_HEADER_LENGTH) {
|
|
||||||
return SHORTER_THAN_HEADER;
|
|
||||||
}
|
|
||||||
//Removing start sequence.
|
|
||||||
//SHOULDDO: Not implemented here.
|
|
||||||
while ( *frameBuffer == START_SEQUENCE_PATTERN ) {
|
|
||||||
frameBuffer++;
|
|
||||||
}
|
|
||||||
TcTransferFrame frame_candidate(frameBuffer);
|
|
||||||
this->currentFrame = frame_candidate; //should work with shallow copy.
|
|
||||||
|
|
||||||
return RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t DataLinkLayer::frameValidationCheck() {
|
|
||||||
//Check TF_version number
|
|
||||||
if (this->currentFrame.getVersionNumber() != FRAME_VERSION_NUMBER_DEFAULT) {
|
|
||||||
return WRONG_TF_VERSION;
|
|
||||||
}
|
|
||||||
//Check SpaceCraft ID
|
|
||||||
if (this->currentFrame.getSpacecraftId() != this->spacecraftId) {
|
|
||||||
return WRONG_SPACECRAFT_ID;
|
|
||||||
}
|
|
||||||
//Check other header limitations:
|
|
||||||
if (!this->currentFrame.bypassFlagSet() && this->currentFrame.controlCommandFlagSet()) {
|
|
||||||
return NO_VALID_FRAME_TYPE;
|
|
||||||
}
|
|
||||||
//- Spares are zero
|
|
||||||
if (!this->currentFrame.spareIsZero()) {
|
|
||||||
return NO_VALID_FRAME_TYPE;
|
|
||||||
}
|
|
||||||
//Compare detected frame length with the one in the header
|
|
||||||
uint16_t length = currentFrame.getFullSize();
|
|
||||||
if (length > receivedDataLength) {
|
|
||||||
//Frame is too long or just right
|
|
||||||
// error << "frameValidationCheck: Too short.";
|
|
||||||
// currentFrame.print();
|
|
||||||
return TOO_SHORT;
|
|
||||||
}
|
|
||||||
if (USE_CRC) {
|
|
||||||
return this->frameCheckCRC();
|
|
||||||
}
|
|
||||||
return RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t DataLinkLayer::frameCheckCRC() {
|
|
||||||
uint16_t checkValue = CRC::crc16ccitt(this->currentFrame.getFullFrame(),
|
|
||||||
this->currentFrame.getFullSize());
|
|
||||||
if (checkValue == 0) {
|
|
||||||
return RETURN_OK;
|
|
||||||
} else {
|
|
||||||
return CRC_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t DataLinkLayer::allFramesReception() {
|
|
||||||
ReturnValue_t status = this->frameDelimitingAndFillRemoval();
|
|
||||||
if (status != RETURN_OK) {
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
return this->frameValidationCheck();
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t DataLinkLayer::masterChannelDemultiplexing() {
|
|
||||||
//Nothing to do at present. Ideally, there would be a map of MCID's identifying which MC to use.
|
|
||||||
return virtualChannelDemultiplexing();
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t DataLinkLayer::virtualChannelDemultiplexing() {
|
|
||||||
uint8_t vcId = currentFrame.getVirtualChannelId();
|
|
||||||
virtualChannelIterator iter = virtualChannels.find(vcId);
|
|
||||||
if (iter == virtualChannels.end()) {
|
|
||||||
//Do not report because passive board will get this error all the time.
|
|
||||||
return RETURN_OK;
|
|
||||||
} else {
|
|
||||||
return (iter->second)->frameAcceptanceAndReportingMechanism(¤tFrame, clcw);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t DataLinkLayer::processFrame(uint16_t length) {
|
|
||||||
receivedDataLength = length;
|
|
||||||
ReturnValue_t status = allFramesReception();
|
|
||||||
if (status != RETURN_OK) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "DataLinkLayer::processFrame: frame reception failed. "
|
|
||||||
"Error code: " << std::hex << status << std::dec << std::endl;
|
|
||||||
#endif
|
|
||||||
// currentFrame.print();
|
|
||||||
return status;
|
|
||||||
} else {
|
|
||||||
return masterChannelDemultiplexing();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t DataLinkLayer::addVirtualChannel(uint8_t virtualChannelId,
|
|
||||||
VirtualChannelReceptionIF* object) {
|
|
||||||
std::pair<virtualChannelIterator, bool> returnValue = virtualChannels.insert(
|
|
||||||
std::pair<uint8_t, VirtualChannelReceptionIF*>(virtualChannelId, object));
|
|
||||||
if (returnValue.second == true) {
|
|
||||||
return RETURN_OK;
|
|
||||||
} else {
|
|
||||||
return RETURN_FAILED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t DataLinkLayer::initialize() {
|
|
||||||
ReturnValue_t returnValue = RETURN_FAILED;
|
|
||||||
//Set Virtual Channel ID to first virtual channel instance in this DataLinkLayer instance to avoid faulty information (e.g. 0) in the VCID.
|
|
||||||
if ( virtualChannels.begin() != virtualChannels.end() ) {
|
|
||||||
clcw->setVirtualChannel( virtualChannels.begin()->second->getChannelId() );
|
|
||||||
} else {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "DataLinkLayer::initialize: No VC assigned to this DLL instance! " << std::endl;
|
|
||||||
#endif
|
|
||||||
return RETURN_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (virtualChannelIterator iterator = virtualChannels.begin();
|
|
||||||
iterator != virtualChannels.end(); iterator++) {
|
|
||||||
returnValue = iterator->second->initialize();
|
|
||||||
if (returnValue != RETURN_OK)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return returnValue;
|
|
||||||
|
|
||||||
}
|
|
@ -1,112 +0,0 @@
|
|||||||
#ifndef DATALINKLAYER_H_
|
|
||||||
#define DATALINKLAYER_H_
|
|
||||||
|
|
||||||
#include "CCSDSReturnValuesIF.h"
|
|
||||||
#include "ClcwIF.h"
|
|
||||||
#include "TcTransferFrame.h"
|
|
||||||
#include "VirtualChannelReceptionIF.h"
|
|
||||||
#include "../events/Event.h"
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
|
|
||||||
class VirtualChannelReception;
|
|
||||||
/**
|
|
||||||
* A complete representation of the CCSDS Data Link Layer.
|
|
||||||
* The operations of this layer are defined in the CCSDS TC Space Data Link Protocol
|
|
||||||
* document. It is configured to handle a VC Demultiplexing function. All reception
|
|
||||||
* steps are performed.
|
|
||||||
*/
|
|
||||||
class DataLinkLayer : public CCSDSReturnValuesIF {
|
|
||||||
public:
|
|
||||||
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::SYSTEM_1;
|
|
||||||
static const Event RF_AVAILABLE = MAKE_EVENT(0, severity::INFO); //!< A RF available signal was detected. P1: raw RFA state, P2: 0
|
|
||||||
static const Event RF_LOST = MAKE_EVENT(1, severity::INFO); //!< A previously found RF available signal was lost. P1: raw RFA state, P2: 0
|
|
||||||
static const Event BIT_LOCK = MAKE_EVENT(2, severity::INFO); //!< A Bit Lock signal. Was detected. P1: raw BLO state, P2: 0
|
|
||||||
static const Event BIT_LOCK_LOST = MAKE_EVENT(3, severity::INFO); //!< A previously found Bit Lock signal was lost. P1: raw BLO state, P2: 0
|
|
||||||
// static const Event RF_CHAIN_LOST = MAKE_EVENT(4, severity::INFO); //!< The CCSDS Board detected that either bit lock or RF available or both are lost. No parameters.
|
|
||||||
static const Event FRAME_PROCESSING_FAILED = MAKE_EVENT(5, severity::LOW); //!< The CCSDS Board could not interpret a TC
|
|
||||||
/**
|
|
||||||
* The Constructor sets the passed parameters and nothing else.
|
|
||||||
* @param set_frame_buffer The buffer in which incoming frame candidates are stored.
|
|
||||||
* @param setClcw The CLCW class to work on when returning CLCW information.
|
|
||||||
* @param set_start_sequence_length Length of the Start sequence in front of every TC Transfer Frame.
|
|
||||||
* @param set_scid The SCID to operate on.
|
|
||||||
*/
|
|
||||||
DataLinkLayer( uint8_t* set_frame_buffer, ClcwIF* setClcw, uint8_t set_start_sequence_length, uint16_t set_scid );
|
|
||||||
/**
|
|
||||||
* Empty virtual destructor.
|
|
||||||
*/
|
|
||||||
~DataLinkLayer();
|
|
||||||
/**
|
|
||||||
* This method tries to process a frame that is placed in #frameBuffer.
|
|
||||||
* The procedures described in the Standard are performed.
|
|
||||||
* @param length Length of the incoming frame candidate.
|
|
||||||
* @return @c RETURN_OK on successful handling, otherwise the return codes of the higher methods.
|
|
||||||
*/
|
|
||||||
ReturnValue_t processFrame( uint16_t length );
|
|
||||||
/**
|
|
||||||
* Configuration method to add a new TC Virtual Channel.
|
|
||||||
* Shall only be called during initialization. As soon as the method was called, the layer can
|
|
||||||
* handle Frames directed to this VC.
|
|
||||||
* @param virtualChannelId Id of the VC. Shall be smaller than 64.
|
|
||||||
* @param object Reference to the object that handles the Frame.
|
|
||||||
* @return @c RETURN_OK on success, @c RETURN_FAILED otherwise.
|
|
||||||
*/
|
|
||||||
ReturnValue_t addVirtualChannel( uint8_t virtualChannelId, VirtualChannelReceptionIF* object );
|
|
||||||
/**
|
|
||||||
* The initialization method calls the @c initialize routine of all virtual channels.
|
|
||||||
* @return The return code of the first failed VC initialization or @c RETURN_OK.
|
|
||||||
*/
|
|
||||||
ReturnValue_t initialize();
|
|
||||||
private:
|
|
||||||
typedef std::map<uint8_t, VirtualChannelReceptionIF*>::iterator virtualChannelIterator; //!< Typedef to simplify handling the #virtualChannels map.
|
|
||||||
static const uint8_t FRAME_VERSION_NUMBER_DEFAULT = 0x00; //!< Constant for the default value of Frame Version Numbers.
|
|
||||||
static const uint8_t FRAME_PRIMARY_HEADER_LENGTH = 5; //!< Length of the frame's primary header.
|
|
||||||
static const uint8_t START_SEQUENCE_PATTERN = 0x00; //!< The start sequence pattern which might be with the frame.
|
|
||||||
static const bool USE_CRC = true; //!< A global, so called "Managed Parameter" that identifies if incoming frames have CRC's or not.
|
|
||||||
uint16_t spacecraftId; //!< The Space Craft Identifier (SCID) configured.
|
|
||||||
uint8_t* frameBuffer; //!< A pointer to point to the current incoming frame.
|
|
||||||
ClcwIF* clcw; //!< Pointer to store the CLCW to work on.
|
|
||||||
uint16_t receivedDataLength; //!< Stores the length of the currently processed frame.
|
|
||||||
TcTransferFrame currentFrame; //!< Stores a more convenient access to the current frame.
|
|
||||||
uint8_t startSequenceLength; //!< Configured length of the start sequence. Maybe this must be done more variable.
|
|
||||||
std::map<uint8_t, VirtualChannelReceptionIF*> virtualChannels; //!< Map of all virtual channels assigned.
|
|
||||||
/**
|
|
||||||
* Method that performs all possible frame validity checks (as specified).
|
|
||||||
* @return Various error codes or @c RETURN_OK on success.
|
|
||||||
*/
|
|
||||||
ReturnValue_t frameValidationCheck();
|
|
||||||
/**
|
|
||||||
* First method to call.
|
|
||||||
* Removes start sequence bytes and checks if the complete frame was received.
|
|
||||||
* SHOULDDO: Maybe handling the start sequence must be done more variable.
|
|
||||||
* @return @c RETURN_OK or @c TOO_SHORT.
|
|
||||||
*/
|
|
||||||
ReturnValue_t frameDelimitingAndFillRemoval();
|
|
||||||
/**
|
|
||||||
* Small helper method to check the CRC of the Frame.
|
|
||||||
* @return @c RETURN_OK or @c CRC_FAILED.
|
|
||||||
*/
|
|
||||||
ReturnValue_t frameCheckCRC();
|
|
||||||
/**
|
|
||||||
* Method that groups the reception process of all Frames.
|
|
||||||
* Calls #frameDelimitingAndFillRemoval and #frameValidationCheck.
|
|
||||||
* @return The return codes of the sub calls.
|
|
||||||
*/
|
|
||||||
ReturnValue_t allFramesReception();
|
|
||||||
/**
|
|
||||||
* Dummy method for master channel demultiplexing.
|
|
||||||
* As there's only one Master Channel here, the method calls #virtualChannelDemultiplexing.
|
|
||||||
* @return The return codes of #virtualChannelDemultiplexing.
|
|
||||||
*/
|
|
||||||
ReturnValue_t masterChannelDemultiplexing();
|
|
||||||
/**
|
|
||||||
* Method to demultiplex the Frames to Virtual Channels (VC's).
|
|
||||||
* Looks up the requested VC in #virtualChannels and forwards the Frame to its
|
|
||||||
* #frameAcceptanceAndReportingMechanism method, if found.
|
|
||||||
* @return The higher method codes or @c VC_NOT_FOUND.
|
|
||||||
*/
|
|
||||||
ReturnValue_t virtualChannelDemultiplexing();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* DATALINKLAYER_H_ */
|
|
@ -1,54 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file Farm1StateIF.h
|
|
||||||
* @brief This file defines the Farm1StateIF class.
|
|
||||||
* @date 24.04.2013
|
|
||||||
* @author baetz
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef FARM1STATEIF_H_
|
|
||||||
#define FARM1STATEIF_H_
|
|
||||||
|
|
||||||
#include "CCSDSReturnValuesIF.h"
|
|
||||||
class VirtualChannelReception;
|
|
||||||
class TcTransferFrame;
|
|
||||||
class ClcwIF;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is the interface for states of the FARM-1 state machine.
|
|
||||||
* Classes implementing this interface can be used as FARM-1 states. This is a simple implementation
|
|
||||||
* of the state pattern.
|
|
||||||
*/
|
|
||||||
class Farm1StateIF : public CCSDSReturnValuesIF {
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* A method that shall handle an incoming frame as AD Frame.
|
|
||||||
* @param frame The frame to handle.
|
|
||||||
* @param clcw Any changes to the CLCW shall be done with the help of this interface.
|
|
||||||
* @return If forwarding to a MAP Channel is required, the return value shall be #FRAME_OK.
|
|
||||||
* Otherwise, an appropriate return value or error code shall be generated.
|
|
||||||
*/
|
|
||||||
virtual ReturnValue_t handleADFrame( TcTransferFrame* frame, ClcwIF* clcw ) = 0;
|
|
||||||
/**
|
|
||||||
* This method shall handle frames that have been successfully identified as BC Unlock frames.
|
|
||||||
* @param clcw Any changes to the CLCW shall be done with the help of this interface.
|
|
||||||
* @return If forwarding to a MAP Channel is required, the return value shall be #FRAME_OK.
|
|
||||||
* Otherwise, an appropriate return value or error code shall be generated.
|
|
||||||
*/
|
|
||||||
virtual ReturnValue_t handleBCUnlockCommand( ClcwIF* clcw ) = 0;
|
|
||||||
/**
|
|
||||||
* This method shall handle frames that have been successfully identified as BC Set VR frames.
|
|
||||||
* @param clcw Any changes to the CLCW shall be done with the help of this interface.
|
|
||||||
* @param vr The V(r) value found in the frame.
|
|
||||||
* @return If forwarding to a MAP Channel is required, the return value shall be #FRAME_OK.
|
|
||||||
* Otherwise, an appropriate return value or error code shall be generated.
|
|
||||||
*/
|
|
||||||
virtual ReturnValue_t handleBCSetVrCommand( ClcwIF* clcw, uint8_t vr ) = 0;
|
|
||||||
/**
|
|
||||||
* Empty virtual destructor.
|
|
||||||
*/
|
|
||||||
virtual ~Farm1StateIF() {
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* FARM1STATEIF_H_ */
|
|
@ -1,35 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file Farm1StateLockout.cpp
|
|
||||||
* @brief This file defines the Farm1StateLockout class.
|
|
||||||
* @date 24.04.2013
|
|
||||||
* @author baetz
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include "ClcwIF.h"
|
|
||||||
#include "Farm1StateLockout.h"
|
|
||||||
#include "TcTransferFrame.h"
|
|
||||||
#include "VirtualChannelReception.h"
|
|
||||||
Farm1StateLockout::Farm1StateLockout(VirtualChannelReception* setMyVC) : myVC(setMyVC) {
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t Farm1StateLockout::handleADFrame(TcTransferFrame* frame,
|
|
||||||
ClcwIF* clcw) {
|
|
||||||
return FARM_IN_LOCKOUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t Farm1StateLockout::handleBCUnlockCommand(ClcwIF* clcw) {
|
|
||||||
myVC->farmBCounter++;
|
|
||||||
clcw->setRetransmitFlag(false);
|
|
||||||
clcw->setLockoutFlag( false );
|
|
||||||
clcw->setWaitFlag( false );
|
|
||||||
myVC->currentState = &(myVC->openState);
|
|
||||||
return BC_IS_UNLOCK_COMMAND;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t Farm1StateLockout::handleBCSetVrCommand(ClcwIF* clcw,
|
|
||||||
uint8_t vr) {
|
|
||||||
myVC->farmBCounter++;
|
|
||||||
return BC_IS_SET_VR_COMMAND;
|
|
||||||
}
|
|
@ -1,59 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file Farm1StateLockout.h
|
|
||||||
* @brief This file defines the Farm1StateLockout class.
|
|
||||||
* @date 24.04.2013
|
|
||||||
* @author baetz
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef FARM1STATELOCKOUT_H_
|
|
||||||
#define FARM1STATELOCKOUT_H_
|
|
||||||
|
|
||||||
#include "Farm1StateIF.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class represents the FARM-1 "Lockout" State.
|
|
||||||
* The Lockout state is reached if the received Transfer Frame Sequence Number is completely wrong
|
|
||||||
* (i.e. within the Lockout Window). No AD Frames are forwarded. To leave the State, a BC Unlock
|
|
||||||
* command is required.
|
|
||||||
*/
|
|
||||||
class Farm1StateLockout : public Farm1StateIF {
|
|
||||||
private:
|
|
||||||
/**
|
|
||||||
* This is a reference to the "owner" class the State works on.
|
|
||||||
*/
|
|
||||||
VirtualChannelReception* myVC;
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* The default constructor if the State.
|
|
||||||
* Sets the "owner" of the State.
|
|
||||||
* @param setMyVC The "owner" class.
|
|
||||||
*/
|
|
||||||
Farm1StateLockout( VirtualChannelReception* setMyVC );
|
|
||||||
/**
|
|
||||||
* All AD Frames are rejected with FARM_IN_LOCKOUT
|
|
||||||
* @param frame The frame to handle.
|
|
||||||
* @param clcw Any changes to the CLCW shall be done with the help of this interface.
|
|
||||||
* @return FARM_IN_LOCKOUT
|
|
||||||
*/
|
|
||||||
ReturnValue_t handleADFrame( TcTransferFrame* frame, ClcwIF* clcw );
|
|
||||||
/**
|
|
||||||
* These commands are handled as specified.
|
|
||||||
* State changes to Farm1StateOpen.
|
|
||||||
* @param clcw Any changes to the CLCW shall be done with the help of this interface.
|
|
||||||
* @return As the frame needs no forwarding to a MAP Channel, #BC_IS_UNLOCK_COMMAND
|
|
||||||
* is returned.
|
|
||||||
*/
|
|
||||||
ReturnValue_t handleBCUnlockCommand( ClcwIF* clcw );
|
|
||||||
/**
|
|
||||||
* These commands are handled as specified.
|
|
||||||
* The V(r) value is not set in Lockout State, even though the Command itself is accepted.
|
|
||||||
* @param clcw Any changes to the CLCW shall be done with the help of this interface.
|
|
||||||
* @param vr The V(r) value found in the frame.
|
|
||||||
* @return As the frame needs no forwarding to a MAP Channel, #BC_IS_SET_VR_COMMAND
|
|
||||||
* is returned.
|
|
||||||
*/
|
|
||||||
ReturnValue_t handleBCSetVrCommand( ClcwIF* clcw, uint8_t vr );
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* FARM1STATELOCKOUT_H_ */
|
|
@ -1,49 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file Farm1StateOpen.cpp
|
|
||||||
* @brief This file defines the Farm1StateOpen class.
|
|
||||||
* @date 24.04.2013
|
|
||||||
* @author baetz
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include "ClcwIF.h"
|
|
||||||
#include "Farm1StateOpen.h"
|
|
||||||
#include "TcTransferFrame.h"
|
|
||||||
#include "VirtualChannelReception.h"
|
|
||||||
|
|
||||||
Farm1StateOpen::Farm1StateOpen(VirtualChannelReception* setMyVC) : myVC(setMyVC) {
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t Farm1StateOpen::handleADFrame(TcTransferFrame* frame,
|
|
||||||
ClcwIF* clcw) {
|
|
||||||
int8_t diff = frame->getSequenceNumber() - myVC->vR;
|
|
||||||
if (diff == 0 ) {
|
|
||||||
myVC->vR++;
|
|
||||||
clcw->setRetransmitFlag(false);
|
|
||||||
return RETURN_OK;
|
|
||||||
} else if (diff < myVC->positiveWindow && diff > 0 ) {
|
|
||||||
clcw->setRetransmitFlag(true);
|
|
||||||
return NS_POSITIVE_W;
|
|
||||||
} else if (diff < 0 && diff >= -myVC->negativeWindow) {
|
|
||||||
return NS_NEGATIVE_W;
|
|
||||||
} else {
|
|
||||||
clcw->setLockoutFlag(true);
|
|
||||||
myVC->currentState = &(myVC->lockoutState);
|
|
||||||
return NS_LOCKOUT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t Farm1StateOpen::handleBCUnlockCommand( ClcwIF* clcw ) {
|
|
||||||
myVC->farmBCounter++;
|
|
||||||
clcw->setRetransmitFlag(false);
|
|
||||||
return BC_IS_UNLOCK_COMMAND;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t Farm1StateOpen::handleBCSetVrCommand( ClcwIF* clcw, uint8_t vr ) {
|
|
||||||
myVC->farmBCounter++;
|
|
||||||
clcw->setRetransmitFlag(false);
|
|
||||||
myVC->vR = vr;
|
|
||||||
return BC_IS_SET_VR_COMMAND;
|
|
||||||
}
|
|
@ -1,62 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file Farm1StateOpen.h
|
|
||||||
* @brief This file defines the Farm1StateOpen class.
|
|
||||||
* @date 24.04.2013
|
|
||||||
* @author baetz
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef FARM1STATEOPEN_H_
|
|
||||||
#define FARM1STATEOPEN_H_
|
|
||||||
|
|
||||||
#include "Farm1StateIF.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class represents the FARM-1 "Open" State.
|
|
||||||
* The Open state is the state of normal operation. It handles all types of frames,
|
|
||||||
* including AD Frames. If a wrong Frame Sequence Number is detected in an AD Frame, the
|
|
||||||
* State reacts as specified.
|
|
||||||
*/
|
|
||||||
class Farm1StateOpen : public Farm1StateIF {
|
|
||||||
private:
|
|
||||||
/**
|
|
||||||
* This is a reference to the "owner" class the State works on.
|
|
||||||
*/
|
|
||||||
VirtualChannelReception* myVC;
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* The default constructor if the State.
|
|
||||||
* Sets the "owner" of the State.
|
|
||||||
* @param setMyVC The "owner" class.
|
|
||||||
*/
|
|
||||||
Farm1StateOpen( VirtualChannelReception* setMyVC );
|
|
||||||
/**
|
|
||||||
* Method to check the validity of AD Frames.
|
|
||||||
* It checks the Frame Sequence Number and reacts as specified in the standard. The state may
|
|
||||||
* change to Farm1StateLockout.
|
|
||||||
* @param frame The frame to handle.
|
|
||||||
* @param clcw Any changes to the CLCW shall be done with the help of this interface.
|
|
||||||
* @return If the Sequence Number is ok, it returns #RETURN_OK. Otherwise either #NS_POSITIVE_W,
|
|
||||||
* #NS_NEGATIVE_W or NS_LOCKOUT is returned.
|
|
||||||
*/
|
|
||||||
ReturnValue_t handleADFrame( TcTransferFrame* frame, ClcwIF* clcw );
|
|
||||||
/**
|
|
||||||
* These commands are handled as specified.
|
|
||||||
* State does not change.
|
|
||||||
* @param clcw Any changes to the CLCW shall be done with the help of this interface.
|
|
||||||
* @return As the frame needs no forwarding to a MAP Channel, #BC_IS_UNLOCK_COMMAND
|
|
||||||
* is returned.
|
|
||||||
*/
|
|
||||||
ReturnValue_t handleBCUnlockCommand( ClcwIF* clcw );
|
|
||||||
/**
|
|
||||||
* These commands are handled as specified.
|
|
||||||
* State does not change.
|
|
||||||
* @param clcw Any changes to the CLCW shall be done with the help of this interface.
|
|
||||||
* @param vr The V(r) value found in the frame.
|
|
||||||
* @return As the frame needs no forwarding to a MAP Channel, #BC_IS_SET_VR_COMMAND
|
|
||||||
* is returned.
|
|
||||||
*/
|
|
||||||
ReturnValue_t handleBCSetVrCommand( ClcwIF* clcw, uint8_t vr );
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* FARM1STATEOPEN_H_ */
|
|
@ -1,43 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file Farm1StateWait.cpp
|
|
||||||
* @brief This file defines the Farm1StateWait class.
|
|
||||||
* @date 24.04.2013
|
|
||||||
* @author baetz
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include "ClcwIF.h"
|
|
||||||
#include "Farm1StateWait.h"
|
|
||||||
#include "TcTransferFrame.h"
|
|
||||||
#include "VirtualChannelReception.h"
|
|
||||||
|
|
||||||
Farm1StateWait::Farm1StateWait(VirtualChannelReception* setMyVC) : myVC(setMyVC) {
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t Farm1StateWait::handleADFrame(TcTransferFrame* frame,
|
|
||||||
ClcwIF* clcw) {
|
|
||||||
|
|
||||||
int8_t diff = frame->getSequenceNumber() - myVC->vR;
|
|
||||||
if ( diff < -myVC->negativeWindow || diff >= myVC->positiveWindow ) {
|
|
||||||
clcw->setLockoutFlag(true);
|
|
||||||
myVC->currentState = &(myVC->lockoutState);
|
|
||||||
}
|
|
||||||
return FARM_IN_WAIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t Farm1StateWait::handleBCUnlockCommand(ClcwIF* clcw) {
|
|
||||||
myVC->farmBCounter++;
|
|
||||||
clcw->setRetransmitFlag(false);
|
|
||||||
clcw->setWaitFlag( false );
|
|
||||||
myVC->currentState = &(myVC->openState);
|
|
||||||
return BC_IS_UNLOCK_COMMAND;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t Farm1StateWait::handleBCSetVrCommand(ClcwIF* clcw, uint8_t vr) {
|
|
||||||
myVC->farmBCounter++;
|
|
||||||
clcw->setWaitFlag( false );
|
|
||||||
clcw->setRetransmitFlag(false);
|
|
||||||
myVC->vR = vr;
|
|
||||||
myVC->currentState = &(myVC->openState);
|
|
||||||
return BC_IS_SET_VR_COMMAND;
|
|
||||||
}
|
|
@ -1,58 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file Farm1StateWait.h
|
|
||||||
* @brief This file defines the Farm1StateWait class.
|
|
||||||
* @date 24.04.2013
|
|
||||||
* @author baetz
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef FARM1STATEWAIT_H_
|
|
||||||
#define FARM1STATEWAIT_H_
|
|
||||||
|
|
||||||
#include "Farm1StateIF.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class represents the FARM-1 "Wait" State.
|
|
||||||
* The Wait state is reached if higher level procedures inform the FARM-1 Machine to wait
|
|
||||||
* for a certain period. Currently, it is not in use.
|
|
||||||
*/
|
|
||||||
class Farm1StateWait : public Farm1StateIF {
|
|
||||||
private:
|
|
||||||
/**
|
|
||||||
* This is a reference to the "owner" class the State works on.
|
|
||||||
*/
|
|
||||||
VirtualChannelReception* myVC;
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* The default constructor if the State.
|
|
||||||
* Sets the "owner" of the State.
|
|
||||||
* @param setMyVC The "owner" class.
|
|
||||||
*/
|
|
||||||
Farm1StateWait( VirtualChannelReception* setMyVC );
|
|
||||||
/**
|
|
||||||
* AD Frames are always discarded.
|
|
||||||
* If the frame number is in the lockout window, the state changes to Farm1StateLockout.
|
|
||||||
* @param frame The frame to handle.
|
|
||||||
* @param clcw Any changes to the CLCW shall be done with the help of this interface.
|
|
||||||
* @return Always returns FARM_IN_WAIT.
|
|
||||||
*/
|
|
||||||
ReturnValue_t handleADFrame( TcTransferFrame* frame, ClcwIF* clcw );
|
|
||||||
/**
|
|
||||||
* These commands are handled as specified.
|
|
||||||
* State changes to Farm1StateOpen.
|
|
||||||
* @param clcw Any changes to the CLCW shall be done with the help of this interface.
|
|
||||||
* @return As the frame needs no forwarding to a MAP Channel, #BC_IS_UNLOCK_COMMAND
|
|
||||||
* is returned.
|
|
||||||
*/
|
|
||||||
ReturnValue_t handleBCUnlockCommand( ClcwIF* clcw );
|
|
||||||
/**
|
|
||||||
* These commands are handled as specified.
|
|
||||||
* @param clcw Any changes to the CLCW shall be done with the help of this interface.
|
|
||||||
* @param vr The V(r) value found in the frame.
|
|
||||||
* @return As the frame needs no forwarding to a MAP Channel, #BC_IS_SET_VR_COMMAND
|
|
||||||
* is returned.
|
|
||||||
*/
|
|
||||||
ReturnValue_t handleBCSetVrCommand( ClcwIF* clcw, uint8_t vr );
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* FARM1STATEWAIT_H_ */
|
|
@ -1,159 +0,0 @@
|
|||||||
#include "MapPacketExtraction.h"
|
|
||||||
#include "../ipc/QueueFactory.h"
|
|
||||||
#include "../serviceinterface/ServiceInterfaceStream.h"
|
|
||||||
#include "../storagemanager/StorageManagerIF.h"
|
|
||||||
#include "../tmtcpacket/SpacePacketBase.h"
|
|
||||||
#include "../tmtcservices/AcceptsTelecommandsIF.h"
|
|
||||||
#include "../tmtcservices/TmTcMessage.h"
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
MapPacketExtraction::MapPacketExtraction(uint8_t setMapId,
|
|
||||||
object_id_t setPacketDestination) :
|
|
||||||
lastSegmentationFlag(NO_SEGMENTATION), mapId(setMapId),
|
|
||||||
bufferPosition(packetBuffer), packetDestination(setPacketDestination),
|
|
||||||
tcQueueId(MessageQueueIF::NO_QUEUE) {
|
|
||||||
std::memset(packetBuffer, 0, sizeof(packetBuffer));
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t MapPacketExtraction::extractPackets(TcTransferFrame* frame) {
|
|
||||||
uint8_t segmentationFlag = frame->getSequenceFlags();
|
|
||||||
ReturnValue_t status = TOO_SHORT_MAP_EXTRACTION;
|
|
||||||
switch (segmentationFlag) {
|
|
||||||
case NO_SEGMENTATION:
|
|
||||||
status = unpackBlockingPackets(frame);
|
|
||||||
break;
|
|
||||||
case FIRST_PORTION:
|
|
||||||
packetLength = frame->getDataLength();
|
|
||||||
if (packetLength <= MAX_PACKET_SIZE) {
|
|
||||||
memcpy(packetBuffer, frame->getDataField(), packetLength);
|
|
||||||
bufferPosition = &packetBuffer[packetLength];
|
|
||||||
status = RETURN_OK;
|
|
||||||
} else {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error
|
|
||||||
<< "MapPacketExtraction::extractPackets. Packet too large! Size: "
|
|
||||||
<< packetLength << std::endl;
|
|
||||||
#endif
|
|
||||||
clearBuffers();
|
|
||||||
status = CONTENT_TOO_LARGE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CONTINUING_PORTION:
|
|
||||||
case LAST_PORTION:
|
|
||||||
if (lastSegmentationFlag == FIRST_PORTION
|
|
||||||
|| lastSegmentationFlag == CONTINUING_PORTION) {
|
|
||||||
packetLength += frame->getDataLength();
|
|
||||||
if (packetLength <= MAX_PACKET_SIZE) {
|
|
||||||
memcpy(bufferPosition, frame->getDataField(),
|
|
||||||
frame->getDataLength());
|
|
||||||
bufferPosition = &packetBuffer[packetLength];
|
|
||||||
if (segmentationFlag == LAST_PORTION) {
|
|
||||||
status = sendCompletePacket(packetBuffer, packetLength);
|
|
||||||
clearBuffers();
|
|
||||||
}
|
|
||||||
status = RETURN_OK;
|
|
||||||
} else {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error
|
|
||||||
<< "MapPacketExtraction::extractPackets. Packet too large! Size: "
|
|
||||||
<< packetLength << std::endl;
|
|
||||||
#endif
|
|
||||||
clearBuffers();
|
|
||||||
status = CONTENT_TOO_LARGE;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error
|
|
||||||
<< "MapPacketExtraction::extractPackets. Illegal segment! Last flag: "
|
|
||||||
<< (int) lastSegmentationFlag << std::endl;
|
|
||||||
#endif
|
|
||||||
clearBuffers();
|
|
||||||
status = ILLEGAL_SEGMENTATION_FLAG;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error
|
|
||||||
<< "MapPacketExtraction::extractPackets. Illegal segmentationFlag: "
|
|
||||||
<< (int) segmentationFlag << std::endl;
|
|
||||||
#endif
|
|
||||||
clearBuffers();
|
|
||||||
status = DATA_CORRUPTED;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
lastSegmentationFlag = segmentationFlag;
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t MapPacketExtraction::unpackBlockingPackets(
|
|
||||||
TcTransferFrame* frame) {
|
|
||||||
ReturnValue_t status = TOO_SHORT_BLOCKED_PACKET;
|
|
||||||
uint32_t totalLength = frame->getDataLength();
|
|
||||||
if (totalLength > MAX_PACKET_SIZE)
|
|
||||||
return CONTENT_TOO_LARGE;
|
|
||||||
uint8_t* position = frame->getDataField();
|
|
||||||
while ((totalLength > SpacePacketBase::MINIMUM_SIZE)) {
|
|
||||||
SpacePacketBase packet(position);
|
|
||||||
uint32_t packetSize = packet.getFullSize();
|
|
||||||
if (packetSize <= totalLength) {
|
|
||||||
status = sendCompletePacket(packet.getWholeData(),
|
|
||||||
packet.getFullSize());
|
|
||||||
totalLength -= packet.getFullSize();
|
|
||||||
position += packet.getFullSize();
|
|
||||||
status = RETURN_OK;
|
|
||||||
} else {
|
|
||||||
status = DATA_CORRUPTED;
|
|
||||||
totalLength = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (totalLength > 0) {
|
|
||||||
status = RESIDUAL_DATA;
|
|
||||||
}
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t MapPacketExtraction::sendCompletePacket(uint8_t* data,
|
|
||||||
uint32_t size) {
|
|
||||||
store_address_t store_id;
|
|
||||||
ReturnValue_t status = this->packetStore->addData(&store_id, data, size);
|
|
||||||
if (status == RETURN_OK) {
|
|
||||||
TmTcMessage message(store_id);
|
|
||||||
status = MessageQueueSenderIF::sendMessage(tcQueueId,&message);
|
|
||||||
}
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MapPacketExtraction::clearBuffers() {
|
|
||||||
memset(packetBuffer, 0, sizeof(packetBuffer));
|
|
||||||
bufferPosition = packetBuffer;
|
|
||||||
packetLength = 0;
|
|
||||||
lastSegmentationFlag = NO_SEGMENTATION;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t MapPacketExtraction::initialize() {
|
|
||||||
packetStore = objectManager->get<StorageManagerIF>(objects::TC_STORE);
|
|
||||||
AcceptsTelecommandsIF* distributor = objectManager->get<
|
|
||||||
AcceptsTelecommandsIF>(packetDestination);
|
|
||||||
if ((packetStore != NULL) && (distributor != NULL)) {
|
|
||||||
tcQueueId = distributor->getRequestQueue();
|
|
||||||
return RETURN_OK;
|
|
||||||
} else {
|
|
||||||
return RETURN_FAILED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MapPacketExtraction::printPacketBuffer(void) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::debug << "DLL: packet_buffer contains: " << std::endl;
|
|
||||||
#endif
|
|
||||||
for (uint32_t i = 0; i < this->packetLength; ++i) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::debug << "packet_buffer[" << std::dec << i << "]: 0x" << std::hex
|
|
||||||
<< (uint16_t) this->packetBuffer[i] << std::endl;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t MapPacketExtraction::getMapId() const {
|
|
||||||
return mapId;
|
|
||||||
}
|
|
@ -1,73 +0,0 @@
|
|||||||
#ifndef FSFW_DATALINKLAYER_MAPPACKETEXTRACTION_H_
|
|
||||||
#define FSFW_DATALINKLAYER_MAPPACKETEXTRACTION_H_
|
|
||||||
|
|
||||||
#include "MapPacketExtractionIF.h"
|
|
||||||
#include "../objectmanager/ObjectManagerIF.h"
|
|
||||||
#include "../returnvalues/HasReturnvaluesIF.h"
|
|
||||||
#include "../ipc/MessageQueueSenderIF.h"
|
|
||||||
|
|
||||||
class StorageManagerIF;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implementation of a MAP Packet Extraction class.
|
|
||||||
* The class implements the full MAP Packet Extraction functionality as described in the CCSDS
|
|
||||||
* TC Space Data Link Protocol. It internally stores incomplete segmented packets until they are
|
|
||||||
* fully received. All found packets are forwarded to a single distribution entity.
|
|
||||||
* @author B. Baetz
|
|
||||||
*/
|
|
||||||
class MapPacketExtraction: public MapPacketExtractionIF {
|
|
||||||
private:
|
|
||||||
static const uint32_t MAX_PACKET_SIZE = 4096;
|
|
||||||
uint8_t lastSegmentationFlag; //!< The segmentation flag of the last received frame.
|
|
||||||
uint8_t mapId; //!< MAP ID of this MAP Channel.
|
|
||||||
uint32_t packetLength = 0; //!< Complete length of the current Space Packet.
|
|
||||||
uint8_t* bufferPosition; //!< Position to write to in the internal Packet buffer.
|
|
||||||
uint8_t packetBuffer[MAX_PACKET_SIZE]; //!< The internal Space Packet Buffer.
|
|
||||||
object_id_t packetDestination;
|
|
||||||
//!< Pointer to the store where full TC packets are stored.
|
|
||||||
StorageManagerIF* packetStore = nullptr;
|
|
||||||
MessageQueueId_t tcQueueId; //!< QueueId to send found packets to the distributor.
|
|
||||||
/**
|
|
||||||
* Debug method to print the packet Buffer's content.
|
|
||||||
*/
|
|
||||||
void printPacketBuffer();
|
|
||||||
/**
|
|
||||||
* Method that is called if the segmentation flag is @c NO_SEGMENTATION.
|
|
||||||
* The method extracts one or more packets within the frame and forwards them to the OBSW.
|
|
||||||
* @param frame The TC Transfer Frame to work on.
|
|
||||||
* @return @c RETURN_OK if all Packets were extracted. If something is entirely wrong,
|
|
||||||
* @c DATA_CORRUPTED is returned, if some bytes are left over @c RESIDUAL_DATA.
|
|
||||||
*/
|
|
||||||
ReturnValue_t unpackBlockingPackets(TcTransferFrame* frame);
|
|
||||||
/**
|
|
||||||
* Helper method to forward a complete packet to the OBSW.
|
|
||||||
* @param data Pointer to the data, either directly from the frame or from the packetBuffer.
|
|
||||||
* @param size Complete total size of the packet.
|
|
||||||
* @return Return Code of the Packet Store or the Message Queue.
|
|
||||||
*/
|
|
||||||
ReturnValue_t sendCompletePacket( uint8_t* data, uint32_t size );
|
|
||||||
/**
|
|
||||||
* Helper method to reset the internal buffer.
|
|
||||||
*/
|
|
||||||
void clearBuffers();
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Default constructor.
|
|
||||||
* Members are set to default values.
|
|
||||||
* @param setMapId The MAP ID of the instance.
|
|
||||||
*/
|
|
||||||
MapPacketExtraction( uint8_t setMapId, object_id_t setPacketDestination );
|
|
||||||
ReturnValue_t extractPackets(TcTransferFrame* frame);
|
|
||||||
/**
|
|
||||||
* The #packetStore and the default destination of #tcQueue are initialized here.
|
|
||||||
* @return @c RETURN_OK on success, @c RETURN_FAILED otherwise.
|
|
||||||
*/
|
|
||||||
ReturnValue_t initialize();
|
|
||||||
/**
|
|
||||||
* Getter.
|
|
||||||
* @return The MAP ID of this instance.
|
|
||||||
*/
|
|
||||||
uint8_t getMapId() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* FSFW_DATALINKLAYER_MAPPACKETEXTRACTION_H_ */
|
|
@ -1,47 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file MapPacketExtractionIF.h
|
|
||||||
* @brief This file defines the MapPacketExtractionIF class.
|
|
||||||
* @date 25.03.2013
|
|
||||||
* @author baetz
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef MAPPACKETEXTRACTIONIF_H_
|
|
||||||
#define MAPPACKETEXTRACTIONIF_H_
|
|
||||||
|
|
||||||
#include "CCSDSReturnValuesIF.h"
|
|
||||||
#include "TcTransferFrame.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is the interface for MAP Packet Extraction classes.
|
|
||||||
* All classes implementing this interface shall be able to extract blocked or segmented Space
|
|
||||||
* Packets on a certain MAP channel. This is done in accordance with the CCSDS TC Space Data Link
|
|
||||||
* Protocol.
|
|
||||||
*/
|
|
||||||
class MapPacketExtractionIF : public CCSDSReturnValuesIF {
|
|
||||||
protected:
|
|
||||||
static const uint8_t FIRST_PORTION = 0b01; //!< Identification of the first part of a segmented Packet.
|
|
||||||
static const uint8_t CONTINUING_PORTION = 0b00; //!< Identification of a continuing part of segmented Packets.
|
|
||||||
static const uint8_t LAST_PORTION = 0b10; //!< The last portion of a segmented Packet.
|
|
||||||
static const uint8_t NO_SEGMENTATION = 0b11; //!< A Frame without segmentation but maybe with blocking.
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Empty virtual destructor.
|
|
||||||
*/
|
|
||||||
virtual ~MapPacketExtractionIF() {
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Method to call to handle a single Transfer Frame.
|
|
||||||
* The method tries to extract Packets from the frame as stated in the Standard.
|
|
||||||
* @param frame
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
virtual ReturnValue_t extractPackets( TcTransferFrame* frame ) = 0;
|
|
||||||
/**
|
|
||||||
* Any post-instantiation initialization shall be done in this method.
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
virtual ReturnValue_t initialize() = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* MAPPACKETEXTRACTIONIF_H_ */
|
|
@ -1,111 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file TcTransferFrame.cpp
|
|
||||||
* @brief This file defines the TcTransferFrame class.
|
|
||||||
* @date 27.04.2013
|
|
||||||
* @author baetz
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include "TcTransferFrame.h"
|
|
||||||
#include "../serviceinterface/ServiceInterfaceStream.h"
|
|
||||||
|
|
||||||
TcTransferFrame::TcTransferFrame() {
|
|
||||||
frame = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
TcTransferFrame::TcTransferFrame(uint8_t* setData) {
|
|
||||||
this->frame = (tc_transfer_frame*)setData;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t TcTransferFrame::getVersionNumber() {
|
|
||||||
return (this->frame->header.flagsAndScid & 0b11000000) >> 6;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TcTransferFrame::bypassFlagSet() {
|
|
||||||
return (this->frame->header.flagsAndScid & 0b00100000) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TcTransferFrame::controlCommandFlagSet() {
|
|
||||||
return (this->frame->header.flagsAndScid & 0b00010000) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TcTransferFrame::spareIsZero() {
|
|
||||||
return ( (this->frame->header.flagsAndScid & 0b00001100) == 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t TcTransferFrame::getSpacecraftId() {
|
|
||||||
return ( (this->frame->header.flagsAndScid & 0b00000011) << 8 ) + this->frame->header.spacecraftId_l;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t TcTransferFrame::getVirtualChannelId() {
|
|
||||||
return (this->frame->header.vcidAndLength_h & 0b11111100) >> 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t TcTransferFrame::getFrameLength() {
|
|
||||||
return ( (this->frame->header.vcidAndLength_h & 0b00000011) << 8 ) + this->frame->header.length_l;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t TcTransferFrame::getDataLength() {
|
|
||||||
return this->getFrameLength() - this->getHeaderSize() -1 - FRAME_CRC_SIZE + 1; // -1 for the segment header.
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t TcTransferFrame::getSequenceNumber() {
|
|
||||||
return this->frame->header.sequenceNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t TcTransferFrame::getSequenceFlags() {
|
|
||||||
return (this->frame->dataField & 0b11000000)>>6;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t TcTransferFrame::getMAPId() {
|
|
||||||
return this->frame->dataField & 0b00111111;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t* TcTransferFrame::getDataField() {
|
|
||||||
return &(this->frame->dataField) + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t* TcTransferFrame::getFullFrame() {
|
|
||||||
return (uint8_t*)this->frame;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t TcTransferFrame::getFullSize() {
|
|
||||||
return this->getFrameLength() + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t TcTransferFrame::getHeaderSize() {
|
|
||||||
return sizeof(frame->header);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t TcTransferFrame::getFullDataLength() {
|
|
||||||
return this->getFrameLength() - this->getHeaderSize() - FRAME_CRC_SIZE + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t* TcTransferFrame::getFullDataField() {
|
|
||||||
return &frame->dataField;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TcTransferFrame::print() {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::debug << "Raw Frame: " << std::hex << std::endl;
|
|
||||||
for (uint16_t count = 0; count < this->getFullSize(); count++ ) {
|
|
||||||
sif::debug << (uint16_t)this->getFullFrame()[count] << " ";
|
|
||||||
}
|
|
||||||
sif::debug << std::dec << std::endl;
|
|
||||||
|
|
||||||
sif::debug << "Frame Header:" << std::endl;
|
|
||||||
sif::debug << "Version Number: " << std::hex
|
|
||||||
<< (uint16_t)this->getVersionNumber() << std::endl;
|
|
||||||
sif::debug << "Bypass Flag set?| Ctrl Cmd Flag set?: "
|
|
||||||
<< (uint16_t)this->bypassFlagSet() << " | "
|
|
||||||
<< (uint16_t)this->controlCommandFlagSet() << std::endl;
|
|
||||||
sif::debug << "SCID : " << this->getSpacecraftId() << std::endl;
|
|
||||||
sif::debug << "VCID : " << (uint16_t)this->getVirtualChannelId()
|
|
||||||
<< std::endl;
|
|
||||||
sif::debug << "Frame length: " << std::dec << this->getFrameLength()
|
|
||||||
<< std::endl;
|
|
||||||
sif::debug << "Sequence Number: " << (uint16_t)this->getSequenceNumber()
|
|
||||||
<< std::endl;
|
|
||||||
#endif
|
|
||||||
}
|
|
@ -1,137 +0,0 @@
|
|||||||
#ifndef TCTRANSFERFRAME_H_
|
|
||||||
#define TCTRANSFERFRAME_H_
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The TcTransferFrame class simplifies handling of such Frames.
|
|
||||||
* It operates on any buffer passed on construction. The data length
|
|
||||||
* is determined by the length field in the frame itself.
|
|
||||||
* It has a lot of getters for convenient access to the content.
|
|
||||||
* @ingroup ccsds_handling
|
|
||||||
*/
|
|
||||||
class TcTransferFrame {
|
|
||||||
protected:
|
|
||||||
/**
|
|
||||||
* The struct that defines the Frame's Primary Header.
|
|
||||||
*/
|
|
||||||
struct TcTransferFramePrimaryHeader {
|
|
||||||
uint8_t flagsAndScid; //!< Highest byte with Flags and part of SCID.
|
|
||||||
uint8_t spacecraftId_l; //!< Byte with rest of SCID
|
|
||||||
uint8_t vcidAndLength_h; //!< Byte with VCID and part of length.
|
|
||||||
uint8_t length_l; //!< Byte with rest of length.
|
|
||||||
uint8_t sequenceNumber; //!< Lowest byte with Frame Sequence Number N(S).
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
* The struct defining the whole Transfer Frame.
|
|
||||||
*/
|
|
||||||
struct tc_transfer_frame {
|
|
||||||
TcTransferFramePrimaryHeader header; //!< The header struct.
|
|
||||||
uint8_t dataField; //!< The data field of the Transfer Frame.
|
|
||||||
};
|
|
||||||
tc_transfer_frame* frame; //!< Pointer to a buffer where a Frame is placed.
|
|
||||||
public:
|
|
||||||
static const uint8_t FRAME_CRC_SIZE = 2; //!< Constant for the CRC size.
|
|
||||||
/**
|
|
||||||
* Empty Constructor that sets the data pointer to NULL.
|
|
||||||
*/
|
|
||||||
TcTransferFrame();
|
|
||||||
/**
|
|
||||||
* The data pointer passed in this Constructor is casted to the #tc_transfer_frame struct.
|
|
||||||
* @param setData The data on which the class shall operate.
|
|
||||||
*/
|
|
||||||
TcTransferFrame(uint8_t* setData);
|
|
||||||
/**
|
|
||||||
* Getter.
|
|
||||||
* @return The Version number.
|
|
||||||
*/
|
|
||||||
uint8_t getVersionNumber();
|
|
||||||
/**
|
|
||||||
* Getter.
|
|
||||||
* @return If the bypass flag is set or not.
|
|
||||||
*/
|
|
||||||
bool bypassFlagSet();
|
|
||||||
/**
|
|
||||||
* Getter.
|
|
||||||
* @return If the control command flag is set or not.
|
|
||||||
*/
|
|
||||||
bool controlCommandFlagSet();
|
|
||||||
/**
|
|
||||||
* Getter.
|
|
||||||
* @return If the spare bits in the Header are zero or not.
|
|
||||||
*/
|
|
||||||
bool spareIsZero();
|
|
||||||
/**
|
|
||||||
* Getter.
|
|
||||||
* @return The Spacecraft Identifier.
|
|
||||||
*/
|
|
||||||
uint16_t getSpacecraftId();
|
|
||||||
/**
|
|
||||||
* Getter.
|
|
||||||
* @return The Virtual Channel Identifier.
|
|
||||||
*/
|
|
||||||
uint8_t getVirtualChannelId();
|
|
||||||
/**
|
|
||||||
* Getter.
|
|
||||||
* @return The Frame length as stored in the Header.
|
|
||||||
*/
|
|
||||||
uint16_t getFrameLength();
|
|
||||||
/**
|
|
||||||
* Getter.
|
|
||||||
* @return The length of pure data (without CRC), assuming that a Segment Header is present.
|
|
||||||
*/
|
|
||||||
uint16_t getDataLength();
|
|
||||||
/**
|
|
||||||
* Getter.
|
|
||||||
* @return The length of pure data (without CRC), assuming that no Segment Header is present (for BC Frames).
|
|
||||||
*/
|
|
||||||
uint16_t getFullDataLength();
|
|
||||||
/**
|
|
||||||
* Getter.
|
|
||||||
* @return The sequence number from the header.
|
|
||||||
*/
|
|
||||||
uint8_t getSequenceNumber();
|
|
||||||
/**
|
|
||||||
* Getter.
|
|
||||||
* @return The Sequence Flags in the Segment Header byte (right aligned).
|
|
||||||
*/
|
|
||||||
uint8_t getSequenceFlags();
|
|
||||||
/**
|
|
||||||
* Getter.
|
|
||||||
* @return The Multiplexer Access Point Identifier from the Segment Header byte.
|
|
||||||
*/
|
|
||||||
uint8_t getMAPId();
|
|
||||||
/**
|
|
||||||
* Getter.
|
|
||||||
* @return A pointer to the date field AFTER a Segment Header.
|
|
||||||
*/
|
|
||||||
uint8_t* getDataField();
|
|
||||||
/**
|
|
||||||
* Getter.
|
|
||||||
* @return A pointer to the first byte in the Data Field (ignoring potential Segment Headers, for BC Frames).
|
|
||||||
*/
|
|
||||||
uint8_t* getFullDataField();
|
|
||||||
/**
|
|
||||||
* Getter.
|
|
||||||
* @return A pointer to the beginning of the Frame.
|
|
||||||
*/
|
|
||||||
uint8_t* getFullFrame();
|
|
||||||
/**
|
|
||||||
* Getter
|
|
||||||
* @return The total size of the Frame, which is the size stated in the Header + 1.
|
|
||||||
*/
|
|
||||||
uint16_t getFullSize();
|
|
||||||
/**
|
|
||||||
* Getter.
|
|
||||||
* @return Size of the #TcTransferFramePrimaryHeader.
|
|
||||||
*/
|
|
||||||
uint16_t getHeaderSize();
|
|
||||||
/**
|
|
||||||
* Debug method to print the whole Frame to screen.
|
|
||||||
*/
|
|
||||||
void print();
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* TCTRANSFERFRAME_H_ */
|
|
@ -1,51 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file TcTransferFrameLocal.cpp
|
|
||||||
* @brief This file defines the TcTransferFrameLocal class.
|
|
||||||
* @date 27.04.2013
|
|
||||||
* @author baetz
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "TcTransferFrameLocal.h"
|
|
||||||
#include "../globalfunctions/CRC.h"
|
|
||||||
#include "../serviceinterface/ServiceInterfaceStream.h"
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
TcTransferFrameLocal::TcTransferFrameLocal(bool bypass, bool controlCommand, uint16_t scid,
|
|
||||||
uint8_t vcId, uint8_t sequenceNumber, uint8_t setSegmentHeader, uint8_t* data, uint16_t dataSize, uint16_t forceCrc) {
|
|
||||||
this->frame = (tc_transfer_frame*)&localData;
|
|
||||||
frame->header.flagsAndScid = (bypass << 5) + (controlCommand << 4) + ((scid & 0x0300) >> 8);
|
|
||||||
frame->header.spacecraftId_l = (scid & 0x00FF);
|
|
||||||
frame->header.vcidAndLength_h = (vcId & 0b00111111) << 2;
|
|
||||||
frame->header.length_l = sizeof(TcTransferFramePrimaryHeader) -1;
|
|
||||||
frame->header.sequenceNumber = sequenceNumber;
|
|
||||||
frame->dataField = setSegmentHeader;
|
|
||||||
if (data != NULL) {
|
|
||||||
if (bypass && controlCommand) {
|
|
||||||
memcpy(&(frame->dataField), data, dataSize);
|
|
||||||
uint16_t totalSize = sizeof(TcTransferFramePrimaryHeader) + dataSize + FRAME_CRC_SIZE -1;
|
|
||||||
frame->header.vcidAndLength_h |= (totalSize & 0x0300) >> 8;
|
|
||||||
frame->header.length_l = (totalSize & 0x00FF);
|
|
||||||
uint16_t crc = CRC::crc16ccitt(getFullFrame(), getFullSize() -2);
|
|
||||||
this->getFullFrame()[getFullSize()-2] = (crc & 0xFF00) >> 8;
|
|
||||||
this->getFullFrame()[getFullSize()-1] = (crc & 0x00FF);
|
|
||||||
} else if (dataSize <= 1016) {
|
|
||||||
memcpy(&(frame->dataField) +1, data, dataSize);
|
|
||||||
uint16_t dataCrcSize = sizeof(TcTransferFramePrimaryHeader) + 1 + dataSize + FRAME_CRC_SIZE -1;
|
|
||||||
frame->header.vcidAndLength_h |= (dataCrcSize & 0x0300) >> 8;
|
|
||||||
frame->header.length_l = (dataCrcSize & 0x00FF);
|
|
||||||
uint16_t crc = CRC::crc16ccitt(getFullFrame(), getFullSize() -2);
|
|
||||||
this->getFullFrame()[getFullSize()-2] = (crc & 0xFF00) >> 8;
|
|
||||||
this->getFullFrame()[getFullSize()-1] = (crc & 0x00FF);
|
|
||||||
} else {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::debug << "TcTransferFrameLocal: dataSize too large: " << dataSize << std::endl;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//No data in frame
|
|
||||||
}
|
|
||||||
if (forceCrc != 0 ) {
|
|
||||||
localData.data[getFullSize()-2] = (forceCrc & 0xFF00) >> 8;
|
|
||||||
localData.data[getFullSize()-1] = (forceCrc & 0x00FF);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,49 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file TcTransferFrameLocal.h
|
|
||||||
* @brief This file defines the TcTransferFrameLocal class.
|
|
||||||
* @date 27.04.2013
|
|
||||||
* @author baetz
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef TCTRANSFERFRAMELOCAL_H_
|
|
||||||
#define TCTRANSFERFRAMELOCAL_H_
|
|
||||||
|
|
||||||
#include "TcTransferFrame.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is a helper class to locally create TC Transfer Frames.
|
|
||||||
* This is mainly required for testing purposes and therefore not very sophisticated.
|
|
||||||
* @ingroup ccsds_handling
|
|
||||||
*/
|
|
||||||
class TcTransferFrameLocal : public TcTransferFrame {
|
|
||||||
private:
|
|
||||||
/**
|
|
||||||
* A stuct to locally store the complete data.
|
|
||||||
*/
|
|
||||||
struct frameData {
|
|
||||||
TcTransferFramePrimaryHeader header; //!< The primary header.
|
|
||||||
uint8_t data[1019]; //!< The data field.
|
|
||||||
};
|
|
||||||
public:
|
|
||||||
frameData localData; //!< The local data in the Frame.
|
|
||||||
/**
|
|
||||||
* The default Constructor.
|
|
||||||
* All parameters in the Header are passed.
|
|
||||||
* If a BC Frame is detected no segment header is created.
|
|
||||||
* Otherwise (AD and BD), the Segment Header is set.
|
|
||||||
* @param bypass The bypass flag.
|
|
||||||
* @param controlCommand The Control Command flag.
|
|
||||||
* @param scid The SCID.
|
|
||||||
* @param vcId The VCID.
|
|
||||||
* @param sequenceNumber The Frame Sequence Number N(s)
|
|
||||||
* @param setSegmentHeader A value for the Segment Header.
|
|
||||||
* @param data Data to put into the Frame Data Field.
|
|
||||||
* @param dataSize Size of the Data.
|
|
||||||
* @param forceCrc if != 0, the value is used as CRC.
|
|
||||||
*/
|
|
||||||
TcTransferFrameLocal(bool bypass, bool controlCommand, uint16_t scid, uint8_t vcId, uint8_t sequenceNumber,
|
|
||||||
uint8_t setSegmentHeader = 0xC0, uint8_t* data = NULL, uint16_t dataSize = 0, uint16_t forceCrc = 0);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* TCTRANSFERFRAMELOCAL_H_ */
|
|
@ -1,123 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file VirtualChannelReception.cpp
|
|
||||||
* @brief This file defines the VirtualChannelReception class.
|
|
||||||
* @date 26.03.2013
|
|
||||||
* @author baetz
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "BCFrame.h"
|
|
||||||
#include "VirtualChannelReception.h"
|
|
||||||
#include "../serviceinterface/ServiceInterfaceStream.h"
|
|
||||||
|
|
||||||
VirtualChannelReception::VirtualChannelReception(uint8_t setChannelId,
|
|
||||||
uint8_t setSlidingWindowWidth) :
|
|
||||||
channelId(setChannelId), slidingWindowWidth(setSlidingWindowWidth), positiveWindow(
|
|
||||||
setSlidingWindowWidth / 2), negativeWindow(setSlidingWindowWidth / 2), currentState(
|
|
||||||
&openState), openState(this), waitState(this), lockoutState(this), vR(0), farmBCounter(
|
|
||||||
0) {
|
|
||||||
internalClcw.setVirtualChannel(channelId);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t VirtualChannelReception::mapDemultiplexing(TcTransferFrame* frame) {
|
|
||||||
uint8_t mapId = frame->getMAPId();
|
|
||||||
mapChannelIterator iter = mapChannels.find(mapId);
|
|
||||||
if (iter == mapChannels.end()) {
|
|
||||||
// error << "VirtualChannelReception::mapDemultiplexing on VC " << std::hex << (int) channelId
|
|
||||||
// << ": MapChannel " << (int) mapId << std::dec << " not found." << std::endl;
|
|
||||||
return VC_NOT_FOUND;
|
|
||||||
} else {
|
|
||||||
return (iter->second)->extractPackets(frame);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t VirtualChannelReception::doFARM(TcTransferFrame* frame, ClcwIF* clcw) {
|
|
||||||
uint8_t bypass = frame->bypassFlagSet();
|
|
||||||
uint8_t controlCommand = frame->controlCommandFlagSet();
|
|
||||||
uint8_t typeValue = (bypass << 1) + controlCommand;
|
|
||||||
switch (typeValue) {
|
|
||||||
case AD_FRAME:
|
|
||||||
return currentState->handleADFrame(frame, clcw);
|
|
||||||
case BD_FRAME:
|
|
||||||
return handleBDFrame(frame, clcw);
|
|
||||||
case BC_FRAME:
|
|
||||||
return handleBCFrame(frame, clcw);
|
|
||||||
default:
|
|
||||||
return ILLEGAL_FLAG_COMBINATION;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t VirtualChannelReception::frameAcceptanceAndReportingMechanism(TcTransferFrame* frame,
|
|
||||||
ClcwIF* clcw) {
|
|
||||||
ReturnValue_t result = RETURN_OK;
|
|
||||||
result = doFARM(frame, &internalClcw);
|
|
||||||
internalClcw.setReceiverFrameSequenceNumber(vR);
|
|
||||||
internalClcw.setFarmBCount(farmBCounter);
|
|
||||||
clcw->setWhole(internalClcw.getAsWhole());
|
|
||||||
switch (result) {
|
|
||||||
case RETURN_OK:
|
|
||||||
return mapDemultiplexing(frame);
|
|
||||||
case BC_IS_SET_VR_COMMAND:
|
|
||||||
case BC_IS_UNLOCK_COMMAND:
|
|
||||||
//Need to catch these codes to avoid error reporting later.
|
|
||||||
return RETURN_OK;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t VirtualChannelReception::addMapChannel(uint8_t mapId, MapPacketExtractionIF* object) {
|
|
||||||
std::pair<mapChannelIterator, bool> returnValue = mapChannels.insert(
|
|
||||||
std::pair<uint8_t, MapPacketExtractionIF*>(mapId, object));
|
|
||||||
if (returnValue.second == true) {
|
|
||||||
return RETURN_OK;
|
|
||||||
} else {
|
|
||||||
return RETURN_FAILED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t VirtualChannelReception::handleBDFrame(TcTransferFrame* frame, ClcwIF* clcw) {
|
|
||||||
farmBCounter++;
|
|
||||||
return RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t VirtualChannelReception::handleBCFrame(TcTransferFrame* frame, ClcwIF* clcw) {
|
|
||||||
BcFrame content;
|
|
||||||
ReturnValue_t returnValue = content.initialize(frame->getFullDataField(),
|
|
||||||
frame->getFullDataLength());
|
|
||||||
if (returnValue == BC_IS_UNLOCK_COMMAND) {
|
|
||||||
returnValue = currentState->handleBCUnlockCommand(clcw);
|
|
||||||
} else if (returnValue == BC_IS_SET_VR_COMMAND) {
|
|
||||||
returnValue = currentState->handleBCSetVrCommand(clcw, content.vR);
|
|
||||||
} else {
|
|
||||||
//Do nothing
|
|
||||||
}
|
|
||||||
return returnValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t VirtualChannelReception::getChannelId() const {
|
|
||||||
return channelId;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t VirtualChannelReception::initialize() {
|
|
||||||
ReturnValue_t returnValue = RETURN_FAILED;
|
|
||||||
if ((slidingWindowWidth > 254) || (slidingWindowWidth % 2 != 0)) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "VirtualChannelReception::initialize: Illegal sliding window width: "
|
|
||||||
<< (int) slidingWindowWidth << std::endl;
|
|
||||||
#endif
|
|
||||||
return RETURN_FAILED;
|
|
||||||
}
|
|
||||||
for (mapChannelIterator iterator = mapChannels.begin(); iterator != mapChannels.end();
|
|
||||||
iterator++) {
|
|
||||||
returnValue = iterator->second->initialize();
|
|
||||||
if (returnValue != RETURN_OK)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return returnValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VirtualChannelReception::setToWaitState() {
|
|
||||||
internalClcw.setWaitFlag(true);
|
|
||||||
this->currentState = &waitState;
|
|
||||||
}
|
|
@ -1,114 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file VirtualChannelReception.h
|
|
||||||
* @brief This file defines the VirtualChannelReception class.
|
|
||||||
* @date 25.03.2013
|
|
||||||
* @author baetz
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef VIRTUALCHANNELRECEPTION_H_
|
|
||||||
#define VIRTUALCHANNELRECEPTION_H_
|
|
||||||
|
|
||||||
#include "CCSDSReturnValuesIF.h"
|
|
||||||
#include "Clcw.h"
|
|
||||||
#include "Farm1StateIF.h"
|
|
||||||
#include "Farm1StateLockout.h"
|
|
||||||
#include "Farm1StateOpen.h"
|
|
||||||
#include "Farm1StateWait.h"
|
|
||||||
#include "MapPacketExtractionIF.h"
|
|
||||||
#include "VirtualChannelReceptionIF.h"
|
|
||||||
#include <map>
|
|
||||||
/**
|
|
||||||
* Implementation of a TC Virtual Channel.
|
|
||||||
* This is a full implementation of a virtual channel as specified in the CCSDS TC Space Data Link
|
|
||||||
* Protocol. It is designed to operate within an instance of the @c DataLinkLayer class.
|
|
||||||
* Features:
|
|
||||||
* - any (6bit) Virtual Channel ID is assignable.
|
|
||||||
* - Supports an arbitrary number of MAP Channels (with a map).
|
|
||||||
* - Has a complete FARM-1 Machine built-in.
|
|
||||||
*
|
|
||||||
* The FARM-1 state machine uses the State Pattern.
|
|
||||||
*/
|
|
||||||
class VirtualChannelReception : public VirtualChannelReceptionIF, public CCSDSReturnValuesIF {
|
|
||||||
friend class Farm1StateOpen;
|
|
||||||
friend class Farm1StateWait;
|
|
||||||
friend class Farm1StateLockout;
|
|
||||||
private:
|
|
||||||
uint8_t channelId; //!< Stores the VCID that was assigned on construction.
|
|
||||||
uint8_t slidingWindowWidth; //!< A constant to set the FARM-1 sliding window width.
|
|
||||||
uint8_t positiveWindow; //!< The positive window for the FARM-1 machine.
|
|
||||||
uint8_t negativeWindow; //!< The negative window for the FARM-1 machine.
|
|
||||||
protected:
|
|
||||||
Farm1StateIF* currentState; //!< The current state. To change, one of the other states must be assigned to this pointer.
|
|
||||||
Farm1StateOpen openState; //!< Instance of the FARM-1 State "Open".
|
|
||||||
Farm1StateWait waitState; //!< Instance of the FARM-1 State "Wait".
|
|
||||||
Farm1StateLockout lockoutState; //!< Instance of the FARM-1 State "Lockout".
|
|
||||||
Clcw internalClcw; //!< A CLCW class to internally set the values before writing them back to the TTC System.
|
|
||||||
uint8_t vR; //!< The Receiver Frame Sequence Number V(R) as it shall be maintained for every Virtual Channel.
|
|
||||||
uint8_t farmBCounter; //!< The FARM-B COunter as it shall be maintained for every Virtual Channel.
|
|
||||||
typedef std::map<uint8_t, MapPacketExtractionIF*>::iterator mapChannelIterator; //!< Typedef to simplify handling of the mapChannels map.
|
|
||||||
std::map<uint8_t, MapPacketExtractionIF*> mapChannels; //!< A map that maintains all map Channels. Channels must be configured on initialization. MAy be omitted in a simplified version.
|
|
||||||
/**
|
|
||||||
* This method handles demultiplexing to different map channels.
|
|
||||||
* It parses the entries of #mapChannels and forwards the Frame to a found MAP Channel.
|
|
||||||
* @param frame The frame to forward.
|
|
||||||
* @return #VC_NOT_FOUND or the return value of the map channel extraction.
|
|
||||||
*/
|
|
||||||
ReturnValue_t mapDemultiplexing( TcTransferFrame* frame );
|
|
||||||
/**
|
|
||||||
* A sub-method that actually does the FARM-1 handling for different Frame types.
|
|
||||||
* @param frame The Tc Transfer Frame to handle.
|
|
||||||
* @param clcw Any changes on the CLCW shall be done with this method.
|
|
||||||
* @return The return code of higher methods or @c ILLEGAL_FLAG_COMBINATION.
|
|
||||||
*/
|
|
||||||
ReturnValue_t doFARM(TcTransferFrame* frame, ClcwIF* clcw);
|
|
||||||
/**
|
|
||||||
* Handles incoming BD Frames.
|
|
||||||
* Handling these Frames is independent of the State, so no subcall to #currentState is
|
|
||||||
* required.
|
|
||||||
* @param frame The Tc Transfer Frame to handle.
|
|
||||||
* @param clcw Any changes on the CLCW shall be done with this method.
|
|
||||||
* @return Always returns @c RETURN_OK.
|
|
||||||
*/
|
|
||||||
ReturnValue_t handleBDFrame( TcTransferFrame* frame, ClcwIF* clcw );
|
|
||||||
/**
|
|
||||||
* Handles incoming BC Frames.
|
|
||||||
* The type of the BC Frame is detected and checked first, then methods of #currentState are called.
|
|
||||||
* @param frame The Tc Transfer Frame to handle.
|
|
||||||
* @param clcw Any changes on the CLCW shall be done with this method.
|
|
||||||
* @return The failure code of BC Frame interpretation or the return code of higher methods.
|
|
||||||
*/
|
|
||||||
ReturnValue_t handleBCFrame( TcTransferFrame* frame, ClcwIF* clcw );
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Default constructor.
|
|
||||||
* Only sets the channelId of the channel. Setting the Sliding Window width is possible as well.
|
|
||||||
* @param setChannelId Virtual Channel Identifier (VCID) of the channel.
|
|
||||||
*/
|
|
||||||
VirtualChannelReception( uint8_t setChannelId, uint8_t setSlidingWindowWidth );
|
|
||||||
ReturnValue_t frameAcceptanceAndReportingMechanism( TcTransferFrame* frame, ClcwIF* clcw );
|
|
||||||
/**
|
|
||||||
* Helper method to simplify adding a mapChannel during construction.
|
|
||||||
* @param mapId The mapId of the object to add.
|
|
||||||
* @param object Pointer to the MapPacketExtraction object itself.
|
|
||||||
* @return @c RETURN_OK if the channel was successfully inserted, @c RETURN_FAILED otherwise.
|
|
||||||
*/
|
|
||||||
ReturnValue_t addMapChannel( uint8_t mapId, MapPacketExtractionIF* object );
|
|
||||||
/**
|
|
||||||
* The initialization routine checks the set #slidingWindowWidth and initializes all MAP
|
|
||||||
* channels.
|
|
||||||
* @return @c RETURN_OK on successful initialization, @c RETURN_FAILED otherwise.
|
|
||||||
*/
|
|
||||||
ReturnValue_t initialize();
|
|
||||||
/**
|
|
||||||
* Getter for the VCID.
|
|
||||||
* @return The #channelId.
|
|
||||||
*/
|
|
||||||
uint8_t getChannelId() const;
|
|
||||||
/**
|
|
||||||
* Small method to set the state to Farm1StateWait.
|
|
||||||
*/
|
|
||||||
void setToWaitState();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* VIRTUALCHANNELRECEPTION_H_ */
|
|
@ -1,57 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file VirtualChannelReceptionIF.h
|
|
||||||
* @brief This file defines the VirtualChannelReceptionIF class.
|
|
||||||
* @date 25.03.2013
|
|
||||||
* @author baetz
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef VIRTUALCHANNELRECEPTIONIF_H_
|
|
||||||
#define VIRTUALCHANNELRECEPTIONIF_H_
|
|
||||||
|
|
||||||
#include "ClcwIF.h"
|
|
||||||
#include "TcTransferFrame.h"
|
|
||||||
#include "../returnvalues/HasReturnvaluesIF.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is the interface for Virtual Channel reception classes.
|
|
||||||
* It represents a single TC Virtual Channel that operates on one IO
|
|
||||||
*/
|
|
||||||
class VirtualChannelReceptionIF {
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Enum including all valid types of frames.
|
|
||||||
* The type is made up by two flags, so 0b1111 is definitely illegal.
|
|
||||||
*/
|
|
||||||
enum frameType {
|
|
||||||
AD_FRAME = 0b00,
|
|
||||||
BC_FRAME = 0b11,
|
|
||||||
BD_FRAME = 0b10,
|
|
||||||
ILLEGAL_FRAME = 0b1111
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
* Empty virtual destructor.
|
|
||||||
*/
|
|
||||||
virtual ~VirtualChannelReceptionIF() {
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* This method shall accept frames and do all FARM-1 stuff.
|
|
||||||
* Handling the Frame includes forwarding to higher-level procedures.
|
|
||||||
* @param frame The Tc Transfer Frame that was received and checked.
|
|
||||||
* @param clcw Any changes to the CLCW value are forwarded by using this parameter.
|
|
||||||
* @return The return Value shall indicate successful processing with @c RETURN_OK.
|
|
||||||
*/
|
|
||||||
virtual ReturnValue_t frameAcceptanceAndReportingMechanism( TcTransferFrame* frame, ClcwIF* clcw ) = 0;
|
|
||||||
/**
|
|
||||||
* If any other System Objects are required for operation they shall be initialized here.
|
|
||||||
* @return @c RETURN_OK for successful initialization.
|
|
||||||
*/
|
|
||||||
virtual ReturnValue_t initialize() = 0;
|
|
||||||
/**
|
|
||||||
* Getter for the VCID.
|
|
||||||
* @return The #channelId.
|
|
||||||
*/
|
|
||||||
virtual uint8_t getChannelId() const = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* VIRTUALCHANNELRECEPTIONIF_H_ */
|
|
@ -1,6 +0,0 @@
|
|||||||
target_sources(${LIB_FSFW_NAME}
|
|
||||||
PRIVATE
|
|
||||||
HkSwitchHelper.cpp
|
|
||||||
PoolDataSetBase.cpp
|
|
||||||
PoolEntry.cpp
|
|
||||||
)
|
|
@ -1,45 +0,0 @@
|
|||||||
#ifndef FSFW_DATAPOOL_DATASETIF_H_
|
|
||||||
#define FSFW_DATAPOOL_DATASETIF_H_
|
|
||||||
|
|
||||||
#include "../returnvalues/HasReturnvaluesIF.h"
|
|
||||||
#include "../timemanager/Clock.h"
|
|
||||||
class PoolVariableIF;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief This class defines a small interface to register on a DataSet.
|
|
||||||
*
|
|
||||||
* @details
|
|
||||||
* Currently, the only purpose of this interface is to provide a
|
|
||||||
* method for locally checked-out variables to register on a data set.
|
|
||||||
* Still, it may become useful for other purposes as well.
|
|
||||||
* @author Bastian Baetz
|
|
||||||
* @ingroup data_pool
|
|
||||||
*/
|
|
||||||
class DataSetIF {
|
|
||||||
public:
|
|
||||||
static constexpr uint8_t INTERFACE_ID = CLASS_ID::DATA_SET_CLASS;
|
|
||||||
static constexpr ReturnValue_t INVALID_PARAMETER_DEFINITION = MAKE_RETURN_CODE(1);
|
|
||||||
static constexpr ReturnValue_t SET_WAS_ALREADY_READ = MAKE_RETURN_CODE(2);
|
|
||||||
static constexpr ReturnValue_t COMMITING_WITHOUT_READING = MAKE_RETURN_CODE(3);
|
|
||||||
|
|
||||||
static constexpr ReturnValue_t DATA_SET_UNINITIALISED = MAKE_RETURN_CODE(4);
|
|
||||||
static constexpr ReturnValue_t DATA_SET_FULL = MAKE_RETURN_CODE(5);
|
|
||||||
static constexpr ReturnValue_t POOL_VAR_NULL = MAKE_RETURN_CODE(6);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief This is an empty virtual destructor,
|
|
||||||
* as it is proposed for C++ interfaces.
|
|
||||||
*/
|
|
||||||
virtual ~DataSetIF() {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief This operation provides a method to register local data pool
|
|
||||||
* variables to register in a data set by passing itself
|
|
||||||
* to this DataSet operation.
|
|
||||||
*/
|
|
||||||
virtual ReturnValue_t registerVariable(PoolVariableIF* variable) = 0;
|
|
||||||
|
|
||||||
virtual uint16_t getFillCount() const = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* FSFW_DATAPOOL_DATASETIF_H_ */
|
|
@ -1,75 +0,0 @@
|
|||||||
#include "../datapool/HkSwitchHelper.h"
|
|
||||||
#include "../ipc/QueueFactory.h"
|
|
||||||
|
|
||||||
HkSwitchHelper::HkSwitchHelper(EventReportingProxyIF* eventProxy) :
|
|
||||||
commandActionHelper(this), eventProxy(eventProxy) {
|
|
||||||
actionQueue = QueueFactory::instance()->createMessageQueue();
|
|
||||||
}
|
|
||||||
|
|
||||||
HkSwitchHelper::~HkSwitchHelper() {
|
|
||||||
QueueFactory::instance()->deleteMessageQueue(actionQueue);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t HkSwitchHelper::initialize() {
|
|
||||||
ReturnValue_t result = commandActionHelper.initialize();
|
|
||||||
|
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t HkSwitchHelper::performOperation(uint8_t operationCode) {
|
|
||||||
CommandMessage command;
|
|
||||||
while (actionQueue->receiveMessage(&command) == HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
ReturnValue_t result = commandActionHelper.handleReply(&command);
|
|
||||||
if (result == HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
command.setToUnknownCommand();
|
|
||||||
actionQueue->reply(&command);
|
|
||||||
}
|
|
||||||
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HkSwitchHelper::stepSuccessfulReceived(ActionId_t actionId, uint8_t step) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void HkSwitchHelper::stepFailedReceived(ActionId_t actionId, uint8_t step,
|
|
||||||
ReturnValue_t returnCode) {
|
|
||||||
eventProxy->forwardEvent(SWITCHING_TM_FAILED, returnCode, actionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HkSwitchHelper::dataReceived(ActionId_t actionId, const uint8_t* data,
|
|
||||||
uint32_t size) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void HkSwitchHelper::completionSuccessfulReceived(ActionId_t actionId) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void HkSwitchHelper::completionFailedReceived(ActionId_t actionId,
|
|
||||||
ReturnValue_t returnCode) {
|
|
||||||
eventProxy->forwardEvent(SWITCHING_TM_FAILED, returnCode, actionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t HkSwitchHelper::switchHK(SerializeIF* sids, bool enable) {
|
|
||||||
// ActionId_t action = HKService::DISABLE_HK;
|
|
||||||
// if (enable) {
|
|
||||||
// action = HKService::ENABLE_HK;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// ReturnValue_t result = commandActionHelper.commandAction(
|
|
||||||
// objects::PUS_HK_SERVICE, action, sids);
|
|
||||||
//
|
|
||||||
// if (result != HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
// eventProxy->forwardEvent(SWITCHING_TM_FAILED, result);
|
|
||||||
// }
|
|
||||||
// return result;
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
MessageQueueIF* HkSwitchHelper::getCommandQueuePtr() {
|
|
||||||
return actionQueue;
|
|
||||||
}
|
|
@ -1,46 +0,0 @@
|
|||||||
#ifndef FRAMEWORK_DATAPOOL_HKSWITCHHELPER_H_
|
|
||||||
#define FRAMEWORK_DATAPOOL_HKSWITCHHELPER_H_
|
|
||||||
|
|
||||||
#include "../tasks/ExecutableObjectIF.h"
|
|
||||||
#include "../action/CommandsActionsIF.h"
|
|
||||||
#include "../events/EventReportingProxyIF.h"
|
|
||||||
|
|
||||||
//TODO this class violations separation between mission and framework
|
|
||||||
//but it is only a transitional solution until the Datapool is
|
|
||||||
//implemented decentrally
|
|
||||||
|
|
||||||
class HkSwitchHelper: public ExecutableObjectIF, public CommandsActionsIF {
|
|
||||||
public:
|
|
||||||
|
|
||||||
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::HK;
|
|
||||||
static const Event SWITCHING_TM_FAILED = MAKE_EVENT(1, severity::LOW); //!< Commanding the HK Service failed, p1: error code, p2 action: 0 disable / 1 enable
|
|
||||||
|
|
||||||
HkSwitchHelper(EventReportingProxyIF *eventProxy);
|
|
||||||
virtual ~HkSwitchHelper();
|
|
||||||
|
|
||||||
ReturnValue_t initialize();
|
|
||||||
|
|
||||||
virtual ReturnValue_t performOperation(uint8_t operationCode = 0);
|
|
||||||
|
|
||||||
ReturnValue_t switchHK(SerializeIF *sids, bool enable);
|
|
||||||
|
|
||||||
virtual void setTaskIF(PeriodicTaskIF* task_){};
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void stepSuccessfulReceived(ActionId_t actionId, uint8_t step);
|
|
||||||
virtual void stepFailedReceived(ActionId_t actionId, uint8_t step,
|
|
||||||
ReturnValue_t returnCode);
|
|
||||||
virtual void dataReceived(ActionId_t actionId, const uint8_t* data,
|
|
||||||
uint32_t size);
|
|
||||||
virtual void completionSuccessfulReceived(ActionId_t actionId);
|
|
||||||
virtual void completionFailedReceived(ActionId_t actionId,
|
|
||||||
ReturnValue_t returnCode);
|
|
||||||
virtual MessageQueueIF* getCommandQueuePtr();
|
|
||||||
|
|
||||||
private:
|
|
||||||
CommandActionHelper commandActionHelper;
|
|
||||||
MessageQueueIF* actionQueue;
|
|
||||||
EventReportingProxyIF *eventProxy;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* FRAMEWORK_DATAPOOL_HKSWITCHHELPER_H_ */
|
|
@ -1,233 +0,0 @@
|
|||||||
#include "PoolDataSetBase.h"
|
|
||||||
#include "ReadCommitIFAttorney.h"
|
|
||||||
|
|
||||||
#include "../serviceinterface/ServiceInterface.h"
|
|
||||||
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
PoolDataSetBase::PoolDataSetBase(PoolVariableIF** registeredVariablesArray,
|
|
||||||
const size_t maxFillCount):
|
|
||||||
registeredVariables(registeredVariablesArray),
|
|
||||||
maxFillCount(maxFillCount) {}
|
|
||||||
|
|
||||||
PoolDataSetBase::~PoolDataSetBase() {}
|
|
||||||
|
|
||||||
|
|
||||||
ReturnValue_t PoolDataSetBase::registerVariable(PoolVariableIF *variable) {
|
|
||||||
if(registeredVariables == nullptr) {
|
|
||||||
/* Underlying container invalid */
|
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
|
||||||
}
|
|
||||||
if (state != States::STATE_SET_UNINITIALISED) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "DataSet::registerVariable: Call made in wrong position." << std::endl;
|
|
||||||
#else
|
|
||||||
sif::printError("DataSet::registerVariable: Call made in wrong position.");
|
|
||||||
#endif
|
|
||||||
return DataSetIF::DATA_SET_UNINITIALISED;
|
|
||||||
}
|
|
||||||
if (variable == nullptr) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "DataSet::registerVariable: Pool variable is nullptr." << std::endl;
|
|
||||||
#else
|
|
||||||
sif::printError("DataSet::registerVariable: Pool variable is nullptr.\n");
|
|
||||||
#endif
|
|
||||||
return DataSetIF::POOL_VAR_NULL;
|
|
||||||
}
|
|
||||||
if (fillCount >= maxFillCount) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "DataSet::registerVariable: DataSet is full." << std::endl;
|
|
||||||
#else
|
|
||||||
sif::printError("DataSet::registerVariable: DataSet is full.\n");
|
|
||||||
#endif
|
|
||||||
return DataSetIF::DATA_SET_FULL;
|
|
||||||
}
|
|
||||||
registeredVariables[fillCount] = variable;
|
|
||||||
fillCount++;
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t PoolDataSetBase::read(MutexIF::TimeoutType timeoutType,
|
|
||||||
uint32_t lockTimeout) {
|
|
||||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
|
||||||
ReturnValue_t error = result;
|
|
||||||
if (state == States::STATE_SET_UNINITIALISED) {
|
|
||||||
lockDataPool(timeoutType, lockTimeout);
|
|
||||||
for (uint16_t count = 0; count < fillCount; count++) {
|
|
||||||
result = readVariable(count);
|
|
||||||
if(result != RETURN_OK) {
|
|
||||||
error = result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
state = States::STATE_SET_WAS_READ;
|
|
||||||
unlockDataPool();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::warning << "PoolDataSetBase::read: Call made in wrong position. Don't forget to "
|
|
||||||
"commit member datasets!" << std::endl;
|
|
||||||
#else
|
|
||||||
sif::printWarning("PoolDataSetBase::read: Call made in wrong position. Don't forget to "
|
|
||||||
"commit member datasets!\n");
|
|
||||||
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
|
||||||
result = SET_WAS_ALREADY_READ;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(error != HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
result = error;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t PoolDataSetBase::getFillCount() const {
|
|
||||||
return fillCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t PoolDataSetBase::readVariable(uint16_t count) {
|
|
||||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
|
||||||
if(registeredVariables[count] == nullptr) {
|
|
||||||
/* Configuration error. */
|
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* These checks are often performed by the respective variable implementation too, but I guess
|
|
||||||
a double check does not hurt. */
|
|
||||||
if (registeredVariables[count]->getReadWriteMode() != PoolVariableIF::VAR_WRITE and
|
|
||||||
registeredVariables[count]->getDataPoolId() != PoolVariableIF::NO_PARAMETER) {
|
|
||||||
if(protectEveryReadCommitCall) {
|
|
||||||
result = registeredVariables[count]->read(timeoutTypeForSingleVars,
|
|
||||||
mutexTimeoutForSingleVars);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* The readWithoutLock function is protected, so we use the attorney here */
|
|
||||||
result = ReadCommitIFAttorney::readWithoutLock(registeredVariables[count]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
result = INVALID_PARAMETER_DEFINITION;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t PoolDataSetBase::commit(MutexIF::TimeoutType timeoutType,
|
|
||||||
uint32_t lockTimeout) {
|
|
||||||
if (state == States::STATE_SET_WAS_READ) {
|
|
||||||
handleAlreadyReadDatasetCommit(timeoutType, lockTimeout);
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return handleUnreadDatasetCommit(timeoutType, lockTimeout);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PoolDataSetBase::handleAlreadyReadDatasetCommit(
|
|
||||||
MutexIF::TimeoutType timeoutType, uint32_t lockTimeout) {
|
|
||||||
lockDataPool(timeoutType, lockTimeout);
|
|
||||||
for (uint16_t count = 0; count < fillCount; count++) {
|
|
||||||
if ((registeredVariables[count]->getReadWriteMode() != PoolVariableIF::VAR_READ) and
|
|
||||||
(registeredVariables[count]->getDataPoolId() != PoolVariableIF::NO_PARAMETER)) {
|
|
||||||
if(protectEveryReadCommitCall) {
|
|
||||||
registeredVariables[count]->commit(timeoutTypeForSingleVars,
|
|
||||||
mutexTimeoutForSingleVars);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* The commitWithoutLock function is protected, so we use the attorney here */
|
|
||||||
ReadCommitIFAttorney::commitWithoutLock(registeredVariables[count]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
state = States::STATE_SET_UNINITIALISED;
|
|
||||||
unlockDataPool();
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t PoolDataSetBase::handleUnreadDatasetCommit(
|
|
||||||
MutexIF::TimeoutType timeoutType, uint32_t lockTimeout) {
|
|
||||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
|
||||||
lockDataPool(timeoutType, lockTimeout);
|
|
||||||
for (uint16_t count = 0; count < fillCount; count++) {
|
|
||||||
if ((registeredVariables[count]->getReadWriteMode() == PoolVariableIF::VAR_WRITE) and
|
|
||||||
(registeredVariables[count]->getDataPoolId() != PoolVariableIF::NO_PARAMETER)) {
|
|
||||||
if(protectEveryReadCommitCall) {
|
|
||||||
result = registeredVariables[count]->commit(timeoutTypeForSingleVars,
|
|
||||||
mutexTimeoutForSingleVars);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* The commitWithoutLock function is protected, so we use the attorney here */
|
|
||||||
ReadCommitIFAttorney::commitWithoutLock(registeredVariables[count]);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (registeredVariables[count]->getDataPoolId()
|
|
||||||
!= PoolVariableIF::NO_PARAMETER) {
|
|
||||||
if (result != COMMITING_WITHOUT_READING) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "DataSet::commit(): commit-without-read call made "
|
|
||||||
"with non write-only variable." << std::endl;
|
|
||||||
#endif
|
|
||||||
result = COMMITING_WITHOUT_READING;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
state = States::STATE_SET_UNINITIALISED;
|
|
||||||
unlockDataPool();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ReturnValue_t PoolDataSetBase::lockDataPool(MutexIF::TimeoutType timeoutType,
|
|
||||||
uint32_t lockTimeout) {
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t PoolDataSetBase::unlockDataPool() {
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t PoolDataSetBase::serialize(uint8_t** buffer, size_t* size,
|
|
||||||
const size_t maxSize, SerializeIF::Endianness streamEndianness) const {
|
|
||||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED;
|
|
||||||
for (uint16_t count = 0; count < fillCount; count++) {
|
|
||||||
result = registeredVariables[count]->serialize(buffer, size, maxSize, streamEndianness);
|
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t PoolDataSetBase::deSerialize(const uint8_t** buffer, size_t* size,
|
|
||||||
SerializeIF::Endianness streamEndianness) {
|
|
||||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED;
|
|
||||||
for (uint16_t count = 0; count < fillCount; count++) {
|
|
||||||
result = registeredVariables[count]->deSerialize(buffer, size,
|
|
||||||
streamEndianness);
|
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t PoolDataSetBase::getSerializedSize() const {
|
|
||||||
uint32_t size = 0;
|
|
||||||
for (uint16_t count = 0; count < fillCount; count++) {
|
|
||||||
size += registeredVariables[count]->getSerializedSize();
|
|
||||||
}
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PoolDataSetBase::setContainer(PoolVariableIF **variablesContainer) {
|
|
||||||
this->registeredVariables = variablesContainer;
|
|
||||||
}
|
|
||||||
|
|
||||||
PoolVariableIF** PoolDataSetBase::getContainer() const {
|
|
||||||
return registeredVariables;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PoolDataSetBase::setReadCommitProtectionBehaviour(
|
|
||||||
bool protectEveryReadCommit, MutexIF::TimeoutType timeoutType,
|
|
||||||
uint32_t mutexTimeout) {
|
|
||||||
this->protectEveryReadCommitCall = protectEveryReadCommit;
|
|
||||||
this->timeoutTypeForSingleVars = timeoutType;
|
|
||||||
this->mutexTimeoutForSingleVars = mutexTimeout;
|
|
||||||
}
|
|
@ -1,180 +0,0 @@
|
|||||||
#ifndef FSFW_DATAPOOL_POOLDATASETBASE_H_
|
|
||||||
#define FSFW_DATAPOOL_POOLDATASETBASE_H_
|
|
||||||
|
|
||||||
#include "PoolDataSetIF.h"
|
|
||||||
#include "PoolVariableIF.h"
|
|
||||||
#include "../serialize/SerializeIF.h"
|
|
||||||
#include "../ipc/MutexIF.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The DataSetBase class manages a set of locally checked out variables.
|
|
||||||
* @details
|
|
||||||
* This class manages a list, where a set of local variables (or pool variables)
|
|
||||||
* are registered. They are checked-out (i.e. their values are looked
|
|
||||||
* up and copied) with the read call. After the user finishes working with the
|
|
||||||
* pool variables, he can write back all variable values to the pool with
|
|
||||||
* the commit call. The data set manages locking and freeing the data pool,
|
|
||||||
* to ensure that all values are read and written back at once.
|
|
||||||
*
|
|
||||||
* An internal state manages usage of this class. Variables may only be
|
|
||||||
* registered before the read call is made, and the commit call only
|
|
||||||
* after the read call.
|
|
||||||
*
|
|
||||||
* If pool variables are writable and not committed until destruction
|
|
||||||
* of the set, the DataSet class automatically sets the valid flag in the
|
|
||||||
* data pool to invalid (without) changing the variable's value.
|
|
||||||
*
|
|
||||||
* The base class lockDataPool und unlockDataPool implementation are empty
|
|
||||||
* and should be implemented to protect the underlying pool type.
|
|
||||||
* @author Bastian Baetz
|
|
||||||
* @ingroup data_pool
|
|
||||||
*/
|
|
||||||
class PoolDataSetBase:
|
|
||||||
public PoolDataSetIF,
|
|
||||||
public SerializeIF,
|
|
||||||
public HasReturnvaluesIF {
|
|
||||||
public:
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Creates an empty dataset. Use registerVariable or
|
|
||||||
* supply a pointer to this dataset to PoolVariable
|
|
||||||
* initializations to register pool variables.
|
|
||||||
*/
|
|
||||||
PoolDataSetBase(PoolVariableIF** registeredVariablesArray, const size_t maxFillCount);
|
|
||||||
|
|
||||||
/* Forbidden for now */
|
|
||||||
PoolDataSetBase(const PoolDataSetBase& otherSet) = delete;
|
|
||||||
const PoolDataSetBase& operator=(const PoolDataSetBase& otherSet) = delete;
|
|
||||||
|
|
||||||
virtual~ PoolDataSetBase();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The read call initializes reading out all registered variables.
|
|
||||||
* It is mandatory to call commit after every read call!
|
|
||||||
* @details
|
|
||||||
* It iterates through the list of registered variables and calls all read()
|
|
||||||
* functions of the registered pool variables (which read out their values
|
|
||||||
* from the data pool) which are not write-only.
|
|
||||||
* In case of an error (e.g. a wrong data type, or an invalid data pool id),
|
|
||||||
* the operation is aborted and @c INVALID_PARAMETER_DEFINITION returned.
|
|
||||||
*
|
|
||||||
* The data pool is locked during the whole read operation and
|
|
||||||
* freed afterwards. It is mandatory to call commit after a read call,
|
|
||||||
* even if the read operation is not successful!
|
|
||||||
* @return
|
|
||||||
* - @c RETURN_OK if all variables were read successfully.
|
|
||||||
* - @c INVALID_PARAMETER_DEFINITION if a pool entry does not exist or there
|
|
||||||
* is a type conflict.
|
|
||||||
* - @c SET_WAS_ALREADY_READ if read() is called twice without calling
|
|
||||||
* commit() in between
|
|
||||||
*/
|
|
||||||
virtual ReturnValue_t read(MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING,
|
|
||||||
uint32_t lockTimeout = 20) override;
|
|
||||||
/**
|
|
||||||
* @brief The commit call initializes writing back the registered variables.
|
|
||||||
* @details
|
|
||||||
* It iterates through the list of registered variables and calls the
|
|
||||||
* commit() method of the remaining registered variables (which write back
|
|
||||||
* their values to the pool).
|
|
||||||
*
|
|
||||||
* The data pool is locked during the whole commit operation and
|
|
||||||
* freed afterwards. The state changes to "was committed" after this operation.
|
|
||||||
*
|
|
||||||
* If the set does contain at least one variable which is not write-only
|
|
||||||
* commit() can only be called after read(). If the set only contains
|
|
||||||
* variables which are write only, commit() can be called without a
|
|
||||||
* preceding read() call. Every read call must be followed by a commit call!
|
|
||||||
* @return - @c RETURN_OK if all variables were read successfully.
|
|
||||||
* - @c COMMITING_WITHOUT_READING if set was not read yet and
|
|
||||||
* contains non write-only variables
|
|
||||||
*/
|
|
||||||
virtual ReturnValue_t commit(MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING,
|
|
||||||
uint32_t lockTimeout = 20) override;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register the passed pool variable instance into the data set.
|
|
||||||
* @param variable
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
virtual ReturnValue_t registerVariable( PoolVariableIF* variable) override;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides the means to lock the underlying data structure to ensure
|
|
||||||
* thread-safety. Default implementation is empty
|
|
||||||
* @return Always returns -@c RETURN_OK
|
|
||||||
*/
|
|
||||||
virtual ReturnValue_t lockDataPool(
|
|
||||||
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING,
|
|
||||||
uint32_t timeoutMs = 20) override;
|
|
||||||
/**
|
|
||||||
* Provides the means to unlock the underlying data structure to ensure
|
|
||||||
* thread-safety. Default implementation is empty
|
|
||||||
* @return Always returns -@c RETURN_OK
|
|
||||||
*/
|
|
||||||
virtual ReturnValue_t unlockDataPool() override;
|
|
||||||
|
|
||||||
virtual uint16_t getFillCount() const;
|
|
||||||
|
|
||||||
/* SerializeIF implementations */
|
|
||||||
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size,
|
|
||||||
const size_t maxSize,
|
|
||||||
SerializeIF::Endianness streamEndianness) const override;
|
|
||||||
virtual size_t getSerializedSize() const override;
|
|
||||||
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
|
||||||
SerializeIF::Endianness streamEndianness) override;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Can be used to individually protect every read and commit call.
|
|
||||||
* @param protectEveryReadCommit
|
|
||||||
* @param mutexTimeout
|
|
||||||
*/
|
|
||||||
void setReadCommitProtectionBehaviour(bool protectEveryReadCommit,
|
|
||||||
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING,
|
|
||||||
uint32_t mutexTimeout = 20);
|
|
||||||
protected:
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The fill_count attribute ensures that the variables
|
|
||||||
* register in the correct array position and that the maximum
|
|
||||||
* number of variables is not exceeded.
|
|
||||||
*/
|
|
||||||
uint16_t fillCount = 0;
|
|
||||||
/**
|
|
||||||
* States of the seet.
|
|
||||||
*/
|
|
||||||
enum class States {
|
|
||||||
STATE_SET_UNINITIALISED, //!< DATA_SET_UNINITIALISED
|
|
||||||
STATE_SET_WAS_READ //!< DATA_SET_WAS_READ
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
* @brief state manages the internal state of the data set,
|
|
||||||
* which is important e.g. for the behavior on destruction.
|
|
||||||
*/
|
|
||||||
States state = States::STATE_SET_UNINITIALISED;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief This array represents all pool variables registered in this set.
|
|
||||||
* Child classes can use a static or dynamic container to create
|
|
||||||
* an array of registered variables and assign the first entry here.
|
|
||||||
*/
|
|
||||||
PoolVariableIF** registeredVariables = nullptr;
|
|
||||||
const size_t maxFillCount = 0;
|
|
||||||
|
|
||||||
void setContainer(PoolVariableIF** variablesContainer);
|
|
||||||
PoolVariableIF** getContainer() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool protectEveryReadCommitCall = false;
|
|
||||||
MutexIF::TimeoutType timeoutTypeForSingleVars = MutexIF::TimeoutType::WAITING;
|
|
||||||
uint32_t mutexTimeoutForSingleVars = 20;
|
|
||||||
|
|
||||||
ReturnValue_t readVariable(uint16_t count);
|
|
||||||
void handleAlreadyReadDatasetCommit(
|
|
||||||
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING,
|
|
||||||
uint32_t timeoutMs = 20);
|
|
||||||
ReturnValue_t handleUnreadDatasetCommit(
|
|
||||||
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING,
|
|
||||||
uint32_t timeoutMs = 20);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* FSFW_DATAPOOL_POOLDATASETBASE_H_ */
|
|
@ -1,36 +0,0 @@
|
|||||||
#ifndef FSFW_DATAPOOL_POOLDATASETIF_H_
|
|
||||||
#define FSFW_DATAPOOL_POOLDATASETIF_H_
|
|
||||||
|
|
||||||
#include "ReadCommitIF.h"
|
|
||||||
#include "DataSetIF.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Extendes the DataSetIF by adding abstract functions to lock
|
|
||||||
* and unlock a data pool and read/commit semantics.
|
|
||||||
*/
|
|
||||||
class PoolDataSetIF:
|
|
||||||
virtual public DataSetIF,
|
|
||||||
virtual public ReadCommitIF {
|
|
||||||
public:
|
|
||||||
virtual~ PoolDataSetIF() {};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Most underlying data structures will have a pool like structure
|
|
||||||
* and will require a lock and unlock mechanism to ensure
|
|
||||||
* thread-safety
|
|
||||||
* @return Lock operation result
|
|
||||||
*/
|
|
||||||
virtual ReturnValue_t lockDataPool(
|
|
||||||
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING,
|
|
||||||
uint32_t timeoutMs = 20) = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Unlock call corresponding to the lock call.
|
|
||||||
* @return Unlock operation result
|
|
||||||
*/
|
|
||||||
virtual ReturnValue_t unlockDataPool() = 0;
|
|
||||||
|
|
||||||
virtual bool isValid() const = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* FSFW_DATAPOOL_POOLDATASETIF_H_ */
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user