Compare commits
989 Commits
Author | SHA1 | Date |
---|---|---|
Robin Müller | a1b6e2ff89 | |
Robin Müller | 8c87dafd5d | |
Robin Müller | 5ff161b70a | |
Robin Müller | 9a1e82de2a | |
Robin Müller | e9b4fc9825 | |
Robin Müller | 0660457c92 | |
Robin Müller | 7c9b9e4cd8 | |
Robin Müller | 3b0ee7ca31 | |
Robin Müller | fb2e480705 | |
Robin Müller | b8ae646060 | |
Robin Müller | f307a86d9a | |
Robin Müller | 8b21dd276d | |
Robin Müller | e00da212cd | |
Robin Müller | a229748aa4 | |
Robin Müller | e6e3753324 | |
Robin Müller | 94bd1ba2ab | |
Robin Müller | e12a8cfa29 | |
Robin Müller | efbcddc2e5 | |
Robin Müller | 31d4b85523 | |
Robin Müller | aff6bb673b | |
Robin Müller | f8e3777c43 | |
Robin Müller | 0e2fa8dc83 | |
Robin Müller | 0cfe559b93 | |
Robin Müller | c5159fb645 | |
Robin Müller | 203c0bac5c | |
Robin Müller | 6b70614762 | |
Jakob Meier | cc99d987a7 | |
Jakob Meier | babb02ebb6 | |
Jakob Meier | 41cdf3c1e8 | |
Jakob Meier | 383995939c | |
Jakob Meier | ede89de552 | |
Robin Müller | a8f8c1496c | |
Jakob Meier | 8aa539e67f | |
Robin Müller | 0bd88a2689 | |
Robin Müller | 008ded64b1 | |
Robin Müller | a3eb81f1de | |
Robin Müller | 24d41e7863 | |
Marius Eggert | 43ea29cb84 | |
Jakob Meier | 63a00b8b4f | |
Marius Eggert | 27c8a97d45 | |
Marius Eggert | 47b21caf5f | |
Marius Eggert | 2673070204 | |
Marius Eggert | 518a07d05b | |
Jakob Meier | 3f2d83d95c | |
Marius Eggert | 516357d855 | |
Marius Eggert | ac28b7e00d | |
Marius Eggert | 0d4a862c1a | |
Marius Eggert | b2576d3422 | |
Marius Eggert | bccaf4a9ea | |
Marius Eggert | 7d4e77843b | |
Robin Müller | cd2cd61ba5 | |
Marius Eggert | 90f3f8ef1f | |
Marius Eggert | 9894935e99 | |
Marius Eggert | a3a6c0720c | |
Marius Eggert | d5a52eadbb | |
Marius Eggert | b5e7179af1 | |
Marius Eggert | 5879eb7f7b | |
Robin Müller | a4943f1cf0 | |
Robin Müller | 4a3135e1bd | |
Robin Müller | e350bf6cec | |
Robin Müller | e64e8b274d | |
Robin Müller | 48bcce65b1 | |
Marius Eggert | 7105e199c6 | |
Marius Eggert | 94de483836 | |
Robin Müller | c648229c99 | |
Marius Eggert | 5b661551a8 | |
Robin Müller | 3978524181 | |
Robin Müller | 7187f2b5cd | |
Robin Müller | 8e367abb47 | |
Robin Müller | b28174db24 | |
Marius Eggert | c906acd659 | |
Marius Eggert | 8dfc84c0b5 | |
Marius Eggert | 74775bb59d | |
Robin Müller | c02d9e009e | |
Robin Müller | 0021aa29f5 | |
Ulrich Mohr | 41d67bff63 | |
Robin Müller | 8d7bb51d44 | |
Robin Müller | 7673d8b396 | |
Robin Müller | 91b194d8eb | |
Robin Müller | 698897bfc5 | |
Robin Müller | d554062b86 | |
Robin Müller | bf7fac071c | |
Robin Müller | 35be7da353 | |
Robin Müller | 18cc870c8e | |
Robin Müller | 133ca51d18 | |
Robin Müller | 0a40391a75 | |
Robin Müller | cc3e64e70d | |
Robin Müller | 6021257a87 | |
Robin Müller | 63c238005e | |
Marius Eggert | 0f604b35c6 | |
Marius Eggert | e3a815444e | |
Marius Eggert | 19093866ee | |
Mikael | f28ba61b02 | |
Mikael | cfd4b1655a | |
mikael.senger | 5cfc69a570 | |
Robin Müller | 497f947237 | |
Robin Müller | 5bd020193b | |
Robin Müller | 420c0625a5 | |
mikael.senger | 38d8fe772b | |
Robin Müller | 42a0b15303 | |
Robin Müller | c199cbedaa | |
Robin Müller | c4e18cc2f3 | |
Robin Müller | c143198494 | |
Robin Müller | 448fbd0d38 | |
Robin Müller | 470f589bde | |
Robin Müller | 33fccaaa54 | |
Robin Müller | 23bcfe0173 | |
Robin Müller | ec0c0a1cdd | |
Robin Müller | dfcfb035be | |
Robin Müller | 6e53582dc9 | |
Robin Müller | fb1500e041 | |
Robin Müller | ea2e58249d | |
Robin Müller | 9ef63825f3 | |
Robin Müller | 073cb4b3d5 | |
Robin Müller | 3c6102fb97 | |
Robin Müller | 734767045a | |
Robin Müller | 12f8cc5fc2 | |
Robin Müller | 1e78d6ce66 | |
Robin Müller | 845f040f13 | |
Robin Müller | 8c11685240 | |
Robin Müller | cb1aaea6cd | |
Robin Müller | 22df8f6147 | |
Robin Müller | 60dcacf432 | |
Robin Müller | b39e1c7e07 | |
Robin Müller | 036667a969 | |
Robin Müller | 67c38f327e | |
Robin Müller | e1816ed230 | |
Robin Müller | 5ff464252f | |
Robin Müller | cd8d64830c | |
Robin Müller | b7056a7467 | |
Robin Müller | 0fc2c7b5e9 | |
Robin Müller | eae7c44874 | |
Robin Müller | e4aae75747 | |
Robin Müller | b094ba145f | |
Robin Müller | 15629abf19 | |
Robin Müller | 7aeb25e064 | |
Robin Müller | d246ce34d0 | |
Marius Eggert | 796c7a9e37 | |
Robin Müller | 7c875f1067 | |
Robin Müller | e8451cac31 | |
Robin Müller | 8ddd6eb18d | |
Robin Müller | 6c6b552059 | |
Robin Müller | 9a1437980f | |
Robin Müller | 12e52a92f2 | |
Robin Müller | dffce43e6b | |
Robin Müller | daf75547a4 | |
Robin Müller | 0cccf26021 | |
Robin Müller | c075f27e20 | |
Robin Müller | 3167988951 | |
Robin Müller | a856f91c67 | |
Robin Müller | f49e607881 | |
Robin Müller | 0f208ec75a | |
Robin Müller | 5679b139ad | |
Robin Müller | 947f2b8685 | |
Robin Müller | 291c75c01f | |
Robin Müller | fde277cd06 | |
Robin Müller | bb186fc965 | |
Robin Müller | e8bf8b9575 | |
Robin Müller | 8f5a8b13d3 | |
Robin Müller | 314cba363f | |
Robin Müller | 244e2d0737 | |
Robin Müller | 8f0974d83e | |
Robin Müller | 8581f9a6f3 | |
Robin Müller | 844c90a625 | |
Robin Müller | 437851db3e | |
Robin Müller | e8b9897ee3 | |
Robin Müller | 33df8e8cc5 | |
Robin Müller | 52fc0958f7 | |
Robin Müller | 66704dc571 | |
Robin Müller | 0943863ec6 | |
Robin Müller | 2585028e75 | |
Robin Müller | 7bf7336d4a | |
Robin Müller | b0b6c68720 | |
Robin Müller | a1f36a0dd8 | |
Robin Müller | e4665c9394 | |
Robin Müller | 98cbf38432 | |
Robin Müller | 5d3f00da7f | |
Robin Müller | 69fd6d0f6a | |
Robin Müller | 045054fce0 | |
Robin Müller | 4c9e731113 | |
Robin Müller | e00e198ff1 | |
Robin Müller | 9c8434d856 | |
Robin Müller | 42c215ef70 | |
Robin Müller | 273fd3ebfd | |
Robin Müller | 6c9c4ee047 | |
Robin Müller | 1bfb695b41 | |
Robin Müller | 1561b9a247 | |
Robin Müller | 896b7a7358 | |
Robin Müller | 8e62143ac8 | |
Robin Müller | 1d97327f79 | |
Robin Müller | 5e9d402598 | |
Robin Müller | b53c48863f | |
Robin Müller | 4dc6398fd5 | |
Robin Müller | 8fcc4eab60 | |
Robin Müller | 972dc7e19e | |
Robin Müller | 06ef498a18 | |
Robin Müller | 6322a31566 | |
Robin Müller | 95b77ed826 | |
Robin Müller | 3b1da85229 | |
Robin Müller | 1cbcfc08ff | |
Robin Müller | d575da8540 | |
Robin Müller | ca27cef2ee | |
Robin Müller | 62ace649a7 | |
Robin Müller | aac74fae38 | |
Robin Müller | a26b0c38ac | |
Robin Müller | f44110a7f5 | |
Robin Müller | 35712070cf | |
Robin Müller | 1b79713430 | |
Robin Müller | a6cc5171da | |
Robin Müller | 9994c46e47 | |
Robin Müller | cf927ecee7 | |
Robin Müller | 42e74d22cc | |
Robin Müller | 36caa58043 | |
Robin Müller | 988e07f0be | |
Ulrich Mohr | 4ecd9eb62e | |
Robin Müller | fb89d7a3b6 | |
Robin Müller | 88e8665280 | |
Robin Müller | 9c8b1c697b | |
Robin Müller | 110cb903a6 | |
Robin Müller | 7e1fb04f8a | |
Robin Müller | 7f2411358d | |
Robin Müller | f0ee7772e8 | |
Robin Müller | 4fc06a1eaf | |
Robin Müller | a196c3387e | |
Robin Müller | f8fae1ac62 | |
Robin Müller | 1b23aa4246 | |
Robin Müller | 7d713219c5 | |
Robin Müller | 1be09a2310 | |
Robin Müller | 7add782470 | |
Marius Eggert | 8da89eba80 | |
Robin Müller | 7e8845f2c2 | |
Robin Müller | 6aff3250c2 | |
Robin Müller | c3572e31a8 | |
Robin Müller | 2293e7f2bb | |
Robin Müller | a85a38c882 | |
Robin Müller | 0f76cdb3ba | |
Robin Müller | 268c2e87c9 | |
Robin Müller | 87f94a252f | |
Ulrich Mohr | c7037d417a | |
Marius Eggert | f80c5980ea | |
Marius Eggert | ad01642fee | |
Robin Müller | f2947bc78e | |
Robin Müller | 0a977ea688 | |
Robin Müller | 74b164b1da | |
Robin Müller | 5322de0599 | |
Robin Müller | 9a4bf51006 | |
Robin Müller | 3a70229510 | |
Robin Müller | b3beedad9f | |
Robin Müller | efe217a197 | |
Robin Müller | b442ca09b9 | |
Ulrich Mohr | 146c3471d0 | |
Ulrich Mohr | 1816c3f623 | |
Ulrich Mohr | d03d5aa74c | |
Ulrich Mohr | 26e97ddf89 | |
Ulrich Mohr | be3a57a795 | |
Ulrich Mohr | 13b97abf0d | |
jgerhards | 64922367e4 | |
Robin Müller | cb6eed134b | |
Ulrich Mohr | f95c373076 | |
Ulrich Mohr | e03731bcf8 | |
Robin Müller | 9fe8579377 | |
Robin Müller | f42a16748d | |
Robin Müller | e8095f82c6 | |
Robin Müller | 9372b2a575 | |
Robin Müller | 2714e588d7 | |
Robin Müller | e905288adc | |
Robin Müller | 3805ea50a7 | |
Robin Müller | 699bd694cd | |
Robin Müller | 0b39ab383f | |
Marius Eggert | aafa53148e | |
Robin Müller | e0adb3325f | |
Robin Müller | 82eaf4412f | |
Robin Müller | 4391823f01 | |
Robin Müller | 1a77e6bb09 | |
Robin Müller | cae131edcf | |
Ulrich Mohr | 4518fec65c | |
Ulrich Mohr | dac1aacab2 | |
Ulrich Mohr | 0042f92fdf | |
Ulrich Mohr | 656faf8169 | |
Ulrich Mohr | f84431e965 | |
Ulrich Mohr | 0cec9ebb73 | |
Ulrich Mohr | a440b7c394 | |
Ulrich Mohr | bbfc1b2b34 | |
Robin Müller | 025b379e8b | |
Robin Müller | 52c3246416 | |
Robin Müller | b673cdfb50 | |
Marius Eggert | 258f0d3313 | |
Robin Müller | 5eb9ee8bc1 | |
Robin Müller | 7f61d17cee | |
Robin Müller | ffa2fa477f | |
Robin Müller | 894d1e3b87 | |
Robin Müller | 285d327b97 | |
Robin Müller | e97fa5ac84 | |
Robin Müller | 5a9304765f | |
Robin Müller | 6650c293da | |
Robin Müller | 9fca7581dd | |
Robin Müller | 4af90f99f3 | |
Robin Müller | 94cdf67a80 | |
Robin Müller | 7966ede11b | |
Robin Müller | 7a392dc33a | |
Robin Müller | 1e3c89b672 | |
Robin Müller | e2e87b149d | |
Robin Müller | 4f632e2c68 | |
Robin Müller | 314f0fa2cd | |
Robin Müller | b31e1037fb | |
Robin Müller | b814e7198f | |
Robin Müller | 6328b70d7b | |
Robin Müller | a937b457f9 | |
Robin Müller | 4415dc24e1 | |
Robin Müller | e704295cce | |
Robin Müller | d16b3c7e67 | |
Robin Müller | 3b86545725 | |
Robin Müller | cf6150cc18 | |
Robin Müller | bfb5c2ff03 | |
Robin Müller | bf02061d47 | |
Robin Müller | 2c4e110254 | |
Robin Müller | 7ed75ea87b | |
Robin Müller | db4587bb59 | |
Robin Müller | 33ac395072 | |
Robin Müller | f8a7c1d4ed | |
Robin Müller | 341437df13 | |
Robin Müller | 227524a21d | |
Robin Müller | c35a0a8541 | |
Robin Müller | 0f81d5e458 | |
Robin Müller | e0a072859b | |
Robin Müller | b50f092939 | |
Robin Müller | 2f90e12179 | |
Robin Müller | 8b77fac099 | |
Robin Müller | 47503824d7 | |
Robin Müller | 5e3f5c4121 | |
Robin Müller | 1f36c082ef | |
Robin Müller | aa84e93603 | |
Robin Müller | 8f63a0e747 | |
Robin Müller | 6fc8f756a7 | |
Robin Müller | 067cb7d0f8 | |
Robin Müller | d98ed40e3d | |
Robin Müller | 2c17af4ef8 | |
Robin Müller | 110fb43b9c | |
Robin Müller | b057250bfb | |
Robin Müller | 066dd0d397 | |
Robin Müller | f735c2e9d4 | |
Robin Müller | 43fd0b2f59 | |
Robin Müller | d0607824ad | |
Robin Müller | cf27954a86 | |
Robin Müller | f84e3284ab | |
Robin Müller | 5250423d1d | |
Robin Müller | 522bd41d6e | |
Robin Müller | c61c85280b | |
Robin Müller | afbe5e1f65 | |
Robin Müller | 4c88ab80c8 | |
Robin Müller | 5ba69b169f | |
Robin Müller | 40405fe6c7 | |
Robin Müller | aac32e763c | |
Robin Müller | bf980d74c0 | |
Robin Müller | b6b9d1d790 | |
Robin Müller | 0973ba6bf2 | |
Robin Müller | 1cfebb5d47 | |
Robin Müller | 0b0a0299bc | |
Robin Müller | 8382d61b92 | |
Robin Müller | 7208343b6d | |
Robin Müller | 9a8d775eb1 | |
Robin Müller | 4d6f6e6b23 | |
Robin Müller | 55f6825a03 | |
Robin Müller | c162acb7df | |
Robin Müller | 87462afe6d | |
Robin Müller | a8de395ea0 | |
Ulrich Mohr | f0bddfcb21 | |
Robin Müller | 23d9b44b3e | |
Robin Müller | 26e4445189 | |
Robin Müller | 9ee3cdf729 | |
Robin Müller | 1b7493f945 | |
Robin Müller | 7f6ba5f40b | |
Robin Müller | 070b48ada2 | |
Robin Müller | d9a139e1ef | |
Robin Müller | c80a3752d9 | |
Robin Müller | af58c414fc | |
Robin Müller | 4c48668125 | |
Robin Müller | 2745b2080d | |
Robin Müller | e9d9f44605 | |
Robin Müller | 2c5af91db1 | |
Robin Müller | 5cd7b98ba7 | |
Robin Müller | a39f1271ec | |
Robin Müller | bbf0d7a0d2 | |
Robin Müller | 04ee3c7362 | |
Robin Müller | 95dab69b35 | |
Robin Müller | 33de15205b | |
Robin Müller | 4d353a1ad2 | |
Robin Müller | 6006c97e48 | |
Robin Müller | 6e17e45506 | |
Jakob Meier | 64537d442a | |
Jakob Meier | 78cf00315d | |
Robin Müller | 245886c555 | |
Robin Müller | f84097543e | |
Robin Müller | 511d07c0c7 | |
Robin Müller | cf735143fe | |
Robin Müller | bdfe31dba4 | |
Robin Müller | 216f603d62 | |
Robin Müller | 174a6aa862 | |
Robin Müller | c2d9370aa1 | |
Robin Müller | 893b434728 | |
Marius Eggert | 6eba84566d | |
Robin Müller | f0415a97b1 | |
Robin Müller | abcf1b29b2 | |
Robin Müller | d373c45d36 | |
Robin Müller | bd208038dd | |
Robin Müller | 206af00c8b | |
Robin Müller | 2efff4d2c5 | |
Robin Müller | 2a0c244468 | |
Robin Müller | e1711f0345 | |
Robin Müller | c327985222 | |
Robin Müller | b45206ccd6 | |
Robin Müller | c8469ca647 | |
Robin Müller | 2d6622b8b8 | |
Robin Müller | 5f9eb01d94 | |
Robin Müller | 3568bdbecf | |
Robin Müller | fcd84b59ae | |
Robin Müller | e3c968096b | |
Robin Müller | c745c0c8b4 | |
Robin Müller | be015b4c66 | |
Robin Müller | dae5e988fd | |
Robin Müller | a6d707a7db | |
Robin Müller | fe41d73895 | |
Robin Müller | 70b785984c | |
Robin Müller | 9de6c4b3aa | |
Robin Müller | d256ede8c1 | |
Robin Müller | f0b8457ba2 | |
Robin Müller | dac2d210b5 | |
Robin Müller | 8b4f73a97b | |
Robin Müller | 7fae6cbd6d | |
Robin Müller | d302ba7185 | |
Robin Müller | 14a92b3d89 | |
Robin Müller | e4fd424d66 | |
Robin Müller | 341a66c265 | |
Robin Müller | b9b076aa4c | |
Robin Müller | d93486a340 | |
Robin Müller | 820a7f059c | |
Robin Müller | f4d188c36f | |
Robin Müller | 1841f92944 | |
Robin Müller | b279985859 | |
Robin Müller | 6ce80ea6c5 | |
Robin Müller | 6f05d6b7b0 | |
Robin Müller | 7f907fb9d3 | |
Robin Müller | 84bbef0167 | |
Robin Müller | 88b2b0e005 | |
Robin Müller | 84dc7ac0ce | |
Robin Müller | ec12ab5daa | |
Robin Müller | 69c94645df | |
Robin Müller | 37e850c5a7 | |
Robin Müller | a1567de9e8 | |
Robin Müller | 2646707d3f | |
Robin Müller | 06e30684fe | |
Robin Müller | 06dca7608a | |
Robin Müller | 6af5274b68 | |
Robin Müller | 38789e053b | |
Robin Müller | e11eabdbcf | |
Robin Müller | 3250bbf269 | |
Robin Müller | a78fe0a7f3 | |
Marius Eggert | acfc1cbf21 | |
Marius Eggert | d17ec02cf0 | |
Robin Müller | f2461cd7e9 | |
Robin Müller | 01cc619e67 | |
Robin Müller | 2339712373 | |
Robin Müller | d9d253d3bb | |
Robin Müller | bd586f6564 | |
Robin Müller | 5f481739d8 | |
Robin Müller | 7ee83e4e5d | |
Robin Müller | 64787f85ca | |
Robin Müller | 1cacceddad | |
Robin Müller | 5c35b8e3cd | |
Robin Müller | 7766b24a1d | |
Robin Müller | 9a4ae550ab | |
Robin Müller | c64b9b3e71 | |
Robin Müller | 226818886f | |
Robin Müller | da12495335 | |
Robin Müller | 0cc3231ceb | |
Robin Müller | 049e3b431d | |
Robin Müller | bd189518b6 | |
Robin Müller | accaf855ee | |
Robin Müller | 75fa7caf25 | |
Robin Müller | 041d1b8795 | |
Robin Müller | 5bb66c9723 | |
Robin Müller | a486559313 | |
Robin Müller | 2aa4af6974 | |
Robin Müller | 75fc7a056d | |
Robin Müller | 05cad893a2 | |
Robin Müller | 1b005d706a | |
Robin Müller | 5b0ea91222 | |
Robin Müller | e68f54b9bd | |
Robin Müller | 8eb869e073 | |
Robin Müller | 46a1c2bace | |
Robin Müller | 2643ff194c | |
Robin Müller | 296bc56e2a | |
Robin Müller | 160ff799ac | |
Robin Müller | c5f91926c9 | |
Robin Müller | be4a87535d | |
Robin Müller | 99927b8e95 | |
Robin Müller | 5e5eb82830 | |
Robin Müller | 686dc97234 | |
Robin Müller | 1f58ba1f9b | |
Robin Müller | 002845108d | |
Robin Müller | 2b6a33e718 | |
Robin Müller | 61fd5d1b62 | |
Robin Müller | 046dbe1deb | |
Robin Müller | e03e7f5260 | |
Robin Müller | 0303c1a885 | |
Robin Müller | 4d2802a470 | |
Robin Müller | 39946bff58 | |
Robin Müller | 2a203ae13d | |
Robin Müller | 6ca1a5c796 | |
Robin Müller | 194b3e100a | |
Robin Müller | 177c39dd53 | |
Robin Müller | 530a261e14 | |
Robin Müller | 31defac17c | |
Robin Müller | ce387deee7 | |
Robin Müller | 72793abfd3 | |
Robin Müller | 0e8f5ddd26 | |
Robin Müller | 672fca5169 | |
Robin Müller | 84b9d1ce21 | |
Robin Müller | e5b5c7d253 | |
Robin Müller | 9a0cc64be3 | |
Robin Müller | 00f1c5bbe9 | |
Robin Müller | 8a61af779d | |
Robin Müller | 6efa482eb0 | |
Robin Müller | f0fa1bf477 | |
Robin Müller | 91ebf98c28 | |
Robin Müller | e1d4209fbe | |
Robin Müller | e302c89f74 | |
Robin Müller | a38279f813 | |
Robin Müller | 7600ed1ea7 | |
Robin Müller | 61ab770d9d | |
Robin Müller | 033676ad3b | |
Robin Müller | e2eeccce50 | |
Robin Müller | f805667779 | |
Robin Müller | af06969905 | |
Robin Müller | 2461209169 | |
Robin Müller | 852f27cec2 | |
Robin Müller | 226dc4d8b7 | |
Robin Müller | fa01798ebb | |
Robin Müller | 1b7e94d718 | |
Robin Müller | 60ff411721 | |
Ulrich Mohr | bddc7a7ca6 | |
Robin Müller | 819a2bfac4 | |
Robin Müller | 1f05e6b297 | |
Robin Müller | b0c5a49b50 | |
Robin Müller | 096af44e39 | |
Robin Müller | 56e8e5a8b3 | |
Robin Müller | 11422a658c | |
Robin Müller | 754b71a35f | |
Robin Müller | 2de9e25ceb | |
Robin Müller | ec7566fb8c | |
Robin Müller | 73454c629c | |
Robin Müller | 0c5c2f6c4f | |
Robin Müller | 009700ce80 | |
Robin Müller | 1e43296f2b | |
Robin Müller | 1aa062df7f | |
Robin Müller | 14a8924a83 | |
Robin Müller | 9f81926aec | |
Robin Müller | 79c38b45df | |
Robin Müller | e893e73f86 | |
Robin Müller | 1d6ccfe5ab | |
Robin Müller | 221df7ece6 | |
Robin Müller | 7f180ac1fa | |
Robin Müller | 692be9df8d | |
Robin Müller | 8195587604 | |
Robin Müller | 40e7b2dc31 | |
Robin Müller | 1c53b60442 | |
Robin Müller | d1630cdc4c | |
Robin Müller | 49747fc8a4 | |
Robin Müller | cfc00d0260 | |
Robin Müller | 1eceef4645 | |
Robin Müller | acab5f6bce | |
Robin Müller | 10dd855244 | |
Robin Müller | f824004897 | |
Robin Müller | 7c5308429c | |
Robin Müller | f78344b8fb | |
Robin Müller | b9d0ff8fb7 | |
Robin Müller | 77f7fa2ef1 | |
Robin Müller | 78314ad966 | |
Robin Müller | 227535c461 | |
Robin Müller | c47bed0760 | |
Robin Müller | 9927dbb2e4 | |
Robin Müller | 14a48fe41d | |
Robin Müller | c932e51818 | |
Robin Müller | 2ca8d72e83 | |
Robin Müller | 03e1a93250 | |
Robin Müller | 6d2f44a432 | |
Robin Müller | 808e3e0462 | |
Robin Müller | 79ab0c4aa5 | |
Robin Müller | c5b24f2516 | |
Robin Müller | bdbe0cc9da | |
Robin Müller | e2c1158337 | |
Robin Müller | 95aac7dc8d | |
Robin Müller | 3d2fc28468 | |
Robin Müller | 1898b4f2db | |
Robin Müller | c38088c64b | |
Robin Müller | 7eb63d6d79 | |
Robin Müller | 1d54507517 | |
Robin Müller | ef9ed95fd1 | |
Robin Müller | ed68268c0c | |
Robin Müller | c549914efb | |
Robin Müller | 753d5ff39e | |
Robin Müller | 36ca35da77 | |
Robin Müller | 4fb7375492 | |
Robin Müller | 47df9e8b5b | |
Robin Müller | 7e0a5d5a9e | |
Robin Müller | ee1c6a3f04 | |
Robin Müller | 86aafe4422 | |
Robin Müller | dbaeed83af | |
Robin Müller | 385a0ffd73 | |
Ulrich Mohr | bd594123a2 | |
Robin Müller | cf8fe7ea72 | |
Robin Müller | 496dac89e4 | |
Robin Müller | cfca27542a | |
Robin Müller | 2fa76d3663 | |
Robin Müller | 726f44cafe | |
Robin Müller | 141dcb1f14 | |
Robin Müller | 6ebd6a965b | |
Robin Müller | 20f0707813 | |
Robin Müller | 8d1777fa0c | |
Robin Müller | 21ac86619e | |
Robin Müller | eedf57624f | |
Robin Müller | ae40543e3a | |
Robin Müller | efd2994dc5 | |
Robin Müller | 3ebebbd493 | |
Robin Müller | a8c066dccc | |
Robin Müller | 4d17f1c4bb | |
Robin Müller | d4ed528426 | |
Robin Müller | e10e71cee9 | |
Robin Müller | d675a789a2 | |
Robin Müller | 6b8c83be29 | |
Robin Müller | 093052604a | |
Robin Müller | 192255df1c | |
Robin Müller | bdd79d060d | |
Robin Müller | 3a47062f2a | |
Robin Müller | 9a590a3fcd | |
Robin Müller | 2a75440b32 | |
Robin Müller | f5866ddace | |
Robin Müller | f91ad84bdc | |
Robin Müller | 7881f5bab8 | |
Robin Müller | 34c714eb17 | |
Robin Müller | 7205885357 | |
Robin Müller | 42c5881c50 | |
Robin Müller | cdd0ca70ed | |
Robin Müller | e3648b6e30 | |
Robin Müller | d815f422c3 | |
Robin Müller | d975958120 | |
Robin Müller | c57e95c698 | |
Robin Müller | 4d82d0e4c1 | |
Robin Müller | 007f958a0b | |
Robin Müller | d022ce82c5 | |
Robin Müller | b28091e05b | |
Robin Müller | f4c4f9946c | |
Robin Müller | 7f89022f5b | |
Robin Müller | fdcfd89ed2 | |
Robin Müller | 03fa77e2b3 | |
Robin Müller | 8970a7379a | |
Robin Müller | 904ae2cc0e | |
Robin Müller | 4a2012ac30 | |
Robin Müller | 0b17a2e74e | |
Robin Müller | ec1d64e061 | |
Robin Müller | a16b77daf0 | |
Robin Müller | 830b907910 | |
Robin Müller | b762f97bfb | |
Jakob Meier | 6a62cf7f1e | |
Robin Müller | c5eb09314f | |
Robin Müller | 682abd1b5b | |
Robin Müller | a4247cd723 | |
Robin Müller | 39881e7671 | |
Robin Müller | 5abbf42e9f | |
Irini Kosmidou | 1910a7838c | |
Irini Kosmidou | ba3a99466a | |
Robin Müller | 438efe074e | |
Robin Müller | 1759700b6a | |
Robin Müller | c7618294ac | |
Jakob Meier | af890c6218 | |
Jakob Meier | 7f3e5e42bb | |
Robin Müller | 5bd3abed8b | |
Robin Müller | eb46f0c473 | |
Robin Müller | 15d69e64f3 | |
Robin Müller | d74bcbb1f8 | |
Robin Müller | c00cb1680d | |
Robin Müller | 7109422e2c | |
Robin Müller | efd12544df | |
Jakob Meier | cda81fc841 | |
Robin Müller | b9fbb4fd4c | |
Robin Müller | 5a69c1f8b9 | |
Robin Müller | 1d1d91f591 | |
Robin Müller | 043b8b5b3f | |
Jakob Meier | 95a64e1da3 | |
Jakob Meier | ab68817e9a | |
Jakob Meier | 36652e6fce | |
Jakob Meier | 3749f31ab4 | |
Jakob Meier | ebbe08639c | |
Jakob Meier | d286fc1855 | |
Robin Müller | cf35cca923 | |
Robin Müller | 2058817ba5 | |
Robin Müller | c328891030 | |
Jakob Meier | 76a459a02c | |
Jakob Meier | fbec1b3dc9 | |
Robin Müller | c4fa7281ae | |
Robin Müller | ac62443f31 | |
Robin Müller | 8cfe848dfe | |
Robin Müller | af7c6c57a3 | |
Robin Müller | c835525196 | |
Robin Müller | 24069dfd78 | |
Robin Müller | 40cc557978 | |
Jakob Meier | 4b128d2435 | |
Robin Müller | f35b0ffbbd | |
Robin Müller | 9368ae81e5 | |
Robin Müller | b8b7756a3e | |
Robin Müller | 4cc108f3a1 | |
Robin Müller | c0292f072e | |
Jakob Meier | 336ad9b7be | |
Robin Müller | 942bfafaa3 | |
Robin Müller | 3a16290707 | |
Robin Müller | 08f1ebf9fc | |
Robin Müller | 64e7d4bb5e | |
Robin Müller | 1886da0d3f | |
Robin Müller | b47eb0a7ff | |
Robin Müller | b1e30ae9ff | |
Robin Müller | 86ca4f246b | |
Robin Müller | e87b5a0207 | |
Robin Müller | d504589c3c | |
Robin Müller | 7b3de87364 | |
Jakob Meier | e758f0be2e | |
Robin Müller | 18b342e94b | |
Robin Müller | f9c42d3583 | |
Robin Müller | d267a3651b | |
Robin Müller | e8023886f6 | |
Robin Müller | 14a1b4a7ac | |
Robin Müller | e49de9422a | |
Robin Müller | 618f76ae78 | |
Robin Müller | ee2f8d6956 | |
Jakob Meier | 0ea044c203 | |
Robin Müller | 4b323053ec | |
Robin Müller | 55ed7ab93e | |
Robin Müller | bcd19045cc | |
Robin Müller | dba08fed7a | |
Robin Müller | 7df1922633 | |
Robin Müller | 4841d5d92d | |
Jakob Meier | ac78a79ca2 | |
Jakob Meier | bf7388c059 | |
Robin Müller | c2de911efa | |
Robin Müller | fc2b709148 | |
Robin Müller | 02473a0cd7 | |
Robin Müller | ab45aa1296 | |
Jakob Meier | c0ff84bb9d | |
Robin Müller | d1ff32bf96 | |
Robin Müller | dafcaa6007 | |
Robin Müller | 5eb52133ac | |
Robin Müller | 025e7647d3 | |
Robin Müller | 0a97077a0e | |
Jakob Meier | bc994595da | |
Robin Müller | ab2d7ca98f | |
Robin Müller | 56e4fca06f | |
Robin Müller | e06c457743 | |
Robin Müller | 5941c21adf | |
Robin Müller | 0e880de0d0 | |
Robin Müller | 29c3a43760 | |
Robin Müller | d72b212fa6 | |
Jakob Meier | 43f0841d0a | |
Robin Müller | 9e5fb64d0e | |
Robin Müller | 71f704c980 | |
Robin Müller | a72cc487df | |
Robin Müller | de2d4da161 | |
Jakob Meier | 19bd26d998 | |
Robin Müller | f59b05c86c | |
Jakob Meier | 80cb0e682f | |
Jakob Meier | 8ee26f81f9 | |
Jakob Meier | 3556eca8e8 | |
Jakob Meier | a9041b84a3 | |
Jakob Meier | 83d9dbc052 | |
Robin Müller | 2220120d54 | |
Robin Müller | 15eb22f9ee | |
Robin Müller | 7f6c8b8b12 | |
Jakob Meier | 789668ae50 | |
Jakob Meier | 7760b3063e | |
Jakob Meier | d04f88bee0 | |
Jakob Meier | e867d09111 | |
Jakob Meier | 43aad11859 | |
Robin Müller | 3225a8e350 | |
Robin Müller | 1c4ea6dd0d | |
Robin Müller | e2eb4bfea4 | |
Jakob Meier | 41682aab3f | |
Jakob Meier | d61fe7db93 | |
Robin Müller | c1be1fe232 | |
Robin Müller | ec2e274f22 | |
Robin Müller | c5a7b98a7d | |
Robin Müller | 6a8da303fb | |
Robin Müller | 3d047f9629 | |
Robin Müller | 1739edd9b0 | |
Robin Müller | 466a3639a5 | |
Jakob Meier | 900ef5b912 | |
Jakob Meier | 280b641cbc | |
Robin Müller | 24ef96d1b8 | |
Robin Müller | befaca78c6 | |
Robin Müller | af4f002a25 | |
Jakob Meier | 9f7b9be800 | |
Jakob Meier | 2c0f3b52e9 | |
Jakob Meier | aa1ea33647 | |
Jakob Meier | 9798b6b4ab | |
Robin Müller | f0d7eaf35a | |
Robin Müller | b128ef9da9 | |
Robin Müller | 085213c60f | |
Jakob Meier | 613dbe9592 | |
Jakob Meier | e949368b06 | |
Jakob Meier | 4d49cb6a3c | |
Robin Müller | e0c9bf5871 | |
Robin Müller | 935a8e13a5 | |
Robin Müller | 5ff88129b8 | |
Jakob Meier | ce17be63f4 | |
Jakob Meier | 2734d9d758 | |
Robin Müller | c45328b34d | |
Robin Müller | 478b305fbe | |
Jakob Meier | 28e93696df | |
Robin Müller | 942d1e5e4b | |
Jakob Meier | 6ce09e968d | |
Robin Müller | 290db6ccad | |
Robin Müller | 94ed582297 | |
Robin Müller | 47ced1efac | |
Jakob Meier | 85a6e4b129 | |
Robin Müller | f94bc02b6c | |
Robin Müller | 5bda877d97 | |
Jakob Meier | 51e7f1c2f2 | |
Robin Müller | a11d7455df | |
Robin Müller | 4dc903fe20 | |
Robin Müller | 3325cc18fc | |
Robin Müller | 43917d98c0 | |
Robin Müller | e3ffcae3e0 | |
Robin Müller | 0677de39aa | |
Robin Müller | aded4fae1e | |
Jakob Meier | 7df51f7202 | |
Robin Müller | 7530c44849 | |
Robin Müller | e4c6a69f77 | |
Robin Müller | 761a0c9bac | |
Robin Müller | 518666f822 | |
Jakob Meier | 318cd8e244 | |
Robin Müller | 1bc7a91869 | |
Robin Müller | 8e26e287c3 | |
Robin Müller | ce2f7c4fdf | |
Robin Müller | b3d2d440d7 | |
Jakob Meier | fbf9626fde | |
Jakob Meier | 29cf8c9009 | |
Jakob Meier | 61d0815de8 | |
Robin Müller | 127fbeb980 | |
Robin Müller | c2581ff4f5 | |
Robin Müller | 7b6f68c509 | |
Jakob Meier | 532607bf8f | |
Jakob Meier | a230dc4313 | |
Robin Müller | 3ea9f999b7 | |
Robin Müller | 79f3c7324a | |
Robin Müller | 60972228ef | |
Robin Müller | 6ea1eabb2d | |
Robin Müller | 283a37dccc | |
Robin Müller | acf0cdfba3 | |
Robin Müller | a01002aa5d | |
Jakob Meier | b52f19254b | |
Robin Müller | 79615e47e4 | |
Jakob Meier | e6130263ef | |
Robin Müller | 6895dbcc81 | |
Robin Müller | 4b5e3e70f7 | |
Robin Müller | bbe21e7e89 | |
Robin Müller | 2823420c46 | |
Robin Müller | 6dd6f28db0 | |
Robin Müller | d791fc87b7 | |
Robin Müller | 16f2fa9327 | |
Robin Müller | 927041209b | |
Jakob Meier | bac8b40880 | |
Jakob Meier | caf78835b2 | |
Robin Müller | b6ed45a85c | |
Robin Müller | ddc1cdb1f5 | |
Robin Müller | 543daaa95a | |
Robin Müller | 38c87fdeb2 | |
Robin Müller | 5ca5fe4040 | |
Jakob Meier | 1b7e0371c3 | |
Jakob Meier | d4ade5e885 | |
Robin Müller | fec5f83f4f | |
Robin Müller | 17262a1da9 | |
Robin Müller | b5d6b9745f | |
Robin Müller | 60639f56dc | |
Robin Müller | 3aa0bbde68 | |
Robin Müller | 97bc71a3ff | |
Robin Müller | 06577ed78a | |
Robin Müller | b27f3b84aa | |
Robin Müller | 9509847b84 | |
Robin Müller | 45b51f9ac8 | |
Jakob Meier | d5ff6da40b | |
Jakob Meier | e498136273 | |
Robin Müller | 47d158156b | |
Robin Müller | d63c01b96f | |
Robin Müller | 3b497dbb8d | |
Robin Müller | bf733162eb | |
Jakob Meier | 73f0b9c0dc | |
Jakob Meier | b5e55f64b0 | |
Robin Müller | 7ca6d1a695 | |
Robin Müller | cc3210f366 | |
Robin Müller | 155d66e534 | |
Robin Müller | d4c76a7e46 | |
Robin Müller | dba3c27b99 | |
Robin Müller | 202cfc6dbb | |
Robin Müller | 84f95e8d76 | |
Jakob Meier | 6de4798805 | |
Robin Müller | 82a645deba | |
Robin Müller | 8b1c277c58 | |
Jakob Meier | 5f23f709cc | |
Robin Müller | a7cb2d4354 | |
Robin Müller | 7571987a1d | |
Robin Müller | d6c1041133 | |
Robin Müller | 3c53e2c259 | |
Robin Müller | 45f0d7fd45 | |
Robin Müller | aebab4c73c | |
Robin Müller | c3c2e1c0dd | |
Robin Müller | 4e6c1cb72a | |
Robin Müller | e2eb6a46b6 | |
Jakob Meier | 75c56280ad | |
Robin Müller | 0ccaf27fcb | |
Robin Müller | e05e203c83 | |
Robin Müller | ac036b2a70 | |
Robin Müller | 2d9216ba19 | |
Robin Müller | 2fed161eff | |
Robin Müller | 4cf2a384f3 | |
Robin Müller | 27267b7cb0 | |
Robin Müller | 505e00c067 | |
Robin Müller | 68225586d2 | |
Robin Müller | 6d825a1aa6 | |
Robin Müller | fa73ad6731 | |
Robin Müller | 331aa9442d | |
Robin Müller | 28b28b5684 | |
Robin Müller | afd3a942e2 | |
Robin Müller | 729bcc4aaf | |
Robin Müller | 6e0b90696d | |
Jakob Meier | eacb4ac407 | |
Jakob Meier | 09c1918c1f | |
Robin Müller | 123f2ff360 | |
Robin Müller | 7ce2c1b624 | |
Robin Müller | 4747e54c5d | |
Robin Müller | 2e230daa14 | |
Robin Müller | e909c6b6f7 | |
Robin Müller | d88d7c938f | |
Robin Müller | 389641f8fd | |
Robin Müller | b440c30223 | |
Robin Müller | 3966b656e9 | |
Robin Müller | 3a5881a0cb | |
Robin Müller | 1e982ec00b | |
Robin Müller | 701135e2a6 | |
Jakob Meier | 19f8e41c7f | |
Robin Müller | c4a055986c | |
Robin Müller | d74a373f1d | |
Robin Müller | cf69af4e7e | |
Robin Müller | 508979d32d | |
Robin Müller | 0d66569687 | |
Robin Müller | a5871ed0b1 | |
Robin Müller | a12e98d948 | |
Robin Müller | bd05afbddd | |
Robin Müller | b3482eba24 | |
Robin Müller | 9e92afbf07 | |
Robin Müller | 0d6d44f72f | |
Robin Müller | 81f5b0c3bf | |
Robin Müller | 062e93fd88 | |
Robin Müller | c20bf31d5d | |
Jakob Meier | 3c06d2dbbb | |
Jakob Meier | 018d814f29 | |
Jakob Meier | c0648a789b | |
Jakob Meier | 9579e94a71 | |
Jakob Meier | 235fd79dfb | |
Jakob Meier | 83635d3667 | |
Robin Müller | 581ae4c990 | |
Robin Müller | 32a9e0c704 | |
Robin Müller | 940c53eba6 | |
Robin Müller | 0d4bd856bd | |
Robin Müller | b7f6a6961b | |
Robin Müller | a910a05541 | |
Robin Müller | 973996e102 | |
Robin Müller | b3aee76d91 | |
Robin Müller | b3151a0ba0 | |
Robin Müller | fca48257b7 | |
Robin Müller | 8f95b03e6a | |
Robin Müller | 527dba9a9d | |
Robin Müller | 22cd38fffd | |
Robin Müller | 1a518109d0 | |
Robin Müller | 8030d9ac1b | |
Robin Müller | 992c05df56 | |
Robin Müller | 6698d283b6 | |
Robin Müller | 33386550cf | |
Robin Müller | 3a65c0db91 | |
Robin Müller | 41614303d7 | |
Robin Müller | 783176848a | |
Robin Müller | 07cb980e06 | |
Robin Müller | d8c5bd125e |
|
@ -1,5 +1,5 @@
|
|||
# PyCharm and CLion
|
||||
/.idea/*
|
||||
.idea/*
|
||||
!/.idea/runConfigurations
|
||||
!/.idea/cmake.xml
|
||||
!/.idea/codeStyles
|
||||
|
|
|
@ -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>
|
50
CHANGELOG.md
50
CHANGELOG.md
|
@ -8,6 +8,54 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||
|
||||
# [unreleased]
|
||||
|
||||
## Fixes
|
||||
|
||||
- FreshDeviceHandlerBase did not initialize the fdirInstance
|
||||
- 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.
|
||||
|
||||
## Added
|
||||
|
||||
- `EventManager`: Add function to print all listeners.
|
||||
|
||||
## Changed
|
||||
|
||||
- `EventManager`: Queue depth is configurable now
|
||||
|
||||
# [v6.0.0] 2023-02-10
|
||||
|
||||
## Fixes
|
||||
|
@ -82,6 +130,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||
|
||||
## Added
|
||||
|
||||
- `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.
|
||||
|
|
|
@ -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}.36.0
|
||||
CACHE STRING "ETL library exact version requirement")
|
||||
set(FSFW_ETL_LINK_TARGET etl::etl)
|
||||
|
||||
|
@ -80,7 +80,7 @@ set(FSFW_CATCH2_LIB_MAJOR_VERSION
|
|||
3
|
||||
CACHE STRING "Catch2 library major version requirement")
|
||||
set(FSFW_CATCH2_LIB_VERSION
|
||||
v${FSFW_CATCH2_LIB_MAJOR_VERSION}.1.0
|
||||
v${FSFW_CATCH2_LIB_MAJOR_VERSION}.3.2
|
||||
CACHE STRING "Catch2 library exact version requirement")
|
||||
|
||||
# Keep this off by default for now. See PR:
|
||||
|
|
|
@ -97,7 +97,7 @@ pipeline {
|
|||
sh 'rsync -r --delete docs/sphinx/* buildfix@documentation.irs.uni-stuttgart.de:/fsfw/development'
|
||||
}
|
||||
}
|
||||
dir(BUILDDIR) {
|
||||
dir(BUILDDIR_LINUX) {
|
||||
sshagent(credentials: ['documentation-buildfix']) {
|
||||
sh 'rsync -r --delete fsfw-tests_coverage/* buildfix@documentation.irs.uni-stuttgart.de:/fsfw/coverage/development'
|
||||
}
|
||||
|
@ -116,7 +116,7 @@ pipeline {
|
|||
sh 'rsync -r --delete docs/sphinx/* buildfix@documentation.irs.uni-stuttgart.de:/fsfw/master'
|
||||
}
|
||||
}
|
||||
dir(BUILDDIR) {
|
||||
dir(BUILDDIR_LINUX) {
|
||||
sshagent(credentials: ['documentation-buildfix']) {
|
||||
sh 'rsync -r --delete fsfw-tests_coverage/* buildfix@documentation.irs.uni-stuttgart.de:/fsfw/coverage/master'
|
||||
}
|
||||
|
|
|
@ -51,7 +51,10 @@ 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"}
|
||||
"extra_nav_links": {
|
||||
"Impressum": "https://www.uni-stuttgart.de/impressum",
|
||||
"Datenschutz": "https://info.irs.uni-stuttgart.de/datenschutz/datenschutzWebmit.html",
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
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);
|
||||
|
|
|
@ -16,8 +16,8 @@ class CommandActionHelper {
|
|||
public:
|
||||
explicit CommandActionHelper(CommandsActionsIF* owner);
|
||||
virtual ~CommandActionHelper();
|
||||
ReturnValue_t commandAction(object_id_t commandTo, ActionId_t actionId, const uint8_t* data,
|
||||
uint32_t size);
|
||||
ReturnValue_t commandAction(object_id_t commandTo, ActionId_t actionId,
|
||||
const uint8_t* data = nullptr, uint32_t size = 0);
|
||||
ReturnValue_t commandAction(object_id_t commandTo, ActionId_t actionId, SerializeIF* data);
|
||||
ReturnValue_t initialize();
|
||||
ReturnValue_t handleReply(CommandMessage* reply);
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
#define FSFW_CFDP_H
|
||||
|
||||
#include "cfdp/definitions.h"
|
||||
#include "cfdp/handler/DestHandler.h"
|
||||
#include "cfdp/handler/FaultHandlerBase.h"
|
||||
#include "cfdp/helpers.h"
|
||||
#include "cfdp/tlv/Lv.h"
|
||||
#include "cfdp/tlv/StringLv.h"
|
||||
#include "cfdp/tlv/Tlv.h"
|
||||
|
|
|
@ -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) {
|
||||
|
@ -51,8 +53,9 @@ class VarLenField : public SerializeIF {
|
|||
return os;
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
using SerializeIF::deSerialize; // we overloaded above, so this is needed to uncofuse the
|
||||
// compiler
|
||||
ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size,
|
||||
Endianness streamEndianness) override;
|
||||
|
||||
|
@ -64,7 +67,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 +76,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 +1,4 @@
|
|||
target_sources(${LIB_FSFW_NAME} PRIVATE FaultHandlerBase.cpp UserBase.cpp)
|
||||
target_sources(
|
||||
${LIB_FSFW_NAME}
|
||||
PRIVATE SourceHandler.cpp DestHandler.cpp PutRequest.cpp
|
||||
ReservedMessageParser.cpp FaultHandlerBase.cpp UserBase.cpp)
|
||||
|
|
|
@ -0,0 +1,574 @@
|
|||
#include "DestHandler.h"
|
||||
|
||||
#include <etl/crc32.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "fsfw/FSFW.h"
|
||||
#include "fsfw/cfdp/pdu/EofPduReader.h"
|
||||
#include "fsfw/cfdp/pdu/FileDataReader.h"
|
||||
#include "fsfw/cfdp/pdu/FinishedPduCreator.h"
|
||||
#include "fsfw/cfdp/pdu/PduHeaderReader.h"
|
||||
#include "fsfw/objectmanager.h"
|
||||
#include "fsfw/tmtcservices/TmTcMessage.h"
|
||||
|
||||
using namespace returnvalue;
|
||||
|
||||
cfdp::DestHandler::DestHandler(DestHandlerParams params, FsfwParams fsfwParams)
|
||||
: tlvVec(params.maxTlvsInOnePdu),
|
||||
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::stateMachine() {
|
||||
ReturnValue_t result;
|
||||
uint8_t errorIdx = 0;
|
||||
fsmRes.resetOfIteration();
|
||||
if (fsmRes.step == TransactionStep::IDLE) {
|
||||
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
|
||||
destParams.packetListRef.erase(infoIter++);
|
||||
} else {
|
||||
infoIter++;
|
||||
}
|
||||
}
|
||||
if (fsmRes.step == TransactionStep::IDLE) {
|
||||
// To decrease the already high complexity of the software, all packets arriving before
|
||||
// a metadata PDU are deleted.
|
||||
for (auto infoIter = destParams.packetListRef.begin();
|
||||
infoIter != destParams.packetListRef.end();) {
|
||||
fsfwParams.tcStore->deleteData(infoIter->storeId);
|
||||
infoIter++;
|
||||
}
|
||||
destParams.packetListRef.clear();
|
||||
}
|
||||
|
||||
if (fsmRes.step != TransactionStep::IDLE) {
|
||||
fsmRes.callStatus = CallStatus::CALL_AGAIN;
|
||||
}
|
||||
return updateFsmRes(errorIdx);
|
||||
}
|
||||
if (fsmRes.state == CfdpState::BUSY_CLASS_1_NACKED) {
|
||||
if (fsmRes.step == TransactionStep::RECEIVING_FILE_DATA_PDUS) {
|
||||
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
|
||||
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
|
||||
destParams.packetListRef.erase(infoIter++);
|
||||
} else {
|
||||
infoIter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fsmRes.step == TransactionStep::TRANSFER_COMPLETION) {
|
||||
result = handleTransferCompletion();
|
||||
checkAndHandleError(result, errorIdx);
|
||||
}
|
||||
if (fsmRes.step == TransactionStep::SENDING_FINISHED_PDU) {
|
||||
result = sendFinishedPdu();
|
||||
checkAndHandleError(result, errorIdx);
|
||||
finish();
|
||||
}
|
||||
return updateFsmRes(errorIdx);
|
||||
}
|
||||
if (fsmRes.state == 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;
|
||||
#endif
|
||||
}
|
||||
return updateFsmRes(errorIdx);
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::passPacket(PacketInfo packet) {
|
||||
if (destParams.packetListRef.full()) {
|
||||
return FAILED;
|
||||
}
|
||||
destParams.packetListRef.push_back(packet);
|
||||
return OK;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::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::DestHandler::handleMetadataPdu(const PacketInfo& info) {
|
||||
// Process metadata PDU
|
||||
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;
|
||||
MetadataGenericInfo metadataInfo(transactionParams.fileSize);
|
||||
MetadataPduReader reader(constAccessorPair.second.data(), constAccessorPair.second.size(),
|
||||
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
|
||||
// is translated into a warning and/or event by an upper layer
|
||||
if (result != OK) {
|
||||
return handleMetadataParseError(result, constAccessorPair.second.data(),
|
||||
constAccessorPair.second.size());
|
||||
}
|
||||
return startTransaction(reader);
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::handleFileDataPdu(const cfdp::PacketInfo& info) {
|
||||
// Process file data PDU
|
||||
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;
|
||||
}
|
||||
FileDataInfo fdInfo;
|
||||
FileDataReader reader(constAccessorPair.second.data(), constAccessorPair.second.size(), fdInfo);
|
||||
ReturnValue_t result = reader.parseData();
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
size_t fileSegmentLen = 0;
|
||||
const uint8_t* fileData = fdInfo.getFileData(&fileSegmentLen);
|
||||
FileOpParams fileOpParams(transactionParams.destName.data(), fileSegmentLen);
|
||||
fileOpParams.offset = fdInfo.getOffset().value();
|
||||
if (destParams.cfg.indicCfg.fileSegmentRecvIndicRequired) {
|
||||
FileSegmentRecvdParams segParams;
|
||||
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};
|
||||
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 << "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 {
|
||||
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 = fsfwParams.tcStore->getData(info.storeId);
|
||||
if (constAccessorPair.first != OK) {
|
||||
// TODO: This is not a CFDP error. Event and/or warning?
|
||||
return constAccessorPair.first;
|
||||
}
|
||||
EofInfo eofInfo(nullptr);
|
||||
EofPduReader reader(constAccessorPair.second.data(), constAccessorPair.second.size(), eofInfo);
|
||||
ReturnValue_t result = reader.parseData();
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
// TODO: Error handling
|
||||
if (eofInfo.getConditionCode() == ConditionCode::NO_ERROR) {
|
||||
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 > transactionParams.progress) {
|
||||
// TODO: File size error
|
||||
}
|
||||
transactionParams.fileSize.setFileSize(fileSizeFromEof, std::nullopt);
|
||||
}
|
||||
if (destParams.cfg.indicCfg.eofRecvIndicRequired) {
|
||||
destParams.user.eofRecvIndication(getTransactionId());
|
||||
}
|
||||
if (fsmRes.step == TransactionStep::RECEIVING_FILE_DATA_PDUS) {
|
||||
if (fsmRes.state == CfdpState::BUSY_CLASS_1_NACKED) {
|
||||
fsmRes.step = TransactionStep::TRANSFER_COMPLETION;
|
||||
} else if (fsmRes.state == CfdpState::BUSY_CLASS_2_ACKED) {
|
||||
fsmRes.step = TransactionStep::SENDING_ACK_PDU;
|
||||
}
|
||||
}
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::handleMetadataParseError(ReturnValue_t result,
|
||||
const uint8_t* rawData, size_t maxSize) {
|
||||
// TODO: try to extract destination ID for error
|
||||
// TODO: Invalid metadata PDU.
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "Parsing Metadata PDU failed with code " << result << std::endl;
|
||||
#else
|
||||
#endif
|
||||
PduHeaderReader headerReader(rawData, maxSize);
|
||||
result = headerReader.parseData();
|
||||
if (result != OK) {
|
||||
// TODO: Now this really should not happen. Warning or error,
|
||||
// yield or cache appropriate returnvalue
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "Parsing Header failed" << std::endl;
|
||||
#else
|
||||
#endif
|
||||
// TODO: Trigger appropriate event
|
||||
return result;
|
||||
}
|
||||
cfdp::EntityId destId;
|
||||
headerReader.getDestId(destId);
|
||||
RemoteEntityCfg* remoteCfg;
|
||||
if (not 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
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "No remote config exists for destination ID" << std::endl;
|
||||
#else
|
||||
#endif
|
||||
// TODO: Trigger appropriate event
|
||||
}
|
||||
// TODO: Appropriate returnvalue?
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::startTransaction(const MetadataPduReader& reader) {
|
||||
if (fsmRes.state != CfdpState::IDLE) {
|
||||
// According to standard, discard metadata PDU if we are busy
|
||||
return OK;
|
||||
}
|
||||
ReturnValue_t result = OK;
|
||||
size_t sourceNameSize = 0;
|
||||
|
||||
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';
|
||||
}
|
||||
size_t destNameSize = 0;
|
||||
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';
|
||||
}
|
||||
|
||||
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 "
|
||||
<< transactionParams.pduConf.sourceId.getValue() << std::endl;
|
||||
#endif
|
||||
return FAILED;
|
||||
}
|
||||
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++;
|
||||
}
|
||||
}
|
||||
params.msgsToUserArray = msgToUserVec.data();
|
||||
destParams.user.metadataRecvdIndication(params);
|
||||
return result;
|
||||
}
|
||||
|
||||
cfdp::CfdpState cfdp::DestHandler::getCfdpState() const { return fsmRes.state; }
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::handleTransferCompletion() {
|
||||
ReturnValue_t result;
|
||||
if (transactionParams.checksumType != ChecksumType::NULL_CHECKSUM) {
|
||||
result = checksumVerification();
|
||||
if (result != OK) {
|
||||
// TODO: Warning / error handling?
|
||||
}
|
||||
} else {
|
||||
transactionParams.conditionCode = ConditionCode::NO_ERROR;
|
||||
}
|
||||
result = noticeOfCompletion();
|
||||
if (result != OK) {
|
||||
}
|
||||
if (fsmRes.state == CfdpState::BUSY_CLASS_1_NACKED) {
|
||||
if (transactionParams.closureRequested) {
|
||||
fsmRes.step = TransactionStep::SENDING_FINISHED_PDU;
|
||||
} else {
|
||||
finish();
|
||||
}
|
||||
} 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() {
|
||||
transactionParams.reset();
|
||||
destParams.packetListRef.clear();
|
||||
fsmRes.state = CfdpState::IDLE;
|
||||
fsmRes.step = TransactionStep::IDLE;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::checksumVerification() {
|
||||
std::array<uint8_t, 1024> buf{};
|
||||
etl::crc32 crcCalc;
|
||||
uint64_t currentOffset = 0;
|
||||
FileOpParams params(transactionParams.destName.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 = 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
|
||||
return FAILED;
|
||||
}
|
||||
crcCalc.add(buf.begin(), buf.begin() + readLen);
|
||||
}
|
||||
currentOffset += readLen;
|
||||
}
|
||||
|
||||
uint32_t value = crcCalc.value();
|
||||
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 " << transactionParams.destName.data() << " failed"
|
||||
<< std::endl;
|
||||
#endif
|
||||
transactionParams.conditionCode = ConditionCode::FILE_CHECKSUM_FAILURE;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::noticeOfCompletion() {
|
||||
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(transactionParams.conditionCode, transactionParams.deliveryCode,
|
||||
transactionParams.deliveryStatus);
|
||||
FinishPduCreator finishedPdu(transactionParams.pduConf, info);
|
||||
store_address_t storeId;
|
||||
uint8_t* dataPtr = nullptr;
|
||||
ReturnValue_t result =
|
||||
fsfwParams.tmStore->getFreeElement(&storeId, finishedPdu.getSerializedSize(), &dataPtr);
|
||||
if (result != OK) {
|
||||
#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) {
|
||||
#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 = fsfwParams.msgQueue->sendMessage(fsfwParams.packetDest.getReportReceptionQueue(), &msg);
|
||||
if (result != OK) {
|
||||
#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++;
|
||||
return OK;
|
||||
}
|
||||
|
||||
cfdp::DestHandler::TransactionStep cfdp::DestHandler::getTransactionStep() const {
|
||||
return fsmRes.step;
|
||||
}
|
||||
|
||||
const cfdp::DestHandler::FsmResult& cfdp::DestHandler::updateFsmRes(uint8_t errors) {
|
||||
fsmRes.errors = errors;
|
||||
fsmRes.result = OK;
|
||||
if (fsmRes.errors > 0) {
|
||||
fsmRes.result = FAILED;
|
||||
}
|
||||
return fsmRes;
|
||||
}
|
||||
|
||||
const cfdp::TransactionId& cfdp::DestHandler::getTransactionId() const {
|
||||
return transactionParams.transactionId;
|
||||
}
|
||||
|
||||
void cfdp::DestHandler::checkAndHandleError(ReturnValue_t result, uint8_t& errorIdx) {
|
||||
if (result != OK and errorIdx < 3) {
|
||||
fsmRes.errorCodes[errorIdx] = result;
|
||||
errorIdx++;
|
||||
}
|
||||
}
|
||||
|
||||
void cfdp::DestHandler::setMsgQueue(MessageQueueIF& queue) { fsfwParams.msgQueue = &queue; }
|
||||
|
||||
void cfdp::DestHandler::setEventReporter(EventReportingProxyIF& reporter) {
|
||||
fsfwParams.eventReporter = &reporter;
|
||||
}
|
||||
|
||||
const cfdp::DestHandlerParams& cfdp::DestHandler::getDestHandlerParams() const {
|
||||
return destParams;
|
||||
}
|
||||
|
||||
StorageManagerIF* cfdp::DestHandler::getTmStore() const { return fsfwParams.tmStore; }
|
||||
StorageManagerIF* cfdp::DestHandler::getTcStore() const { return fsfwParams.tcStore; }
|
|
@ -0,0 +1,178 @@
|
|||
#ifndef FSFW_CFDP_CFDPDESTHANDLER_H
|
||||
#define FSFW_CFDP_CFDPDESTHANDLER_H
|
||||
|
||||
#include <etl/list.h>
|
||||
#include <etl/set.h>
|
||||
|
||||
#include <array>
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
|
||||
#include "RemoteConfigTableIF.h"
|
||||
#include "UserBase.h"
|
||||
#include "defs.h"
|
||||
#include "fsfw/cfdp/handler/mib.h"
|
||||
#include "fsfw/cfdp/pdu/MetadataPduReader.h"
|
||||
#include "fsfw/cfdp/pdu/PduConfig.h"
|
||||
#include "fsfw/cfdp/tlv/MessageToUserTlv.h"
|
||||
#include "fsfw/container/DynamicFIFO.h"
|
||||
#include "fsfw/storagemanager/StorageManagerIF.h"
|
||||
#include "fsfw/storagemanager/storeAddress.h"
|
||||
#include "fsfw/tmtcservices/AcceptsTelemetryIF.h"
|
||||
|
||||
namespace cfdp {
|
||||
|
||||
template <size_t SIZE>
|
||||
using LostSegmentsList = etl::set<etl::pair<uint64_t, uint64_t>, SIZE>;
|
||||
using LostSegmentsListBase = etl::iset<etl::pair<uint64_t, uint64_t>>;
|
||||
|
||||
struct DestHandlerParams {
|
||||
DestHandlerParams(LocalEntityCfg cfg, UserBase& user, RemoteConfigTableIF& remoteCfgTable,
|
||||
PacketInfoListBase& packetList,
|
||||
// TODO: This container can potentially take tons of space. For a better
|
||||
// memory efficient implementation, an additional abstraction could be
|
||||
// be used so users can use uint32_t as the pair type
|
||||
// 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),
|
||||
remoteCfgTable(remoteCfgTable),
|
||||
packetListRef(packetList),
|
||||
lostSegmentsContainer(lostSegmentsContainer) {}
|
||||
|
||||
LocalEntityCfg cfg;
|
||||
UserBase& user;
|
||||
RemoteConfigTableIF& remoteCfgTable;
|
||||
|
||||
PacketInfoListBase& packetListRef;
|
||||
LostSegmentsListBase& lostSegmentsContainer;
|
||||
uint8_t maxTlvsInOnePdu = 20;
|
||||
size_t maxFilenameLen = 255;
|
||||
};
|
||||
|
||||
class DestHandler {
|
||||
public:
|
||||
enum class TransactionStep : uint8_t {
|
||||
IDLE = 0,
|
||||
TRANSACTION_START = 1,
|
||||
RECEIVING_FILE_DATA_PDUS = 2,
|
||||
SENDING_ACK_PDU = 3,
|
||||
TRANSFER_COMPLETION = 4,
|
||||
SENDING_FINISHED_PDU = 5
|
||||
};
|
||||
|
||||
struct FsmResult {
|
||||
public:
|
||||
ReturnValue_t result = returnvalue::OK;
|
||||
CallStatus callStatus = CallStatus::CALL_AFTER_DELAY;
|
||||
TransactionStep step = TransactionStep::IDLE;
|
||||
CfdpState state = CfdpState::IDLE;
|
||||
uint32_t packetsSent = 0;
|
||||
uint8_t errors = 0;
|
||||
std::array<ReturnValue_t, 3> errorCodes = {};
|
||||
void resetOfIteration() {
|
||||
result = returnvalue::OK;
|
||||
callStatus = CallStatus::CALL_AFTER_DELAY;
|
||||
packetsSent = 0;
|
||||
errors = 0;
|
||||
errorCodes.fill(returnvalue::OK);
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Will be returned if it is advisable to call the state machine operation call again
|
||||
*/
|
||||
ReturnValue_t PARTIAL_SUCCESS = returnvalue::makeCode(0, 2);
|
||||
ReturnValue_t FAILURE = returnvalue::makeCode(0, 3);
|
||||
explicit DestHandler(DestHandlerParams handlerParams, FsfwParams fsfwParams);
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
* - @c returnvalue::OK State machine OK for this execution cycle
|
||||
* - @c CALL_FSM_AGAIN State machine should be called again.
|
||||
*/
|
||||
const FsmResult& stateMachine();
|
||||
void setMsgQueue(MessageQueueIF& queue);
|
||||
void setEventReporter(EventReportingProxyIF& reporter);
|
||||
|
||||
ReturnValue_t passPacket(PacketInfo packet);
|
||||
|
||||
ReturnValue_t initialize();
|
||||
|
||||
[[nodiscard]] CfdpState getCfdpState() const;
|
||||
[[nodiscard]] TransactionStep getTransactionStep() const;
|
||||
[[nodiscard]] const TransactionId& getTransactionId() const;
|
||||
[[nodiscard]] const DestHandlerParams& getDestHandlerParams() const;
|
||||
[[nodiscard]] StorageManagerIF* getTcStore() const;
|
||||
[[nodiscard]] StorageManagerIF* getTmStore() const;
|
||||
|
||||
private:
|
||||
struct TransactionParams {
|
||||
// Initialize char vectors with length + 1 for 0 termination
|
||||
explicit TransactionParams(size_t maxFileNameLen)
|
||||
: sourceName(maxFileNameLen + 1), destName(maxFileNameLen + 1) {}
|
||||
|
||||
void reset() {
|
||||
pduConf = PduConfig();
|
||||
transactionId = TransactionId();
|
||||
std::fill(sourceName.begin(), sourceName.end(), '\0');
|
||||
std::fill(destName.begin(), destName.end(), '\0');
|
||||
fileSize.setFileSize(0, false);
|
||||
conditionCode = ConditionCode::NO_ERROR;
|
||||
deliveryCode = FileDeliveryCode::DATA_INCOMPLETE;
|
||||
deliveryStatus = FileDeliveryStatus::DISCARDED_DELIBERATELY;
|
||||
crc = 0;
|
||||
progress = 0;
|
||||
remoteCfg = nullptr;
|
||||
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::Fss fileSize;
|
||||
TransactionId transactionId;
|
||||
PduConfig pduConf;
|
||||
ConditionCode conditionCode = ConditionCode::NO_ERROR;
|
||||
FileDeliveryCode deliveryCode = FileDeliveryCode::DATA_INCOMPLETE;
|
||||
FileDeliveryStatus deliveryStatus = FileDeliveryStatus::DISCARDED_DELIBERATELY;
|
||||
uint32_t crc = 0;
|
||||
uint64_t progress = 0;
|
||||
RemoteEntityCfg* remoteCfg = nullptr;
|
||||
};
|
||||
|
||||
std::vector<cfdp::Tlv> tlvVec;
|
||||
std::vector<MessageToUserTlv> msgToUserVec;
|
||||
TransactionParams transactionParams;
|
||||
DestHandlerParams destParams;
|
||||
cfdp::FsfwParams fsfwParams;
|
||||
FsmResult fsmRes;
|
||||
|
||||
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();
|
||||
};
|
||||
|
||||
} // namespace cfdp
|
||||
|
||||
#endif // FSFW_CFDP_CFDPDESTHANDLER_H
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -0,0 +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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
#ifndef FSFW_CFDP_CFDPSOURCEHANDLER_H
|
||||
#define FSFW_CFDP_CFDPSOURCEHANDLER_H
|
||||
|
||||
#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;
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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; }
|
|
@ -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)
|
||||
|
|
|
@ -23,6 +23,8 @@ class EntityIdTlv : public TlvIF {
|
|||
*/
|
||||
ReturnValue_t deSerialize(cfdp::Tlv& tlv, Endianness endianness);
|
||||
|
||||
using SerializeIF::deSerialize; // we overloaded this function, so this is needed to unconfuse
|
||||
// the compiler
|
||||
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
||||
Endianness streamEndianness) override;
|
||||
|
||||
|
|
|
@ -29,6 +29,8 @@ class FilestoreResponseTlv : public cfdp::FilestoreTlvBase {
|
|||
*/
|
||||
ReturnValue_t deSerialize(const cfdp::Tlv& tlv, Endianness endianness);
|
||||
|
||||
using SerializeIF::deSerialize; // we overloaded this function, so this is needed to unconfuse
|
||||
// the compiler
|
||||
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
||||
Endianness streamEndianness) override;
|
||||
|
||||
|
|
|
@ -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:
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -155,8 +155,8 @@ class FixedMap : public SerializeIF {
|
|||
|
||||
uint32_t maxSize() const { return theMap.maxSize(); }
|
||||
|
||||
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
||||
Endianness streamEndianness) const {
|
||||
ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
||||
Endianness streamEndianness) const override {
|
||||
ReturnValue_t result =
|
||||
SerializeAdapter::serialize(&this->_size, buffer, size, maxSize, streamEndianness);
|
||||
uint32_t i = 0;
|
||||
|
@ -170,7 +170,7 @@ class FixedMap : public SerializeIF {
|
|||
return result;
|
||||
}
|
||||
|
||||
virtual size_t getSerializedSize() const {
|
||||
size_t getSerializedSize() const override {
|
||||
uint32_t printSize = sizeof(_size);
|
||||
uint32_t i = 0;
|
||||
|
||||
|
@ -182,8 +182,8 @@ class FixedMap : public SerializeIF {
|
|||
return printSize;
|
||||
}
|
||||
|
||||
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
||||
Endianness streamEndianness) {
|
||||
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
||||
Endianness streamEndianness) override {
|
||||
ReturnValue_t result =
|
||||
SerializeAdapter::deSerialize(&this->_size, buffer, size, streamEndianness);
|
||||
if (this->_size > theMap.maxSize()) {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "fsfw/container/SharedRingBuffer.h"
|
||||
|
||||
#include "SharedRingBuffer.h"
|
||||
#include "fsfw/ipc/MutexFactory.h"
|
||||
#include "fsfw/ipc/MutexGuard.h"
|
||||
|
||||
|
@ -15,7 +16,12 @@ SharedRingBuffer::SharedRingBuffer(object_id_t objectId, uint8_t* buffer, const
|
|||
mutex = MutexFactory::instance()->createMutex();
|
||||
}
|
||||
|
||||
SharedRingBuffer::~SharedRingBuffer() { MutexFactory::instance()->deleteMutex(mutex); }
|
||||
SharedRingBuffer::~SharedRingBuffer() {
|
||||
MutexFactory::instance()->deleteMutex(mutex);
|
||||
if (receiveSizesFifo != nullptr) {
|
||||
delete (receiveSizesFifo);
|
||||
}
|
||||
}
|
||||
|
||||
void SharedRingBuffer::setToUseReceiveSizeFIFO(size_t fifoDepth) { this->fifoDepth = fifoDepth; }
|
||||
|
||||
|
@ -30,18 +36,31 @@ MutexIF* SharedRingBuffer::getMutexHandle() const { return mutex; }
|
|||
|
||||
ReturnValue_t SharedRingBuffer::initialize() {
|
||||
if (fifoDepth > 0) {
|
||||
receiveSizesFIFO = new DynamicFIFO<size_t>(fifoDepth);
|
||||
receiveSizesFifo = new DynamicFIFO<size_t>(fifoDepth);
|
||||
}
|
||||
return SystemObject::initialize();
|
||||
}
|
||||
|
||||
DynamicFIFO<size_t>* SharedRingBuffer::getReceiveSizesFIFO() {
|
||||
if (receiveSizesFIFO == nullptr) {
|
||||
DynamicFIFO<size_t>* SharedRingBuffer::getReceiveSizesFifo() {
|
||||
if (receiveSizesFifo == nullptr) {
|
||||
// Configuration error.
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "SharedRingBuffer::getReceiveSizesFIFO: Ring buffer"
|
||||
<< " was not configured to have sizes FIFO, returning nullptr!" << std::endl;
|
||||
#endif
|
||||
}
|
||||
return receiveSizesFIFO;
|
||||
return receiveSizesFifo;
|
||||
}
|
||||
|
||||
ReturnValue_t SharedRingBuffer::fifoEmpty(bool& empty, MutexIF::TimeoutType timeoutType,
|
||||
uint32_t timeoutMs) {
|
||||
if (receiveSizesFifo == nullptr) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
MutexGuard mg(mutex, timeoutType, timeoutMs);
|
||||
if (mg.getLockResult() != returnvalue::OK) {
|
||||
return mg.getLockResult();
|
||||
}
|
||||
empty = receiveSizesFifo->empty();
|
||||
return returnvalue::OK;
|
||||
}
|
|
@ -20,7 +20,7 @@ class SharedRingBuffer : public SystemObject, public SimpleRingBuffer {
|
|||
* This constructor allocates a new internal buffer with the supplied size.
|
||||
* @param size
|
||||
* @param overwriteOld
|
||||
* If the ring buffer is overflowing at a write operartion, the oldest data
|
||||
* If the ring buffer is overflowing at a write operation, the oldest data
|
||||
* will be overwritten.
|
||||
*/
|
||||
SharedRingBuffer(object_id_t objectId, const size_t size, bool overwriteOld,
|
||||
|
@ -30,7 +30,7 @@ class SharedRingBuffer : public SystemObject, public SimpleRingBuffer {
|
|||
* @param buffer
|
||||
* @param size
|
||||
* @param overwriteOld
|
||||
* If the ring buffer is overflowing at a write operartion, the oldest data
|
||||
* If the ring buffer is overflowing at a write operation, the oldest data
|
||||
* will be overwritten.
|
||||
*/
|
||||
SharedRingBuffer(object_id_t objectId, uint8_t* buffer, const size_t size, bool overwriteOld,
|
||||
|
@ -78,13 +78,15 @@ class SharedRingBuffer : public SystemObject, public SimpleRingBuffer {
|
|||
* Do not forget to protect access with a lock if required!
|
||||
* @return
|
||||
*/
|
||||
DynamicFIFO<size_t>* getReceiveSizesFIFO();
|
||||
DynamicFIFO<size_t>* getReceiveSizesFifo();
|
||||
|
||||
ReturnValue_t fifoEmpty(bool& empty, MutexIF::TimeoutType timeoutType, uint32_t timeoutMs);
|
||||
|
||||
private:
|
||||
MutexIF* mutex = nullptr;
|
||||
|
||||
size_t fifoDepth = 0;
|
||||
DynamicFIFO<size_t>* receiveSizesFIFO = nullptr;
|
||||
DynamicFIFO<size_t>* receiveSizesFifo = nullptr;
|
||||
};
|
||||
|
||||
#endif /* FSFW_CONTAINER_SHAREDRINGBUFFER_H_ */
|
||||
#endif /* FSFW_CONTAINER_SHAREDRINGBUFFER_H_ */
|
|
@ -4,48 +4,31 @@
|
|||
#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),
|
||||
healthHelper(this, setObjectId) {
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(commandQueueDepth);
|
||||
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(
|
||||
commandQueueDepth, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||
}
|
||||
|
||||
ControllerBase::~ControllerBase() { QueueFactory::instance()->deleteMessageQueue(commandQueue); }
|
||||
|
||||
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(); }
|
||||
|
@ -75,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);
|
||||
|
@ -89,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); }
|
||||
|
||||
ReturnValue_t ControllerBase::performOperation(uint8_t opCode) {
|
||||
handleQueue();
|
||||
performControlOperation();
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
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(opCode);
|
||||
return returnvalue::OK;
|
||||
}
|
||||
ReturnValue_t ControllerBase::setHealth(HealthState health) {
|
||||
switch (health) {
|
||||
case HEALTHY:
|
||||
|
@ -118,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:
|
||||
/**
|
||||
|
@ -51,13 +61,11 @@ class ControllerBase : public HasModesIF,
|
|||
/**
|
||||
* Periodic helper, implemented by child class.
|
||||
*/
|
||||
virtual void performControlOperation() = 0;
|
||||
virtual void performControlOperation(uint8_t opCode) = 0;
|
||||
|
||||
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) {}
|
||||
|
||||
|
@ -82,7 +81,7 @@ ReturnValue_t ExtendedControllerBase::initializeAfterTaskCreation() {
|
|||
|
||||
ReturnValue_t ExtendedControllerBase::performOperation(uint8_t opCode) {
|
||||
handleQueue();
|
||||
performControlOperation();
|
||||
performControlOperation(opCode);
|
||||
/* We do this after performing control operation because variables will be set changed
|
||||
in this function. */
|
||||
poolManager.performHkOperation();
|
||||
|
|
|
@ -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 */
|
||||
|
@ -44,9 +44,9 @@ class ExtendedControllerBase : public ControllerBase,
|
|||
/**
|
||||
* Periodic helper from ControllerBase, implemented by child class.
|
||||
*/
|
||||
void performControlOperation() override = 0;
|
||||
void performControlOperation(uint8_t opCode) override = 0;
|
||||
|
||||
/* Handle the four messages mentioned above */
|
||||
// Handle the four messages mentioned above
|
||||
void handleQueue() override;
|
||||
|
||||
/* HasActionsIF 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,16 @@ 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;
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "CoordinateTransformations::Conversion from UTC to TT failed. Continuing "
|
||||
"calculations with UTC."
|
||||
<< std::endl;
|
||||
#endif
|
||||
}
|
||||
double jD2000TT;
|
||||
Clock::convertTimevalToJD2000(timeTT, &jD2000TT);
|
||||
|
||||
|
@ -207,3 +218,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;
|
||||
}
|
||||
|
||||
|
|
|
@ -88,13 +88,18 @@ ReturnValue_t MapPacketExtraction::unpackBlockingPackets(TcTransferFrame* frame)
|
|||
uint32_t totalLength = frame->getDataLength();
|
||||
if (totalLength > MAX_PACKET_SIZE) return CONTENT_TOO_LARGE;
|
||||
uint8_t* position = frame->getDataField();
|
||||
while ((totalLength > SpacePacketBase::MINIMUM_SIZE)) {
|
||||
SpacePacketBase packet(position);
|
||||
uint32_t packetSize = packet.getFullSize();
|
||||
while ((totalLength > ccsds::HEADER_LEN)) {
|
||||
SpacePacketReader packet(position, totalLength);
|
||||
status = packet.checkSize();
|
||||
if (status != returnvalue::OK) {
|
||||
// TODO: Better error handling
|
||||
status = DATA_CORRUPTED;
|
||||
}
|
||||
uint32_t packetSize = packet.getFullPacketLen();
|
||||
if (packetSize <= totalLength) {
|
||||
status = sendCompletePacket(packet.getWholeData(), packet.getFullSize());
|
||||
totalLength -= packet.getFullSize();
|
||||
position += packet.getFullSize();
|
||||
status = sendCompletePacket(packet.getFullData(), packet.getFullPacketLen());
|
||||
totalLength -= packet.getFullPacketLen();
|
||||
position += packet.getFullPacketLen();
|
||||
status = returnvalue::OK;
|
||||
} else {
|
||||
status = DATA_CORRUPTED;
|
||||
|
@ -107,7 +112,7 @@ ReturnValue_t MapPacketExtraction::unpackBlockingPackets(TcTransferFrame* frame)
|
|||
return status;
|
||||
}
|
||||
|
||||
ReturnValue_t MapPacketExtraction::sendCompletePacket(uint8_t* data, uint32_t size) {
|
||||
ReturnValue_t MapPacketExtraction::sendCompletePacket(const uint8_t* data, uint32_t size) {
|
||||
store_address_t store_id;
|
||||
ReturnValue_t status = this->packetStore->addData(&store_id, data, size);
|
||||
if (status == returnvalue::OK) {
|
||||
|
|
|
@ -47,7 +47,7 @@ class MapPacketExtraction : public MapPacketExtractionIF {
|
|||
* @param size Complete total size of the packet.
|
||||
* @return Return Code of the Packet Store or the Message Queue.
|
||||
*/
|
||||
ReturnValue_t sendCompletePacket(uint8_t* data, uint32_t size);
|
||||
ReturnValue_t sendCompletePacket(const uint8_t* data, uint32_t size);
|
||||
/**
|
||||
* Helper method to reset the internal buffer.
|
||||
*/
|
||||
|
|
|
@ -64,8 +64,8 @@ class PoolDataSetBase : public PoolDataSetIF, public SerializeIF {
|
|||
* - @c SET_WAS_ALREADY_READ if read() is called twice without calling
|
||||
* commit() in between
|
||||
*/
|
||||
virtual ReturnValue_t read(MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING,
|
||||
uint32_t lockTimeout = 20) override;
|
||||
ReturnValue_t read(MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING,
|
||||
uint32_t lockTimeout = 20) override;
|
||||
/**
|
||||
* @brief The commit call initializes writing back the registered variables.
|
||||
* @details
|
||||
|
@ -84,15 +84,15 @@ class PoolDataSetBase : public PoolDataSetIF, public SerializeIF {
|
|||
* - @c COMMITING_WITHOUT_READING if set was not read yet and
|
||||
* contains non write-only variables
|
||||
*/
|
||||
virtual ReturnValue_t commit(MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING,
|
||||
uint32_t lockTimeout = 20) override;
|
||||
ReturnValue_t commit(MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING,
|
||||
uint32_t lockTimeout = 20) override;
|
||||
|
||||
/**
|
||||
* Register the passed pool variable instance into the data set.
|
||||
* @param variable
|
||||
* @return
|
||||
*/
|
||||
virtual ReturnValue_t registerVariable(PoolVariableIF* variable) override;
|
||||
ReturnValue_t registerVariable(PoolVariableIF* variable) override;
|
||||
|
||||
/**
|
||||
* Provides the means to lock the underlying data structure to ensure
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -350,7 +349,6 @@ ReturnValue_t LocalDataPoolManager::subscribeForPeriodicPacket(subdp::ParamsBase
|
|||
LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, params.sid);
|
||||
if (dataSet != nullptr) {
|
||||
LocalPoolDataSetAttorney::setReportingEnabled(*dataSet, params.enableReporting);
|
||||
LocalPoolDataSetAttorney::setDiagnostic(*dataSet, params.isDiagnostics());
|
||||
LocalPoolDataSetAttorney::initializePeriodicHelper(*dataSet, params.collectionInterval,
|
||||
owner->getPeriodicOperationFrequency());
|
||||
}
|
||||
|
@ -382,7 +380,6 @@ ReturnValue_t LocalDataPoolManager::subscribeForUpdatePacket(subdp::ParamsBase&
|
|||
LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, params.sid);
|
||||
if (dataSet != nullptr) {
|
||||
LocalPoolDataSetAttorney::setReportingEnabled(*dataSet, true);
|
||||
LocalPoolDataSetAttorney::setDiagnostic(*dataSet, params.isDiagnostics());
|
||||
}
|
||||
|
||||
hkReceivers.push_back(hkReceiver);
|
||||
|
@ -466,70 +463,37 @@ ReturnValue_t LocalDataPoolManager::handleHousekeepingMessage(CommandMessage* me
|
|||
ReturnValue_t result = returnvalue::OK;
|
||||
switch (command) {
|
||||
// Houskeeping interface handling.
|
||||
case (HousekeepingMessage::ENABLE_PERIODIC_DIAGNOSTICS_GENERATION): {
|
||||
result = togglePeriodicGeneration(sid, true, true);
|
||||
break;
|
||||
}
|
||||
|
||||
case (HousekeepingMessage::DISABLE_PERIODIC_DIAGNOSTICS_GENERATION): {
|
||||
result = togglePeriodicGeneration(sid, false, true);
|
||||
break;
|
||||
}
|
||||
|
||||
case (HousekeepingMessage::ENABLE_PERIODIC_HK_REPORT_GENERATION): {
|
||||
result = togglePeriodicGeneration(sid, true, false);
|
||||
result = togglePeriodicGeneration(sid, true);
|
||||
break;
|
||||
}
|
||||
|
||||
case (HousekeepingMessage::DISABLE_PERIODIC_HK_REPORT_GENERATION): {
|
||||
result = togglePeriodicGeneration(sid, false, false);
|
||||
break;
|
||||
}
|
||||
|
||||
case (HousekeepingMessage::REPORT_DIAGNOSTICS_REPORT_STRUCTURES): {
|
||||
result = generateSetStructurePacket(sid, true);
|
||||
if (result == returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
result = togglePeriodicGeneration(sid, false);
|
||||
break;
|
||||
}
|
||||
|
||||
case (HousekeepingMessage::REPORT_HK_REPORT_STRUCTURES): {
|
||||
result = generateSetStructurePacket(sid, false);
|
||||
result = generateSetStructurePacket(sid);
|
||||
if (result == returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case (HousekeepingMessage::MODIFY_DIAGNOSTICS_REPORT_COLLECTION_INTERVAL):
|
||||
case (HousekeepingMessage::MODIFY_PARAMETER_REPORT_COLLECTION_INTERVAL): {
|
||||
float newCollIntvl = 0;
|
||||
HousekeepingMessage::getCollectionIntervalModificationCommand(message, &newCollIntvl);
|
||||
if (command == HousekeepingMessage::MODIFY_DIAGNOSTICS_REPORT_COLLECTION_INTERVAL) {
|
||||
result = changeCollectionInterval(sid, newCollIntvl, true);
|
||||
} else {
|
||||
result = changeCollectionInterval(sid, newCollIntvl, false);
|
||||
}
|
||||
result = changeCollectionInterval(sid, newCollIntvl);
|
||||
break;
|
||||
}
|
||||
|
||||
case (HousekeepingMessage::GENERATE_ONE_PARAMETER_REPORT):
|
||||
case (HousekeepingMessage::GENERATE_ONE_DIAGNOSTICS_REPORT): {
|
||||
case (HousekeepingMessage::GENERATE_ONE_PARAMETER_REPORT): {
|
||||
LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid);
|
||||
if (dataSet == nullptr) {
|
||||
printWarningOrError(sif::OutputTypes::OUT_WARNING, "handleHousekeepingMessage",
|
||||
DATASET_NOT_FOUND);
|
||||
return DATASET_NOT_FOUND;
|
||||
}
|
||||
if (command == HousekeepingMessage::GENERATE_ONE_PARAMETER_REPORT and
|
||||
LocalPoolDataSetAttorney::isDiagnostics(*dataSet)) {
|
||||
result = WRONG_HK_PACKET_TYPE;
|
||||
break;
|
||||
} else if (command == HousekeepingMessage::GENERATE_ONE_DIAGNOSTICS_REPORT and
|
||||
not LocalPoolDataSetAttorney::isDiagnostics(*dataSet)) {
|
||||
result = WRONG_HK_PACKET_TYPE;
|
||||
break;
|
||||
}
|
||||
return generateHousekeepingPacket(HousekeepingMessage::getSid(message), dataSet, true);
|
||||
}
|
||||
|
||||
|
@ -570,6 +534,10 @@ ReturnValue_t LocalDataPoolManager::handleHousekeepingMessage(CommandMessage* me
|
|||
|
||||
CommandMessage reply;
|
||||
if (result != returnvalue::OK) {
|
||||
if (result == WRONG_HK_PACKET_TYPE) {
|
||||
printWarningOrError(sif::OutputTypes::OUT_WARNING, "handleHousekeepingMessage",
|
||||
WRONG_HK_PACKET_TYPE);
|
||||
}
|
||||
HousekeepingMessage::setHkRequestFailureReply(&reply, sid, result);
|
||||
} else {
|
||||
HousekeepingMessage::setHkRequestSuccessReply(&reply, sid);
|
||||
|
@ -615,11 +583,7 @@ ReturnValue_t LocalDataPoolManager::generateHousekeepingPacket(sid_t sid,
|
|||
|
||||
/* Now we set a HK message and send it the HK packet destination. */
|
||||
CommandMessage hkMessage;
|
||||
if (LocalPoolDataSetAttorney::isDiagnostics(*dataSet)) {
|
||||
HousekeepingMessage::setHkDiagnosticsReply(&hkMessage, sid, storeId);
|
||||
} else {
|
||||
HousekeepingMessage::setHkReportReply(&hkMessage, sid, storeId);
|
||||
}
|
||||
HousekeepingMessage::setHkReportReply(&hkMessage, sid, storeId);
|
||||
|
||||
if (hkQueue == nullptr) {
|
||||
/* Error, no queue available to send packet with. */
|
||||
|
@ -657,10 +621,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);
|
||||
|
@ -698,8 +658,7 @@ void LocalDataPoolManager::performPeriodicHkGeneration(HkReceiver& receiver) {
|
|||
}
|
||||
}
|
||||
|
||||
ReturnValue_t LocalDataPoolManager::togglePeriodicGeneration(sid_t sid, bool enable,
|
||||
bool isDiagnostics) {
|
||||
ReturnValue_t LocalDataPoolManager::togglePeriodicGeneration(sid_t sid, bool enable) {
|
||||
LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid);
|
||||
if (dataSet == nullptr) {
|
||||
printWarningOrError(sif::OutputTypes::OUT_WARNING, "togglePeriodicGeneration",
|
||||
|
@ -707,22 +666,17 @@ ReturnValue_t LocalDataPoolManager::togglePeriodicGeneration(sid_t sid, bool ena
|
|||
return DATASET_NOT_FOUND;
|
||||
}
|
||||
|
||||
if ((LocalPoolDataSetAttorney::isDiagnostics(*dataSet) and not isDiagnostics) or
|
||||
(not LocalPoolDataSetAttorney::isDiagnostics(*dataSet) and isDiagnostics)) {
|
||||
return WRONG_HK_PACKET_TYPE;
|
||||
}
|
||||
|
||||
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",
|
||||
|
@ -730,11 +684,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);
|
||||
|
||||
|
@ -747,7 +696,7 @@ ReturnValue_t LocalDataPoolManager::changeCollectionInterval(sid_t sid, float ne
|
|||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
ReturnValue_t LocalDataPoolManager::generateSetStructurePacket(sid_t sid, bool isDiagnostics) {
|
||||
ReturnValue_t LocalDataPoolManager::generateSetStructurePacket(sid_t sid) {
|
||||
/* Get and check dataset first. */
|
||||
LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid);
|
||||
if (dataSet == nullptr) {
|
||||
|
@ -756,11 +705,6 @@ ReturnValue_t LocalDataPoolManager::generateSetStructurePacket(sid_t sid, bool i
|
|||
return DATASET_NOT_FOUND;
|
||||
}
|
||||
|
||||
bool targetIsDiagnostics = LocalPoolDataSetAttorney::isDiagnostics(*dataSet);
|
||||
if ((targetIsDiagnostics and not isDiagnostics) or (not targetIsDiagnostics and isDiagnostics)) {
|
||||
return WRONG_HK_PACKET_TYPE;
|
||||
}
|
||||
|
||||
bool valid = dataSet->isValid();
|
||||
bool reportingEnabled = LocalPoolDataSetAttorney::getReportingEnabled(*dataSet);
|
||||
float collectionInterval =
|
||||
|
@ -792,11 +736,7 @@ ReturnValue_t LocalDataPoolManager::generateSetStructurePacket(sid_t sid, bool i
|
|||
|
||||
// Send structure reporting reply.
|
||||
CommandMessage reply;
|
||||
if (isDiagnostics) {
|
||||
HousekeepingMessage::setDiagnosticsStuctureReportReply(&reply, sid, storeId);
|
||||
} else {
|
||||
HousekeepingMessage::setHkStuctureReportReply(&reply, sid, storeId);
|
||||
}
|
||||
HousekeepingMessage::setHkStuctureReportReply(&reply, sid, storeId);
|
||||
|
||||
result = hkQueue->reply(&reply);
|
||||
if (result != returnvalue::OK) {
|
||||
|
@ -825,6 +765,8 @@ void LocalDataPoolManager::printWarningOrError(sif::OutputTypes outputType,
|
|||
errorPrint = "Dataset not found";
|
||||
} else if (error == POOLOBJECT_NOT_FOUND) {
|
||||
errorPrint = "Pool Object not found";
|
||||
} else if (error == WRONG_HK_PACKET_TYPE) {
|
||||
errorPrint = "Wrong Packet Type";
|
||||
} else if (error == returnvalue::FAILED) {
|
||||
if (outputType == sif::OutputTypes::OUT_WARNING) {
|
||||
errorPrint = "Generic Warning";
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
@ -347,10 +337,8 @@ class LocalDataPoolManager : public ProvidesDataPoolSubscriptionIF, public Acces
|
|||
size_t* serializedSize);
|
||||
|
||||
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);
|
||||
ReturnValue_t togglePeriodicGeneration(sid_t sid, bool enable);
|
||||
ReturnValue_t generateSetStructurePacket(sid_t sid);
|
||||
|
||||
void handleHkUpdateResetListInsertion(DataType dataType, DataId dataId);
|
||||
void handleChangeResetLogic(DataType type, DataId dataId, MarkChangedIF* toReset);
|
||||
|
|
|
@ -239,10 +239,6 @@ ReturnValue_t LocalPoolDataSetBase::serialize(uint8_t **buffer, size_t *size, si
|
|||
}
|
||||
}
|
||||
|
||||
void LocalPoolDataSetBase::setDiagnostic(bool isDiagnostics) { this->diagnostic = isDiagnostics; }
|
||||
|
||||
bool LocalPoolDataSetBase::isDiagnostics() const { return diagnostic; }
|
||||
|
||||
void LocalPoolDataSetBase::setReportingEnabled(bool reportingEnabled) {
|
||||
this->reportingEnabled = reportingEnabled;
|
||||
}
|
||||
|
@ -250,9 +246,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; }
|
||||
|
|
|
@ -162,6 +162,7 @@ class LocalPoolDataSetBase : public PoolDataSetBase, public MarkChangedIF {
|
|||
object_id_t getCreatorObjectId();
|
||||
|
||||
bool getReportingEnabled() const;
|
||||
void setReportingEnabled(bool enabled);
|
||||
|
||||
/**
|
||||
* Returns the current periodic HK generation interval this set
|
||||
|
@ -181,18 +182,12 @@ class LocalPoolDataSetBase : public PoolDataSetBase, public MarkChangedIF {
|
|||
//! This mutex is used if the data is created by one object only.
|
||||
MutexIF* mutexIfSingleDataCreator = nullptr;
|
||||
|
||||
bool diagnostic = false;
|
||||
void setDiagnostic(bool diagnostics);
|
||||
bool isDiagnostics() const;
|
||||
|
||||
/**
|
||||
* Used for periodic generation.
|
||||
*/
|
||||
bool reportingEnabled = false;
|
||||
void setReportingEnabled(bool enabled);
|
||||
|
||||
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
|
||||
|
|
|
@ -87,9 +87,9 @@ class LocalPoolVariable : public LocalPoolObjectBase {
|
|||
|
||||
ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
||||
SerializeIF::Endianness streamEndianness) const override;
|
||||
virtual size_t getSerializedSize() const override;
|
||||
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
||||
SerializeIF::Endianness streamEndianness) override;
|
||||
size_t getSerializedSize() const override;
|
||||
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
||||
SerializeIF::Endianness streamEndianness) override;
|
||||
|
||||
/**
|
||||
* @brief This is a call to read the array's values
|
||||
|
|
|
@ -98,11 +98,11 @@ class LocalPoolVector : public LocalPoolObjectBase {
|
|||
T& operator[](size_t i);
|
||||
const T& operator[](size_t i) const;
|
||||
|
||||
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, const size_t maxSize,
|
||||
SerializeIF::Endianness streamEndiannes) const override;
|
||||
virtual size_t getSerializedSize() const override;
|
||||
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
||||
SerializeIF::Endianness streamEndianness) override;
|
||||
ReturnValue_t serialize(uint8_t** buffer, size_t* size, const size_t maxSize,
|
||||
SerializeIF::Endianness streamEndiannes) const override;
|
||||
size_t getSerializedSize() const override;
|
||||
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
||||
SerializeIF::Endianness streamEndianness) override;
|
||||
|
||||
/**
|
||||
* @brief This is a call to read the array's values
|
||||
|
|
|
@ -98,11 +98,6 @@ class ProvidesDataPoolSubscriptionIF {
|
|||
virtual ReturnValue_t subscribeForRegularUpdatePacket(subdp::RegularHkUpdateParams params) = 0;
|
||||
virtual ReturnValue_t subscribeForDiagUpdatePacket(subdp::DiagnosticsHkUpdateParams params) = 0;
|
||||
|
||||
// virtual ReturnValue_t
|
||||
// subscribeForUpdatePacket(sid_t sid, bool reportingEnabled, bool isDiagnostics) {
|
||||
// return subscribeForUpdatePacket(sid, reportingEnabled, isDiagnostics, objects::NO_OBJECT);
|
||||
// }
|
||||
|
||||
[[deprecated(
|
||||
"Please use the new API which takes all arguments as one wrapper "
|
||||
"struct")]] virtual ReturnValue_t
|
||||
|
|
|
@ -5,17 +5,9 @@
|
|||
|
||||
class LocalPoolDataSetAttorney {
|
||||
private:
|
||||
static void setDiagnostic(LocalPoolDataSetBase& set, bool diagnostics) {
|
||||
set.setDiagnostic(diagnostics);
|
||||
}
|
||||
|
||||
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()),
|
||||
|
@ -26,11 +26,7 @@ void AssemblyBase::performChildOperation() {
|
|||
|
||||
void AssemblyBase::startTransition(Mode_t mode, Submode_t submode) {
|
||||
doStartTransition(mode, submode);
|
||||
if (modeHelper.isForced()) {
|
||||
triggerEvent(FORCING_MODE, mode, submode);
|
||||
} else {
|
||||
triggerEvent(CHANGING_MODE, mode, submode);
|
||||
}
|
||||
triggerModeHelperEvents(mode, submode);
|
||||
}
|
||||
|
||||
void AssemblyBase::doStartTransition(Mode_t mode, Submode_t submode) {
|
||||
|
@ -77,9 +73,10 @@ bool AssemblyBase::handleChildrenChangedHealth() {
|
|||
}
|
||||
HealthState healthState = healthHelper.healthTable->getHealth(iter->first);
|
||||
if (healthState == HasHealthIF::NEEDS_RECOVERY) {
|
||||
triggerEvent(TRYING_RECOVERY);
|
||||
triggerEvent(TRYING_RECOVERY, iter->first, 0);
|
||||
recoveryState = RECOVERY_STARTED;
|
||||
recoveringDevice = iter;
|
||||
// The user needs to take care of commanding the children off in commandChildren
|
||||
doStartTransition(targetMode, targetSubmode);
|
||||
} else {
|
||||
triggerEvent(CHILD_CHANGED_HEALTH);
|
||||
|
@ -228,6 +225,9 @@ ReturnValue_t AssemblyBase::handleHealthReply(CommandMessage* message) {
|
|||
bool AssemblyBase::checkAndHandleRecovery() {
|
||||
switch (recoveryState) {
|
||||
case RECOVERY_STARTED:
|
||||
// The recovery was already start in #handleChildrenChangedHealth and we just need
|
||||
// to wait for an off time period.
|
||||
// TODO: make time period configurable
|
||||
recoveryState = RECOVERY_WAIT;
|
||||
recoveryOffTimer.resetTimer();
|
||||
return true;
|
||||
|
@ -266,3 +266,11 @@ void AssemblyBase::overwriteDeviceHealth(object_id_t objectId, HasHealthIF::Heal
|
|||
modeHelper.setForced(true);
|
||||
sendHealthCommand(childrenMap[objectId].commandQueue, EXTERNAL_CONTROL);
|
||||
}
|
||||
|
||||
void AssemblyBase::triggerModeHelperEvents(Mode_t mode, Submode_t submode) {
|
||||
if (modeHelper.isForced()) {
|
||||
triggerEvent(FORCING_MODE, mode, submode);
|
||||
} else {
|
||||
triggerEvent(CHANGING_MODE, mode, submode);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,8 @@
|
|||
* Documentation: Dissertation Baetz p.156, 157.
|
||||
*
|
||||
* This class reduces the complexity of controller components which would
|
||||
* otherwise be needed for the handling of redundant devices.
|
||||
* otherwise be needed for the handling of redundant devices. However, it can also be used to
|
||||
* manage the mode keeping and recovery of non-redundant devices
|
||||
*
|
||||
* The template class monitors mode and health state of its children
|
||||
* and checks availability of devices on every detected change.
|
||||
|
@ -26,11 +27,9 @@
|
|||
*
|
||||
* Important:
|
||||
*
|
||||
* The implementation must call registerChild(object_id_t child)
|
||||
* for all commanded children during initialization.
|
||||
* The implementation must call #registerChild for all commanded children during initialization.
|
||||
* The implementation must call the initialization function of the base class.
|
||||
* (This will call the function in SubsystemBase)
|
||||
*
|
||||
*/
|
||||
class AssemblyBase : public SubsystemBase {
|
||||
public:
|
||||
|
@ -42,14 +41,15 @@ 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:
|
||||
/**
|
||||
* Command children to reach [mode,submode] combination
|
||||
* Can be done by setting #commandsOutstanding correctly,
|
||||
* or using executeTable()
|
||||
* Command children to reach [mode,submode] combination. Can be done by setting
|
||||
* #commandsOutstanding correctly, or using #executeTable. In case of an FDIR recovery,
|
||||
* the user needs to ensure that the target devices are healthy. If a device is not healthy,
|
||||
* a recovery might be on-going and the device needs to be commanded to off first.
|
||||
* @param mode
|
||||
* @param submode
|
||||
* @return
|
||||
|
@ -120,8 +120,19 @@ class AssemblyBase : public SubsystemBase {
|
|||
|
||||
virtual ReturnValue_t handleHealthReply(CommandMessage *message);
|
||||
|
||||
virtual void performChildOperation();
|
||||
/**
|
||||
* @brief Default periodic handler
|
||||
* @details
|
||||
* This is the default periodic handler which will be called by the SubsystemBase
|
||||
* performOperation. It performs the child transitions or reacts to changed health/mode states
|
||||
* of children objects
|
||||
*/
|
||||
virtual void performChildOperation() override;
|
||||
|
||||
/**
|
||||
* This function handles changed mode or health states of children
|
||||
* @return
|
||||
*/
|
||||
bool handleChildrenChanged();
|
||||
|
||||
/**
|
||||
|
@ -134,12 +145,37 @@ class AssemblyBase : public SubsystemBase {
|
|||
|
||||
bool handleChildrenChangedHealth();
|
||||
|
||||
/**
|
||||
* Core transition handler. The default implementation will only do something if
|
||||
* #commandsOutstanding is smaller or equal to zero, which means that all mode commands
|
||||
* from the #doPerformTransition call were executed successfully.
|
||||
*
|
||||
* Unless a second step was requested, the function will then use #checkChildrenState to
|
||||
* determine whether the target mode was reached.
|
||||
*
|
||||
* There is some special handling for certain (internal) modes:
|
||||
* - A second step is necessary. #commandChildren will be performed again
|
||||
* - The device health was overwritten. #commandChildren will be called
|
||||
* - A recovery is ongoing. #checkAndHandleRecovery will be called.
|
||||
*/
|
||||
virtual void handleChildrenTransition();
|
||||
|
||||
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, uint32_t *msToReachTheMode);
|
||||
|
||||
/**
|
||||
* Calls #doStartTransition and triggers an informative event as well that the mode will
|
||||
* change
|
||||
* @param mode
|
||||
* @param submode
|
||||
*/
|
||||
virtual void startTransition(Mode_t mode, Submode_t submode);
|
||||
|
||||
/**
|
||||
* This function starts the transition by setting the internal #targetSubmode and #targetMode
|
||||
* variables and then calling the #commandChildren function.
|
||||
* @param mode
|
||||
* @param submode
|
||||
*/
|
||||
virtual void doStartTransition(Mode_t mode, Submode_t submode);
|
||||
|
||||
virtual bool isInTransition();
|
||||
|
@ -160,7 +196,7 @@ class AssemblyBase : public SubsystemBase {
|
|||
* Manages recovery of a device
|
||||
* @return true if recovery is still ongoing, false else.
|
||||
*/
|
||||
bool checkAndHandleRecovery();
|
||||
virtual bool checkAndHandleRecovery();
|
||||
|
||||
/**
|
||||
* Helper method to overwrite health state of one of the children.
|
||||
|
@ -168,6 +204,8 @@ class AssemblyBase : public SubsystemBase {
|
|||
* @param objectId Must be a registered child.
|
||||
*/
|
||||
void overwriteDeviceHealth(object_id_t objectId, HasHealthIF::HealthState oldHealth);
|
||||
|
||||
void triggerModeHelperEvents(Mode_t mode, Submode_t submode);
|
||||
};
|
||||
|
||||
#endif /* FSFW_DEVICEHANDLERS_ASSEMBLYBASE_H_ */
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -49,6 +49,7 @@ class DeviceCommunicationIF {
|
|||
// is this needed if there is no open/close call?
|
||||
static const ReturnValue_t NOT_ACTIVE = MAKE_RETURN_CODE(0x05);
|
||||
static const ReturnValue_t TOO_MUCH_DATA = MAKE_RETURN_CODE(0x06);
|
||||
static constexpr ReturnValue_t BUSY = MAKE_RETURN_CODE(0x07);
|
||||
|
||||
virtual ~DeviceCommunicationIF() {}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include "fsfw/devicehandlers/DeviceHandlerBase.h"
|
||||
#include "DeviceHandlerBase.h"
|
||||
|
||||
#include "fsfw/datapool/PoolReadGuard.h"
|
||||
#include "fsfw/datapoollocal/LocalPoolVariable.h"
|
||||
|
@ -13,6 +13,7 @@
|
|||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||
#include "fsfw/storagemanager/StorageManagerIF.h"
|
||||
#include "fsfw/subsystem/SubsystemBase.h"
|
||||
#include "fsfw/subsystem/helper.h"
|
||||
#include "fsfw/thermal/ThermalComponentIF.h"
|
||||
|
||||
object_id_t DeviceHandlerBase::powerSwitcherId = objects::NO_OBJECT;
|
||||
|
@ -23,8 +24,6 @@ DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, object_id_t device
|
|||
CookieIF* comCookie, FailureIsolationBase* fdirInstance,
|
||||
size_t cmdQueueSize)
|
||||
: SystemObject(setObjectId),
|
||||
mode(MODE_OFF),
|
||||
submode(SUBMODE_NONE),
|
||||
wiretappingMode(OFF),
|
||||
storedRawData(StorageManagerIF::INVALID_ADDRESS),
|
||||
deviceCommunicationId(deviceCommunication),
|
||||
|
@ -39,10 +38,13 @@ DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, object_id_t device
|
|||
defaultFDIRUsed(fdirInstance == nullptr),
|
||||
switchOffWasReported(false),
|
||||
childTransitionDelay(5000),
|
||||
mode(MODE_OFF),
|
||||
submode(SUBMODE_NONE),
|
||||
transitionSourceMode(_MODE_POWER_DOWN),
|
||||
transitionSourceSubMode(SUBMODE_NONE) {
|
||||
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(
|
||||
cmdQueueSize, MessageQueueMessage::MAX_MESSAGE_SIZE);
|
||||
cmdQueueSize, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||
insertInCommandMap(RAW_COMMAND_ID);
|
||||
cookieInfo.state = COOKIE_UNUSED;
|
||||
cookieInfo.pendingCommand = deviceCommandMap.end();
|
||||
|
@ -50,21 +52,13 @@ DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, object_id_t device
|
|||
printWarningOrError(sif::OutputTypes::OUT_ERROR, "DeviceHandlerBase", returnvalue::FAILED,
|
||||
"Invalid cookie");
|
||||
}
|
||||
if (this->fdirInstance == nullptr) {
|
||||
this->fdirInstance = new DeviceHandlerFailureIsolation(setObjectId, defaultFdirParentId);
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceHandlerBase::setHkDestination(object_id_t hkDestination) {
|
||||
this->hkDestination = hkDestination;
|
||||
}
|
||||
|
||||
void DeviceHandlerBase::setThermalStateRequestPoolIds(lp_id_t thermalStatePoolId,
|
||||
lp_id_t heaterRequestPoolId,
|
||||
uint32_t thermalSetId) {
|
||||
thermalSet =
|
||||
new DeviceHandlerThermalSet(this, thermalSetId, thermalStatePoolId, heaterRequestPoolId);
|
||||
}
|
||||
void DeviceHandlerBase::enableThermalModule(ThermalStateCfg cfg) { this->thermalStateCfg = cfg; }
|
||||
|
||||
DeviceHandlerBase::~DeviceHandlerBase() {
|
||||
if (comCookie != nullptr) {
|
||||
|
@ -130,6 +124,10 @@ ReturnValue_t DeviceHandlerBase::initialize() {
|
|||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
if (this->fdirInstance == nullptr) {
|
||||
this->fdirInstance =
|
||||
new DeviceHandlerFailureIsolation(this->getObjectId(), defaultFdirParentId);
|
||||
}
|
||||
|
||||
communicationInterface =
|
||||
ObjectManager::instance()->get<DeviceCommunicationIF>(deviceCommunicationId);
|
||||
|
@ -224,12 +222,11 @@ ReturnValue_t DeviceHandlerBase::initialize() {
|
|||
fillCommandAndReplyMap();
|
||||
|
||||
if (thermalSet != nullptr) {
|
||||
PoolReadGuard pg(thermalSet);
|
||||
// Set temperature target state to NON_OP.
|
||||
result = thermalSet->read();
|
||||
if (result == returnvalue::OK) {
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
thermalSet->heaterRequest.value = ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL;
|
||||
thermalSet->heaterRequest.setValid(true);
|
||||
thermalSet->commit();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -353,7 +350,6 @@ void DeviceHandlerBase::doStateMachine() {
|
|||
currentUptime - timeoutStart >= powerSwitcher->getSwitchDelayMs()) {
|
||||
triggerEvent(MODE_TRANSITION_FAILED, PowerSwitchIF::SWITCH_TIMEOUT, 0);
|
||||
setMode(_MODE_POWER_DOWN);
|
||||
callChildStatemachine();
|
||||
break;
|
||||
}
|
||||
ReturnValue_t switchState = getStateOfSwitches();
|
||||
|
@ -367,13 +363,12 @@ void DeviceHandlerBase::doStateMachine() {
|
|||
}
|
||||
} break;
|
||||
case _MODE_WAIT_OFF: {
|
||||
uint32_t currentUptime;
|
||||
Clock::getUptime(¤tUptime);
|
||||
|
||||
if (powerSwitcher == nullptr) {
|
||||
setMode(MODE_OFF);
|
||||
break;
|
||||
}
|
||||
uint32_t currentUptime;
|
||||
Clock::getUptime(¤tUptime);
|
||||
if (currentUptime - timeoutStart >= powerSwitcher->getSwitchDelayMs()) {
|
||||
triggerEvent(MODE_TRANSITION_FAILED, PowerSwitchIF::SWITCH_TIMEOUT, 0);
|
||||
setMode(MODE_ERROR_ON);
|
||||
|
@ -381,7 +376,7 @@ void DeviceHandlerBase::doStateMachine() {
|
|||
}
|
||||
ReturnValue_t switchState = getStateOfSwitches();
|
||||
if ((switchState == PowerSwitchIF::SWITCH_OFF) || (switchState == NO_SWITCH)) {
|
||||
setMode(_MODE_SWITCH_IS_OFF);
|
||||
setMode(MODE_OFF, SUBMODE_NONE);
|
||||
}
|
||||
} break;
|
||||
case MODE_OFF:
|
||||
|
@ -394,9 +389,6 @@ void DeviceHandlerBase::doStateMachine() {
|
|||
case MODE_NORMAL:
|
||||
case MODE_ERROR_ON:
|
||||
break;
|
||||
case _MODE_SWITCH_IS_OFF:
|
||||
setMode(MODE_OFF, SUBMODE_NONE);
|
||||
break;
|
||||
default:
|
||||
triggerEvent(OBJECT_IN_INVALID_MODE, mode, submode);
|
||||
setMode(_MODE_POWER_DOWN, 0);
|
||||
|
@ -568,25 +560,40 @@ void DeviceHandlerBase::setTransition(Mode_t modeTo, Submode_t submodeTo) {
|
|||
}
|
||||
|
||||
void DeviceHandlerBase::setMode(Mode_t newMode, uint8_t newSubmode) {
|
||||
/* TODO: This will probably be done by the LocalDataPoolManager now */
|
||||
// changeHK(mode, submode, false);
|
||||
/**
|
||||
* handle transition from OFF to NORMAL by continuing towards normal when ON is reached
|
||||
*/
|
||||
if (newMode == MODE_ON and continueToNormal) {
|
||||
continueToNormal = false;
|
||||
// TODO: Check whether the following two lines are okay to do so.
|
||||
transitionSourceMode = MODE_ON;
|
||||
transitionSourceSubMode = newSubmode;
|
||||
mode = _MODE_TO_NORMAL;
|
||||
return;
|
||||
}
|
||||
|
||||
submode = newSubmode;
|
||||
mode = newMode;
|
||||
modeChanged();
|
||||
setNormalDatapoolEntriesInvalid();
|
||||
if (newMode == MODE_OFF) {
|
||||
disableCommandsAndReplies();
|
||||
}
|
||||
if (!isTransitionalMode()) {
|
||||
// clear this flag when a non-transitional Mode is reached to be safe
|
||||
continueToNormal = false;
|
||||
modeHelper.modeChanged(newMode, newSubmode);
|
||||
announceMode(false);
|
||||
}
|
||||
Clock::getUptime(&timeoutStart);
|
||||
|
||||
if (mode == MODE_OFF and thermalSet != nullptr) {
|
||||
ReturnValue_t result = thermalSet->read();
|
||||
if (result == returnvalue::OK) {
|
||||
PoolReadGuard pg(thermalSet);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
if (thermalSet->heaterRequest.value != ThermalComponentIF::STATE_REQUEST_IGNORE) {
|
||||
thermalSet->heaterRequest.value = ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL;
|
||||
}
|
||||
thermalSet->heaterRequest.commit(PoolVariableIF::VALID);
|
||||
thermalSet->heaterRequest.setValid(true);
|
||||
}
|
||||
}
|
||||
/* TODO: This will probably be done by the LocalDataPoolManager now */
|
||||
|
@ -1059,8 +1066,7 @@ Mode_t DeviceHandlerBase::getBaseMode(Mode_t transitionMode) {
|
|||
return transitionMode & ~(TRANSITION_MODE_BASE_ACTION_MASK | TRANSITION_MODE_CHILD_ACTION_MASK);
|
||||
}
|
||||
|
||||
// SHOULDDO: Allow transition from OFF to NORMAL to reduce complexity in assemblies. And, by the
|
||||
// way, throw away DHB and write a new one:
|
||||
// SHOULDDO: throw away DHB and write a new one:
|
||||
// - Include power and thermal completely, but more modular :-)
|
||||
// - Don't use modes for state transitions, reduce FSM (Finte State Machine) complexity.
|
||||
// - Modularization?
|
||||
|
@ -1072,13 +1078,12 @@ ReturnValue_t DeviceHandlerBase::checkModeCommand(Mode_t commandedMode, Submode_
|
|||
if ((mode == MODE_ERROR_ON) && (commandedMode != MODE_OFF)) {
|
||||
return TRANS_NOT_ALLOWED;
|
||||
}
|
||||
if ((commandedMode == MODE_NORMAL) && (mode == MODE_OFF)) {
|
||||
return TRANS_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
if ((commandedMode == MODE_ON) && (mode == MODE_OFF) and (thermalSet != nullptr)) {
|
||||
ReturnValue_t result = thermalSet->read();
|
||||
if (result == returnvalue::OK) {
|
||||
// Do not check thermal state for MODE_RAW
|
||||
if ((mode == MODE_OFF) and ((commandedMode == MODE_ON) or (commandedMode == MODE_NORMAL)) and
|
||||
(thermalSet != nullptr)) {
|
||||
PoolReadGuard pg(thermalSet);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
if ((thermalSet->heaterRequest.value != ThermalComponentIF::STATE_REQUEST_IGNORE) and
|
||||
(not ThermalComponentIF::isOperational(thermalSet->thermalState.value))) {
|
||||
triggerEvent(ThermalComponentIF::TEMP_NOT_IN_OP_RANGE, thermalSet->thermalState.value);
|
||||
|
@ -1091,6 +1096,7 @@ ReturnValue_t DeviceHandlerBase::checkModeCommand(Mode_t commandedMode, Submode_
|
|||
}
|
||||
|
||||
void DeviceHandlerBase::startTransition(Mode_t commandedMode, Submode_t commandedSubmode) {
|
||||
continueToNormal = false;
|
||||
switch (commandedMode) {
|
||||
case MODE_ON:
|
||||
handleTransitionToOnMode(commandedMode, commandedSubmode);
|
||||
|
@ -1120,8 +1126,9 @@ void DeviceHandlerBase::startTransition(Mode_t commandedMode, Submode_t commande
|
|||
case MODE_NORMAL:
|
||||
if (mode != MODE_OFF) {
|
||||
setTransition(MODE_NORMAL, commandedSubmode);
|
||||
} else {
|
||||
replyReturnvalueToCommand(HasModesIF::TRANS_NOT_ALLOWED);
|
||||
} else { // mode is off
|
||||
continueToNormal = true;
|
||||
handleTransitionToOnMode(MODE_NORMAL, commandedSubmode);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -1137,11 +1144,10 @@ void DeviceHandlerBase::handleTransitionToOnMode(Mode_t commandedMode, Submode_t
|
|||
childTransitionDelay = getTransitionDelayMs(_MODE_START_UP, MODE_ON);
|
||||
triggerEvent(CHANGING_MODE, commandedMode, commandedSubmode);
|
||||
if (thermalSet != nullptr) {
|
||||
ReturnValue_t result = thermalSet->read();
|
||||
if (result == returnvalue::OK) {
|
||||
PoolReadGuard pg(thermalSet);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
if (thermalSet->heaterRequest != ThermalComponentIF::STATE_REQUEST_IGNORE) {
|
||||
thermalSet->heaterRequest = ThermalComponentIF::STATE_REQUEST_OPERATIONAL;
|
||||
thermalSet->commit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1279,6 +1285,7 @@ void DeviceHandlerBase::handleDeviceTm(const SerializeIF& dataSet, DeviceCommand
|
|||
if (iter->second.command != deviceCommandMap.end()) {
|
||||
MessageQueueId_t queueId = iter->second.command->second.sendReplyTo;
|
||||
|
||||
// This may fail, but we'll ignore the fault.
|
||||
if (queueId != NO_COMMANDER) {
|
||||
// This may fail, but we'll ignore the fault.
|
||||
actionHelper.reportData(queueId, replyId, const_cast<SerializeIF*>(&dataSet));
|
||||
|
@ -1457,15 +1464,17 @@ void DeviceHandlerBase::setTaskIF(PeriodicTaskIF* task) { executingTask = task;
|
|||
void DeviceHandlerBase::debugInterface(uint8_t positionTracker, object_id_t objectId,
|
||||
uint32_t parameter) {}
|
||||
|
||||
Submode_t DeviceHandlerBase::getInitialSubmode() { return SUBMODE_NONE; }
|
||||
|
||||
void DeviceHandlerBase::performOperationHook() {}
|
||||
|
||||
ReturnValue_t DeviceHandlerBase::initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
|
||||
LocalDataPoolManager& poolManager) {
|
||||
if (thermalSet != nullptr) {
|
||||
localDataPoolMap.emplace(thermalSet->thermalStatePoolId,
|
||||
new PoolEntry<DeviceHandlerIF::dh_thermal_state_t>);
|
||||
localDataPoolMap.emplace(thermalSet->heaterRequestPoolId,
|
||||
new PoolEntry<DeviceHandlerIF::dh_heater_request_t>);
|
||||
if (thermalStateCfg.has_value()) {
|
||||
localDataPoolMap.emplace(thermalStateCfg.value().thermalStatePoolId,
|
||||
new PoolEntry<DeviceHandlerIF::dh_thermal_state_t>());
|
||||
localDataPoolMap.emplace(thermalStateCfg.value().thermalRequestPoolId,
|
||||
new PoolEntry<DeviceHandlerIF::dh_heater_request_t>());
|
||||
}
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
@ -1478,8 +1487,12 @@ ReturnValue_t DeviceHandlerBase::initializeAfterTaskCreation() {
|
|||
}
|
||||
this->poolManager.initializeAfterTaskCreation();
|
||||
|
||||
if (thermalStateCfg.has_value()) {
|
||||
ThermalStateCfg& cfg = thermalStateCfg.value();
|
||||
thermalSet = new DeviceHandlerThermalSet(this, cfg);
|
||||
}
|
||||
if (setStartupImmediately) {
|
||||
startTransition(MODE_ON, SUBMODE_NONE);
|
||||
startTransition(MODE_ON, getInitialSubmode());
|
||||
}
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
@ -1566,3 +1579,52 @@ MessageQueueId_t DeviceHandlerBase::getCommanderQueueId(DeviceCommandId_t replyI
|
|||
}
|
||||
return commandIter->second.sendReplyTo;
|
||||
}
|
||||
|
||||
void DeviceHandlerBase::setCustomFdir(FailureIsolationBase* fdir) { this->fdirInstance = fdir; }
|
||||
|
||||
void DeviceHandlerBase::setPowerSwitcher(PowerSwitchIF* switcher) {
|
||||
this->powerSwitcher = switcher;
|
||||
}
|
||||
|
||||
Mode_t DeviceHandlerBase::getMode() { return mode; }
|
||||
|
||||
Submode_t DeviceHandlerBase::getSubmode() { return submode; }
|
||||
|
||||
void DeviceHandlerBase::disableCommandsAndReplies() {
|
||||
for (auto& command : deviceCommandMap) {
|
||||
if (command.second.isExecuting) {
|
||||
command.second.isExecuting = false;
|
||||
}
|
||||
}
|
||||
for (auto& reply : deviceReplyMap) {
|
||||
if (!reply.second.periodic) {
|
||||
if (reply.second.countdown != nullptr) {
|
||||
reply.second.countdown->timeOut();
|
||||
} else {
|
||||
reply.second.delayCycles = 0;
|
||||
}
|
||||
reply.second.active = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t DeviceHandlerBase::connectModeTreeParent(HasModeTreeChildrenIF& parent) {
|
||||
return modetree::connectModeTreeParent(parent, *this, &healthHelper, modeHelper);
|
||||
}
|
||||
|
||||
const HasHealthIF* DeviceHandlerBase::getOptHealthIF() const { return this; }
|
||||
|
||||
const HasModesIF& DeviceHandlerBase::getModeIF() const { return *this; }
|
||||
|
||||
ModeTreeChildIF& DeviceHandlerBase::getModeTreeChildIF() { return *this; }
|
||||
|
||||
ReturnValue_t DeviceHandlerBase::finishAction(bool success, DeviceCommandId_t action,
|
||||
ReturnValue_t result) {
|
||||
auto commandIter = deviceCommandMap.find(action);
|
||||
if (commandIter == deviceCommandMap.end()) {
|
||||
return MessageQueueIF::NO_QUEUE;
|
||||
}
|
||||
commandIter->second.isExecuting = false;
|
||||
actionHelper.finish(success, commandIter->second.sendReplyTo, action, result);
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define FSFW_DEVICEHANDLERS_DEVICEHANDLERBASE_H_
|
||||
|
||||
#include <map>
|
||||
#include <optional>
|
||||
|
||||
#include "DeviceCommunicationIF.h"
|
||||
#include "DeviceHandlerFailureIsolation.h"
|
||||
|
@ -21,6 +22,7 @@
|
|||
#include "fsfw/returnvalues/returnvalue.h"
|
||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||
#include "fsfw/serviceinterface/serviceInterfaceDefintions.h"
|
||||
#include "fsfw/subsystem/ModeTreeConnectionIF.h"
|
||||
#include "fsfw/tasks/ExecutableObjectIF.h"
|
||||
#include "fsfw/tasks/PeriodicTaskIF.h"
|
||||
|
||||
|
@ -83,6 +85,8 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||
public HasModesIF,
|
||||
public HasHealthIF,
|
||||
public HasActionsIF,
|
||||
public ModeTreeChildIF,
|
||||
public ModeTreeConnectionIF,
|
||||
public ReceivesParameterMessagesIF,
|
||||
public HasLocalDataPoolIF {
|
||||
friend void(Factory::setStaticFrameworkObjectIds)();
|
||||
|
@ -102,6 +106,51 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||
DeviceHandlerBase(object_id_t setObjectId, object_id_t deviceCommunication, CookieIF *comCookie,
|
||||
FailureIsolationBase *fdirInstance = nullptr, size_t cmdQueueSize = 20);
|
||||
|
||||
void setCustomFdir(FailureIsolationBase *fdir);
|
||||
void setPowerSwitcher(PowerSwitchIF *switcher);
|
||||
|
||||
/**
|
||||
* extending the modes of DeviceHandler IF for internal state machine
|
||||
*/
|
||||
static constexpr uint8_t TRANSITION_MODE_CHILD_ACTION_MASK = 0x20;
|
||||
static constexpr uint8_t TRANSITION_MODE_BASE_ACTION_MASK = 0x10;
|
||||
//! This is a transitional state which can not be commanded. The device
|
||||
//! handler performs all commands to get the device in a state ready to
|
||||
//! perform commands. When this is completed, the mode changes to @c MODE_ON.
|
||||
static const Mode_t _MODE_START_UP = TRANSITION_MODE_CHILD_ACTION_MASK | 5;
|
||||
//! This is a transitional state which can not be commanded.
|
||||
//! The device handler performs all actions and commands to get the device
|
||||
//! shut down. When the device is off, the mode changes to @c MODE_OFF.
|
||||
//! It is possible to set the mode to _MODE_SHUT_DOWN to use the to off
|
||||
//! transition if available.
|
||||
static const Mode_t _MODE_SHUT_DOWN = TRANSITION_MODE_CHILD_ACTION_MASK | 6;
|
||||
//! It is possible to set the mode to _MODE_TO_ON to use the to on
|
||||
//! transition if available.
|
||||
static const Mode_t _MODE_TO_ON = TRANSITION_MODE_CHILD_ACTION_MASK | HasModesIF::MODE_ON;
|
||||
//! It is possible to set the mode to _MODE_TO_RAW to use the to raw
|
||||
//! transition if available.
|
||||
static const Mode_t _MODE_TO_RAW = TRANSITION_MODE_CHILD_ACTION_MASK | MODE_RAW;
|
||||
//! It is possible to set the mode to _MODE_TO_NORMAL to use the to normal
|
||||
//! transition if available.
|
||||
static const Mode_t _MODE_TO_NORMAL = TRANSITION_MODE_CHILD_ACTION_MASK | MODE_NORMAL;
|
||||
//! This is a transitional state which can not be commanded.
|
||||
//! The device is shut down and ready to be switched off.
|
||||
//! After the command to set the switch off has been sent,
|
||||
//! the mode changes to @c _MODE_WAIT_OFF
|
||||
static const Mode_t _MODE_POWER_DOWN = TRANSITION_MODE_BASE_ACTION_MASK | 1;
|
||||
//! This is a transitional state which can not be commanded. The device
|
||||
//! will be switched on in this state. After the command to set the switch
|
||||
//! on has been sent, the mode changes to @c _MODE_WAIT_ON.
|
||||
static const Mode_t _MODE_POWER_ON = TRANSITION_MODE_BASE_ACTION_MASK | 2;
|
||||
//! This is a transitional state which can not be commanded. The switch has
|
||||
//! been commanded off and the handler waits for it to be off.
|
||||
//! When the switch is off, the mode changes to @c MODE_OFF.
|
||||
static const Mode_t _MODE_WAIT_OFF = TRANSITION_MODE_BASE_ACTION_MASK | 3;
|
||||
//! This is a transitional state which can not be commanded. The switch
|
||||
//! has been commanded on and the handler waits for it to be on.
|
||||
//! When the switch is on, the mode changes to @c _MODE_TO_ON.
|
||||
static const Mode_t _MODE_WAIT_ON = TRANSITION_MODE_BASE_ACTION_MASK | 4;
|
||||
|
||||
void setHkDestination(object_id_t hkDestination);
|
||||
|
||||
/**
|
||||
|
@ -110,13 +159,12 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||
* The device handler will then take care of creating local pool entries
|
||||
* for the device thermal state and device heating request.
|
||||
* Custom local pool IDs can be assigned as well.
|
||||
* @param thermalStatePoolId
|
||||
* @param thermalRequestPoolId
|
||||
*/
|
||||
void setThermalStateRequestPoolIds(
|
||||
lp_id_t thermalStatePoolId = DeviceHandlerIF::DEFAULT_THERMAL_STATE_POOL_ID,
|
||||
lp_id_t thermalRequestPoolId = DeviceHandlerIF::DEFAULT_THERMAL_HEATING_REQUEST_POOL_ID,
|
||||
uint32_t thermalSetId = DeviceHandlerIF::DEFAULT_THERMAL_SET_ID);
|
||||
void enableThermalModule(ThermalStateCfg cfg);
|
||||
|
||||
ReturnValue_t connectModeTreeParent(HasModeTreeChildrenIF &parent) override;
|
||||
ModeTreeChildIF &getModeTreeChildIF() override;
|
||||
|
||||
/**
|
||||
* @brief Helper function to ease device handler development.
|
||||
* This will instruct the transition to MODE_ON immediately
|
||||
|
@ -162,7 +210,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||
* @param counter Specifies which Action to perform
|
||||
* @return returnvalue::OK for successful execution
|
||||
*/
|
||||
virtual ReturnValue_t performOperation(uint8_t counter) override;
|
||||
ReturnValue_t performOperation(uint8_t counter) override;
|
||||
|
||||
/**
|
||||
* @brief Initializes the device handler
|
||||
|
@ -172,14 +220,14 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||
* Calls fillCommandAndReplyMap().
|
||||
* @return
|
||||
*/
|
||||
virtual ReturnValue_t initialize() override;
|
||||
ReturnValue_t initialize() override;
|
||||
|
||||
/**
|
||||
* @brief Intialization steps performed after all tasks have been created.
|
||||
* This function will be called by the executing task.
|
||||
* @return
|
||||
*/
|
||||
virtual ReturnValue_t initializeAfterTaskCreation() override;
|
||||
ReturnValue_t initializeAfterTaskCreation() override;
|
||||
|
||||
/** Destructor. */
|
||||
virtual ~DeviceHandlerBase();
|
||||
|
@ -196,6 +244,8 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||
virtual object_id_t getObjectId() const override;
|
||||
|
||||
/**
|
||||
* This is a helper method for classes which are parent nodes in the mode tree.
|
||||
* It registers the passed queue as the destination for mode and health messages.
|
||||
* @param parentQueueId
|
||||
*/
|
||||
virtual void setParentQueue(MessageQueueId_t parentQueueId);
|
||||
|
@ -207,8 +257,8 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||
Mode_t getTransitionSourceMode() const;
|
||||
Submode_t getTransitionSourceSubMode() const;
|
||||
virtual void getMode(Mode_t *mode, Submode_t *submode);
|
||||
HealthState getHealth();
|
||||
ReturnValue_t setHealth(HealthState health);
|
||||
virtual HealthState getHealth() override;
|
||||
virtual ReturnValue_t setHealth(HealthState health) override;
|
||||
virtual ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueId,
|
||||
ParameterWrapper *parameterWrapper,
|
||||
const ParameterWrapper *newValues,
|
||||
|
@ -395,6 +445,8 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||
*/
|
||||
virtual ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) = 0;
|
||||
MessageQueueId_t getCommanderQueueId(DeviceCommandId_t replyId) const;
|
||||
ReturnValue_t finishAction(bool success, DeviceCommandId_t action, ReturnValue_t result);
|
||||
|
||||
/**
|
||||
* Helper function to get pending command. This is useful for devices
|
||||
* like SPI sensors to identify the last sent command.
|
||||
|
@ -463,14 +515,14 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||
* @brief This is a helper method to insert replies in the reply map.
|
||||
* @param deviceCommand Identifier of the reply to add.
|
||||
* @param maxDelayCycles The maximum number of delay cycles the reply waits
|
||||
* until it times out.
|
||||
* until it times out.
|
||||
* @param periodic Indicates if the command is periodic (i.e. it is sent
|
||||
* by the device repeatedly without request) or not. Default is aperiodic (0).
|
||||
* Please note that periodic replies are disabled by default. You can enable them with
|
||||
* #updatePeriodicReply
|
||||
* by the device repeatedly without request) or not. Default is aperiodic (0).
|
||||
* Please note that periodic replies are disabled by default. You can enable them with
|
||||
* #updatePeriodicReply
|
||||
* @param countdown Instead of using maxDelayCycles to timeout a device reply it is also possible
|
||||
* to provide a pointer to a Countdown object which will signal the timeout
|
||||
* when expired
|
||||
* to provide a pointer to a Countdown object which will signal the timeout
|
||||
* when expired
|
||||
* @return - @c returnvalue::OK when the command was successfully inserted,
|
||||
* - @c returnvalue::FAILED else.
|
||||
*/
|
||||
|
@ -655,6 +707,12 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||
virtual void debugInterface(uint8_t positionTracker = 0, object_id_t objectId = 0,
|
||||
uint32_t parameter = 0);
|
||||
|
||||
/**
|
||||
* @brief Can be overwritten by a child to specify the initial submode when device has been set
|
||||
* to startup immediately.
|
||||
*/
|
||||
virtual Submode_t getInitialSubmode();
|
||||
|
||||
protected:
|
||||
static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_BASE;
|
||||
|
||||
|
@ -684,15 +742,18 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||
size_t rawPacketLen = 0;
|
||||
|
||||
/**
|
||||
* The mode the device handler is currently in.
|
||||
* This should never be changed directly but only with setMode()
|
||||
* Get the current mode
|
||||
*
|
||||
* set via setMode()
|
||||
*/
|
||||
Mode_t mode;
|
||||
Mode_t getMode();
|
||||
|
||||
/**
|
||||
* The submode the device handler is currently in.
|
||||
* This should never be changed directly but only with setMode()
|
||||
* Get the current Submode
|
||||
*
|
||||
* set via setMode()
|
||||
*/
|
||||
Submode_t submode;
|
||||
Submode_t getSubmode();
|
||||
|
||||
/** This is the counter value from performOperation(). */
|
||||
uint8_t pstStep = 0;
|
||||
|
@ -773,11 +834,18 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||
* This is used to keep track of pending replies.
|
||||
*/
|
||||
struct DeviceReplyInfo {
|
||||
//! For Command-Reply combinations:
|
||||
//! The maximum number of cycles the handler should wait for a reply
|
||||
//! to this command.
|
||||
//!
|
||||
//! Reply Only:
|
||||
//! For periodic replies, this variable will be the number of delay cycles between the replies.
|
||||
//! For the non-periodic variant, this variable is not used as there is no meaningful
|
||||
//! definition for delay
|
||||
uint16_t maxDelayCycles;
|
||||
//! The currently remaining cycles the handler should wait for a reply,
|
||||
//! 0 means there is no reply expected
|
||||
//! This variable will be set to #maxDelayCycles if a reply is expected.
|
||||
//! For non-periodic replies without a command, this variable is unused.
|
||||
//! A runtime value of 0 means there is no reply is currently expected.
|
||||
uint16_t delayCycles;
|
||||
size_t replyLen = 0; //!< Expected size of the reply.
|
||||
//! if this is !=0, the delayCycles will not be reset to 0 but to
|
||||
|
@ -833,6 +901,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||
/** Pointer to the used FDIR instance. If not provided by child,
|
||||
* default class is instantiated. */
|
||||
FailureIsolationBase *fdirInstance;
|
||||
object_id_t parent = objects::NO_OBJECT;
|
||||
|
||||
//! To correctly delete the default instance.
|
||||
bool defaultFDIRUsed;
|
||||
|
@ -853,6 +922,8 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||
//! Object which may be the root cause of an identified fault.
|
||||
static object_id_t defaultFdirParentId;
|
||||
|
||||
std::optional<ThermalStateCfg> thermalStateCfg;
|
||||
|
||||
/**
|
||||
* @brief Send a reply to a received device handler command.
|
||||
*
|
||||
|
@ -873,8 +944,8 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||
* Do the transition to the main modes (MODE_ON, MODE_NORMAL and MODE_RAW).
|
||||
*
|
||||
* If the transition is complete, the mode should be set to the target mode,
|
||||
* which can be deduced from the current mode which is
|
||||
* [_MODE_TO_ON, _MODE_TO_NORMAL, _MODE_TO_RAW]
|
||||
* which can be deduced from the current mode (which is
|
||||
* [_MODE_TO_ON, _MODE_TO_NORMAL, _MODE_TO_RAW]) using getBaseMode()
|
||||
*
|
||||
* The intended target submode is already set.
|
||||
* The origin submode can be read in subModeFrom.
|
||||
|
@ -941,6 +1012,9 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||
*/
|
||||
LocalDataPoolManager *getHkManagerHandle() override;
|
||||
|
||||
const HasHealthIF *getOptHealthIF() const override;
|
||||
const HasModesIF &getModeIF() const override;
|
||||
|
||||
/**
|
||||
* Returns the delay cycle count of a reply.
|
||||
* A count != 0 indicates that the command is already executed.
|
||||
|
@ -1120,6 +1194,22 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||
*/
|
||||
virtual ReturnValue_t doSendReadHook();
|
||||
|
||||
/**
|
||||
* Send a RMAP getRead command.
|
||||
*
|
||||
* The size of the getRead command is #maxDeviceReplyLen.
|
||||
* This is always executed, independently from the current mode.
|
||||
*/
|
||||
virtual void doSendRead(void);
|
||||
/**
|
||||
* Check the getRead reply and the contained data.
|
||||
*
|
||||
* If data was received scanForReply() and, if successful, handleReply()
|
||||
* are called. If the current mode is @c MODE_RAW, the received packet
|
||||
* is sent to the commanding object via commandQueue.
|
||||
*/
|
||||
virtual void doGetRead();
|
||||
|
||||
private:
|
||||
/**
|
||||
* State a cookie is in.
|
||||
|
@ -1170,6 +1260,18 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||
*/
|
||||
uint32_t childTransitionDelay;
|
||||
|
||||
/**
|
||||
* The mode the device handler is currently in.
|
||||
* This should not be changed directly but only with setMode()
|
||||
*/
|
||||
Mode_t mode;
|
||||
|
||||
/**
|
||||
* The submode the device handler is currently in.
|
||||
* This should not be changed directly but only with setMode()
|
||||
*/
|
||||
Submode_t submode;
|
||||
|
||||
/**
|
||||
* @brief The mode the current transition originated from
|
||||
*
|
||||
|
@ -1187,6 +1289,15 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||
*/
|
||||
Submode_t transitionSourceSubMode;
|
||||
|
||||
/**
|
||||
* used to make the state machine continue from ON to NOMAL when
|
||||
* a Device is commanded to NORMAL in OFF mode
|
||||
*
|
||||
* set in startTransition()
|
||||
* evaluated in setMode() to continue to NORMAL when ON is reached
|
||||
*/
|
||||
bool continueToNormal;
|
||||
|
||||
/**
|
||||
* read the command queue
|
||||
*/
|
||||
|
@ -1255,21 +1366,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||
* - if the action was successful, the reply timout counter is initialized
|
||||
*/
|
||||
void doGetWrite(void);
|
||||
/**
|
||||
* Send a RMAP getRead command.
|
||||
*
|
||||
* The size of the getRead command is #maxDeviceReplyLen.
|
||||
* This is always executed, independently from the current mode.
|
||||
*/
|
||||
void doSendRead(void);
|
||||
/**
|
||||
* Check the getRead reply and the contained data.
|
||||
*
|
||||
* If data was received scanForReply() and, if successful, handleReply()
|
||||
* are called. If the current mode is @c MODE_RAW, the received packet
|
||||
* is sent to the commanding object via commandQueue.
|
||||
*/
|
||||
void doGetRead(void);
|
||||
|
||||
/**
|
||||
* @brief Resets replies which use a timeout to detect missed replies.
|
||||
|
@ -1323,6 +1419,11 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||
void printWarningOrError(sif::OutputTypes errorType, const char *functionName,
|
||||
ReturnValue_t errorCode = returnvalue::FAILED,
|
||||
const char *errorPrint = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Disables all commands and replies when device is set to MODE_OFF
|
||||
*/
|
||||
void disableCommandsAndReplies();
|
||||
};
|
||||
|
||||
#endif /* FSFW_DEVICEHANDLERS_DEVICEHANDLERBASE_H_ */
|
||||
|
|
|
@ -10,8 +10,9 @@
|
|||
|
||||
object_id_t DeviceHandlerFailureIsolation::powerConfirmationId = objects::NO_OBJECT;
|
||||
|
||||
DeviceHandlerFailureIsolation::DeviceHandlerFailureIsolation(object_id_t owner, object_id_t parent)
|
||||
: FailureIsolationBase(owner, parent),
|
||||
DeviceHandlerFailureIsolation::DeviceHandlerFailureIsolation(object_id_t owner, object_id_t parent,
|
||||
uint8_t eventQueueDepth)
|
||||
: FailureIsolationBase(owner, parent, eventQueueDepth),
|
||||
strangeReplyCount(DEFAULT_MAX_STRANGE_REPLIES, DEFAULT_STRANGE_REPLIES_TIME_MS,
|
||||
parameterDomainBase++),
|
||||
missedReplyCount(DEFAULT_MAX_MISSED_REPLY_COUNT, DEFAULT_MISSED_REPLY_TIME_MS,
|
||||
|
@ -25,10 +26,16 @@ ReturnValue_t DeviceHandlerFailureIsolation::eventReceived(EventMessage* event)
|
|||
if (isFdirInActionOrAreWeFaulty(event)) {
|
||||
return returnvalue::OK;
|
||||
}
|
||||
// As mentioned in the function documentation, no FDIR reaction are performed when the device
|
||||
// is in external control.
|
||||
if (owner->getHealth() == HasHealthIF::EXTERNAL_CONTROL) {
|
||||
return returnvalue::OK;
|
||||
}
|
||||
ReturnValue_t result = returnvalue::FAILED;
|
||||
switch (event->getEvent()) {
|
||||
case HasModesIF::MODE_TRANSITION_FAILED:
|
||||
case HasModesIF::OBJECT_IN_INVALID_MODE:
|
||||
case DeviceHandlerIF::DEVICE_WANTS_HARD_REBOOT:
|
||||
// We'll try a recovery as long as defined in MAX_REBOOT.
|
||||
// Might cause some AssemblyBase cycles, so keep number low.
|
||||
handleRecovery(event->getEvent());
|
||||
|
@ -184,15 +191,6 @@ void DeviceHandlerFailureIsolation::setFdirState(FDIRState state) {
|
|||
fdirState = state;
|
||||
}
|
||||
|
||||
void DeviceHandlerFailureIsolation::triggerEvent(Event event, uint32_t parameter1,
|
||||
uint32_t parameter2) {
|
||||
// Do not throw error events if fdirState != none.
|
||||
// This will still forward MODE and HEALTH INFO events in any case.
|
||||
if (fdirState == NONE || event::getSeverity(event) == severity::INFO) {
|
||||
FailureIsolationBase::triggerEvent(event, parameter1, parameter2);
|
||||
}
|
||||
}
|
||||
|
||||
bool DeviceHandlerFailureIsolation::isFdirActionInProgress() { return (fdirState != NONE); }
|
||||
|
||||
void DeviceHandlerFailureIsolation::startRecovery(Event reason) {
|
||||
|
|
|
@ -13,10 +13,10 @@ class DeviceHandlerFailureIsolation : public FailureIsolationBase {
|
|||
friend class Heater;
|
||||
|
||||
public:
|
||||
DeviceHandlerFailureIsolation(object_id_t owner, object_id_t parent);
|
||||
DeviceHandlerFailureIsolation(object_id_t owner, object_id_t parent,
|
||||
uint8_t eventQueueDepth = 10);
|
||||
~DeviceHandlerFailureIsolation();
|
||||
ReturnValue_t initialize();
|
||||
void triggerEvent(Event event, uint32_t parameter1 = 0, uint32_t parameter2 = 0);
|
||||
bool isFdirActionInProgress();
|
||||
virtual ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueId,
|
||||
ParameterWrapper* parameterWrapper,
|
||||
|
@ -40,6 +40,19 @@ class DeviceHandlerFailureIsolation : public FailureIsolationBase {
|
|||
static const uint32_t DEFAULT_MAX_MISSED_REPLY_COUNT = 5;
|
||||
static const uint32_t DEFAULT_MISSED_REPLY_TIME_MS = 10000;
|
||||
|
||||
/**
|
||||
* This is the default implementation of the eventReceived function.
|
||||
*
|
||||
* It will perform recoveries or failures on a pre-defined set of events. If the user wants
|
||||
* to add handling for custom events, this function should be overriden.
|
||||
*
|
||||
* It should be noted that the default implementation will not perform FDIR reactions if the
|
||||
* handler is faulty or in external control by default. If the user commands the device
|
||||
* manually, this might be related to debugging to testing the device in a low-level way. FDIR
|
||||
* reactions might get in the way of this process by restarting the device or putting it in
|
||||
* the faulty state. If the user still requires FDIR handling in the EXTERNAL_CONTROL case,
|
||||
* this function should be overriden.
|
||||
*/
|
||||
virtual ReturnValue_t eventReceived(EventMessage* event);
|
||||
virtual void eventConfirmed(EventMessage* event);
|
||||
void wasParentsFault(EventMessage* event);
|
||||
|
|
|
@ -24,9 +24,6 @@ class DeviceHandlerIF {
|
|||
static const DeviceCommandId_t RAW_COMMAND_ID = -1;
|
||||
static const DeviceCommandId_t NO_COMMAND_ID = -2;
|
||||
|
||||
static constexpr uint8_t TRANSITION_MODE_CHILD_ACTION_MASK = 0x20;
|
||||
static constexpr uint8_t TRANSITION_MODE_BASE_ACTION_MASK = 0x10;
|
||||
|
||||
using dh_heater_request_t = uint8_t;
|
||||
using dh_thermal_state_t = int8_t;
|
||||
|
||||
|
@ -54,47 +51,6 @@ class DeviceHandlerIF {
|
|||
//! device still is powered. In this mode, only a mode change to @c MODE_OFF
|
||||
//! can be commanded, which tries to switch off the device again.
|
||||
static const Mode_t MODE_ERROR_ON = 4;
|
||||
//! This is a transitional state which can not be commanded. The device
|
||||
//! handler performs all commands to get the device in a state ready to
|
||||
//! perform commands. When this is completed, the mode changes to @c MODE_ON.
|
||||
static const Mode_t _MODE_START_UP = TRANSITION_MODE_CHILD_ACTION_MASK | 5;
|
||||
//! This is a transitional state which can not be commanded.
|
||||
//! The device handler performs all actions and commands to get the device
|
||||
//! shut down. When the device is off, the mode changes to @c MODE_OFF.
|
||||
//! It is possible to set the mode to _MODE_SHUT_DOWN to use the to off
|
||||
//! transition if available.
|
||||
static const Mode_t _MODE_SHUT_DOWN = TRANSITION_MODE_CHILD_ACTION_MASK | 6;
|
||||
//! It is possible to set the mode to _MODE_TO_ON to use the to on
|
||||
//! transition if available.
|
||||
static const Mode_t _MODE_TO_ON = TRANSITION_MODE_CHILD_ACTION_MASK | HasModesIF::MODE_ON;
|
||||
//! It is possible to set the mode to _MODE_TO_RAW to use the to raw
|
||||
//! transition if available.
|
||||
static const Mode_t _MODE_TO_RAW = TRANSITION_MODE_CHILD_ACTION_MASK | MODE_RAW;
|
||||
//! It is possible to set the mode to _MODE_TO_NORMAL to use the to normal
|
||||
//! transition if available.
|
||||
static const Mode_t _MODE_TO_NORMAL = TRANSITION_MODE_CHILD_ACTION_MASK | MODE_NORMAL;
|
||||
//! This is a transitional state which can not be commanded.
|
||||
//! The device is shut down and ready to be switched off.
|
||||
//! After the command to set the switch off has been sent,
|
||||
//! the mode changes to @c MODE_WAIT_OFF
|
||||
static const Mode_t _MODE_POWER_DOWN = TRANSITION_MODE_BASE_ACTION_MASK | 1;
|
||||
//! This is a transitional state which can not be commanded. The device
|
||||
//! will be switched on in this state. After the command to set the switch
|
||||
//! on has been sent, the mode changes to @c MODE_WAIT_ON.
|
||||
static const Mode_t _MODE_POWER_ON = TRANSITION_MODE_BASE_ACTION_MASK | 2;
|
||||
//! This is a transitional state which can not be commanded. The switch has
|
||||
//! been commanded off and the handler waits for it to be off.
|
||||
//! When the switch is off, the mode changes to @c MODE_OFF.
|
||||
static const Mode_t _MODE_WAIT_OFF = TRANSITION_MODE_BASE_ACTION_MASK | 3;
|
||||
//! This is a transitional state which can not be commanded. The switch
|
||||
//! has been commanded on and the handler waits for it to be on.
|
||||
//! When the switch is on, the mode changes to @c MODE_TO_ON.
|
||||
static const Mode_t _MODE_WAIT_ON = TRANSITION_MODE_BASE_ACTION_MASK | 4;
|
||||
//! This is a transitional state which can not be commanded. The switch has
|
||||
//! been commanded off and is off now. This state is only to do an RMAP
|
||||
//! cycle once more where the doSendRead() function will set the mode to
|
||||
//! MODE_OFF. The reason to do this is to get rid of stuck packets in the IO Board.
|
||||
static const Mode_t _MODE_SWITCH_IS_OFF = TRANSITION_MODE_BASE_ACTION_MASK | 5;
|
||||
|
||||
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::CDH;
|
||||
static const Event DEVICE_BUILDING_COMMAND_FAILED = MAKE_EVENT(0, severity::LOW);
|
||||
|
@ -109,6 +65,7 @@ class DeviceHandlerIF {
|
|||
static const Event INVALID_DEVICE_COMMAND = MAKE_EVENT(8, severity::LOW);
|
||||
static const Event MONITORING_LIMIT_EXCEEDED = MAKE_EVENT(9, severity::LOW);
|
||||
static const Event MONITORING_AMBIGUOUS = MAKE_EVENT(10, severity::HIGH);
|
||||
static const Event DEVICE_WANTS_HARD_REBOOT = MAKE_EVENT(11, severity::HIGH);
|
||||
|
||||
static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_IF;
|
||||
|
||||
|
@ -128,6 +85,7 @@ class DeviceHandlerIF {
|
|||
static const ReturnValue_t NO_REPLY_EXPECTED = MAKE_RETURN_CODE(0xA8);
|
||||
static const ReturnValue_t NON_OP_TEMPERATURE = MAKE_RETURN_CODE(0xA9);
|
||||
static const ReturnValue_t COMMAND_NOT_IMPLEMENTED = MAKE_RETURN_CODE(0xAA);
|
||||
static const ReturnValue_t NON_OP_STATE_OF_CHARGE = MAKE_RETURN_CODE(0xAB);
|
||||
|
||||
// Standard codes used in scanForReply
|
||||
static const ReturnValue_t CHECKSUM_ERROR = MAKE_RETURN_CODE(0xB0);
|
||||
|
@ -179,4 +137,10 @@ class DeviceHandlerIF {
|
|||
virtual MessageQueueId_t getCommandQueue() const = 0;
|
||||
};
|
||||
|
||||
struct ThermalStateCfg {
|
||||
lp_id_t thermalStatePoolId = DeviceHandlerIF::DEFAULT_THERMAL_STATE_POOL_ID;
|
||||
lp_id_t thermalRequestPoolId = DeviceHandlerIF::DEFAULT_THERMAL_HEATING_REQUEST_POOL_ID;
|
||||
uint32_t thermalSetId = DeviceHandlerIF::DEFAULT_THERMAL_SET_ID;
|
||||
};
|
||||
|
||||
#endif /* FSFW_DEVICEHANDLERS_DEVICEHANDLERIF_H_ */
|
||||
|
|
|
@ -7,27 +7,21 @@
|
|||
|
||||
class DeviceHandlerThermalSet : public StaticLocalDataSet<2> {
|
||||
public:
|
||||
DeviceHandlerThermalSet(
|
||||
HasLocalDataPoolIF* hkOwner, uint32_t setId = DeviceHandlerIF::DEFAULT_THERMAL_SET_ID,
|
||||
lp_id_t thermalStateId = DeviceHandlerIF::DEFAULT_THERMAL_STATE_POOL_ID,
|
||||
lp_id_t heaterRequestId = DeviceHandlerIF::DEFAULT_THERMAL_HEATING_REQUEST_POOL_ID)
|
||||
: DeviceHandlerThermalSet(hkOwner->getObjectId(), setId, thermalStateId, heaterRequestId) {}
|
||||
DeviceHandlerThermalSet(HasLocalDataPoolIF* hkOwner, ThermalStateCfg cfg)
|
||||
: DeviceHandlerThermalSet(hkOwner->getObjectId(), cfg) {}
|
||||
|
||||
DeviceHandlerThermalSet(
|
||||
object_id_t deviceHandler, uint32_t setId = DeviceHandlerIF::DEFAULT_THERMAL_SET_ID,
|
||||
lp_id_t thermalStateId = DeviceHandlerIF::DEFAULT_THERMAL_STATE_POOL_ID,
|
||||
lp_id_t thermalStateRequestId = DeviceHandlerIF::DEFAULT_THERMAL_HEATING_REQUEST_POOL_ID)
|
||||
: StaticLocalDataSet(sid_t(deviceHandler, setId)),
|
||||
thermalStatePoolId(thermalStateId),
|
||||
heaterRequestPoolId(thermalStateRequestId) {}
|
||||
DeviceHandlerThermalSet(object_id_t deviceHandler, ThermalStateCfg cfg)
|
||||
: StaticLocalDataSet(sid_t(deviceHandler, cfg.thermalSetId)),
|
||||
thermalStatePoolId(cfg.thermalStatePoolId),
|
||||
heaterRequestPoolId(cfg.thermalRequestPoolId) {}
|
||||
|
||||
const lp_id_t thermalStatePoolId;
|
||||
const lp_id_t heaterRequestPoolId;
|
||||
|
||||
lp_var_t<DeviceHandlerIF::dh_thermal_state_t> thermalState =
|
||||
lp_var_t<DeviceHandlerIF::dh_thermal_state_t>(thermalStatePoolId, sid.objectId, this);
|
||||
lp_var_t<DeviceHandlerIF::dh_thermal_state_t>(sid.objectId, thermalStatePoolId, this);
|
||||
lp_var_t<DeviceHandlerIF::dh_heater_request_t> heaterRequest =
|
||||
lp_var_t<DeviceHandlerIF::dh_heater_request_t>(heaterRequestPoolId, sid.objectId, this);
|
||||
lp_var_t<DeviceHandlerIF::dh_heater_request_t>(sid.objectId, heaterRequestPoolId, this);
|
||||
};
|
||||
|
||||
#endif /* FSFW_DEVICEHANDLERS_DEVICEHANDLERTHERMALSET_H_ */
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue