Compare commits
739 Commits
mueller/ua
...
develop
Author | SHA1 | Date | |
---|---|---|---|
42867ad0cb | |||
6381d9a83c | |||
73bf1cc229
|
|||
222f02aefd | |||
e9b4fc9825 | |||
0660457c92
|
|||
7c9b9e4cd8
|
|||
3b0ee7ca31
|
|||
fb2e480705 | |||
b8ae646060 | |||
f307a86d9a
|
|||
8b21dd276d | |||
e00da212cd | |||
a229748aa4 | |||
e6e3753324 | |||
94bd1ba2ab | |||
e12a8cfa29 | |||
efbcddc2e5 | |||
31d4b85523 | |||
aff6bb673b
|
|||
f8e3777c43
|
|||
0e2fa8dc83
|
|||
0cfe559b93
|
|||
c5159fb645
|
|||
203c0bac5c
|
|||
43ea29cb84 | |||
27c8a97d45 | |||
47b21caf5f | |||
2673070204 | |||
518a07d05b | |||
516357d855 | |||
ac28b7e00d | |||
0d4a862c1a | |||
b2576d3422 | |||
bccaf4a9ea | |||
7d4e77843b | |||
cd2cd61ba5 | |||
90f3f8ef1f | |||
9894935e99 | |||
a3a6c0720c | |||
d5a52eadbb | |||
b5e7179af1 | |||
5879eb7f7b | |||
e64e8b274d | |||
48bcce65b1 | |||
7105e199c6 | |||
94de483836 | |||
c648229c99 | |||
5b661551a8 | |||
3978524181 | |||
7187f2b5cd | |||
8e367abb47 | |||
b28174db24 | |||
c906acd659 | |||
8dfc84c0b5 | |||
74775bb59d | |||
c02d9e009e | |||
0021aa29f5 | |||
41d67bff63 | |||
8d7bb51d44
|
|||
7673d8b396
|
|||
91b194d8eb | |||
698897bfc5 | |||
d554062b86
|
|||
bf7fac071c | |||
35be7da353
|
|||
18cc870c8e
|
|||
133ca51d18
|
|||
0a40391a75
|
|||
cc3e64e70d | |||
6021257a87
|
|||
63c238005e | |||
0f604b35c6 | |||
e3a815444e | |||
19093866ee | |||
497f947237
|
|||
5bd020193b
|
|||
420c0625a5
|
|||
42a0b15303
|
|||
c199cbedaa
|
|||
c4e18cc2f3
|
|||
c143198494
|
|||
448fbd0d38
|
|||
470f589bde
|
|||
dfcfb035be
|
|||
6e53582dc9
|
|||
fb1500e041
|
|||
ea2e58249d
|
|||
9ef63825f3
|
|||
073cb4b3d5
|
|||
8c11685240
|
|||
cb1aaea6cd
|
|||
22df8f6147
|
|||
60dcacf432
|
|||
b39e1c7e07 | |||
036667a969
|
|||
67c38f327e
|
|||
e1816ed230
|
|||
5ff464252f
|
|||
cd8d64830c
|
|||
b7056a7467
|
|||
0fc2c7b5e9
|
|||
eae7c44874
|
|||
e4aae75747
|
|||
b094ba145f
|
|||
15629abf19
|
|||
7aeb25e064
|
|||
d246ce34d0 | |||
796c7a9e37 | |||
7c875f1067
|
|||
e8451cac31
|
|||
8ddd6eb18d
|
|||
6c6b552059
|
|||
9a1437980f
|
|||
12e52a92f2
|
|||
dffce43e6b
|
|||
daf75547a4
|
|||
0cccf26021
|
|||
c075f27e20
|
|||
3167988951
|
|||
a856f91c67
|
|||
f49e607881
|
|||
0f208ec75a
|
|||
5679b139ad
|
|||
947f2b8685
|
|||
291c75c01f
|
|||
fde277cd06
|
|||
bb186fc965
|
|||
e8bf8b9575
|
|||
8f5a8b13d3
|
|||
314cba363f
|
|||
244e2d0737
|
|||
8f0974d83e
|
|||
8581f9a6f3
|
|||
844c90a625
|
|||
437851db3e
|
|||
e8b9897ee3
|
|||
33df8e8cc5
|
|||
52fc0958f7
|
|||
66704dc571
|
|||
0943863ec6
|
|||
2585028e75
|
|||
7bf7336d4a
|
|||
b0b6c68720
|
|||
a1f36a0dd8
|
|||
e4665c9394
|
|||
98cbf38432
|
|||
5d3f00da7f
|
|||
69fd6d0f6a
|
|||
045054fce0
|
|||
4c9e731113 | |||
e00e198ff1
|
|||
9c8434d856
|
|||
42c215ef70
|
|||
273fd3ebfd
|
|||
6c9c4ee047
|
|||
1bfb695b41
|
|||
1561b9a247
|
|||
896b7a7358
|
|||
8e62143ac8
|
|||
1d97327f79
|
|||
5e9d402598
|
|||
b53c48863f
|
|||
4dc6398fd5
|
|||
8fcc4eab60
|
|||
972dc7e19e
|
|||
06ef498a18
|
|||
6322a31566
|
|||
95b77ed826
|
|||
3b1da85229
|
|||
1cbcfc08ff
|
|||
d575da8540 | |||
ca27cef2ee
|
|||
62ace649a7
|
|||
aac74fae38
|
|||
a26b0c38ac
|
|||
f44110a7f5
|
|||
35712070cf
|
|||
1b79713430 | |||
a6cc5171da
|
|||
9994c46e47 | |||
cf927ecee7
|
|||
42e74d22cc | |||
36caa58043 | |||
988e07f0be
|
|||
88e8665280
|
|||
9c8b1c697b
|
|||
110cb903a6
|
|||
1b23aa4246
|
|||
7d713219c5
|
|||
1be09a2310
|
|||
7add782470
|
|||
8da89eba80 | |||
7e8845f2c2 | |||
6aff3250c2 | |||
c3572e31a8
|
|||
2293e7f2bb | |||
a85a38c882 | |||
0f76cdb3ba | |||
268c2e87c9 | |||
87f94a252f | |||
c7037d417a | |||
f80c5980ea | |||
ad01642fee | |||
f2947bc78e | |||
0a977ea688 | |||
74b164b1da | |||
5322de0599 | |||
9a4bf51006 | |||
3a70229510 | |||
b3beedad9f | |||
efe217a197 | |||
b442ca09b9 | |||
9372b2a575 | |||
aafa53148e | |||
e0adb3325f | |||
4391823f01 | |||
1a77e6bb09 | |||
cae131edcf | |||
4518fec65c | |||
dac1aacab2 | |||
0042f92fdf | |||
656faf8169 | |||
f84431e965 | |||
0cec9ebb73 | |||
a440b7c394 | |||
bbfc1b2b34 | |||
025b379e8b
|
|||
258f0d3313 | |||
5eb9ee8bc1 | |||
7f61d17cee | |||
ffa2fa477f | |||
894d1e3b87 | |||
285d327b97 | |||
e97fa5ac84 | |||
5a9304765f | |||
6650c293da | |||
9fca7581dd | |||
4af90f99f3 | |||
94cdf67a80 | |||
7966ede11b | |||
7a392dc33a | |||
1e3c89b672 | |||
e2e87b149d | |||
4f632e2c68 | |||
314f0fa2cd | |||
b31e1037fb | |||
b814e7198f | |||
6328b70d7b | |||
a937b457f9 | |||
4415dc24e1 | |||
e704295cce | |||
d16b3c7e67 | |||
3b86545725 | |||
cf6150cc18 | |||
bfb5c2ff03 | |||
bf02061d47 | |||
2c4e110254 | |||
7ed75ea87b | |||
db4587bb59 | |||
33ac395072 | |||
f8a7c1d4ed | |||
341437df13 | |||
227524a21d | |||
0f81d5e458 | |||
b50f092939 | |||
2f90e12179 | |||
8b77fac099 | |||
47503824d7 | |||
5e3f5c4121 | |||
1f36c082ef | |||
aa84e93603 | |||
8f63a0e747 | |||
6fc8f756a7 | |||
d98ed40e3d | |||
b057250bfb | |||
066dd0d397 | |||
f735c2e9d4 | |||
43fd0b2f59 | |||
d0607824ad | |||
cf27954a86 | |||
f84e3284ab | |||
5250423d1d | |||
522bd41d6e | |||
c61c85280b | |||
afbe5e1f65 | |||
4c88ab80c8 | |||
5ba69b169f | |||
40405fe6c7 | |||
aac32e763c | |||
bf980d74c0 | |||
b6b9d1d790 | |||
0973ba6bf2 | |||
1cfebb5d47 | |||
0b0a0299bc | |||
8382d61b92 | |||
7208343b6d | |||
9a8d775eb1 | |||
4d6f6e6b23 | |||
55f6825a03 | |||
c162acb7df | |||
87462afe6d | |||
a8de395ea0 | |||
f0bddfcb21 | |||
23d9b44b3e | |||
26e4445189 | |||
9ee3cdf729 | |||
1b7493f945 | |||
7f6ba5f40b | |||
070b48ada2 | |||
d9a139e1ef | |||
c80a3752d9 | |||
af58c414fc | |||
4c48668125 | |||
2745b2080d | |||
e9d9f44605 | |||
2c5af91db1 | |||
5cd7b98ba7 | |||
a39f1271ec | |||
bbf0d7a0d2 | |||
04ee3c7362 | |||
95dab69b35 | |||
33de15205b | |||
4d353a1ad2 | |||
6006c97e48 | |||
6e17e45506 | |||
64537d442a | |||
78cf00315d | |||
245886c555 | |||
f84097543e | |||
511d07c0c7 | |||
cf735143fe | |||
bdfe31dba4 | |||
216f603d62 | |||
174a6aa862 | |||
c2d9370aa1 | |||
893b434728 | |||
6eba84566d | |||
f0415a97b1 | |||
abcf1b29b2 | |||
dc7afc5415 | |||
9bf3ff95b7 | |||
61562b18ab | |||
d76d97a36b | |||
d373c45d36 | |||
bd208038dd | |||
206af00c8b | |||
2efff4d2c5 | |||
2a0c244468 | |||
e1711f0345 | |||
c327985222 | |||
76b377c4c0 | |||
b45206ccd6 | |||
c8469ca647 | |||
2d6622b8b8 | |||
5f9eb01d94 | |||
3568bdbecf | |||
fcd84b59ae | |||
e3c968096b | |||
c745c0c8b4 | |||
be015b4c66 | |||
dae5e988fd | |||
a6d707a7db | |||
fe41d73895 | |||
70b785984c | |||
9de6c4b3aa | |||
d256ede8c1 | |||
f0b8457ba2 | |||
dac2d210b5 | |||
8b4f73a97b | |||
7fae6cbd6d | |||
d302ba7185 | |||
3562bf11b9 | |||
fffb2b61e5 | |||
94e5f62331 | |||
14a92b3d89 | |||
e4fd424d66 | |||
341a66c265 | |||
b9b076aa4c | |||
d93486a340 | |||
820a7f059c | |||
f4d188c36f | |||
1841f92944 | |||
b279985859 | |||
0a9c563bbc | |||
fa7675897d | |||
3a2393885f | |||
c752b6d143 | |||
b676040c7c | |||
010509efb4 | |||
dfb1633f00 | |||
5f7172e130 | |||
0c6465cd95 | |||
f94987c46d | |||
1809ce359b | |||
8c712441ab | |||
6ce80ea6c5 | |||
f1b0ca7cff | |||
000df85556 | |||
1fffcc2229 | |||
6f05d6b7b0 | |||
7f907fb9d3 | |||
a419806a05 | |||
84bbef0167 | |||
88b2b0e005 | |||
6445debfa1 | |||
8014e4adf9 | |||
84dc7ac0ce | |||
ec12ab5daa | |||
134d908f26 | |||
40a9e12416 | |||
f39054edd4 | |||
5adf89b911 | |||
c2e6a22dec | |||
c8e065a713 | |||
69c94645df | |||
37e850c5a7 | |||
3ed49dbae3 | |||
a1567de9e8 | |||
4cf52d5dfe | |||
2646707d3f | |||
539d7aac9e | |||
0a23f2c85a | |||
06e30684fe | |||
46230e6c6d | |||
b22d439300 | |||
7e7b3bbbc9 | |||
06dca7608a | |||
6af5274b68 | |||
5b92247fbd | |||
e2b66df72e | |||
d9da55fdab | |||
7b828f233a | |||
c3d1000cd5 | |||
8e0e57714d | |||
066f7a6f9b | |||
cc9e54ea6b | |||
31465a4e0f | |||
c0e5d1eb99 | |||
3bc5d4a2e0 | |||
b1e9dd9e4a | |||
ab86599db3 | |||
034eb34c2e | |||
38789e053b | |||
4374c7c4f4 | |||
5343844be5 | |||
e11eabdbcf | |||
3250bbf269 | |||
a78fe0a7f3 | |||
acfc1cbf21 | |||
d17ec02cf0 | |||
e300490b93 | |||
f2461cd7e9 | |||
01cc619e67 | |||
0f811777a7 | |||
e93137939e | |||
2339712373 | |||
c1f42618db | |||
d9d253d3bb | |||
bd586f6564 | |||
1f88c006d9 | |||
5f481739d8 | |||
7e94baceef | |||
7ee83e4e5d | |||
64787f85ca | |||
61df451dd8 | |||
29ea89044e | |||
e487f5be87 | |||
1cacceddad | |||
5c35b8e3cd | |||
9b05e8f274 | |||
7766b24a1d | |||
eb223dae88 | |||
3656662d88 | |||
fe71978467 | |||
b646717a76 | |||
99d8c845f2 | |||
9a4ae550ab | |||
c64b9b3e71 | |||
226818886f | |||
da12495335 | |||
0cc3231ceb | |||
049e3b431d | |||
bd189518b6 | |||
0e7c6b117f | |||
accaf855ee | |||
75fa7caf25 | |||
d16c5024dc | |||
a4531e4ced | |||
97c629ad84 | |||
bf12f284fa | |||
ba62c28b64 | |||
041d1b8795 | |||
7adb47aecb | |||
5bb66c9723 | |||
8589f4d63a | |||
ca80589233 | |||
f2ebaed092 | |||
f0b89e98df | |||
2aa4af6974 | |||
75fc7a056d | |||
05cad893a2 | |||
5557d95994 | |||
fc24c9b5d8 | |||
1b005d706a | |||
5b0ea91222 | |||
7ef69c839c | |||
9b798d798e | |||
e68f54b9bd | |||
8eb869e073 | |||
b13453f46b | |||
d0e322d7e2 | |||
46a1c2bace | |||
2643ff194c | |||
ecde164f68 | |||
50930b41ba | |||
296bc56e2a | |||
d6ee2ed400 | |||
f2150ff9c2 | |||
1b9c98f3fe | |||
742152b28e | |||
bf4ca56658 | |||
16ffa00155 | |||
14c681c93a | |||
0958c3a00e | |||
d699d16307 | |||
3b0fed733f | |||
23d3812fe3 | |||
dec7db3ae2 | |||
65a5abab49 | |||
0129783e34 | |||
cabe0868ec | |||
f05295bada | |||
160ff799ac | |||
b85ca64690 | |||
3bc3da5a8d | |||
f8c07ec9cf | |||
8199b8f359 | |||
cbc8dbcdd4 | |||
d31a5306f0 | |||
a236a5ec50 | |||
03620970e2 | |||
8fe8d810e9 | |||
9483c2809d | |||
fe3d6bd432 | |||
c5f91926c9 | |||
be4a87535d | |||
99927b8e95 | |||
5e5eb82830 | |||
686dc97234 | |||
2a842666d5 | |||
c013fcc1f5 | |||
1f58ba1f9b | |||
002845108d | |||
1b8fc2af19 | |||
72d7c43445 | |||
ab9b6c8c89 | |||
69d338f9bb | |||
68223869d5 | |||
93fda71989 | |||
7b0db08962 | |||
0956fbc740 | |||
b48e0fdc0d | |||
1d084ee22f | |||
1bea2344f6 | |||
d7e16a67a7 | |||
6021d897b8 | |||
83a6f0b5f8 | |||
a9c6c088f2 | |||
2b6a33e718 | |||
61fd5d1b62 | |||
046dbe1deb | |||
e03e7f5260 | |||
b6a3c206cc | |||
5b352978c5 | |||
0303c1a885 | |||
4d2802a470 | |||
819a298b19 | |||
39946bff58 | |||
16246d6ece | |||
5c84f12440 | |||
2a203ae13d | |||
6ca1a5c796 | |||
83c2c4825c | |||
194b3e100a | |||
177c39dd53 | |||
530a261e14 | |||
c913fe40bf | |||
70ec08bf1d | |||
ef23665d9c | |||
eefc122292 | |||
bee33526a1 | |||
0e8f5ddd26 | |||
672fca5169 | |||
84b9d1ce21 | |||
e5b5c7d253 | |||
9a0cc64be3 | |||
00f1c5bbe9 | |||
8a61af779d | |||
6efa482eb0 | |||
f0fa1bf477 | |||
91ebf98c28 | |||
e1d4209fbe | |||
e302c89f74 | |||
a38279f813 | |||
7600ed1ea7 | |||
61ab770d9d | |||
033676ad3b | |||
e2eeccce50 | |||
f805667779 | |||
af06969905 | |||
2461209169 | |||
f715b65d6e | |||
c11af63015 | |||
852f27cec2 | |||
226dc4d8b7 | |||
fa01798ebb | |||
1b7e94d718 | |||
60ff411721 | |||
bddc7a7ca6 | |||
819a2bfac4 | |||
1f05e6b297 | |||
11a22577be | |||
dc1583c932 | |||
94f1f1f908 | |||
81a7de2814 | |||
d26f230bee | |||
4db124c680 | |||
955579c856 | |||
2df66c9304 | |||
54ad6b3016 | |||
73e313c35b | |||
c6585c8645 | |||
dd2f42d22b | |||
d8a4675842 | |||
b0c5a49b50 | |||
1164c21ddd | |||
096af44e39 | |||
56e8e5a8b3 | |||
11422a658c | |||
754b71a35f | |||
2de9e25ceb | |||
ec7566fb8c | |||
73454c629c | |||
77b1a85b47 | |||
0c5c2f6c4f | |||
009700ce80 | |||
652c31a683 | |||
1e43296f2b | |||
1aa062df7f | |||
bfe120636c | |||
a8041f220f | |||
dd636b186b | |||
3349fc36f8 | |||
14a8924a83 | |||
9f81926aec | |||
79c38b45df | |||
e893e73f86 | |||
f3e9277e59 | |||
d592f1ecbc | |||
6ec18171a8 | |||
518dcdef4b | |||
d9730032fd | |||
b3ac72b7db | |||
cd0cb43412 | |||
32c12b3dbf | |||
3e9acf476e | |||
99101ce2bf | |||
6b991045f7 | |||
df06064df0 | |||
1d6ccfe5ab | |||
221df7ece6 | |||
7f180ac1fa | |||
337cb0d6c9 | |||
692be9df8d | |||
8195587604 | |||
1c53b60442 | |||
d1630cdc4c | |||
49747fc8a4 | |||
cfc00d0260 | |||
c283e0c988 | |||
448d20f3bd | |||
2316728d74 | |||
6f562e5f3e | |||
1eceef4645 | |||
176f243194 | |||
d964fa2107 | |||
7b5ae6a445 | |||
8e362a000c | |||
7877776e24 | |||
acab5f6bce | |||
10dd855244 | |||
f824004897 | |||
7c5308429c | |||
f78344b8fb | |||
3de0ae5a48 | |||
77f7fa2ef1 | |||
78314ad966 | |||
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 | |||
bdbe0cc9da | |||
bcbbc9763a | |||
0042372cb6 | |||
8dea13742f | |||
0f027d29d2 | |||
ce7146e468 | |||
a681a4a797 | |||
83b7b8707c | |||
4002b74ea2 | |||
4f7f8310c9 | |||
6eea711d9f | |||
9d626e0a5d |
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,5 +1,5 @@
|
||||
# PyCharm and CLion
|
||||
/.idea/*
|
||||
.idea/*
|
||||
!/.idea/runConfigurations
|
||||
!/.idea/cmake.xml
|
||||
!/.idea/codeStyles
|
||||
|
8
.idea/cmake.xml
generated
Normal file
8
.idea/cmake.xml
generated
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CMakeSharedSettings">
|
||||
<configurations>
|
||||
<configuration PROFILE_NAME="Debug Test" ENABLED="true" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DFSFW_OSAL=host -DFSFW_BUILD_TESTS=ON" NO_GENERATOR="true" />
|
||||
</configurations>
|
||||
</component>
|
||||
</project>
|
200
CHANGELOG.md
200
CHANGELOG.md
@ -8,32 +8,165 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
# [unreleased]
|
||||
|
||||
# [v6.0.0]
|
||||
## Fixes
|
||||
|
||||
- The `PusTmCreator` API only accepted 255 bytes of source data. It can now accept source
|
||||
data with a size limited only by the size of `size_t`.
|
||||
- Important bugfix in CFDP PDU header format: The entity length field and the transaction sequence
|
||||
number fields stored the actual length of the field instead of the length minus 1 like specified
|
||||
in the CFDP standard.
|
||||
- PUS Health Service: Size check for set health command.
|
||||
Perform operation completion for announce health command.
|
||||
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/746
|
||||
- Linux OSAL `getUptime` fix: Check validity of `/proc/uptime` file before reading uptime.
|
||||
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/745
|
||||
- Small tweak for version getter
|
||||
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/744
|
||||
|
||||
## Added
|
||||
|
||||
- add CFDP subsystem ID
|
||||
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/742
|
||||
- `PusTmZcWriter` now exposes API to set message counter field.
|
||||
- Relative timeshift in the PUS time service.
|
||||
|
||||
## Changed
|
||||
|
||||
- The PUS time service now dumps the time before setting a new time and after having set the
|
||||
time.
|
||||
- HK generation is now countdown based.
|
||||
- Bump ETL version to 20.35.14
|
||||
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/748
|
||||
- Renamed `PCDU_2` subsystem ID to `POWER_SWITCH_IF`.
|
||||
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/743
|
||||
- Add new `PowerSwitchIF::SWITCH_UNKNOWN` returnvalue.
|
||||
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/743
|
||||
- Assert that `FixedArrayList` is larger than 0 at compile time.
|
||||
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/740
|
||||
- Health functions are virtual now.
|
||||
- PUS Service Base request queue depth and maximum number of handled packets per cycle is now
|
||||
configurable.
|
||||
|
||||
# [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
|
||||
|
||||
- DHB TM handler `handleDeviceTM` renamed to `handleDeviceTm` and now takes
|
||||
`util::DataWrapper` as the data input argument. This allows more flexibility in the possible
|
||||
types of telemetry.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/669
|
||||
- Add `util::DataWrapper` class inside the `util` module. This is a tagged union which allows
|
||||
to specify raw data either as a classic C-style raw pointer and size or as a `SerializeIF`
|
||||
pointer.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/668
|
||||
- `CServiceHealthCommanding`: Add announce all health info implementation
|
||||
PR: https://egit.irs.uni-stuttgart.de/eive/fsfw/pulls/122
|
||||
- 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)`
|
||||
@ -66,10 +199,37 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
- Make functions `const` where it makes sense
|
||||
- Add `const char* getName const` abstract function
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/684
|
||||
- Move some generic `StorageManagerIF` implementations from `LocalPool` to
|
||||
interface itself so it can be re-used more easily. Also add new
|
||||
abstract function `bool hasDataAtId(store_address_t storeId) const`.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/685
|
||||
- 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
|
||||
|
||||
@ -89,7 +249,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
implementation without an extra component
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/682
|
||||
|
||||
# [v5.0.0] 25.07.2022
|
||||
# [v5.0.0] 2022-07-25
|
||||
|
||||
## Changes
|
||||
|
||||
@ -222,6 +382,7 @@ https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/593
|
||||
- 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
|
||||
@ -236,17 +397,6 @@ https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/593
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/590
|
||||
- `Subsystem`: New API to add table and sequence entries
|
||||
|
||||
## HAL
|
||||
|
||||
- SPI: Cache the SPI device in the communication interface. Architecturally, this makes a
|
||||
lot more sense because each ComIF should be responsible for one SPI bus.
|
||||
- SPI: Move the empty transfer to update the line polarity to separate function. This means
|
||||
it is not automatically called when calling the setter function for SPI speed and mode.
|
||||
The user should call this function after locking the CS mutex if multiple SPI devices with
|
||||
differing speeds and modes are attached to one bus.
|
||||
- SPI: Getter functions for SPI speed and mode.
|
||||
- I2C: Add wiretapping option for I2C. Enabled with `FSFW_HAL_I2C_WIRETAPPING` defined to 1.
|
||||
|
||||
## Fixed
|
||||
|
||||
- TCP TMTC Server: `MutexGuard` was not created properly in
|
||||
|
@ -13,7 +13,7 @@ list(APPEND CMAKE_MODULE_PATH
|
||||
# Version file handling #
|
||||
# ##############################################################################
|
||||
|
||||
set(FSFW_VERSION_IF_GIT_FAILS 5)
|
||||
set(FSFW_VERSION_IF_GIT_FAILS 6)
|
||||
set(FSFW_SUBVERSION_IF_GIT_FAILS 0)
|
||||
set(FSFW_REVISION_IF_GIT_FAILS 0)
|
||||
|
||||
@ -72,7 +72,7 @@ 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
|
||||
${FSFW_ETL_LIB_MAJOR_VERSION}.35.14
|
||||
CACHE STRING "ETL library exact version requirement")
|
||||
set(FSFW_ETL_LINK_TARGET etl::etl)
|
||||
|
||||
@ -122,6 +122,7 @@ 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
|
||||
@ -152,12 +153,12 @@ if(FSFW_BUILD_TESTS)
|
||||
"${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})
|
||||
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"
|
||||
"${MSG_PREFIX} Catch2 installation not found. Downloading Catch2 library with FetchContent."
|
||||
)
|
||||
include(FetchContent)
|
||||
|
||||
@ -195,13 +196,13 @@ message(
|
||||
)
|
||||
|
||||
# Check whether the user has already installed ETL first
|
||||
find_package(${FSFW_ETL_LIB_NAME} ${FSFW_ETL_LIB_MAJOR_VERSION} CONFIG QUIET)
|
||||
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} No ETL installation was found with find_package. Installing and providing "
|
||||
"etl with FindPackage")
|
||||
"${MSG_PREFIX} ETL installation not found. Downloading ETL with FetchContent."
|
||||
)
|
||||
include(FetchContent)
|
||||
|
||||
FetchContent_Declare(
|
||||
@ -326,7 +327,8 @@ if(FSFW_BUILD_TESTS)
|
||||
"/usr/local/include/*"
|
||||
"*/fsfw_tests/*"
|
||||
"*/catch2-src/*"
|
||||
"*/fsfw_hal/*")
|
||||
"*/fsfw_hal/*"
|
||||
"unittests/*")
|
||||
endif()
|
||||
|
||||
target_link_options(${FSFW_TEST_TGT} PRIVATE -fprofile-arcs
|
||||
@ -344,8 +346,15 @@ if(FSFW_BUILD_TESTS)
|
||||
DEPENDENCIES ${FSFW_TEST_TGT})
|
||||
else()
|
||||
setup_target_for_coverage_lcov(
|
||||
NAME ${FSFW_TEST_TGT}_coverage EXECUTABLE ${FSFW_TEST_TGT}
|
||||
DEPENDENCIES ${FSFW_TEST_TGT})
|
||||
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()
|
||||
|
@ -5,7 +5,7 @@ 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
|
||||
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
|
||||
|
||||
@ -23,3 +23,7 @@ RUN git clone https://github.com/ETLCPP/etl.git && \
|
||||
|
||||
#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
|
110
automation/Jenkinsfile
vendored
110
automation/Jenkinsfile
vendored
@ -1,45 +1,87 @@
|
||||
pipeline {
|
||||
environment {
|
||||
BUILDDIR = 'cmake-build-tests'
|
||||
BUILDDIR_HOST = 'cmake-build-tests-host'
|
||||
BUILDDIR_LINUX = 'cmake-build-tests-linux'
|
||||
DOCDDIR = 'cmake-build-documentation'
|
||||
}
|
||||
agent {
|
||||
docker {
|
||||
image 'fsfw-ci:d5'
|
||||
args '--network host'
|
||||
image 'fsfw-ci:d6'
|
||||
args '--network host --sysctl fs.mqueue.msg_max=100'
|
||||
}
|
||||
}
|
||||
stages {
|
||||
stage('Clean') {
|
||||
steps {
|
||||
sh 'rm -rf $BUILDDIR'
|
||||
}
|
||||
}
|
||||
stage('Configure') {
|
||||
steps {
|
||||
dir(BUILDDIR) {
|
||||
sh 'cmake -DFSFW_OSAL=host -DFSFW_BUILD_TESTS=ON -DFSFW_CICD_BUILD=ON ..'
|
||||
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('Build') {
|
||||
steps {
|
||||
dir(BUILDDIR) {
|
||||
sh 'cmake --build . -j4'
|
||||
stage('Linux') {
|
||||
stages{
|
||||
stage('Clean') {
|
||||
steps {
|
||||
sh 'rm -rf $BUILDDIR_LINUX'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Unittests') {
|
||||
steps {
|
||||
dir(BUILDDIR) {
|
||||
sh 'cmake --build . -- fsfw-tests_coverage -j4'
|
||||
stage('Configure') {
|
||||
steps {
|
||||
dir(BUILDDIR_LINUX) {
|
||||
sh 'cmake -DFSFW_OSAL=linux -DFSFW_BUILD_TESTS=ON -DFSFW_CICD_BUILD=ON ..'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Valgrind') {
|
||||
steps {
|
||||
dir(BUILDDIR) {
|
||||
sh 'valgrind --leak-check=full --error-exitcode=1 ./fsfw-tests'
|
||||
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'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -52,14 +94,12 @@ pipeline {
|
||||
sh 'cmake -DFSFW_BUILD_DOCS=ON -DFSFW_OSAL=host ..'
|
||||
sh 'make Sphinx'
|
||||
sshagent(credentials: ['documentation-buildfix']) {
|
||||
sh 'ssh -o StrictHostKeyChecking=no buildfix@documentation.intra.irs.uni-stuttgart.de rm -rf /mnt/data/www/html/fsfw/development/*'
|
||||
sh 'scp -o StrictHostKeyChecking=no -r docs/sphinx/* buildfix@documentation.intra.irs.uni-stuttgart.de:/mnt/data/www/html/fsfw/development'
|
||||
sh 'rsync -r --delete docs/sphinx/* buildfix@documentation.irs.uni-stuttgart.de:/fsfw/development'
|
||||
}
|
||||
}
|
||||
dir(BUILDDIR) {
|
||||
sshagent(credentials: ['documentation-buildfix']) {
|
||||
sh 'ssh -o StrictHostKeyChecking=no buildfix@documentation.intra.irs.uni-stuttgart.de rm -rf /mnt/data/www/html/fsfw/coverage/development/*'
|
||||
sh 'scp -o StrictHostKeyChecking=no -r fsfw-tests_coverage/* buildfix@documentation.intra.irs.uni-stuttgart.de:/mnt/data/www/html/fsfw/coverage/development'
|
||||
sh 'rsync -r --delete fsfw-tests_coverage/* buildfix@documentation.irs.uni-stuttgart.de:/fsfw/coverage/development'
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -73,14 +113,12 @@ pipeline {
|
||||
sh 'cmake -DFSFW_BUILD_DOCS=ON -DFSFW_OSAL=host ..'
|
||||
sh 'make Sphinx'
|
||||
sshagent(credentials: ['documentation-buildfix']) {
|
||||
sh 'ssh -o StrictHostKeyChecking=no buildfix@documentation.intra.irs.uni-stuttgart.de rm -rf /mnt/data/www/html/fsfw/master/*'
|
||||
sh 'scp -o StrictHostKeyChecking=no -r docs/sphinx/* buildfix@documentation.intra.irs.uni-stuttgart.de:/mnt/data/www/html/fsfw/master'
|
||||
sh 'rsync -r --delete docs/sphinx/* buildfix@documentation.irs.uni-stuttgart.de:/fsfw/master'
|
||||
}
|
||||
}
|
||||
dir(BUILDDIR) {
|
||||
sshagent(credentials: ['documentation-buildfix']) {
|
||||
sh 'ssh -o StrictHostKeyChecking=no buildfix@documentation.intra.irs.uni-stuttgart.de rm -rf /mnt/data/www/html/fsfw/coverage/master/*'
|
||||
sh 'scp -o StrictHostKeyChecking=no -r fsfw-tests_coverage/* buildfix@documentation.intra.irs.uni-stuttgart.de:/mnt/data/www/html/fsfw/coverage/master'
|
||||
sh 'rsync -r --delete fsfw-tests_coverage/* buildfix@documentation.irs.uni-stuttgart.de:/fsfw/coverage/master'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -140,7 +140,7 @@ 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 PATHS ${CMAKE_SOURCE_DIR}/scripts/test)
|
||||
find_program( GCOVR_PATH gcovr )
|
||||
find_program( CPPFILT_PATH NAMES c++filt )
|
||||
|
||||
if(NOT GCOV_PATH)
|
||||
|
@ -1,40 +0,0 @@
|
||||
Configuring the FSFW
|
||||
======
|
||||
|
||||
The FSFW can be configured via the `fsfwconfig` folder. A template folder has
|
||||
been provided to have a starting point for this. The folder should be added
|
||||
to the include path. The primary configuration file is the `FSFWConfig.h` folder. Some
|
||||
of the available options will be explained in more detail here.
|
||||
|
||||
# Auto-Translation of Events
|
||||
|
||||
The FSFW allows the automatic translation of events, which allows developers to track triggered
|
||||
events directly via console output. Using this feature requires:
|
||||
|
||||
1. `FSFW_OBJ_EVENT_TRANSLATION` set to 1 in the configuration file.
|
||||
2. Special auto-generated translation files which translate event IDs and object IDs into
|
||||
human readable strings. These files can be generated using the
|
||||
[modgen Python scripts](https://git.ksat-stuttgart.de/source/modgen.git).
|
||||
3. The generated translation files for the object IDs should be named `translatesObjects.cpp`
|
||||
and `translateObjects.h` and should be copied to the `fsfwconfig/objects` folder
|
||||
4. The generated translation files for the event IDs should be named `translateEvents.cpp` and
|
||||
`translateEvents.h` and should be copied to the `fsfwconfig/events` folder
|
||||
|
||||
An example implementations of these translation file generators can be found as part
|
||||
of the [SOURCE project here](https://git.ksat-stuttgart.de/source/sourceobsw/-/tree/development/generators)
|
||||
or the [FSFW example](https://egit.irs.uni-stuttgart.de/fsfw/fsfw_example_public/src/branch/master/generators)
|
||||
|
||||
## Configuring the Event Manager
|
||||
|
||||
The number of allowed subscriptions can be modified with the following
|
||||
parameters:
|
||||
|
||||
``` c++
|
||||
namespace fsfwconfig {
|
||||
//! Configure the allocated pool sizes for the event manager.
|
||||
static constexpr size_t FSFW_EVENTMGMR_MATCHTREE_NODES = 240;
|
||||
static constexpr size_t FSFW_EVENTMGMT_EVENTIDMATCHERS = 120;
|
||||
static constexpr size_t FSFW_EVENTMGMR_RANGEMATCHERS = 120;
|
||||
}
|
||||
```
|
||||
|
@ -1 +0,0 @@
|
||||
## Controllers
|
@ -1,55 +0,0 @@
|
||||
## FSFW Core Modules
|
||||
|
||||
These core modules provide the most important functionalities of the
|
||||
Flight Software Framework
|
||||
|
||||
### Clock
|
||||
|
||||
* This is a class of static functions that can be used at anytime
|
||||
* Leap Seconds must be set if any time conversions from UTC to other times is used
|
||||
|
||||
### ObjectManager
|
||||
|
||||
* Must be created during program startup
|
||||
* The component which handles all references. All SystemObjects register at this component.
|
||||
* Any SystemObject needs to have a unique ObjectId. Those can be managed like objects::framework_objects.
|
||||
* A reference to an object can be get by calling the following function. T must be the specific Interface you want to call.
|
||||
A nullptr check of the returning Pointer must be done. This function is based on Run-time type information.
|
||||
|
||||
```cpp
|
||||
template <typename T> T* ObjectManagerIF::get( object_id_t id )
|
||||
```
|
||||
* A typical way to create all objects on startup is a handing a static produce function to the
|
||||
ObjectManager on creation. By calling objectManager->initialize() the produce function will be
|
||||
called and all SystemObjects will be initialized afterwards.
|
||||
|
||||
### Event Manager
|
||||
|
||||
* Component which allows routing of events
|
||||
* Other objects can subscribe to specific events, ranges of events or all events of an object.
|
||||
* Subscriptions can be done during runtime but should be done during initialization
|
||||
* Amounts of allowed subscriptions can be configured in `FSFWConfig.h`
|
||||
|
||||
### Health Table
|
||||
|
||||
* A component which holds every health state
|
||||
* Provides a thread safe way to access all health states without the need of message exchanges
|
||||
|
||||
### Stores
|
||||
|
||||
* The message based communication can only exchange a few bytes of information inside the message
|
||||
itself. Therefore, additional information can be exchanged with Stores. With this, only the
|
||||
store address must be exchanged in the message.
|
||||
* Internally, the FSFW uses an IPC Store to exchange data between processes. For incoming TCs a TC
|
||||
Store is used. For outgoing TM a TM store is used.
|
||||
* All of them should use the Thread Safe Class storagemanager/PoolManager
|
||||
|
||||
### Tasks
|
||||
|
||||
There are two different types of tasks:
|
||||
* The PeriodicTask just executes objects that are of type ExecutableObjectIF in the order of the
|
||||
insertion to the Tasks.
|
||||
* FixedTimeslotTask executes a list of calls in the order of the given list. This is intended for
|
||||
DeviceHandlers, where polling should be in a defined order. An example can be found in
|
||||
`defaultcfg/fsfwconfig/pollingSequence` folder
|
||||
|
@ -1 +0,0 @@
|
||||
## Device Handlers
|
@ -1,135 +0,0 @@
|
||||
High-level overview
|
||||
======
|
||||
|
||||
# Structure
|
||||
|
||||
The general structure is driven by the usage of interfaces provided by objects.
|
||||
The FSFW uses C++11 as baseline. The intention behind this is that this C++ Standard should be
|
||||
widely available, even with older compilers.
|
||||
The FSFW uses dynamic allocation during the initialization but provides static containers during runtime.
|
||||
This simplifies the instantiation of objects and allows the usage of some standard containers.
|
||||
Dynamic Allocation after initialization is discouraged and different solutions are provided in the
|
||||
FSFW to achieve that. The fsfw uses run-time type information but exceptions are not allowed.
|
||||
|
||||
# Failure Handling
|
||||
|
||||
Functions should return a defined `ReturnValue_t` to signal to the caller that something has
|
||||
gone wrong. Returnvalues must be unique. For this the function `returnvalue::makeCode`
|
||||
or the macro `MAKE_RETURN` can be used. The `CLASS_ID` is a unique id for that type of object.
|
||||
See `returnvalues/FwClassIds` folder. The user can add custom `CLASS_ID`s via the
|
||||
`fsfwconfig` folder.
|
||||
|
||||
# OSAL
|
||||
|
||||
The FSFW provides operation system abstraction layers for Linux, FreeRTOS and RTEMS.
|
||||
The OSAL provides periodic tasks, message queues, clocks and semaphores as well as mutexes.
|
||||
The [OSAL README](doc/README-osal.md#top) provides more detailed information on provided components
|
||||
and how to use them.
|
||||
|
||||
# Core Components
|
||||
|
||||
The FSFW has following core components. More detailed informations can be found in the
|
||||
[core component section](doc/README-core.md#top):
|
||||
|
||||
1. Tasks: Abstraction for different (periodic) task types like periodic tasks or tasks
|
||||
with fixed timeslots
|
||||
2. ObjectManager: This module stores all `SystemObjects` by mapping a provided unique object ID
|
||||
to the object handles.
|
||||
3. Static Stores: Different stores are provided to store data of variable size (like telecommands
|
||||
or small telemetry) in a pool structure without using dynamic memory allocation.
|
||||
These pools are allocated up front.
|
||||
3. Clock: This module provided common time related functions
|
||||
4. EventManager: This module allows routing of events generated by `SystemObjects`
|
||||
5. HealthTable: A component which stores the health states of objects
|
||||
|
||||
# Static IDs in the framework
|
||||
|
||||
Some parts of the framework use a static routing address for communication.
|
||||
An example setup of ids can be found in the example config in `defaultcft/fsfwconfig/objects`
|
||||
inside the function `Factory::setStaticFrameworkObjectIds()`.
|
||||
|
||||
# Events
|
||||
|
||||
Events are tied to objects. EventIds can be generated by calling the Macro MAKE_EVENT.
|
||||
This works analog to the returnvalues. Every object that needs own EventIds has to get a
|
||||
unique SUBSYSTEM_ID. Every SystemObject can call triggerEvent from the parent class.
|
||||
Therefore, event messages contain the specific EventId and the objectId of the object that
|
||||
has triggered.
|
||||
|
||||
# Internal Communication
|
||||
|
||||
Components communicate mostly via Messages through Queues.
|
||||
Those queues are created by calling the singleton `QueueFactory::instance()->create()` which
|
||||
will create `MessageQueue` instances for the used OSAL.
|
||||
|
||||
# External Communication
|
||||
|
||||
The external communication with the mission control system is mostly up to the user implementation.
|
||||
The FSFW provides PUS Services which can be used to but don't need to be used.
|
||||
The services can be seen as a conversion from a TC to a message based communication and back.
|
||||
|
||||
## TMTC Communication
|
||||
|
||||
The FSFW provides some components to facilitate TMTC handling via the PUS commands.
|
||||
For example, a UDP or TCP PUS server socket can be opened on a specific port using the
|
||||
files located in `osal/common`. The FSFW example uses this functionality to allow sending telecommands
|
||||
and receiving telemetry using the [TMTC commander application](https://github.com/spacefisch/tmtccmd).
|
||||
Simple commands like the PUS Service 17 ping service can be tested by simply running the
|
||||
`tmtc_client_cli.py` or `tmtc_client_gui.py` utility in
|
||||
the [example tmtc folder](https://egit.irs.uni-stuttgart.de/fsfw/fsfw_example_public/src/branch/master/tmtc)
|
||||
while the `fsfw_example` application is running.
|
||||
|
||||
More generally, any class responsible for handling incoming telecommands and sending telemetry
|
||||
can implement the generic `TmTcBridge` class located in `tmtcservices`. Many applications
|
||||
also use a dedicated polling task for reading telecommands which passes telecommands
|
||||
to the `TmTcBridge` implementation.
|
||||
|
||||
## CCSDS Frames, CCSDS Space Packets and PUS
|
||||
|
||||
If the communication is based on CCSDS Frames and Space Packets, several classes can be used to
|
||||
distributed the packets to the corresponding services. Those can be found in `tcdistribution`.
|
||||
If Space Packets are used, a timestamper has to be provided by the user.
|
||||
An example can be found in the `timemanager` folder, which uses `CCSDSTime::CDS_short`.
|
||||
|
||||
# Device Handlers
|
||||
|
||||
DeviceHandlers are another important component of the FSFW.
|
||||
The idea is, to have a software counterpart of every physical device to provide a simple mode,
|
||||
health and commanding interface. By separating the underlying Communication Interface with
|
||||
`DeviceCommunicationIF`, a device handler (DH) can be tested on different hardware.
|
||||
The DH has mechanisms to monitor the communication with the physical device which allow
|
||||
for FDIR reaction. Device Handlers can be created by implementing `DeviceHandlerBase`.
|
||||
A standard FDIR component for the DH will be created automatically but can
|
||||
be overwritten by the user. More information on DeviceHandlers can be found in the
|
||||
related [documentation section](doc/README-devicehandlers.md#top).
|
||||
|
||||
# Modes and Health
|
||||
|
||||
The two interfaces `HasModesIF` and `HasHealthIF` provide access for commanding and monitoring
|
||||
of components. On-board Mode Management is implement in hierarchy system.
|
||||
DeviceHandlers and Controllers are the lowest part of the hierarchy.
|
||||
The next layer are Assemblies. Those assemblies act as a component which handle
|
||||
redundancies of handlers. Assemblies share a common core with the next level which
|
||||
are the Subsystems.
|
||||
|
||||
Those Assemblies are intended to act as auto-generated components from a database which describes
|
||||
the subsystem modes. The definitions contain transition and target tables which contain the DH,
|
||||
Assembly and Controller Modes to be commanded.
|
||||
Transition tables contain as many steps as needed to reach the mode from any other mode, e.g. a
|
||||
switch into any higher AOCS mode might first turn on the sensors, than the actuators and the
|
||||
controller as last component.
|
||||
The target table is used to describe the state that is checked continuously by the subsystem.
|
||||
All of this allows System Modes to be generated as Subsystem object as well from the same database.
|
||||
This System contains list of subsystem modes in the transition and target tables.
|
||||
Therefore, it allows a modular system to create system modes and easy commanding of those, because
|
||||
only the highest components must be commanded.
|
||||
|
||||
The health state represents if the component is able to perform its tasks.
|
||||
This can be used to signal the system to avoid using this component instead of a redundant one.
|
||||
The on-board FDIR uses the health state for isolation and recovery.
|
||||
|
||||
# Unit Tests
|
||||
|
||||
Unit Tests are provided in the unittest folder. Those use the catch2 framework but do not include
|
||||
catch2 itself. More information on how to run these tests can be found in the separate
|
||||
[`fsfw_tests` reposoitory](https://egit.irs.uni-stuttgart.de/fsfw/fsfw_tests)
|
@ -1,174 +0,0 @@
|
||||
## Local Data Pools Developer Information
|
||||
|
||||
The following text is targeted towards mission software developers which would like
|
||||
to use the local data pools provided by the FSFW to store data like sensor values so they can be
|
||||
used by other software objects like controllers as well. If a custom class should have a local
|
||||
pool which can be used by other software objects as well, following steps have to be performed:
|
||||
|
||||
1. Create a `LocalDataPoolManager` member object in the custom class
|
||||
2. Implement the `HasLocalDataPoolIF` with specifies the interface between the local pool manager
|
||||
and the class owning the local pool.
|
||||
|
||||
The local data pool manager is also able to process housekeeping service requests in form
|
||||
of messages, generate periodic housekeeping packet, generate notification and snapshots of changed
|
||||
variables and datasets and process notifications and snapshots coming from other objects.
|
||||
The two former tasks are related to the external interface using telemetry and telecommands (TMTC)
|
||||
while the later two are related to data consumers like controllers only acting on data change
|
||||
detected by the data creator instead of checking the data manually each cycle. Two important
|
||||
framework classes `DeviceHandlerBase` and `ExtendedControllerBase` already perform the two steps
|
||||
shown above so the steps required are altered slightly.
|
||||
|
||||
### Storing and Accessing pool data
|
||||
|
||||
The pool manager is responsible for thread-safe access of the pool data, but the actual
|
||||
access to the pool data from the point of view of a mission software developer happens via proxy
|
||||
classes like pool variable classes. These classes store a copy
|
||||
of the pool variable with the matching datatype and copy the actual data from the local pool
|
||||
on a `read` call. Changed variables can then be written to the local pool with a `commit` call.
|
||||
The `read` and `commit` calls are thread-safe and can be called concurrently from data creators
|
||||
and data consumers. Generally, a user will create a dataset class which in turn groups all
|
||||
cohesive pool variables. These sets simply iterator over the list of variables and call the
|
||||
`read` and `commit` functions of each variable. The following diagram shows the
|
||||
high-level architecture of the local data pools.
|
||||
|
||||
.. image:: ../misc/logo/FSFW_Logo_V3_bw.png
|
||||
:alt: FSFW Logo
|
||||
|
||||
|
||||
An example is shown for using the local data pools with a Gyroscope.
|
||||
For example, the following code shows an implementation to access data from a Gyroscope taken
|
||||
from the SOURCE CubeSat project:
|
||||
|
||||
```cpp
|
||||
class GyroPrimaryDataset: public StaticLocalDataSet<3 * sizeof(float)> {
|
||||
public:
|
||||
/**
|
||||
* Constructor for data users
|
||||
* @param gyroId
|
||||
*/
|
||||
GyroPrimaryDataset(object_id_t gyroId):
|
||||
StaticLocalDataSet(sid_t(gyroId, gyrodefs::GYRO_DATA_SET_ID)) {
|
||||
setAllVariablesReadOnly();
|
||||
}
|
||||
|
||||
lp_var_t<float> angVelocityX = lp_var_t<float>(sid.objectId,
|
||||
gyrodefs::ANGULAR_VELOCITY_X, this);
|
||||
lp_var_t<float> angVelocityY = lp_var_t<float>(sid.objectId,
|
||||
gyrodefs::ANGULAR_VELOCITY_Y, this);
|
||||
lp_var_t<float> angVelocityZ = lp_var_t<float>(sid.objectId,
|
||||
gyrodefs::ANGULAR_VELOCITY_Z, this);
|
||||
private:
|
||||
|
||||
friend class GyroHandler;
|
||||
/**
|
||||
* Constructor for data creator
|
||||
* @param hkOwner
|
||||
*/
|
||||
GyroPrimaryDataset(HasLocalDataPoolIF* hkOwner):
|
||||
StaticLocalDataSet(hkOwner, gyrodefs::GYRO_DATA_SET_ID) {}
|
||||
};
|
||||
```
|
||||
|
||||
There is a public constructor for users which sets all variables to read-only and there is a
|
||||
constructor for the GyroHandler data creator by marking it private and declaring the `GyroHandler`
|
||||
as a friend class. Both the atittude controller and the `GyroHandler` can now
|
||||
use the same class definition to access the pool variables with `read` and `commit` semantics
|
||||
in a thread-safe way. Generally, each class requiring access will have the set class as a member
|
||||
class. The data creator will also be generally a `DeviceHandlerBase` subclass and some additional
|
||||
steps are necessary to expose the set for housekeeping purposes.
|
||||
|
||||
### Using the local data pools in a `DeviceHandlerBase` subclass
|
||||
|
||||
It is very common to store data generated by devices like a sensor into a pool which can
|
||||
then be used by other objects. Therefore, the `DeviceHandlerBase` already has a
|
||||
local pool. Using the aforementioned example, our `GyroHandler` will now have the set class
|
||||
as a member:
|
||||
|
||||
```cpp
|
||||
class GyroHandler: ... {
|
||||
|
||||
public:
|
||||
...
|
||||
private:
|
||||
...
|
||||
GyroPrimaryDataset gyroData;
|
||||
...
|
||||
};
|
||||
```
|
||||
|
||||
The constructor used for the creators expects the owner class as a parameter, so we initialize
|
||||
the object in the `GyroHandler` constructor like this:
|
||||
|
||||
```cpp
|
||||
GyroHandler::GyroHandler(object_id_t objectId, object_id_t comIF,
|
||||
CookieIF *comCookie, uint8_t switchId):
|
||||
DeviceHandlerBase(objectId, comIF, comCookie), switchId(switchId),
|
||||
gyroData(this) {}
|
||||
```
|
||||
|
||||
We need to assign the set to a reply ID used in the `DeviceHandlerBase`.
|
||||
The combination of the `GyroHandler` object ID and the reply ID will be the 64-bit structure ID
|
||||
`sid_t` and is used to globally identify the set, for example when requesting housekeeping data or
|
||||
generating update messages. We need to assign our custom set class in some way so that the local
|
||||
pool manager can access the custom data sets as well.
|
||||
By default, the `getDataSetHandle` will take care of this tasks. The default implementation for a
|
||||
`DeviceHandlerBase` subclass will use the internal command map to retrieve
|
||||
a handle to a dataset from a given reply ID. Therefore,
|
||||
we assign the set in the `fillCommandAndReplyMap` function:
|
||||
|
||||
```cpp
|
||||
void GyroHandler::fillCommandAndReplyMap() {
|
||||
...
|
||||
this->insertInCommandAndReplyMap(gyrodefs::GYRO_DATA, 3, &gyroData);
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Now, we need to create the actual pool entries as well, using the `initializeLocalDataPool`
|
||||
function. Here, we also immediately subscribe for periodic housekeeping packets
|
||||
with an interval of 4 seconds. They are still disabled in this example and can be enabled
|
||||
with a housekeeping service command.
|
||||
|
||||
```cpp
|
||||
ReturnValue_t GyroHandler::initializeLocalDataPool(localpool::DataPool &localDataPoolMap,
|
||||
LocalDataPoolManager &poolManager) {
|
||||
localDataPoolMap.emplace(gyrodefs::ANGULAR_VELOCITY_X,
|
||||
new PoolEntry<float>({0.0}));
|
||||
localDataPoolMap.emplace(gyrodefs::ANGULAR_VELOCITY_Y,
|
||||
new PoolEntry<float>({0.0}));
|
||||
localDataPoolMap.emplace(gyrodefs::ANGULAR_VELOCITY_Z,
|
||||
new PoolEntry<float>({0.0}));
|
||||
localDataPoolMap.emplace(gyrodefs::GENERAL_CONFIG_REG42,
|
||||
new PoolEntry<uint8_t>({0}));
|
||||
localDataPoolMap.emplace(gyrodefs::RANGE_CONFIG_REG43,
|
||||
new PoolEntry<uint8_t>({0}));
|
||||
|
||||
poolManager.subscribeForPeriodicPacket(gyroData.getSid(), false, 4.0, false);
|
||||
return returnvalue::OK;
|
||||
}
|
||||
```
|
||||
|
||||
Now, if we receive some sensor data and converted them into the right format,
|
||||
we can write it into the pool like this, using a guard class to ensure the set is commited back
|
||||
in any case:
|
||||
|
||||
```cpp
|
||||
PoolReadGuard readHelper(&gyroData);
|
||||
if(readHelper.getReadResult() == returnvalue::OK) {
|
||||
if(not gyroData.isValid()) {
|
||||
gyroData.setValidity(true, true);
|
||||
}
|
||||
|
||||
gyroData.angVelocityX = angularVelocityX;
|
||||
gyroData.angVelocityY = angularVelocityY;
|
||||
gyroData.angVelocityZ = angularVelocityZ;
|
||||
}
|
||||
```
|
||||
|
||||
The guard class will commit the changed data on destruction automatically.
|
||||
|
||||
### Using the local data pools in a `ExtendedControllerBase` subclass
|
||||
|
||||
Coming soon
|
||||
|
||||
|
@ -1,32 +0,0 @@
|
||||
# Operating System Abstraction Layer (OSAL)
|
||||
|
||||
Some specific information on the provided OSALs are provided.
|
||||
|
||||
## Linux OSAL
|
||||
|
||||
This OSAL can be used to compile for Linux host systems like Ubuntu 20.04 or for
|
||||
embedded Linux targets like the Raspberry Pi. This OSAL generally requires threading support
|
||||
and real-time functionalities. For most UNIX systems, this is done by adding `-lrt` and `-lpthread` to the linked libraries in the compilation process. The CMake build support provided will do this automatically for the `fsfw` target. It should be noted that most UNIX systems need to be configured specifically to allow the real-time functionalities required by the FSFW.
|
||||
|
||||
More information on how to set up a Linux system accordingly can be found in the
|
||||
[Linux README of the FSFW example application](https://egit.irs.uni-stuttgart.de/fsfw/fsfw_example/src/branch/master/doc/README-linux.md#top)
|
||||
|
||||
## Hosted OSAL
|
||||
|
||||
This is the newest OSAL. Support for Semaphores has not been implemented yet and will propably be implemented as soon as C++20 with Semaphore support has matured. This OSAL can be used to run the FSFW on any host system, but currently has only been tested on Windows 10 and Ubuntu 20.04. Unlike the other OSALs, it uses dynamic memory allocation (e.g. for the message queue implementation). Cross-platform serial port (USB) support might be added soon.
|
||||
|
||||
## FreeRTOS OSAL
|
||||
|
||||
FreeRTOS is not included and the developer needs to take care of compiling the FreeRTOS sources and adding the `FreeRTOSConfig.h` file location to the include path. This OSAL has only been tested extensively with the pre-emptive scheduler configuration so far but it should in principle also be possible to use a cooperative scheduler. It is recommended to use the `heap_4` allocation scheme. When using newlib (nano), it is also recommended to add `#define configUSE_NEWLIB_REENTRANT` to the FreeRTOS configuration file to ensure thread-safety.
|
||||
|
||||
When using this OSAL, developers also need to provide an implementation for the `vRequestContextSwitchFromISR` function. This has been done because the call to request a context switch from an ISR is generally located in the `portmacro.h` header and is different depending on the target architecture or device.
|
||||
|
||||
## RTEMS OSAL
|
||||
|
||||
The RTEMS OSAL was the first implemented OSAL which is also used on the active satellite Flying Laptop.
|
||||
|
||||
## TCP/IP socket abstraction
|
||||
|
||||
The Linux and Host OSAL provide abstraction layers for the socket API. Currently, only UDP sockets have been imlemented. This is very useful to test TMTC handling either on the host computer directly (targeting localhost with a TMTC application) or on embedded Linux devices, sending TMTC packets via Ethernet.
|
||||
|
||||
|
@ -1 +0,0 @@
|
||||
## PUS Services
|
@ -50,6 +50,14 @@ exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
|
||||
#
|
||||
html_theme = "alabaster"
|
||||
|
||||
html_theme_options = {
|
||||
"extra_nav_links": {
|
||||
"Impressum": "https://www.uni-stuttgart.de/impressum",
|
||||
"Datenschutz": "https://info.irs.uni-stuttgart.de/datenschutz/datenschutzWebmit.html",
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
|
@ -6,15 +6,14 @@ High-level overview
|
||||
Structure
|
||||
----------
|
||||
|
||||
The general structure is driven by the usage of interfaces provided by objects.
|
||||
The FSFW uses C++17 as baseline.
|
||||
It also uses dynamic allocation during the initialization but provides
|
||||
static containers during runtime.
|
||||
This simplifies the instantiation of objects and allows the usage of some
|
||||
standard containers.
|
||||
Dynamic Allocation after initialization is discouraged and different solutions
|
||||
are provided in the FSFW to achieve that. The fsfw uses run-time type
|
||||
information but will not throw exceptions.
|
||||
The general structure is driven by the usage of interfaces provided by objects.
|
||||
The FSFW uses C++17 as baseline. Most modern compilers like GCC should have support for this
|
||||
standard, even for micocontrollers.
|
||||
|
||||
The FSFW might use dynamic allocation during program initialization but not during runtime.
|
||||
It offers pool objects, static containers and it also exposes the
|
||||
`Embedded Template Library <https://www.etlcpp.com/>`_ to allow writing code which does not perform
|
||||
allocation during runtime. The fsfw uses run-time type information but will not throw exceptions.
|
||||
|
||||
Failure Handling
|
||||
-----------------
|
||||
|
110
scripts/check_release.py
Executable file
110
scripts/check_release.py
Executable file
@ -0,0 +1,110 @@
|
||||
#! /bin/python
|
||||
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import urllib.request
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(
|
||||
description="List undocumented PRs"
|
||||
)
|
||||
parser.add_argument("-v", "--version", type=str, required=True)
|
||||
args = parser.parse_args()
|
||||
|
||||
match = re.search("([0-9]+\.[0-9]+\.[0-9]+)", args.version)
|
||||
|
||||
if not match:
|
||||
print("invalid version")
|
||||
exit(1)
|
||||
|
||||
version = "v" + match.group(1)
|
||||
|
||||
print("looking for milestone for " + version + " ...")
|
||||
|
||||
|
||||
with urllib.request.urlopen("https://egit.irs.uni-stuttgart.de/api/v1/repos/fsfw/fsfw/milestones?name=" + version) as milestone_json:
|
||||
milestones = json.load(milestone_json)
|
||||
if (len(milestones) == 0):
|
||||
print("did not find any milestone")
|
||||
exit(1)
|
||||
if (len(milestones) > 1):
|
||||
print("found multiple milestons")
|
||||
milestone_title = milestones[0]['title']
|
||||
milestone = str(milestones[0]['id'])
|
||||
print("Using Milestone \""+ milestone_title + "\" with id " + milestone)
|
||||
|
||||
milestone_prs = []
|
||||
|
||||
page = 1
|
||||
last_count = 1;
|
||||
while last_count != 0:
|
||||
with urllib.request.urlopen("https://egit.irs.uni-stuttgart.de/api/v1/repos/fsfw/fsfw/pulls?state=closed&milestone=" + str(milestone) + "&limit=100&page=" + str(page)) as pull_requests_json:
|
||||
pull_requests = json.load(pull_requests_json)
|
||||
for pr in pull_requests:
|
||||
milestone_prs.append({'number': str(pr['number']), 'title' : pr['title']})
|
||||
page += 1
|
||||
last_count = len(pull_requests)
|
||||
|
||||
print("Found " + str(len(milestone_prs)) + " closed PRs in Milestone")
|
||||
|
||||
print("looking for CHANGELOG.md ...")
|
||||
|
||||
path = Path(".")
|
||||
|
||||
files = list(path.glob("CHANGELOG.md"))
|
||||
|
||||
if (len(files) != 1):
|
||||
files = list(path.glob("../CHANGELOG.md"))
|
||||
|
||||
if (len(files) != 1):
|
||||
print("did not find CHANGELOG.md. Run script in either root directory or scripts subfolder.")
|
||||
exit(1)
|
||||
|
||||
print("Scanning CHANGELOG.md ...")
|
||||
|
||||
changelog_prs = []
|
||||
|
||||
with open(files[0]) as changelog:
|
||||
line = changelog.readline()
|
||||
while (line):
|
||||
#print("line: " + line)
|
||||
match = re.search("\#.+(v[0-9]+\.[0-9]+\.[0-9]+)", line)
|
||||
if (match):
|
||||
if match.group(1) == version:
|
||||
#print("found version")
|
||||
line = changelog.readline()
|
||||
continue
|
||||
else:
|
||||
#print("done with " + match.group(1))
|
||||
break
|
||||
|
||||
match = re.search("PR: https://egit\.irs\.uni-stuttgart\.de/fsfw/fsfw/pulls/([0-9]+)", line)
|
||||
if match:
|
||||
changelog_prs.append(match.group(1))
|
||||
|
||||
line = changelog.readline()
|
||||
|
||||
print("Found " + str(len(changelog_prs)) + " PRs in CHANGELOG.md")
|
||||
|
||||
print("")
|
||||
|
||||
copy_array = changelog_prs.copy()
|
||||
print("PRs in CHANGELOG.md that are not in Milestone:")
|
||||
for pr in milestone_prs:
|
||||
if pr['number'] in copy_array:
|
||||
copy_array.remove(pr['number'])
|
||||
for pr in copy_array:
|
||||
print("https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/" + pr)
|
||||
|
||||
print("")
|
||||
|
||||
print("PRs in milestone that are not in CHANGELOG.md:")
|
||||
|
||||
for pr in milestone_prs:
|
||||
if pr['number'] not in changelog_prs:
|
||||
print("- " + pr['title'] + "\n PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/" + pr['number'])
|
||||
|
||||
main()
|
@ -207,7 +207,7 @@ def check_for_cmake_build_dir(build_dir_list: list) -> list:
|
||||
def perform_lcov_operation(directory: str, chdir: bool):
|
||||
if chdir:
|
||||
os.chdir(directory)
|
||||
cmd_runner("cmake --build . -- fsfw-tests_coverage -j")
|
||||
cmd_runner("cmake --build . -j -- fsfw-tests_coverage")
|
||||
|
||||
|
||||
def determine_build_dir(build_dir_list: List[str]):
|
||||
|
@ -32,6 +32,7 @@ add_subdirectory(timemanager)
|
||||
add_subdirectory(tmtcpacket)
|
||||
add_subdirectory(tmtcservices)
|
||||
add_subdirectory(filesystem)
|
||||
add_subdirectory(util)
|
||||
|
||||
# Optional
|
||||
|
||||
|
@ -59,17 +59,24 @@ void ActionHelper::setQueueToUse(MessageQueueIF* queue) { queueToUse = queue; }
|
||||
|
||||
void ActionHelper::prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId,
|
||||
store_address_t dataAddress) {
|
||||
bool hasAdditionalData = false;
|
||||
const uint8_t* dataPtr = nullptr;
|
||||
size_t size = 0;
|
||||
ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size);
|
||||
if (result != returnvalue::OK) {
|
||||
CommandMessage reply;
|
||||
ActionMessage::setStepReply(&reply, actionId, 0, result);
|
||||
queueToUse->sendMessage(commandedBy, &reply);
|
||||
return;
|
||||
ReturnValue_t result;
|
||||
if (dataAddress != store_address_t::invalid()) {
|
||||
hasAdditionalData = true;
|
||||
ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size);
|
||||
if (result != returnvalue::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 (hasAdditionalData) {
|
||||
ipcStore->deleteData(dataAddress);
|
||||
}
|
||||
if (result == HasActionsIF::EXECUTION_FINISHED) {
|
||||
CommandMessage reply;
|
||||
ActionMessage::setCompletionReply(&reply, actionId, true, result);
|
||||
|
@ -2,7 +2,6 @@
|
||||
#define FSFW_CFDP_H
|
||||
|
||||
#include "cfdp/definitions.h"
|
||||
#include "cfdp/handler/CfdpHandler.h"
|
||||
#include "cfdp/handler/DestHandler.h"
|
||||
#include "cfdp/handler/FaultHandlerBase.h"
|
||||
#include "cfdp/helpers.h"
|
||||
|
@ -4,8 +4,9 @@ CfdpMessage::CfdpMessage() = default;
|
||||
|
||||
CfdpMessage::~CfdpMessage() = default;
|
||||
|
||||
void CfdpMessage::setCommand(CommandMessage *message, store_address_t cfdpPacket) {
|
||||
message->setParameter(cfdpPacket.raw);
|
||||
void CfdpMessage::setPutRequest(CommandMessage *message, store_address_t putRequest) {
|
||||
message->setCommand(PUT_REQUEST);
|
||||
message->setParameter(putRequest.raw);
|
||||
}
|
||||
|
||||
store_address_t CfdpMessage::getStoreId(const CommandMessage *message) {
|
||||
|
@ -11,9 +11,11 @@ class CfdpMessage {
|
||||
|
||||
public:
|
||||
static const uint8_t MESSAGE_ID = messagetypes::CFDP;
|
||||
static const Command_t PUT_REQUEST = MAKE_COMMAND_ID(1);
|
||||
static const Command_t CANCEL_REQUEST = MAKE_COMMAND_ID(1);
|
||||
|
||||
virtual ~CfdpMessage();
|
||||
static void setCommand(CommandMessage* message, store_address_t cfdpPacket);
|
||||
static void setPutRequest(CommandMessage* message, store_address_t putRequest);
|
||||
|
||||
static store_address_t getStoreId(const CommandMessage* message);
|
||||
|
||||
|
@ -8,11 +8,14 @@
|
||||
|
||||
namespace cfdp {
|
||||
|
||||
struct FileSize : public SerializeIF {
|
||||
/**
|
||||
* Helper type for the CFDP File Size Sensitive (FSS) fields.
|
||||
*/
|
||||
struct Fss : public SerializeIF {
|
||||
public:
|
||||
FileSize() = default;
|
||||
Fss() = default;
|
||||
|
||||
explicit FileSize(uint64_t fileSize, bool isLarge = false) { setFileSize(fileSize, isLarge); };
|
||||
explicit Fss(uint64_t fileSize, bool isLarge = false) { setFileSize(fileSize, isLarge); };
|
||||
|
||||
[[nodiscard]] uint64_t value() const { return fileSize; }
|
||||
|
@ -3,8 +3,8 @@
|
||||
#include "fsfw/serialize/SerializeAdapter.h"
|
||||
#include "fsfw/serviceinterface.h"
|
||||
|
||||
cfdp::VarLenField::VarLenField(cfdp::WidthInBytes width, size_t value) : VarLenField() {
|
||||
ReturnValue_t result = this->setValue(width, value);
|
||||
cfdp::VarLenField::VarLenField(cfdp::WidthInBytes width, uint64_t value) : VarLenField() {
|
||||
ReturnValue_t result = this->setValueAndWidth(width, value);
|
||||
if (result != returnvalue::OK) {
|
||||
#if FSFW_DISABLE_PRINTOUT == 0
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
@ -20,8 +20,8 @@ cfdp::VarLenField::VarLenField() : width(cfdp::WidthInBytes::ONE_BYTE) { value.o
|
||||
|
||||
cfdp::WidthInBytes cfdp::VarLenField::getWidth() const { return width; }
|
||||
|
||||
ReturnValue_t cfdp::VarLenField::setValue(cfdp::WidthInBytes widthInBytes, size_t value_) {
|
||||
switch (widthInBytes) {
|
||||
ReturnValue_t cfdp::VarLenField::setValueAndWidth(cfdp::WidthInBytes width_, uint64_t value_) {
|
||||
switch (width_) {
|
||||
case (cfdp::WidthInBytes::ONE_BYTE): {
|
||||
if (value_ > UINT8_MAX) {
|
||||
return returnvalue::FAILED;
|
||||
@ -43,15 +43,18 @@ ReturnValue_t cfdp::VarLenField::setValue(cfdp::WidthInBytes widthInBytes, size_
|
||||
this->value.fourBytes = value_;
|
||||
break;
|
||||
}
|
||||
case (cfdp::WidthInBytes::EIGHT_BYTES): {
|
||||
this->value.eightBytes = value_;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
this->width = widthInBytes;
|
||||
this->width = width_;
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
size_t cfdp::VarLenField::getValue() const {
|
||||
uint64_t cfdp::VarLenField::getValue() const {
|
||||
switch (width) {
|
||||
case (cfdp::WidthInBytes::ONE_BYTE): {
|
||||
return value.oneByte;
|
||||
@ -62,6 +65,9 @@ size_t cfdp::VarLenField::getValue() const {
|
||||
case (cfdp::WidthInBytes::FOUR_BYTES): {
|
||||
return value.fourBytes;
|
||||
}
|
||||
case (cfdp::WidthInBytes::EIGHT_BYTES): {
|
||||
return value.eightBytes;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -84,6 +90,10 @@ ReturnValue_t cfdp::VarLenField::serialize(uint8_t **buffer, size_t *size, size_
|
||||
case (cfdp::WidthInBytes::FOUR_BYTES): {
|
||||
return SerializeAdapter::serialize(&value.fourBytes, buffer, size, maxSize, streamEndianness);
|
||||
}
|
||||
case (cfdp::WidthInBytes::EIGHT_BYTES): {
|
||||
return SerializeAdapter::serialize(&value.eightBytes, buffer, size, maxSize,
|
||||
streamEndianness);
|
||||
}
|
||||
default: {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
@ -98,11 +108,16 @@ ReturnValue_t cfdp::VarLenField::deSerialize(cfdp::WidthInBytes width_, const ui
|
||||
return deSerialize(buffer, size, streamEndianness);
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::VarLenField::setValue(uint64_t value_) {
|
||||
return setValueAndWidth(getWidth(), value_);
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::VarLenField::deSerialize(const uint8_t **buffer, size_t *size,
|
||||
Endianness streamEndianness) {
|
||||
switch (width) {
|
||||
case (cfdp::WidthInBytes::ONE_BYTE): {
|
||||
value.oneByte = **buffer;
|
||||
*buffer += 1;
|
||||
*size += 1;
|
||||
return returnvalue::OK;
|
||||
}
|
||||
@ -112,6 +127,9 @@ ReturnValue_t cfdp::VarLenField::deSerialize(const uint8_t **buffer, size_t *siz
|
||||
case (cfdp::WidthInBytes::FOUR_BYTES): {
|
||||
return SerializeAdapter::deSerialize(&value.fourBytes, buffer, size, streamEndianness);
|
||||
}
|
||||
case (cfdp::WidthInBytes::EIGHT_BYTES): {
|
||||
return SerializeAdapter::deSerialize(&value.eightBytes, buffer, size, streamEndianness);
|
||||
}
|
||||
default: {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
@ -135,3 +153,5 @@ bool cfdp::VarLenField::operator==(const cfdp::VarLenField &other) const {
|
||||
bool cfdp::VarLenField::operator!=(const cfdp::VarLenField &other) const {
|
||||
return not(*this == other);
|
||||
}
|
||||
|
||||
void cfdp::VarLenField::setWidth(cfdp::WidthInBytes width_) { this->width = width_; }
|
||||
|
@ -25,13 +25,15 @@ class VarLenField : public SerializeIF {
|
||||
template <typename T>
|
||||
explicit VarLenField(UnsignedByteField<T> byteField);
|
||||
|
||||
VarLenField(cfdp::WidthInBytes width, size_t value);
|
||||
VarLenField(cfdp::WidthInBytes width, uint64_t value);
|
||||
|
||||
bool operator==(const VarLenField &other) const;
|
||||
bool operator!=(const VarLenField &other) const;
|
||||
bool operator<(const VarLenField &other) const;
|
||||
|
||||
ReturnValue_t setValue(cfdp::WidthInBytes, size_t value);
|
||||
ReturnValue_t setValueAndWidth(cfdp::WidthInBytes width, uint64_t value);
|
||||
void setWidth(cfdp::WidthInBytes width);
|
||||
ReturnValue_t setValue(uint64_t value);
|
||||
|
||||
ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize,
|
||||
Endianness streamEndianness) const override;
|
||||
@ -42,7 +44,7 @@ class VarLenField : public SerializeIF {
|
||||
Endianness streamEndianness);
|
||||
|
||||
[[nodiscard]] cfdp::WidthInBytes getWidth() const;
|
||||
[[nodiscard]] size_t getValue() const;
|
||||
[[nodiscard]] uint64_t getValue() const;
|
||||
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
friend std::ostream &operator<<(std::ostream &os, const VarLenField &id) {
|
||||
@ -64,7 +66,7 @@ template <typename T>
|
||||
cfdp::VarLenField::VarLenField(UnsignedByteField<T> byteField)
|
||||
: width(static_cast<cfdp::WidthInBytes>(sizeof(T))) {
|
||||
static_assert((sizeof(T) % 2) == 0);
|
||||
setValue(width, byteField.getValue());
|
||||
setValueAndWidth(width, byteField.getValue());
|
||||
}
|
||||
|
||||
struct EntityId : public VarLenField {
|
||||
@ -73,6 +75,32 @@ struct EntityId : public VarLenField {
|
||||
template <typename T>
|
||||
explicit EntityId(UnsignedByteField<T> byteField) : VarLenField(byteField) {}
|
||||
EntityId(cfdp::WidthInBytes width, size_t entityId) : VarLenField(width, entityId) {}
|
||||
|
||||
ReturnValue_t serializeAsLv(uint8_t **buffer, size_t *size, size_t maxSize) const {
|
||||
if (buffer == nullptr or size == nullptr) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
if (*size + 1 + getWidth() > maxSize) {
|
||||
return SerializeIF::BUFFER_TOO_SHORT;
|
||||
}
|
||||
**buffer = getWidth();
|
||||
*buffer += 1;
|
||||
*size += 1;
|
||||
return serialize(buffer, size, maxSize, SerializeIF::Endianness::NETWORK);
|
||||
}
|
||||
|
||||
ReturnValue_t deSerializeFromLv(const uint8_t **buffer, size_t *deserLen) {
|
||||
if (buffer == nullptr or deserLen == nullptr) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
if (*deserLen < 2) {
|
||||
return SerializeIF::STREAM_TOO_SHORT;
|
||||
}
|
||||
auto width = static_cast<WidthInBytes>(**buffer);
|
||||
*buffer += 1;
|
||||
*deserLen -= 1;
|
||||
return VarLenField::deSerialize(width, buffer, deserLen, SerializeIF::Endianness::NETWORK);
|
||||
}
|
||||
};
|
||||
|
||||
struct TransactionSeqNum : public VarLenField {
|
||||
|
@ -17,7 +17,7 @@ static constexpr char CFDP_VERSION_2_NAME[] = "CCSDS 727.0-B-5";
|
||||
static constexpr uint8_t CFDP_VERSION_2 = 0b001;
|
||||
static constexpr uint8_t VERSION_BITS = CFDP_VERSION_2 << 5;
|
||||
|
||||
static constexpr uint8_t CFDP_CLASS_ID = CLASS_ID::CFDP;
|
||||
static constexpr uint8_t CFDP_CLASS_ID = CLASS_ID::CFDP_BASE;
|
||||
|
||||
static constexpr ReturnValue_t INVALID_TLV_TYPE = returnvalue::makeCode(CFDP_CLASS_ID, 1);
|
||||
static constexpr ReturnValue_t INVALID_DIRECTIVE_FIELD = returnvalue::makeCode(CFDP_CLASS_ID, 2);
|
||||
@ -68,6 +68,7 @@ enum WidthInBytes : uint8_t {
|
||||
ONE_BYTE = 1,
|
||||
TWO_BYTES = 2,
|
||||
FOUR_BYTES = 4,
|
||||
EIGHT_BYTES = 8
|
||||
};
|
||||
|
||||
enum FileDirective : uint8_t {
|
||||
@ -142,6 +143,20 @@ enum RecordContinuationState {
|
||||
CONTAINS_START_AND_END = 0b11
|
||||
};
|
||||
|
||||
enum class ProxyOpMessageType : uint8_t {
|
||||
PUT_REQUEST = 0x00,
|
||||
MSG_TO_USR = 0x01,
|
||||
FS_REQUEST = 0x02,
|
||||
FAULT_HANDLER_OVERRIDE = 0x03,
|
||||
TRANSMISSION_MODE = 0x04,
|
||||
FLOW_LABEL = 0x05,
|
||||
SEG_CTRL = 0x06,
|
||||
PUT_RESPONSE = 0x07,
|
||||
FS_RESPONSE = 0x08,
|
||||
PUT_CANCEL = 0x09,
|
||||
CLOSURE = 0x0b
|
||||
};
|
||||
|
||||
} // namespace cfdp
|
||||
|
||||
#endif /* FSFW_SRC_FSFW_CFDP_PDU_DEFINITIONS_H_ */
|
||||
|
@ -1,3 +1,4 @@
|
||||
target_sources(
|
||||
${LIB_FSFW_NAME} PRIVATE SourceHandler.cpp DestHandler.cpp
|
||||
FaultHandlerBase.cpp UserBase.cpp CfdpHandler.cpp)
|
||||
${LIB_FSFW_NAME}
|
||||
PRIVATE SourceHandler.cpp DestHandler.cpp PutRequest.cpp
|
||||
ReservedMessageParser.cpp FaultHandlerBase.cpp UserBase.cpp)
|
||||
|
@ -1,134 +0,0 @@
|
||||
#include "CfdpHandler.h"
|
||||
|
||||
#include "fsfw/cfdp/pdu/AckPduReader.h"
|
||||
#include "fsfw/cfdp/pdu/PduHeaderReader.h"
|
||||
#include "fsfw/globalfunctions/arrayprinter.h"
|
||||
#include "fsfw/ipc/QueueFactory.h"
|
||||
#include "fsfw/tmtcservices/TmTcMessage.h"
|
||||
|
||||
using namespace returnvalue;
|
||||
using namespace cfdp;
|
||||
|
||||
CfdpHandler::CfdpHandler(const FsfwHandlerParams& fsfwParams, const CfdpHandlerCfg& cfdpCfg)
|
||||
: SystemObject(fsfwParams.objectId),
|
||||
msgQueue(fsfwParams.msgQueue),
|
||||
destHandler(
|
||||
DestHandlerParams(LocalEntityCfg(cfdpCfg.id, cfdpCfg.indicCfg, cfdpCfg.faultHandler),
|
||||
cfdpCfg.userHandler, cfdpCfg.remoteCfgProvider, cfdpCfg.packetInfoList,
|
||||
cfdpCfg.lostSegmentsList),
|
||||
FsfwParams(fsfwParams.packetDest, nullptr, this, fsfwParams.tcStore,
|
||||
fsfwParams.tmStore)) {
|
||||
destHandler.setMsgQueue(msgQueue);
|
||||
}
|
||||
|
||||
[[nodiscard]] const char* CfdpHandler::getName() const { return "CFDP Handler"; }
|
||||
|
||||
[[nodiscard]] uint32_t CfdpHandler::getIdentifier() const {
|
||||
return destHandler.getDestHandlerParams().cfg.localId.getValue();
|
||||
}
|
||||
|
||||
[[nodiscard]] MessageQueueId_t CfdpHandler::getRequestQueue() const { return msgQueue.getId(); }
|
||||
|
||||
ReturnValue_t CfdpHandler::initialize() {
|
||||
ReturnValue_t result = destHandler.initialize();
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
tcStore = destHandler.getTcStore();
|
||||
tmStore = destHandler.getTmStore();
|
||||
|
||||
return SystemObject::initialize();
|
||||
}
|
||||
|
||||
ReturnValue_t CfdpHandler::performOperation(uint8_t operationCode) {
|
||||
// TODO: Receive TC packets and route them to source and dest handler, depending on which is
|
||||
// correct or more appropriate
|
||||
ReturnValue_t status;
|
||||
ReturnValue_t result = OK;
|
||||
TmTcMessage tmtcMsg;
|
||||
for (status = msgQueue.receiveMessage(&tmtcMsg); status == returnvalue::OK;
|
||||
status = msgQueue.receiveMessage(&tmtcMsg)) {
|
||||
result = handleCfdpPacket(tmtcMsg);
|
||||
if (result != OK) {
|
||||
status = result;
|
||||
}
|
||||
}
|
||||
auto& fsmRes = destHandler.performStateMachine();
|
||||
// TODO: Error handling?
|
||||
while (fsmRes.callStatus == CallStatus::CALL_AGAIN) {
|
||||
destHandler.performStateMachine();
|
||||
// TODO: Error handling?
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
ReturnValue_t CfdpHandler::handleCfdpPacket(TmTcMessage& msg) {
|
||||
auto accessorPair = tcStore->getData(msg.getStorageId());
|
||||
if (accessorPair.first != OK) {
|
||||
return accessorPair.first;
|
||||
}
|
||||
PduHeaderReader reader(accessorPair.second.data(), accessorPair.second.size());
|
||||
ReturnValue_t result = reader.parseData();
|
||||
if (result != returnvalue::OK) {
|
||||
return INVALID_PDU_FORMAT;
|
||||
}
|
||||
// The CFDP distributor should have taken care of ensuring the destination ID is correct
|
||||
PduType type = reader.getPduType();
|
||||
// Only the destination handler can process these PDUs
|
||||
if (type == PduType::FILE_DATA) {
|
||||
// Disable auto-deletion of packet
|
||||
accessorPair.second.release();
|
||||
PacketInfo info(type, msg.getStorageId());
|
||||
result = destHandler.passPacket(info);
|
||||
} else {
|
||||
// Route depending on PDU type and directive type if applicable. It retrieves directive type
|
||||
// from the raw stream for better performance (with sanity and directive code check).
|
||||
// The routing is based on section 4.5 of the CFDP standard which specifies the PDU forwarding
|
||||
// procedure.
|
||||
|
||||
// PDU header only. Invalid supplied data. A directive packet should have a valid data field
|
||||
// with at least one byte being the directive code
|
||||
const uint8_t* pduDataField = reader.getPduDataField();
|
||||
if (pduDataField == nullptr) {
|
||||
return INVALID_PDU_FORMAT;
|
||||
}
|
||||
if (not FileDirectiveReader::checkFileDirective(pduDataField[0])) {
|
||||
return INVALID_DIRECTIVE_FIELD;
|
||||
}
|
||||
auto directive = static_cast<FileDirective>(pduDataField[0]);
|
||||
|
||||
auto passToDestHandler = [&]() {
|
||||
accessorPair.second.release();
|
||||
PacketInfo info(type, msg.getStorageId(), directive);
|
||||
result = destHandler.passPacket(info);
|
||||
};
|
||||
auto passToSourceHandler = [&]() {
|
||||
|
||||
};
|
||||
if (directive == FileDirective::METADATA or directive == FileDirective::EOF_DIRECTIVE or
|
||||
directive == FileDirective::PROMPT) {
|
||||
// Section b) of 4.5.3: These PDUs should always be targeted towards the file receiver a.k.a.
|
||||
// the destination handler
|
||||
passToDestHandler();
|
||||
} else if (directive == FileDirective::FINISH or directive == FileDirective::NAK or
|
||||
directive == FileDirective::KEEP_ALIVE) {
|
||||
// Section c) of 4.5.3: These PDUs should always be targeted towards the file sender a.k.a.
|
||||
// the source handler
|
||||
passToSourceHandler();
|
||||
} else if (directive == FileDirective::ACK) {
|
||||
// Section a): Recipient depends of the type of PDU that is being acknowledged. We can simply
|
||||
// extract the PDU type from the raw stream. If it is an EOF PDU, this packet is passed to
|
||||
// the source handler, for a Finished PDU, it is passed to the destination handler.
|
||||
FileDirective ackedDirective;
|
||||
if (not AckPduReader::checkAckedDirectiveField(pduDataField[1], ackedDirective)) {
|
||||
return INVALID_ACK_DIRECTIVE_FIELDS;
|
||||
}
|
||||
if (ackedDirective == FileDirective::EOF_DIRECTIVE) {
|
||||
passToSourceHandler();
|
||||
} else if (ackedDirective == FileDirective::FINISH) {
|
||||
passToDestHandler();
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
#ifndef FSFW_EXAMPLE_HOSTED_CFDPHANDLER_H
|
||||
#define FSFW_EXAMPLE_HOSTED_CFDPHANDLER_H
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "fsfw/cfdp/handler/DestHandler.h"
|
||||
#include "fsfw/objectmanager/SystemObject.h"
|
||||
#include "fsfw/tasks/ExecutableObjectIF.h"
|
||||
#include "fsfw/tmtcservices/AcceptsTelecommandsIF.h"
|
||||
#include "fsfw/tmtcservices/TmTcMessage.h"
|
||||
|
||||
struct FsfwHandlerParams {
|
||||
FsfwHandlerParams(object_id_t objectId, HasFileSystemIF& vfs, AcceptsTelemetryIF& packetDest,
|
||||
StorageManagerIF& tcStore, StorageManagerIF& tmStore, MessageQueueIF& msgQueue)
|
||||
: objectId(objectId),
|
||||
vfs(vfs),
|
||||
packetDest(packetDest),
|
||||
tcStore(tcStore),
|
||||
tmStore(tmStore),
|
||||
msgQueue(msgQueue) {}
|
||||
object_id_t objectId{};
|
||||
HasFileSystemIF& vfs;
|
||||
AcceptsTelemetryIF& packetDest;
|
||||
StorageManagerIF& tcStore;
|
||||
StorageManagerIF& tmStore;
|
||||
MessageQueueIF& msgQueue;
|
||||
};
|
||||
|
||||
struct CfdpHandlerCfg {
|
||||
CfdpHandlerCfg(cfdp::EntityId localId, cfdp::IndicationCfg indicationCfg,
|
||||
cfdp::UserBase& userHandler, cfdp::FaultHandlerBase& userFaultHandler,
|
||||
cfdp::PacketInfoListBase& packetInfo, cfdp::LostSegmentsListBase& lostSegmentsList,
|
||||
cfdp::RemoteConfigTableIF& remoteCfgProvider)
|
||||
: id(std::move(localId)),
|
||||
indicCfg(indicationCfg),
|
||||
packetInfoList(packetInfo),
|
||||
lostSegmentsList(lostSegmentsList),
|
||||
remoteCfgProvider(remoteCfgProvider),
|
||||
userHandler(userHandler),
|
||||
faultHandler(userFaultHandler) {}
|
||||
|
||||
cfdp::EntityId id;
|
||||
cfdp::IndicationCfg indicCfg;
|
||||
cfdp::PacketInfoListBase& packetInfoList;
|
||||
cfdp::LostSegmentsListBase& lostSegmentsList;
|
||||
cfdp::RemoteConfigTableIF& remoteCfgProvider;
|
||||
cfdp::UserBase& userHandler;
|
||||
cfdp::FaultHandlerBase& faultHandler;
|
||||
};
|
||||
|
||||
class CfdpHandler : public SystemObject, public ExecutableObjectIF, public AcceptsTelecommandsIF {
|
||||
public:
|
||||
explicit CfdpHandler(const FsfwHandlerParams& fsfwParams, const CfdpHandlerCfg& cfdpCfg);
|
||||
|
||||
[[nodiscard]] const char* getName() const override;
|
||||
[[nodiscard]] uint32_t getIdentifier() const override;
|
||||
[[nodiscard]] MessageQueueId_t getRequestQueue() const override;
|
||||
|
||||
ReturnValue_t initialize() override;
|
||||
ReturnValue_t performOperation(uint8_t operationCode) override;
|
||||
|
||||
private:
|
||||
MessageQueueIF& msgQueue;
|
||||
cfdp::DestHandler destHandler;
|
||||
StorageManagerIF* tcStore = nullptr;
|
||||
StorageManagerIF* tmStore = nullptr;
|
||||
|
||||
ReturnValue_t handleCfdpPacket(TmTcMessage& msg);
|
||||
};
|
||||
|
||||
#endif // FSFW_EXAMPLE_HOSTED_CFDPHANDLER_H
|
@ -16,25 +16,26 @@ using namespace returnvalue;
|
||||
|
||||
cfdp::DestHandler::DestHandler(DestHandlerParams params, FsfwParams fsfwParams)
|
||||
: tlvVec(params.maxTlvsInOnePdu),
|
||||
userTlvVec(params.maxTlvsInOnePdu),
|
||||
dp(std::move(params)),
|
||||
fp(fsfwParams),
|
||||
tp(params.maxFilenameLen) {
|
||||
tp.pduConf.direction = cfdp::Direction::TOWARDS_SENDER;
|
||||
msgToUserVec(params.maxTlvsInOnePdu),
|
||||
transactionParams(params.maxFilenameLen),
|
||||
destParams(std::move(params)),
|
||||
fsfwParams(fsfwParams) {
|
||||
transactionParams.pduConf.direction = cfdp::Direction::TOWARDS_SENDER;
|
||||
}
|
||||
|
||||
const cfdp::DestHandler::FsmResult& cfdp::DestHandler::performStateMachine() {
|
||||
const cfdp::DestHandler::FsmResult& cfdp::DestHandler::stateMachine() {
|
||||
ReturnValue_t result;
|
||||
uint8_t errorIdx = 0;
|
||||
fsmRes.resetOfIteration();
|
||||
if (fsmRes.step == TransactionStep::IDLE) {
|
||||
for (auto infoIter = dp.packetListRef.begin(); infoIter != dp.packetListRef.end();) {
|
||||
for (auto infoIter = destParams.packetListRef.begin();
|
||||
infoIter != destParams.packetListRef.end();) {
|
||||
if (infoIter->pduType == PduType::FILE_DIRECTIVE and
|
||||
infoIter->directiveType == FileDirective::METADATA) {
|
||||
result = handleMetadataPdu(*infoIter);
|
||||
checkAndHandleError(result, errorIdx);
|
||||
// Store data was deleted in PDU handler because a store guard is used
|
||||
dp.packetListRef.erase(infoIter++);
|
||||
destParams.packetListRef.erase(infoIter++);
|
||||
} else {
|
||||
infoIter++;
|
||||
}
|
||||
@ -42,11 +43,12 @@ const cfdp::DestHandler::FsmResult& cfdp::DestHandler::performStateMachine() {
|
||||
if (fsmRes.step == TransactionStep::IDLE) {
|
||||
// To decrease the already high complexity of the software, all packets arriving before
|
||||
// a metadata PDU are deleted.
|
||||
for (auto infoIter = dp.packetListRef.begin(); infoIter != dp.packetListRef.end();) {
|
||||
fp.tcStore->deleteData(infoIter->storeId);
|
||||
for (auto infoIter = destParams.packetListRef.begin();
|
||||
infoIter != destParams.packetListRef.end();) {
|
||||
fsfwParams.tcStore->deleteData(infoIter->storeId);
|
||||
infoIter++;
|
||||
}
|
||||
dp.packetListRef.clear();
|
||||
destParams.packetListRef.clear();
|
||||
}
|
||||
|
||||
if (fsmRes.step != TransactionStep::IDLE) {
|
||||
@ -54,21 +56,22 @@ const cfdp::DestHandler::FsmResult& cfdp::DestHandler::performStateMachine() {
|
||||
}
|
||||
return updateFsmRes(errorIdx);
|
||||
}
|
||||
if (fsmRes.state == CfdpStates::BUSY_CLASS_1_NACKED) {
|
||||
if (fsmRes.state == CfdpState::BUSY_CLASS_1_NACKED) {
|
||||
if (fsmRes.step == TransactionStep::RECEIVING_FILE_DATA_PDUS) {
|
||||
for (auto infoIter = dp.packetListRef.begin(); infoIter != dp.packetListRef.end();) {
|
||||
for (auto infoIter = destParams.packetListRef.begin();
|
||||
infoIter != destParams.packetListRef.end();) {
|
||||
if (infoIter->pduType == PduType::FILE_DATA) {
|
||||
result = handleFileDataPdu(*infoIter);
|
||||
checkAndHandleError(result, errorIdx);
|
||||
// Store data was deleted in PDU handler because a store guard is used
|
||||
dp.packetListRef.erase(infoIter++);
|
||||
destParams.packetListRef.erase(infoIter++);
|
||||
} else if (infoIter->pduType == PduType::FILE_DIRECTIVE and
|
||||
infoIter->directiveType == FileDirective::EOF_DIRECTIVE) {
|
||||
// TODO: Support for check timer missing
|
||||
result = handleEofPdu(*infoIter);
|
||||
checkAndHandleError(result, errorIdx);
|
||||
// Store data was deleted in PDU handler because a store guard is used
|
||||
dp.packetListRef.erase(infoIter++);
|
||||
destParams.packetListRef.erase(infoIter++);
|
||||
} else {
|
||||
infoIter++;
|
||||
}
|
||||
@ -85,7 +88,7 @@ const cfdp::DestHandler::FsmResult& cfdp::DestHandler::performStateMachine() {
|
||||
}
|
||||
return updateFsmRes(errorIdx);
|
||||
}
|
||||
if (fsmRes.state == CfdpStates::BUSY_CLASS_2_ACKED) {
|
||||
if (fsmRes.state == CfdpState::BUSY_CLASS_2_ACKED) {
|
||||
// TODO: Will be implemented at a later stage
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "CFDP state machine for acknowledged mode not implemented yet" << std::endl;
|
||||
@ -95,29 +98,29 @@ const cfdp::DestHandler::FsmResult& cfdp::DestHandler::performStateMachine() {
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::passPacket(PacketInfo packet) {
|
||||
if (dp.packetListRef.full()) {
|
||||
if (destParams.packetListRef.full()) {
|
||||
return FAILED;
|
||||
}
|
||||
dp.packetListRef.push_back(packet);
|
||||
destParams.packetListRef.push_back(packet);
|
||||
return OK;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::initialize() {
|
||||
if (fp.tmStore == nullptr) {
|
||||
fp.tmStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TM_STORE);
|
||||
if (fp.tmStore == nullptr) {
|
||||
if (fsfwParams.tmStore == nullptr) {
|
||||
fsfwParams.tmStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TM_STORE);
|
||||
if (fsfwParams.tmStore == nullptr) {
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
if (fp.tcStore == nullptr) {
|
||||
fp.tcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TC_STORE);
|
||||
if (fp.tcStore == nullptr) {
|
||||
if (fsfwParams.tcStore == nullptr) {
|
||||
fsfwParams.tcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TC_STORE);
|
||||
if (fsfwParams.tcStore == nullptr) {
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
if (fp.msgQueue == nullptr) {
|
||||
if (fsfwParams.msgQueue == nullptr) {
|
||||
return FAILED;
|
||||
}
|
||||
return OK;
|
||||
@ -125,18 +128,16 @@ ReturnValue_t cfdp::DestHandler::initialize() {
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::handleMetadataPdu(const PacketInfo& info) {
|
||||
// Process metadata PDU
|
||||
auto constAccessorPair = fp.tcStore->getData(info.storeId);
|
||||
auto constAccessorPair = fsfwParams.tcStore->getData(info.storeId);
|
||||
if (constAccessorPair.first != OK) {
|
||||
// TODO: This is not a CFDP error. Event and/or warning?
|
||||
return constAccessorPair.first;
|
||||
}
|
||||
cfdp::StringLv sourceFileName;
|
||||
cfdp::StringLv destFileName;
|
||||
MetadataInfo metadataInfo(tp.fileSize, sourceFileName, destFileName);
|
||||
cfdp::Tlv* tlvArrayAsPtr = tlvVec.data();
|
||||
metadataInfo.setOptionsArray(&tlvArrayAsPtr, std::nullopt, tlvVec.size());
|
||||
MetadataGenericInfo metadataInfo(transactionParams.fileSize);
|
||||
MetadataPduReader reader(constAccessorPair.second.data(), constAccessorPair.second.size(),
|
||||
metadataInfo);
|
||||
metadataInfo, tlvVec.data(), tlvVec.size());
|
||||
ReturnValue_t result = reader.parseData();
|
||||
// TODO: The standard does not really specify what happens if this kind of error happens
|
||||
// I think it might be a good idea to cache some sort of error code, which
|
||||
@ -145,18 +146,17 @@ ReturnValue_t cfdp::DestHandler::handleMetadataPdu(const PacketInfo& info) {
|
||||
return handleMetadataParseError(result, constAccessorPair.second.data(),
|
||||
constAccessorPair.second.size());
|
||||
}
|
||||
return startTransaction(reader, metadataInfo);
|
||||
return startTransaction(reader);
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::handleFileDataPdu(const cfdp::PacketInfo& info) {
|
||||
// Process file data PDU
|
||||
auto constAccessorPair = fp.tcStore->getData(info.storeId);
|
||||
auto constAccessorPair = fsfwParams.tcStore->getData(info.storeId);
|
||||
if (constAccessorPair.first != OK) {
|
||||
// TODO: This is not a CFDP error. Event and/or warning?
|
||||
return constAccessorPair.first;
|
||||
}
|
||||
cfdp::FileSize offset;
|
||||
FileDataInfo fdInfo(offset);
|
||||
FileDataInfo fdInfo;
|
||||
FileDataReader reader(constAccessorPair.second.data(), constAccessorPair.second.size(), fdInfo);
|
||||
ReturnValue_t result = reader.parseData();
|
||||
if (result != OK) {
|
||||
@ -164,37 +164,46 @@ ReturnValue_t cfdp::DestHandler::handleFileDataPdu(const cfdp::PacketInfo& info)
|
||||
}
|
||||
size_t fileSegmentLen = 0;
|
||||
const uint8_t* fileData = fdInfo.getFileData(&fileSegmentLen);
|
||||
FileOpParams fileOpParams(tp.destName.data(), fileSegmentLen);
|
||||
fileOpParams.offset = offset.value();
|
||||
if (dp.cfg.indicCfg.fileSegmentRecvIndicRequired) {
|
||||
FileOpParams fileOpParams(transactionParams.destName.data(), fileSegmentLen);
|
||||
fileOpParams.offset = fdInfo.getOffset().value();
|
||||
if (destParams.cfg.indicCfg.fileSegmentRecvIndicRequired) {
|
||||
FileSegmentRecvdParams segParams;
|
||||
segParams.offset = offset.value();
|
||||
segParams.id = tp.transactionId;
|
||||
segParams.offset = fdInfo.getOffset().value();
|
||||
segParams.id = transactionParams.transactionId;
|
||||
segParams.length = fileSegmentLen;
|
||||
segParams.recContState = fdInfo.getRecordContinuationState();
|
||||
size_t segmentMetadatLen = 0;
|
||||
auto* segMetadata = fdInfo.getSegmentMetadata(&segmentMetadatLen);
|
||||
segParams.segmentMetadata = {segMetadata, segmentMetadatLen};
|
||||
dp.user.fileSegmentRecvdIndication(segParams);
|
||||
}
|
||||
result = dp.user.vfs.writeToFile(fileOpParams, fileData);
|
||||
if (offset.value() + fileSegmentLen > tp.progress) {
|
||||
tp.progress = offset.value() + fileSegmentLen;
|
||||
destParams.user.fileSegmentRecvdIndication(segParams);
|
||||
}
|
||||
result = destParams.user.vfs.writeToFile(fileOpParams, fileData);
|
||||
if (result != returnvalue::OK) {
|
||||
// TODO: Proper Error handling
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "File write error" << std::endl;
|
||||
sif::error << "cfdp::DestHandler: VFS file write error with code 0x" << std::hex << std::setw(2)
|
||||
<< result << std::endl;
|
||||
#endif
|
||||
transactionParams.vfsErrorCount++;
|
||||
if (transactionParams.vfsErrorCount < 3) {
|
||||
// TODO: Provide execution step as parameter
|
||||
fsfwParams.eventReporter->forwardEvent(events::FILESTORE_ERROR,
|
||||
static_cast<uint8_t>(fsmRes.step), result);
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
tp.deliveryStatus = FileDeliveryStatus::RETAINED_IN_FILESTORE;
|
||||
transactionParams.deliveryStatus = FileDeliveryStatus::RETAINED_IN_FILESTORE;
|
||||
transactionParams.vfsErrorCount = 0;
|
||||
}
|
||||
if (fdInfo.getOffset().value() + fileSegmentLen > transactionParams.progress) {
|
||||
transactionParams.progress = fdInfo.getOffset().value() + fileSegmentLen;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::handleEofPdu(const cfdp::PacketInfo& info) {
|
||||
// Process EOF PDU
|
||||
auto constAccessorPair = fp.tcStore->getData(info.storeId);
|
||||
auto constAccessorPair = fsfwParams.tcStore->getData(info.storeId);
|
||||
if (constAccessorPair.first != OK) {
|
||||
// TODO: This is not a CFDP error. Event and/or warning?
|
||||
return constAccessorPair.first;
|
||||
@ -207,21 +216,21 @@ ReturnValue_t cfdp::DestHandler::handleEofPdu(const cfdp::PacketInfo& info) {
|
||||
}
|
||||
// TODO: Error handling
|
||||
if (eofInfo.getConditionCode() == ConditionCode::NO_ERROR) {
|
||||
tp.crc = eofInfo.getChecksum();
|
||||
transactionParams.crc = eofInfo.getChecksum();
|
||||
uint64_t fileSizeFromEof = eofInfo.getFileSize().value();
|
||||
// CFDP 4.6.1.2.9: Declare file size error if progress exceeds file size
|
||||
if (fileSizeFromEof > tp.progress) {
|
||||
if (fileSizeFromEof > transactionParams.progress) {
|
||||
// TODO: File size error
|
||||
}
|
||||
tp.fileSize.setFileSize(fileSizeFromEof, std::nullopt);
|
||||
transactionParams.fileSize.setFileSize(fileSizeFromEof, std::nullopt);
|
||||
}
|
||||
if (dp.cfg.indicCfg.eofRecvIndicRequired) {
|
||||
dp.user.eofRecvIndication(getTransactionId());
|
||||
if (destParams.cfg.indicCfg.eofRecvIndicRequired) {
|
||||
destParams.user.eofRecvIndication(getTransactionId());
|
||||
}
|
||||
if (fsmRes.step == TransactionStep::RECEIVING_FILE_DATA_PDUS) {
|
||||
if (fsmRes.state == CfdpStates::BUSY_CLASS_1_NACKED) {
|
||||
if (fsmRes.state == CfdpState::BUSY_CLASS_1_NACKED) {
|
||||
fsmRes.step = TransactionStep::TRANSFER_COMPLETION;
|
||||
} else if (fsmRes.state == CfdpStates::BUSY_CLASS_2_ACKED) {
|
||||
} else if (fsmRes.state == CfdpState::BUSY_CLASS_2_ACKED) {
|
||||
fsmRes.step = TransactionStep::SENDING_ACK_PDU;
|
||||
}
|
||||
}
|
||||
@ -251,7 +260,7 @@ ReturnValue_t cfdp::DestHandler::handleMetadataParseError(ReturnValue_t result,
|
||||
cfdp::EntityId destId;
|
||||
headerReader.getDestId(destId);
|
||||
RemoteEntityCfg* remoteCfg;
|
||||
if (not dp.remoteCfgTable.getRemoteCfg(destId, &remoteCfg)) {
|
||||
if (not destParams.remoteCfgTable.getRemoteCfg(destId, &remoteCfg)) {
|
||||
// TODO: No remote config for dest ID. I consider this a configuration error, which is not
|
||||
// covered by the standard.
|
||||
// Warning or error, yield or cache appropriate returnvalue
|
||||
@ -265,127 +274,195 @@ ReturnValue_t cfdp::DestHandler::handleMetadataParseError(ReturnValue_t result,
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::startTransaction(MetadataPduReader& reader, MetadataInfo& info) {
|
||||
if (fsmRes.state != CfdpStates::IDLE) {
|
||||
ReturnValue_t cfdp::DestHandler::startTransaction(const MetadataPduReader& reader) {
|
||||
if (fsmRes.state != CfdpState::IDLE) {
|
||||
// According to standard, discard metadata PDU if we are busy
|
||||
return OK;
|
||||
}
|
||||
ReturnValue_t result = OK;
|
||||
fsmRes.step = TransactionStep::TRANSACTION_START;
|
||||
if (reader.getTransmissionMode() == TransmissionMode::UNACKNOWLEDGED) {
|
||||
fsmRes.state = CfdpStates::BUSY_CLASS_1_NACKED;
|
||||
} else if (reader.getTransmissionMode() == TransmissionMode::ACKNOWLEDGED) {
|
||||
fsmRes.state = CfdpStates::BUSY_CLASS_2_ACKED;
|
||||
}
|
||||
tp.checksumType = info.getChecksumType();
|
||||
tp.closureRequested = info.isClosureRequested();
|
||||
size_t sourceNameSize = 0;
|
||||
const uint8_t* sourceNamePtr = info.getSourceFileName().getValue(&sourceNameSize);
|
||||
if (sourceNameSize > tp.sourceName.size()) {
|
||||
// TODO: Warning, event etc.
|
||||
return FAILED;
|
||||
|
||||
if (not reader.getSourceFileName().isEmpty()) {
|
||||
const uint8_t* sourceNamePtr = reader.getSourceFileName().getValue(&sourceNameSize);
|
||||
if (sourceNameSize + 1 > transactionParams.sourceName.size()) {
|
||||
fileErrorHandler(events::FILENAME_TOO_LARGE_ERROR, 0, "source filename too large");
|
||||
return FAILED;
|
||||
}
|
||||
std::memcpy(transactionParams.sourceName.data(), sourceNamePtr, sourceNameSize);
|
||||
transactionParams.sourceName[sourceNameSize] = '\0';
|
||||
}
|
||||
std::memcpy(tp.sourceName.data(), sourceNamePtr, sourceNameSize);
|
||||
tp.sourceName[sourceNameSize] = '\0';
|
||||
size_t destNameSize = 0;
|
||||
const uint8_t* destNamePtr = info.getDestFileName().getValue(&destNameSize);
|
||||
if (destNameSize > tp.destName.size()) {
|
||||
// TODO: Warning, event etc.
|
||||
return FAILED;
|
||||
if (not reader.getDestFileName().isEmpty()) {
|
||||
const uint8_t* destNamePtr = reader.getDestFileName().getValue(&destNameSize);
|
||||
if (destNameSize + 1 > transactionParams.destName.size()) {
|
||||
fileErrorHandler(events::FILENAME_TOO_LARGE_ERROR, 0, "dest filename too large");
|
||||
return FAILED;
|
||||
}
|
||||
std::memcpy(transactionParams.destName.data(), destNamePtr, destNameSize);
|
||||
transactionParams.destName[destNameSize] = '\0';
|
||||
}
|
||||
std::memcpy(tp.destName.data(), destNamePtr, destNameSize);
|
||||
tp.destName[destNameSize] = '\0';
|
||||
reader.fillConfig(tp.pduConf);
|
||||
tp.pduConf.direction = Direction::TOWARDS_SENDER;
|
||||
tp.transactionId.entityId = tp.pduConf.sourceId;
|
||||
tp.transactionId.seqNum = tp.pduConf.seqNum;
|
||||
if (not dp.remoteCfgTable.getRemoteCfg(tp.pduConf.sourceId, &tp.remoteCfg)) {
|
||||
|
||||
transactionParams.metadataOnly = true;
|
||||
// If both dest name size and source name size are 0, we are dealing with a metadata only PDU,
|
||||
// so there is no need to create a file or truncate an existing file
|
||||
if (destNameSize > 0 and sourceNameSize > 0) {
|
||||
transactionParams.metadataOnly = false;
|
||||
FilesystemParams fparams(transactionParams.destName.data());
|
||||
// handling to allow only specifying target directory. Example:
|
||||
// Source path /test/hello.txt, dest path /tmp -> dest path /tmp/hello.txt
|
||||
if (destParams.user.vfs.isDirectory(transactionParams.destName.data())) {
|
||||
result = tryBuildingAbsoluteDestName(destNameSize);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
if (destParams.user.vfs.fileExists(fparams)) {
|
||||
result = destParams.user.vfs.truncateFile(fparams);
|
||||
if (result != returnvalue::OK) {
|
||||
fileErrorHandler(events::FILESTORE_ERROR, result, "file truncation error");
|
||||
return FAILED;
|
||||
// TODO: Relevant for filestore rejection error?
|
||||
}
|
||||
} else {
|
||||
result = destParams.user.vfs.createFile(fparams);
|
||||
if (result != OK) {
|
||||
fileErrorHandler(events::FILESTORE_ERROR, result, "file creation error");
|
||||
return FAILED;
|
||||
// TODO: Relevant for filestore rejection error?
|
||||
}
|
||||
}
|
||||
}
|
||||
EntityId sourceId;
|
||||
reader.getSourceId(sourceId);
|
||||
if (not destParams.remoteCfgTable.getRemoteCfg(sourceId, &transactionParams.remoteCfg)) {
|
||||
// TODO: Warning, event etc.
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "cfdp::DestHandler" << __func__
|
||||
<< ": No remote configuration found for destination ID "
|
||||
<< tp.pduConf.sourceId.getValue() << std::endl;
|
||||
<< transactionParams.pduConf.sourceId.getValue() << std::endl;
|
||||
#endif
|
||||
return FAILED;
|
||||
}
|
||||
// If both dest name size and source name size are 0, we are dealing with a metadata only PDU,
|
||||
// so there is no need to create a file or truncate an existing file
|
||||
if (destNameSize > 0 and sourceNameSize > 0) {
|
||||
FilesystemParams fparams(tp.destName.data());
|
||||
// TODO: Filesystem errors?
|
||||
if (dp.user.vfs.fileExists(fparams)) {
|
||||
dp.user.vfs.truncateFile(fparams);
|
||||
} else {
|
||||
result = dp.user.vfs.createFile(fparams);
|
||||
if (result != OK) {
|
||||
// TODO: Handle FS error. This is probably a case for the filestore rejection mechanism of
|
||||
// CFDP.
|
||||
// In any case, it does not really make sense to continue here
|
||||
}
|
||||
if (reader.getTransmissionMode() == TransmissionMode::UNACKNOWLEDGED) {
|
||||
fsmRes.state = CfdpState::BUSY_CLASS_1_NACKED;
|
||||
} else if (reader.getTransmissionMode() == TransmissionMode::ACKNOWLEDGED) {
|
||||
fsmRes.state = CfdpState::BUSY_CLASS_2_ACKED;
|
||||
}
|
||||
if (transactionParams.metadataOnly) {
|
||||
fsmRes.step = TransactionStep::TRANSFER_COMPLETION;
|
||||
} else {
|
||||
// Kind of ugly, make FSM working on packet per packet basis..
|
||||
fsmRes.step = TransactionStep::TRANSACTION_START;
|
||||
fsmRes.step = TransactionStep::RECEIVING_FILE_DATA_PDUS;
|
||||
}
|
||||
auto& info = reader.getGenericInfo();
|
||||
transactionParams.checksumType = info.getChecksumType();
|
||||
transactionParams.closureRequested = info.isClosureRequested();
|
||||
reader.fillConfig(transactionParams.pduConf);
|
||||
transactionParams.pduConf.direction = Direction::TOWARDS_SENDER;
|
||||
transactionParams.transactionId.entityId = transactionParams.pduConf.sourceId;
|
||||
transactionParams.transactionId.seqNum = transactionParams.pduConf.seqNum;
|
||||
transactionParams.fileSize = info.getFileSize();
|
||||
MetadataRecvdParams params(transactionParams.transactionId, transactionParams.pduConf.sourceId,
|
||||
transactionParams.fileSize);
|
||||
params.destFileName = transactionParams.destName.data();
|
||||
params.sourceFileName = transactionParams.sourceName.data();
|
||||
params.numberOfMsgsToUser = 0;
|
||||
for (const auto& opt : tlvVec) {
|
||||
if (opt.getType() == TlvType::MSG_TO_USER) {
|
||||
msgToUserVec[params.numberOfMsgsToUser] =
|
||||
MessageToUserTlv(opt.getValue(), opt.getLengthField());
|
||||
params.numberOfMsgsToUser++;
|
||||
}
|
||||
}
|
||||
fsmRes.step = TransactionStep::RECEIVING_FILE_DATA_PDUS;
|
||||
MetadataRecvdParams params(tp.transactionId, tp.pduConf.sourceId);
|
||||
params.fileSize = tp.fileSize.getSize();
|
||||
params.destFileName = tp.destName.data();
|
||||
params.sourceFileName = tp.sourceName.data();
|
||||
params.msgsToUserArray = dynamic_cast<MessageToUserTlv*>(userTlvVec.data());
|
||||
params.msgsToUserLen = info.getOptionsLen();
|
||||
dp.user.metadataRecvdIndication(params);
|
||||
params.msgsToUserArray = msgToUserVec.data();
|
||||
destParams.user.metadataRecvdIndication(params);
|
||||
return result;
|
||||
}
|
||||
|
||||
cfdp::CfdpStates cfdp::DestHandler::getCfdpState() const { return fsmRes.state; }
|
||||
cfdp::CfdpState cfdp::DestHandler::getCfdpState() const { return fsmRes.state; }
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::handleTransferCompletion() {
|
||||
ReturnValue_t result;
|
||||
if (tp.checksumType != ChecksumType::NULL_CHECKSUM) {
|
||||
if (transactionParams.checksumType != ChecksumType::NULL_CHECKSUM) {
|
||||
result = checksumVerification();
|
||||
if (result != OK) {
|
||||
// TODO: Warning / error handling?
|
||||
}
|
||||
} else {
|
||||
tp.conditionCode = ConditionCode::NO_ERROR;
|
||||
transactionParams.conditionCode = ConditionCode::NO_ERROR;
|
||||
}
|
||||
result = noticeOfCompletion();
|
||||
if (result != OK) {
|
||||
}
|
||||
if (fsmRes.state == CfdpStates::BUSY_CLASS_1_NACKED) {
|
||||
if (tp.closureRequested) {
|
||||
if (fsmRes.state == CfdpState::BUSY_CLASS_1_NACKED) {
|
||||
if (transactionParams.closureRequested) {
|
||||
fsmRes.step = TransactionStep::SENDING_FINISHED_PDU;
|
||||
} else {
|
||||
finish();
|
||||
}
|
||||
} else if (fsmRes.state == CfdpStates::BUSY_CLASS_2_ACKED) {
|
||||
} else if (fsmRes.state == CfdpState::BUSY_CLASS_2_ACKED) {
|
||||
fsmRes.step = TransactionStep::SENDING_FINISHED_PDU;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::tryBuildingAbsoluteDestName(size_t destNameSize) {
|
||||
// A path may only have a maximum of 256 characters in CFDP, so this buffer should be sufficient
|
||||
// for all use-cases.
|
||||
char baseNameBuf[512]{};
|
||||
FilesystemParams fparamsSrc(transactionParams.sourceName.data());
|
||||
size_t baseNameLen = 0;
|
||||
ReturnValue_t result = destParams.user.vfs.getBaseFilename(fparamsSrc, baseNameBuf,
|
||||
sizeof(baseNameBuf), baseNameLen);
|
||||
if (result != returnvalue::OK or baseNameLen == 0) {
|
||||
fileErrorHandler(events::FILENAME_TOO_LARGE_ERROR, 0, "error retrieving source base name");
|
||||
return FAILED;
|
||||
}
|
||||
// Destination name + slash + base name + null termination
|
||||
if (destNameSize + 1 + baseNameLen + 1 > transactionParams.destName.size()) {
|
||||
fileErrorHandler(events::FILENAME_TOO_LARGE_ERROR, 0,
|
||||
"dest filename too large after adding source base name");
|
||||
return FAILED;
|
||||
}
|
||||
transactionParams.destName[destNameSize++] = '/';
|
||||
std::memcpy(transactionParams.destName.data() + destNameSize, baseNameBuf, baseNameLen);
|
||||
destNameSize += baseNameLen;
|
||||
transactionParams.destName[destNameSize++] = '\0';
|
||||
return OK;
|
||||
}
|
||||
|
||||
void cfdp::DestHandler::fileErrorHandler(Event event, ReturnValue_t result,
|
||||
const char* info) const {
|
||||
fsfwParams.eventReporter->forwardEvent(event, static_cast<uint8_t>(fsmRes.step), result);
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "cfdp::DestHandler: " << info << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
void cfdp::DestHandler::finish() {
|
||||
tp.reset();
|
||||
dp.packetListRef.clear();
|
||||
fsmRes.state = CfdpStates::IDLE;
|
||||
transactionParams.reset();
|
||||
destParams.packetListRef.clear();
|
||||
fsmRes.state = CfdpState::IDLE;
|
||||
fsmRes.step = TransactionStep::IDLE;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::checksumVerification() {
|
||||
std::array<uint8_t, 1024> buf{};
|
||||
// TODO: Checksum verification and notice of completion
|
||||
etl::crc32 crcCalc;
|
||||
uint64_t currentOffset = 0;
|
||||
FileOpParams params(tp.destName.data(), tp.fileSize.value());
|
||||
while (currentOffset < tp.fileSize.value()) {
|
||||
FileOpParams params(transactionParams.destName.data(), transactionParams.fileSize.value());
|
||||
while (currentOffset < transactionParams.fileSize.value()) {
|
||||
uint64_t readLen;
|
||||
if (currentOffset + buf.size() > tp.fileSize.value()) {
|
||||
readLen = tp.fileSize.value() - currentOffset;
|
||||
if (currentOffset + buf.size() > transactionParams.fileSize.value()) {
|
||||
readLen = transactionParams.fileSize.value() - currentOffset;
|
||||
} else {
|
||||
readLen = buf.size();
|
||||
}
|
||||
if (readLen > 0) {
|
||||
params.offset = currentOffset;
|
||||
params.size = readLen;
|
||||
auto result = dp.user.vfs.readFromFile(params, buf.data(), buf.size());
|
||||
auto result = destParams.user.vfs.readFromFile(params, buf.data(), buf.size());
|
||||
if (result != OK) {
|
||||
// TODO: I think this is a case for a filestore rejection, but it might sense to print
|
||||
// a warning or trigger an event because this should generally not happen
|
||||
@ -397,49 +474,62 @@ ReturnValue_t cfdp::DestHandler::checksumVerification() {
|
||||
}
|
||||
|
||||
uint32_t value = crcCalc.value();
|
||||
if (value == tp.crc) {
|
||||
tp.conditionCode = ConditionCode::NO_ERROR;
|
||||
tp.deliveryCode = FileDeliveryCode::DATA_COMPLETE;
|
||||
if (value == transactionParams.crc) {
|
||||
transactionParams.conditionCode = ConditionCode::NO_ERROR;
|
||||
transactionParams.deliveryCode = FileDeliveryCode::DATA_COMPLETE;
|
||||
} else {
|
||||
// TODO: Proper error handling
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "CRC check for file " << tp.destName.data() << " failed" << std::endl;
|
||||
sif::warning << "CRC check for file " << transactionParams.destName.data() << " failed"
|
||||
<< std::endl;
|
||||
#endif
|
||||
tp.conditionCode = ConditionCode::FILE_CHECKSUM_FAILURE;
|
||||
transactionParams.conditionCode = ConditionCode::FILE_CHECKSUM_FAILURE;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::noticeOfCompletion() {
|
||||
if (dp.cfg.indicCfg.transactionFinishedIndicRequired) {
|
||||
TransactionFinishedParams params(tp.transactionId, tp.conditionCode, tp.deliveryCode,
|
||||
tp.deliveryStatus);
|
||||
dp.user.transactionFinishedIndication(params);
|
||||
if (destParams.cfg.indicCfg.transactionFinishedIndicRequired) {
|
||||
TransactionFinishedParams params(
|
||||
transactionParams.transactionId, transactionParams.conditionCode,
|
||||
transactionParams.deliveryCode, transactionParams.deliveryStatus);
|
||||
destParams.user.transactionFinishedIndication(params);
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::sendFinishedPdu() {
|
||||
FinishedInfo info(tp.conditionCode, tp.deliveryCode, tp.deliveryStatus);
|
||||
FinishPduCreator finishedPdu(tp.pduConf, info);
|
||||
FinishedInfo info(transactionParams.conditionCode, transactionParams.deliveryCode,
|
||||
transactionParams.deliveryStatus);
|
||||
FinishPduCreator finishedPdu(transactionParams.pduConf, info);
|
||||
store_address_t storeId;
|
||||
uint8_t* dataPtr = nullptr;
|
||||
ReturnValue_t result =
|
||||
fp.tcStore->getFreeElement(&storeId, finishedPdu.getSerializedSize(), &dataPtr);
|
||||
fsfwParams.tmStore->getFreeElement(&storeId, finishedPdu.getSerializedSize(), &dataPtr);
|
||||
if (result != OK) {
|
||||
// TODO: Error handling and event, this is a non CFDP specific error (most likely store is full)
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "cfdp::DestHandler:sendFinishedPdu: Getting store slot failed" << std::endl;
|
||||
#endif
|
||||
fsfwParams.eventReporter->forwardEvent(events::STORE_ERROR, result, 0);
|
||||
return result;
|
||||
}
|
||||
size_t serLen = 0;
|
||||
result = finishedPdu.serialize(dataPtr, serLen, finishedPdu.getSerializedSize());
|
||||
if (result != OK) {
|
||||
// TODO: Error printout, this really should not happen
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "cfdp::DestHandler::sendFinishedPdu: Serializing Finished PDU failed"
|
||||
<< std::endl;
|
||||
#endif
|
||||
fsfwParams.eventReporter->forwardEvent(events::SERIALIZATION_ERROR, result, 0);
|
||||
return result;
|
||||
}
|
||||
TmTcMessage msg(storeId);
|
||||
result = fp.msgQueue->sendMessage(fp.packetDest.getReportReceptionQueue(), &msg);
|
||||
result = fsfwParams.msgQueue->sendMessage(fsfwParams.packetDest.getReportReceptionQueue(), &msg);
|
||||
if (result != OK) {
|
||||
// TODO: Error handling and event, this is a non CFDP specific error (most likely store is full)
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "cfdp::DestHandler::sendFinishedPdu: Sending PDU failed" << std::endl;
|
||||
#endif
|
||||
fsfwParams.eventReporter->forwardEvent(events::MSG_QUEUE_ERROR, result, 0);
|
||||
return result;
|
||||
}
|
||||
fsmRes.packetsSent++;
|
||||
@ -459,7 +549,9 @@ const cfdp::DestHandler::FsmResult& cfdp::DestHandler::updateFsmRes(uint8_t erro
|
||||
return fsmRes;
|
||||
}
|
||||
|
||||
const cfdp::TransactionId& cfdp::DestHandler::getTransactionId() const { return tp.transactionId; }
|
||||
const cfdp::TransactionId& cfdp::DestHandler::getTransactionId() const {
|
||||
return transactionParams.transactionId;
|
||||
}
|
||||
|
||||
void cfdp::DestHandler::checkAndHandleError(ReturnValue_t result, uint8_t& errorIdx) {
|
||||
if (result != OK and errorIdx < 3) {
|
||||
@ -468,13 +560,15 @@ void cfdp::DestHandler::checkAndHandleError(ReturnValue_t result, uint8_t& error
|
||||
}
|
||||
}
|
||||
|
||||
void cfdp::DestHandler::setMsgQueue(MessageQueueIF& queue) { fp.msgQueue = &queue; }
|
||||
void cfdp::DestHandler::setMsgQueue(MessageQueueIF& queue) { fsfwParams.msgQueue = &queue; }
|
||||
|
||||
void cfdp::DestHandler::setEventReporter(EventReportingProxyIF& reporter) {
|
||||
fp.eventReporter = &reporter;
|
||||
fsfwParams.eventReporter = &reporter;
|
||||
}
|
||||
|
||||
const cfdp::DestHandlerParams& cfdp::DestHandler::getDestHandlerParams() const { return dp; }
|
||||
const cfdp::DestHandlerParams& cfdp::DestHandler::getDestHandlerParams() const {
|
||||
return destParams;
|
||||
}
|
||||
|
||||
StorageManagerIF* cfdp::DestHandler::getTmStore() const { return fp.tmStore; }
|
||||
StorageManagerIF* cfdp::DestHandler::getTcStore() const { return fp.tcStore; }
|
||||
StorageManagerIF* cfdp::DestHandler::getTmStore() const { return fsfwParams.tmStore; }
|
||||
StorageManagerIF* cfdp::DestHandler::getTcStore() const { return fsfwParams.tcStore; }
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "fsfw/cfdp/handler/mib.h"
|
||||
#include "fsfw/cfdp/pdu/MetadataPduReader.h"
|
||||
#include "fsfw/cfdp/pdu/PduConfig.h"
|
||||
#include "fsfw/cfdp/tlv/MessageToUserTlv.h"
|
||||
#include "fsfw/container/DynamicFIFO.h"
|
||||
#include "fsfw/storagemanager/StorageManagerIF.h"
|
||||
#include "fsfw/storagemanager/storeAddress.h"
|
||||
@ -20,23 +21,9 @@
|
||||
|
||||
namespace cfdp {
|
||||
|
||||
struct PacketInfo {
|
||||
PacketInfo(PduType type, store_address_t storeId,
|
||||
std::optional<FileDirective> directive = std::nullopt)
|
||||
: pduType(type), directiveType(directive), storeId(storeId) {}
|
||||
|
||||
PduType pduType = PduType::FILE_DATA;
|
||||
std::optional<FileDirective> directiveType = FileDirective::INVALID_DIRECTIVE;
|
||||
store_address_t storeId = store_address_t::invalid();
|
||||
PacketInfo() = default;
|
||||
};
|
||||
|
||||
template <size_t SIZE>
|
||||
using LostSegmentsList = etl::set<etl::pair<uint64_t, uint64_t>, SIZE>;
|
||||
template <size_t SIZE>
|
||||
using PacketInfoList = etl::list<PacketInfo, SIZE>;
|
||||
using LostSegmentsListBase = etl::iset<etl::pair<uint64_t, uint64_t>>;
|
||||
using PacketInfoListBase = etl::ilist<PacketInfo>;
|
||||
|
||||
struct DestHandlerParams {
|
||||
DestHandlerParams(LocalEntityCfg cfg, UserBase& user, RemoteConfigTableIF& remoteCfgTable,
|
||||
@ -44,6 +31,9 @@ struct DestHandlerParams {
|
||||
// TODO: This container can potentially take tons of space. For a better
|
||||
// memory efficient implementation, an additional abstraction could be
|
||||
// be used so users can use uint32_t as the pair type
|
||||
// TODO: Actually, we can provide a better abstraction via interface, which
|
||||
// allows using something like a bounded map. This simplifies
|
||||
// the implementation significantly.
|
||||
LostSegmentsListBase& lostSegmentsContainer)
|
||||
: cfg(std::move(cfg)),
|
||||
user(user),
|
||||
@ -57,34 +47,13 @@ struct DestHandlerParams {
|
||||
|
||||
PacketInfoListBase& packetListRef;
|
||||
LostSegmentsListBase& lostSegmentsContainer;
|
||||
uint8_t maxTlvsInOnePdu = 10;
|
||||
uint8_t maxTlvsInOnePdu = 20;
|
||||
size_t maxFilenameLen = 255;
|
||||
};
|
||||
|
||||
struct FsfwParams {
|
||||
FsfwParams(AcceptsTelemetryIF& packetDest, MessageQueueIF* msgQueue,
|
||||
EventReportingProxyIF* eventReporter, StorageManagerIF& tcStore,
|
||||
StorageManagerIF& tmStore)
|
||||
: FsfwParams(packetDest, msgQueue, eventReporter) {
|
||||
this->tcStore = &tcStore;
|
||||
this->tmStore = &tmStore;
|
||||
}
|
||||
|
||||
FsfwParams(AcceptsTelemetryIF& packetDest, MessageQueueIF* msgQueue,
|
||||
EventReportingProxyIF* eventReporter)
|
||||
: packetDest(packetDest), msgQueue(msgQueue), eventReporter(eventReporter) {}
|
||||
AcceptsTelemetryIF& packetDest;
|
||||
MessageQueueIF* msgQueue;
|
||||
EventReportingProxyIF* eventReporter = nullptr;
|
||||
StorageManagerIF* tcStore = nullptr;
|
||||
StorageManagerIF* tmStore = nullptr;
|
||||
};
|
||||
|
||||
enum class CallStatus { DONE, CALL_AFTER_DELAY, CALL_AGAIN };
|
||||
|
||||
class DestHandler {
|
||||
public:
|
||||
enum class TransactionStep {
|
||||
enum class TransactionStep : uint8_t {
|
||||
IDLE = 0,
|
||||
TRANSACTION_START = 1,
|
||||
RECEIVING_FILE_DATA_PDUS = 2,
|
||||
@ -98,7 +67,7 @@ class DestHandler {
|
||||
ReturnValue_t result = returnvalue::OK;
|
||||
CallStatus callStatus = CallStatus::CALL_AFTER_DELAY;
|
||||
TransactionStep step = TransactionStep::IDLE;
|
||||
CfdpStates state = CfdpStates::IDLE;
|
||||
CfdpState state = CfdpState::IDLE;
|
||||
uint32_t packetsSent = 0;
|
||||
uint8_t errors = 0;
|
||||
std::array<ReturnValue_t, 3> errorCodes = {};
|
||||
@ -123,7 +92,7 @@ class DestHandler {
|
||||
* - @c returnvalue::OK State machine OK for this execution cycle
|
||||
* - @c CALL_FSM_AGAIN State machine should be called again.
|
||||
*/
|
||||
const FsmResult& performStateMachine();
|
||||
const FsmResult& stateMachine();
|
||||
void setMsgQueue(MessageQueueIF& queue);
|
||||
void setEventReporter(EventReportingProxyIF& reporter);
|
||||
|
||||
@ -131,7 +100,7 @@ class DestHandler {
|
||||
|
||||
ReturnValue_t initialize();
|
||||
|
||||
[[nodiscard]] CfdpStates getCfdpState() const;
|
||||
[[nodiscard]] CfdpState getCfdpState() const;
|
||||
[[nodiscard]] TransactionStep getTransactionStep() const;
|
||||
[[nodiscard]] const TransactionId& getTransactionId() const;
|
||||
[[nodiscard]] const DestHandlerParams& getDestHandlerParams() const;
|
||||
@ -156,15 +125,19 @@ class DestHandler {
|
||||
crc = 0;
|
||||
progress = 0;
|
||||
remoteCfg = nullptr;
|
||||
metadataOnly = false;
|
||||
closureRequested = false;
|
||||
vfsErrorCount = 0;
|
||||
checksumType = ChecksumType::NULL_CHECKSUM;
|
||||
}
|
||||
|
||||
bool metadataOnly = false;
|
||||
ChecksumType checksumType = ChecksumType::NULL_CHECKSUM;
|
||||
bool closureRequested = false;
|
||||
uint16_t vfsErrorCount = 0;
|
||||
std::vector<char> sourceName;
|
||||
std::vector<char> destName;
|
||||
cfdp::FileSize fileSize;
|
||||
cfdp::Fss fileSize;
|
||||
TransactionId transactionId;
|
||||
PduConfig pduConf;
|
||||
ConditionCode conditionCode = ConditionCode::NO_ERROR;
|
||||
@ -176,22 +149,24 @@ class DestHandler {
|
||||
};
|
||||
|
||||
std::vector<cfdp::Tlv> tlvVec;
|
||||
std::vector<cfdp::Tlv> userTlvVec;
|
||||
DestHandlerParams dp;
|
||||
FsfwParams fp;
|
||||
TransactionParams tp;
|
||||
std::vector<MessageToUserTlv> msgToUserVec;
|
||||
TransactionParams transactionParams;
|
||||
DestHandlerParams destParams;
|
||||
cfdp::FsfwParams fsfwParams;
|
||||
FsmResult fsmRes;
|
||||
|
||||
ReturnValue_t startTransaction(MetadataPduReader& reader, MetadataInfo& info);
|
||||
ReturnValue_t startTransaction(const MetadataPduReader& reader);
|
||||
ReturnValue_t handleMetadataPdu(const PacketInfo& info);
|
||||
ReturnValue_t handleFileDataPdu(const PacketInfo& info);
|
||||
ReturnValue_t handleEofPdu(const PacketInfo& info);
|
||||
ReturnValue_t handleMetadataParseError(ReturnValue_t result, const uint8_t* rawData,
|
||||
size_t maxSize);
|
||||
ReturnValue_t handleTransferCompletion();
|
||||
ReturnValue_t tryBuildingAbsoluteDestName(size_t destNameSize);
|
||||
ReturnValue_t sendFinishedPdu();
|
||||
ReturnValue_t noticeOfCompletion();
|
||||
ReturnValue_t checksumVerification();
|
||||
void fileErrorHandler(Event event, ReturnValue_t result, const char* info) const;
|
||||
const FsmResult& updateFsmRes(uint8_t errors);
|
||||
void checkAndHandleError(ReturnValue_t result, uint8_t& errorIdx);
|
||||
void finish();
|
||||
|
201
src/fsfw/cfdp/handler/PutRequest.cpp
Normal file
201
src/fsfw/cfdp/handler/PutRequest.cpp
Normal file
@ -0,0 +1,201 @@
|
||||
#include "PutRequest.h"
|
||||
|
||||
using namespace returnvalue;
|
||||
|
||||
cfdp::PutRequest::PutRequest(cfdp::EntityId destId, const uint8_t *msgsToUser,
|
||||
size_t msgsToUserTotalSize, const uint8_t *fsRequests,
|
||||
size_t fsRequestsSize)
|
||||
: destId(std::move(destId)),
|
||||
metadataOnly(true),
|
||||
msgsToUsersTotalSize(msgsToUserTotalSize),
|
||||
msgsToUserStartPtr(msgsToUser),
|
||||
fsRequestsTotalSize(fsRequestsSize),
|
||||
fsRequestStartPtr(fsRequests) {}
|
||||
|
||||
cfdp::PutRequest::PutRequest(cfdp::EntityId destId, cfdp::StringLv &sourceName,
|
||||
cfdp::StringLv &destName)
|
||||
: destId(std::move(destId)), sourceName(std::move(sourceName)), destName(std::move(destName)) {}
|
||||
|
||||
[[nodiscard]] bool cfdp::PutRequest::isMetadataOnly() const { return metadataOnly; }
|
||||
|
||||
ReturnValue_t cfdp::PutRequest::serialize(uint8_t **buffer, size_t *size, size_t maxSize,
|
||||
SerializeIF::Endianness streamEndianness) const {
|
||||
if (buffer == nullptr or size == nullptr) {
|
||||
return FAILED;
|
||||
}
|
||||
if (*size + getSerializedSize() > maxSize) {
|
||||
return SerializeIF::BUFFER_TOO_SHORT;
|
||||
}
|
||||
ReturnValue_t result = destId.serializeAsLv(buffer, size, maxSize);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
result = SerializeAdapter::serialize(&metadataOnly, buffer, size, maxSize, streamEndianness);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
if (!metadataOnly) {
|
||||
result = sourceName.serialize(buffer, size, maxSize, streamEndianness);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
result = destName.serialize(buffer, size, maxSize, streamEndianness);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
result =
|
||||
SerializeAdapter::serialize(&hasTransmissionMode, buffer, size, maxSize, streamEndianness);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
result =
|
||||
SerializeAdapter::serialize(&transmissionMode, buffer, size, maxSize, streamEndianness);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
result =
|
||||
SerializeAdapter::serialize(&hasClosureRequested, buffer, size, maxSize, streamEndianness);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
result =
|
||||
SerializeAdapter::serialize(&closureRequested, buffer, size, maxSize, streamEndianness);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
result =
|
||||
SerializeAdapter::serialize(&msgsToUsersTotalSize, buffer, size, maxSize, streamEndianness);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
std::memcpy(*buffer, msgsToUserStartPtr, msgsToUsersTotalSize);
|
||||
*buffer += msgsToUsersTotalSize;
|
||||
*size += msgsToUsersTotalSize;
|
||||
|
||||
result =
|
||||
SerializeAdapter::serialize(&fsRequestsTotalSize, buffer, size, maxSize, streamEndianness);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
std::memcpy(*buffer, fsRequestStartPtr, fsRequestsTotalSize);
|
||||
*buffer += fsRequestsTotalSize;
|
||||
*size += fsRequestsTotalSize;
|
||||
return OK;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::PutRequest::deSerialize(const uint8_t **buffer, size_t *size,
|
||||
SerializeIF::Endianness streamEndianness) {
|
||||
if (buffer == nullptr or size == nullptr) {
|
||||
return FAILED;
|
||||
}
|
||||
ReturnValue_t result = destId.deSerializeFromLv(buffer, size);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
result = SerializeAdapter::deSerialize(&metadataOnly, buffer, size, streamEndianness);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
if (!metadataOnly) {
|
||||
result = sourceName.deSerialize(buffer, size, streamEndianness);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
result = destName.deSerialize(buffer, size, streamEndianness);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
result = SerializeAdapter::deSerialize(&hasTransmissionMode, buffer, size, streamEndianness);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
result = SerializeAdapter::deSerialize(&transmissionMode, buffer, size, streamEndianness);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
result = SerializeAdapter::deSerialize(&hasClosureRequested, buffer, size, streamEndianness);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
result = SerializeAdapter::deSerialize(&closureRequested, buffer, size, streamEndianness);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
result = SerializeAdapter::deSerialize(&msgsToUsersTotalSize, buffer, size, streamEndianness);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
msgsToUserStartPtr = *buffer;
|
||||
*buffer += msgsToUsersTotalSize;
|
||||
*size += msgsToUsersTotalSize;
|
||||
|
||||
result = SerializeAdapter::deSerialize(&fsRequestsTotalSize, buffer, size, streamEndianness);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
fsRequestStartPtr = *buffer;
|
||||
*buffer += fsRequestsTotalSize;
|
||||
*size += fsRequestsTotalSize;
|
||||
return OK;
|
||||
}
|
||||
|
||||
size_t cfdp::PutRequest::getSerializedSize() const {
|
||||
// Entity ID LV (1 leading size byte) and the metadata only flag.
|
||||
size_t baseSize = 1 + destId.getSerializedSize() + 1;
|
||||
if (!metadataOnly) {
|
||||
baseSize += sourceName.getSerializedSize() + destName.getSerializedSize() + 4;
|
||||
}
|
||||
baseSize += sizeof(msgsToUsersTotalSize) + msgsToUsersTotalSize + sizeof(fsRequestsTotalSize) +
|
||||
fsRequestsTotalSize;
|
||||
return baseSize;
|
||||
}
|
||||
|
||||
void cfdp::PutRequest::setSourceAndDestName(cfdp::StringLv &sourceName_,
|
||||
cfdp::StringLv &destName_) {
|
||||
metadataOnly = false;
|
||||
this->sourceName = std::move(sourceName_);
|
||||
this->destName = std::move(destName_);
|
||||
}
|
||||
|
||||
const cfdp::StringLv &cfdp::PutRequest::getSourceName() const { return sourceName; }
|
||||
|
||||
const cfdp::StringLv &cfdp::PutRequest::getDestName() const { return destName; }
|
||||
|
||||
const cfdp::EntityId &cfdp::PutRequest::getDestId() const { return destId; }
|
||||
|
||||
void cfdp::PutRequest::setDestId(cfdp::EntityId id) { destId = std::move(id); }
|
||||
|
||||
void cfdp::PutRequest::setTransmissionMode(cfdp::TransmissionMode transmissionMode_) {
|
||||
this->transmissionMode = transmissionMode_;
|
||||
hasTransmissionMode = true;
|
||||
}
|
||||
|
||||
void cfdp::PutRequest::clearTransmissionMode() { hasTransmissionMode = false; }
|
||||
|
||||
void cfdp::PutRequest::clearClosureRequest() { hasClosureRequested = false; }
|
||||
|
||||
void cfdp::PutRequest::setClosureRequest(bool closureRequested_) {
|
||||
this->closureRequested = closureRequested_;
|
||||
hasClosureRequested = true;
|
||||
}
|
||||
|
||||
const uint8_t *cfdp::PutRequest::getMessagesToUser(size_t &totalSize) {
|
||||
totalSize = this->msgsToUsersTotalSize;
|
||||
return msgsToUserStartPtr;
|
||||
}
|
||||
|
||||
bool cfdp::PutRequest::getClosureRequested(bool &closureRequested_) const {
|
||||
if (hasClosureRequested) {
|
||||
closureRequested_ = this->closureRequested;
|
||||
}
|
||||
return hasClosureRequested;
|
||||
}
|
||||
|
||||
bool cfdp::PutRequest::getTransmissionMode(cfdp::TransmissionMode &mode) const {
|
||||
if (hasTransmissionMode) {
|
||||
mode = static_cast<cfdp::TransmissionMode>(this->transmissionMode);
|
||||
}
|
||||
return hasTransmissionMode;
|
||||
}
|
82
src/fsfw/cfdp/handler/PutRequest.h
Normal file
82
src/fsfw/cfdp/handler/PutRequest.h
Normal file
@ -0,0 +1,82 @@
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
#include "fsfw/cfdp/VarLenFields.h"
|
||||
#include "fsfw/cfdp/tlv/FilestoreRequestTlv.h"
|
||||
#include "fsfw/cfdp/tlv/MessageToUserTlv.h"
|
||||
|
||||
namespace cfdp {
|
||||
|
||||
class PutRequest : public SerializeIF {
|
||||
public:
|
||||
/**
|
||||
* Metadata only constructor.
|
||||
* @param destId
|
||||
* @param msgsToUser
|
||||
* @param msgsToUserTotalSize
|
||||
* @param fsRequests
|
||||
* @param fsRequestsSize
|
||||
*/
|
||||
PutRequest(EntityId destId, const uint8_t* msgsToUser, size_t msgsToUserTotalSize,
|
||||
const uint8_t* fsRequests, size_t fsRequestsSize);
|
||||
/**
|
||||
* Put request to initiate file transfers. By default, the transmission mode and closure requested
|
||||
* parameter are not present, thereby being derived from the remote configuration for a
|
||||
* particular destination ID.
|
||||
* @param destId
|
||||
* @param sourceName
|
||||
* @param destName
|
||||
*/
|
||||
PutRequest(EntityId destId, cfdp::StringLv& sourceName, cfdp::StringLv& destName);
|
||||
|
||||
/**
|
||||
* Default constructor for deserialization.
|
||||
*/
|
||||
PutRequest() = default;
|
||||
|
||||
[[nodiscard]] ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
||||
Endianness streamEndianness) const override;
|
||||
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
||||
Endianness streamEndianness) override;
|
||||
[[nodiscard]] size_t getSerializedSize() const override;
|
||||
void setSourceAndDestName(cfdp::StringLv& sourceName, cfdp::StringLv& destName);
|
||||
|
||||
[[nodiscard]] const cfdp::StringLv& getSourceName() const;
|
||||
[[nodiscard]] const cfdp::StringLv& getDestName() const;
|
||||
|
||||
void setTransmissionMode(cfdp::TransmissionMode transmissionMode);
|
||||
void clearTransmissionMode();
|
||||
void setClosureRequest(bool closureRequested);
|
||||
void clearClosureRequest();
|
||||
|
||||
const uint8_t* getMessagesToUser(size_t& msgSize);
|
||||
|
||||
[[nodiscard]] bool isMetadataOnly() const;
|
||||
|
||||
bool getTransmissionMode(TransmissionMode& mode) const;
|
||||
bool getClosureRequested(bool& closureRequested) const;
|
||||
|
||||
[[nodiscard]] const EntityId& getDestId() const;
|
||||
void setDestId(EntityId id);
|
||||
|
||||
private:
|
||||
EntityId destId;
|
||||
uint8_t metadataOnly = true;
|
||||
// Transaction parameters. Omitted if the put request is metadata only.
|
||||
cfdp::StringLv sourceName;
|
||||
|
||||
cfdp::StringLv destName;
|
||||
bool hasTransmissionMode = false;
|
||||
uint8_t transmissionMode = TransmissionMode::UNACKNOWLEDGED;
|
||||
bool hasClosureRequested = false;
|
||||
uint8_t closureRequested = false;
|
||||
// Metadata
|
||||
size_t msgsToUsersTotalSize = 0;
|
||||
const uint8_t* msgsToUserStartPtr = nullptr;
|
||||
size_t fsRequestsTotalSize = 0;
|
||||
const uint8_t* fsRequestStartPtr = nullptr;
|
||||
};
|
||||
|
||||
} // namespace cfdp
|
@ -16,7 +16,7 @@ class RemoteConfigTableIF {
|
||||
*/
|
||||
class OneRemoteConfigProvider : public RemoteConfigTableIF {
|
||||
public:
|
||||
explicit OneRemoteConfigProvider(RemoteEntityCfg cfg) : cfg(std::move(cfg)) {}
|
||||
explicit OneRemoteConfigProvider(RemoteEntityCfg& cfg) : cfg(cfg) {}
|
||||
|
||||
bool getRemoteCfg(const EntityId& remoteId, cfdp::RemoteEntityCfg** cfg_) override {
|
||||
if (remoteId != cfg.remoteId) {
|
||||
@ -27,7 +27,7 @@ class OneRemoteConfigProvider : public RemoteConfigTableIF {
|
||||
}
|
||||
|
||||
private:
|
||||
RemoteEntityCfg cfg;
|
||||
RemoteEntityCfg& cfg;
|
||||
};
|
||||
|
||||
} // namespace cfdp
|
||||
|
74
src/fsfw/cfdp/handler/ReservedMessageParser.cpp
Normal file
74
src/fsfw/cfdp/handler/ReservedMessageParser.cpp
Normal file
@ -0,0 +1,74 @@
|
||||
#include "ReservedMessageParser.h"
|
||||
|
||||
#include "fsfw/cfdp/CfdpMessage.h"
|
||||
#include "fsfw/cfdp/handler/PutRequest.h"
|
||||
#include "fsfw/cfdp/tlv/MessageToUserTlv.h"
|
||||
#include "fsfw/ipc/CommandMessage.h"
|
||||
#include "fsfw/ipc/QueueFactory.h"
|
||||
|
||||
using namespace returnvalue;
|
||||
|
||||
cfdp::ReservedMessageParser::ReservedMessageParser(StorageManagerIF& ipcStore,
|
||||
MessageQueueIF& msgQueue,
|
||||
MessageQueueId_t userDestination)
|
||||
: msgQueue(msgQueue), ipcStore(ipcStore), userDestination(userDestination) {}
|
||||
|
||||
ReturnValue_t cfdp::ReservedMessageParser::parse(const MessageToUserTlv* msgsToUserArray,
|
||||
size_t numMsgToUser) {
|
||||
ReturnValue_t result = returnvalue::OK;
|
||||
cfdp::StringLv sourceFileName;
|
||||
cfdp::StringLv destFileName;
|
||||
PutRequest putRequest;
|
||||
const uint8_t* currentPtr = nullptr;
|
||||
size_t deserSize = 0;
|
||||
bool needToSendPutRequest = false;
|
||||
for (size_t idx = 0; idx < numMsgToUser; idx++) {
|
||||
if (&msgsToUserArray[idx] == nullptr) {
|
||||
continue;
|
||||
}
|
||||
uint8_t messageType = 0;
|
||||
if (msgsToUserArray[idx].isReservedCfdpMessage(messageType, ¤tPtr, deserSize)) {
|
||||
if (messageType == static_cast<uint8_t>(ProxyOpMessageType::PUT_REQUEST)) {
|
||||
EntityId entityIdLv;
|
||||
result = entityIdLv.deSerializeFromLv(¤tPtr, &deserSize);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
putRequest.setDestId(entityIdLv);
|
||||
result =
|
||||
sourceFileName.deSerialize(¤tPtr, &deserSize, SerializeIF::Endianness::NETWORK);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
result =
|
||||
destFileName.deSerialize(¤tPtr, &deserSize, SerializeIF::Endianness::NETWORK);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
putRequest.setSourceAndDestName(sourceFileName, destFileName);
|
||||
needToSendPutRequest = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (needToSendPutRequest) {
|
||||
store_address_t storeId;
|
||||
uint8_t* dataPtr;
|
||||
result = ipcStore.getFreeElement(&storeId, putRequest.getSerializedSize(), &dataPtr);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
size_t serLen = 0;
|
||||
result = putRequest.serialize(&dataPtr, &serLen, putRequest.getSerializedSize(),
|
||||
SerializeIF::Endianness::MACHINE);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
CommandMessage msg;
|
||||
CfdpMessage::setPutRequest(&msg, storeId);
|
||||
result = msgQueue.sendMessage(userDestination, &msg);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return OK;
|
||||
}
|
27
src/fsfw/cfdp/handler/ReservedMessageParser.h
Normal file
27
src/fsfw/cfdp/handler/ReservedMessageParser.h
Normal file
@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include "fsfw/cfdp/tlv/MessageToUserTlv.h"
|
||||
#include "fsfw/ipc/MessageQueueIF.h"
|
||||
#include "fsfw/storagemanager/StorageManagerIF.h"
|
||||
|
||||
namespace cfdp {
|
||||
|
||||
/**
|
||||
* This class parses messages to user for special CFDP messages and converts them to appropriate
|
||||
* CFDP requests sent via the IPC store where applicable. It also provides an API to retrieve
|
||||
* custom messages which are not special CFDP messages from a provided bytestream.
|
||||
*/
|
||||
class ReservedMessageParser {
|
||||
public:
|
||||
ReservedMessageParser(StorageManagerIF& ipcStore, MessageQueueIF& msgQueue,
|
||||
MessageQueueId_t userDestination);
|
||||
|
||||
ReturnValue_t parse(const MessageToUserTlv* msgsToUserArray, size_t numMsgsToUser);
|
||||
|
||||
private:
|
||||
MessageQueueIF& msgQueue;
|
||||
StorageManagerIF& ipcStore;
|
||||
MessageQueueId_t userDestination;
|
||||
};
|
||||
|
||||
} // namespace cfdp
|
@ -1 +1,376 @@
|
||||
#include "SourceHandler.h"
|
||||
|
||||
#include <etl/crc32.h>
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "fsfw/cfdp/pdu/EofPduCreator.h"
|
||||
#include "fsfw/cfdp/pdu/FileDataCreator.h"
|
||||
#include "fsfw/cfdp/pdu/MetadataPduCreator.h"
|
||||
#include "fsfw/filesystem/HasFileSystemIF.h"
|
||||
#include "fsfw/globalfunctions/arrayprinter.h"
|
||||
#include "fsfw/objectmanager.h"
|
||||
#include "fsfw/serviceinterface.h"
|
||||
#include "fsfw/tasks/TaskFactory.h"
|
||||
#include "fsfw/tmtcservices/TmTcMessage.h"
|
||||
|
||||
using namespace returnvalue;
|
||||
|
||||
cfdp::SourceHandler::SourceHandler(SourceHandlerParams params, FsfwParams fsfwParams)
|
||||
: sourceParams(std::move(params)), fsfwParams(fsfwParams) {
|
||||
// The entity ID portion of the transaction ID will always remain fixed.
|
||||
transactionParams.id.entityId = sourceParams.cfg.localId;
|
||||
transactionParams.pduConf.sourceId = sourceParams.cfg.localId;
|
||||
if (sourceParams.seqCountProvider.bitWidth() == 8) {
|
||||
transactionParams.pduConf.seqNum.setWidth(cfdp::WidthInBytes::ONE_BYTE);
|
||||
} else if (sourceParams.seqCountProvider.bitWidth() == 16) {
|
||||
transactionParams.pduConf.seqNum.setWidth(cfdp::WidthInBytes::TWO_BYTES);
|
||||
} else if (sourceParams.seqCountProvider.bitWidth() == 32) {
|
||||
transactionParams.pduConf.seqNum.setWidth(cfdp::WidthInBytes::FOUR_BYTES);
|
||||
} else if (sourceParams.seqCountProvider.bitWidth() == 64) {
|
||||
transactionParams.pduConf.seqNum.setWidth(cfdp::WidthInBytes::EIGHT_BYTES);
|
||||
} else {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "cfdp::SourceHandler: Seq count provider bit width "
|
||||
<< sourceParams.seqCountProvider.bitWidth() << " not allowed" << std::endl;
|
||||
#else
|
||||
sif::printError("cfdp::SourceHandler: Seq count provider bit width %d not allowed\n",
|
||||
sourceParams.seqCountProvider.bitWidth());
|
||||
#endif
|
||||
// Yeah, what am I supposed to do here? Can't throw an exception in the FSFW..
|
||||
transactionParams.pduConf.seqNum.setWidth(cfdp::WidthInBytes::ONE_BYTE);
|
||||
}
|
||||
transactionParams.pduConf.seqNum.setValue(0);
|
||||
}
|
||||
|
||||
cfdp::SourceHandler::FsmResult& cfdp::SourceHandler::fsmNacked() {
|
||||
ReturnValue_t result;
|
||||
if (step == TransactionStep::IDLE) {
|
||||
step = TransactionStep::TRANSACTION_START;
|
||||
}
|
||||
if (step == TransactionStep::TRANSACTION_START) {
|
||||
sourceParams.user.transactionIndication(transactionParams.id);
|
||||
result = checksumGeneration();
|
||||
if (result != OK) {
|
||||
addError(result);
|
||||
}
|
||||
step = TransactionStep::SENDING_METADATA;
|
||||
}
|
||||
if (step == TransactionStep::SENDING_METADATA) {
|
||||
result = prepareAndSendMetadataPdu();
|
||||
if (result != OK) {
|
||||
addError(result);
|
||||
}
|
||||
fsmResult.callStatus = CallStatus::CALL_AGAIN;
|
||||
return fsmResult;
|
||||
}
|
||||
if (step == TransactionStep::SENDING_FILE_DATA) {
|
||||
bool noFdPdu = false;
|
||||
result = prepareAndSendNextFileDataPdu(noFdPdu);
|
||||
if (result == OK and !noFdPdu) {
|
||||
fsmResult.callStatus = CallStatus::CALL_AGAIN;
|
||||
return fsmResult;
|
||||
}
|
||||
}
|
||||
if (step == TransactionStep::SENDING_EOF) {
|
||||
result = prepareAndSendEofPdu();
|
||||
if (result != OK) {
|
||||
addError(result);
|
||||
}
|
||||
if (sourceParams.cfg.indicCfg.eofSentIndicRequired) {
|
||||
sourceParams.user.eofSentIndication(transactionParams.id);
|
||||
}
|
||||
if (transactionParams.closureRequested) {
|
||||
step = TransactionStep::WAIT_FOR_FINISH;
|
||||
fsmResult.callStatus = CallStatus::CALL_AFTER_DELAY;
|
||||
} else {
|
||||
step = TransactionStep::NOTICE_OF_COMPLETION;
|
||||
fsmResult.callStatus = CallStatus::CALL_AGAIN;
|
||||
}
|
||||
return fsmResult;
|
||||
}
|
||||
if (step == TransactionStep::WAIT_FOR_FINISH) {
|
||||
// TODO: In case this is a request with closure, wait for finish.
|
||||
// Done, issue notice of completion
|
||||
step = TransactionStep::NOTICE_OF_COMPLETION;
|
||||
}
|
||||
if (step == TransactionStep::NOTICE_OF_COMPLETION) {
|
||||
noticeOfCompletion();
|
||||
reset();
|
||||
}
|
||||
return fsmResult;
|
||||
}
|
||||
|
||||
const cfdp::SourceHandler::FsmResult& cfdp::SourceHandler::stateMachine() {
|
||||
fsmResult.packetsSent = 0;
|
||||
fsmResult.errors = 0;
|
||||
fsmResult.callStatus = CallStatus::DONE;
|
||||
if (state == cfdp::CfdpState::IDLE) {
|
||||
return fsmResult;
|
||||
}
|
||||
if (state == cfdp::CfdpState::BUSY_CLASS_1_NACKED) {
|
||||
return fsmNacked();
|
||||
}
|
||||
return fsmResult;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::SourceHandler::checksumGeneration() {
|
||||
if (transactionParams.fileSize.value() == 0) {
|
||||
// NULL checksum for empty file.
|
||||
transactionParams.crc = 0;
|
||||
return OK;
|
||||
}
|
||||
std::array<uint8_t, 1024> buf{};
|
||||
etl::crc32 crcCalc;
|
||||
uint64_t currentOffset = 0;
|
||||
FileOpParams params(transactionParams.sourceName.data(), transactionParams.fileSize.value());
|
||||
while (currentOffset < transactionParams.fileSize.value()) {
|
||||
uint64_t readLen;
|
||||
if (currentOffset + buf.size() > transactionParams.fileSize.value()) {
|
||||
readLen = transactionParams.fileSize.value() - currentOffset;
|
||||
} else {
|
||||
readLen = buf.size();
|
||||
}
|
||||
if (readLen > 0) {
|
||||
params.offset = currentOffset;
|
||||
params.size = readLen;
|
||||
auto result = sourceParams.user.vfs.readFromFile(params, buf.data(), buf.size());
|
||||
if (result != OK) {
|
||||
addError(result);
|
||||
return FAILED;
|
||||
}
|
||||
crcCalc.add(buf.begin(), buf.begin() + readLen);
|
||||
}
|
||||
currentOffset += readLen;
|
||||
}
|
||||
|
||||
transactionParams.crc = crcCalc.value();
|
||||
return OK;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::SourceHandler::transactionStart(PutRequest& putRequest, RemoteEntityCfg& cfg) {
|
||||
if (state != CfdpState::IDLE) {
|
||||
return SOURCE_TRANSACTION_PENDING;
|
||||
}
|
||||
if (cfg.remoteId != putRequest.getDestId()) {
|
||||
return WRONG_REMOTE_CFG_ENTITY_ID;
|
||||
}
|
||||
if (putRequest.getSourceName().getValueLen() == 0) {
|
||||
return SOURCE_NAME_EMPTY;
|
||||
}
|
||||
if (putRequest.getDestName().getValueLen() == 0) {
|
||||
return DEST_NAME_EMPTY;
|
||||
}
|
||||
const char* srcNamePtr = putRequest.getSourceName().getCString(transactionParams.sourceNameSize);
|
||||
const char* destNamePtr = putRequest.getDestName().getCString(transactionParams.destNameSize);
|
||||
std::strncpy(transactionParams.sourceName.data(), srcNamePtr, transactionParams.sourceNameSize);
|
||||
std::strncpy(transactionParams.destName.data(), destNamePtr, transactionParams.destNameSize);
|
||||
// Add 0 termination. The source and dest name size can not be larger than UINT8_MAX, so this
|
||||
// operation is safe.
|
||||
transactionParams.sourceName[transactionParams.sourceNameSize] = '\0';
|
||||
transactionParams.destName[transactionParams.destNameSize] = '\0';
|
||||
FilesystemParams params(transactionParams.sourceName.data());
|
||||
if (!sourceParams.user.vfs.fileExists(params)) {
|
||||
return FILE_DOES_NOT_EXIST;
|
||||
}
|
||||
if (cfg.maxFileSegmentLen > fileBuf.size() or cfg.maxFileSegmentLen == 0) {
|
||||
return FILE_SEGMENT_LEN_INVALID;
|
||||
}
|
||||
// If transmission mode is not set, use default transmission mode for the remote entity.
|
||||
if (not putRequest.getTransmissionMode(transactionParams.pduConf.mode)) {
|
||||
transactionParams.pduConf.mode = cfg.defaultTransmissionMode;
|
||||
}
|
||||
// If closure request field is not set, use default option for the remote entity.
|
||||
if (not putRequest.getClosureRequested(transactionParams.closureRequested)) {
|
||||
transactionParams.closureRequested = cfg.closureRequested;
|
||||
}
|
||||
const EntityId& destId = putRequest.getDestId();
|
||||
// The width of the source and destination ID must be the same. Use the larger ID value to
|
||||
// ensure the width is large enough for both IDs
|
||||
if (destId.getWidth() > transactionParams.pduConf.sourceId.getWidth()) {
|
||||
transactionParams.pduConf.destId = destId;
|
||||
transactionParams.pduConf.sourceId.setWidth(destId.getWidth());
|
||||
} else {
|
||||
transactionParams.pduConf.destId.setValueAndWidth(transactionParams.pduConf.sourceId.getWidth(),
|
||||
destId.getValue());
|
||||
}
|
||||
// Only used for PDU forwarding, file is sent to file receiver regularly here.
|
||||
transactionParams.pduConf.direction = Direction::TOWARDS_RECEIVER;
|
||||
transactionParams.pduConf.seqNum.setValue(sourceParams.seqCountProvider.getAndIncrement());
|
||||
transactionParams.id.seqNum = transactionParams.pduConf.seqNum;
|
||||
|
||||
if (transactionParams.pduConf.mode == TransmissionMode::ACKNOWLEDGED) {
|
||||
state = cfdp::CfdpState::BUSY_CLASS_2_ACKED;
|
||||
} else if (transactionParams.pduConf.mode == TransmissionMode::UNACKNOWLEDGED) {
|
||||
state = cfdp::CfdpState::BUSY_CLASS_1_NACKED;
|
||||
}
|
||||
step = TransactionStep::IDLE;
|
||||
uint64_t fileSize = 0;
|
||||
sourceParams.user.vfs.getFileSize(params, fileSize);
|
||||
transactionParams.pduConf.largeFile = false;
|
||||
if (fileSize > UINT32_MAX) {
|
||||
transactionParams.pduConf.largeFile = true;
|
||||
}
|
||||
if (fileSize == 0) {
|
||||
transactionParams.checksumType = ChecksumType::NULL_CHECKSUM;
|
||||
} else {
|
||||
transactionParams.checksumType = ChecksumType::CRC_32;
|
||||
}
|
||||
transactionParams.fileSize.setFileSize(fileSize, transactionParams.pduConf.largeFile);
|
||||
transactionParams.progress = 0;
|
||||
transactionParams.remoteCfg = cfg;
|
||||
return OK;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::SourceHandler::prepareAndSendMetadataPdu() {
|
||||
cfdp::StringLv sourceName(transactionParams.sourceName.data(), transactionParams.sourceNameSize);
|
||||
cfdp::StringLv destName(transactionParams.destName.data(), transactionParams.destNameSize);
|
||||
auto metadataInfo =
|
||||
MetadataGenericInfo(transactionParams.closureRequested, transactionParams.checksumType,
|
||||
transactionParams.fileSize);
|
||||
auto metadataPdu =
|
||||
MetadataPduCreator(transactionParams.pduConf, metadataInfo, sourceName, destName, nullptr, 0);
|
||||
ReturnValue_t result = sendGenericPdu(metadataPdu);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
// Advance FSM if everything works
|
||||
step = TransactionStep::SENDING_FILE_DATA;
|
||||
return OK;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::SourceHandler::prepareAndSendNextFileDataPdu(bool& noFileDataPdu) {
|
||||
cfdp::Fss offset(transactionParams.progress);
|
||||
uint64_t readLen;
|
||||
uint64_t fileSize = transactionParams.fileSize.value();
|
||||
noFileDataPdu = false;
|
||||
if (fileSize == 0) {
|
||||
// We are done, no need to send file data PDUs for an empty file.
|
||||
step = TransactionStep::SENDING_EOF;
|
||||
noFileDataPdu = true;
|
||||
return OK;
|
||||
}
|
||||
if (fileSize < transactionParams.remoteCfg.maxFileSegmentLen) {
|
||||
readLen = transactionParams.fileSize.value();
|
||||
} else {
|
||||
if (transactionParams.progress + transactionParams.remoteCfg.maxFileSegmentLen > fileSize) {
|
||||
readLen = fileSize - transactionParams.progress;
|
||||
} else {
|
||||
readLen = transactionParams.remoteCfg.maxFileSegmentLen;
|
||||
}
|
||||
}
|
||||
FileOpParams fileParams(transactionParams.sourceName.data(), readLen);
|
||||
fileParams.offset = transactionParams.progress;
|
||||
ReturnValue_t result =
|
||||
sourceParams.user.vfs.readFromFile(fileParams, fileBuf.data(), fileBuf.size());
|
||||
if (result != returnvalue::OK) {
|
||||
addError(result);
|
||||
return result;
|
||||
}
|
||||
auto fileDataInfo = FileDataInfo(offset, fileBuf.data(), readLen);
|
||||
auto fileDataPdu = FileDataCreator(transactionParams.pduConf, fileDataInfo);
|
||||
result = sendGenericPdu(fileDataPdu);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
transactionParams.progress += readLen;
|
||||
if (transactionParams.progress >= fileSize) {
|
||||
// Advance FSM after all file data PDUs were sent.
|
||||
step = TransactionStep::SENDING_EOF;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::SourceHandler::prepareAndSendEofPdu() {
|
||||
auto eofInfo =
|
||||
EofInfo(ConditionCode::NO_ERROR, transactionParams.crc, transactionParams.fileSize);
|
||||
auto eofPdu = EofPduCreator(transactionParams.pduConf, eofInfo);
|
||||
ReturnValue_t result = sendGenericPdu(eofPdu);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::SourceHandler::initialize() {
|
||||
if (fsfwParams.tmStore == nullptr) {
|
||||
fsfwParams.tmStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TM_STORE);
|
||||
if (fsfwParams.tmStore == nullptr) {
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
if (fsfwParams.tcStore == nullptr) {
|
||||
fsfwParams.tcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TC_STORE);
|
||||
if (fsfwParams.tcStore == nullptr) {
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
if (fsfwParams.msgQueue == nullptr) {
|
||||
return FAILED;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::SourceHandler::sendGenericPdu(const SerializeIF& pdu) {
|
||||
uint8_t* dataPtr;
|
||||
store_address_t storeId;
|
||||
ReturnValue_t result =
|
||||
fsfwParams.tmStore->getFreeElement(&storeId, pdu.getSerializedSize(), &dataPtr);
|
||||
if (result != OK) {
|
||||
addError(result);
|
||||
fsmResult.callStatus = CallStatus::CALL_AFTER_DELAY;
|
||||
if (result == StorageManagerIF::DATA_STORAGE_FULL) {
|
||||
return TM_STORE_FULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
size_t serializedLen = 0;
|
||||
result = pdu.serializeBe(dataPtr, serializedLen, pdu.getSerializedSize());
|
||||
if (result != OK) {
|
||||
addError(result);
|
||||
return result;
|
||||
}
|
||||
TmTcMessage tmMsg(storeId);
|
||||
result =
|
||||
fsfwParams.msgQueue->sendMessage(fsfwParams.packetDest.getReportReceptionQueue(), &tmMsg);
|
||||
if (result != OK) {
|
||||
fsmResult.callStatus = CallStatus::CALL_AFTER_DELAY;
|
||||
}
|
||||
if (result == MessageQueueIF::FULL) {
|
||||
return TARGET_MSG_QUEUE_FULL;
|
||||
} else if (result == OK) {
|
||||
fsmResult.packetsSent += 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::SourceHandler::noticeOfCompletion() {
|
||||
if (sourceParams.cfg.indicCfg.transactionFinishedIndicRequired) {
|
||||
cfdp::TransactionFinishedParams params(transactionParams.id, ConditionCode::NO_ERROR,
|
||||
FileDeliveryCode::DATA_COMPLETE,
|
||||
FileDeliveryStatus::RETAINED_IN_FILESTORE);
|
||||
sourceParams.user.transactionFinishedIndication(params);
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::SourceHandler::reset() {
|
||||
step = TransactionStep::IDLE;
|
||||
state = cfdp::CfdpState::IDLE;
|
||||
fsmResult.callStatus = CallStatus::DONE;
|
||||
transactionParams.reset();
|
||||
return OK;
|
||||
}
|
||||
cfdp::CfdpState cfdp::SourceHandler::getState() const { return state; }
|
||||
|
||||
cfdp::SourceHandler::TransactionStep cfdp::SourceHandler::getStep() const { return step; }
|
||||
|
||||
void cfdp::SourceHandler::addError(ReturnValue_t error) {
|
||||
if (fsmResult.errors < fsmResult.errorCodes.size()) {
|
||||
fsmResult.errorCodes[fsmResult.errors] = error;
|
||||
fsmResult.errors++;
|
||||
fsmResult.result = error;
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,110 @@
|
||||
#ifndef FSFW_CFDP_CFDPSOURCEHANDLER_H
|
||||
#define FSFW_CFDP_CFDPSOURCEHANDLER_H
|
||||
|
||||
class SourceHandler {};
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
#include "UserBase.h"
|
||||
#include "defs.h"
|
||||
#include "fsfw/cfdp/Fss.h"
|
||||
#include "fsfw/cfdp/handler/PutRequest.h"
|
||||
#include "fsfw/cfdp/handler/mib.h"
|
||||
#include "fsfw/events/EventReportingProxyIF.h"
|
||||
#include "fsfw/storagemanager/StorageManagerIF.h"
|
||||
#include "fsfw/tmtcservices/AcceptsTelemetryIF.h"
|
||||
#include "fsfw/util/ProvidesSeqCountIF.h"
|
||||
|
||||
namespace cfdp {
|
||||
|
||||
struct SourceHandlerParams {
|
||||
SourceHandlerParams(LocalEntityCfg cfg, UserBase& user, ProvidesSeqCountIF& seqCountProvider)
|
||||
: cfg(std::move(cfg)), user(user), seqCountProvider(seqCountProvider) {}
|
||||
|
||||
LocalEntityCfg cfg;
|
||||
UserBase& user;
|
||||
ProvidesSeqCountIF& seqCountProvider;
|
||||
};
|
||||
|
||||
class SourceHandler {
|
||||
public:
|
||||
enum class TransactionStep : uint8_t {
|
||||
IDLE = 0,
|
||||
TRANSACTION_START = 1,
|
||||
SENDING_METADATA = 3,
|
||||
SENDING_FILE_DATA = 4,
|
||||
SENDING_EOF = 5,
|
||||
WAIT_FOR_ACK = 6,
|
||||
WAIT_FOR_FINISH = 7,
|
||||
NOTICE_OF_COMPLETION = 8
|
||||
};
|
||||
struct FsmResult {
|
||||
public:
|
||||
ReturnValue_t result = returnvalue::OK;
|
||||
CallStatus callStatus = CallStatus::CALL_AFTER_DELAY;
|
||||
CfdpState state = CfdpState::IDLE;
|
||||
uint32_t packetsSent = 0;
|
||||
uint8_t errors = 0;
|
||||
std::array<ReturnValue_t, 3> errorCodes = {};
|
||||
};
|
||||
|
||||
SourceHandler(SourceHandlerParams params, FsfwParams fsfwParams);
|
||||
|
||||
[[nodiscard]] CfdpState getState() const;
|
||||
[[nodiscard]] TransactionStep getStep() const;
|
||||
|
||||
/**
|
||||
* Pass a put request to the source handler, which might initiate a CFDP transaction and start
|
||||
* the state machine
|
||||
* @return
|
||||
*/
|
||||
ReturnValue_t transactionStart(PutRequest& putRequest, RemoteEntityCfg& cfg);
|
||||
const FsmResult& stateMachine();
|
||||
|
||||
ReturnValue_t initialize();
|
||||
|
||||
private:
|
||||
struct TransactionParams {
|
||||
uint32_t crc{};
|
||||
std::array<char, UINT8_MAX + 1> sourceName{};
|
||||
size_t sourceNameSize = 0;
|
||||
std::array<char, UINT8_MAX + 1> destName{};
|
||||
size_t destNameSize = 0;
|
||||
cfdp::Fss fileSize;
|
||||
size_t progress = 0;
|
||||
bool closureRequested = false;
|
||||
ChecksumType checksumType = ChecksumType::NULL_CHECKSUM;
|
||||
RemoteEntityCfg remoteCfg;
|
||||
PduConfig pduConf;
|
||||
cfdp::TransactionId id{};
|
||||
|
||||
void reset() {
|
||||
sourceNameSize = 0;
|
||||
destNameSize = 0;
|
||||
fileSize.setFileSize(0, false);
|
||||
progress = 0;
|
||||
closureRequested = false;
|
||||
}
|
||||
} transactionParams;
|
||||
|
||||
cfdp::CfdpState state = cfdp::CfdpState::IDLE;
|
||||
TransactionStep step = TransactionStep::IDLE;
|
||||
std::array<uint8_t, 4096> fileBuf{};
|
||||
SourceHandlerParams sourceParams;
|
||||
cfdp::FsfwParams fsfwParams;
|
||||
FsmResult fsmResult;
|
||||
|
||||
FsmResult& fsmNacked();
|
||||
ReturnValue_t checksumGeneration();
|
||||
ReturnValue_t prepareAndSendMetadataPdu();
|
||||
ReturnValue_t prepareAndSendNextFileDataPdu(bool& noFileDataPdu);
|
||||
ReturnValue_t prepareAndSendEofPdu();
|
||||
ReturnValue_t noticeOfCompletion();
|
||||
ReturnValue_t reset();
|
||||
|
||||
[[nodiscard]] ReturnValue_t sendGenericPdu(const SerializeIF& pdu);
|
||||
void addError(ReturnValue_t error);
|
||||
};
|
||||
|
||||
} // namespace cfdp
|
||||
|
||||
#endif // FSFW_CFDP_CFDPSOURCEHANDLER_H
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "StatusReportIF.h"
|
||||
#include "fsfw/cfdp/Fss.h"
|
||||
#include "fsfw/cfdp/VarLenFields.h"
|
||||
#include "fsfw/cfdp/tlv/FilestoreResponseTlv.h"
|
||||
#include "fsfw/cfdp/tlv/MessageToUserTlv.h"
|
||||
@ -27,14 +28,14 @@ struct TransactionFinishedParams {
|
||||
};
|
||||
|
||||
struct MetadataRecvdParams {
|
||||
MetadataRecvdParams(const TransactionId& id, const EntityId& sourceId)
|
||||
: id(id), sourceId(sourceId) {}
|
||||
MetadataRecvdParams(const TransactionId& id, const EntityId& sourceId, Fss fileSize)
|
||||
: id(id), sourceId(sourceId), fileSize(std::move(fileSize)) {}
|
||||
const TransactionId& id;
|
||||
const EntityId& sourceId;
|
||||
uint64_t fileSize = 0;
|
||||
Fss fileSize{};
|
||||
const char* sourceFileName = "";
|
||||
const char* destFileName = "";
|
||||
size_t msgsToUserLen = 0;
|
||||
size_t numberOfMsgsToUser = 0;
|
||||
const MessageToUserTlv* msgsToUserArray = nullptr;
|
||||
};
|
||||
|
||||
@ -65,6 +66,7 @@ struct FileSegmentRecvdParams {
|
||||
*/
|
||||
class UserBase {
|
||||
friend class DestHandler;
|
||||
friend class SourceHandler;
|
||||
|
||||
public:
|
||||
explicit UserBase(HasFileSystemIF& vfs);
|
||||
|
@ -1,9 +1,76 @@
|
||||
#ifndef FSFW_CFDP_HANDLER_DEFS_H
|
||||
#define FSFW_CFDP_HANDLER_DEFS_H
|
||||
|
||||
#include <etl/list.h>
|
||||
|
||||
#include "fsfw/storagemanager/StorageManagerIF.h"
|
||||
#include "fsfw/storagemanager/storeAddress.h"
|
||||
#include "fsfw/tmtcservices/AcceptsTelemetryIF.h"
|
||||
|
||||
namespace cfdp {
|
||||
|
||||
enum class CfdpStates { IDLE, BUSY_CLASS_1_NACKED, BUSY_CLASS_2_ACKED, SUSPENDED };
|
||||
enum class CfdpState { IDLE, BUSY_CLASS_1_NACKED, BUSY_CLASS_2_ACKED, SUSPENDED };
|
||||
|
||||
}
|
||||
static constexpr uint8_t SSID = SUBSYSTEM_ID::CFDP;
|
||||
static constexpr uint8_t CID = CLASS_ID::CFDP_HANDLER;
|
||||
|
||||
struct PacketInfo {
|
||||
PacketInfo(PduType type, store_address_t storeId,
|
||||
std::optional<FileDirective> directive = std::nullopt)
|
||||
: pduType(type), directiveType(directive), storeId(storeId) {}
|
||||
|
||||
PduType pduType = PduType::FILE_DATA;
|
||||
std::optional<FileDirective> directiveType = FileDirective::INVALID_DIRECTIVE;
|
||||
store_address_t storeId = store_address_t::invalid();
|
||||
PacketInfo() = default;
|
||||
};
|
||||
|
||||
struct FsfwParams {
|
||||
FsfwParams(AcceptsTelemetryIF& packetDest, MessageQueueIF* msgQueue,
|
||||
EventReportingProxyIF* eventReporter, StorageManagerIF& tcStore,
|
||||
StorageManagerIF& tmStore)
|
||||
: FsfwParams(packetDest, msgQueue, eventReporter) {
|
||||
this->tcStore = &tcStore;
|
||||
this->tmStore = &tmStore;
|
||||
}
|
||||
|
||||
FsfwParams(AcceptsTelemetryIF& packetDest, MessageQueueIF* msgQueue,
|
||||
EventReportingProxyIF* eventReporter)
|
||||
: packetDest(packetDest), msgQueue(msgQueue), eventReporter(eventReporter) {}
|
||||
AcceptsTelemetryIF& packetDest;
|
||||
MessageQueueIF* msgQueue;
|
||||
EventReportingProxyIF* eventReporter = nullptr;
|
||||
StorageManagerIF* tcStore = nullptr;
|
||||
StorageManagerIF* tmStore = nullptr;
|
||||
};
|
||||
|
||||
template <size_t SIZE>
|
||||
using PacketInfoList = etl::list<PacketInfo, SIZE>;
|
||||
using PacketInfoListBase = etl::ilist<PacketInfo>;
|
||||
|
||||
enum class CallStatus { DONE, CALL_AFTER_DELAY, CALL_AGAIN };
|
||||
|
||||
namespace events {
|
||||
|
||||
static constexpr Event STORE_ERROR = event::makeEvent(SSID, 0, severity::LOW);
|
||||
static constexpr Event MSG_QUEUE_ERROR = event::makeEvent(SSID, 1, severity::LOW);
|
||||
static constexpr Event SERIALIZATION_ERROR = event::makeEvent(SSID, 2, severity::LOW);
|
||||
static constexpr Event FILESTORE_ERROR = event::makeEvent(SSID, 3, severity::LOW);
|
||||
//! [EXPORT] : [COMMENT] P1: Transaction step ID, P2: 0 for source file name, 1 for dest file name
|
||||
static constexpr Event FILENAME_TOO_LARGE_ERROR = event::makeEvent(SSID, 4, severity::LOW);
|
||||
//! [EXPORT] : [COMMENT] CFDP request handling failed. P2: Returncode.
|
||||
static constexpr Event HANDLING_CFDP_REQUEST_FAILED = event::makeEvent(SSID, 5, severity::LOW);
|
||||
|
||||
} // namespace events
|
||||
|
||||
static constexpr ReturnValue_t SOURCE_TRANSACTION_PENDING = returnvalue::makeCode(CID, 0);
|
||||
static constexpr ReturnValue_t FILE_DOES_NOT_EXIST = returnvalue::makeCode(CID, 1);
|
||||
static constexpr ReturnValue_t FILE_SEGMENT_LEN_INVALID = returnvalue::makeCode(CID, 2);
|
||||
static constexpr ReturnValue_t SOURCE_NAME_EMPTY = returnvalue::makeCode(CID, 3);
|
||||
static constexpr ReturnValue_t DEST_NAME_EMPTY = returnvalue::makeCode(CID, 4);
|
||||
static constexpr ReturnValue_t WRONG_REMOTE_CFG_ENTITY_ID = returnvalue::makeCode(CID, 5);
|
||||
static constexpr ReturnValue_t TARGET_MSG_QUEUE_FULL = returnvalue::makeCode(CID, 6);
|
||||
static constexpr ReturnValue_t TM_STORE_FULL = returnvalue::makeCode(CID, 7);
|
||||
|
||||
} // namespace cfdp
|
||||
#endif // FSFW_CFDP_HANDLER_DEFS_H
|
||||
|
@ -27,14 +27,15 @@ struct LocalEntityCfg {
|
||||
};
|
||||
|
||||
struct RemoteEntityCfg {
|
||||
RemoteEntityCfg() = default;
|
||||
explicit RemoteEntityCfg(EntityId id) : remoteId(std::move(id)) {}
|
||||
EntityId remoteId;
|
||||
size_t maxFileSegmentLen = 2048;
|
||||
size_t maxFileSegmentLen = 1024;
|
||||
bool closureRequested = false;
|
||||
bool crcOnTransmission = false;
|
||||
TransmissionMode defaultTransmissionMode = TransmissionMode::UNACKNOWLEDGED;
|
||||
ChecksumType defaultChecksum = ChecksumType::NULL_CHECKSUM;
|
||||
const uint8_t version = CFDP_VERSION_2;
|
||||
uint8_t version = CFDP_VERSION_2;
|
||||
};
|
||||
|
||||
} // namespace cfdp
|
||||
|
@ -17,7 +17,7 @@ target_sources(
|
||||
FinishedInfo.cpp
|
||||
FinishedPduCreator.cpp
|
||||
FinishedPduReader.cpp
|
||||
MetadataInfo.cpp
|
||||
MetadataGenericInfo.cpp
|
||||
MetadataPduCreator.cpp
|
||||
MetadataPduReader.cpp
|
||||
KeepAlivePduCreator.cpp
|
||||
|
@ -1,8 +1,13 @@
|
||||
#include "EofInfo.h"
|
||||
|
||||
EofInfo::EofInfo(cfdp::ConditionCode conditionCode, uint32_t checksum, cfdp::FileSize fileSize,
|
||||
#include <utility>
|
||||
|
||||
EofInfo::EofInfo(cfdp::ConditionCode conditionCode, uint32_t checksum, cfdp::Fss fileSize,
|
||||
EntityIdTlv* faultLoc)
|
||||
: conditionCode(conditionCode), checksum(checksum), fileSize(fileSize), faultLoc(faultLoc) {}
|
||||
: conditionCode(conditionCode),
|
||||
checksum(checksum),
|
||||
fileSize(std::move(fileSize)),
|
||||
faultLoc(faultLoc) {}
|
||||
|
||||
EofInfo::EofInfo(EntityIdTlv* faultLoc)
|
||||
: conditionCode(cfdp::ConditionCode::NO_CONDITION_FIELD),
|
||||
@ -16,15 +21,15 @@ cfdp::ConditionCode EofInfo::getConditionCode() const { return conditionCode; }
|
||||
|
||||
EntityIdTlv* EofInfo::getFaultLoc() const { return faultLoc; }
|
||||
|
||||
cfdp::FileSize& EofInfo::getFileSize() { return fileSize; }
|
||||
cfdp::Fss& EofInfo::getFileSize() { return fileSize; }
|
||||
|
||||
void EofInfo::setChecksum(uint32_t checksum) { this->checksum = checksum; }
|
||||
void EofInfo::setChecksum(uint32_t checksum_) { this->checksum = checksum_; }
|
||||
|
||||
void EofInfo::setConditionCode(cfdp::ConditionCode conditionCode) {
|
||||
this->conditionCode = conditionCode;
|
||||
void EofInfo::setConditionCode(cfdp::ConditionCode conditionCode_) {
|
||||
this->conditionCode = conditionCode_;
|
||||
}
|
||||
|
||||
void EofInfo::setFaultLoc(EntityIdTlv* faultLoc) { this->faultLoc = faultLoc; }
|
||||
void EofInfo::setFaultLoc(EntityIdTlv* faultLoc_) { this->faultLoc = faultLoc_; }
|
||||
|
||||
size_t EofInfo::getSerializedSize(bool fssLarge) {
|
||||
// Condition code + spare + 4 byte checksum
|
||||
@ -42,6 +47,6 @@ size_t EofInfo::getSerializedSize(bool fssLarge) {
|
||||
return size;
|
||||
}
|
||||
|
||||
ReturnValue_t EofInfo::setFileSize(size_t fileSize, bool isLarge) {
|
||||
return this->fileSize.setFileSize(fileSize, isLarge);
|
||||
ReturnValue_t EofInfo::setFileSize(size_t fileSize_, bool isLarge) {
|
||||
return this->fileSize.setFileSize(fileSize_, isLarge);
|
||||
}
|
||||
|
@ -1,14 +1,14 @@
|
||||
#ifndef FSFW_SRC_FSFW_CFDP_PDU_EOFINFO_H_
|
||||
#define FSFW_SRC_FSFW_CFDP_PDU_EOFINFO_H_
|
||||
|
||||
#include "../FileSize.h"
|
||||
#include "../Fss.h"
|
||||
#include "../definitions.h"
|
||||
#include "fsfw/cfdp/tlv/EntityIdTlv.h"
|
||||
|
||||
struct EofInfo {
|
||||
public:
|
||||
explicit EofInfo(EntityIdTlv* faultLoc = nullptr);
|
||||
EofInfo(cfdp::ConditionCode conditionCode, uint32_t checksum, cfdp::FileSize fileSize,
|
||||
EofInfo(cfdp::ConditionCode conditionCode, uint32_t checksum, cfdp::Fss fileSize,
|
||||
EntityIdTlv* faultLoc = nullptr);
|
||||
|
||||
size_t getSerializedSize(bool fssLarge = false);
|
||||
@ -17,7 +17,7 @@ struct EofInfo {
|
||||
[[nodiscard]] cfdp::ConditionCode getConditionCode() const;
|
||||
|
||||
[[nodiscard]] EntityIdTlv* getFaultLoc() const;
|
||||
cfdp::FileSize& getFileSize();
|
||||
cfdp::Fss& getFileSize();
|
||||
void setChecksum(uint32_t checksum);
|
||||
void setConditionCode(cfdp::ConditionCode conditionCode);
|
||||
void setFaultLoc(EntityIdTlv* faultLoc);
|
||||
@ -26,7 +26,7 @@ struct EofInfo {
|
||||
private:
|
||||
cfdp::ConditionCode conditionCode;
|
||||
uint32_t checksum;
|
||||
cfdp::FileSize fileSize;
|
||||
cfdp::Fss fileSize;
|
||||
EntityIdTlv* faultLoc = nullptr;
|
||||
};
|
||||
|
||||
|
@ -37,7 +37,7 @@ ReturnValue_t FileDataCreator::serialize(uint8_t** buffer, size_t* size, size_t
|
||||
*buffer += segmentMetadataLen;
|
||||
*size += segmentMetadataLen;
|
||||
}
|
||||
cfdp::FileSize& offset = info.getOffset();
|
||||
cfdp::Fss& offset = info.getOffset();
|
||||
result = offset.serialize(this->getLargeFileFlag(), buffer, size, maxSize, streamEndianness);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
|
@ -1,9 +1,9 @@
|
||||
#include "FileDataInfo.h"
|
||||
|
||||
FileDataInfo::FileDataInfo(cfdp::FileSize &offset, const uint8_t *fileData, size_t fileSize)
|
||||
: offset(offset), fileData(fileData), fileSize(fileSize) {}
|
||||
#include <utility>
|
||||
|
||||
FileDataInfo::FileDataInfo(cfdp::FileSize &offset) : offset(offset) {}
|
||||
FileDataInfo::FileDataInfo(cfdp::Fss offset, const uint8_t *fileData, size_t fileSize)
|
||||
: offset(std::move(offset)), fileData(fileData), fileSize(fileSize) {}
|
||||
|
||||
void FileDataInfo::setSegmentMetadataFlag(bool enable) {
|
||||
if (enable) {
|
||||
@ -71,7 +71,7 @@ const uint8_t *FileDataInfo::getSegmentMetadata(size_t *segmentMetadataLen_) {
|
||||
return segmentMetadata;
|
||||
}
|
||||
|
||||
cfdp::FileSize &FileDataInfo::getOffset() { return offset; }
|
||||
cfdp::Fss &FileDataInfo::getOffset() { return offset; }
|
||||
|
||||
void FileDataInfo::setRecordContinuationState(cfdp::RecordContinuationState recContState) {
|
||||
this->recContState = recContState;
|
||||
|
@ -1,17 +1,17 @@
|
||||
#ifndef FSFW_SRC_FSFW_CFDP_PDU_FILEDATAINFO_H_
|
||||
#define FSFW_SRC_FSFW_CFDP_PDU_FILEDATAINFO_H_
|
||||
|
||||
#include <fsfw/cfdp/FileSize.h>
|
||||
#include <fsfw/cfdp/Fss.h>
|
||||
#include <fsfw/cfdp/definitions.h>
|
||||
|
||||
class FileDataInfo {
|
||||
public:
|
||||
explicit FileDataInfo(cfdp::FileSize& offset);
|
||||
FileDataInfo(cfdp::FileSize& offset, const uint8_t* fileData, size_t fileSize);
|
||||
FileDataInfo() = default;
|
||||
FileDataInfo(cfdp::Fss offset, const uint8_t* fileData, size_t fileSize);
|
||||
|
||||
[[nodiscard]] size_t getSerializedSize(bool largeFile = false) const;
|
||||
|
||||
cfdp::FileSize& getOffset();
|
||||
cfdp::Fss& getOffset();
|
||||
const uint8_t* getFileData(size_t* fileSize = nullptr) const;
|
||||
void setFileData(const uint8_t* fileData, size_t fileSize);
|
||||
|
||||
@ -33,7 +33,7 @@ class FileDataInfo {
|
||||
private:
|
||||
cfdp::SegmentMetadataFlag segmentMetadataFlag = cfdp::SegmentMetadataFlag::NOT_PRESENT;
|
||||
cfdp::SegmentationControl segCtrl = cfdp::SegmentationControl::NO_RECORD_BOUNDARIES_PRESERVATION;
|
||||
cfdp::FileSize& offset;
|
||||
cfdp::Fss offset;
|
||||
const uint8_t* fileData = nullptr;
|
||||
size_t fileSize = 0;
|
||||
cfdp::RecordContinuationState recContState = cfdp::RecordContinuationState::NO_START_NO_END;
|
||||
|
@ -17,7 +17,7 @@ ReturnValue_t FinishPduCreator::serialize(uint8_t **buffer, size_t *size, size_t
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
if (*size + 1 >= maxSize) {
|
||||
if (*size + 1 > maxSize) {
|
||||
return SerializeIF::BUFFER_TOO_SHORT;
|
||||
}
|
||||
**buffer = finishInfo.getConditionCode() << 4 | finishInfo.getDeliveryCode() << 2 |
|
||||
|
@ -24,8 +24,8 @@ ReturnValue_t HeaderCreator::serialize(uint8_t **buffer, size_t *size, size_t ma
|
||||
*buffer += 1;
|
||||
**buffer = pduDataFieldLen & 0x00ff;
|
||||
*buffer += 1;
|
||||
**buffer = segmentationCtrl << 7 | pduConf.sourceId.getWidth() << 4 | segmentMetadataFlag << 3 |
|
||||
pduConf.seqNum.getWidth();
|
||||
**buffer = segmentationCtrl << 7 | ((pduConf.sourceId.getWidth() - 1) << 4) |
|
||||
segmentMetadataFlag << 3 | (pduConf.seqNum.getWidth() - 1);
|
||||
*buffer += 1;
|
||||
*size += 4;
|
||||
ReturnValue_t result = pduConf.sourceId.serialize(buffer, size, maxSize, streamEndianness);
|
||||
|
@ -78,11 +78,11 @@ cfdp::SegmentationControl PduHeaderReader::getSegmentationControl() const {
|
||||
}
|
||||
|
||||
cfdp::WidthInBytes PduHeaderReader::getLenEntityIds() const {
|
||||
return static_cast<cfdp::WidthInBytes>((pointers.fixedHeader->fourthByte >> 4) & 0x07);
|
||||
return static_cast<cfdp::WidthInBytes>(((pointers.fixedHeader->fourthByte >> 4) & 0b111) + 1);
|
||||
}
|
||||
|
||||
cfdp::WidthInBytes PduHeaderReader::getLenSeqNum() const {
|
||||
return static_cast<cfdp::WidthInBytes>(pointers.fixedHeader->fourthByte & 0x07);
|
||||
return static_cast<cfdp::WidthInBytes>((pointers.fixedHeader->fourthByte & 0b111) + 1);
|
||||
}
|
||||
|
||||
cfdp::SegmentMetadataFlag PduHeaderReader::getSegmentMetadataFlag() const {
|
||||
@ -103,11 +103,11 @@ void PduHeaderReader::getTransactionSeqNum(cfdp::TransactionSeqNum &seqNum) cons
|
||||
}
|
||||
|
||||
void PduHeaderReader::assignVarLenField(cfdp::VarLenField *field, cfdp::WidthInBytes width,
|
||||
void *sourcePtr) const {
|
||||
void *sourcePtr) {
|
||||
switch (width) {
|
||||
case (cfdp::WidthInBytes::ONE_BYTE): {
|
||||
auto *fieldTyped = static_cast<uint8_t *>(sourcePtr);
|
||||
field->setValue(width, *fieldTyped);
|
||||
field->setValueAndWidth(width, *fieldTyped);
|
||||
break;
|
||||
}
|
||||
case (cfdp::WidthInBytes::TWO_BYTES): {
|
||||
@ -115,7 +115,7 @@ void PduHeaderReader::assignVarLenField(cfdp::VarLenField *field, cfdp::WidthInB
|
||||
size_t deserSize = 0;
|
||||
SerializeAdapter::deSerialize(&fieldTyped, static_cast<uint8_t *>(sourcePtr), &deserSize,
|
||||
SerializeIF::Endianness::NETWORK);
|
||||
field->setValue(width, fieldTyped);
|
||||
field->setValueAndWidth(width, fieldTyped);
|
||||
break;
|
||||
}
|
||||
case (cfdp::WidthInBytes::FOUR_BYTES): {
|
||||
@ -123,7 +123,15 @@ void PduHeaderReader::assignVarLenField(cfdp::VarLenField *field, cfdp::WidthInB
|
||||
size_t deserSize = 0;
|
||||
SerializeAdapter::deSerialize(&fieldTyped, static_cast<uint8_t *>(sourcePtr), &deserSize,
|
||||
SerializeIF::Endianness::NETWORK);
|
||||
field->setValue(width, fieldTyped);
|
||||
field->setValueAndWidth(width, fieldTyped);
|
||||
break;
|
||||
}
|
||||
case (cfdp::WidthInBytes::EIGHT_BYTES): {
|
||||
uint64_t fieldTyped = 0;
|
||||
size_t deserSize = 0;
|
||||
SerializeAdapter::deSerialize(&fieldTyped, static_cast<uint8_t *>(sourcePtr), &deserSize,
|
||||
SerializeIF::Endianness::NETWORK);
|
||||
field->setValueAndWidth(width, fieldTyped);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "KeepAlivePduCreator.h"
|
||||
|
||||
KeepAlivePduCreator::KeepAlivePduCreator(PduConfig &conf, cfdp::FileSize &progress)
|
||||
KeepAlivePduCreator::KeepAlivePduCreator(PduConfig &conf, cfdp::Fss &progress)
|
||||
: FileDirectiveCreator(conf, cfdp::FileDirective::KEEP_ALIVE, 4), progress(progress) {
|
||||
updateDirectiveFieldLen();
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
#ifndef FSFW_CFDP_PDU_KEEPALIVEPDUSERIALIZER_H_
|
||||
#define FSFW_CFDP_PDU_KEEPALIVEPDUSERIALIZER_H_
|
||||
|
||||
#include "fsfw/cfdp/FileSize.h"
|
||||
#include "fsfw/cfdp/Fss.h"
|
||||
#include "fsfw/cfdp/pdu/FileDirectiveCreator.h"
|
||||
|
||||
class KeepAlivePduCreator : public FileDirectiveCreator {
|
||||
public:
|
||||
KeepAlivePduCreator(PduConfig& conf, cfdp::FileSize& progress);
|
||||
KeepAlivePduCreator(PduConfig& conf, cfdp::Fss& progress);
|
||||
|
||||
void updateDirectiveFieldLen();
|
||||
|
||||
@ -16,7 +16,7 @@ class KeepAlivePduCreator : public FileDirectiveCreator {
|
||||
Endianness streamEndianness) const override;
|
||||
|
||||
private:
|
||||
cfdp::FileSize& progress;
|
||||
cfdp::Fss& progress;
|
||||
};
|
||||
|
||||
#endif /* FSFW_CFDP_PDU_KEEPALIVEPDUSERIALIZER_H_ */
|
||||
|
@ -1,7 +1,6 @@
|
||||
#include "KeepAlivePduReader.h"
|
||||
|
||||
KeepAlivePduReader::KeepAlivePduReader(const uint8_t* pduBuf, size_t maxSize,
|
||||
cfdp::FileSize& progress)
|
||||
KeepAlivePduReader::KeepAlivePduReader(const uint8_t* pduBuf, size_t maxSize, cfdp::Fss& progress)
|
||||
: FileDirectiveReader(pduBuf, maxSize), progress(progress) {}
|
||||
|
||||
ReturnValue_t KeepAlivePduReader::parseData() {
|
||||
@ -15,4 +14,4 @@ ReturnValue_t KeepAlivePduReader::parseData() {
|
||||
return progress.deSerialize(&buffer, &remLen, getEndianness());
|
||||
}
|
||||
|
||||
cfdp::FileSize& KeepAlivePduReader::getProgress() { return progress; }
|
||||
cfdp::Fss& KeepAlivePduReader::getProgress() { return progress; }
|
||||
|
@ -1,19 +1,19 @@
|
||||
#ifndef FSFW_CFDP_PDU_KEEPALIVEREADER_H_
|
||||
#define FSFW_CFDP_PDU_KEEPALIVEREADER_H_
|
||||
|
||||
#include "fsfw/cfdp/FileSize.h"
|
||||
#include "fsfw/cfdp/Fss.h"
|
||||
#include "fsfw/cfdp/pdu/FileDirectiveReader.h"
|
||||
|
||||
class KeepAlivePduReader : public FileDirectiveReader {
|
||||
public:
|
||||
KeepAlivePduReader(const uint8_t* pduBuf, size_t maxSize, cfdp::FileSize& progress);
|
||||
KeepAlivePduReader(const uint8_t* pduBuf, size_t maxSize, cfdp::Fss& progress);
|
||||
|
||||
ReturnValue_t parseData() override;
|
||||
|
||||
cfdp::FileSize& getProgress();
|
||||
cfdp::Fss& getProgress();
|
||||
|
||||
private:
|
||||
cfdp::FileSize& progress;
|
||||
cfdp::Fss& progress;
|
||||
};
|
||||
|
||||
#endif /* FSFW_CFDP_PDU_KEEPALIVEPDUREADER_H_ */
|
||||
|
35
src/fsfw/cfdp/pdu/MetadataGenericInfo.cpp
Normal file
35
src/fsfw/cfdp/pdu/MetadataGenericInfo.cpp
Normal file
@ -0,0 +1,35 @@
|
||||
#include "MetadataGenericInfo.h"
|
||||
|
||||
MetadataGenericInfo::MetadataGenericInfo(bool closureRequested, cfdp::ChecksumType checksumType,
|
||||
cfdp::Fss fileSize)
|
||||
: MetadataGenericInfo(std::move(fileSize)) {
|
||||
this->closureRequested = closureRequested;
|
||||
this->checksumType = checksumType;
|
||||
}
|
||||
|
||||
MetadataGenericInfo::MetadataGenericInfo(cfdp::Fss fileSize) : fileSize(std::move(fileSize)) {}
|
||||
|
||||
cfdp::ChecksumType MetadataGenericInfo::getChecksumType() const { return checksumType; }
|
||||
|
||||
void MetadataGenericInfo::setChecksumType(cfdp::ChecksumType checksumType_) {
|
||||
checksumType = checksumType_;
|
||||
}
|
||||
|
||||
bool MetadataGenericInfo::isClosureRequested() const { return closureRequested; }
|
||||
|
||||
void MetadataGenericInfo::setClosureRequested(bool closureRequested_) {
|
||||
closureRequested = closureRequested_;
|
||||
}
|
||||
|
||||
const cfdp::Fss& MetadataGenericInfo::getFileSize() const { return fileSize; }
|
||||
|
||||
size_t MetadataGenericInfo::getSerializedSize(bool fssLarge) {
|
||||
// 1 byte + minimal FSS 4 bytes
|
||||
size_t size = 5;
|
||||
if (fssLarge) {
|
||||
size += 4;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
cfdp::Fss& MetadataGenericInfo::getMutFileSize() { return fileSize; }
|
35
src/fsfw/cfdp/pdu/MetadataGenericInfo.h
Normal file
35
src/fsfw/cfdp/pdu/MetadataGenericInfo.h
Normal file
@ -0,0 +1,35 @@
|
||||
#ifndef FSFW_SRC_FSFW_CFDP_PDU_METADATAINFO_H_
|
||||
#define FSFW_SRC_FSFW_CFDP_PDU_METADATAINFO_H_
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "fsfw/cfdp/Fss.h"
|
||||
#include "fsfw/cfdp/definitions.h"
|
||||
#include "fsfw/cfdp/tlv/Lv.h"
|
||||
#include "fsfw/cfdp/tlv/StringLv.h"
|
||||
#include "fsfw/cfdp/tlv/Tlv.h"
|
||||
|
||||
class MetadataGenericInfo {
|
||||
public:
|
||||
MetadataGenericInfo() = default;
|
||||
explicit MetadataGenericInfo(cfdp::Fss fileSize);
|
||||
MetadataGenericInfo(bool closureRequested, cfdp::ChecksumType checksumType, cfdp::Fss fileSize);
|
||||
|
||||
static size_t getSerializedSize(bool fssLarge = false);
|
||||
|
||||
[[nodiscard]] cfdp::ChecksumType getChecksumType() const;
|
||||
void setChecksumType(cfdp::ChecksumType checksumType);
|
||||
[[nodiscard]] bool isClosureRequested() const;
|
||||
void setClosureRequested(bool closureRequested = false);
|
||||
|
||||
[[nodiscard]] const cfdp::Fss& getFileSize() const;
|
||||
|
||||
cfdp::Fss& getMutFileSize();
|
||||
|
||||
private:
|
||||
bool closureRequested = false;
|
||||
cfdp::ChecksumType checksumType = cfdp::ChecksumType::NULL_CHECKSUM;
|
||||
cfdp::Fss fileSize;
|
||||
};
|
||||
|
||||
#endif /* FSFW_SRC_FSFW_CFDP_PDU_METADATAINFO_H_ */
|
@ -1,103 +0,0 @@
|
||||
#include "MetadataInfo.h"
|
||||
|
||||
MetadataInfo::MetadataInfo(bool closureRequested, cfdp::ChecksumType checksumType,
|
||||
cfdp::FileSize& fileSize, cfdp::StringLv& sourceFileName,
|
||||
cfdp::StringLv& destFileName)
|
||||
: MetadataInfo(fileSize, sourceFileName, destFileName) {
|
||||
this->closureRequested = closureRequested;
|
||||
this->checksumType = checksumType;
|
||||
}
|
||||
|
||||
MetadataInfo::MetadataInfo(cfdp::FileSize& fileSize, cfdp::StringLv& sourceFileName,
|
||||
cfdp::StringLv& destFileName)
|
||||
: fileSize(fileSize), sourceFileName(sourceFileName), destFileName(destFileName) {}
|
||||
|
||||
void MetadataInfo::setOptionsArray(cfdp::Tlv** optionsArray_, std::optional<size_t> optionsLen_,
|
||||
std::optional<size_t> maxOptionsLen_) {
|
||||
this->optionsArray = optionsArray_;
|
||||
if (maxOptionsLen_) {
|
||||
this->maxOptionsLen = maxOptionsLen_.value();
|
||||
}
|
||||
if (optionsLen_) {
|
||||
this->optionsLen = optionsLen_.value();
|
||||
}
|
||||
}
|
||||
|
||||
cfdp::ChecksumType MetadataInfo::getChecksumType() const { return checksumType; }
|
||||
|
||||
void MetadataInfo::setChecksumType(cfdp::ChecksumType checksumType_) {
|
||||
checksumType = checksumType_;
|
||||
}
|
||||
|
||||
bool MetadataInfo::isClosureRequested() const { return closureRequested; }
|
||||
|
||||
void MetadataInfo::setClosureRequested(bool closureRequested_) {
|
||||
closureRequested = closureRequested_;
|
||||
}
|
||||
|
||||
cfdp::StringLv& MetadataInfo::getDestFileName() { return destFileName; }
|
||||
|
||||
cfdp::FileSize& MetadataInfo::getFileSize() { return fileSize; }
|
||||
|
||||
ReturnValue_t MetadataInfo::getOptions(cfdp::Tlv*** optionsArray_, size_t* optionsLen_,
|
||||
size_t* maxOptsLen) {
|
||||
if (optionsArray_ == nullptr or optionsArray == nullptr) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
*optionsArray_ = optionsArray;
|
||||
if (optionsLen_ != nullptr) {
|
||||
*optionsLen_ = this->optionsLen;
|
||||
}
|
||||
if (maxOptsLen != nullptr) {
|
||||
*maxOptsLen = this->maxOptionsLen;
|
||||
}
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
bool MetadataInfo::hasOptions() const {
|
||||
if (optionsArray != nullptr and optionsLen > 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MetadataInfo::canHoldOptions() const {
|
||||
if (optionsArray != nullptr and maxOptionsLen > 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t MetadataInfo::getSerializedSize(bool fssLarge) {
|
||||
// 1 byte + minimal FSS 4 bytes
|
||||
size_t size = 5;
|
||||
if (fssLarge) {
|
||||
size += 4;
|
||||
}
|
||||
size += sourceFileName.getSerializedSize();
|
||||
size += destFileName.getSerializedSize();
|
||||
if (hasOptions()) {
|
||||
for (size_t idx = 0; idx < optionsLen; idx++) {
|
||||
size += optionsArray[idx]->getSerializedSize();
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
void MetadataInfo::setDestFileName(cfdp::StringLv& destFileName_) {
|
||||
this->destFileName = destFileName_;
|
||||
}
|
||||
|
||||
void MetadataInfo::setSourceFileName(cfdp::StringLv& sourceFileName_) {
|
||||
this->sourceFileName = sourceFileName_;
|
||||
}
|
||||
|
||||
size_t MetadataInfo::getMaxOptionsLen() const { return maxOptionsLen; }
|
||||
|
||||
void MetadataInfo::setMaxOptionsLen(size_t maxOptionsLen_) { this->maxOptionsLen = maxOptionsLen_; }
|
||||
|
||||
size_t MetadataInfo::getOptionsLen() const { return optionsLen; }
|
||||
|
||||
void MetadataInfo::setOptionsLen(size_t optionsLen_) { this->optionsLen = optionsLen_; }
|
||||
|
||||
cfdp::StringLv& MetadataInfo::getSourceFileName() { return sourceFileName; }
|
@ -1,55 +0,0 @@
|
||||
#ifndef FSFW_SRC_FSFW_CFDP_PDU_METADATAINFO_H_
|
||||
#define FSFW_SRC_FSFW_CFDP_PDU_METADATAINFO_H_
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "fsfw/cfdp/FileSize.h"
|
||||
#include "fsfw/cfdp/definitions.h"
|
||||
#include "fsfw/cfdp/tlv/Lv.h"
|
||||
#include "fsfw/cfdp/tlv/StringLv.h"
|
||||
#include "fsfw/cfdp/tlv/Tlv.h"
|
||||
|
||||
class MetadataInfo {
|
||||
public:
|
||||
MetadataInfo(cfdp::FileSize& fileSize, cfdp::StringLv& sourceFileName,
|
||||
cfdp::StringLv& destFileName);
|
||||
MetadataInfo(bool closureRequested, cfdp::ChecksumType checksumType, cfdp::FileSize& fileSize,
|
||||
cfdp::StringLv& sourceFileName, cfdp::StringLv& destFileName);
|
||||
|
||||
size_t getSerializedSize(bool fssLarge = false);
|
||||
|
||||
void setOptionsArray(cfdp::Tlv** optionsArray, std::optional<size_t> optionsLen,
|
||||
std::optional<size_t> maxOptionsLen);
|
||||
[[nodiscard]] cfdp::ChecksumType getChecksumType() const;
|
||||
void setChecksumType(cfdp::ChecksumType checksumType);
|
||||
[[nodiscard]] bool isClosureRequested() const;
|
||||
void setClosureRequested(bool closureRequested = false);
|
||||
|
||||
void setDestFileName(cfdp::StringLv& destFileName);
|
||||
void setSourceFileName(cfdp::StringLv& sourceFileName);
|
||||
|
||||
cfdp::StringLv& getDestFileName();
|
||||
cfdp::StringLv& getSourceFileName();
|
||||
cfdp::FileSize& getFileSize();
|
||||
|
||||
[[nodiscard]] bool hasOptions() const;
|
||||
[[nodiscard]] bool canHoldOptions() const;
|
||||
ReturnValue_t getOptions(cfdp::Tlv*** optionsArray, size_t* optionsLen, size_t* maxOptsLen);
|
||||
void setOptionsLen(size_t optionsLen);
|
||||
[[nodiscard]] size_t getOptionsLen() const;
|
||||
void setMaxOptionsLen(size_t maxOptionsLen);
|
||||
[[nodiscard]] size_t getMaxOptionsLen() const;
|
||||
|
||||
private:
|
||||
bool closureRequested = false;
|
||||
cfdp::ChecksumType checksumType = cfdp::ChecksumType::NULL_CHECKSUM;
|
||||
cfdp::FileSize& fileSize;
|
||||
cfdp::StringLv& sourceFileName;
|
||||
cfdp::StringLv& destFileName;
|
||||
|
||||
cfdp::Tlv** optionsArray = nullptr;
|
||||
size_t optionsLen = 0;
|
||||
size_t maxOptionsLen = 0;
|
||||
};
|
||||
|
||||
#endif /* FSFW_SRC_FSFW_CFDP_PDU_METADATAINFO_H_ */
|
@ -1,12 +1,26 @@
|
||||
#include "MetadataPduCreator.h"
|
||||
|
||||
MetadataPduCreator::MetadataPduCreator(PduConfig &conf, MetadataInfo &info)
|
||||
: FileDirectiveCreator(conf, cfdp::FileDirective::METADATA, 5), info(info) {
|
||||
MetadataPduCreator::MetadataPduCreator(PduConfig &conf, MetadataGenericInfo &info,
|
||||
cfdp::StringLv &srcFileName, cfdp::StringLv &destFileName,
|
||||
cfdp::Tlv **optionsArray, size_t optionsLen)
|
||||
: FileDirectiveCreator(conf, cfdp::FileDirective::METADATA, 5),
|
||||
info(info),
|
||||
srcFileName(srcFileName),
|
||||
destFileName(destFileName),
|
||||
optionsArray(optionsArray),
|
||||
optionsLen(optionsLen) {
|
||||
updateDirectiveFieldLen();
|
||||
}
|
||||
|
||||
void MetadataPduCreator::updateDirectiveFieldLen() {
|
||||
setDirectiveDataFieldLen(info.getSerializedSize(getLargeFileFlag()));
|
||||
size_t dirFieldLen = MetadataGenericInfo::getSerializedSize(HeaderCreator::getLargeFileFlag()) +
|
||||
srcFileName.getSerializedSize() + destFileName.getSerializedSize();
|
||||
if (optionsLen > 0 and optionsArray != nullptr) {
|
||||
for (size_t idx = 0; idx < optionsLen; idx++) {
|
||||
dirFieldLen += optionsArray[idx]->getSerializedSize();
|
||||
}
|
||||
}
|
||||
setDirectiveDataFieldLen(dirFieldLen);
|
||||
}
|
||||
|
||||
size_t MetadataPduCreator::getSerializedSize() const {
|
||||
@ -29,21 +43,18 @@ ReturnValue_t MetadataPduCreator::serialize(uint8_t **buffer, size_t *size, size
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
result = info.getSourceFileName().serialize(buffer, size, maxSize, streamEndianness);
|
||||
result = srcFileName.serialize(buffer, size, maxSize, streamEndianness);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
result = info.getDestFileName().serialize(buffer, size, maxSize, streamEndianness);
|
||||
result = destFileName.serialize(buffer, size, maxSize, streamEndianness);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (info.hasOptions()) {
|
||||
cfdp::Tlv **optsArray = nullptr;
|
||||
size_t optsLen = 0;
|
||||
info.getOptions(&optsArray, &optsLen, nullptr);
|
||||
for (size_t idx = 0; idx < optsLen; idx++) {
|
||||
result = optsArray[idx]->serialize(buffer, size, maxSize, streamEndianness);
|
||||
if (optionsLen > 0 and optionsArray != nullptr) {
|
||||
for (size_t idx = 0; idx < optionsLen; idx++) {
|
||||
result = optionsArray[idx]->serialize(buffer, size, maxSize, streamEndianness);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
@ -51,3 +62,5 @@ ReturnValue_t MetadataPduCreator::serialize(uint8_t **buffer, size_t *size, size
|
||||
}
|
||||
return result;
|
||||
}
|
||||
const cfdp::StringLv &MetadataPduCreator::getSourceFileName() const { return srcFileName; }
|
||||
const cfdp::StringLv &MetadataPduCreator::getDestFileName() const { return destFileName; }
|
||||
|
@ -2,22 +2,30 @@
|
||||
#define FSFW_CFDP_PDU_METADATAPDUCREATOR_H_
|
||||
|
||||
#include "fsfw/cfdp/pdu/FileDirectiveCreator.h"
|
||||
#include "fsfw/cfdp/pdu/MetadataInfo.h"
|
||||
#include "fsfw/cfdp/pdu/MetadataGenericInfo.h"
|
||||
|
||||
class MetadataPduCreator : public FileDirectiveCreator {
|
||||
public:
|
||||
MetadataPduCreator(PduConfig& conf, MetadataInfo& info);
|
||||
MetadataPduCreator(PduConfig& conf, MetadataGenericInfo& info, cfdp::StringLv& srcFileName,
|
||||
cfdp::StringLv& destFileName, cfdp::Tlv** optionsArray, size_t optionsLen);
|
||||
|
||||
void updateDirectiveFieldLen();
|
||||
|
||||
[[nodiscard]] size_t getSerializedSize() const override;
|
||||
|
||||
const cfdp::StringLv& getSourceFileName() const;
|
||||
const cfdp::StringLv& getDestFileName() const;
|
||||
|
||||
ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
||||
Endianness streamEndianness) const override;
|
||||
using FileDirectiveCreator::serialize;
|
||||
|
||||
private:
|
||||
MetadataInfo& info;
|
||||
MetadataGenericInfo& info;
|
||||
cfdp::StringLv& srcFileName;
|
||||
cfdp::StringLv& destFileName;
|
||||
cfdp::Tlv** optionsArray;
|
||||
size_t optionsLen;
|
||||
};
|
||||
|
||||
#endif /* FSFW_CFDP_PDU_METADATAPDUCREATOR_H_ */
|
||||
|
@ -1,9 +1,15 @@
|
||||
#include "MetadataPduReader.h"
|
||||
|
||||
MetadataPduReader::MetadataPduReader(const uint8_t* pduBuf, size_t maxSize, MetadataInfo& info)
|
||||
: FileDirectiveReader(pduBuf, maxSize), info(info) {}
|
||||
MetadataPduReader::MetadataPduReader(const uint8_t* pduBuf, size_t maxSize,
|
||||
MetadataGenericInfo& info, cfdp::Tlv* optionsArray,
|
||||
size_t optArrayMaxSize)
|
||||
: FileDirectiveReader(pduBuf, maxSize),
|
||||
info(info),
|
||||
optionArray(optionsArray),
|
||||
optionArrayMaxSize(optArrayMaxSize) {}
|
||||
|
||||
ReturnValue_t MetadataPduReader::parseData() {
|
||||
parsedOptions = 0;
|
||||
ReturnValue_t result = FileDirectiveReader::parseData();
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
@ -19,39 +25,43 @@ ReturnValue_t MetadataPduReader::parseData() {
|
||||
remSize -= 1;
|
||||
buf += 1;
|
||||
auto endianness = getEndianness();
|
||||
result = info.getFileSize().deSerialize(&buf, &remSize, endianness);
|
||||
result = info.getMutFileSize().deSerialize(&buf, &remSize, endianness);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
result = info.getSourceFileName().deSerialize(&buf, &remSize, endianness);
|
||||
result = srcFileName.deSerialize(&buf, &remSize, endianness);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
result = info.getDestFileName().deSerialize(&buf, &remSize, endianness);
|
||||
result = destFileName.deSerialize(&buf, &remSize, endianness);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
info.setOptionsLen(0);
|
||||
if (remSize > 0) {
|
||||
if (not info.canHoldOptions()) {
|
||||
if (optionArrayMaxSize == 0 or optionArray == nullptr) {
|
||||
return cfdp::METADATA_CANT_PARSE_OPTIONS;
|
||||
}
|
||||
cfdp::Tlv** optionsArray = nullptr;
|
||||
size_t optsMaxLen = 0;
|
||||
size_t optsIdx = 0;
|
||||
info.getOptions(&optionsArray, nullptr, &optsMaxLen);
|
||||
while (remSize > 0) {
|
||||
if (optsIdx > optsMaxLen) {
|
||||
if (optsIdx > optionArrayMaxSize) {
|
||||
return cfdp::METADATA_CANT_PARSE_OPTIONS;
|
||||
}
|
||||
result = optionsArray[optsIdx]->deSerialize(&buf, &remSize, endianness);
|
||||
result = optionArray[optsIdx].deSerialize(&buf, &remSize, endianness);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
optsIdx++;
|
||||
}
|
||||
info.setOptionsLen(optsIdx);
|
||||
parsedOptions = optsIdx;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t MetadataPduReader::getNumberOfParsedOptions() const { return parsedOptions; }
|
||||
|
||||
const cfdp::StringLv& MetadataPduReader::getSourceFileName() const { return srcFileName; }
|
||||
|
||||
const cfdp::StringLv& MetadataPduReader::getDestFileName() const { return destFileName; }
|
||||
|
||||
const MetadataGenericInfo& MetadataPduReader::getGenericInfo() const { return info; }
|
||||
|
@ -2,16 +2,28 @@
|
||||
#define FSFW_CFDP_PDU_METADATAPDUREADER_H_
|
||||
|
||||
#include "fsfw/cfdp/pdu/FileDirectiveReader.h"
|
||||
#include "fsfw/cfdp/pdu/MetadataInfo.h"
|
||||
#include "fsfw/cfdp/pdu/MetadataGenericInfo.h"
|
||||
|
||||
class MetadataPduReader : public FileDirectiveReader {
|
||||
public:
|
||||
MetadataPduReader(const uint8_t* pduBuf, size_t maxSize, MetadataInfo& info);
|
||||
MetadataPduReader(const uint8_t* pduBuf, size_t maxSize, MetadataGenericInfo& info,
|
||||
cfdp::Tlv* optionsArray, size_t optArrayMaxSize);
|
||||
|
||||
ReturnValue_t parseData() override;
|
||||
|
||||
[[nodiscard]] const MetadataGenericInfo& getGenericInfo() const;
|
||||
[[nodiscard]] const cfdp::StringLv& getSourceFileName() const;
|
||||
[[nodiscard]] const cfdp::StringLv& getDestFileName() const;
|
||||
|
||||
[[nodiscard]] size_t getNumberOfParsedOptions() const;
|
||||
|
||||
private:
|
||||
MetadataInfo& info;
|
||||
cfdp::StringLv srcFileName;
|
||||
cfdp::StringLv destFileName;
|
||||
MetadataGenericInfo& info;
|
||||
cfdp::Tlv* optionArray;
|
||||
size_t optionArrayMaxSize;
|
||||
size_t parsedOptions = 0;
|
||||
};
|
||||
|
||||
#endif /* FSFW_CFDP_PDU_METADATAPDUREADER_H_ */
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "NakInfo.h"
|
||||
|
||||
NakInfo::NakInfo(cfdp::FileSize startOfScope, cfdp::FileSize endOfScope)
|
||||
NakInfo::NakInfo(cfdp::Fss startOfScope, cfdp::Fss endOfScope)
|
||||
: startOfScope(startOfScope), endOfScope(endOfScope) {}
|
||||
|
||||
size_t NakInfo::getSerializedSize(bool fssLarge) {
|
||||
@ -57,9 +57,9 @@ void NakInfo::setSegmentRequests(SegmentRequest* segmentRequests, size_t* segmen
|
||||
}
|
||||
}
|
||||
|
||||
cfdp::FileSize& NakInfo::getStartOfScope() { return startOfScope; }
|
||||
cfdp::Fss& NakInfo::getStartOfScope() { return startOfScope; }
|
||||
|
||||
cfdp::FileSize& NakInfo::getEndOfScope() { return endOfScope; }
|
||||
cfdp::Fss& NakInfo::getEndOfScope() { return endOfScope; }
|
||||
|
||||
size_t NakInfo::getSegmentRequestsLen() const { return segmentRequestsLen; }
|
||||
|
||||
|
@ -3,21 +3,21 @@
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "fsfw/cfdp/FileSize.h"
|
||||
#include "fsfw/cfdp/Fss.h"
|
||||
|
||||
class NakInfo {
|
||||
public:
|
||||
using SegmentRequest = std::pair<cfdp::FileSize, cfdp::FileSize>;
|
||||
using SegmentRequest = std::pair<cfdp::Fss, cfdp::Fss>;
|
||||
|
||||
NakInfo(cfdp::FileSize startOfScope, cfdp::FileSize endOfScope);
|
||||
NakInfo(cfdp::Fss startOfScope, cfdp::Fss endOfScope);
|
||||
|
||||
void setSegmentRequests(SegmentRequest* segmentRequests, size_t* segmentRequestLen,
|
||||
size_t* maxSegmentRequestLen);
|
||||
|
||||
size_t getSerializedSize(bool fssLarge = false);
|
||||
|
||||
cfdp::FileSize& getStartOfScope();
|
||||
cfdp::FileSize& getEndOfScope();
|
||||
cfdp::Fss& getStartOfScope();
|
||||
cfdp::Fss& getEndOfScope();
|
||||
|
||||
bool hasSegmentRequests() const;
|
||||
bool canHoldSegmentRequests() const;
|
||||
@ -31,8 +31,8 @@ class NakInfo {
|
||||
void setSegmentRequestLen(size_t readLen);
|
||||
|
||||
private:
|
||||
cfdp::FileSize startOfScope;
|
||||
cfdp::FileSize endOfScope;
|
||||
cfdp::Fss startOfScope;
|
||||
cfdp::Fss endOfScope;
|
||||
SegmentRequest* segmentRequests = nullptr;
|
||||
size_t segmentRequestsLen = 0;
|
||||
size_t maxSegmentRequestsLen = 0;
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "NakInfo.h"
|
||||
#include "fsfw/cfdp/FileSize.h"
|
||||
#include "fsfw/cfdp/Fss.h"
|
||||
#include "fsfw/cfdp/definitions.h"
|
||||
#include "fsfw/cfdp/pdu/FileDirectiveCreator.h"
|
||||
|
||||
|
@ -105,7 +105,8 @@ class PduHeaderReader : public RedirectableDataPointerIF, public PduHeaderIF {
|
||||
* @return
|
||||
*/
|
||||
ReturnValue_t setData(uint8_t* dataPtr, size_t maxSize, void* args) override;
|
||||
void assignVarLenField(cfdp::VarLenField* field, cfdp::WidthInBytes width, void* sourcePtr) const;
|
||||
static void assignVarLenField(cfdp::VarLenField* field, cfdp::WidthInBytes width,
|
||||
void* sourcePtr);
|
||||
void* sourceIdRaw = nullptr;
|
||||
void* seqNumRaw = nullptr;
|
||||
void* destIdRaw = nullptr;
|
||||
|
@ -8,4 +8,5 @@ target_sources(
|
||||
StringLv.cpp
|
||||
FlowLabelTlv.cpp
|
||||
MessageToUserTlv.cpp
|
||||
FaultHandlerOverrideTlv.cpp)
|
||||
FaultHandlerOverrideTlv.cpp
|
||||
ReservedMessageCreator.cpp)
|
||||
|
@ -14,23 +14,6 @@ cfdp::Lv::Lv(const std::vector<uint8_t>& data) : value(data.data(), data.size(),
|
||||
|
||||
cfdp::Lv::Lv() : value(static_cast<uint8_t*>(nullptr), 0, true) {}
|
||||
|
||||
cfdp::Lv::Lv(const Lv& other)
|
||||
: value(other.value.getConstBuffer(), other.value.getSerializedSize() - 1, true) {
|
||||
if (other.value.getSerializedSize() - 1 > 0) {
|
||||
zeroLen = false;
|
||||
}
|
||||
}
|
||||
|
||||
cfdp::Lv& cfdp::Lv::operator=(const Lv& other) {
|
||||
size_t otherSize = 0;
|
||||
auto* otherVal = const_cast<uint8_t*>(other.getValue(&otherSize));
|
||||
if (otherVal == nullptr or otherSize == 0) {
|
||||
this->zeroLen = true;
|
||||
}
|
||||
this->value.setConstBuffer(otherVal, otherSize);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::Lv::serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
||||
Endianness streamEndianness) const {
|
||||
if (maxSize < 1) {
|
||||
@ -49,10 +32,8 @@ ReturnValue_t cfdp::Lv::serialize(uint8_t** buffer, size_t* size, size_t maxSize
|
||||
}
|
||||
|
||||
size_t cfdp::Lv::getSerializedSize() const {
|
||||
if (zeroLen) {
|
||||
if (zeroLen or value.getConstBuffer() == nullptr) {
|
||||
return 1;
|
||||
} else if (value.getConstBuffer() == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
return value.getSerializedSize();
|
||||
}
|
||||
@ -85,7 +66,34 @@ ReturnValue_t cfdp::Lv::deSerialize(const uint8_t** buffer, size_t* size,
|
||||
const uint8_t* cfdp::Lv::getValue(size_t* size) const {
|
||||
if (size != nullptr) {
|
||||
// Length without length field
|
||||
*size = value.getSerializedSize() - 1;
|
||||
*size = getSerializedSize() - 1;
|
||||
}
|
||||
return value.getConstBuffer();
|
||||
}
|
||||
cfdp::Lv::Lv(cfdp::Lv&& other) noexcept
|
||||
: value(other.value.getConstBuffer(), other.value.getSerializedSize() - 1, true) {
|
||||
if (other.value.getSerializedSize() - 1 > 0) {
|
||||
zeroLen = false;
|
||||
}
|
||||
// Leave other class in intact state.
|
||||
other.zeroLen = false;
|
||||
other.value = SerialBufferAdapter<uint8_t>();
|
||||
}
|
||||
|
||||
cfdp::Lv& cfdp::Lv::operator=(cfdp::Lv&& other) noexcept {
|
||||
size_t otherSize = 0;
|
||||
this->zeroLen = false;
|
||||
auto* otherVal = const_cast<uint8_t*>(other.getValue(&otherSize));
|
||||
if (otherVal == nullptr or otherSize == 0) {
|
||||
this->zeroLen = true;
|
||||
}
|
||||
this->value.setConstBuffer(otherVal, otherSize);
|
||||
// Leave other class in intact state.
|
||||
other.zeroLen = false;
|
||||
other.value = SerialBufferAdapter<uint8_t>();
|
||||
return *this;
|
||||
}
|
||||
|
||||
size_t cfdp::Lv::getValueLen() const { return getSerializedSize() - 1; }
|
||||
|
||||
bool cfdp::Lv::isEmpty() const { return zeroLen; }
|
||||
|
@ -18,8 +18,12 @@ class Lv : public SerializeIF {
|
||||
Lv(const uint8_t* value, size_t size);
|
||||
Lv();
|
||||
|
||||
Lv(const Lv&);
|
||||
Lv& operator=(const Lv&);
|
||||
// Semantically, this class is a zero-copy helper, so the copy ctor and copy assigment do not
|
||||
// really make sense here.
|
||||
Lv(const Lv&) = delete;
|
||||
Lv& operator=(const Lv&) = delete;
|
||||
Lv(Lv&&) noexcept;
|
||||
Lv& operator=(Lv&&) noexcept;
|
||||
|
||||
ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
||||
Endianness streamEndianness) const override;
|
||||
@ -36,6 +40,8 @@ class Lv : public SerializeIF {
|
||||
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
||||
Endianness streamEndianness) override;
|
||||
|
||||
size_t getValueLen() const;
|
||||
|
||||
/**
|
||||
* Get value field and its size.
|
||||
* @param size Optionally retrieve size. Size will be the size of the actual value field
|
||||
@ -44,6 +50,8 @@ class Lv : public SerializeIF {
|
||||
*/
|
||||
const uint8_t* getValue(size_t* size) const;
|
||||
|
||||
bool isEmpty() const;
|
||||
|
||||
private:
|
||||
bool zeroLen = true;
|
||||
SerialBufferAdapter<uint8_t> value;
|
||||
|
@ -7,3 +7,22 @@ MessageToUserTlv::MessageToUserTlv() : Tlv() {}
|
||||
|
||||
MessageToUserTlv::MessageToUserTlv(const std::vector<uint8_t>& data)
|
||||
: Tlv(cfdp::TlvType::MSG_TO_USER, data.data(), data.size()) {}
|
||||
|
||||
MessageToUserTlv::MessageToUserTlv(const uint8_t* value, size_t size)
|
||||
: Tlv(cfdp::TlvType::MSG_TO_USER, value, size) {}
|
||||
|
||||
bool MessageToUserTlv::isReservedCfdpMessage(uint8_t& messageType, const uint8_t** msgDataStart,
|
||||
size_t& msgLen) const {
|
||||
if (cfdp::Tlv::getLengthField() < 5) {
|
||||
return false;
|
||||
}
|
||||
if (std::strncmp(reinterpret_cast<const char*>(getValue()), "cfdp", 4) == 0) {
|
||||
messageType = getValue()[4];
|
||||
if (msgDataStart != nullptr) {
|
||||
*msgDataStart = getValue() + 5;
|
||||
}
|
||||
msgLen = cfdp::Tlv::getSerializedSize() - 5;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -9,8 +9,12 @@ class MessageToUserTlv : public cfdp::Tlv {
|
||||
public:
|
||||
MessageToUserTlv();
|
||||
MessageToUserTlv(uint8_t* value, size_t size);
|
||||
MessageToUserTlv(const uint8_t* value, size_t size);
|
||||
explicit MessageToUserTlv(const std::vector<uint8_t>& data);
|
||||
|
||||
bool isReservedCfdpMessage(uint8_t& messageType, const uint8_t** msgDataStart,
|
||||
size_t& msgLen) const;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
|
39
src/fsfw/cfdp/tlv/ReservedMessageCreator.cpp
Normal file
39
src/fsfw/cfdp/tlv/ReservedMessageCreator.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
#include "ReservedMessageCreator.h"
|
||||
|
||||
cfdp::ReservedMessageCreator::ReservedMessageCreator(uint8_t messageType, uint8_t *msgData,
|
||||
size_t msgLen)
|
||||
: messageType(messageType), msgData(msgData), msgSize(msgLen) {}
|
||||
|
||||
ReturnValue_t cfdp::ReservedMessageCreator::serialize(
|
||||
uint8_t **buffer, size_t *size, size_t maxSize,
|
||||
SerializeIF::Endianness streamEndianness) const {
|
||||
if (*size + getSerializedSize() > maxSize) {
|
||||
return SerializeIF::BUFFER_TOO_SHORT;
|
||||
}
|
||||
**buffer = TlvType::MSG_TO_USER;
|
||||
*buffer += 1;
|
||||
*size += 1;
|
||||
**buffer = getSerializedSize() - 2;
|
||||
*size += 1;
|
||||
*buffer += 1;
|
||||
std::memcpy(*buffer, MSG_HEADER, 4);
|
||||
*buffer += 4;
|
||||
*size += 4;
|
||||
**buffer = messageType;
|
||||
*buffer += 1;
|
||||
*size += 1;
|
||||
std::memcpy(*buffer, msgData, msgSize);
|
||||
*buffer += msgSize;
|
||||
*size += msgSize;
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
size_t cfdp::ReservedMessageCreator::getSerializedSize() const {
|
||||
// 2 bytes type and length, 4 bytes CFDP, 1 byte reserved message type, message data.
|
||||
return 2 + 5 + msgSize;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::ReservedMessageCreator::deSerialize(const uint8_t **buffer, size_t *size,
|
||||
SerializeIF::Endianness streamEndianness) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
24
src/fsfw/cfdp/tlv/ReservedMessageCreator.h
Normal file
24
src/fsfw/cfdp/tlv/ReservedMessageCreator.h
Normal file
@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include "Tlv.h"
|
||||
|
||||
namespace cfdp {
|
||||
|
||||
class ReservedMessageCreator : public SerializeIF {
|
||||
public:
|
||||
static constexpr char MSG_HEADER[] = "cfdp";
|
||||
|
||||
ReservedMessageCreator(uint8_t messageType, uint8_t *msgData, size_t msgLen);
|
||||
[[nodiscard]] ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize,
|
||||
Endianness streamEndianness) const override;
|
||||
[[nodiscard]] size_t getSerializedSize() const override;
|
||||
ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size,
|
||||
Endianness streamEndianness) override;
|
||||
|
||||
private:
|
||||
uint8_t messageType;
|
||||
uint8_t *msgData;
|
||||
size_t msgSize;
|
||||
};
|
||||
|
||||
} // namespace cfdp
|
@ -7,3 +7,12 @@ cfdp::StringLv::StringLv(const char* filename, size_t len)
|
||||
: Lv(reinterpret_cast<const uint8_t*>(filename), len) {}
|
||||
|
||||
cfdp::StringLv::StringLv() : Lv() {}
|
||||
|
||||
const char* cfdp::StringLv::getCString(size_t& fileSize) const {
|
||||
return reinterpret_cast<const char*>(getValue(&fileSize));
|
||||
}
|
||||
|
||||
std::string cfdp::StringLv::getString() const {
|
||||
size_t fileSize;
|
||||
return {getCString(fileSize), fileSize};
|
||||
}
|
||||
|
@ -13,6 +13,8 @@ class StringLv : public Lv {
|
||||
explicit StringLv(const std::string& fileName);
|
||||
explicit StringLv(const char* filename, size_t len);
|
||||
|
||||
const char* getCString(size_t& fileSize) const;
|
||||
std::string getString() const;
|
||||
// Delete the move constructor to avoid passing in a temporary
|
||||
StringLv(const std::string&&) = delete;
|
||||
};
|
||||
|
@ -54,6 +54,7 @@ ReturnValue_t cfdp::Tlv::deSerialize(const uint8_t **buffer, size_t *size,
|
||||
return STREAM_TOO_SHORT;
|
||||
}
|
||||
|
||||
rawData = *buffer;
|
||||
uint8_t rawType = **buffer;
|
||||
if (not checkType(rawType)) {
|
||||
return INVALID_TLV_TYPE;
|
||||
@ -102,3 +103,5 @@ void cfdp::Tlv::setValue(uint8_t *value, size_t len) {
|
||||
uint8_t cfdp::Tlv::getLengthField() const { return this->value.getSerializedSize() - 1; }
|
||||
|
||||
void cfdp::Tlv::setType(TlvType type) { this->type = type; }
|
||||
|
||||
const uint8_t *cfdp::Tlv::getRawData() const { return rawData; }
|
||||
|
@ -47,6 +47,7 @@ class Tlv : public TlvIF {
|
||||
void setValue(uint8_t *value, size_t len);
|
||||
|
||||
[[nodiscard]] const uint8_t *getValue() const;
|
||||
[[nodiscard]] const uint8_t *getRawData() const;
|
||||
void setType(TlvType type);
|
||||
[[nodiscard]] TlvType getType() const override;
|
||||
[[nodiscard]] uint8_t getLengthField() const override;
|
||||
@ -55,6 +56,7 @@ class Tlv : public TlvIF {
|
||||
bool checkType(uint8_t rawType);
|
||||
|
||||
bool zeroLen = true;
|
||||
const uint8_t *rawData = nullptr;
|
||||
TlvType type = TlvType::INVALID_TLV;
|
||||
SerialBufferAdapter<uint8_t> value;
|
||||
};
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "../returnvalues/returnvalue.h"
|
||||
#include "../serialize/SerializeAdapter.h"
|
||||
#include "../serialize/SerializeIF.h"
|
||||
#include "definitions.h"
|
||||
|
||||
/**
|
||||
* @brief A List that stores its values in an array.
|
||||
@ -19,9 +20,6 @@ class ArrayList {
|
||||
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.
|
||||
@ -187,7 +185,7 @@ class ArrayList {
|
||||
*/
|
||||
ReturnValue_t insert(T entry) {
|
||||
if (size >= maxSize_) {
|
||||
return FULL;
|
||||
return containers::LIST_FULL;
|
||||
}
|
||||
entries[size] = entry;
|
||||
++size;
|
||||
|
@ -12,6 +12,7 @@ template <typename T, size_t MAX_SIZE, typename count_t = uint8_t>
|
||||
class FixedArrayList : public ArrayList<T, count_t> {
|
||||
static_assert(MAX_SIZE <= std::numeric_limits<count_t>::max(),
|
||||
"count_t is not large enough to hold MAX_SIZE");
|
||||
static_assert(MAX_SIZE > 0, "MAX_SIZE is 0");
|
||||
|
||||
private:
|
||||
T data[MAX_SIZE];
|
||||
@ -20,15 +21,19 @@ class FixedArrayList : public ArrayList<T, count_t> {
|
||||
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;
|
||||
for (size_t idx = 0; idx < this->size; idx++) {
|
||||
data[idx] = other.data[idx];
|
||||
}
|
||||
}
|
||||
|
||||
FixedArrayList& operator=(FixedArrayList other) {
|
||||
memcpy(this->data, other.data, sizeof(this->data));
|
||||
this->entries = data;
|
||||
this->size = other.size;
|
||||
for (size_t idx = 0; idx < this->size; idx++) {
|
||||
data[idx] = other.data[idx];
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -4,8 +4,8 @@
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "../returnvalues/returnvalue.h"
|
||||
#include "ArrayList.h"
|
||||
#include "definitions.h"
|
||||
|
||||
/**
|
||||
* @brief Map implementation for maps with a pre-defined size.
|
||||
@ -24,11 +24,6 @@ class FixedMap : public SerializeIF {
|
||||
"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;
|
||||
@ -76,10 +71,10 @@ class FixedMap : public SerializeIF {
|
||||
|
||||
ReturnValue_t insert(key_t key, T value, Iterator* storedValue = nullptr) {
|
||||
if (exists(key) == returnvalue::OK) {
|
||||
return KEY_ALREADY_EXISTS;
|
||||
return containers::KEY_ALREADY_EXISTS;
|
||||
}
|
||||
if (_size == theMap.maxSize()) {
|
||||
return MAP_FULL;
|
||||
return containers::MAP_FULL;
|
||||
}
|
||||
theMap[_size].first = key;
|
||||
theMap[_size].second = value;
|
||||
@ -93,7 +88,7 @@ class FixedMap : public SerializeIF {
|
||||
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;
|
||||
ReturnValue_t result = containers::KEY_DOES_NOT_EXIST;
|
||||
if (findIndex(key) < _size) {
|
||||
result = returnvalue::OK;
|
||||
}
|
||||
@ -103,7 +98,7 @@ class FixedMap : public SerializeIF {
|
||||
ReturnValue_t erase(Iterator* iter) {
|
||||
uint32_t i;
|
||||
if ((i = findIndex((*iter).value->first)) >= _size) {
|
||||
return KEY_DOES_NOT_EXIST;
|
||||
return containers::KEY_DOES_NOT_EXIST;
|
||||
}
|
||||
theMap[i] = theMap[_size - 1];
|
||||
--_size;
|
||||
@ -114,7 +109,7 @@ class FixedMap : public SerializeIF {
|
||||
ReturnValue_t erase(key_t key) {
|
||||
uint32_t i;
|
||||
if ((i = findIndex(key)) >= _size) {
|
||||
return KEY_DOES_NOT_EXIST;
|
||||
return containers::KEY_DOES_NOT_EXIST;
|
||||
}
|
||||
theMap[i] = theMap[_size - 1];
|
||||
--_size;
|
||||
|
14
src/fsfw/container/definitions.h
Normal file
14
src/fsfw/container/definitions.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef FSFW_CONTAINER_DEFINITIONS_H_
|
||||
#define FSFW_CONTAINER_DEFINITIONS_H_
|
||||
|
||||
#include "fsfw/retval.h"
|
||||
|
||||
namespace containers {
|
||||
static const ReturnValue_t KEY_ALREADY_EXISTS = returnvalue::makeCode(CLASS_ID::FIXED_MAP, 0x01);
|
||||
static const ReturnValue_t MAP_FULL = returnvalue::makeCode(CLASS_ID::FIXED_MAP, 0x02);
|
||||
static const ReturnValue_t KEY_DOES_NOT_EXIST = returnvalue::makeCode(CLASS_ID::FIXED_MAP, 0x03);
|
||||
|
||||
static const ReturnValue_t LIST_FULL = returnvalue::makeCode(CLASS_ID::ARRAY_LIST, 0x01);
|
||||
} // namespace containers
|
||||
|
||||
#endif /* FSFW_CONTAINER_DEFINITIONS_H_ */
|
@ -4,11 +4,10 @@
|
||||
#include "fsfw/ipc/QueueFactory.h"
|
||||
#include "fsfw/objectmanager/ObjectManager.h"
|
||||
#include "fsfw/subsystem/SubsystemBase.h"
|
||||
#include "fsfw/subsystem/helper.h"
|
||||
|
||||
ControllerBase::ControllerBase(object_id_t setObjectId, object_id_t parentId,
|
||||
size_t commandQueueDepth)
|
||||
ControllerBase::ControllerBase(object_id_t setObjectId, size_t commandQueueDepth)
|
||||
: SystemObject(setObjectId),
|
||||
parentId(parentId),
|
||||
mode(MODE_OFF),
|
||||
submode(SUBMODE_NONE),
|
||||
modeHelper(this),
|
||||
@ -21,33 +20,15 @@ ControllerBase::ControllerBase(object_id_t setObjectId, object_id_t parentId,
|
||||
ControllerBase::~ControllerBase() { QueueFactory::instance()->deleteMessageQueue(commandQueue); }
|
||||
|
||||
ReturnValue_t ControllerBase::initialize() {
|
||||
ReturnValue_t result = SystemObject::initialize();
|
||||
ReturnValue_t result = modeHelper.initialize();
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
MessageQueueId_t parentQueue = 0;
|
||||
if (parentId != objects::NO_OBJECT) {
|
||||
auto* parent = ObjectManager::instance()->get<SubsystemBase>(parentId);
|
||||
if (parent == nullptr) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
parentQueue = parent->getCommandQueue();
|
||||
|
||||
parent->registerChild(getObjectId());
|
||||
}
|
||||
|
||||
result = healthHelper.initialize(parentQueue);
|
||||
result = healthHelper.initialize();
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = modeHelper.initialize(parentQueue);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return returnvalue::OK;
|
||||
return SystemObject::initialize();
|
||||
}
|
||||
|
||||
MessageQueueId_t ControllerBase::getCommandQueue() const { return commandQueue->getId(); }
|
||||
@ -77,7 +58,7 @@ void ControllerBase::handleQueue() {
|
||||
|
||||
void ControllerBase::startTransition(Mode_t mode_, Submode_t submode_) {
|
||||
changeHK(this->mode, this->submode, false);
|
||||
triggerEvent(CHANGING_MODE, mode, submode);
|
||||
triggerEvent(CHANGING_MODE, mode_, submode_);
|
||||
mode = mode_;
|
||||
submode = submode_;
|
||||
modeHelper.modeChanged(mode, submode);
|
||||
@ -91,18 +72,17 @@ void ControllerBase::getMode(Mode_t* mode_, Submode_t* submode_) {
|
||||
*submode_ = this->submode;
|
||||
}
|
||||
|
||||
void ControllerBase::setToExternalControl() { healthHelper.setHealth(EXTERNAL_CONTROL); }
|
||||
|
||||
void ControllerBase::announceMode(bool recursive) { triggerEvent(MODE_INFO, mode, submode); }
|
||||
|
||||
void ControllerBase::modeChanged(Mode_t mode_, Submode_t submode_) {}
|
||||
|
||||
void ControllerBase::setToExternalControl() { healthHelper.setHealth(EXTERNAL_CONTROL); }
|
||||
|
||||
ReturnValue_t ControllerBase::performOperation(uint8_t opCode) {
|
||||
handleQueue();
|
||||
performControlOperation();
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
void ControllerBase::modeChanged(Mode_t mode_, Submode_t submode_) {}
|
||||
|
||||
ReturnValue_t ControllerBase::setHealth(HealthState health) {
|
||||
switch (health) {
|
||||
case HEALTHY:
|
||||
@ -120,3 +100,13 @@ void ControllerBase::setTaskIF(PeriodicTaskIF* task_) { executingTask = task_; }
|
||||
void ControllerBase::changeHK(Mode_t mode_, Submode_t submode_, bool enable) {}
|
||||
|
||||
ReturnValue_t ControllerBase::initializeAfterTaskCreation() { return returnvalue::OK; }
|
||||
|
||||
const HasHealthIF* ControllerBase::getOptHealthIF() const { return this; }
|
||||
|
||||
const HasModesIF& ControllerBase::getModeIF() const { return *this; }
|
||||
|
||||
ModeTreeChildIF& ControllerBase::getModeTreeChildIF() { return *this; }
|
||||
|
||||
ReturnValue_t ControllerBase::connectModeTreeParent(HasModeTreeChildrenIF& parent) {
|
||||
return modetree::connectModeTreeParent(parent, *this, &healthHelper, modeHelper);
|
||||
}
|
||||
|
@ -6,6 +6,9 @@
|
||||
#include "fsfw/modes/HasModesIF.h"
|
||||
#include "fsfw/modes/ModeHelper.h"
|
||||
#include "fsfw/objectmanager/SystemObject.h"
|
||||
#include "fsfw/subsystem/HasModeTreeChildrenIF.h"
|
||||
#include "fsfw/subsystem/ModeTreeChildIF.h"
|
||||
#include "fsfw/subsystem/ModeTreeConnectionIF.h"
|
||||
#include "fsfw/tasks/ExecutableObjectIF.h"
|
||||
#include "fsfw/tasks/PeriodicTaskIF.h"
|
||||
|
||||
@ -18,13 +21,18 @@
|
||||
class ControllerBase : public HasModesIF,
|
||||
public HasHealthIF,
|
||||
public ExecutableObjectIF,
|
||||
public ModeTreeChildIF,
|
||||
public ModeTreeConnectionIF,
|
||||
public SystemObject {
|
||||
public:
|
||||
static const Mode_t MODE_NORMAL = 2;
|
||||
|
||||
ControllerBase(object_id_t setObjectId, object_id_t parentId, size_t commandQueueDepth = 3);
|
||||
ControllerBase(object_id_t setObjectId, size_t commandQueueDepth = 3);
|
||||
~ControllerBase() override;
|
||||
|
||||
ReturnValue_t connectModeTreeParent(HasModeTreeChildrenIF &parent) override;
|
||||
ModeTreeChildIF &getModeTreeChildIF() override;
|
||||
|
||||
/** SystemObject override */
|
||||
ReturnValue_t initialize() override;
|
||||
|
||||
@ -38,6 +46,8 @@ class ControllerBase : public HasModesIF,
|
||||
ReturnValue_t performOperation(uint8_t opCode) override;
|
||||
void setTaskIF(PeriodicTaskIF *task) override;
|
||||
ReturnValue_t initializeAfterTaskCreation() override;
|
||||
const HasHealthIF *getOptHealthIF() const override;
|
||||
const HasModesIF &getModeIF() const override;
|
||||
|
||||
protected:
|
||||
/**
|
||||
@ -56,8 +66,6 @@ class ControllerBase : public HasModesIF,
|
||||
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
|
||||
uint32_t *msToReachTheMode) override = 0;
|
||||
|
||||
const object_id_t parentId;
|
||||
|
||||
Mode_t mode;
|
||||
|
||||
Submode_t submode;
|
||||
|
@ -1,8 +1,7 @@
|
||||
#include "fsfw/controller/ExtendedControllerBase.h"
|
||||
|
||||
ExtendedControllerBase::ExtendedControllerBase(object_id_t objectId, object_id_t parentId,
|
||||
size_t commandQueueDepth)
|
||||
: ControllerBase(objectId, parentId, commandQueueDepth),
|
||||
ExtendedControllerBase::ExtendedControllerBase(object_id_t objectId, size_t commandQueueDepth)
|
||||
: ControllerBase(objectId, commandQueueDepth),
|
||||
poolManager(this, commandQueue),
|
||||
actionHelper(this, commandQueue) {}
|
||||
|
||||
|
@ -17,7 +17,7 @@ class ExtendedControllerBase : public ControllerBase,
|
||||
public HasActionsIF,
|
||||
public HasLocalDataPoolIF {
|
||||
public:
|
||||
ExtendedControllerBase(object_id_t objectId, object_id_t parentId, size_t commandQueueDepth = 3);
|
||||
ExtendedControllerBase(object_id_t objectId, size_t commandQueueDepth = 3);
|
||||
~ExtendedControllerBase() override;
|
||||
|
||||
/* SystemObjectIF overrides */
|
||||
|
@ -6,6 +6,8 @@
|
||||
#include "fsfw/globalfunctions/constants.h"
|
||||
#include "fsfw/globalfunctions/math/MatrixOperations.h"
|
||||
#include "fsfw/globalfunctions/math/VectorOperations.h"
|
||||
#include "fsfw/globalfunctions/sign.h"
|
||||
#include "fsfw/serviceinterface.h"
|
||||
|
||||
void CoordinateTransformations::positionEcfToEci(const double* ecfPosition, double* eciPosition,
|
||||
timeval* timeUTC) {
|
||||
@ -97,7 +99,14 @@ void CoordinateTransformations::ecfToEci(const double* ecfCoordinates, double* e
|
||||
|
||||
double CoordinateTransformations::getJuleanCenturiesTT(timeval timeUTC) {
|
||||
timeval timeTT;
|
||||
Clock::convertUTCToTT(timeUTC, &timeTT);
|
||||
ReturnValue_t result = Clock::convertUTCToTT(timeUTC, &timeTT);
|
||||
if (result != returnvalue::OK) {
|
||||
// i think it is better to continue here than to abort
|
||||
timeTT = timeUTC;
|
||||
sif::error << "CoordinateTransformations::Conversion from UTC to TT failed. Continuing "
|
||||
"calculations with UTC."
|
||||
<< std::endl;
|
||||
}
|
||||
double jD2000TT;
|
||||
Clock::convertTimevalToJD2000(timeTT, &jD2000TT);
|
||||
|
||||
@ -207,3 +216,61 @@ void CoordinateTransformations::getTransMatrixECITOECF(timeval timeUTC, double T
|
||||
|
||||
MatrixOperations<double>::multiply(mTheta[0], Ttemp[0], Tfi[0], 3, 3, 3);
|
||||
};
|
||||
|
||||
void CoordinateTransformations::cartesianFromLatLongAlt(const double lat, const double longi,
|
||||
const double alt, double* cartesianOutput) {
|
||||
/* @brief: cartesianFromLatLongAlt() - calculates cartesian coordinates in ECEF from latitude,
|
||||
* longitude and altitude
|
||||
* @param: lat geodetic latitude [rad]
|
||||
* longi longitude [rad]
|
||||
* alt altitude [m]
|
||||
* cartesianOutput Cartesian Coordinates in ECEF (3x1)
|
||||
* @source: Fundamentals of Spacecraft Attitude Determination and Control, P.34ff
|
||||
* Landis Markley and John L. Crassidis*/
|
||||
double radiusPolar = 6356752.314;
|
||||
double radiusEqua = 6378137;
|
||||
|
||||
double eccentricity = sqrt(1 - pow(radiusPolar, 2) / pow(radiusEqua, 2));
|
||||
double auxRadius = radiusEqua / sqrt(1 - pow(eccentricity, 2) * pow(sin(lat), 2));
|
||||
|
||||
cartesianOutput[0] = (auxRadius + alt) * cos(lat) * cos(longi);
|
||||
cartesianOutput[1] = (auxRadius + alt) * cos(lat) * sin(longi);
|
||||
cartesianOutput[2] = ((1 - pow(eccentricity, 2)) * auxRadius + alt) * sin(lat);
|
||||
};
|
||||
|
||||
void CoordinateTransformations::latLongAltFromCartesian(const double* vector, double& latitude,
|
||||
double& longitude, double& altitude) {
|
||||
/* @brief: latLongAltFromCartesian() - calculates latitude, longitude and altitude from
|
||||
* cartesian coordinates in ECEF
|
||||
* @param: x x-value of position vector [m]
|
||||
* y y-value of position vector [m]
|
||||
* z z-value of position vector [m]
|
||||
* latitude geodetic latitude [rad]
|
||||
* longitude longitude [rad]
|
||||
* altitude altitude [m]
|
||||
* @source: Fundamentals of Spacecraft Attitude Determination and Control, P.35 f
|
||||
* Landis Markley and John L. Crassidis*/
|
||||
// From World Geodetic System the Earth Radii
|
||||
double a = 6378137.0; // semimajor axis [m]
|
||||
double b = 6356752.3142; // semiminor axis [m]
|
||||
|
||||
// Calculation
|
||||
double e2 = 1 - pow(b, 2) / pow(a, 2);
|
||||
double epsilon2 = pow(a, 2) / pow(b, 2) - 1;
|
||||
double rho = sqrt(pow(vector[0], 2) + pow(vector[1], 2));
|
||||
double p = std::abs(vector[2]) / epsilon2;
|
||||
double s = pow(rho, 2) / (e2 * epsilon2);
|
||||
double q = pow(p, 2) - pow(b, 2) + s;
|
||||
double u = p / sqrt(q);
|
||||
double v = pow(b, 2) * pow(u, 2) / q;
|
||||
double P = 27 * v * s / q;
|
||||
double Q = pow(sqrt(P + 1) + sqrt(P), 2. / 3.);
|
||||
double t = (1 + Q + 1 / Q) / 6;
|
||||
double c = sqrt(pow(u, 2) - 1 + 2 * t);
|
||||
double w = (c - u) / 2;
|
||||
double d = sign(vector[2]) * sqrt(q) * (w + sqrt(sqrt(pow(t, 2) + v) - u * w - t / 2 - 1. / 4.));
|
||||
double N = a * sqrt(1 + epsilon2 * pow(d, 2) / pow(b, 2));
|
||||
latitude = asin((epsilon2 + 1) * d / N);
|
||||
altitude = rho * cos(latitude) + vector[2] * sin(latitude) - pow(a, 2) / N;
|
||||
longitude = atan2(vector[1], vector[0]);
|
||||
}
|
||||
|
@ -23,6 +23,12 @@ class CoordinateTransformations {
|
||||
|
||||
static void getEarthRotationMatrix(timeval timeUTC, double matrix[][3]);
|
||||
|
||||
static void cartesianFromLatLongAlt(const double lat, const double longi, const double alt,
|
||||
double* cartesianOutput);
|
||||
|
||||
static void latLongAltFromCartesian(const double* vector, double& latitude, double& longitude,
|
||||
double& altitude);
|
||||
|
||||
private:
|
||||
CoordinateTransformations();
|
||||
static void ecfToEci(const double* ecfCoordinates, double* eciCoordinates,
|
||||
|
@ -166,9 +166,9 @@ ReturnValue_t Sgp4Propagator::propagate(double* position, double* velocity, time
|
||||
timeval timeSinceEpoch = time - epoch;
|
||||
double minutesSinceEpoch = timeSinceEpoch.tv_sec / 60. + timeSinceEpoch.tv_usec / 60000000.;
|
||||
|
||||
double yearsSinceEpoch = minutesSinceEpoch / 60 / 24 / 365;
|
||||
double daysSinceEpoch = minutesSinceEpoch / 60 / 24;
|
||||
|
||||
if ((yearsSinceEpoch > 1) || (yearsSinceEpoch < -1)) {
|
||||
if ((daysSinceEpoch > 7) || (daysSinceEpoch < -7)) {
|
||||
return TLE_TOO_OLD;
|
||||
}
|
||||
|
||||
|
@ -70,8 +70,7 @@ ReturnValue_t LocalDataPoolManager::initialize(MessageQueueIF* queueToUse) {
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
ReturnValue_t LocalDataPoolManager::initializeAfterTaskCreation(uint8_t nonDiagInvlFactor) {
|
||||
setNonDiagnosticIntervalFactor(nonDiagInvlFactor);
|
||||
ReturnValue_t LocalDataPoolManager::initializeAfterTaskCreation() {
|
||||
return initializeHousekeepingPoolEntriesOnce();
|
||||
}
|
||||
|
||||
@ -506,9 +505,9 @@ ReturnValue_t LocalDataPoolManager::handleHousekeepingMessage(CommandMessage* me
|
||||
float newCollIntvl = 0;
|
||||
HousekeepingMessage::getCollectionIntervalModificationCommand(message, &newCollIntvl);
|
||||
if (command == HousekeepingMessage::MODIFY_DIAGNOSTICS_REPORT_COLLECTION_INTERVAL) {
|
||||
result = changeCollectionInterval(sid, newCollIntvl, true);
|
||||
result = changeCollectionInterval(sid, newCollIntvl);
|
||||
} else {
|
||||
result = changeCollectionInterval(sid, newCollIntvl, false);
|
||||
result = changeCollectionInterval(sid, newCollIntvl);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -661,10 +660,6 @@ ReturnValue_t LocalDataPoolManager::serializeHkPacketIntoStore(HousekeepingPacke
|
||||
return hkPacket.serialize(&dataPtr, serializedSize, maxSize, SerializeIF::Endianness::MACHINE);
|
||||
}
|
||||
|
||||
void LocalDataPoolManager::setNonDiagnosticIntervalFactor(uint8_t nonDiagInvlFactor) {
|
||||
this->nonDiagnosticIntervalFactor = nonDiagInvlFactor;
|
||||
}
|
||||
|
||||
void LocalDataPoolManager::performPeriodicHkGeneration(HkReceiver& receiver) {
|
||||
sid_t sid = receiver.dataId.sid;
|
||||
LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid);
|
||||
@ -718,15 +713,15 @@ ReturnValue_t LocalDataPoolManager::togglePeriodicGeneration(sid_t sid, bool ena
|
||||
|
||||
if ((LocalPoolDataSetAttorney::getReportingEnabled(*dataSet) and enable) or
|
||||
(not LocalPoolDataSetAttorney::getReportingEnabled(*dataSet) and not enable)) {
|
||||
return REPORTING_STATUS_UNCHANGED;
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
LocalPoolDataSetAttorney::setReportingEnabled(*dataSet, enable);
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
ReturnValue_t LocalDataPoolManager::changeCollectionInterval(sid_t sid, float newCollectionInterval,
|
||||
bool isDiagnostics) {
|
||||
ReturnValue_t LocalDataPoolManager::changeCollectionInterval(sid_t sid,
|
||||
float newCollectionInterval) {
|
||||
LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid);
|
||||
if (dataSet == nullptr) {
|
||||
printWarningOrError(sif::OutputTypes::OUT_WARNING, "changeCollectionInterval",
|
||||
@ -734,11 +729,6 @@ ReturnValue_t LocalDataPoolManager::changeCollectionInterval(sid_t sid, float ne
|
||||
return DATASET_NOT_FOUND;
|
||||
}
|
||||
|
||||
bool targetIsDiagnostics = LocalPoolDataSetAttorney::isDiagnostics(*dataSet);
|
||||
if ((targetIsDiagnostics and not isDiagnostics) or (not targetIsDiagnostics and isDiagnostics)) {
|
||||
return WRONG_HK_PACKET_TYPE;
|
||||
}
|
||||
|
||||
PeriodicHousekeepingHelper* periodicHelper =
|
||||
LocalPoolDataSetAttorney::getPeriodicHelper(*dataSet);
|
||||
|
||||
|
@ -102,7 +102,7 @@ class LocalDataPoolManager : public ProvidesDataPoolSubscriptionIF, public Acces
|
||||
* @param nonDiagInvlFactor
|
||||
* @return
|
||||
*/
|
||||
ReturnValue_t initializeAfterTaskCreation(uint8_t nonDiagInvlFactor = 5);
|
||||
ReturnValue_t initializeAfterTaskCreation();
|
||||
|
||||
/**
|
||||
* @brief This should be called in the periodic handler of the owner.
|
||||
@ -152,17 +152,6 @@ class LocalDataPoolManager : public ProvidesDataPoolSubscriptionIF, public Acces
|
||||
MessageQueueId_t targetQueueId,
|
||||
bool generateSnapshot) override;
|
||||
|
||||
/**
|
||||
* Non-Diagnostics packets usually have a lower minimum sampling frequency
|
||||
* than diagnostic packets.
|
||||
* A factor can be specified to determine the minimum sampling frequency
|
||||
* for non-diagnostic packets. The minimum sampling frequency of the
|
||||
* diagnostics packets,which is usually jusst the period of the
|
||||
* performOperation calls, is multiplied with that factor.
|
||||
* @param factor
|
||||
*/
|
||||
void setNonDiagnosticIntervalFactor(uint8_t nonDiagInvlFactor);
|
||||
|
||||
/**
|
||||
* @brief The manager is also able to handle housekeeping messages.
|
||||
* @details
|
||||
@ -185,6 +174,7 @@ class LocalDataPoolManager : public ProvidesDataPoolSubscriptionIF, public Acces
|
||||
ReturnValue_t generateHousekeepingPacket(sid_t sid, LocalPoolDataSetBase* dataSet,
|
||||
bool forDownlink,
|
||||
MessageQueueId_t destination = MessageQueueIF::NO_QUEUE);
|
||||
ReturnValue_t changeCollectionInterval(sid_t sid, float newCollectionInterval);
|
||||
|
||||
HasLocalDataPoolIF* getOwner();
|
||||
|
||||
@ -348,8 +338,6 @@ class LocalDataPoolManager : public ProvidesDataPoolSubscriptionIF, public Acces
|
||||
|
||||
void performPeriodicHkGeneration(HkReceiver& hkReceiver);
|
||||
ReturnValue_t togglePeriodicGeneration(sid_t sid, bool enable, bool isDiagnostics);
|
||||
ReturnValue_t changeCollectionInterval(sid_t sid, float newCollectionInterval,
|
||||
bool isDiagnostics);
|
||||
ReturnValue_t generateSetStructurePacket(sid_t sid, bool isDiagnostics);
|
||||
|
||||
void handleHkUpdateResetListInsertion(DataType dataType, DataId dataId);
|
||||
|
@ -250,9 +250,8 @@ void LocalPoolDataSetBase::setReportingEnabled(bool reportingEnabled) {
|
||||
bool LocalPoolDataSetBase::getReportingEnabled() const { return reportingEnabled; }
|
||||
|
||||
void LocalPoolDataSetBase::initializePeriodicHelper(float collectionInterval,
|
||||
dur_millis_t minimumPeriodicInterval,
|
||||
uint8_t nonDiagIntervalFactor) {
|
||||
periodicHelper->initialize(collectionInterval, minimumPeriodicInterval, nonDiagIntervalFactor);
|
||||
dur_millis_t minimumPeriodicInterval) {
|
||||
periodicHelper->initialize(collectionInterval, minimumPeriodicInterval);
|
||||
}
|
||||
|
||||
void LocalPoolDataSetBase::setChanged(bool changed) { this->changed = changed; }
|
||||
|
@ -191,8 +191,7 @@ class LocalPoolDataSetBase : public PoolDataSetBase, public MarkChangedIF {
|
||||
*/
|
||||
bool reportingEnabled = false;
|
||||
|
||||
void initializePeriodicHelper(float collectionInterval, dur_millis_t minimumPeriodicInterval,
|
||||
uint8_t nonDiagIntervalFactor = 5);
|
||||
void initializePeriodicHelper(float collectionInterval, dur_millis_t minimumPeriodicInterval);
|
||||
|
||||
/**
|
||||
* If the valid state of a dataset is always relevant to the whole
|
||||
|
@ -12,10 +12,8 @@ class LocalPoolDataSetAttorney {
|
||||
static bool isDiagnostics(LocalPoolDataSetBase& set) { return set.isDiagnostics(); }
|
||||
|
||||
static void initializePeriodicHelper(LocalPoolDataSetBase& set, float collectionInterval,
|
||||
uint32_t minimumPeriodicIntervalMs,
|
||||
uint8_t nonDiagIntervalFactor = 5) {
|
||||
set.initializePeriodicHelper(collectionInterval, minimumPeriodicIntervalMs,
|
||||
nonDiagIntervalFactor);
|
||||
uint32_t minimumPeriodicIntervalMs) {
|
||||
set.initializePeriodicHelper(collectionInterval, minimumPeriodicIntervalMs);
|
||||
}
|
||||
|
||||
static void setReportingEnabled(LocalPoolDataSetBase& set, bool enabled) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "fsfw/devicehandlers/AssemblyBase.h"
|
||||
|
||||
AssemblyBase::AssemblyBase(object_id_t objectId, object_id_t parentId, uint16_t commandQueueDepth)
|
||||
: SubsystemBase(objectId, parentId, MODE_OFF, commandQueueDepth),
|
||||
AssemblyBase::AssemblyBase(object_id_t objectId, uint16_t commandQueueDepth)
|
||||
: SubsystemBase(objectId, MODE_OFF, commandQueueDepth),
|
||||
internalState(STATE_NONE),
|
||||
recoveryState(RECOVERY_IDLE),
|
||||
recoveringDevice(childrenMap.end()),
|
||||
|
@ -41,7 +41,7 @@ class AssemblyBase : public SubsystemBase {
|
||||
static const ReturnValue_t NEED_TO_CHANGE_HEALTH = MAKE_RETURN_CODE(0x05);
|
||||
static const ReturnValue_t NOT_ENOUGH_CHILDREN_IN_CORRECT_STATE = MAKE_RETURN_CODE(0xa1);
|
||||
|
||||
AssemblyBase(object_id_t objectId, object_id_t parentId, uint16_t commandQueueDepth = 8);
|
||||
AssemblyBase(object_id_t objectId, uint16_t commandQueueDepth = 8);
|
||||
virtual ~AssemblyBase();
|
||||
|
||||
protected:
|
||||
|
@ -7,4 +7,5 @@ target_sources(
|
||||
DeviceHandlerFailureIsolation.cpp
|
||||
DeviceHandlerMessage.cpp
|
||||
DeviceTmReportingWrapper.cpp
|
||||
FreshDeviceHandlerBase.cpp
|
||||
HealthDevice.cpp)
|
||||
|
@ -3,17 +3,12 @@
|
||||
#include "fsfw/subsystem/SubsystemBase.h"
|
||||
|
||||
ChildHandlerBase::ChildHandlerBase(object_id_t setObjectId, object_id_t deviceCommunication,
|
||||
CookieIF* cookie, object_id_t hkDestination,
|
||||
uint32_t thermalStatePoolId, uint32_t thermalRequestPoolId,
|
||||
object_id_t parent, FailureIsolationBase* customFdir,
|
||||
size_t cmdQueueSize)
|
||||
CookieIF* cookie, HasModeTreeChildrenIF& parent,
|
||||
FailureIsolationBase* customFdir, size_t cmdQueueSize)
|
||||
: DeviceHandlerBase(setObjectId, deviceCommunication, cookie,
|
||||
(customFdir == nullptr ? &childHandlerFdir : customFdir), cmdQueueSize),
|
||||
parentId(parent),
|
||||
childHandlerFdir(setObjectId) {
|
||||
this->setHkDestination(hkDestination);
|
||||
this->setThermalStateRequestPoolIds(thermalStatePoolId, thermalRequestPoolId);
|
||||
}
|
||||
parent(parent),
|
||||
childHandlerFdir(setObjectId) {}
|
||||
|
||||
ChildHandlerBase::~ChildHandlerBase() {}
|
||||
|
||||
@ -23,21 +18,5 @@ ReturnValue_t ChildHandlerBase::initialize() {
|
||||
return result;
|
||||
}
|
||||
|
||||
MessageQueueId_t parentQueue = 0;
|
||||
|
||||
if (parentId != objects::NO_OBJECT) {
|
||||
SubsystemBase* parent = ObjectManager::instance()->get<SubsystemBase>(parentId);
|
||||
if (parent == NULL) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
parentQueue = parent->getCommandQueue();
|
||||
|
||||
parent->registerChild(getObjectId());
|
||||
}
|
||||
|
||||
healthHelper.setParentQueue(parentQueue);
|
||||
|
||||
modeHelper.setParentQueue(parentQueue);
|
||||
|
||||
return returnvalue::OK;
|
||||
return DeviceHandlerBase::connectModeTreeParent(parent);
|
||||
}
|
||||
|
@ -1,22 +1,23 @@
|
||||
#ifndef FSFW_DEVICEHANDLER_CHILDHANDLERBASE_H_
|
||||
#define FSFW_DEVICEHANDLER_CHILDHANDLERBASE_H_
|
||||
|
||||
#include <fsfw/subsystem/HasModeTreeChildrenIF.h>
|
||||
|
||||
#include "ChildHandlerFDIR.h"
|
||||
#include "DeviceHandlerBase.h"
|
||||
|
||||
class ChildHandlerBase : public DeviceHandlerBase {
|
||||
public:
|
||||
ChildHandlerBase(object_id_t setObjectId, object_id_t deviceCommunication, CookieIF* cookie,
|
||||
object_id_t hkDestination, uint32_t thermalStatePoolId,
|
||||
uint32_t thermalRequestPoolId, object_id_t parent = objects::NO_OBJECT,
|
||||
FailureIsolationBase* customFdir = nullptr, size_t cmdQueueSize = 20);
|
||||
HasModeTreeChildrenIF& parent, FailureIsolationBase* customFdir = nullptr,
|
||||
size_t cmdQueueSize = 20);
|
||||
|
||||
virtual ~ChildHandlerBase();
|
||||
|
||||
virtual ReturnValue_t initialize();
|
||||
|
||||
protected:
|
||||
const uint32_t parentId;
|
||||
HasModeTreeChildrenIF& parent;
|
||||
ChildHandlerFDIR childHandlerFdir;
|
||||
};
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user