Compare commits

...

304 Commits

Author SHA1 Message Date
Robin Müller fb2e480705 did i forgot to push? 2024-04-16 13:58:10 +02:00
Robin Müller b8ae646060 this include might be missing 2024-04-16 13:53:35 +02:00
Robin Müller 8b21dd276d Merge pull request 'implement relative timeshift' (#173) from time-service-relative-timeshift into develop
Reviewed-on: #173
Reviewed-by: Marius Eggert <eggertm@irs.uni-stuttgart.de>
2024-04-09 13:31:13 +02:00
Robin Müller e00da212cd Merge branch 'develop' into time-service-relative-timeshift 2024-04-09 11:11:59 +02:00
Robin Müller a229748aa4 distinct clock dump events 2024-04-09 10:57:00 +02:00
Robin Müller e6e3753324 Merge pull request 're-work some FDIR logic' (#172) from improve-dev-fdir into develop
Reviewed-on: #172
2024-04-09 10:47:32 +02:00
Robin Müller 94bd1ba2ab fix comment blocks 2024-04-08 13:38:14 +02:00
Robin Müller e12a8cfa29 make this change downwards compatible 2024-04-08 13:31:21 +02:00
Robin Müller efbcddc2e5 improvements for time service 2024-04-08 13:26:55 +02:00
Robin Müller 31d4b85523 some optimizations 2024-04-08 13:14:20 +02:00
Robin Müller aff6bb673b
make marius the happies man alive 2024-04-08 10:34:28 +02:00
Robin Müller f8e3777c43
more fixes 2024-04-03 16:23:21 +02:00
Robin Müller 0e2fa8dc83
lets not forget error handling 2024-04-03 16:19:40 +02:00
Robin Müller 0cfe559b93
implement relative timeshift 2024-04-03 16:15:07 +02:00
Robin Müller c5159fb645
optimize docs 2024-04-03 12:52:32 +02:00
Robin Müller 203c0bac5c
re-work some FDIR logic 2024-04-03 12:47:11 +02:00
Marius Eggert 43ea29cb84 Merge pull request 'Function to prevent Quaternion Sign Jump' (#171) from quat-no-sign-jump into develop
Reviewed-on: #171
Reviewed-by: Robin Müller <muellerr@irs.uni-stuttgart.de>
2024-03-18 10:59:19 +01:00
Marius Eggert 27c8a97d45 added function to prevent quaternion sign jump 2024-03-13 16:59:14 +01:00
Marius Eggert 47b21caf5f Merge pull request 'Removed duplicate Code' (#170) from cleanup into develop
Reviewed-on: #170
Reviewed-by: Robin Müller <muellerr@irs.uni-stuttgart.de>
2024-03-06 10:54:12 +01:00
Marius Eggert 2673070204 actually do something with this rtval 2024-03-06 09:41:02 +01:00
Marius Eggert 518a07d05b removed duplicate code 2024-03-05 14:29:47 +01:00
Marius Eggert 516357d855 Merge pull request 'Expand Globalfunctions' (#168) from expand-globalfunctions into develop
Reviewed-on: #168
Reviewed-by: Robin Müller <muellerr@irs.uni-stuttgart.de>
2024-02-27 12:50:28 +01:00
Marius Eggert ac28b7e00d Merge branch 'develop' into expand-globalfunctions 2024-02-26 13:57:04 +01:00
Marius Eggert 0d4a862c1a Merge pull request 'Increase configurability of PusServiceBase' (#169) from psb-update into develop
Reviewed-on: #169
Reviewed-by: Marius Eggert <eggertm@irs.uni-stuttgart.de>
2024-02-26 13:56:46 +01:00
Marius Eggert b2576d3422 why are we ignoring usec 2024-02-23 11:33:20 +01:00
Marius Eggert bccaf4a9ea capital 2024-02-23 11:31:11 +01:00
Marius Eggert 7d4e77843b frmt 2024-02-23 11:09:59 +01:00
Robin Müller cd2cd61ba5 Increase configurability of PusServiceBase 2024-02-13 15:57:43 +01:00
Marius Eggert 90f3f8ef1f removed printout 2024-02-12 14:51:54 +01:00
Marius Eggert 9894935e99 time systems 2024-02-12 14:42:58 +01:00
Marius Eggert a3a6c0720c fixes 2024-02-12 14:36:14 +01:00
Marius Eggert d5a52eadbb i should have done this ages ago 2024-02-12 14:20:04 +01:00
Marius Eggert b5e7179af1 Merge pull request 'Rotation from Quaternions' (#167) from rotation-from-quaternions into develop
Reviewed-on: #167
Reviewed-by: Robin Müller <muellerr@irs.uni-stuttgart.de>
2024-01-29 14:11:08 +01:00
Marius Eggert 5879eb7f7b rotation from quaternions 2024-01-26 11:06:05 +01:00
Robin Müller e64e8b274d Merge pull request 'check whether map is full on insert' (#166) from insert-full-check into develop
Reviewed-on: #166
Reviewed-by: Marius Eggert <eggertm@irs.uni-stuttgart.de>
2023-12-12 17:53:14 +01:00
Robin Müller 48bcce65b1 check whether map is full on insert 2023-12-12 11:24:35 +01:00
Marius Eggert 7105e199c6 Merge pull request 'SLERP for antiparallel Quaternions' (#165) from slerp-fix-antiparallel-quaternions into develop
Reviewed-on: #165
Reviewed-by: Robin Müller <muellerr@irs.uni-stuttgart.de>
2023-12-06 10:41:02 +01:00
Marius Eggert 94de483836 small fix 2023-12-06 09:26:22 +01:00
Robin Müller c648229c99 Merge pull request 'SLERP' (#163) from slerp into develop
Reviewed-on: #163
Reviewed-by: Robin Müller <muellerr@irs.uni-stuttgart.de>
2023-12-05 09:25:48 +01:00
Marius Eggert 5b661551a8 fixes 2023-12-04 17:52:24 +01:00
Robin Müller 3978524181 Merge branch 'develop' into slerp 2023-11-29 15:19:09 +01:00
Robin Müller 7187f2b5cd Merge pull request 'TLE turns too old after just 7 Days' (#164) from tle-too-old into develop
Reviewed-on: #164
2023-11-29 15:17:39 +01:00
Robin Müller 8e367abb47 Merge branch 'develop' into tle-too-old 2023-11-29 15:17:19 +01:00
Robin Müller b28174db24 Merge pull request 'Fresh DHB pre-queue check hook' (#162) from fresh-dhb-pre-queue-hook into develop
Reviewed-on: #162
Reviewed-by: Marius Eggert <eggertm@irs.uni-stuttgart.de>
2023-11-29 14:18:23 +01:00
Marius Eggert c906acd659 tle turns too old after just 7 days 2023-11-29 09:48:11 +01:00
Marius Eggert 8dfc84c0b5 smoll fix 2023-11-27 10:52:47 +01:00
Marius Eggert 74775bb59d slerp 2023-11-27 10:38:25 +01:00
Robin Müller c02d9e009e docs improvements and fix 2023-11-21 17:40:06 +01:00
Robin Müller 0021aa29f5 pre-queue hook 2023-11-21 17:37:02 +01:00
Ulrich Mohr 41d67bff63 Merge pull request 'New simpler DHB' (#161) from new-dhb into develop
Reviewed-on: #161
Reviewed-by: Ulrich Mohr <mohr@irs.uni-stuttgart.de>
2023-11-16 11:02:44 +01:00
Robin Müller 8d7bb51d44
add missing call to perform HK op 2023-11-15 11:39:04 +01:00
Robin Müller 7673d8b396
add paramHelper 2023-11-15 10:03:56 +01:00
Robin Müller 91b194d8eb Merge branch 'new-dhb' of https://egit.irs.uni-stuttgart.de/eive/fsfw into new-dhb 2023-11-14 11:48:20 +01:00
Robin Müller 698897bfc5 default args 2023-11-14 11:48:17 +01:00
Robin Müller d554062b86
trigger event default arguments 2023-11-13 15:32:42 +01:00
Robin Müller bf7fac071c add mode setters 2023-11-09 17:18:33 +01:00
Robin Müller 35be7da353
some more docs 2023-11-09 11:28:59 +01:00
Robin Müller 18cc870c8e
add FDIR handling 2023-11-09 11:04:45 +01:00
Robin Müller 133ca51d18
visibility changes 2023-11-09 10:45:21 +01:00
Robin Müller 0a40391a75
thats the baseline 2023-11-09 10:36:45 +01:00
Robin Müller cc3e64e70d Merge pull request 'CFDP SOURCE handler' (#157) from cfdp-source-handler into develop
Reviewed-on: #157
Reviewed-by: Marius Eggert <eggertm@irs.uni-stuttgart.de>
2023-10-19 10:59:53 +02:00
Robin Müller 6021257a87
unittest fix 2023-10-19 10:21:18 +02:00
Robin Müller 63c238005e Merge remote-tracking branch 'origin/develop' into cfdp-source-handler 2023-10-11 12:57:14 +02:00
Marius Eggert 0f604b35c6 improved readability 2023-10-09 09:26:56 +02:00
Marius Eggert e3a815444e checkModeCommand to protected 2023-09-29 15:26:43 +02:00
Marius Eggert 19093866ee rtval for non op soc 2023-09-29 14:27:54 +02:00
Robin Müller 497f947237
add missing 0 termination 2023-09-14 15:04:54 +02:00
Robin Müller 5bd020193b
initialize result 2023-09-11 15:38:46 +02:00
Robin Müller 420c0625a5
result was not stored properly 2023-09-11 15:38:06 +02:00
Robin Müller 42a0b15303
hardcore bug 2023-09-06 20:49:53 +02:00
Robin Müller c199cbedaa
some improvements, remove debugging stuff 2023-09-06 13:40:18 +02:00
Robin Müller c4e18cc2f3
what was i thinking here? 2023-09-06 11:45:02 +02:00
Robin Müller c143198494
debugging 2023-09-06 10:11:09 +02:00
Robin Müller 448fbd0d38
this should be less confusing, saner defaults 2023-09-05 16:04:48 +02:00
Robin Müller 470f589bde
need to rework this fsm.. but works now 2023-09-04 11:01:55 +02:00
Robin Müller dfcfb035be
fix some retval duplications 2023-08-31 15:09:22 +02:00
Robin Müller 6e53582dc9
split up CFDP retval domains 2023-08-31 14:59:09 +02:00
Robin Müller fb1500e041
continue 2023-08-30 11:34:38 +02:00
Robin Müller ea2e58249d
API improvements 2023-08-30 11:18:49 +02:00
Robin Müller 9ef63825f3
optimization 2023-08-16 13:15:34 +02:00
Robin Müller 073cb4b3d5
adaptions for reserved message handling 2023-08-16 13:10:21 +02:00
Robin Müller 8c11685240
introduce handling for full target queue 2023-08-14 21:19:35 +02:00
Robin Müller cb1aaea6cd
add more checks 2023-08-14 21:04:22 +02:00
Robin Müller 22df8f6147
fix the tests 2023-08-14 21:01:29 +02:00
Robin Müller 60dcacf432
further tweaks for both CFDP handlers 2023-08-14 20:47:27 +02:00
Robin Müller b39e1c7e07 Merge remote-tracking branch 'origin/develop' into cfdp-source-handler 2023-08-14 15:59:13 +02:00
Robin Müller 036667a969
type improvements 2023-08-14 15:58:01 +02:00
Robin Müller 67c38f327e
rename source file 2023-08-14 13:54:11 +02:00
Robin Müller e1816ed230
that should be all indications 2023-08-14 13:45:13 +02:00
Robin Müller 5ff464252f
added some user checks 2023-08-14 13:40:25 +02:00
Robin Müller cd8d64830c
more checks 2023-08-14 13:33:47 +02:00
Robin Müller b7056a7467
additional checks 2023-08-14 13:24:22 +02:00
Robin Müller 0fc2c7b5e9
oops 2023-08-14 13:19:48 +02:00
Robin Müller eae7c44874
reset error count 2023-08-14 13:19:32 +02:00
Robin Müller e4aae75747
more checks 2023-08-14 12:19:55 +02:00
Robin Müller b094ba145f
multi file segment works 2023-08-14 12:15:35 +02:00
Robin Müller 15629abf19
the joys of UB or whatever that crap was 2023-08-14 12:13:29 +02:00
Robin Müller 7aeb25e064
unittest for transfer with 2 segments 2023-08-14 11:26:57 +02:00
Robin Müller d246ce34d0 Merge pull request 'Change TLE validity duration' (#159) from spg4-tle-too-old into develop
Reviewed-on: #159
Reviewed-by: Robin Müller <muellerr@irs.uni-stuttgart.de>
2023-08-14 10:09:00 +02:00
Marius Eggert 796c7a9e37 tle is too old after 30 days now 2023-08-09 11:42:11 +02:00
Robin Müller 7c875f1067
unittest for small file transfer done 2023-08-04 15:17:53 +02:00
Robin Müller e8451cac31
add one test condition 2023-08-04 14:21:36 +02:00
Robin Müller 8ddd6eb18d
some improvements for test 2023-08-03 17:44:30 +02:00
Robin Müller 6c6b552059
start small file transfer test 2023-08-03 17:43:03 +02:00
Robin Müller 9a1437980f
add empty stubs 2023-08-03 15:50:27 +02:00
Robin Müller 12e52a92f2
empty file transfer test done 2023-08-03 15:49:23 +02:00
Robin Müller dffce43e6b
metadata PDU seems to be correct 2023-08-03 15:30:38 +02:00
Robin Müller daf75547a4
insidious bug 2023-08-03 15:13:26 +02:00
Robin Müller 0cccf26021
should not be problematic but somehow is.. 2023-08-03 14:34:21 +02:00
Robin Müller c075f27e20
start verifying metadata PDU 2023-08-03 13:57:55 +02:00
Robin Müller 3167988951
continue source handler 2023-08-03 13:03:58 +02:00
Robin Müller a856f91c67
nice 2023-07-27 17:15:01 +02:00
Robin Müller f49e607881
finally it works 2023-07-27 15:07:14 +02:00
Robin Müller 0f208ec75a
seems to work well 2023-07-27 14:55:46 +02:00
Robin Müller 5679b139ad
reserved message unittest working 2023-07-26 18:20:32 +02:00
Robin Müller 947f2b8685
add some additional API 2023-07-26 17:47:27 +02:00
Robin Müller 291c75c01f
test put request 2023-07-26 17:29:35 +02:00
Robin Müller fde277cd06
start adding dedicated put request handler 2023-07-26 17:17:51 +02:00
Robin Müller bb186fc965
more bugfixes 2023-07-26 16:58:58 +02:00
Robin Müller e8bf8b9575
looking good 2023-07-26 16:36:21 +02:00
Robin Müller 8f5a8b13d3
parsing finally works 2023-07-26 16:25:42 +02:00
Robin Müller 314cba363f
contnue msg parser unittest 2023-07-25 16:16:35 +02:00
Robin Müller 244e2d0737
start adding message parser unittests 2023-07-25 13:58:22 +02:00
Robin Müller 8f0974d83e
finished reserved msg creator function 2023-07-24 18:07:20 +02:00
Robin Müller 8581f9a6f3
start implementing reserved message creator 2023-07-24 18:01:25 +02:00
Robin Müller 844c90a625
constructor fix 2023-07-24 16:42:13 +02:00
Robin Müller 437851db3e
naming 2023-07-24 16:40:44 +02:00
Robin Müller e8b9897ee3
even better name 2023-07-24 16:40:25 +02:00
Robin Müller 33df8e8cc5
this parser should do the job 2023-07-24 16:38:11 +02:00
Robin Müller 52fc0958f7
iniitalize field 2023-07-24 11:58:06 +02:00
Robin Müller 66704dc571
getting tricky again.. 2023-07-24 11:57:33 +02:00
Robin Müller 0943863ec6
need to think about that parser again.. 2023-07-24 11:35:26 +02:00
Robin Müller 2585028e75
put request serializable now 2023-07-24 11:33:37 +02:00
Robin Müller 7bf7336d4a
almost done 2023-07-24 11:15:50 +02:00
Robin Müller b0b6c68720
we already have CFDP messages 2023-07-24 11:05:11 +02:00
Robin Müller a1f36a0dd8
put request 2023-07-24 10:58:18 +02:00
Robin Müller e4665c9394
continue with the msg to user / put request architecture 2023-07-24 10:52:38 +02:00
Robin Müller 98cbf38432
this is going to be complex.. 2023-07-24 10:11:16 +02:00
Robin Müller 5d3f00da7f
that should do the job 2023-07-24 10:06:45 +02:00
Robin Müller 69fd6d0f6a
lets see how we can do this 2023-07-21 16:35:05 +02:00
Robin Müller 045054fce0
start implementing metadata parser 2023-07-21 16:12:17 +02:00
Robin Müller 4c9e731113 Merge branch 'cfdp-source-handler' of https://egit.irs.uni-stuttgart.de/eive/fsfw into cfdp-source-handler 2023-07-21 16:09:59 +02:00
Robin Müller e00e198ff1
this seems to work 2023-07-21 16:09:52 +02:00
Robin Müller 9c8434d856
LOOKING GOOOD 2023-07-19 23:43:40 +02:00
Robin Müller 42c215ef70
some additional notes 2023-07-19 23:24:43 +02:00
Robin Müller 273fd3ebfd
added sequence count provider abstraction 2023-07-19 23:22:55 +02:00
Robin Müller 6c9c4ee047
add EOF impl 2023-07-19 14:06:15 +02:00
Robin Müller 1bfb695b41
some minor tweaks 2023-07-19 14:02:03 +02:00
Robin Müller 1561b9a247
implemented fle data PDUs 2023-07-19 13:44:52 +02:00
Robin Müller 896b7a7358
start FD PDU handling 2023-07-19 00:12:14 +02:00
Robin Müller 8e62143ac8
continue impl 2023-07-18 09:38:46 +02:00
Robin Müller 1d97327f79
start implementing metadata PDU generation 2023-07-17 18:56:10 +02:00
Robin Müller 5e9d402598
getFileSize API for fsfw 2023-07-17 16:40:44 +02:00
Robin Müller b53c48863f
start introducing FSM result 2023-07-17 15:21:22 +02:00
Robin Müller 4dc6398fd5
continue source FSM 2023-07-17 15:11:51 +02:00
Robin Müller 8fcc4eab60
some internal state handling 2023-07-17 15:03:08 +02:00
Robin Müller 972dc7e19e
continue source handler 2023-07-17 14:54:45 +02:00
Robin Müller 06ef498a18
start implementing put request function 2023-07-17 14:48:37 +02:00
Robin Müller 6322a31566
some fixes 2023-07-17 13:43:48 +02:00
Robin Müller 95b77ed826
put request support baseline 2023-07-17 13:28:32 +02:00
Robin Müller 3b1da85229
start setting up source handler 2023-07-17 11:37:20 +02:00
Robin Müller 1cbcfc08ff
reorder includes 2023-07-17 10:46:12 +02:00
Robin Müller d575da8540 Merge pull request 'Small tweak to allow immediate HK generation' (#158) from small-hk-tweak into develop
Reviewed-on: #158
Reviewed-by: Marius Eggert <eggertm@irs.uni-stuttgart.de>
2023-07-17 10:37:39 +02:00
Robin Müller ca27cef2ee
Merge branch 'small-hk-tweak' into cfdp-source-handler 2023-07-17 10:37:03 +02:00
Robin Müller 62ace649a7
fix unittest 2023-07-17 10:35:35 +02:00
Robin Müller aac74fae38
shared cmake file 2023-07-17 10:34:19 +02:00
Robin Müller a26b0c38ac
small tweak to allow immediate HK generation 2023-07-17 10:31:02 +02:00
Robin Müller f44110a7f5
share the FSFW Param block 2023-07-17 10:25:09 +02:00
Robin Müller 35712070cf
source handler 2023-07-17 10:15:06 +02:00
Robin Müller 1b79713430 Merge branch 'cfdp-source-handler' of https://egit.irs.uni-stuttgart.de/eive/fsfw into cfdp-source-handler 2023-07-17 09:53:51 +02:00
Robin Müller a6cc5171da
continue source handler 2023-07-17 09:53:23 +02:00
Robin Müller 9994c46e47 Merge branch 'develop' into cfdp-source-handler 2023-07-14 16:01:51 +02:00
Robin Müller cf927ecee7
added bare structure of FSM 2023-07-14 15:56:38 +02:00
Robin Müller 42e74d22cc Merge pull request 'countdown based HK generation' (#156) from hk-generation-countdown-based into develop
Reviewed-on: #156
Reviewed-by: Marius Eggert <eggertm@irs.uni-stuttgart.de>
2023-07-11 17:35:10 +02:00
Robin Müller 36caa58043 Merge branch 'develop' into hk-generation-countdown-based 2023-07-11 17:34:24 +02:00
Robin Müller 988e07f0be
countdown 2023-07-11 15:40:43 +02:00
Robin Müller 88e8665280
important bugfix for PUS TM creator 2023-07-10 17:45:02 +02:00
Robin Müller 9c8b1c697b
added back missing function 2023-07-10 14:20:02 +02:00
Robin Müller 110cb903a6
countdown based HK generation 2023-07-10 14:14:31 +02:00
Robin Müller 1b23aa4246
bugfixes and improvements for dest handler 2023-06-30 12:01:18 +02:00
Robin Müller 7d713219c5
continue source handler 2023-06-30 11:59:22 +02:00
Robin Müller 1be09a2310
the C++ tooling is shit 2023-06-30 11:48:25 +02:00
Robin Müller 7add782470
start CFDP source handler 2023-06-30 11:36:19 +02:00
Marius Eggert 8da89eba80 Merge pull request 'add API to set msg counter' (#155) from pus-msg-counter-mutable into develop
Reviewed-on: #155
Reviewed-by: Marius Eggert <eggertm@irs.uni-stuttgart.de>
2023-06-28 13:19:28 +02:00
Robin Müller 7e8845f2c2 Merge remote-tracking branch 'origin/develop' into pus-msg-counter-mutable 2023-06-26 18:12:36 +02:00
Robin Müller 6aff3250c2 Merge pull request 'Internal Error Reporter Configurability' (#154) from internal-error-reporter-set into develop
Reviewed-on: #154
2023-06-26 18:10:06 +02:00
Robin Müller c3572e31a8
add API to set msg counter 2023-06-25 12:35:50 +02:00
Robin Müller 2293e7f2bb
typo 2023-06-22 16:12:41 +02:00
Robin Müller a85a38c882
some thnings are configurable now 2023-06-22 16:08:29 +02:00
Robin Müller 0f76cdb3ba
typo 2023-06-20 20:36:03 +02:00
Robin Müller 268c2e87c9 Merge pull request 'max value calc fix' (#153) from max-value-fix-v2 into develop
Reviewed-on: #153
2023-06-20 18:20:00 +02:00
Robin Müller 87f94a252f Merge branch 'develop' into max-value-fix-v2 2023-06-20 18:19:19 +02:00
Ulrich Mohr c7037d417a nullptr check for optional argument 2023-06-20 11:54:15 +02:00
Marius Eggert f80c5980ea max value calc fix 2023-06-19 17:04:45 +02:00
Marius Eggert ad01642fee Merge pull request 'specify truncate flag explicitely' (#151) from specify-truncate-flag-explicitely into develop
Reviewed-on: #151
Reviewed-by: Marius Eggert <eggertm@irs.uni-stuttgart.de>
2023-06-19 09:32:19 +02:00
Robin Müller f2947bc78e
specify truncate flag explicitely 2023-06-18 19:04:36 +02:00
Robin Müller 0a977ea688 Merge pull request 'make number of parallel cmds configurable' (#149) from make-srv3-num-parallel-cmds-configurable into develop
Reviewed-on: #149
2023-06-14 03:37:02 +02:00
Robin Müller 74b164b1da make number of parallel cmds configurable 2023-06-13 08:09:04 +02:00
Robin Müller 5322de0599 Merge pull request 'Pull CFPD bugfix in dev branch' (#147) from pull-cfdp-fix-into-dev-branch into obsw-v3.0.0-dev
Reviewed-on: #147
2023-06-09 13:41:29 +02:00
Robin Müller 9a4bf51006 Merge branch 'develop' into obsw-v3.0.0-dev 2023-06-09 13:11:30 +02:00
Robin Müller 3a70229510 Merge pull request 'configurable queue depth' (#146) from service-8-configurable-queue-depth into obsw-v3.0.0-dev
Reviewed-on: #146
2023-06-09 13:03:17 +02:00
Robin Müller b3beedad9f Merge branch 'obsw-v3.0.0-dev' into service-8-configurable-queue-depth 2023-06-09 13:03:08 +02:00
Robin Müller efe217a197 Merge pull request 'Rework L3GD20H Config' (#143) from gyr-config-rework into obsw-v3.0.0-dev
Reviewed-on: #143
2023-06-09 13:01:23 +02:00
Robin Müller b442ca09b9 configurable queue depth 2023-06-07 13:46:46 +02:00
Robin Müller 9372b2a575
Merge remote-tracking branch 'upstream/development' into develop 2023-05-25 15:03:54 +02:00
Marius Eggert aafa53148e Merge pull request 'CFDP Bugfix' (#144) from cfdp-bugfix-unittest-fixes into develop
Reviewed-on: #144
Reviewed-by: Marius Eggert <eggertm@irs.uni-stuttgart.de>
2023-05-22 10:40:44 +02:00
Robin Müller e0adb3325f
werks 2023-05-22 10:37:26 +02:00
Robin Müller 4391823f01
changelog 2023-05-15 16:14:36 +02:00
Robin Müller 1a77e6bb09
proper floating point comparison 2023-05-15 16:13:05 +02:00
Robin Müller cae131edcf
CFDP and unittest bugfixes 2023-05-15 16:02:55 +02:00
Ulrich Mohr 4518fec65c CHANGELOG 2023-05-08 15:25:47 +02:00
Ulrich Mohr dac1aacab2 Merge pull request 'Update Power Switch IF' (#743) from eive/fsfw:update_power_switch_if into development
Reviewed-on: fsfw/fsfw#743
2023-05-08 15:00:47 +02:00
Ulrich Mohr 0042f92fdf Merge pull request 'bump ETL version' (#748) from KSat/fsfw:bump_etl_dep into development
Reviewed-on: fsfw/fsfw#748
2023-05-08 14:53:02 +02:00
Ulrich Mohr 656faf8169 Merge remote-tracking branch 'upstream/development' into update_power_switch_if 2023-05-08 14:44:27 +02:00
Ulrich Mohr f84431e965 Merge pull request 'bugfix and changelog for Linux getUptime' (#745) from eive/fsfw:important_bugfix_linux_get_uptime into development
Reviewed-on: fsfw/fsfw#745
2023-05-08 14:29:55 +02:00
Ulrich Mohr 0cec9ebb73 Merge pull request 'small tweak for version getter' (#744) from eive/fsfw:small_version_getter_tweak into development
Reviewed-on: fsfw/fsfw#744
2023-05-08 14:13:06 +02:00
Ulrich Mohr a440b7c394 Merge pull request 'add CFDP subsystem ID' (#742) from eive/fsfw:add_cfdp_subsystem_id into development
Reviewed-on: fsfw/fsfw#742
2023-05-08 14:09:04 +02:00
Ulrich Mohr bbfc1b2b34 Merge pull request 'FixedArrayList compile time assert' (#740) from eive/fsfw:container_additional_assert into development
Reviewed-on: fsfw/fsfw#740
2023-05-08 14:04:56 +02:00
Robin Müller 025b379e8b
bump ETL version 2023-05-04 14:04:55 +02:00
Marius Eggert 258f0d3313 use both LPFs 2023-04-19 15:25:14 +02:00
Robin Müller 5eb9ee8bc1
DHB fdir: event queue depth confgurable 2023-04-14 21:22:24 +02:00
Robin Müller 7f61d17cee
even better event manager printout 2023-04-14 21:08:44 +02:00
Robin Müller ffa2fa477f Merge pull request 'move CFDP handler' (#142) from move_cfdp_handler into develop
Reviewed-on: #142
2023-04-11 16:50:46 +02:00
Robin Müller 894d1e3b87
move CFDP handler 2023-04-11 16:36:54 +02:00
Robin Müller 285d327b97
clean up spi retval defs 2023-04-07 17:42:44 +02:00
Robin Müller e97fa5ac84
add skip directive for retvals 2023-04-07 11:03:46 +02:00
Robin Müller 5a9304765f
accepts action commands without ipc data 2023-04-06 22:34:57 +02:00
Robin Müller 6650c293da
change collection interval is public now 2023-04-04 15:59:26 +02:00
Robin Müller 9fca7581dd Merge branch 'develop' of https://egit.irs.uni-stuttgart.de/eive/fsfw into develop 2023-04-04 01:52:29 +02:00
Robin Müller 4af90f99f3
changelog 2023-04-04 01:52:26 +02:00
Robin Müller 94cdf67a80
make health functions virtual 2023-04-04 01:51:58 +02:00
Robin Müller 7966ede11b
add O_SYNC flag for UioMapper 2023-04-03 21:57:18 +02:00
Robin Müller 7a392dc33a
new register function 2023-04-03 18:54:35 +02:00
Robin Müller 1e3c89b672
i dont think ths needs to be public 2023-04-03 17:59:14 +02:00
Robin Müller e2e87b149d
initialize switch state list 2023-04-03 14:31:45 +02:00
Robin Müller 4f632e2c68
ctrl base bugfix 2023-03-28 19:37:47 +02:00
Robin Müller 314f0fa2cd
start power switch component in undefined mode 2023-03-28 15:27:48 +02:00
Robin Müller b31e1037fb
HK service configurable queue depth 2023-03-26 20:05:10 +02:00
Robin Müller b814e7198f Merge pull request 'Allow creating regular threads' (#140) from allow_creating_regular_threads into develop
Reviewed-on: #140
2023-03-24 14:15:53 +01:00
Robin Müller 6328b70d7b Merge branch 'develop' into allow_creating_regular_threads 2023-03-24 14:15:39 +01:00
Robin Müller a937b457f9
this is so confusing 2023-03-24 14:10:47 +01:00
Robin Müller 4415dc24e1
fix host OSAL 2023-03-24 13:25:34 +01:00
Robin Müller e704295cce
default value 2023-03-24 11:58:23 +01:00
Robin Müller d16b3c7e67
try to do this cleanly 2023-03-24 11:53:41 +01:00
Robin Müller 3b86545725 Merge pull request 'add BUSY retval' (#141) from busy_retval_dhb_com into develop
Reviewed-on: #141
2023-03-24 11:35:09 +01:00
Robin Müller cf6150cc18
add BUSY retval 2023-03-24 00:57:44 +01:00
Robin Müller bfb5c2ff03 Merge branch 'develop' into allow_creating_regular_threads 2023-03-23 18:45:49 +01:00
Robin Müller bf02061d47 Merge pull request 'use RR sched instead of FIFO for Linux RT' (#139) from use_rr_sched into develop
Reviewed-on: #139
2023-03-23 18:45:09 +01:00
Robin Müller 2c4e110254 Merge branch 'develop' into use_rr_sched 2023-03-23 18:44:59 +01:00
Robin Müller 7ed75ea87b Merge remote-tracking branch 'origin/develop' into allow_creating_regular_threads 2023-03-23 18:44:06 +01:00
Robin Müller db4587bb59
allow creating regular threads 2023-03-23 18:29:17 +01:00
Robin Müller 33ac395072
use RR sched instead of FIFO for Linux RT 2023-03-23 15:42:14 +01:00
Robin Müller f8a7c1d4ed
rename namespace 2023-03-22 01:03:49 +01:00
Robin Müller 341437df13
add flush functions for serial helpers 2023-03-21 20:20:13 +01:00
Robin Müller 227524a21d
transition source submode is tricky 2023-03-20 15:49:09 +01:00
Robin Müller 0f81d5e458
Merge remote-tracking branch 'upstream/development' into container_additional_assert 2023-03-15 12:34:36 +01:00
Robin Müller b50f092939
Merge remote-tracking branch 'upstream/development' into update_power_switch_if 2023-03-15 12:33:08 +01:00
Robin Müller 2f90e12179
Merge remote-tracking branch 'upstream/development' into important_bugfix_linux_get_uptime 2023-03-15 12:32:25 +01:00
Robin Müller 8b77fac099 Merge pull request 'health service fixes and changelog' (#746) from eive/fsfw:health_service_fixes into development
Reviewed-on: fsfw/fsfw#746
2023-03-15 12:29:31 +01:00
Robin Müller 47503824d7
health service fixes and changelog 2023-03-15 12:27:39 +01:00
Robin Müller 5e3f5c4121
fuse update 2023-03-15 12:25:39 +01:00
Robin Müller 1f36c082ef
bugfix and changelog for Linux getUptime 2023-03-15 12:21:50 +01:00
Robin Müller aa84e93603
small tweak for version getter 2023-03-15 12:17:36 +01:00
Robin Müller 8f63a0e747
changelog 2023-03-15 12:15:21 +01:00
Robin Müller 6fc8f756a7
update power switch IF 2023-03-15 12:13:55 +01:00
Robin Müller d98ed40e3d
add CFDP subsystem ID 2023-03-15 12:09:30 +01:00
Robin Müller b057250bfb
changelog 2023-03-15 11:53:12 +01:00
Robin Müller 066dd0d397
changelog 2023-03-15 11:52:20 +01:00
Robin Müller f735c2e9d4
assert size larger than 0 2023-03-15 11:51:51 +01:00
Robin Müller 43fd0b2f59
resolve some more merge conflicts 2023-03-15 11:48:50 +01:00
Robin Müller d0607824ad
Merge remote-tracking branch 'upstream/development' into develop 2023-03-15 11:40:48 +01:00
Robin Müller cf27954a86
changelog 2023-03-14 19:55:01 +01:00
Robin Müller f84e3284ab
just hardcode spill option to true 2023-03-14 19:54:21 +01:00
Robin Müller 5250423d1d Merge pull request 'Periodic HK helper simplification' (#136) from periodic_hk_helper_simplification into develop
Reviewed-on: #136
2023-03-14 18:27:14 +01:00
Robin Müller 522bd41d6e
changelog 2023-03-14 18:26:44 +01:00
Robin Müller c61c85280b
remove more code 2023-03-14 18:26:04 +01:00
Robin Müller afbe5e1f65
Merge remote-tracking branch 'origin/develop' into periodic_hk_helper_simplification 2023-03-14 18:23:57 +01:00
Robin Müller 4c88ab80c8 Merge pull request 'Pool Manager spill to higher pools option' (#135) from pool_manager_spilling_opt into develop
Reviewed-on: #135
2023-03-14 18:22:31 +01:00
Robin Müller 5ba69b169f
changelog 2023-03-14 18:22:00 +01:00
Robin Müller 40405fe6c7
add spill option 2023-03-14 18:21:16 +01:00
Robin Müller aac32e763c
some compile fixes 2023-03-14 18:20:17 +01:00
Robin Müller bf980d74c0
HK helper simplification 2023-03-14 17:40:39 +01:00
Robin Müller b6b9d1d790
make dataset enable idempotent 2023-03-14 16:49:46 +01:00
Robin Müller 0973ba6bf2 Merge pull request 'basic faulty cb for power switcher component' (#134) from feature_power_switch_faulty_cb into develop
Reviewed-on: #134
2023-03-14 14:15:11 +01:00
Robin Müller 1cfebb5d47 Merge branch 'develop' into feature_power_switch_faulty_cb 2023-03-14 14:14:50 +01:00
Robin Müller 0b0a0299bc
power switch IF improvements 2023-03-14 13:45:03 +01:00
Robin Müller 8382d61b92
possible fix for power switch component 2023-03-14 11:44:13 +01:00
Robin Müller 7208343b6d
basic faulty cb for power switcher component 2023-03-13 16:01:13 +01:00
Ulrich Mohr dc7afc5415 Version bump, CHANGELOG update, format 2023-02-23 13:38:24 +01:00
Ulrich Mohr 9bf3ff95b7 Merge pull request 'Add Health Service Announce All Health Info' (#725) from eive/fsfw:add_health_service_announce_all into development
Reviewed-on: fsfw/fsfw#725
2023-02-23 13:13:56 +01:00
Ulrich Mohr 61562b18ab Merge branch 'development' into add_health_service_announce_all 2023-02-23 12:56:12 +01:00
Ulrich Mohr d76d97a36b changed health table parameter to objectId 2023-02-23 12:44:42 +01:00
Ulrich Mohr 76b377c4c0 Merge pull request 'Mode Service: Add allowed subservice' (#739) from eive/fsfw:small_mode_service_fix into development
Reviewed-on: fsfw/fsfw#739
2023-02-20 13:40:53 +01:00
Ulrich Mohr 3562bf11b9 CHANGELOG update 2023-02-10 11:06:46 +01:00
Ulrich Mohr fffb2b61e5 release check helper 2023-02-10 11:06:30 +01:00
Robin Müller 94e5f62331
add allowed subservice 2023-02-09 18:30:08 +01:00
Ulrich Mohr 0a9c563bbc format 2023-02-09 15:58:48 +01:00
Steffen Gaisser 5b92247fbd Merge branch 'development' into add_health_service_announce_all 2023-02-06 16:31:05 +01:00
Steffen Gaisser d9da55fdab Merge branch 'development' into add_health_service_announce_all 2023-02-06 15:03:52 +01:00
Robin Müller 066f7a6f9b
remove unreachable code 2023-02-06 14:41:14 +01:00
Robin Müller c1f42618db small but important bugfix for health service 2023-02-01 19:59:32 +01:00
Robin Müller 61df451dd8
update changelog 2023-02-01 17:41:47 +01:00
Robin Müller 29ea89044e beatufil 2023-02-01 17:35:49 +01:00
Robin Müller e487f5be87
proper announce all impl 2023-02-01 17:35:32 +01:00
191 changed files with 3726 additions and 1296 deletions

2
.gitignore vendored
View File

@ -1,5 +1,5 @@
# PyCharm and CLion
/.idea/*
.idea/*
!/.idea/runConfigurations
!/.idea/cmake.xml
!/.idea/codeStyles

8
.idea/cmake.xml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CMakeSharedSettings">
<configurations>
<configuration PROFILE_NAME="Debug Test" ENABLED="true" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DFSFW_OSAL=host -DFSFW_BUILD_TESTS=ON" NO_GENERATOR="true" />
</configurations>
</component>
</project>

View File

@ -8,17 +8,55 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
# [unreleased]
# [v6.0.0]
## Fixes
- The `PusTmCreator` API only accepted 255 bytes of source data. It can now accept source
data with a size limited only by the size of `size_t`.
- Important bugfix in CFDP PDU header format: The entity length field and the transaction sequence
number fields stored the actual length of the field instead of the length minus 1 like specified
in the CFDP standard.
- PUS Health Service: Size check for set health command.
Perform operation completion for announce health command.
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/746
- Linux OSAL `getUptime` fix: Check validity of `/proc/uptime` file before reading uptime.
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/745
- Small tweak for version getter
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/744
## Added
- add CFDP subsystem ID
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/742
- `PusTmZcWriter` now exposes API to set message counter field.
- Relative timeshift in the PUS time service.
## Changed
- The PUS time service now dumps the time before setting a new time and after having set the
time.
- HK generation is now countdown based.
- Bump ETL version to 20.35.14
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/748
- Renamed `PCDU_2` subsystem ID to `POWER_SWITCH_IF`.
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/743
- Add new `PowerSwitchIF::SWITCH_UNKNOWN` returnvalue.
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/743
- Assert that `FixedArrayList` is larger than 0 at compile time.
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/740
- Health functions are virtual now.
- PUS Service Base request queue depth and maximum number of handled packets per cycle is now
configurable.
# [v6.0.0] 2023-02-10
## Fixes
- Add monotonic watchdog Clock API and use it in `Countdown` and `Stopwatch` class.
- Bugfix in `Service11TelecommandScheduling` which allowed commands
time tagged in the past to be inserted.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/738
- Mode Service: Add allowed subservice
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/739
- `CService200ModeManagement`: Various bugfixes which lead to now execution complete being generated
on mode announcements, duplicate mode reply generated on announce commands, and the mode read
subservice not working properly.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/736
- Memory leak fixes for the TCP/IP TMTC bridge.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/737
- `Service9TimeManagement`: Fix the time dump at the `SET_TIME` subservice: Include clock timeval
@ -27,16 +65,20 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- HAL MGM3100 Handler: Use axis specific gain/scaling factors. Previously,
only the X scaling factor was used.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/724
- Bugfix for RM3100 MGM sensors. Z value was previously calculated
with bytes of the X value.
- HAL MGM3100 Handler: Z value was previously calculated with bytes of the X value.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/733
- DHB `setNormalDatapoolEntriesInvalid`: The default implementation did not set the validity
to false correctly because the `read` and `write` calls were missing.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/728
- PUS TMTC creator module: Sequence flags were set to continuation segment (0b00) instead
of the correct unsegmented flags (0b11) as specified in the standard.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/727
- TC Scheduler Service 11: Add size and CRC check for contained TC.
Bug: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/issues/719
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/720
- Only delete health table entry in `HealthHelper` destructor if
health table was set.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/710/files
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/710
- I2C Bugfixes: Do not keep iterator as member and fix some incorrect handling with the iterator.
Also properly reset the reply size for successfull transfers and erroneous transfers.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/700
@ -46,6 +88,36 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- `TcpTmTcServer.cpp`: The server was actually not able to handle
CCSDS packets which were clumped together. This has been fixed now.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/673
- `CServiceHealthCommanding`: Add announce all health info implementation
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/725
- various fixes related to linux Unittests and memory leaks
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/715
- small fix to allow teardown handling
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/713
- fix compiler warning for fixed array list copy ctor
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/704
- missing include
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/703
- defaultconfig did not build anymore
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/702
- hotfix
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/699
- small fix for helper
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/698
- missing retval conv
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/697
- DHB Countdown Bug
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/693
- doc corrections
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/687
- better error printout
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/686
- include correction
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/683
- better warning for missing include paths
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/676
- Service 11 regression
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/670
## Added
@ -64,17 +136,36 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/709
- Add new `UnsignedByteField` class
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/660
- publish documentation for development and master branch
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/681
- Add Linux HAL options
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/663
- Expand SerializeIF
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/656
- PUS Service 11: Additional Safety Check
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/666
- improvements for auto-formatter script
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/665
- provide a weak print char impl
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/674
## Removed
- now that doc server is up, remove markdown files
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/688
- remove bsp specific code
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/679
## Changes
- `CService201HealthCommanding` renamed to `CServiceHealthCommanding`,
service ID customizable now. `CServiceHealthCommanding` expects configuration struct
`HealthServiceCfg` now
PR: https://egit.irs.uni-stuttgart.de/eive/fsfw/pulls/122
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/725
- `AcceptsTelemetryIF`: `getReportReceptionQueue` is const now
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/712
- Moved some container returnvalues to dedicated header and namespace
to they can be used without template specification.
so they can be used without template specification.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/707
- Remove default secondary header argument for
`uint16_t getTcSpacePacketIdFromApid(uint16_t apid, bool secondaryHeaderFlag)` and
@ -104,18 +195,41 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- `DeviceHandlerBase`: New signature of `handleDeviceTm` which expects
a `const SerializeIF&` and additional helper variant which expects `const uint8_t*`
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/671
- Move some generic `StorageManagerIF` implementations from `LocalPool` to
interface itself so it can be re-used more easily. Also add new
abstract function `bool hasDataAtId(store_address_t storeId) const`.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/685
- Improvements for `AcceptsTelemetryIF` and `AcceptsTelecommandsIF`:
- Make functions `const` where it makes sense
- Add `const char* getName const` abstract function
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/684
- Move some generic `StorageManagerIF` implementations from `LocalPool` to
interface itself so it can be re-used more easily. Also add new
abstract function `bool hasDataAtId(store_address_t storeId) const`.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/685
- Generic TMTC Bridge Update
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/734
- comment tweak to event parser can read everything
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/732
- CMakeLists file updates
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/731
- improve srv20 error messages
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/723
- I2C Linux: remove duplicate printout
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/718
- printout handling improvements
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/717
- vec getter, reset for content
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/716
- updates for source sequence counter
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/714
- SP reader getPacketData is const now
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/708
- refactoring of serial drivers for linux
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/705
- Local Pool Update Remove Add Data Ignore Fault Argument
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/701
- Switch to new documentation server
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/694
- Windows Tweaks
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/691
- Refactor Local Pool API
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/667
- group MGM data in local pool vectors
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/664
## CFDP
@ -135,17 +249,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
implementation without an extra component
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/682
## HAL
- SPI: Cache the SPI device in the communication interface. Architecturally, this makes a
lot more sense because each ComIF should be responsible for one SPI bus.
- SPI: Move the empty transfer to update the line polarity to separate function. This means
it is not automatically called when calling the setter function for SPI speed and mode.
The user should call this function after locking the CS mutex if multiple SPI devices with
differing speeds and modes are attached to one bus.
- SPI: Getter functions for SPI speed and mode.
# [v5.0.0] 25.07.2022
# [v5.0.0] 2022-07-25
## Changes

View File

@ -13,7 +13,7 @@ list(APPEND CMAKE_MODULE_PATH
# Version file handling #
# ##############################################################################
set(FSFW_VERSION_IF_GIT_FAILS 5)
set(FSFW_VERSION_IF_GIT_FAILS 6)
set(FSFW_SUBVERSION_IF_GIT_FAILS 0)
set(FSFW_REVISION_IF_GIT_FAILS 0)
@ -72,7 +72,7 @@ set(FSFW_ETL_LIB_MAJOR_VERSION
20
CACHE STRING "ETL library major version requirement")
set(FSFW_ETL_LIB_VERSION
${FSFW_ETL_LIB_MAJOR_VERSION}.28.0
${FSFW_ETL_LIB_MAJOR_VERSION}.35.14
CACHE STRING "ETL library exact version requirement")
set(FSFW_ETL_LINK_TARGET etl::etl)

110
scripts/check_release.py Executable file
View File

@ -0,0 +1,110 @@
#! /bin/python
import argparse
import json
import urllib.request
import re
from pathlib import Path
def main() -> None:
parser = argparse.ArgumentParser(
description="List undocumented PRs"
)
parser.add_argument("-v", "--version", type=str, required=True)
args = parser.parse_args()
match = re.search("([0-9]+\.[0-9]+\.[0-9]+)", args.version)
if not match:
print("invalid version")
exit(1)
version = "v" + match.group(1)
print("looking for milestone for " + version + " ...")
with urllib.request.urlopen("https://egit.irs.uni-stuttgart.de/api/v1/repos/fsfw/fsfw/milestones?name=" + version) as milestone_json:
milestones = json.load(milestone_json)
if (len(milestones) == 0):
print("did not find any milestone")
exit(1)
if (len(milestones) > 1):
print("found multiple milestons")
milestone_title = milestones[0]['title']
milestone = str(milestones[0]['id'])
print("Using Milestone \""+ milestone_title + "\" with id " + milestone)
milestone_prs = []
page = 1
last_count = 1;
while last_count != 0:
with urllib.request.urlopen("https://egit.irs.uni-stuttgart.de/api/v1/repos/fsfw/fsfw/pulls?state=closed&milestone=" + str(milestone) + "&limit=100&page=" + str(page)) as pull_requests_json:
pull_requests = json.load(pull_requests_json)
for pr in pull_requests:
milestone_prs.append({'number': str(pr['number']), 'title' : pr['title']})
page += 1
last_count = len(pull_requests)
print("Found " + str(len(milestone_prs)) + " closed PRs in Milestone")
print("looking for CHANGELOG.md ...")
path = Path(".")
files = list(path.glob("CHANGELOG.md"))
if (len(files) != 1):
files = list(path.glob("../CHANGELOG.md"))
if (len(files) != 1):
print("did not find CHANGELOG.md. Run script in either root directory or scripts subfolder.")
exit(1)
print("Scanning CHANGELOG.md ...")
changelog_prs = []
with open(files[0]) as changelog:
line = changelog.readline()
while (line):
#print("line: " + line)
match = re.search("\#.+(v[0-9]+\.[0-9]+\.[0-9]+)", line)
if (match):
if match.group(1) == version:
#print("found version")
line = changelog.readline()
continue
else:
#print("done with " + match.group(1))
break
match = re.search("PR: https://egit\.irs\.uni-stuttgart\.de/fsfw/fsfw/pulls/([0-9]+)", line)
if match:
changelog_prs.append(match.group(1))
line = changelog.readline()
print("Found " + str(len(changelog_prs)) + " PRs in CHANGELOG.md")
print("")
copy_array = changelog_prs.copy()
print("PRs in CHANGELOG.md that are not in Milestone:")
for pr in milestone_prs:
if pr['number'] in copy_array:
copy_array.remove(pr['number'])
for pr in copy_array:
print("https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/" + pr)
print("")
print("PRs in milestone that are not in CHANGELOG.md:")
for pr in milestone_prs:
if pr['number'] not in changelog_prs:
print("- " + pr['title'] + "\n PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/" + pr['number'])
main()

View File

@ -32,6 +32,7 @@ add_subdirectory(timemanager)
add_subdirectory(tmtcpacket)
add_subdirectory(tmtcservices)
add_subdirectory(filesystem)
add_subdirectory(util)
# Optional

View File

@ -59,17 +59,24 @@ void ActionHelper::setQueueToUse(MessageQueueIF* queue) { queueToUse = queue; }
void ActionHelper::prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId,
store_address_t dataAddress) {
bool hasAdditionalData = false;
const uint8_t* dataPtr = nullptr;
size_t size = 0;
ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size);
if (result != returnvalue::OK) {
CommandMessage reply;
ActionMessage::setStepReply(&reply, actionId, 0, result);
queueToUse->sendMessage(commandedBy, &reply);
return;
ReturnValue_t result;
if (dataAddress != store_address_t::invalid()) {
hasAdditionalData = true;
ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size);
if (result != returnvalue::OK) {
CommandMessage reply;
ActionMessage::setStepReply(&reply, actionId, 0, result);
queueToUse->sendMessage(commandedBy, &reply);
return;
}
}
result = owner->executeAction(actionId, commandedBy, dataPtr, size);
ipcStore->deleteData(dataAddress);
if (hasAdditionalData) {
ipcStore->deleteData(dataAddress);
}
if (result == HasActionsIF::EXECUTION_FINISHED) {
CommandMessage reply;
ActionMessage::setCompletionReply(&reply, actionId, true, result);

View File

@ -2,7 +2,6 @@
#define FSFW_CFDP_H
#include "cfdp/definitions.h"
#include "cfdp/handler/CfdpHandler.h"
#include "cfdp/handler/DestHandler.h"
#include "cfdp/handler/FaultHandlerBase.h"
#include "cfdp/helpers.h"

View File

@ -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) {

View File

@ -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);

View File

@ -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; }

View File

@ -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_; }

View File

@ -25,13 +25,15 @@ class VarLenField : public SerializeIF {
template <typename T>
explicit VarLenField(UnsignedByteField<T> byteField);
VarLenField(cfdp::WidthInBytes width, size_t value);
VarLenField(cfdp::WidthInBytes width, uint64_t value);
bool operator==(const VarLenField &other) const;
bool operator!=(const VarLenField &other) const;
bool operator<(const VarLenField &other) const;
ReturnValue_t setValue(cfdp::WidthInBytes, size_t value);
ReturnValue_t setValueAndWidth(cfdp::WidthInBytes width, uint64_t value);
void setWidth(cfdp::WidthInBytes width);
ReturnValue_t setValue(uint64_t value);
ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize,
Endianness streamEndianness) const override;
@ -42,7 +44,7 @@ class VarLenField : public SerializeIF {
Endianness streamEndianness);
[[nodiscard]] cfdp::WidthInBytes getWidth() const;
[[nodiscard]] size_t getValue() const;
[[nodiscard]] uint64_t getValue() const;
#if FSFW_CPP_OSTREAM_ENABLED == 1
friend std::ostream &operator<<(std::ostream &os, const VarLenField &id) {
@ -64,7 +66,7 @@ template <typename T>
cfdp::VarLenField::VarLenField(UnsignedByteField<T> byteField)
: width(static_cast<cfdp::WidthInBytes>(sizeof(T))) {
static_assert((sizeof(T) % 2) == 0);
setValue(width, byteField.getValue());
setValueAndWidth(width, byteField.getValue());
}
struct EntityId : public VarLenField {
@ -73,6 +75,32 @@ struct EntityId : public VarLenField {
template <typename T>
explicit EntityId(UnsignedByteField<T> byteField) : VarLenField(byteField) {}
EntityId(cfdp::WidthInBytes width, size_t entityId) : VarLenField(width, entityId) {}
ReturnValue_t serializeAsLv(uint8_t **buffer, size_t *size, size_t maxSize) const {
if (buffer == nullptr or size == nullptr) {
return returnvalue::FAILED;
}
if (*size + 1 + getWidth() > maxSize) {
return SerializeIF::BUFFER_TOO_SHORT;
}
**buffer = getWidth();
*buffer += 1;
*size += 1;
return serialize(buffer, size, maxSize, SerializeIF::Endianness::NETWORK);
}
ReturnValue_t deSerializeFromLv(const uint8_t **buffer, size_t *deserLen) {
if (buffer == nullptr or deserLen == nullptr) {
return returnvalue::FAILED;
}
if (*deserLen < 2) {
return SerializeIF::STREAM_TOO_SHORT;
}
auto width = static_cast<WidthInBytes>(**buffer);
*buffer += 1;
*deserLen -= 1;
return VarLenField::deSerialize(width, buffer, deserLen, SerializeIF::Endianness::NETWORK);
}
};
struct TransactionSeqNum : public VarLenField {

View File

@ -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_ */

View File

@ -1,3 +1,4 @@
target_sources(
${LIB_FSFW_NAME} PRIVATE SourceHandler.cpp DestHandler.cpp
FaultHandlerBase.cpp UserBase.cpp CfdpHandler.cpp)
${LIB_FSFW_NAME}
PRIVATE SourceHandler.cpp DestHandler.cpp PutRequest.cpp
ReservedMessageParser.cpp FaultHandlerBase.cpp UserBase.cpp)

View File

@ -1,134 +0,0 @@
#include "CfdpHandler.h"
#include "fsfw/cfdp/pdu/AckPduReader.h"
#include "fsfw/cfdp/pdu/PduHeaderReader.h"
#include "fsfw/globalfunctions/arrayprinter.h"
#include "fsfw/ipc/QueueFactory.h"
#include "fsfw/tmtcservices/TmTcMessage.h"
using namespace returnvalue;
using namespace cfdp;
CfdpHandler::CfdpHandler(const FsfwHandlerParams& fsfwParams, const CfdpHandlerCfg& cfdpCfg)
: SystemObject(fsfwParams.objectId),
msgQueue(fsfwParams.msgQueue),
destHandler(
DestHandlerParams(LocalEntityCfg(cfdpCfg.id, cfdpCfg.indicCfg, cfdpCfg.faultHandler),
cfdpCfg.userHandler, cfdpCfg.remoteCfgProvider, cfdpCfg.packetInfoList,
cfdpCfg.lostSegmentsList),
FsfwParams(fsfwParams.packetDest, nullptr, this, fsfwParams.tcStore,
fsfwParams.tmStore)) {
destHandler.setMsgQueue(msgQueue);
}
[[nodiscard]] const char* CfdpHandler::getName() const { return "CFDP Handler"; }
[[nodiscard]] uint32_t CfdpHandler::getIdentifier() const {
return destHandler.getDestHandlerParams().cfg.localId.getValue();
}
[[nodiscard]] MessageQueueId_t CfdpHandler::getRequestQueue() const { return msgQueue.getId(); }
ReturnValue_t CfdpHandler::initialize() {
ReturnValue_t result = destHandler.initialize();
if (result != OK) {
return result;
}
tcStore = destHandler.getTcStore();
tmStore = destHandler.getTmStore();
return SystemObject::initialize();
}
ReturnValue_t CfdpHandler::performOperation(uint8_t operationCode) {
// TODO: Receive TC packets and route them to source and dest handler, depending on which is
// correct or more appropriate
ReturnValue_t status;
ReturnValue_t result = OK;
TmTcMessage tmtcMsg;
for (status = msgQueue.receiveMessage(&tmtcMsg); status == returnvalue::OK;
status = msgQueue.receiveMessage(&tmtcMsg)) {
result = handleCfdpPacket(tmtcMsg);
if (result != OK) {
status = result;
}
}
auto& fsmRes = destHandler.performStateMachine();
// TODO: Error handling?
while (fsmRes.callStatus == CallStatus::CALL_AGAIN) {
destHandler.performStateMachine();
// TODO: Error handling?
}
return status;
}
ReturnValue_t CfdpHandler::handleCfdpPacket(TmTcMessage& msg) {
auto accessorPair = tcStore->getData(msg.getStorageId());
if (accessorPair.first != OK) {
return accessorPair.first;
}
PduHeaderReader reader(accessorPair.second.data(), accessorPair.second.size());
ReturnValue_t result = reader.parseData();
if (result != returnvalue::OK) {
return INVALID_PDU_FORMAT;
}
// The CFDP distributor should have taken care of ensuring the destination ID is correct
PduType type = reader.getPduType();
// Only the destination handler can process these PDUs
if (type == PduType::FILE_DATA) {
// Disable auto-deletion of packet
accessorPair.second.release();
PacketInfo info(type, msg.getStorageId());
result = destHandler.passPacket(info);
} else {
// Route depending on PDU type and directive type if applicable. It retrieves directive type
// from the raw stream for better performance (with sanity and directive code check).
// The routing is based on section 4.5 of the CFDP standard which specifies the PDU forwarding
// procedure.
// PDU header only. Invalid supplied data. A directive packet should have a valid data field
// with at least one byte being the directive code
const uint8_t* pduDataField = reader.getPduDataField();
if (pduDataField == nullptr) {
return INVALID_PDU_FORMAT;
}
if (not FileDirectiveReader::checkFileDirective(pduDataField[0])) {
return INVALID_DIRECTIVE_FIELD;
}
auto directive = static_cast<FileDirective>(pduDataField[0]);
auto passToDestHandler = [&]() {
accessorPair.second.release();
PacketInfo info(type, msg.getStorageId(), directive);
result = destHandler.passPacket(info);
};
auto passToSourceHandler = [&]() {
};
if (directive == FileDirective::METADATA or directive == FileDirective::EOF_DIRECTIVE or
directive == FileDirective::PROMPT) {
// Section b) of 4.5.3: These PDUs should always be targeted towards the file receiver a.k.a.
// the destination handler
passToDestHandler();
} else if (directive == FileDirective::FINISH or directive == FileDirective::NAK or
directive == FileDirective::KEEP_ALIVE) {
// Section c) of 4.5.3: These PDUs should always be targeted towards the file sender a.k.a.
// the source handler
passToSourceHandler();
} else if (directive == FileDirective::ACK) {
// Section a): Recipient depends of the type of PDU that is being acknowledged. We can simply
// extract the PDU type from the raw stream. If it is an EOF PDU, this packet is passed to
// the source handler, for a Finished PDU, it is passed to the destination handler.
FileDirective ackedDirective;
if (not AckPduReader::checkAckedDirectiveField(pduDataField[1], ackedDirective)) {
return INVALID_ACK_DIRECTIVE_FIELDS;
}
if (ackedDirective == FileDirective::EOF_DIRECTIVE) {
passToSourceHandler();
} else if (ackedDirective == FileDirective::FINISH) {
passToDestHandler();
}
}
}
return result;
}

View File

@ -1,71 +0,0 @@
#ifndef FSFW_EXAMPLE_HOSTED_CFDPHANDLER_H
#define FSFW_EXAMPLE_HOSTED_CFDPHANDLER_H
#include <utility>
#include "fsfw/cfdp/handler/DestHandler.h"
#include "fsfw/objectmanager/SystemObject.h"
#include "fsfw/tasks/ExecutableObjectIF.h"
#include "fsfw/tmtcservices/AcceptsTelecommandsIF.h"
#include "fsfw/tmtcservices/TmTcMessage.h"
struct FsfwHandlerParams {
FsfwHandlerParams(object_id_t objectId, HasFileSystemIF& vfs, AcceptsTelemetryIF& packetDest,
StorageManagerIF& tcStore, StorageManagerIF& tmStore, MessageQueueIF& msgQueue)
: objectId(objectId),
vfs(vfs),
packetDest(packetDest),
tcStore(tcStore),
tmStore(tmStore),
msgQueue(msgQueue) {}
object_id_t objectId{};
HasFileSystemIF& vfs;
AcceptsTelemetryIF& packetDest;
StorageManagerIF& tcStore;
StorageManagerIF& tmStore;
MessageQueueIF& msgQueue;
};
struct CfdpHandlerCfg {
CfdpHandlerCfg(cfdp::EntityId localId, cfdp::IndicationCfg indicationCfg,
cfdp::UserBase& userHandler, cfdp::FaultHandlerBase& userFaultHandler,
cfdp::PacketInfoListBase& packetInfo, cfdp::LostSegmentsListBase& lostSegmentsList,
cfdp::RemoteConfigTableIF& remoteCfgProvider)
: id(std::move(localId)),
indicCfg(indicationCfg),
packetInfoList(packetInfo),
lostSegmentsList(lostSegmentsList),
remoteCfgProvider(remoteCfgProvider),
userHandler(userHandler),
faultHandler(userFaultHandler) {}
cfdp::EntityId id;
cfdp::IndicationCfg indicCfg;
cfdp::PacketInfoListBase& packetInfoList;
cfdp::LostSegmentsListBase& lostSegmentsList;
cfdp::RemoteConfigTableIF& remoteCfgProvider;
cfdp::UserBase& userHandler;
cfdp::FaultHandlerBase& faultHandler;
};
class CfdpHandler : public SystemObject, public ExecutableObjectIF, public AcceptsTelecommandsIF {
public:
explicit CfdpHandler(const FsfwHandlerParams& fsfwParams, const CfdpHandlerCfg& cfdpCfg);
[[nodiscard]] const char* getName() const override;
[[nodiscard]] uint32_t getIdentifier() const override;
[[nodiscard]] MessageQueueId_t getRequestQueue() const override;
ReturnValue_t initialize() override;
ReturnValue_t performOperation(uint8_t operationCode) override;
private:
MessageQueueIF& msgQueue;
cfdp::DestHandler destHandler;
StorageManagerIF* tcStore = nullptr;
StorageManagerIF* tmStore = nullptr;
ReturnValue_t handleCfdpPacket(TmTcMessage& msg);
};
#endif // FSFW_EXAMPLE_HOSTED_CFDPHANDLER_H

View File

@ -16,25 +16,26 @@ using namespace returnvalue;
cfdp::DestHandler::DestHandler(DestHandlerParams params, FsfwParams fsfwParams)
: tlvVec(params.maxTlvsInOnePdu),
userTlvVec(params.maxTlvsInOnePdu),
dp(std::move(params)),
fp(fsfwParams),
tp(params.maxFilenameLen) {
tp.pduConf.direction = cfdp::Direction::TOWARDS_SENDER;
msgToUserVec(params.maxTlvsInOnePdu),
transactionParams(params.maxFilenameLen),
destParams(std::move(params)),
fsfwParams(fsfwParams) {
transactionParams.pduConf.direction = cfdp::Direction::TOWARDS_SENDER;
}
const cfdp::DestHandler::FsmResult& cfdp::DestHandler::performStateMachine() {
const cfdp::DestHandler::FsmResult& cfdp::DestHandler::stateMachine() {
ReturnValue_t result;
uint8_t errorIdx = 0;
fsmRes.resetOfIteration();
if (fsmRes.step == TransactionStep::IDLE) {
for (auto infoIter = dp.packetListRef.begin(); infoIter != dp.packetListRef.end();) {
for (auto infoIter = destParams.packetListRef.begin();
infoIter != destParams.packetListRef.end();) {
if (infoIter->pduType == PduType::FILE_DIRECTIVE and
infoIter->directiveType == FileDirective::METADATA) {
result = handleMetadataPdu(*infoIter);
checkAndHandleError(result, errorIdx);
// Store data was deleted in PDU handler because a store guard is used
dp.packetListRef.erase(infoIter++);
destParams.packetListRef.erase(infoIter++);
} else {
infoIter++;
}
@ -42,11 +43,12 @@ const cfdp::DestHandler::FsmResult& cfdp::DestHandler::performStateMachine() {
if (fsmRes.step == TransactionStep::IDLE) {
// To decrease the already high complexity of the software, all packets arriving before
// a metadata PDU are deleted.
for (auto infoIter = dp.packetListRef.begin(); infoIter != dp.packetListRef.end();) {
fp.tcStore->deleteData(infoIter->storeId);
for (auto infoIter = destParams.packetListRef.begin();
infoIter != destParams.packetListRef.end();) {
fsfwParams.tcStore->deleteData(infoIter->storeId);
infoIter++;
}
dp.packetListRef.clear();
destParams.packetListRef.clear();
}
if (fsmRes.step != TransactionStep::IDLE) {
@ -54,21 +56,22 @@ const cfdp::DestHandler::FsmResult& cfdp::DestHandler::performStateMachine() {
}
return updateFsmRes(errorIdx);
}
if (fsmRes.state == CfdpStates::BUSY_CLASS_1_NACKED) {
if (fsmRes.state == CfdpState::BUSY_CLASS_1_NACKED) {
if (fsmRes.step == TransactionStep::RECEIVING_FILE_DATA_PDUS) {
for (auto infoIter = dp.packetListRef.begin(); infoIter != dp.packetListRef.end();) {
for (auto infoIter = destParams.packetListRef.begin();
infoIter != destParams.packetListRef.end();) {
if (infoIter->pduType == PduType::FILE_DATA) {
result = handleFileDataPdu(*infoIter);
checkAndHandleError(result, errorIdx);
// Store data was deleted in PDU handler because a store guard is used
dp.packetListRef.erase(infoIter++);
destParams.packetListRef.erase(infoIter++);
} else if (infoIter->pduType == PduType::FILE_DIRECTIVE and
infoIter->directiveType == FileDirective::EOF_DIRECTIVE) {
// TODO: Support for check timer missing
result = handleEofPdu(*infoIter);
checkAndHandleError(result, errorIdx);
// Store data was deleted in PDU handler because a store guard is used
dp.packetListRef.erase(infoIter++);
destParams.packetListRef.erase(infoIter++);
} else {
infoIter++;
}
@ -85,7 +88,7 @@ const cfdp::DestHandler::FsmResult& cfdp::DestHandler::performStateMachine() {
}
return updateFsmRes(errorIdx);
}
if (fsmRes.state == CfdpStates::BUSY_CLASS_2_ACKED) {
if (fsmRes.state == CfdpState::BUSY_CLASS_2_ACKED) {
// TODO: Will be implemented at a later stage
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "CFDP state machine for acknowledged mode not implemented yet" << std::endl;
@ -95,29 +98,29 @@ const cfdp::DestHandler::FsmResult& cfdp::DestHandler::performStateMachine() {
}
ReturnValue_t cfdp::DestHandler::passPacket(PacketInfo packet) {
if (dp.packetListRef.full()) {
if (destParams.packetListRef.full()) {
return FAILED;
}
dp.packetListRef.push_back(packet);
destParams.packetListRef.push_back(packet);
return OK;
}
ReturnValue_t cfdp::DestHandler::initialize() {
if (fp.tmStore == nullptr) {
fp.tmStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TM_STORE);
if (fp.tmStore == nullptr) {
if (fsfwParams.tmStore == nullptr) {
fsfwParams.tmStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TM_STORE);
if (fsfwParams.tmStore == nullptr) {
return FAILED;
}
}
if (fp.tcStore == nullptr) {
fp.tcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TC_STORE);
if (fp.tcStore == nullptr) {
if (fsfwParams.tcStore == nullptr) {
fsfwParams.tcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TC_STORE);
if (fsfwParams.tcStore == nullptr) {
return FAILED;
}
}
if (fp.msgQueue == nullptr) {
if (fsfwParams.msgQueue == nullptr) {
return FAILED;
}
return OK;
@ -125,18 +128,16 @@ ReturnValue_t cfdp::DestHandler::initialize() {
ReturnValue_t cfdp::DestHandler::handleMetadataPdu(const PacketInfo& info) {
// Process metadata PDU
auto constAccessorPair = fp.tcStore->getData(info.storeId);
auto constAccessorPair = fsfwParams.tcStore->getData(info.storeId);
if (constAccessorPair.first != OK) {
// TODO: This is not a CFDP error. Event and/or warning?
return constAccessorPair.first;
}
cfdp::StringLv sourceFileName;
cfdp::StringLv destFileName;
MetadataInfo metadataInfo(tp.fileSize, sourceFileName, destFileName);
cfdp::Tlv* tlvArrayAsPtr = tlvVec.data();
metadataInfo.setOptionsArray(&tlvArrayAsPtr, std::nullopt, tlvVec.size());
MetadataGenericInfo metadataInfo(transactionParams.fileSize);
MetadataPduReader reader(constAccessorPair.second.data(), constAccessorPair.second.size(),
metadataInfo);
metadataInfo, tlvVec.data(), tlvVec.size());
ReturnValue_t result = reader.parseData();
// TODO: The standard does not really specify what happens if this kind of error happens
// I think it might be a good idea to cache some sort of error code, which
@ -145,18 +146,17 @@ ReturnValue_t cfdp::DestHandler::handleMetadataPdu(const PacketInfo& info) {
return handleMetadataParseError(result, constAccessorPair.second.data(),
constAccessorPair.second.size());
}
return startTransaction(reader, metadataInfo);
return startTransaction(reader);
}
ReturnValue_t cfdp::DestHandler::handleFileDataPdu(const cfdp::PacketInfo& info) {
// Process file data PDU
auto constAccessorPair = fp.tcStore->getData(info.storeId);
auto constAccessorPair = fsfwParams.tcStore->getData(info.storeId);
if (constAccessorPair.first != OK) {
// TODO: This is not a CFDP error. Event and/or warning?
return constAccessorPair.first;
}
cfdp::FileSize offset;
FileDataInfo fdInfo(offset);
FileDataInfo fdInfo;
FileDataReader reader(constAccessorPair.second.data(), constAccessorPair.second.size(), fdInfo);
ReturnValue_t result = reader.parseData();
if (result != OK) {
@ -164,46 +164,46 @@ ReturnValue_t cfdp::DestHandler::handleFileDataPdu(const cfdp::PacketInfo& info)
}
size_t fileSegmentLen = 0;
const uint8_t* fileData = fdInfo.getFileData(&fileSegmentLen);
FileOpParams fileOpParams(tp.destName.data(), fileSegmentLen);
fileOpParams.offset = offset.value();
if (dp.cfg.indicCfg.fileSegmentRecvIndicRequired) {
FileOpParams fileOpParams(transactionParams.destName.data(), fileSegmentLen);
fileOpParams.offset = fdInfo.getOffset().value();
if (destParams.cfg.indicCfg.fileSegmentRecvIndicRequired) {
FileSegmentRecvdParams segParams;
segParams.offset = offset.value();
segParams.id = tp.transactionId;
segParams.offset = fdInfo.getOffset().value();
segParams.id = transactionParams.transactionId;
segParams.length = fileSegmentLen;
segParams.recContState = fdInfo.getRecordContinuationState();
size_t segmentMetadatLen = 0;
auto* segMetadata = fdInfo.getSegmentMetadata(&segmentMetadatLen);
segParams.segmentMetadata = {segMetadata, segmentMetadatLen};
dp.user.fileSegmentRecvdIndication(segParams);
destParams.user.fileSegmentRecvdIndication(segParams);
}
result = dp.user.vfs.writeToFile(fileOpParams, fileData);
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
tp.vfsErrorCount++;
if (tp.vfsErrorCount < 3) {
transactionParams.vfsErrorCount++;
if (transactionParams.vfsErrorCount < 3) {
// TODO: Provide execution step as parameter
fp.eventReporter->forwardEvent(events::FILESTORE_ERROR, static_cast<uint8_t>(fsmRes.step),
result);
fsfwParams.eventReporter->forwardEvent(events::FILESTORE_ERROR,
static_cast<uint8_t>(fsmRes.step), result);
}
return result;
} else {
tp.deliveryStatus = FileDeliveryStatus::RETAINED_IN_FILESTORE;
tp.vfsErrorCount = 0;
transactionParams.deliveryStatus = FileDeliveryStatus::RETAINED_IN_FILESTORE;
transactionParams.vfsErrorCount = 0;
}
if (offset.value() + fileSegmentLen > tp.progress) {
tp.progress = offset.value() + fileSegmentLen;
if (fdInfo.getOffset().value() + fileSegmentLen > transactionParams.progress) {
transactionParams.progress = fdInfo.getOffset().value() + fileSegmentLen;
}
return result;
}
ReturnValue_t cfdp::DestHandler::handleEofPdu(const cfdp::PacketInfo& info) {
// Process EOF PDU
auto constAccessorPair = fp.tcStore->getData(info.storeId);
auto constAccessorPair = fsfwParams.tcStore->getData(info.storeId);
if (constAccessorPair.first != OK) {
// TODO: This is not a CFDP error. Event and/or warning?
return constAccessorPair.first;
@ -216,21 +216,21 @@ ReturnValue_t cfdp::DestHandler::handleEofPdu(const cfdp::PacketInfo& info) {
}
// TODO: Error handling
if (eofInfo.getConditionCode() == ConditionCode::NO_ERROR) {
tp.crc = eofInfo.getChecksum();
transactionParams.crc = eofInfo.getChecksum();
uint64_t fileSizeFromEof = eofInfo.getFileSize().value();
// CFDP 4.6.1.2.9: Declare file size error if progress exceeds file size
if (fileSizeFromEof > tp.progress) {
if (fileSizeFromEof > transactionParams.progress) {
// TODO: File size error
}
tp.fileSize.setFileSize(fileSizeFromEof, std::nullopt);
transactionParams.fileSize.setFileSize(fileSizeFromEof, std::nullopt);
}
if (dp.cfg.indicCfg.eofRecvIndicRequired) {
dp.user.eofRecvIndication(getTransactionId());
if (destParams.cfg.indicCfg.eofRecvIndicRequired) {
destParams.user.eofRecvIndication(getTransactionId());
}
if (fsmRes.step == TransactionStep::RECEIVING_FILE_DATA_PDUS) {
if (fsmRes.state == CfdpStates::BUSY_CLASS_1_NACKED) {
if (fsmRes.state == CfdpState::BUSY_CLASS_1_NACKED) {
fsmRes.step = TransactionStep::TRANSFER_COMPLETION;
} else if (fsmRes.state == CfdpStates::BUSY_CLASS_2_ACKED) {
} else if (fsmRes.state == CfdpState::BUSY_CLASS_2_ACKED) {
fsmRes.step = TransactionStep::SENDING_ACK_PDU;
}
}
@ -260,7 +260,7 @@ ReturnValue_t cfdp::DestHandler::handleMetadataParseError(ReturnValue_t result,
cfdp::EntityId destId;
headerReader.getDestId(destId);
RemoteEntityCfg* remoteCfg;
if (not dp.remoteCfgTable.getRemoteCfg(destId, &remoteCfg)) {
if (not destParams.remoteCfgTable.getRemoteCfg(destId, &remoteCfg)) {
// TODO: No remote config for dest ID. I consider this a configuration error, which is not
// covered by the standard.
// Warning or error, yield or cache appropriate returnvalue
@ -274,51 +274,57 @@ ReturnValue_t cfdp::DestHandler::handleMetadataParseError(ReturnValue_t result,
return returnvalue::FAILED;
}
ReturnValue_t cfdp::DestHandler::startTransaction(MetadataPduReader& reader, MetadataInfo& info) {
if (fsmRes.state != CfdpStates::IDLE) {
ReturnValue_t cfdp::DestHandler::startTransaction(const MetadataPduReader& reader) {
if (fsmRes.state != CfdpState::IDLE) {
// According to standard, discard metadata PDU if we are busy
return OK;
}
ReturnValue_t result = OK;
size_t sourceNameSize = 0;
const uint8_t* sourceNamePtr = info.getSourceFileName().getValue(&sourceNameSize);
if (sourceNameSize + 1 > tp.sourceName.size()) {
fileErrorHandler(events::FILENAME_TOO_LARGE_ERROR, 0, "source filename too large");
return FAILED;
if (not reader.getSourceFileName().isEmpty()) {
const uint8_t* sourceNamePtr = reader.getSourceFileName().getValue(&sourceNameSize);
if (sourceNameSize + 1 > transactionParams.sourceName.size()) {
fileErrorHandler(events::FILENAME_TOO_LARGE_ERROR, 0, "source filename too large");
return FAILED;
}
std::memcpy(transactionParams.sourceName.data(), sourceNamePtr, sourceNameSize);
transactionParams.sourceName[sourceNameSize] = '\0';
}
std::memcpy(tp.sourceName.data(), sourceNamePtr, sourceNameSize);
tp.sourceName[sourceNameSize] = '\0';
size_t destNameSize = 0;
const uint8_t* destNamePtr = info.getDestFileName().getValue(&destNameSize);
if (destNameSize + 1 > tp.destName.size()) {
fileErrorHandler(events::FILENAME_TOO_LARGE_ERROR, 0, "dest filename too large");
return FAILED;
if (not reader.getDestFileName().isEmpty()) {
const uint8_t* destNamePtr = reader.getDestFileName().getValue(&destNameSize);
if (destNameSize + 1 > transactionParams.destName.size()) {
fileErrorHandler(events::FILENAME_TOO_LARGE_ERROR, 0, "dest filename too large");
return FAILED;
}
std::memcpy(transactionParams.destName.data(), destNamePtr, destNameSize);
transactionParams.destName[destNameSize] = '\0';
}
std::memcpy(tp.destName.data(), destNamePtr, destNameSize);
tp.destName[destNameSize] = '\0';
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) {
FilesystemParams fparams(tp.destName.data());
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 (dp.user.vfs.isDirectory(tp.destName.data())) {
if (destParams.user.vfs.isDirectory(transactionParams.destName.data())) {
result = tryBuildingAbsoluteDestName(destNameSize);
if (result != OK) {
return result;
}
}
if (dp.user.vfs.fileExists(fparams)) {
result = dp.user.vfs.truncateFile(fparams);
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 = dp.user.vfs.createFile(fparams);
result = destParams.user.vfs.createFile(fparams);
if (result != OK) {
fileErrorHandler(events::FILESTORE_ERROR, result, "file creation error");
return FAILED;
@ -328,120 +334,135 @@ ReturnValue_t cfdp::DestHandler::startTransaction(MetadataPduReader& reader, Met
}
EntityId sourceId;
reader.getSourceId(sourceId);
if (not dp.remoteCfgTable.getRemoteCfg(sourceId, &tp.remoteCfg)) {
if (not destParams.remoteCfgTable.getRemoteCfg(sourceId, &transactionParams.remoteCfg)) {
// TODO: Warning, event etc.
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "cfdp::DestHandler" << __func__
<< ": No remote configuration found for destination ID "
<< tp.pduConf.sourceId.getValue() << std::endl;
<< transactionParams.pduConf.sourceId.getValue() << std::endl;
#endif
return FAILED;
}
fsmRes.step = TransactionStep::TRANSACTION_START;
if (reader.getTransmissionMode() == TransmissionMode::UNACKNOWLEDGED) {
fsmRes.state = CfdpStates::BUSY_CLASS_1_NACKED;
fsmRes.state = CfdpState::BUSY_CLASS_1_NACKED;
} else if (reader.getTransmissionMode() == TransmissionMode::ACKNOWLEDGED) {
fsmRes.state = CfdpStates::BUSY_CLASS_2_ACKED;
fsmRes.state = CfdpState::BUSY_CLASS_2_ACKED;
}
tp.checksumType = info.getChecksumType();
tp.closureRequested = info.isClosureRequested();
reader.fillConfig(tp.pduConf);
tp.pduConf.direction = Direction::TOWARDS_SENDER;
tp.transactionId.entityId = tp.pduConf.sourceId;
tp.transactionId.seqNum = tp.pduConf.seqNum;
fsmRes.step = TransactionStep::RECEIVING_FILE_DATA_PDUS;
MetadataRecvdParams params(tp.transactionId, tp.pduConf.sourceId);
params.fileSize = tp.fileSize.getSize();
params.destFileName = tp.destName.data();
params.sourceFileName = tp.sourceName.data();
params.msgsToUserArray = dynamic_cast<MessageToUserTlv*>(userTlvVec.data());
params.msgsToUserLen = info.getOptionsLen();
dp.user.metadataRecvdIndication(params);
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::CfdpStates cfdp::DestHandler::getCfdpState() const { return fsmRes.state; }
cfdp::CfdpState cfdp::DestHandler::getCfdpState() const { return fsmRes.state; }
ReturnValue_t cfdp::DestHandler::handleTransferCompletion() {
ReturnValue_t result;
if (tp.checksumType != ChecksumType::NULL_CHECKSUM) {
if (transactionParams.checksumType != ChecksumType::NULL_CHECKSUM) {
result = checksumVerification();
if (result != OK) {
// TODO: Warning / error handling?
}
} else {
tp.conditionCode = ConditionCode::NO_ERROR;
transactionParams.conditionCode = ConditionCode::NO_ERROR;
}
result = noticeOfCompletion();
if (result != OK) {
}
if (fsmRes.state == CfdpStates::BUSY_CLASS_1_NACKED) {
if (tp.closureRequested) {
if (fsmRes.state == CfdpState::BUSY_CLASS_1_NACKED) {
if (transactionParams.closureRequested) {
fsmRes.step = TransactionStep::SENDING_FINISHED_PDU;
} else {
finish();
}
} else if (fsmRes.state == CfdpStates::BUSY_CLASS_2_ACKED) {
} else if (fsmRes.state == CfdpState::BUSY_CLASS_2_ACKED) {
fsmRes.step = TransactionStep::SENDING_FINISHED_PDU;
}
return OK;
}
ReturnValue_t cfdp::DestHandler::tryBuildingAbsoluteDestName(size_t destNameSize) {
char baseNameBuf[tp.destName.size()]{};
FilesystemParams fparamsSrc(tp.sourceName.data());
// 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 =
dp.user.vfs.getBaseFilename(fparamsSrc, baseNameBuf, sizeof(baseNameBuf), baseNameLen);
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 > tp.destName.size()) {
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;
}
tp.destName[destNameSize++] = '/';
std::memcpy(tp.destName.data() + destNameSize, baseNameBuf, baseNameLen);
transactionParams.destName[destNameSize++] = '/';
std::memcpy(transactionParams.destName.data() + destNameSize, baseNameBuf, baseNameLen);
destNameSize += baseNameLen;
tp.destName[destNameSize++] = '\0';
transactionParams.destName[destNameSize++] = '\0';
return OK;
}
void cfdp::DestHandler::fileErrorHandler(Event event, ReturnValue_t result, const char* info) {
fp.eventReporter->forwardEvent(events::FILENAME_TOO_LARGE_ERROR,
static_cast<uint8_t>(fsmRes.step), result);
void cfdp::DestHandler::fileErrorHandler(Event event, ReturnValue_t result,
const char* info) const {
fsfwParams.eventReporter->forwardEvent(event, static_cast<uint8_t>(fsmRes.step), result);
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "cfdp::DestHandler: " << info << std::endl;
#endif
}
void cfdp::DestHandler::finish() {
tp.reset();
dp.packetListRef.clear();
fsmRes.state = CfdpStates::IDLE;
transactionParams.reset();
destParams.packetListRef.clear();
fsmRes.state = CfdpState::IDLE;
fsmRes.step = TransactionStep::IDLE;
}
ReturnValue_t cfdp::DestHandler::checksumVerification() {
std::array<uint8_t, 1024> buf{};
// TODO: Checksum verification and notice of completion
etl::crc32 crcCalc;
uint64_t currentOffset = 0;
FileOpParams params(tp.destName.data(), tp.fileSize.value());
while (currentOffset < tp.fileSize.value()) {
FileOpParams params(transactionParams.destName.data(), transactionParams.fileSize.value());
while (currentOffset < transactionParams.fileSize.value()) {
uint64_t readLen;
if (currentOffset + buf.size() > tp.fileSize.value()) {
readLen = tp.fileSize.value() - currentOffset;
if (currentOffset + buf.size() > transactionParams.fileSize.value()) {
readLen = transactionParams.fileSize.value() - currentOffset;
} else {
readLen = buf.size();
}
if (readLen > 0) {
params.offset = currentOffset;
params.size = readLen;
auto result = dp.user.vfs.readFromFile(params, buf.data(), buf.size());
auto result = destParams.user.vfs.readFromFile(params, buf.data(), buf.size());
if (result != OK) {
// TODO: I think this is a case for a filestore rejection, but it might sense to print
// a warning or trigger an event because this should generally not happen
@ -453,40 +474,43 @@ ReturnValue_t cfdp::DestHandler::checksumVerification() {
}
uint32_t value = crcCalc.value();
if (value == tp.crc) {
tp.conditionCode = ConditionCode::NO_ERROR;
tp.deliveryCode = FileDeliveryCode::DATA_COMPLETE;
if (value == transactionParams.crc) {
transactionParams.conditionCode = ConditionCode::NO_ERROR;
transactionParams.deliveryCode = FileDeliveryCode::DATA_COMPLETE;
} else {
// TODO: Proper error handling
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "CRC check for file " << tp.destName.data() << " failed" << std::endl;
sif::warning << "CRC check for file " << transactionParams.destName.data() << " failed"
<< std::endl;
#endif
tp.conditionCode = ConditionCode::FILE_CHECKSUM_FAILURE;
transactionParams.conditionCode = ConditionCode::FILE_CHECKSUM_FAILURE;
}
return OK;
}
ReturnValue_t cfdp::DestHandler::noticeOfCompletion() {
if (dp.cfg.indicCfg.transactionFinishedIndicRequired) {
TransactionFinishedParams params(tp.transactionId, tp.conditionCode, tp.deliveryCode,
tp.deliveryStatus);
dp.user.transactionFinishedIndication(params);
if (destParams.cfg.indicCfg.transactionFinishedIndicRequired) {
TransactionFinishedParams params(
transactionParams.transactionId, transactionParams.conditionCode,
transactionParams.deliveryCode, transactionParams.deliveryStatus);
destParams.user.transactionFinishedIndication(params);
}
return OK;
}
ReturnValue_t cfdp::DestHandler::sendFinishedPdu() {
FinishedInfo info(tp.conditionCode, tp.deliveryCode, tp.deliveryStatus);
FinishPduCreator finishedPdu(tp.pduConf, info);
FinishedInfo info(transactionParams.conditionCode, transactionParams.deliveryCode,
transactionParams.deliveryStatus);
FinishPduCreator finishedPdu(transactionParams.pduConf, info);
store_address_t storeId;
uint8_t* dataPtr = nullptr;
ReturnValue_t result =
fp.tmStore->getFreeElement(&storeId, finishedPdu.getSerializedSize(), &dataPtr);
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
fp.eventReporter->forwardEvent(events::STORE_ERROR, result, 0);
fsfwParams.eventReporter->forwardEvent(events::STORE_ERROR, result, 0);
return result;
}
size_t serLen = 0;
@ -496,16 +520,16 @@ ReturnValue_t cfdp::DestHandler::sendFinishedPdu() {
sif::warning << "cfdp::DestHandler::sendFinishedPdu: Serializing Finished PDU failed"
<< std::endl;
#endif
fp.eventReporter->forwardEvent(events::SERIALIZATION_ERROR, result, 0);
fsfwParams.eventReporter->forwardEvent(events::SERIALIZATION_ERROR, result, 0);
return result;
}
TmTcMessage msg(storeId);
result = fp.msgQueue->sendMessage(fp.packetDest.getReportReceptionQueue(), &msg);
result = fsfwParams.msgQueue->sendMessage(fsfwParams.packetDest.getReportReceptionQueue(), &msg);
if (result != OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "cfdp::DestHandler::sendFinishedPdu: Sending PDU failed" << std::endl;
#endif
fp.eventReporter->forwardEvent(events::MSG_QUEUE_ERROR, result, 0);
fsfwParams.eventReporter->forwardEvent(events::MSG_QUEUE_ERROR, result, 0);
return result;
}
fsmRes.packetsSent++;
@ -525,7 +549,9 @@ const cfdp::DestHandler::FsmResult& cfdp::DestHandler::updateFsmRes(uint8_t erro
return fsmRes;
}
const cfdp::TransactionId& cfdp::DestHandler::getTransactionId() const { return tp.transactionId; }
const cfdp::TransactionId& cfdp::DestHandler::getTransactionId() const {
return transactionParams.transactionId;
}
void cfdp::DestHandler::checkAndHandleError(ReturnValue_t result, uint8_t& errorIdx) {
if (result != OK and errorIdx < 3) {
@ -534,13 +560,15 @@ void cfdp::DestHandler::checkAndHandleError(ReturnValue_t result, uint8_t& error
}
}
void cfdp::DestHandler::setMsgQueue(MessageQueueIF& queue) { fp.msgQueue = &queue; }
void cfdp::DestHandler::setMsgQueue(MessageQueueIF& queue) { fsfwParams.msgQueue = &queue; }
void cfdp::DestHandler::setEventReporter(EventReportingProxyIF& reporter) {
fp.eventReporter = &reporter;
fsfwParams.eventReporter = &reporter;
}
const cfdp::DestHandlerParams& cfdp::DestHandler::getDestHandlerParams() const { return dp; }
const cfdp::DestHandlerParams& cfdp::DestHandler::getDestHandlerParams() const {
return destParams;
}
StorageManagerIF* cfdp::DestHandler::getTmStore() const { return fp.tmStore; }
StorageManagerIF* cfdp::DestHandler::getTcStore() const { return fp.tcStore; }
StorageManagerIF* cfdp::DestHandler::getTmStore() const { return fsfwParams.tmStore; }
StorageManagerIF* cfdp::DestHandler::getTcStore() const { return fsfwParams.tcStore; }

View File

@ -13,6 +13,7 @@
#include "fsfw/cfdp/handler/mib.h"
#include "fsfw/cfdp/pdu/MetadataPduReader.h"
#include "fsfw/cfdp/pdu/PduConfig.h"
#include "fsfw/cfdp/tlv/MessageToUserTlv.h"
#include "fsfw/container/DynamicFIFO.h"
#include "fsfw/storagemanager/StorageManagerIF.h"
#include "fsfw/storagemanager/storeAddress.h"
@ -20,23 +21,9 @@
namespace cfdp {
struct PacketInfo {
PacketInfo(PduType type, store_address_t storeId,
std::optional<FileDirective> directive = std::nullopt)
: pduType(type), directiveType(directive), storeId(storeId) {}
PduType pduType = PduType::FILE_DATA;
std::optional<FileDirective> directiveType = FileDirective::INVALID_DIRECTIVE;
store_address_t storeId = store_address_t::invalid();
PacketInfo() = default;
};
template <size_t SIZE>
using LostSegmentsList = etl::set<etl::pair<uint64_t, uint64_t>, SIZE>;
template <size_t SIZE>
using PacketInfoList = etl::list<PacketInfo, SIZE>;
using LostSegmentsListBase = etl::iset<etl::pair<uint64_t, uint64_t>>;
using PacketInfoListBase = etl::ilist<PacketInfo>;
struct DestHandlerParams {
DestHandlerParams(LocalEntityCfg cfg, UserBase& user, RemoteConfigTableIF& remoteCfgTable,
@ -44,6 +31,9 @@ struct DestHandlerParams {
// TODO: This container can potentially take tons of space. For a better
// memory efficient implementation, an additional abstraction could be
// be used so users can use uint32_t as the pair type
// TODO: Actually, we can provide a better abstraction via interface, which
// allows using something like a bounded map. This simplifies
// the implementation significantly.
LostSegmentsListBase& lostSegmentsContainer)
: cfg(std::move(cfg)),
user(user),
@ -57,31 +47,10 @@ struct DestHandlerParams {
PacketInfoListBase& packetListRef;
LostSegmentsListBase& lostSegmentsContainer;
uint8_t maxTlvsInOnePdu = 10;
uint8_t maxTlvsInOnePdu = 20;
size_t maxFilenameLen = 255;
};
struct FsfwParams {
FsfwParams(AcceptsTelemetryIF& packetDest, MessageQueueIF* msgQueue,
EventReportingProxyIF* eventReporter, StorageManagerIF& tcStore,
StorageManagerIF& tmStore)
: FsfwParams(packetDest, msgQueue, eventReporter) {
this->tcStore = &tcStore;
this->tmStore = &tmStore;
}
FsfwParams(AcceptsTelemetryIF& packetDest, MessageQueueIF* msgQueue,
EventReportingProxyIF* eventReporter)
: packetDest(packetDest), msgQueue(msgQueue), eventReporter(eventReporter) {}
AcceptsTelemetryIF& packetDest;
MessageQueueIF* msgQueue;
EventReportingProxyIF* eventReporter = nullptr;
StorageManagerIF* tcStore = nullptr;
StorageManagerIF* tmStore = nullptr;
};
enum class CallStatus { DONE, CALL_AFTER_DELAY, CALL_AGAIN };
class DestHandler {
public:
enum class TransactionStep : uint8_t {
@ -98,7 +67,7 @@ class DestHandler {
ReturnValue_t result = returnvalue::OK;
CallStatus callStatus = CallStatus::CALL_AFTER_DELAY;
TransactionStep step = TransactionStep::IDLE;
CfdpStates state = CfdpStates::IDLE;
CfdpState state = CfdpState::IDLE;
uint32_t packetsSent = 0;
uint8_t errors = 0;
std::array<ReturnValue_t, 3> errorCodes = {};
@ -123,7 +92,7 @@ class DestHandler {
* - @c returnvalue::OK State machine OK for this execution cycle
* - @c CALL_FSM_AGAIN State machine should be called again.
*/
const FsmResult& performStateMachine();
const FsmResult& stateMachine();
void setMsgQueue(MessageQueueIF& queue);
void setEventReporter(EventReportingProxyIF& reporter);
@ -131,7 +100,7 @@ class DestHandler {
ReturnValue_t initialize();
[[nodiscard]] CfdpStates getCfdpState() const;
[[nodiscard]] CfdpState getCfdpState() const;
[[nodiscard]] TransactionStep getTransactionStep() const;
[[nodiscard]] const TransactionId& getTransactionId() const;
[[nodiscard]] const DestHandlerParams& getDestHandlerParams() const;
@ -156,17 +125,19 @@ class DestHandler {
crc = 0;
progress = 0;
remoteCfg = nullptr;
metadataOnly = false;
closureRequested = false;
vfsErrorCount = 0;
checksumType = ChecksumType::NULL_CHECKSUM;
}
bool metadataOnly = false;
ChecksumType checksumType = ChecksumType::NULL_CHECKSUM;
bool closureRequested = false;
uint16_t vfsErrorCount = 0;
std::vector<char> sourceName;
std::vector<char> destName;
cfdp::FileSize fileSize;
cfdp::Fss fileSize;
TransactionId transactionId;
PduConfig pduConf;
ConditionCode conditionCode = ConditionCode::NO_ERROR;
@ -178,13 +149,13 @@ class DestHandler {
};
std::vector<cfdp::Tlv> tlvVec;
std::vector<cfdp::Tlv> userTlvVec;
DestHandlerParams dp;
FsfwParams fp;
TransactionParams tp;
std::vector<MessageToUserTlv> msgToUserVec;
TransactionParams transactionParams;
DestHandlerParams destParams;
cfdp::FsfwParams fsfwParams;
FsmResult fsmRes;
ReturnValue_t startTransaction(MetadataPduReader& reader, MetadataInfo& info);
ReturnValue_t startTransaction(const MetadataPduReader& reader);
ReturnValue_t handleMetadataPdu(const PacketInfo& info);
ReturnValue_t handleFileDataPdu(const PacketInfo& info);
ReturnValue_t handleEofPdu(const PacketInfo& info);
@ -195,7 +166,7 @@ class DestHandler {
ReturnValue_t sendFinishedPdu();
ReturnValue_t noticeOfCompletion();
ReturnValue_t checksumVerification();
void fileErrorHandler(Event event, ReturnValue_t result, const char* info);
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();

View File

@ -0,0 +1,201 @@
#include "PutRequest.h"
using namespace returnvalue;
cfdp::PutRequest::PutRequest(cfdp::EntityId destId, const uint8_t *msgsToUser,
size_t msgsToUserTotalSize, const uint8_t *fsRequests,
size_t fsRequestsSize)
: destId(std::move(destId)),
metadataOnly(true),
msgsToUsersTotalSize(msgsToUserTotalSize),
msgsToUserStartPtr(msgsToUser),
fsRequestsTotalSize(fsRequestsSize),
fsRequestStartPtr(fsRequests) {}
cfdp::PutRequest::PutRequest(cfdp::EntityId destId, cfdp::StringLv &sourceName,
cfdp::StringLv &destName)
: destId(std::move(destId)), sourceName(std::move(sourceName)), destName(std::move(destName)) {}
[[nodiscard]] bool cfdp::PutRequest::isMetadataOnly() const { return metadataOnly; }
ReturnValue_t cfdp::PutRequest::serialize(uint8_t **buffer, size_t *size, size_t maxSize,
SerializeIF::Endianness streamEndianness) const {
if (buffer == nullptr or size == nullptr) {
return FAILED;
}
if (*size + getSerializedSize() > maxSize) {
return SerializeIF::BUFFER_TOO_SHORT;
}
ReturnValue_t result = destId.serializeAsLv(buffer, size, maxSize);
if (result != OK) {
return result;
}
result = SerializeAdapter::serialize(&metadataOnly, buffer, size, maxSize, streamEndianness);
if (result != OK) {
return result;
}
if (!metadataOnly) {
result = sourceName.serialize(buffer, size, maxSize, streamEndianness);
if (result != OK) {
return result;
}
result = destName.serialize(buffer, size, maxSize, streamEndianness);
if (result != OK) {
return result;
}
result =
SerializeAdapter::serialize(&hasTransmissionMode, buffer, size, maxSize, streamEndianness);
if (result != OK) {
return result;
}
result =
SerializeAdapter::serialize(&transmissionMode, buffer, size, maxSize, streamEndianness);
if (result != OK) {
return result;
}
result =
SerializeAdapter::serialize(&hasClosureRequested, buffer, size, maxSize, streamEndianness);
if (result != OK) {
return result;
}
result =
SerializeAdapter::serialize(&closureRequested, buffer, size, maxSize, streamEndianness);
if (result != OK) {
return result;
}
}
result =
SerializeAdapter::serialize(&msgsToUsersTotalSize, buffer, size, maxSize, streamEndianness);
if (result != OK) {
return result;
}
std::memcpy(*buffer, msgsToUserStartPtr, msgsToUsersTotalSize);
*buffer += msgsToUsersTotalSize;
*size += msgsToUsersTotalSize;
result =
SerializeAdapter::serialize(&fsRequestsTotalSize, buffer, size, maxSize, streamEndianness);
if (result != OK) {
return result;
}
std::memcpy(*buffer, fsRequestStartPtr, fsRequestsTotalSize);
*buffer += fsRequestsTotalSize;
*size += fsRequestsTotalSize;
return OK;
}
ReturnValue_t cfdp::PutRequest::deSerialize(const uint8_t **buffer, size_t *size,
SerializeIF::Endianness streamEndianness) {
if (buffer == nullptr or size == nullptr) {
return FAILED;
}
ReturnValue_t result = destId.deSerializeFromLv(buffer, size);
if (result != OK) {
return result;
}
result = SerializeAdapter::deSerialize(&metadataOnly, buffer, size, streamEndianness);
if (result != OK) {
return result;
}
if (!metadataOnly) {
result = sourceName.deSerialize(buffer, size, streamEndianness);
if (result != OK) {
return result;
}
result = destName.deSerialize(buffer, size, streamEndianness);
if (result != OK) {
return result;
}
result = SerializeAdapter::deSerialize(&hasTransmissionMode, buffer, size, streamEndianness);
if (result != OK) {
return result;
}
result = SerializeAdapter::deSerialize(&transmissionMode, buffer, size, streamEndianness);
if (result != OK) {
return result;
}
result = SerializeAdapter::deSerialize(&hasClosureRequested, buffer, size, streamEndianness);
if (result != OK) {
return result;
}
result = SerializeAdapter::deSerialize(&closureRequested, buffer, size, streamEndianness);
if (result != OK) {
return result;
}
}
result = SerializeAdapter::deSerialize(&msgsToUsersTotalSize, buffer, size, streamEndianness);
if (result != OK) {
return result;
}
msgsToUserStartPtr = *buffer;
*buffer += msgsToUsersTotalSize;
*size += msgsToUsersTotalSize;
result = SerializeAdapter::deSerialize(&fsRequestsTotalSize, buffer, size, streamEndianness);
if (result != OK) {
return result;
}
fsRequestStartPtr = *buffer;
*buffer += fsRequestsTotalSize;
*size += fsRequestsTotalSize;
return OK;
}
size_t cfdp::PutRequest::getSerializedSize() const {
// Entity ID LV (1 leading size byte) and the metadata only flag.
size_t baseSize = 1 + destId.getSerializedSize() + 1;
if (!metadataOnly) {
baseSize += sourceName.getSerializedSize() + destName.getSerializedSize() + 4;
}
baseSize += sizeof(msgsToUsersTotalSize) + msgsToUsersTotalSize + sizeof(fsRequestsTotalSize) +
fsRequestsTotalSize;
return baseSize;
}
void cfdp::PutRequest::setSourceAndDestName(cfdp::StringLv &sourceName_,
cfdp::StringLv &destName_) {
metadataOnly = false;
this->sourceName = std::move(sourceName_);
this->destName = std::move(destName_);
}
const cfdp::StringLv &cfdp::PutRequest::getSourceName() const { return sourceName; }
const cfdp::StringLv &cfdp::PutRequest::getDestName() const { return destName; }
const cfdp::EntityId &cfdp::PutRequest::getDestId() const { return destId; }
void cfdp::PutRequest::setDestId(cfdp::EntityId id) { destId = std::move(id); }
void cfdp::PutRequest::setTransmissionMode(cfdp::TransmissionMode transmissionMode_) {
this->transmissionMode = transmissionMode_;
hasTransmissionMode = true;
}
void cfdp::PutRequest::clearTransmissionMode() { hasTransmissionMode = false; }
void cfdp::PutRequest::clearClosureRequest() { hasClosureRequested = false; }
void cfdp::PutRequest::setClosureRequest(bool closureRequested_) {
this->closureRequested = closureRequested_;
hasClosureRequested = true;
}
const uint8_t *cfdp::PutRequest::getMessagesToUser(size_t &totalSize) {
totalSize = this->msgsToUsersTotalSize;
return msgsToUserStartPtr;
}
bool cfdp::PutRequest::getClosureRequested(bool &closureRequested_) const {
if (hasClosureRequested) {
closureRequested_ = this->closureRequested;
}
return hasClosureRequested;
}
bool cfdp::PutRequest::getTransmissionMode(cfdp::TransmissionMode &mode) const {
if (hasTransmissionMode) {
mode = static_cast<cfdp::TransmissionMode>(this->transmissionMode);
}
return hasTransmissionMode;
}

View File

@ -0,0 +1,82 @@
#pragma once
#include <optional>
#include <vector>
#include "fsfw/cfdp/VarLenFields.h"
#include "fsfw/cfdp/tlv/FilestoreRequestTlv.h"
#include "fsfw/cfdp/tlv/MessageToUserTlv.h"
namespace cfdp {
class PutRequest : public SerializeIF {
public:
/**
* Metadata only constructor.
* @param destId
* @param msgsToUser
* @param msgsToUserTotalSize
* @param fsRequests
* @param fsRequestsSize
*/
PutRequest(EntityId destId, const uint8_t* msgsToUser, size_t msgsToUserTotalSize,
const uint8_t* fsRequests, size_t fsRequestsSize);
/**
* Put request to initiate file transfers. By default, the transmission mode and closure requested
* parameter are not present, thereby being derived from the remote configuration for a
* particular destination ID.
* @param destId
* @param sourceName
* @param destName
*/
PutRequest(EntityId destId, cfdp::StringLv& sourceName, cfdp::StringLv& destName);
/**
* Default constructor for deserialization.
*/
PutRequest() = default;
[[nodiscard]] ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
Endianness streamEndianness) const override;
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
Endianness streamEndianness) override;
[[nodiscard]] size_t getSerializedSize() const override;
void setSourceAndDestName(cfdp::StringLv& sourceName, cfdp::StringLv& destName);
[[nodiscard]] const cfdp::StringLv& getSourceName() const;
[[nodiscard]] const cfdp::StringLv& getDestName() const;
void setTransmissionMode(cfdp::TransmissionMode transmissionMode);
void clearTransmissionMode();
void setClosureRequest(bool closureRequested);
void clearClosureRequest();
const uint8_t* getMessagesToUser(size_t& msgSize);
[[nodiscard]] bool isMetadataOnly() const;
bool getTransmissionMode(TransmissionMode& mode) const;
bool getClosureRequested(bool& closureRequested) const;
[[nodiscard]] const EntityId& getDestId() const;
void setDestId(EntityId id);
private:
EntityId destId;
uint8_t metadataOnly = true;
// Transaction parameters. Omitted if the put request is metadata only.
cfdp::StringLv sourceName;
cfdp::StringLv destName;
bool hasTransmissionMode = false;
uint8_t transmissionMode = TransmissionMode::UNACKNOWLEDGED;
bool hasClosureRequested = false;
uint8_t closureRequested = false;
// Metadata
size_t msgsToUsersTotalSize = 0;
const uint8_t* msgsToUserStartPtr = nullptr;
size_t fsRequestsTotalSize = 0;
const uint8_t* fsRequestStartPtr = nullptr;
};
} // namespace cfdp

View File

@ -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

View File

@ -0,0 +1,74 @@
#include "ReservedMessageParser.h"
#include "fsfw/cfdp/CfdpMessage.h"
#include "fsfw/cfdp/handler/PutRequest.h"
#include "fsfw/cfdp/tlv/MessageToUserTlv.h"
#include "fsfw/ipc/CommandMessage.h"
#include "fsfw/ipc/QueueFactory.h"
using namespace returnvalue;
cfdp::ReservedMessageParser::ReservedMessageParser(StorageManagerIF& ipcStore,
MessageQueueIF& msgQueue,
MessageQueueId_t userDestination)
: msgQueue(msgQueue), ipcStore(ipcStore), userDestination(userDestination) {}
ReturnValue_t cfdp::ReservedMessageParser::parse(const MessageToUserTlv* msgsToUserArray,
size_t numMsgToUser) {
ReturnValue_t result = returnvalue::OK;
cfdp::StringLv sourceFileName;
cfdp::StringLv destFileName;
PutRequest putRequest;
const uint8_t* currentPtr = nullptr;
size_t deserSize = 0;
bool needToSendPutRequest = false;
for (size_t idx = 0; idx < numMsgToUser; idx++) {
if (&msgsToUserArray[idx] == nullptr) {
continue;
}
uint8_t messageType = 0;
if (msgsToUserArray[idx].isReservedCfdpMessage(messageType, &currentPtr, deserSize)) {
if (messageType == static_cast<uint8_t>(ProxyOpMessageType::PUT_REQUEST)) {
EntityId entityIdLv;
result = entityIdLv.deSerializeFromLv(&currentPtr, &deserSize);
if (result != returnvalue::OK) {
return result;
}
putRequest.setDestId(entityIdLv);
result =
sourceFileName.deSerialize(&currentPtr, &deserSize, SerializeIF::Endianness::NETWORK);
if (result != OK) {
return result;
}
result =
destFileName.deSerialize(&currentPtr, &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;
}

View File

@ -0,0 +1,27 @@
#pragma once
#include "fsfw/cfdp/tlv/MessageToUserTlv.h"
#include "fsfw/ipc/MessageQueueIF.h"
#include "fsfw/storagemanager/StorageManagerIF.h"
namespace cfdp {
/**
* This class parses messages to user for special CFDP messages and converts them to appropriate
* CFDP requests sent via the IPC store where applicable. It also provides an API to retrieve
* custom messages which are not special CFDP messages from a provided bytestream.
*/
class ReservedMessageParser {
public:
ReservedMessageParser(StorageManagerIF& ipcStore, MessageQueueIF& msgQueue,
MessageQueueId_t userDestination);
ReturnValue_t parse(const MessageToUserTlv* msgsToUserArray, size_t numMsgsToUser);
private:
MessageQueueIF& msgQueue;
StorageManagerIF& ipcStore;
MessageQueueId_t userDestination;
};
} // namespace cfdp

View File

@ -1 +1,376 @@
#include "SourceHandler.h"
#include <etl/crc32.h>
#include <array>
#include "fsfw/cfdp/pdu/EofPduCreator.h"
#include "fsfw/cfdp/pdu/FileDataCreator.h"
#include "fsfw/cfdp/pdu/MetadataPduCreator.h"
#include "fsfw/filesystem/HasFileSystemIF.h"
#include "fsfw/globalfunctions/arrayprinter.h"
#include "fsfw/objectmanager.h"
#include "fsfw/serviceinterface.h"
#include "fsfw/tasks/TaskFactory.h"
#include "fsfw/tmtcservices/TmTcMessage.h"
using namespace returnvalue;
cfdp::SourceHandler::SourceHandler(SourceHandlerParams params, FsfwParams fsfwParams)
: sourceParams(std::move(params)), fsfwParams(fsfwParams) {
// The entity ID portion of the transaction ID will always remain fixed.
transactionParams.id.entityId = sourceParams.cfg.localId;
transactionParams.pduConf.sourceId = sourceParams.cfg.localId;
if (sourceParams.seqCountProvider.bitWidth() == 8) {
transactionParams.pduConf.seqNum.setWidth(cfdp::WidthInBytes::ONE_BYTE);
} else if (sourceParams.seqCountProvider.bitWidth() == 16) {
transactionParams.pduConf.seqNum.setWidth(cfdp::WidthInBytes::TWO_BYTES);
} else if (sourceParams.seqCountProvider.bitWidth() == 32) {
transactionParams.pduConf.seqNum.setWidth(cfdp::WidthInBytes::FOUR_BYTES);
} else if (sourceParams.seqCountProvider.bitWidth() == 64) {
transactionParams.pduConf.seqNum.setWidth(cfdp::WidthInBytes::EIGHT_BYTES);
} else {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "cfdp::SourceHandler: Seq count provider bit width "
<< sourceParams.seqCountProvider.bitWidth() << " not allowed" << std::endl;
#else
sif::printError("cfdp::SourceHandler: Seq count provider bit width %d not allowed\n",
sourceParams.seqCountProvider.bitWidth());
#endif
// Yeah, what am I supposed to do here? Can't throw an exception in the FSFW..
transactionParams.pduConf.seqNum.setWidth(cfdp::WidthInBytes::ONE_BYTE);
}
transactionParams.pduConf.seqNum.setValue(0);
}
cfdp::SourceHandler::FsmResult& cfdp::SourceHandler::fsmNacked() {
ReturnValue_t result;
if (step == TransactionStep::IDLE) {
step = TransactionStep::TRANSACTION_START;
}
if (step == TransactionStep::TRANSACTION_START) {
sourceParams.user.transactionIndication(transactionParams.id);
result = checksumGeneration();
if (result != OK) {
addError(result);
}
step = TransactionStep::SENDING_METADATA;
}
if (step == TransactionStep::SENDING_METADATA) {
result = prepareAndSendMetadataPdu();
if (result != OK) {
addError(result);
}
fsmResult.callStatus = CallStatus::CALL_AGAIN;
return fsmResult;
}
if (step == TransactionStep::SENDING_FILE_DATA) {
bool noFdPdu = false;
result = prepareAndSendNextFileDataPdu(noFdPdu);
if (result == OK and !noFdPdu) {
fsmResult.callStatus = CallStatus::CALL_AGAIN;
return fsmResult;
}
}
if (step == TransactionStep::SENDING_EOF) {
result = prepareAndSendEofPdu();
if (result != OK) {
addError(result);
}
if (sourceParams.cfg.indicCfg.eofSentIndicRequired) {
sourceParams.user.eofSentIndication(transactionParams.id);
}
if (transactionParams.closureRequested) {
step = TransactionStep::WAIT_FOR_FINISH;
fsmResult.callStatus = CallStatus::CALL_AFTER_DELAY;
} else {
step = TransactionStep::NOTICE_OF_COMPLETION;
fsmResult.callStatus = CallStatus::CALL_AGAIN;
}
return fsmResult;
}
if (step == TransactionStep::WAIT_FOR_FINISH) {
// TODO: In case this is a request with closure, wait for finish.
// Done, issue notice of completion
step = TransactionStep::NOTICE_OF_COMPLETION;
}
if (step == TransactionStep::NOTICE_OF_COMPLETION) {
noticeOfCompletion();
reset();
}
return fsmResult;
}
const cfdp::SourceHandler::FsmResult& cfdp::SourceHandler::stateMachine() {
fsmResult.packetsSent = 0;
fsmResult.errors = 0;
fsmResult.callStatus = CallStatus::DONE;
if (state == cfdp::CfdpState::IDLE) {
return fsmResult;
}
if (state == cfdp::CfdpState::BUSY_CLASS_1_NACKED) {
return fsmNacked();
}
return fsmResult;
}
ReturnValue_t cfdp::SourceHandler::checksumGeneration() {
if (transactionParams.fileSize.value() == 0) {
// NULL checksum for empty file.
transactionParams.crc = 0;
return OK;
}
std::array<uint8_t, 1024> buf{};
etl::crc32 crcCalc;
uint64_t currentOffset = 0;
FileOpParams params(transactionParams.sourceName.data(), transactionParams.fileSize.value());
while (currentOffset < transactionParams.fileSize.value()) {
uint64_t readLen;
if (currentOffset + buf.size() > transactionParams.fileSize.value()) {
readLen = transactionParams.fileSize.value() - currentOffset;
} else {
readLen = buf.size();
}
if (readLen > 0) {
params.offset = currentOffset;
params.size = readLen;
auto result = sourceParams.user.vfs.readFromFile(params, buf.data(), buf.size());
if (result != OK) {
addError(result);
return FAILED;
}
crcCalc.add(buf.begin(), buf.begin() + readLen);
}
currentOffset += readLen;
}
transactionParams.crc = crcCalc.value();
return OK;
}
ReturnValue_t cfdp::SourceHandler::transactionStart(PutRequest& putRequest, RemoteEntityCfg& cfg) {
if (state != CfdpState::IDLE) {
return SOURCE_TRANSACTION_PENDING;
}
if (cfg.remoteId != putRequest.getDestId()) {
return WRONG_REMOTE_CFG_ENTITY_ID;
}
if (putRequest.getSourceName().getValueLen() == 0) {
return SOURCE_NAME_EMPTY;
}
if (putRequest.getDestName().getValueLen() == 0) {
return DEST_NAME_EMPTY;
}
const char* srcNamePtr = putRequest.getSourceName().getCString(transactionParams.sourceNameSize);
const char* destNamePtr = putRequest.getDestName().getCString(transactionParams.destNameSize);
std::strncpy(transactionParams.sourceName.data(), srcNamePtr, transactionParams.sourceNameSize);
std::strncpy(transactionParams.destName.data(), destNamePtr, transactionParams.destNameSize);
// Add 0 termination. The source and dest name size can not be larger than UINT8_MAX, so this
// operation is safe.
transactionParams.sourceName[transactionParams.sourceNameSize] = '\0';
transactionParams.destName[transactionParams.destNameSize] = '\0';
FilesystemParams params(transactionParams.sourceName.data());
if (!sourceParams.user.vfs.fileExists(params)) {
return FILE_DOES_NOT_EXIST;
}
if (cfg.maxFileSegmentLen > fileBuf.size() or cfg.maxFileSegmentLen == 0) {
return FILE_SEGMENT_LEN_INVALID;
}
// If transmission mode is not set, use default transmission mode for the remote entity.
if (not putRequest.getTransmissionMode(transactionParams.pduConf.mode)) {
transactionParams.pduConf.mode = cfg.defaultTransmissionMode;
}
// If closure request field is not set, use default option for the remote entity.
if (not putRequest.getClosureRequested(transactionParams.closureRequested)) {
transactionParams.closureRequested = cfg.closureRequested;
}
const EntityId& destId = putRequest.getDestId();
// The width of the source and destination ID must be the same. Use the larger ID value to
// ensure the width is large enough for both IDs
if (destId.getWidth() > transactionParams.pduConf.sourceId.getWidth()) {
transactionParams.pduConf.destId = destId;
transactionParams.pduConf.sourceId.setWidth(destId.getWidth());
} else {
transactionParams.pduConf.destId.setValueAndWidth(transactionParams.pduConf.sourceId.getWidth(),
destId.getValue());
}
// Only used for PDU forwarding, file is sent to file receiver regularly here.
transactionParams.pduConf.direction = Direction::TOWARDS_RECEIVER;
transactionParams.pduConf.seqNum.setValue(sourceParams.seqCountProvider.getAndIncrement());
transactionParams.id.seqNum = transactionParams.pduConf.seqNum;
if (transactionParams.pduConf.mode == TransmissionMode::ACKNOWLEDGED) {
state = cfdp::CfdpState::BUSY_CLASS_2_ACKED;
} else if (transactionParams.pduConf.mode == TransmissionMode::UNACKNOWLEDGED) {
state = cfdp::CfdpState::BUSY_CLASS_1_NACKED;
}
step = TransactionStep::IDLE;
uint64_t fileSize = 0;
sourceParams.user.vfs.getFileSize(params, fileSize);
transactionParams.pduConf.largeFile = false;
if (fileSize > UINT32_MAX) {
transactionParams.pduConf.largeFile = true;
}
if (fileSize == 0) {
transactionParams.checksumType = ChecksumType::NULL_CHECKSUM;
} else {
transactionParams.checksumType = ChecksumType::CRC_32;
}
transactionParams.fileSize.setFileSize(fileSize, transactionParams.pduConf.largeFile);
transactionParams.progress = 0;
transactionParams.remoteCfg = cfg;
return OK;
}
ReturnValue_t cfdp::SourceHandler::prepareAndSendMetadataPdu() {
cfdp::StringLv sourceName(transactionParams.sourceName.data(), transactionParams.sourceNameSize);
cfdp::StringLv destName(transactionParams.destName.data(), transactionParams.destNameSize);
auto metadataInfo =
MetadataGenericInfo(transactionParams.closureRequested, transactionParams.checksumType,
transactionParams.fileSize);
auto metadataPdu =
MetadataPduCreator(transactionParams.pduConf, metadataInfo, sourceName, destName, nullptr, 0);
ReturnValue_t result = sendGenericPdu(metadataPdu);
if (result != OK) {
return result;
}
// Advance FSM if everything works
step = TransactionStep::SENDING_FILE_DATA;
return OK;
}
ReturnValue_t cfdp::SourceHandler::prepareAndSendNextFileDataPdu(bool& noFileDataPdu) {
cfdp::Fss offset(transactionParams.progress);
uint64_t readLen;
uint64_t fileSize = transactionParams.fileSize.value();
noFileDataPdu = false;
if (fileSize == 0) {
// We are done, no need to send file data PDUs for an empty file.
step = TransactionStep::SENDING_EOF;
noFileDataPdu = true;
return OK;
}
if (fileSize < transactionParams.remoteCfg.maxFileSegmentLen) {
readLen = transactionParams.fileSize.value();
} else {
if (transactionParams.progress + transactionParams.remoteCfg.maxFileSegmentLen > fileSize) {
readLen = fileSize - transactionParams.progress;
} else {
readLen = transactionParams.remoteCfg.maxFileSegmentLen;
}
}
FileOpParams fileParams(transactionParams.sourceName.data(), readLen);
fileParams.offset = transactionParams.progress;
ReturnValue_t result =
sourceParams.user.vfs.readFromFile(fileParams, fileBuf.data(), fileBuf.size());
if (result != returnvalue::OK) {
addError(result);
return result;
}
auto fileDataInfo = FileDataInfo(offset, fileBuf.data(), readLen);
auto fileDataPdu = FileDataCreator(transactionParams.pduConf, fileDataInfo);
result = sendGenericPdu(fileDataPdu);
if (result != OK) {
return result;
}
transactionParams.progress += readLen;
if (transactionParams.progress >= fileSize) {
// Advance FSM after all file data PDUs were sent.
step = TransactionStep::SENDING_EOF;
}
return OK;
}
ReturnValue_t cfdp::SourceHandler::prepareAndSendEofPdu() {
auto eofInfo =
EofInfo(ConditionCode::NO_ERROR, transactionParams.crc, transactionParams.fileSize);
auto eofPdu = EofPduCreator(transactionParams.pduConf, eofInfo);
ReturnValue_t result = sendGenericPdu(eofPdu);
if (result != OK) {
return result;
}
return OK;
}
ReturnValue_t cfdp::SourceHandler::initialize() {
if (fsfwParams.tmStore == nullptr) {
fsfwParams.tmStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TM_STORE);
if (fsfwParams.tmStore == nullptr) {
return FAILED;
}
}
if (fsfwParams.tcStore == nullptr) {
fsfwParams.tcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TC_STORE);
if (fsfwParams.tcStore == nullptr) {
return FAILED;
}
}
if (fsfwParams.msgQueue == nullptr) {
return FAILED;
}
return OK;
}
ReturnValue_t cfdp::SourceHandler::sendGenericPdu(const SerializeIF& pdu) {
uint8_t* dataPtr;
store_address_t storeId;
ReturnValue_t result =
fsfwParams.tmStore->getFreeElement(&storeId, pdu.getSerializedSize(), &dataPtr);
if (result != OK) {
addError(result);
fsmResult.callStatus = CallStatus::CALL_AFTER_DELAY;
if (result == StorageManagerIF::DATA_STORAGE_FULL) {
return TM_STORE_FULL;
}
return result;
}
size_t serializedLen = 0;
result = pdu.serializeBe(dataPtr, serializedLen, pdu.getSerializedSize());
if (result != OK) {
addError(result);
return result;
}
TmTcMessage tmMsg(storeId);
result =
fsfwParams.msgQueue->sendMessage(fsfwParams.packetDest.getReportReceptionQueue(), &tmMsg);
if (result != OK) {
fsmResult.callStatus = CallStatus::CALL_AFTER_DELAY;
}
if (result == MessageQueueIF::FULL) {
return TARGET_MSG_QUEUE_FULL;
} else if (result == OK) {
fsmResult.packetsSent += 1;
}
return result;
}
ReturnValue_t cfdp::SourceHandler::noticeOfCompletion() {
if (sourceParams.cfg.indicCfg.transactionFinishedIndicRequired) {
cfdp::TransactionFinishedParams params(transactionParams.id, ConditionCode::NO_ERROR,
FileDeliveryCode::DATA_COMPLETE,
FileDeliveryStatus::RETAINED_IN_FILESTORE);
sourceParams.user.transactionFinishedIndication(params);
}
return OK;
}
ReturnValue_t cfdp::SourceHandler::reset() {
step = TransactionStep::IDLE;
state = cfdp::CfdpState::IDLE;
fsmResult.callStatus = CallStatus::DONE;
transactionParams.reset();
return OK;
}
cfdp::CfdpState cfdp::SourceHandler::getState() const { return state; }
cfdp::SourceHandler::TransactionStep cfdp::SourceHandler::getStep() const { return step; }
void cfdp::SourceHandler::addError(ReturnValue_t error) {
if (fsmResult.errors < fsmResult.errorCodes.size()) {
fsmResult.errorCodes[fsmResult.errors] = error;
fsmResult.errors++;
fsmResult.result = error;
}
}

View File

@ -1,6 +1,110 @@
#ifndef FSFW_CFDP_CFDPSOURCEHANDLER_H
#define FSFW_CFDP_CFDPSOURCEHANDLER_H
class SourceHandler {};
#include <cstdint>
#include <vector>
#include "UserBase.h"
#include "defs.h"
#include "fsfw/cfdp/Fss.h"
#include "fsfw/cfdp/handler/PutRequest.h"
#include "fsfw/cfdp/handler/mib.h"
#include "fsfw/events/EventReportingProxyIF.h"
#include "fsfw/storagemanager/StorageManagerIF.h"
#include "fsfw/tmtcservices/AcceptsTelemetryIF.h"
#include "fsfw/util/ProvidesSeqCountIF.h"
namespace cfdp {
struct SourceHandlerParams {
SourceHandlerParams(LocalEntityCfg cfg, UserBase& user, ProvidesSeqCountIF& seqCountProvider)
: cfg(std::move(cfg)), user(user), seqCountProvider(seqCountProvider) {}
LocalEntityCfg cfg;
UserBase& user;
ProvidesSeqCountIF& seqCountProvider;
};
class SourceHandler {
public:
enum class TransactionStep : uint8_t {
IDLE = 0,
TRANSACTION_START = 1,
SENDING_METADATA = 3,
SENDING_FILE_DATA = 4,
SENDING_EOF = 5,
WAIT_FOR_ACK = 6,
WAIT_FOR_FINISH = 7,
NOTICE_OF_COMPLETION = 8
};
struct FsmResult {
public:
ReturnValue_t result = returnvalue::OK;
CallStatus callStatus = CallStatus::CALL_AFTER_DELAY;
CfdpState state = CfdpState::IDLE;
uint32_t packetsSent = 0;
uint8_t errors = 0;
std::array<ReturnValue_t, 3> errorCodes = {};
};
SourceHandler(SourceHandlerParams params, FsfwParams fsfwParams);
[[nodiscard]] CfdpState getState() const;
[[nodiscard]] TransactionStep getStep() const;
/**
* Pass a put request to the source handler, which might initiate a CFDP transaction and start
* the state machine
* @return
*/
ReturnValue_t transactionStart(PutRequest& putRequest, RemoteEntityCfg& cfg);
const FsmResult& stateMachine();
ReturnValue_t initialize();
private:
struct TransactionParams {
uint32_t crc{};
std::array<char, UINT8_MAX + 1> sourceName{};
size_t sourceNameSize = 0;
std::array<char, UINT8_MAX + 1> destName{};
size_t destNameSize = 0;
cfdp::Fss fileSize;
size_t progress = 0;
bool closureRequested = false;
ChecksumType checksumType = ChecksumType::NULL_CHECKSUM;
RemoteEntityCfg remoteCfg;
PduConfig pduConf;
cfdp::TransactionId id{};
void reset() {
sourceNameSize = 0;
destNameSize = 0;
fileSize.setFileSize(0, false);
progress = 0;
closureRequested = false;
}
} transactionParams;
cfdp::CfdpState state = cfdp::CfdpState::IDLE;
TransactionStep step = TransactionStep::IDLE;
std::array<uint8_t, 4096> fileBuf{};
SourceHandlerParams sourceParams;
cfdp::FsfwParams fsfwParams;
FsmResult fsmResult;
FsmResult& fsmNacked();
ReturnValue_t checksumGeneration();
ReturnValue_t prepareAndSendMetadataPdu();
ReturnValue_t prepareAndSendNextFileDataPdu(bool& noFileDataPdu);
ReturnValue_t prepareAndSendEofPdu();
ReturnValue_t noticeOfCompletion();
ReturnValue_t reset();
[[nodiscard]] ReturnValue_t sendGenericPdu(const SerializeIF& pdu);
void addError(ReturnValue_t error);
};
} // namespace cfdp
#endif // FSFW_CFDP_CFDPSOURCEHANDLER_H

View File

@ -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);

View File

@ -1,11 +1,54 @@
#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 {
@ -15,8 +58,19 @@ static constexpr Event SERIALIZATION_ERROR = event::makeEvent(SSID, 2, severity:
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

View File

@ -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

View File

@ -17,7 +17,7 @@ target_sources(
FinishedInfo.cpp
FinishedPduCreator.cpp
FinishedPduReader.cpp
MetadataInfo.cpp
MetadataGenericInfo.cpp
MetadataPduCreator.cpp
MetadataPduReader.cpp
KeepAlivePduCreator.cpp

View File

@ -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);
}

View File

@ -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;
};

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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();
}

View File

@ -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_ */

View File

@ -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; }

View File

@ -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_ */

View File

@ -0,0 +1,35 @@
#include "MetadataGenericInfo.h"
MetadataGenericInfo::MetadataGenericInfo(bool closureRequested, cfdp::ChecksumType checksumType,
cfdp::Fss fileSize)
: MetadataGenericInfo(std::move(fileSize)) {
this->closureRequested = closureRequested;
this->checksumType = checksumType;
}
MetadataGenericInfo::MetadataGenericInfo(cfdp::Fss fileSize) : fileSize(std::move(fileSize)) {}
cfdp::ChecksumType MetadataGenericInfo::getChecksumType() const { return checksumType; }
void MetadataGenericInfo::setChecksumType(cfdp::ChecksumType checksumType_) {
checksumType = checksumType_;
}
bool MetadataGenericInfo::isClosureRequested() const { return closureRequested; }
void MetadataGenericInfo::setClosureRequested(bool closureRequested_) {
closureRequested = closureRequested_;
}
const cfdp::Fss& MetadataGenericInfo::getFileSize() const { return fileSize; }
size_t MetadataGenericInfo::getSerializedSize(bool fssLarge) {
// 1 byte + minimal FSS 4 bytes
size_t size = 5;
if (fssLarge) {
size += 4;
}
return size;
}
cfdp::Fss& MetadataGenericInfo::getMutFileSize() { return fileSize; }

View File

@ -0,0 +1,35 @@
#ifndef FSFW_SRC_FSFW_CFDP_PDU_METADATAINFO_H_
#define FSFW_SRC_FSFW_CFDP_PDU_METADATAINFO_H_
#include <optional>
#include "fsfw/cfdp/Fss.h"
#include "fsfw/cfdp/definitions.h"
#include "fsfw/cfdp/tlv/Lv.h"
#include "fsfw/cfdp/tlv/StringLv.h"
#include "fsfw/cfdp/tlv/Tlv.h"
class MetadataGenericInfo {
public:
MetadataGenericInfo() = default;
explicit MetadataGenericInfo(cfdp::Fss fileSize);
MetadataGenericInfo(bool closureRequested, cfdp::ChecksumType checksumType, cfdp::Fss fileSize);
static size_t getSerializedSize(bool fssLarge = false);
[[nodiscard]] cfdp::ChecksumType getChecksumType() const;
void setChecksumType(cfdp::ChecksumType checksumType);
[[nodiscard]] bool isClosureRequested() const;
void setClosureRequested(bool closureRequested = false);
[[nodiscard]] const cfdp::Fss& getFileSize() const;
cfdp::Fss& getMutFileSize();
private:
bool closureRequested = false;
cfdp::ChecksumType checksumType = cfdp::ChecksumType::NULL_CHECKSUM;
cfdp::Fss fileSize;
};
#endif /* FSFW_SRC_FSFW_CFDP_PDU_METADATAINFO_H_ */

View File

@ -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; }

View File

@ -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_ */

View File

@ -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; }

View File

@ -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_ */

View File

@ -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; }

View File

@ -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_ */

View File

@ -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; }

View File

@ -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;

View File

@ -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"

View File

@ -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;

View File

@ -8,4 +8,5 @@ target_sources(
StringLv.cpp
FlowLabelTlv.cpp
MessageToUserTlv.cpp
FaultHandlerOverrideTlv.cpp)
FaultHandlerOverrideTlv.cpp
ReservedMessageCreator.cpp)

View File

@ -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; }

View File

@ -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;

View File

@ -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;
}

View File

@ -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:
};

View File

@ -0,0 +1,39 @@
#include "ReservedMessageCreator.h"
cfdp::ReservedMessageCreator::ReservedMessageCreator(uint8_t messageType, uint8_t *msgData,
size_t msgLen)
: messageType(messageType), msgData(msgData), msgSize(msgLen) {}
ReturnValue_t cfdp::ReservedMessageCreator::serialize(
uint8_t **buffer, size_t *size, size_t maxSize,
SerializeIF::Endianness streamEndianness) const {
if (*size + getSerializedSize() > maxSize) {
return SerializeIF::BUFFER_TOO_SHORT;
}
**buffer = TlvType::MSG_TO_USER;
*buffer += 1;
*size += 1;
**buffer = getSerializedSize() - 2;
*size += 1;
*buffer += 1;
std::memcpy(*buffer, MSG_HEADER, 4);
*buffer += 4;
*size += 4;
**buffer = messageType;
*buffer += 1;
*size += 1;
std::memcpy(*buffer, msgData, msgSize);
*buffer += msgSize;
*size += msgSize;
return returnvalue::OK;
}
size_t cfdp::ReservedMessageCreator::getSerializedSize() const {
// 2 bytes type and length, 4 bytes CFDP, 1 byte reserved message type, message data.
return 2 + 5 + msgSize;
}
ReturnValue_t cfdp::ReservedMessageCreator::deSerialize(const uint8_t **buffer, size_t *size,
SerializeIF::Endianness streamEndianness) {
return returnvalue::FAILED;
}

View File

@ -0,0 +1,24 @@
#pragma once
#include "Tlv.h"
namespace cfdp {
class ReservedMessageCreator : public SerializeIF {
public:
static constexpr char MSG_HEADER[] = "cfdp";
ReservedMessageCreator(uint8_t messageType, uint8_t *msgData, size_t msgLen);
[[nodiscard]] ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize,
Endianness streamEndianness) const override;
[[nodiscard]] size_t getSerializedSize() const override;
ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size,
Endianness streamEndianness) override;
private:
uint8_t messageType;
uint8_t *msgData;
size_t msgSize;
};
} // namespace cfdp

View File

@ -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};
}

View File

@ -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;
};

View File

@ -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; }

View File

@ -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;
};

View File

@ -58,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);
@ -72,18 +72,17 @@ void ControllerBase::getMode(Mode_t* mode_, Submode_t* submode_) {
*submode_ = this->submode;
}
void ControllerBase::setToExternalControl() { healthHelper.setHealth(EXTERNAL_CONTROL); }
void ControllerBase::announceMode(bool recursive) { triggerEvent(MODE_INFO, mode, submode); }
void ControllerBase::modeChanged(Mode_t mode_, Submode_t submode_) {}
void ControllerBase::setToExternalControl() { healthHelper.setHealth(EXTERNAL_CONTROL); }
ReturnValue_t ControllerBase::performOperation(uint8_t opCode) {
handleQueue();
performControlOperation();
return returnvalue::OK;
}
void ControllerBase::modeChanged(Mode_t mode_, Submode_t submode_) {}
ReturnValue_t ControllerBase::setHealth(HealthState health) {
switch (health) {
case HEALTHY:

View File

@ -6,6 +6,8 @@
#include "fsfw/globalfunctions/constants.h"
#include "fsfw/globalfunctions/math/MatrixOperations.h"
#include "fsfw/globalfunctions/math/VectorOperations.h"
#include "fsfw/globalfunctions/sign.h"
#include "fsfw/serviceinterface.h"
void CoordinateTransformations::positionEcfToEci(const double* ecfPosition, double* eciPosition,
timeval* timeUTC) {
@ -97,7 +99,14 @@ void CoordinateTransformations::ecfToEci(const double* ecfCoordinates, double* e
double CoordinateTransformations::getJuleanCenturiesTT(timeval timeUTC) {
timeval timeTT;
Clock::convertUTCToTT(timeUTC, &timeTT);
ReturnValue_t result = Clock::convertUTCToTT(timeUTC, &timeTT);
if (result != returnvalue::OK) {
// i think it is better to continue here than to abort
timeTT = timeUTC;
sif::error << "CoordinateTransformations::Conversion from UTC to TT failed. Continuing "
"calculations with UTC."
<< std::endl;
}
double jD2000TT;
Clock::convertTimevalToJD2000(timeTT, &jD2000TT);
@ -207,3 +216,61 @@ void CoordinateTransformations::getTransMatrixECITOECF(timeval timeUTC, double T
MatrixOperations<double>::multiply(mTheta[0], Ttemp[0], Tfi[0], 3, 3, 3);
};
void CoordinateTransformations::cartesianFromLatLongAlt(const double lat, const double longi,
const double alt, double* cartesianOutput) {
/* @brief: cartesianFromLatLongAlt() - calculates cartesian coordinates in ECEF from latitude,
* longitude and altitude
* @param: lat geodetic latitude [rad]
* longi longitude [rad]
* alt altitude [m]
* cartesianOutput Cartesian Coordinates in ECEF (3x1)
* @source: Fundamentals of Spacecraft Attitude Determination and Control, P.34ff
* Landis Markley and John L. Crassidis*/
double radiusPolar = 6356752.314;
double radiusEqua = 6378137;
double eccentricity = sqrt(1 - pow(radiusPolar, 2) / pow(radiusEqua, 2));
double auxRadius = radiusEqua / sqrt(1 - pow(eccentricity, 2) * pow(sin(lat), 2));
cartesianOutput[0] = (auxRadius + alt) * cos(lat) * cos(longi);
cartesianOutput[1] = (auxRadius + alt) * cos(lat) * sin(longi);
cartesianOutput[2] = ((1 - pow(eccentricity, 2)) * auxRadius + alt) * sin(lat);
};
void CoordinateTransformations::latLongAltFromCartesian(const double* vector, double& latitude,
double& longitude, double& altitude) {
/* @brief: latLongAltFromCartesian() - calculates latitude, longitude and altitude from
* cartesian coordinates in ECEF
* @param: x x-value of position vector [m]
* y y-value of position vector [m]
* z z-value of position vector [m]
* latitude geodetic latitude [rad]
* longitude longitude [rad]
* altitude altitude [m]
* @source: Fundamentals of Spacecraft Attitude Determination and Control, P.35 f
* Landis Markley and John L. Crassidis*/
// From World Geodetic System the Earth Radii
double a = 6378137.0; // semimajor axis [m]
double b = 6356752.3142; // semiminor axis [m]
// Calculation
double e2 = 1 - pow(b, 2) / pow(a, 2);
double epsilon2 = pow(a, 2) / pow(b, 2) - 1;
double rho = sqrt(pow(vector[0], 2) + pow(vector[1], 2));
double p = std::abs(vector[2]) / epsilon2;
double s = pow(rho, 2) / (e2 * epsilon2);
double q = pow(p, 2) - pow(b, 2) + s;
double u = p / sqrt(q);
double v = pow(b, 2) * pow(u, 2) / q;
double P = 27 * v * s / q;
double Q = pow(sqrt(P + 1) + sqrt(P), 2. / 3.);
double t = (1 + Q + 1 / Q) / 6;
double c = sqrt(pow(u, 2) - 1 + 2 * t);
double w = (c - u) / 2;
double d = sign(vector[2]) * sqrt(q) * (w + sqrt(sqrt(pow(t, 2) + v) - u * w - t / 2 - 1. / 4.));
double N = a * sqrt(1 + epsilon2 * pow(d, 2) / pow(b, 2));
latitude = asin((epsilon2 + 1) * d / N);
altitude = rho * cos(latitude) + vector[2] * sin(latitude) - pow(a, 2) / N;
longitude = atan2(vector[1], vector[0]);
}

View File

@ -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,

View File

@ -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;
}

View File

@ -70,8 +70,7 @@ ReturnValue_t LocalDataPoolManager::initialize(MessageQueueIF* queueToUse) {
return returnvalue::OK;
}
ReturnValue_t LocalDataPoolManager::initializeAfterTaskCreation(uint8_t nonDiagInvlFactor) {
setNonDiagnosticIntervalFactor(nonDiagInvlFactor);
ReturnValue_t LocalDataPoolManager::initializeAfterTaskCreation() {
return initializeHousekeepingPoolEntriesOnce();
}
@ -506,9 +505,9 @@ ReturnValue_t LocalDataPoolManager::handleHousekeepingMessage(CommandMessage* me
float newCollIntvl = 0;
HousekeepingMessage::getCollectionIntervalModificationCommand(message, &newCollIntvl);
if (command == HousekeepingMessage::MODIFY_DIAGNOSTICS_REPORT_COLLECTION_INTERVAL) {
result = changeCollectionInterval(sid, newCollIntvl, true);
result = changeCollectionInterval(sid, newCollIntvl);
} else {
result = changeCollectionInterval(sid, newCollIntvl, false);
result = changeCollectionInterval(sid, newCollIntvl);
}
break;
}
@ -661,10 +660,6 @@ ReturnValue_t LocalDataPoolManager::serializeHkPacketIntoStore(HousekeepingPacke
return hkPacket.serialize(&dataPtr, serializedSize, maxSize, SerializeIF::Endianness::MACHINE);
}
void LocalDataPoolManager::setNonDiagnosticIntervalFactor(uint8_t nonDiagInvlFactor) {
this->nonDiagnosticIntervalFactor = nonDiagInvlFactor;
}
void LocalDataPoolManager::performPeriodicHkGeneration(HkReceiver& receiver) {
sid_t sid = receiver.dataId.sid;
LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid);
@ -718,15 +713,15 @@ ReturnValue_t LocalDataPoolManager::togglePeriodicGeneration(sid_t sid, bool ena
if ((LocalPoolDataSetAttorney::getReportingEnabled(*dataSet) and enable) or
(not LocalPoolDataSetAttorney::getReportingEnabled(*dataSet) and not enable)) {
return REPORTING_STATUS_UNCHANGED;
return returnvalue::OK;
}
LocalPoolDataSetAttorney::setReportingEnabled(*dataSet, enable);
return returnvalue::OK;
}
ReturnValue_t LocalDataPoolManager::changeCollectionInterval(sid_t sid, float newCollectionInterval,
bool isDiagnostics) {
ReturnValue_t LocalDataPoolManager::changeCollectionInterval(sid_t sid,
float newCollectionInterval) {
LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid);
if (dataSet == nullptr) {
printWarningOrError(sif::OutputTypes::OUT_WARNING, "changeCollectionInterval",
@ -734,11 +729,6 @@ ReturnValue_t LocalDataPoolManager::changeCollectionInterval(sid_t sid, float ne
return DATASET_NOT_FOUND;
}
bool targetIsDiagnostics = LocalPoolDataSetAttorney::isDiagnostics(*dataSet);
if ((targetIsDiagnostics and not isDiagnostics) or (not targetIsDiagnostics and isDiagnostics)) {
return WRONG_HK_PACKET_TYPE;
}
PeriodicHousekeepingHelper* periodicHelper =
LocalPoolDataSetAttorney::getPeriodicHelper(*dataSet);

View File

@ -102,7 +102,7 @@ class LocalDataPoolManager : public ProvidesDataPoolSubscriptionIF, public Acces
* @param nonDiagInvlFactor
* @return
*/
ReturnValue_t initializeAfterTaskCreation(uint8_t nonDiagInvlFactor = 5);
ReturnValue_t initializeAfterTaskCreation();
/**
* @brief This should be called in the periodic handler of the owner.
@ -152,17 +152,6 @@ class LocalDataPoolManager : public ProvidesDataPoolSubscriptionIF, public Acces
MessageQueueId_t targetQueueId,
bool generateSnapshot) override;
/**
* Non-Diagnostics packets usually have a lower minimum sampling frequency
* than diagnostic packets.
* A factor can be specified to determine the minimum sampling frequency
* for non-diagnostic packets. The minimum sampling frequency of the
* diagnostics packets,which is usually jusst the period of the
* performOperation calls, is multiplied with that factor.
* @param factor
*/
void setNonDiagnosticIntervalFactor(uint8_t nonDiagInvlFactor);
/**
* @brief The manager is also able to handle housekeeping messages.
* @details
@ -185,6 +174,7 @@ class LocalDataPoolManager : public ProvidesDataPoolSubscriptionIF, public Acces
ReturnValue_t generateHousekeepingPacket(sid_t sid, LocalPoolDataSetBase* dataSet,
bool forDownlink,
MessageQueueId_t destination = MessageQueueIF::NO_QUEUE);
ReturnValue_t changeCollectionInterval(sid_t sid, float newCollectionInterval);
HasLocalDataPoolIF* getOwner();
@ -348,8 +338,6 @@ class LocalDataPoolManager : public ProvidesDataPoolSubscriptionIF, public Acces
void performPeriodicHkGeneration(HkReceiver& hkReceiver);
ReturnValue_t togglePeriodicGeneration(sid_t sid, bool enable, bool isDiagnostics);
ReturnValue_t changeCollectionInterval(sid_t sid, float newCollectionInterval,
bool isDiagnostics);
ReturnValue_t generateSetStructurePacket(sid_t sid, bool isDiagnostics);
void handleHkUpdateResetListInsertion(DataType dataType, DataId dataId);

View File

@ -250,9 +250,8 @@ void LocalPoolDataSetBase::setReportingEnabled(bool reportingEnabled) {
bool LocalPoolDataSetBase::getReportingEnabled() const { return reportingEnabled; }
void LocalPoolDataSetBase::initializePeriodicHelper(float collectionInterval,
dur_millis_t minimumPeriodicInterval,
uint8_t nonDiagIntervalFactor) {
periodicHelper->initialize(collectionInterval, minimumPeriodicInterval, nonDiagIntervalFactor);
dur_millis_t minimumPeriodicInterval) {
periodicHelper->initialize(collectionInterval, minimumPeriodicInterval);
}
void LocalPoolDataSetBase::setChanged(bool changed) { this->changed = changed; }

View File

@ -191,8 +191,7 @@ class LocalPoolDataSetBase : public PoolDataSetBase, public MarkChangedIF {
*/
bool reportingEnabled = false;
void initializePeriodicHelper(float collectionInterval, dur_millis_t minimumPeriodicInterval,
uint8_t nonDiagIntervalFactor = 5);
void initializePeriodicHelper(float collectionInterval, dur_millis_t minimumPeriodicInterval);
/**
* If the valid state of a dataset is always relevant to the whole

View File

@ -12,10 +12,8 @@ class LocalPoolDataSetAttorney {
static bool isDiagnostics(LocalPoolDataSetBase& set) { return set.isDiagnostics(); }
static void initializePeriodicHelper(LocalPoolDataSetBase& set, float collectionInterval,
uint32_t minimumPeriodicIntervalMs,
uint8_t nonDiagIntervalFactor = 5) {
set.initializePeriodicHelper(collectionInterval, minimumPeriodicIntervalMs,
nonDiagIntervalFactor);
uint32_t minimumPeriodicIntervalMs) {
set.initializePeriodicHelper(collectionInterval, minimumPeriodicIntervalMs);
}
static void setReportingEnabled(LocalPoolDataSetBase& set, bool enabled) {

View File

@ -7,4 +7,5 @@ target_sources(
DeviceHandlerFailureIsolation.cpp
DeviceHandlerMessage.cpp
DeviceTmReportingWrapper.cpp
FreshDeviceHandlerBase.cpp
HealthDevice.cpp)

View File

@ -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() {}

View File

@ -567,7 +567,7 @@ void DeviceHandlerBase::setMode(Mode_t newMode, uint8_t newSubmode) {
continueToNormal = false;
// TODO: Check whether the following two lines are okay to do so.
transitionSourceMode = MODE_ON;
transitionSourceSubMode = submode;
transitionSourceSubMode = newSubmode;
mode = _MODE_TO_NORMAL;
return;
}

View File

@ -257,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,

View File

@ -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,6 +26,11 @@ 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:
@ -185,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) {

View File

@ -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);

View File

@ -85,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);

View File

@ -0,0 +1,201 @@
#include "FreshDeviceHandlerBase.h"
#include "fsfw/devicehandlers/DeviceHandlerFailureIsolation.h"
#include "fsfw/ipc/QueueFactory.h"
#include "fsfw/subsystem/helper.h"
FreshDeviceHandlerBase::FreshDeviceHandlerBase(DhbConfig config)
: SystemObject(config.objectId),
actionHelper(this, nullptr),
modeHelper(this),
healthHelper(this, getObjectId()),
paramHelper(this),
poolManager(this, nullptr),
defaultFdirParent(config.defaultFdirParent) {
auto mqArgs = MqArgs(config.objectId, static_cast<void*>(this));
messageQueue = QueueFactory::instance()->createMessageQueue(
config.msgQueueDepth, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
}
FreshDeviceHandlerBase::~FreshDeviceHandlerBase() {
QueueFactory::instance()->deleteMessageQueue(messageQueue);
if (not hasCustomFdir) {
delete fdirInstance;
}
}
[[nodiscard]] object_id_t FreshDeviceHandlerBase::getObjectId() const {
return SystemObject::getObjectId();
}
ReturnValue_t FreshDeviceHandlerBase::performOperation(uint8_t opCode) {
performDeviceOperationPreQueueHandling(opCode);
handleQueue();
performDeviceOperation(opCode);
poolManager.performHkOperation();
return returnvalue::OK;
}
ReturnValue_t FreshDeviceHandlerBase::performDeviceOperationPreQueueHandling(uint8_t opCode) {
return returnvalue::OK;
}
void FreshDeviceHandlerBase::startTransition(Mode_t mode_, Submode_t submode_) {
triggerEvent(CHANGING_MODE, mode_, submode_);
// Complete mode transition immediately by default.
setMode(mode_, submode_);
}
void FreshDeviceHandlerBase::setMode(Mode_t newMode, Submode_t newSubmode) {
mode = newMode;
submode = newSubmode;
modeHelper.modeChanged(mode, submode);
modeChanged(mode, submode);
announceMode(false);
}
void FreshDeviceHandlerBase::setMode(Mode_t newMode) { setMode(newMode, submode); }
void FreshDeviceHandlerBase::getMode(Mode_t* mode_, Submode_t* submode_) {
*mode_ = this->mode;
*submode_ = this->submode;
}
void FreshDeviceHandlerBase::announceMode(bool recursive) {
triggerEvent(MODE_INFO, mode, submode);
}
void FreshDeviceHandlerBase::modeChanged(Mode_t mode_, Submode_t submode_) {}
[[nodiscard]] MessageQueueId_t FreshDeviceHandlerBase::getCommandQueue() const {
return messageQueue->getId();
}
ReturnValue_t FreshDeviceHandlerBase::handleQueue() {
CommandMessage command;
ReturnValue_t result;
for (result = messageQueue->receiveMessage(&command); result == returnvalue::OK;
result = messageQueue->receiveMessage(&command)) {
result = actionHelper.handleActionMessage(&command);
if (result == returnvalue::OK) {
continue;
}
result = modeHelper.handleModeCommand(&command);
if (result == returnvalue::OK) {
continue;
}
result = healthHelper.handleHealthCommand(&command);
if (result == returnvalue::OK) {
continue;
}
result = paramHelper.handleParameterMessage(&command);
if (result == returnvalue::OK) {
continue;
}
result = poolManager.handleHousekeepingMessage(&command);
if (result == returnvalue::OK) {
continue;
}
result = handleCommandMessage(&command);
if (result == returnvalue::OK) {
continue;
}
command.setToUnknownCommand();
messageQueue->reply(&command);
}
return result;
}
HasHealthIF::HealthState FreshDeviceHandlerBase::getHealth() { return healthHelper.getHealth(); }
const HasHealthIF* FreshDeviceHandlerBase::getOptHealthIF() const { return this; }
const HasModesIF& FreshDeviceHandlerBase::getModeIF() const { return *this; }
ModeTreeChildIF& FreshDeviceHandlerBase::getModeTreeChildIF() { return *this; }
ReturnValue_t FreshDeviceHandlerBase::connectModeTreeParent(HasModeTreeChildrenIF& parent) {
return modetree::connectModeTreeParent(parent, *this, &healthHelper, modeHelper);
}
// Executable Overrides.
void FreshDeviceHandlerBase::setTaskIF(PeriodicTaskIF* task_) { executingTask = task_; }
// Pool Manager overrides.
LocalDataPoolManager* FreshDeviceHandlerBase::getHkManagerHandle() { return &poolManager; }
[[nodiscard]] uint32_t FreshDeviceHandlerBase::getPeriodicOperationFrequency() const {
return this->executingTask->getPeriodMs();
}
ReturnValue_t FreshDeviceHandlerBase::initializeAfterTaskCreation() {
return poolManager.initializeAfterTaskCreation();
}
ReturnValue_t FreshDeviceHandlerBase::setHealth(HasHealthIF::HealthState health) {
// Assembly should handle commanding to OFF.
healthHelper.setHealth(health);
return returnvalue::OK;
}
void FreshDeviceHandlerBase::triggerEvent(Event event, uint32_t parameter1, uint32_t parameter2) {
fdirInstance->triggerEvent(event, parameter1, parameter2);
}
void FreshDeviceHandlerBase::forwardEvent(Event event, uint32_t parameter1,
uint32_t parameter2) const {
fdirInstance->triggerEvent(event, parameter1, parameter2);
}
void FreshDeviceHandlerBase::setToExternalControl() { setHealth(HealthState::EXTERNAL_CONTROL); }
// System Object overrides.
ReturnValue_t FreshDeviceHandlerBase::initialize() {
ReturnValue_t result = modeHelper.initialize();
if (result != returnvalue::OK) {
return result;
}
result = healthHelper.initialize();
if (result != returnvalue::OK) {
return result;
}
result = actionHelper.initialize(messageQueue);
if (result != returnvalue::OK) {
return result;
}
result = paramHelper.initialize();
if (result != returnvalue::OK) {
return result;
}
result = poolManager.initialize(messageQueue);
if (result != returnvalue::OK) {
return result;
}
if (fdirInstance == nullptr) {
hasCustomFdir = false;
fdirInstance = new DeviceHandlerFailureIsolation(getObjectId(), defaultFdirParent);
}
result = fdirInstance->initialize();
if (result != returnvalue::OK) {
return result;
}
return SystemObject::initialize();
}
ReturnValue_t FreshDeviceHandlerBase::getParameter(uint8_t domainId, uint8_t uniqueId,
ParameterWrapper* parameterWrapper,
const ParameterWrapper* newValues,
uint16_t startAtIndex) {
ReturnValue_t result =
fdirInstance->getParameter(domainId, uniqueId, parameterWrapper, newValues, startAtIndex);
if (result != INVALID_DOMAIN_ID) {
return result;
}
return INVALID_DOMAIN_ID;
}

View File

@ -0,0 +1,167 @@
#pragma once
#include "fsfw/action.h"
#include "fsfw/datapoollocal/HasLocalDataPoolIF.h"
#include "fsfw/datapoollocal/LocalDataPoolManager.h"
#include "fsfw/devicehandlers/DeviceHandlerIF.h"
#include "fsfw/fdir/FailureIsolationBase.h"
#include "fsfw/health/HasHealthIF.h"
#include "fsfw/health/HealthHelper.h"
#include "fsfw/modes/HasModesIF.h"
#include "fsfw/objectmanager.h"
#include "fsfw/parameters/ParameterHelper.h"
#include "fsfw/parameters/ReceivesParameterMessagesIF.h"
#include "fsfw/retval.h"
#include "fsfw/subsystem/ModeTreeChildIF.h"
#include "fsfw/subsystem/ModeTreeConnectionIF.h"
#include "fsfw/tasks/ExecutableObjectIF.h"
#include "fsfw/tasks/PeriodicTaskIF.h"
struct DhbConfig {
explicit DhbConfig(object_id_t objectId) : objectId(objectId) {}
object_id_t objectId;
FailureIsolationBase* fdirInstance = nullptr;
object_id_t defaultFdirParent = objects::NO_OBJECT;
uint32_t msgQueueDepth = 10;
};
class FreshDeviceHandlerBase : public SystemObject,
public DeviceHandlerIF,
public HasModesIF,
public HasHealthIF,
public ExecutableObjectIF,
public ModeTreeChildIF,
public ModeTreeConnectionIF,
public HasActionsIF,
public ReceivesParameterMessagesIF,
public HasLocalDataPoolIF {
public:
explicit FreshDeviceHandlerBase(DhbConfig config);
~FreshDeviceHandlerBase() override;
/**
* Periodic helper executed function, implemented by child class.
*/
virtual void performDeviceOperation(uint8_t opCode) = 0;
[[nodiscard]] object_id_t getObjectId() const override;
[[nodiscard]] MessageQueueId_t getCommandQueue() const override;
HasHealthIF::HealthState getHealth() override;
// Mode Tree Overrides.
[[nodiscard]] const HasHealthIF* getOptHealthIF() const override;
[[nodiscard]] const HasModesIF& getModeIF() const override;
ReturnValue_t connectModeTreeParent(HasModeTreeChildrenIF& parent) override;
ModeTreeChildIF& getModeTreeChildIF() override;
[[nodiscard]] uint32_t getPeriodicOperationFrequency() const override;
protected:
// Pool Manager overrides.
LocalDataPoolManager* getHkManagerHandle() override;
ActionHelper actionHelper;
ModeHelper modeHelper;
HealthHelper healthHelper;
ParameterHelper paramHelper;
LocalDataPoolManager poolManager;
bool hasCustomFdir = false;
FailureIsolationBase* fdirInstance;
object_id_t defaultFdirParent;
/**
* Pointer to the task which executes this component,
* is invalid before setTaskIF was called.
*/
PeriodicTaskIF* executingTask = nullptr;
Mode_t mode = HasModesIF::MODE_UNDEFINED;
Submode_t submode = 0;
MessageQueueIF* messageQueue;
/**
* The default queue handler will process all messages for the interfaces implemented
* by this class. If there are special requirements, for example that action commands are
* received on a different queue, the user can override this function for those special
* requirements.
*/
virtual ReturnValue_t handleQueue();
// Mode Helpers.
virtual void modeChanged(Mode_t mode, Submode_t submode);
/**
* The default implementation sets the new mode immediately. If this is not applicable for
* certain modes, the user should provide a custom implementation, which performs rougly
* the same functionality of this function, when all the steps have been taken to reach the
* new mode.
*/
void startTransition(Mode_t mode, Submode_t submode) override;
virtual void setMode(Mode_t newMode, Submode_t newSubmode);
virtual void setMode(Mode_t newMode);
void getMode(Mode_t* mode, Submode_t* submode) override;
void setToExternalControl() override;
void announceMode(bool recursive) override;
// System Object overrides.
ReturnValue_t initialize() override;
/**
* Implemented by child class. Handle all command messages which are
* not health, mode, action or housekeeping messages.
* @param message
* @return
*/
virtual ReturnValue_t handleCommandMessage(CommandMessage* message) = 0;
// HK manager abstract functions.
LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override = 0;
ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
LocalDataPoolManager& poolManager) override = 0;
// Mode abstract functions
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
uint32_t* msToReachTheMode) override = 0;
// Health Overrides.
ReturnValue_t setHealth(HealthState health) override;
// Action override. Forward to user.
ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
const uint8_t* data, size_t size) override = 0;
// Executable overrides.
ReturnValue_t performOperation(uint8_t opCode) override;
ReturnValue_t initializeAfterTaskCreation() override;
/**
* This calls the FDIR instance event trigger function.
* @param event
* @param parameter1
* @param parameter2
*/
void triggerEvent(Event event, uint32_t parameter1 = 0, uint32_t parameter2 = 0) override;
/**
* This calls the FDIR instance event forward function.
* @param event
* @param parameter1
* @param parameter2
*/
void forwardEvent(Event event, uint32_t parameter1, uint32_t parameter2) const override;
/**
* This implementation handles the FDIR parameters. The user can override this to handle
* custom parameters.
* @param domainId
* @param uniqueId
* @param parameterWrapper
* @param newValues
* @param startAtIndex
* @return
*/
ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueId, ParameterWrapper* parameterWrapper,
const ParameterWrapper* newValues, uint16_t startAtIndex) override;
virtual ReturnValue_t performDeviceOperationPreQueueHandling(uint8_t opCode);
private:
// Executable Overrides.
void setTaskIF(PeriodicTaskIF* task) override;
};

View File

@ -29,11 +29,10 @@ ReturnValue_t HealthDevice::initialize() {
if (result != returnvalue::OK) {
return result;
}
if (parentQueue != 0) {
if (parentQueue != MessageQueueIF::NO_QUEUE) {
return healthHelper.initialize(parentQueue);
} else {
return healthHelper.initialize();
}
return healthHelper.initialize();
}
MessageQueueId_t HealthDevice::getCommandQueue() const { return commandQueue->getId(); }

View File

@ -29,10 +29,8 @@ class HealthDevice : public SystemObject, public ExecutableObjectIF, public HasH
protected:
HealthState lastHealth;
MessageQueueId_t parentQueue;
MessageQueueId_t parentQueue = MessageQueueIF::NO_QUEUE;
MessageQueueIF* commandQueue;
public:
HealthHelper healthHelper;
};

View File

@ -55,8 +55,9 @@ void EventManager::notifyListeners(EventMessage* message) {
if (result != returnvalue::OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << std::hex << "EventManager::notifyListeners: MSG to 0x" << std::setfill('0')
<< std::setw(8) << listener.first << " failed with result 0x" << std::setw(4)
<< result << std::setfill(' ') << std::endl;
<< std::setw(8) << listener.first << " for event 0x" << std::setw(4)
<< message->getEventId() << " failed with result 0x" << std::setw(4) << result
<< std::setfill(' ') << std::endl;
#else
sif::printError("Sending message to listener 0x%08x failed with result %04x\n",
listener.first, result);

View File

@ -10,7 +10,7 @@ enum : uint8_t {
CDH = 28,
TCS_1 = 59,
PCDU_1 = 42,
PCDU_2 = 43,
POWER_SWITCH_IF = 43,
HEATER = 50,
T_SENSORS = 52,
FDIR = 70,

View File

@ -148,25 +148,16 @@ void FailureIsolationBase::doConfirmFault(EventMessage* event) {
ReturnValue_t FailureIsolationBase::confirmFault(EventMessage* event) { return YOUR_FAULT; }
void FailureIsolationBase::triggerEvent(Event event, uint32_t parameter1, uint32_t parameter2) {
// With this mechanism, all events are disabled for a certain device.
// That's not so good for visibility.
if (isFdirDisabledForSeverity(event::getSeverity(event))) {
return;
}
// By default, we trigger all events and also call the handler function to handle FDIR reactions
// which might occur due to these events. This makes all events visible. If the handling of
// FDIR reaction should be disabled, this should be done through dedicated logic inside the
// eventReceived function.
EventMessage message(event, ownerId, parameter1, parameter2);
EventManagerIF::triggerEvent(&message, eventQueue->getId());
eventReceived(&message);
}
bool FailureIsolationBase::isFdirDisabledForSeverity(EventSeverity_t severity) {
if ((owner != NULL) && (severity != severity::INFO)) {
if (owner->getHealth() == HasHealthIF::EXTERNAL_CONTROL) {
// External control disables handling of fault messages.
return true;
}
}
return false;
}
bool FailureIsolationBase::isFdirDisabledForSeverity(EventSeverity_t severity) { return false; }
void FailureIsolationBase::throwFdirEvent(Event event, uint32_t parameter1, uint32_t parameter2) {
EventMessage message(event, ownerId, parameter1, parameter2);

View File

@ -44,13 +44,13 @@ class FailureIsolationBase : public ConfirmsFailuresIF, public HasParametersIF {
virtual void wasParentsFault(EventMessage* event);
virtual ReturnValue_t confirmFault(EventMessage* event);
virtual void decrementFaultCounters() = 0;
virtual bool isFdirDisabledForSeverity(EventSeverity_t severity);
ReturnValue_t sendConfirmationRequest(EventMessage* event,
MessageQueueId_t destination = MessageQueueIF::NO_QUEUE);
void throwFdirEvent(Event event, uint32_t parameter1 = 0, uint32_t parameter2 = 0);
private:
void doConfirmFault(EventMessage* event);
bool isFdirDisabledForSeverity(EventSeverity_t severity);
};
#endif /* FRAMEWORK_FDIR_FAILUREISOLATIONBASE_H_ */
#endif /* FRAMEWORK_FDIR */

View File

@ -17,7 +17,7 @@ struct FilesystemParams {
};
struct FileOpParams {
FileOpParams(const char* path, size_t size) : fsParams(path), size(size) {}
FileOpParams(const char* path, size_t opSize) : fsParams(path), size(opSize) {}
[[nodiscard]] const char* path() const { return fsParams.path; }
@ -80,6 +80,8 @@ class HasFileSystemIF {
virtual bool isDirectory(const char* path) = 0;
virtual bool getFileSize(FilesystemParams params, uint64_t& fileSize) = 0;
virtual bool fileExists(FilesystemParams params) = 0;
/**

View File

@ -18,8 +18,11 @@
*/
class DleParser {
public:
//! [EXPORT] : [SKIP]
static constexpr ReturnValue_t NO_PACKET_FOUND = returnvalue::makeCode(1, 1);
//! [EXPORT] : [SKIP]
static constexpr ReturnValue_t POSSIBLE_PACKET_LOSS = returnvalue::makeCode(1, 2);
using BufPair = std::pair<uint8_t*, size_t>;
enum class ContextType { NONE, PACKET_FOUND, ERROR };

View File

@ -1,9 +1,12 @@
#ifndef MATRIXOPERATIONS_H_
#define MATRIXOPERATIONS_H_
#include <fsfw/retval.h>
#include <stdint.h>
#include <cmath>
#include <cstring>
#include <utility>
template <typename T1, typename T2 = T1, typename T3 = T2>
class MatrixOperations {
@ -95,6 +98,139 @@ class MatrixOperations {
}
}
}
static bool isFinite(const T1 *inputMatrix, uint8_t rows, uint8_t cols) {
for (uint8_t col = 0; col < cols; col++) {
for (uint8_t row = 0; row < rows; row++) {
if (not std::isfinite(inputMatrix[row * cols + cols])) {
return false;
}
}
}
return true;
}
static void writeSubmatrix(T1 *mainMatrix, T1 *subMatrix, uint8_t subRows, uint8_t subCols,
uint8_t mainRows, uint8_t mainCols, uint8_t startRow,
uint8_t startCol) {
if ((startRow + subRows > mainRows) or (startCol + subCols > mainCols)) {
return;
}
for (uint8_t row = 0; row < subRows; row++) {
for (uint8_t col = 0; col < subCols; col++) {
mainMatrix[(startRow + row) * mainCols + (startCol + col)] = subMatrix[row * subCols + col];
}
}
}
static ReturnValue_t inverseMatrix(const T1 *inputMatrix, T1 *inverse, uint8_t size) {
// Stopwatch stopwatch;
T1 matrix[size][size], identity[size][size];
// reformat array to matrix
for (uint8_t row = 0; row < size; row++) {
for (uint8_t col = 0; col < size; col++) {
matrix[row][col] = inputMatrix[row * size + col];
}
}
// init identity matrix
std::memset(identity, 0.0, sizeof(identity));
for (uint8_t diag = 0; diag < size; diag++) {
identity[diag][diag] = 1;
}
// gauss-jordan algo
// sort matrix such as no diag entry shall be 0
for (uint8_t row = 0; row < size; row++) {
if (matrix[row][row] == 0.0) {
bool swaped = false;
uint8_t rowIndex = 0;
while ((rowIndex < size) && !swaped) {
if ((matrix[rowIndex][row] != 0.0) && (matrix[row][rowIndex] != 0.0)) {
for (uint8_t colIndex = 0; colIndex < size; colIndex++) {
std::swap(matrix[row][colIndex], matrix[rowIndex][colIndex]);
std::swap(identity[row][colIndex], identity[rowIndex][colIndex]);
}
swaped = true;
}
rowIndex++;
}
if (!swaped) {
return returnvalue::FAILED; // matrix not invertible
}
}
}
for (int row = 0; row < size; row++) {
if (matrix[row][row] == 0.0) {
uint8_t rowIndex;
if (row == 0) {
rowIndex = size - 1;
} else {
rowIndex = row - 1;
}
for (uint8_t colIndex = 0; colIndex < size; colIndex++) {
std::swap(matrix[row][colIndex], matrix[rowIndex][colIndex]);
std::swap(identity[row][colIndex], identity[rowIndex][colIndex]);
}
row--;
if (row < 0) {
return returnvalue::FAILED; // Matrix is not invertible
}
}
}
// remove non diag elements in matrix (jordan)
for (int row = 0; row < size; row++) {
for (int rowIndex = 0; rowIndex < size; rowIndex++) {
if (row != rowIndex) {
double ratio = matrix[rowIndex][row] / matrix[row][row];
for (int colIndex = 0; colIndex < size; colIndex++) {
matrix[rowIndex][colIndex] -= ratio * matrix[row][colIndex];
identity[rowIndex][colIndex] -= ratio * identity[row][colIndex];
}
}
}
}
// normalize rows in matrix (gauss)
for (int row = 0; row < size; row++) {
for (int col = 0; col < size; col++) {
identity[row][col] = identity[row][col] / matrix[row][row];
}
}
std::memcpy(inverse, identity, sizeof(identity));
return returnvalue::OK; // successful inversion
}
static void inverseMatrixDimThree(const T1 *matrix, T1 *output) {
int i, j;
double determinant = 0;
double mat[3][3] = {{matrix[0], matrix[1], matrix[2]},
{matrix[3], matrix[4], matrix[5]},
{matrix[6], matrix[7], matrix[8]}};
for (i = 0; i < 3; i++) {
determinant = determinant + (mat[0][i] * (mat[1][(i + 1) % 3] * mat[2][(i + 2) % 3] -
mat[1][(i + 2) % 3] * mat[2][(i + 1) % 3]));
}
for (i = 0; i < 3; i++) {
for (j = 0; j < 3; j++) {
output[i * 3 + j] = ((mat[(j + 1) % 3][(i + 1) % 3] * mat[(j + 2) % 3][(i + 2) % 3]) -
(mat[(j + 1) % 3][(i + 2) % 3] * mat[(j + 2) % 3][(i + 1) % 3])) /
determinant;
}
}
}
static void skewMatrix(const T1 *vector, T2 *result) {
// Input Dimension [3], Output [3][3]
result[0] = 0;
result[1] = -vector[2];
result[2] = vector[1];
result[3] = vector[2];
result[4] = 0;
result[5] = -vector[0];
result[6] = -vector[1];
result[7] = vector[0];
result[8] = 0;
}
};
#endif /* MATRIXOPERATIONS_H_ */

View File

@ -39,6 +39,48 @@ void QuaternionOperations::inverse(const double* quaternion, double* inverseQuat
VectorOperations<double>::mulScalar(inverseQuaternion, -1, inverseQuaternion, 3);
}
void QuaternionOperations::slerp(const double q1[4], const double q2[4], const double weight,
double q[4]) {
double q1s[4] = {0, 0, 0, 0}, q2I[4] = {0, 0, 0, 0}, qD[4] = {0, 0, 0, 0}, left[4] = {0, 0, 0, 0},
right[4] = {0, 0, 0, 0}, angle = 0;
// we need to be able to invert this quaternion
std::memcpy(q1s, q1, 4 * sizeof(double));
// calculate angle between orientations
inverse(q2, q2I);
multiply(q1s, q2I, qD);
angle = std::acos(qD[3]);
if (std::cos(angle) < 0.0) {
// we need to invert one quaternion
VectorOperations<double>::mulScalar(q1s, -1, q1s, 4);
multiply(q1s, q2I, qD);
angle = std::acos(qD[3]);
}
if (std::sin(angle) == 0.0) {
// nothing to calculate here
std::memcpy(q, q1s, 4 * sizeof(double));
return;
}
VectorOperations<double>::mulScalar(q1s, std::sin((1 - weight) * angle) / std::sin(angle), left,
4);
VectorOperations<double>::mulScalar(q2, std::sin(weight * angle) / std::sin(angle), right, 4);
VectorOperations<double>::add(left, right, q, 4);
normalize(q);
}
void QuaternionOperations::preventSignJump(double qNew[4], const double qOld[4]) {
double qDiff[4] = {0, 0, 0, 0}, qSum[4] = {0, 0, 0, 0};
VectorOperations<double>::subtract(qOld, qNew, qDiff, 4);
VectorOperations<double>::add(qOld, qNew, qSum, 4);
if (VectorOperations<double>::norm(qDiff, 4) > VectorOperations<double>::norm(qSum, 4)) {
VectorOperations<double>::mulScalar(qNew, -1, qNew, 4);
}
}
QuaternionOperations::QuaternionOperations() {}
void QuaternionOperations::normalize(const double* quaternion, double* unitQuaternion) {
@ -120,3 +162,25 @@ double QuaternionOperations::getAngle(const double* quaternion, bool abs) {
}
}
}
void QuaternionOperations::rotationFromQuaternions(const double qNew[4], const double qOld[4],
const double timeDelta, double rotRate[3]) {
double qOldInv[4] = {0, 0, 0, 0};
double qDelta[4] = {0, 0, 0, 0};
inverse(qOld, qOldInv);
multiply(qNew, qOldInv, qDelta);
if (VectorOperations<double>::norm(qDelta, 4) != 0.0) {
normalize(qDelta);
}
if (VectorOperations<double>::norm(qDelta, 3) == 0.0) {
rotRate[0] = 0.0;
rotRate[1] = 0.0;
rotRate[2] = 0.0;
return;
}
double rotVec[3] = {0, 0, 0};
double angle = getAngle(qDelta);
VectorOperations<double>::normalize(qDelta, rotVec, 3);
VectorOperations<double>::mulScalar(rotVec, angle / timeDelta, rotRate, 3);
}

View File

@ -23,6 +23,13 @@ class QuaternionOperations {
static void inverse(const double *quaternion, double *inverseQuaternion);
static void slerp(const double q1[4], const double q2[4], const double weight, double q[4]);
static void rotationFromQuaternions(const double qNew[4], const double qOld[4],
const double timeDelta, double rotRate[3]);
static void preventSignJump(double qNew[4], const double qOld[4]);
/**
* returns angle in ]-Pi;Pi] or [0;Pi] if abs == true
*/

View File

@ -53,8 +53,9 @@ class VectorOperations {
mulScalar(vector, 1 / norm(vector, size), normalizedVector, size);
}
static T maxAbsValue(const T *vector, uint8_t size, uint8_t *index = 0) {
T max = -1;
static T maxAbsValue(const T *vector, uint8_t size, uint8_t *index = nullptr) {
T max = vector[size - 1];
uint8_t foundIndex = size - 1;
for (; size > 0; size--) {
T abs = vector[size - 1];
@ -64,29 +65,49 @@ class VectorOperations {
if (abs > max) {
max = abs;
if (index != 0) {
*index = size - 1;
foundIndex = size - 1;
}
}
}
if (index != nullptr) {
*index = foundIndex;
}
return max;
}
static T maxValue(const T *vector, uint8_t size, uint8_t *index = 0) {
T max = -1;
static T maxValue(const T *vector, uint8_t size, uint8_t *index = nullptr) {
T max = vector[size - 1];
uint8_t foundIndex = size - 1;
for (; size > 0; size--) {
if (vector[size - 1] > max) {
max = vector[size - 1];
if (index != 0) {
*index = size - 1;
foundIndex = size - 1;
}
}
}
if (index != nullptr) {
*index = foundIndex;
}
return max;
}
static void copy(const T *in, T *out, uint8_t size) { mulScalar(in, 1, out, size); }
static bool isFinite(const T *inputVector, uint8_t size) {
for (uint8_t i = 0; i < size; i++) {
if (not std::isfinite(inputVector[i])) {
return false;
}
}
return true;
}
private:
VectorOperations();
};

View File

@ -3,85 +3,37 @@
#include <cmath>
#include "fsfw/datapoollocal/LocalPoolDataSetBase.h"
#include "fsfw/serviceinterface.h"
PeriodicHousekeepingHelper::PeriodicHousekeepingHelper(LocalPoolDataSetBase* owner)
: owner(owner) {}
void PeriodicHousekeepingHelper::initialize(float collectionInterval,
dur_millis_t minimumPeriodicInterval,
uint8_t nonDiagIntervalFactor) {
dur_millis_t minimumPeriodicInterval) {
this->minimumPeriodicInterval = minimumPeriodicInterval;
this->nonDiagIntervalFactor = nonDiagIntervalFactor;
collectionIntervalTicks = intervalSecondsToIntervalTicks(collectionInterval);
/* This will cause a checkOpNecessary call to be true immediately. I think it's okay
if a HK packet is generated immediately instead of waiting one generation cycle. */
internalTickCounter = collectionIntervalTicks;
changeCollectionInterval(collectionInterval);
}
float PeriodicHousekeepingHelper::getCollectionIntervalInSeconds() const {
return intervalTicksToSeconds(collectionIntervalTicks);
return collectionInterval;
}
bool PeriodicHousekeepingHelper::checkOpNecessary() {
if (internalTickCounter >= collectionIntervalTicks) {
internalTickCounter = 1;
if (hkGenerationCd.hasTimedOut()) {
hkGenerationCd.resetTimer();
return true;
}
internalTickCounter++;
return false;
}
uint32_t PeriodicHousekeepingHelper::intervalSecondsToIntervalTicks(
float collectionIntervalSeconds) {
if (owner == nullptr) {
return 0;
}
bool isDiagnostics = owner->isDiagnostics();
/* Avoid division by zero */
if (minimumPeriodicInterval == 0) {
if (isDiagnostics) {
/* Perform operation each cycle */
return 1;
} else {
return nonDiagIntervalFactor;
}
} else {
dur_millis_t intervalInMs = collectionIntervalSeconds * 1000;
uint32_t divisor = minimumPeriodicInterval;
if (not isDiagnostics) {
/* We need to multiply the divisor because non-diagnostics only
allow a multiple of the minimum periodic interval */
divisor *= nonDiagIntervalFactor;
}
uint32_t ticks = std::ceil(static_cast<float>(intervalInMs) / divisor);
if (not isDiagnostics) {
/* Now we need to multiply the calculated ticks with the factor as as well
because the minimum tick count to generate a non-diagnostic is the factor itself.
Example calculation for non-diagnostic with
0.4 second interval and 0.2 second task interval.
Resultant tick count of 5 is equal to operation each second.
Examle calculation for non-diagnostic with 2.0 second interval and 0.2 second
task interval.
Resultant tick count of 10 is equal to operatin every 2 seconds.
Example calculation for diagnostic with 0.4 second interval and 0.3
second task interval. Resulting tick count of 2 is equal to operation
every 0.6 seconds. */
ticks *= nonDiagIntervalFactor;
}
return ticks;
}
}
float PeriodicHousekeepingHelper::intervalTicksToSeconds(uint32_t collectionInterval) const {
/* Number of ticks times the minimum interval is in milliseconds, so we divide by 1000 to get
the value in seconds */
return static_cast<float>(collectionInterval * minimumPeriodicInterval / 1000.0);
}
void PeriodicHousekeepingHelper::changeCollectionInterval(float newIntervalSeconds) {
collectionIntervalTicks = intervalSecondsToIntervalTicks(newIntervalSeconds);
uint32_t intervalMs = newIntervalSeconds * 1000;
if (newIntervalSeconds <= 0) {
intervalMs = minimumPeriodicInterval;
newIntervalSeconds = static_cast<float>(minimumPeriodicInterval) / 1000.0;
}
collectionInterval = newIntervalSeconds;
hkGenerationCd.setTimeout(intervalMs);
// We want an immediate HK packet at the start, so time out the generation CD immediately.
hkGenerationCd.timeOut();
}

View File

@ -4,6 +4,7 @@
#include <cstdint>
#include "fsfw/timemanager/Clock.h"
#include "fsfw/timemanager/Countdown.h"
class LocalPoolDataSetBase;
@ -11,8 +12,7 @@ class PeriodicHousekeepingHelper {
public:
PeriodicHousekeepingHelper(LocalPoolDataSetBase* owner);
void initialize(float collectionInterval, dur_millis_t minimumPeriodicInterval,
uint8_t nonDiagIntervalFactor);
void initialize(float collectionInterval, dur_millis_t minimumPeriodicInterval);
void changeCollectionInterval(float newInterval);
float getCollectionIntervalInSeconds() const;
@ -20,14 +20,10 @@ class PeriodicHousekeepingHelper {
private:
LocalPoolDataSetBase* owner = nullptr;
uint8_t nonDiagIntervalFactor = 0;
uint32_t intervalSecondsToIntervalTicks(float collectionIntervalSeconds);
float intervalTicksToSeconds(uint32_t collectionInterval) const;
Countdown hkGenerationCd;
float collectionInterval = 0.0;
dur_millis_t minimumPeriodicInterval = 0;
uint32_t internalTickCounter = 1;
uint32_t collectionIntervalTicks = 0;
};
#endif /* FSFW_HOUSEKEEPING_PERIODICHOUSEKEEPINGHELPER_H_ */

View File

@ -5,9 +5,12 @@
#include "fsfw/ipc/QueueFactory.h"
#include "fsfw/serviceinterface/ServiceInterface.h"
InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId, uint32_t messageQueueDepth)
InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId, uint32_t messageQueueDepth,
bool enableSetByDefault, float generationFrequency)
: SystemObject(setObjectId),
poolManager(this, commandQueue),
enableSetByDefault(enableSetByDefault),
generationFrequency(generationFrequency),
internalErrorSid(setObjectId, InternalErrorDataset::ERROR_SET_ID),
internalErrorDataset(this) {
commandQueue = QueueFactory::instance()->createMessageQueue(messageQueueDepth);
@ -134,9 +137,8 @@ ReturnValue_t InternalErrorReporter::initializeLocalDataPool(localpool::DataPool
localDataPoolMap.emplace(errorPoolIds::TM_HITS, &tmHitsEntry);
localDataPoolMap.emplace(errorPoolIds::QUEUE_HITS, &queueHitsEntry);
localDataPoolMap.emplace(errorPoolIds::STORE_HITS, &storeHitsEntry);
poolManager.subscribeForDiagPeriodicPacket(subdp::DiagnosticsHkPeriodicParams(
internalErrorSid, false,
static_cast<float>(getPeriodicOperationFrequency()) / static_cast<float>(1000.0)));
poolManager.subscribeForRegularPeriodicPacket(
subdp::RegularHkPeriodicParams(internalErrorSid, enableSetByDefault, generationFrequency));
internalErrorDataset.setValidity(true, true);
return returnvalue::OK;
}

View File

@ -21,7 +21,8 @@ class InternalErrorReporter : public SystemObject,
public InternalErrorReporterIF,
public HasLocalDataPoolIF {
public:
InternalErrorReporter(object_id_t setObjectId, uint32_t messageQueueDepth = 5);
InternalErrorReporter(object_id_t setObjectId, uint32_t messageQueueDepth,
bool enableSetByDefault, float generationFrequency);
/**
* Enable diagnostic printout. Please note that this feature will
@ -63,6 +64,8 @@ class InternalErrorReporter : public SystemObject,
MutexIF* mutex = nullptr;
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING;
uint32_t timeoutMs = 20;
bool enableSetByDefault;
float generationFrequency;
sid_t internalErrorSid;
InternalErrorDataset internalErrorDataset;

View File

@ -116,8 +116,8 @@ void ObjectManager::initialize() {
<< std::dec << std::setfill(' ') << std::endl;
#else
sif::printError(
"ObjectManager::initialize: Object 0x%08x failed to initialize with code 0x%04x\n", var,
it.first);
"ObjectManager::initialize: Object 0x%08x failed to initialize with code 0x%04x\n",
it.first, result);
#endif
#endif
errorCount++;

View File

@ -21,7 +21,7 @@ TcpTmTcBridge::TcpTmTcBridge(object_id_t objectId, object_id_t tcDestination,
: TmTcBridge("TCP TMTC Bridge", objectId, tcDestination, msgQueueDepth, tmStoreId, tcStoreId) {
mutex = MutexFactory::instance()->createMutex();
// Connection is always up, TM is requested by connecting to server and receiving packets
registerCommConnect();
TmTcBridge::registerCommConnect();
}
ReturnValue_t TcpTmTcBridge::initialize() {

Some files were not shown because too many files have changed in this diff Show More