Compare commits

...

171 Commits

Author SHA1 Message Date
3b0ee7ca31 i forgot to push.. 2024-04-17 10:07:09 +02:00
f307a86d9a improve linux interface 2024-04-11 13:11:51 +02:00
8b21dd276d Merge pull request 'implement relative timeshift' () from time-service-relative-timeshift into develop
Reviewed-on: 
Reviewed-by: Marius Eggert <eggertm@irs.uni-stuttgart.de>
2024-04-09 13:31:13 +02:00
e00da212cd Merge branch 'develop' into time-service-relative-timeshift 2024-04-09 11:11:59 +02:00
a229748aa4 distinct clock dump events 2024-04-09 10:57:00 +02:00
e6e3753324 Merge pull request 're-work some FDIR logic' () from improve-dev-fdir into develop
Reviewed-on: 
2024-04-09 10:47:32 +02:00
94bd1ba2ab fix comment blocks 2024-04-08 13:38:14 +02:00
e12a8cfa29 make this change downwards compatible 2024-04-08 13:31:21 +02:00
efbcddc2e5 improvements for time service 2024-04-08 13:26:55 +02:00
31d4b85523 some optimizations 2024-04-08 13:14:20 +02:00
aff6bb673b make marius the happies man alive 2024-04-08 10:34:28 +02:00
f8e3777c43 more fixes 2024-04-03 16:23:21 +02:00
0e2fa8dc83 lets not forget error handling 2024-04-03 16:19:40 +02:00
0cfe559b93 implement relative timeshift 2024-04-03 16:15:07 +02:00
c5159fb645 optimize docs 2024-04-03 12:52:32 +02:00
203c0bac5c re-work some FDIR logic 2024-04-03 12:47:11 +02:00
43ea29cb84 Merge pull request 'Function to prevent Quaternion Sign Jump' () from quat-no-sign-jump into develop
Reviewed-on: 
Reviewed-by: Robin Müller <muellerr@irs.uni-stuttgart.de>
2024-03-18 10:59:19 +01:00
27c8a97d45 added function to prevent quaternion sign jump 2024-03-13 16:59:14 +01:00
47b21caf5f Merge pull request 'Removed duplicate Code' () from cleanup into develop
Reviewed-on: 
Reviewed-by: Robin Müller <muellerr@irs.uni-stuttgart.de>
2024-03-06 10:54:12 +01:00
2673070204 actually do something with this rtval 2024-03-06 09:41:02 +01:00
518a07d05b removed duplicate code 2024-03-05 14:29:47 +01:00
516357d855 Merge pull request 'Expand Globalfunctions' () from expand-globalfunctions into develop
Reviewed-on: 
Reviewed-by: Robin Müller <muellerr@irs.uni-stuttgart.de>
2024-02-27 12:50:28 +01:00
ac28b7e00d Merge branch 'develop' into expand-globalfunctions 2024-02-26 13:57:04 +01:00
0d4a862c1a Merge pull request 'Increase configurability of PusServiceBase' () from psb-update into develop
Reviewed-on: 
Reviewed-by: Marius Eggert <eggertm@irs.uni-stuttgart.de>
2024-02-26 13:56:46 +01:00
b2576d3422 why are we ignoring usec 2024-02-23 11:33:20 +01:00
bccaf4a9ea capital 2024-02-23 11:31:11 +01:00
7d4e77843b frmt 2024-02-23 11:09:59 +01:00
cd2cd61ba5 Increase configurability of PusServiceBase 2024-02-13 15:57:43 +01:00
90f3f8ef1f removed printout 2024-02-12 14:51:54 +01:00
9894935e99 time systems 2024-02-12 14:42:58 +01:00
a3a6c0720c fixes 2024-02-12 14:36:14 +01:00
d5a52eadbb i should have done this ages ago 2024-02-12 14:20:04 +01:00
b5e7179af1 Merge pull request 'Rotation from Quaternions' () from rotation-from-quaternions into develop
Reviewed-on: 
Reviewed-by: Robin Müller <muellerr@irs.uni-stuttgart.de>
2024-01-29 14:11:08 +01:00
5879eb7f7b rotation from quaternions 2024-01-26 11:06:05 +01:00
e64e8b274d Merge pull request 'check whether map is full on insert' () from insert-full-check into develop
Reviewed-on: 
Reviewed-by: Marius Eggert <eggertm@irs.uni-stuttgart.de>
2023-12-12 17:53:14 +01:00
48bcce65b1 check whether map is full on insert 2023-12-12 11:24:35 +01:00
7105e199c6 Merge pull request 'SLERP for antiparallel Quaternions' () from slerp-fix-antiparallel-quaternions into develop
Reviewed-on: 
Reviewed-by: Robin Müller <muellerr@irs.uni-stuttgart.de>
2023-12-06 10:41:02 +01:00
94de483836 small fix 2023-12-06 09:26:22 +01:00
c648229c99 Merge pull request 'SLERP' () from slerp into develop
Reviewed-on: 
Reviewed-by: Robin Müller <muellerr@irs.uni-stuttgart.de>
2023-12-05 09:25:48 +01:00
5b661551a8 fixes 2023-12-04 17:52:24 +01:00
3978524181 Merge branch 'develop' into slerp 2023-11-29 15:19:09 +01:00
7187f2b5cd Merge pull request 'TLE turns too old after just 7 Days' () from tle-too-old into develop
Reviewed-on: 
2023-11-29 15:17:39 +01:00
8e367abb47 Merge branch 'develop' into tle-too-old 2023-11-29 15:17:19 +01:00
b28174db24 Merge pull request 'Fresh DHB pre-queue check hook' () from fresh-dhb-pre-queue-hook into develop
Reviewed-on: 
Reviewed-by: Marius Eggert <eggertm@irs.uni-stuttgart.de>
2023-11-29 14:18:23 +01:00
c906acd659 tle turns too old after just 7 days 2023-11-29 09:48:11 +01:00
8dfc84c0b5 smoll fix 2023-11-27 10:52:47 +01:00
74775bb59d slerp 2023-11-27 10:38:25 +01:00
c02d9e009e docs improvements and fix 2023-11-21 17:40:06 +01:00
0021aa29f5 pre-queue hook 2023-11-21 17:37:02 +01:00
41d67bff63 Merge pull request 'New simpler DHB' () from new-dhb into develop
Reviewed-on: 
Reviewed-by: Ulrich Mohr <mohr@irs.uni-stuttgart.de>
2023-11-16 11:02:44 +01:00
8d7bb51d44 add missing call to perform HK op 2023-11-15 11:39:04 +01:00
7673d8b396 add paramHelper 2023-11-15 10:03:56 +01:00
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
698897bfc5 default args 2023-11-14 11:48:17 +01:00
d554062b86 trigger event default arguments 2023-11-13 15:32:42 +01:00
bf7fac071c add mode setters 2023-11-09 17:18:33 +01:00
35be7da353 some more docs 2023-11-09 11:28:59 +01:00
18cc870c8e add FDIR handling 2023-11-09 11:04:45 +01:00
133ca51d18 visibility changes 2023-11-09 10:45:21 +01:00
0a40391a75 thats the baseline 2023-11-09 10:36:45 +01:00
cc3e64e70d Merge pull request 'CFDP SOURCE handler' () from cfdp-source-handler into develop
Reviewed-on: 
Reviewed-by: Marius Eggert <eggertm@irs.uni-stuttgart.de>
2023-10-19 10:59:53 +02:00
6021257a87 unittest fix 2023-10-19 10:21:18 +02:00
63c238005e Merge remote-tracking branch 'origin/develop' into cfdp-source-handler 2023-10-11 12:57:14 +02:00
0f604b35c6 improved readability 2023-10-09 09:26:56 +02:00
e3a815444e checkModeCommand to protected 2023-09-29 15:26:43 +02:00
19093866ee rtval for non op soc 2023-09-29 14:27:54 +02:00
497f947237 add missing 0 termination 2023-09-14 15:04:54 +02:00
5bd020193b initialize result 2023-09-11 15:38:46 +02:00
420c0625a5 result was not stored properly 2023-09-11 15:38:06 +02:00
42a0b15303 hardcore bug 2023-09-06 20:49:53 +02:00
c199cbedaa some improvements, remove debugging stuff 2023-09-06 13:40:18 +02:00
c4e18cc2f3 what was i thinking here? 2023-09-06 11:45:02 +02:00
c143198494 debugging 2023-09-06 10:11:09 +02:00
448fbd0d38 this should be less confusing, saner defaults 2023-09-05 16:04:48 +02:00
470f589bde need to rework this fsm.. but works now 2023-09-04 11:01:55 +02:00
dfcfb035be fix some retval duplications 2023-08-31 15:09:22 +02:00
6e53582dc9 split up CFDP retval domains 2023-08-31 14:59:09 +02:00
fb1500e041 continue 2023-08-30 11:34:38 +02:00
ea2e58249d API improvements 2023-08-30 11:18:49 +02:00
9ef63825f3 optimization 2023-08-16 13:15:34 +02:00
073cb4b3d5 adaptions for reserved message handling 2023-08-16 13:10:21 +02:00
8c11685240 introduce handling for full target queue 2023-08-14 21:19:35 +02:00
cb1aaea6cd add more checks 2023-08-14 21:04:22 +02:00
22df8f6147 fix the tests 2023-08-14 21:01:29 +02:00
60dcacf432 further tweaks for both CFDP handlers 2023-08-14 20:47:27 +02:00
b39e1c7e07 Merge remote-tracking branch 'origin/develop' into cfdp-source-handler 2023-08-14 15:59:13 +02:00
036667a969 type improvements 2023-08-14 15:58:01 +02:00
67c38f327e rename source file 2023-08-14 13:54:11 +02:00
e1816ed230 that should be all indications 2023-08-14 13:45:13 +02:00
5ff464252f added some user checks 2023-08-14 13:40:25 +02:00
cd8d64830c more checks 2023-08-14 13:33:47 +02:00
b7056a7467 additional checks 2023-08-14 13:24:22 +02:00
0fc2c7b5e9 oops 2023-08-14 13:19:48 +02:00
eae7c44874 reset error count 2023-08-14 13:19:32 +02:00
e4aae75747 more checks 2023-08-14 12:19:55 +02:00
b094ba145f multi file segment works 2023-08-14 12:15:35 +02:00
15629abf19 the joys of UB or whatever that crap was 2023-08-14 12:13:29 +02:00
7aeb25e064 unittest for transfer with 2 segments 2023-08-14 11:26:57 +02:00
7c875f1067 unittest for small file transfer done 2023-08-04 15:17:53 +02:00
e8451cac31 add one test condition 2023-08-04 14:21:36 +02:00
8ddd6eb18d some improvements for test 2023-08-03 17:44:30 +02:00
6c6b552059 start small file transfer test 2023-08-03 17:43:03 +02:00
9a1437980f add empty stubs 2023-08-03 15:50:27 +02:00
12e52a92f2 empty file transfer test done 2023-08-03 15:49:23 +02:00
dffce43e6b metadata PDU seems to be correct 2023-08-03 15:30:38 +02:00
daf75547a4 insidious bug 2023-08-03 15:13:26 +02:00
0cccf26021 should not be problematic but somehow is.. 2023-08-03 14:34:21 +02:00
c075f27e20 start verifying metadata PDU 2023-08-03 13:57:55 +02:00
3167988951 continue source handler 2023-08-03 13:03:58 +02:00
a856f91c67 nice 2023-07-27 17:15:01 +02:00
f49e607881 finally it works 2023-07-27 15:07:14 +02:00
0f208ec75a seems to work well 2023-07-27 14:55:46 +02:00
5679b139ad reserved message unittest working 2023-07-26 18:20:32 +02:00
947f2b8685 add some additional API 2023-07-26 17:47:27 +02:00
291c75c01f test put request 2023-07-26 17:29:35 +02:00
fde277cd06 start adding dedicated put request handler 2023-07-26 17:17:51 +02:00
bb186fc965 more bugfixes 2023-07-26 16:58:58 +02:00
e8bf8b9575 looking good 2023-07-26 16:36:21 +02:00
8f5a8b13d3 parsing finally works 2023-07-26 16:25:42 +02:00
314cba363f contnue msg parser unittest 2023-07-25 16:16:35 +02:00
244e2d0737 start adding message parser unittests 2023-07-25 13:58:22 +02:00
8f0974d83e finished reserved msg creator function 2023-07-24 18:07:20 +02:00
8581f9a6f3 start implementing reserved message creator 2023-07-24 18:01:25 +02:00
844c90a625 constructor fix 2023-07-24 16:42:13 +02:00
437851db3e naming 2023-07-24 16:40:44 +02:00
e8b9897ee3 even better name 2023-07-24 16:40:25 +02:00
33df8e8cc5 this parser should do the job 2023-07-24 16:38:11 +02:00
52fc0958f7 iniitalize field 2023-07-24 11:58:06 +02:00
66704dc571 getting tricky again.. 2023-07-24 11:57:33 +02:00
0943863ec6 need to think about that parser again.. 2023-07-24 11:35:26 +02:00
2585028e75 put request serializable now 2023-07-24 11:33:37 +02:00
7bf7336d4a almost done 2023-07-24 11:15:50 +02:00
b0b6c68720 we already have CFDP messages 2023-07-24 11:05:11 +02:00
a1f36a0dd8 put request 2023-07-24 10:58:18 +02:00
e4665c9394 continue with the msg to user / put request architecture 2023-07-24 10:52:38 +02:00
98cbf38432 this is going to be complex.. 2023-07-24 10:11:16 +02:00
5d3f00da7f that should do the job 2023-07-24 10:06:45 +02:00
69fd6d0f6a lets see how we can do this 2023-07-21 16:35:05 +02:00
045054fce0 start implementing metadata parser 2023-07-21 16:12:17 +02:00
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
e00e198ff1 this seems to work 2023-07-21 16:09:52 +02:00
9c8434d856 LOOKING GOOOD 2023-07-19 23:43:40 +02:00
42c215ef70 some additional notes 2023-07-19 23:24:43 +02:00
273fd3ebfd added sequence count provider abstraction 2023-07-19 23:22:55 +02:00
6c9c4ee047 add EOF impl 2023-07-19 14:06:15 +02:00
1bfb695b41 some minor tweaks 2023-07-19 14:02:03 +02:00
1561b9a247 implemented fle data PDUs 2023-07-19 13:44:52 +02:00
896b7a7358 start FD PDU handling 2023-07-19 00:12:14 +02:00
8e62143ac8 continue impl 2023-07-18 09:38:46 +02:00
1d97327f79 start implementing metadata PDU generation 2023-07-17 18:56:10 +02:00
5e9d402598 getFileSize API for fsfw 2023-07-17 16:40:44 +02:00
b53c48863f start introducing FSM result 2023-07-17 15:21:22 +02:00
4dc6398fd5 continue source FSM 2023-07-17 15:11:51 +02:00
8fcc4eab60 some internal state handling 2023-07-17 15:03:08 +02:00
972dc7e19e continue source handler 2023-07-17 14:54:45 +02:00
06ef498a18 start implementing put request function 2023-07-17 14:48:37 +02:00
6322a31566 some fixes 2023-07-17 13:43:48 +02:00
95b77ed826 put request support baseline 2023-07-17 13:28:32 +02:00
3b1da85229 start setting up source handler 2023-07-17 11:37:20 +02:00
1cbcfc08ff reorder includes 2023-07-17 10:46:12 +02:00
ca27cef2ee Merge branch 'small-hk-tweak' into cfdp-source-handler 2023-07-17 10:37:03 +02:00
f44110a7f5 share the FSFW Param block 2023-07-17 10:25:09 +02:00
35712070cf source handler 2023-07-17 10:15:06 +02:00
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
a6cc5171da continue source handler 2023-07-17 09:53:23 +02:00
9994c46e47 Merge branch 'develop' into cfdp-source-handler 2023-07-14 16:01:51 +02:00
cf927ecee7 added bare structure of FSM 2023-07-14 15:56:38 +02:00
1b23aa4246 bugfixes and improvements for dest handler 2023-06-30 12:01:18 +02:00
7d713219c5 continue source handler 2023-06-30 11:59:22 +02:00
1be09a2310 the C++ tooling is shit 2023-06-30 11:48:25 +02:00
7add782470 start CFDP source handler 2023-06-30 11:36:19 +02:00
131 changed files with 3147 additions and 741 deletions
.gitignore
.idea
CHANGELOG.md
src
fsfw
CMakeLists.txt
cfdp
controller
coordinates
devicehandlers
fdir
filesystem
globalfunctions
objectmanager
osal
power
pus
returnvalues
serialize
storagemanager
tmtcservices
util
fsfw_hal
unittests

2
.gitignore vendored

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

2
.idea/cmake.xml generated

@ -2,7 +2,7 @@
<project version="4"> <project version="4">
<component name="CMakeSharedSettings"> <component name="CMakeSharedSettings">
<configurations> <configurations>
<configuration PROFILE_NAME="Debug Test" ENABLED="true" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DFSFW_BUILD_TESTS=ON -DFSFW_OSAL=host" /> <configuration PROFILE_NAME="Debug Test" ENABLED="true" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DFSFW_OSAL=host -DFSFW_BUILD_TESTS=ON" NO_GENERATOR="true" />
</configurations> </configurations>
</component> </component>
</project> </project>

@ -28,9 +28,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- add CFDP subsystem ID - add CFDP subsystem ID
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/742 https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/742
- `PusTmZcWriter` now exposes API to set message counter field. - `PusTmZcWriter` now exposes API to set message counter field.
- Relative timeshift in the PUS time service.
## Changed ## 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. - HK generation is now countdown based.
- Bump ETL version to 20.35.14 - Bump ETL version to 20.35.14
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/748 https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/748
@ -41,6 +44,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Assert that `FixedArrayList` is larger than 0 at compile time. - Assert that `FixedArrayList` is larger than 0 at compile time.
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/740 https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/740
- Health functions are virtual now. - 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 # [v6.0.0] 2023-02-10

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

@ -4,8 +4,9 @@ CfdpMessage::CfdpMessage() = default;
CfdpMessage::~CfdpMessage() = default; CfdpMessage::~CfdpMessage() = default;
void CfdpMessage::setCommand(CommandMessage *message, store_address_t cfdpPacket) { void CfdpMessage::setPutRequest(CommandMessage *message, store_address_t putRequest) {
message->setParameter(cfdpPacket.raw); message->setCommand(PUT_REQUEST);
message->setParameter(putRequest.raw);
} }
store_address_t CfdpMessage::getStoreId(const CommandMessage *message) { store_address_t CfdpMessage::getStoreId(const CommandMessage *message) {

@ -11,9 +11,11 @@ class CfdpMessage {
public: public:
static const uint8_t MESSAGE_ID = messagetypes::CFDP; 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(); 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); static store_address_t getStoreId(const CommandMessage* message);

@ -8,11 +8,14 @@
namespace cfdp { namespace cfdp {
struct FileSize : public SerializeIF { /**
* Helper type for the CFDP File Size Sensitive (FSS) fields.
*/
struct Fss : public SerializeIF {
public: 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; } [[nodiscard]] uint64_t value() const { return fileSize; }

@ -3,8 +3,8 @@
#include "fsfw/serialize/SerializeAdapter.h" #include "fsfw/serialize/SerializeAdapter.h"
#include "fsfw/serviceinterface.h" #include "fsfw/serviceinterface.h"
cfdp::VarLenField::VarLenField(cfdp::WidthInBytes width, size_t value) : VarLenField() { cfdp::VarLenField::VarLenField(cfdp::WidthInBytes width, uint64_t value) : VarLenField() {
ReturnValue_t result = this->setValue(width, value); ReturnValue_t result = this->setValueAndWidth(width, value);
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
#if FSFW_DISABLE_PRINTOUT == 0 #if FSFW_DISABLE_PRINTOUT == 0
#if FSFW_CPP_OSTREAM_ENABLED == 1 #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; } cfdp::WidthInBytes cfdp::VarLenField::getWidth() const { return width; }
ReturnValue_t cfdp::VarLenField::setValue(cfdp::WidthInBytes widthInBytes, size_t value_) { ReturnValue_t cfdp::VarLenField::setValueAndWidth(cfdp::WidthInBytes width_, uint64_t value_) {
switch (widthInBytes) { switch (width_) {
case (cfdp::WidthInBytes::ONE_BYTE): { case (cfdp::WidthInBytes::ONE_BYTE): {
if (value_ > UINT8_MAX) { if (value_ > UINT8_MAX) {
return returnvalue::FAILED; return returnvalue::FAILED;
@ -43,15 +43,18 @@ ReturnValue_t cfdp::VarLenField::setValue(cfdp::WidthInBytes widthInBytes, size_
this->value.fourBytes = value_; this->value.fourBytes = value_;
break; break;
} }
case (cfdp::WidthInBytes::EIGHT_BYTES): {
this->value.eightBytes = value_;
}
default: { default: {
break; break;
} }
} }
this->width = widthInBytes; this->width = width_;
return returnvalue::OK; return returnvalue::OK;
} }
size_t cfdp::VarLenField::getValue() const { uint64_t cfdp::VarLenField::getValue() const {
switch (width) { switch (width) {
case (cfdp::WidthInBytes::ONE_BYTE): { case (cfdp::WidthInBytes::ONE_BYTE): {
return value.oneByte; return value.oneByte;
@ -62,6 +65,9 @@ size_t cfdp::VarLenField::getValue() const {
case (cfdp::WidthInBytes::FOUR_BYTES): { case (cfdp::WidthInBytes::FOUR_BYTES): {
return value.fourBytes; return value.fourBytes;
} }
case (cfdp::WidthInBytes::EIGHT_BYTES): {
return value.eightBytes;
}
} }
return 0; return 0;
} }
@ -84,6 +90,10 @@ ReturnValue_t cfdp::VarLenField::serialize(uint8_t **buffer, size_t *size, size_
case (cfdp::WidthInBytes::FOUR_BYTES): { case (cfdp::WidthInBytes::FOUR_BYTES): {
return SerializeAdapter::serialize(&value.fourBytes, buffer, size, maxSize, streamEndianness); return SerializeAdapter::serialize(&value.fourBytes, buffer, size, maxSize, streamEndianness);
} }
case (cfdp::WidthInBytes::EIGHT_BYTES): {
return SerializeAdapter::serialize(&value.eightBytes, buffer, size, maxSize,
streamEndianness);
}
default: { default: {
return returnvalue::FAILED; return returnvalue::FAILED;
} }
@ -98,11 +108,16 @@ ReturnValue_t cfdp::VarLenField::deSerialize(cfdp::WidthInBytes width_, const ui
return deSerialize(buffer, size, streamEndianness); 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, ReturnValue_t cfdp::VarLenField::deSerialize(const uint8_t **buffer, size_t *size,
Endianness streamEndianness) { Endianness streamEndianness) {
switch (width) { switch (width) {
case (cfdp::WidthInBytes::ONE_BYTE): { case (cfdp::WidthInBytes::ONE_BYTE): {
value.oneByte = **buffer; value.oneByte = **buffer;
*buffer += 1;
*size += 1; *size += 1;
return returnvalue::OK; return returnvalue::OK;
} }
@ -112,6 +127,9 @@ ReturnValue_t cfdp::VarLenField::deSerialize(const uint8_t **buffer, size_t *siz
case (cfdp::WidthInBytes::FOUR_BYTES): { case (cfdp::WidthInBytes::FOUR_BYTES): {
return SerializeAdapter::deSerialize(&value.fourBytes, buffer, size, streamEndianness); return SerializeAdapter::deSerialize(&value.fourBytes, buffer, size, streamEndianness);
} }
case (cfdp::WidthInBytes::EIGHT_BYTES): {
return SerializeAdapter::deSerialize(&value.eightBytes, buffer, size, streamEndianness);
}
default: { default: {
return returnvalue::FAILED; 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 { bool cfdp::VarLenField::operator!=(const cfdp::VarLenField &other) const {
return not(*this == other); return not(*this == other);
} }
void cfdp::VarLenField::setWidth(cfdp::WidthInBytes width_) { this->width = width_; }

@ -25,13 +25,15 @@ class VarLenField : public SerializeIF {
template <typename T> template <typename T>
explicit VarLenField(UnsignedByteField<T> byteField); 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; 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, ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize,
Endianness streamEndianness) const override; Endianness streamEndianness) const override;
@ -42,7 +44,7 @@ class VarLenField : public SerializeIF {
Endianness streamEndianness); Endianness streamEndianness);
[[nodiscard]] cfdp::WidthInBytes getWidth() const; [[nodiscard]] cfdp::WidthInBytes getWidth() const;
[[nodiscard]] size_t getValue() const; [[nodiscard]] uint64_t getValue() const;
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
friend std::ostream &operator<<(std::ostream &os, const VarLenField &id) { friend std::ostream &operator<<(std::ostream &os, const VarLenField &id) {
@ -64,7 +66,7 @@ template <typename T>
cfdp::VarLenField::VarLenField(UnsignedByteField<T> byteField) cfdp::VarLenField::VarLenField(UnsignedByteField<T> byteField)
: width(static_cast<cfdp::WidthInBytes>(sizeof(T))) { : width(static_cast<cfdp::WidthInBytes>(sizeof(T))) {
static_assert((sizeof(T) % 2) == 0); static_assert((sizeof(T) % 2) == 0);
setValue(width, byteField.getValue()); setValueAndWidth(width, byteField.getValue());
} }
struct EntityId : public VarLenField { struct EntityId : public VarLenField {
@ -73,6 +75,32 @@ struct EntityId : public VarLenField {
template <typename T> template <typename T>
explicit EntityId(UnsignedByteField<T> byteField) : VarLenField(byteField) {} explicit EntityId(UnsignedByteField<T> byteField) : VarLenField(byteField) {}
EntityId(cfdp::WidthInBytes width, size_t entityId) : VarLenField(width, entityId) {} 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 { struct TransactionSeqNum : public VarLenField {

@ -17,7 +17,7 @@ static constexpr char CFDP_VERSION_2_NAME[] = "CCSDS 727.0-B-5";
static constexpr uint8_t CFDP_VERSION_2 = 0b001; static constexpr uint8_t CFDP_VERSION_2 = 0b001;
static constexpr uint8_t VERSION_BITS = CFDP_VERSION_2 << 5; 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_TLV_TYPE = returnvalue::makeCode(CFDP_CLASS_ID, 1);
static constexpr ReturnValue_t INVALID_DIRECTIVE_FIELD = returnvalue::makeCode(CFDP_CLASS_ID, 2); static constexpr ReturnValue_t INVALID_DIRECTIVE_FIELD = returnvalue::makeCode(CFDP_CLASS_ID, 2);
@ -68,6 +68,7 @@ enum WidthInBytes : uint8_t {
ONE_BYTE = 1, ONE_BYTE = 1,
TWO_BYTES = 2, TWO_BYTES = 2,
FOUR_BYTES = 4, FOUR_BYTES = 4,
EIGHT_BYTES = 8
}; };
enum FileDirective : uint8_t { enum FileDirective : uint8_t {
@ -142,6 +143,20 @@ enum RecordContinuationState {
CONTAINS_START_AND_END = 0b11 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 } // namespace cfdp
#endif /* FSFW_SRC_FSFW_CFDP_PDU_DEFINITIONS_H_ */ #endif /* FSFW_SRC_FSFW_CFDP_PDU_DEFINITIONS_H_ */

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

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

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

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

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

@ -16,7 +16,7 @@ class RemoteConfigTableIF {
*/ */
class OneRemoteConfigProvider : public RemoteConfigTableIF { class OneRemoteConfigProvider : public RemoteConfigTableIF {
public: public:
explicit OneRemoteConfigProvider(RemoteEntityCfg cfg) : cfg(std::move(cfg)) {} explicit OneRemoteConfigProvider(RemoteEntityCfg& cfg) : cfg(cfg) {}
bool getRemoteCfg(const EntityId& remoteId, cfdp::RemoteEntityCfg** cfg_) override { bool getRemoteCfg(const EntityId& remoteId, cfdp::RemoteEntityCfg** cfg_) override {
if (remoteId != cfg.remoteId) { if (remoteId != cfg.remoteId) {
@ -27,7 +27,7 @@ class OneRemoteConfigProvider : public RemoteConfigTableIF {
} }
private: private:
RemoteEntityCfg cfg; RemoteEntityCfg& cfg;
}; };
} // namespace cfdp } // namespace cfdp

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

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

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

@ -1,6 +1,110 @@
#ifndef FSFW_CFDP_CFDPSOURCEHANDLER_H #ifndef FSFW_CFDP_CFDPSOURCEHANDLER_H
#define 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 #endif // FSFW_CFDP_CFDPSOURCEHANDLER_H

@ -6,6 +6,7 @@
#include <vector> #include <vector>
#include "StatusReportIF.h" #include "StatusReportIF.h"
#include "fsfw/cfdp/Fss.h"
#include "fsfw/cfdp/VarLenFields.h" #include "fsfw/cfdp/VarLenFields.h"
#include "fsfw/cfdp/tlv/FilestoreResponseTlv.h" #include "fsfw/cfdp/tlv/FilestoreResponseTlv.h"
#include "fsfw/cfdp/tlv/MessageToUserTlv.h" #include "fsfw/cfdp/tlv/MessageToUserTlv.h"
@ -27,14 +28,14 @@ struct TransactionFinishedParams {
}; };
struct MetadataRecvdParams { struct MetadataRecvdParams {
MetadataRecvdParams(const TransactionId& id, const EntityId& sourceId) MetadataRecvdParams(const TransactionId& id, const EntityId& sourceId, Fss fileSize)
: id(id), sourceId(sourceId) {} : id(id), sourceId(sourceId), fileSize(std::move(fileSize)) {}
const TransactionId& id; const TransactionId& id;
const EntityId& sourceId; const EntityId& sourceId;
uint64_t fileSize = 0; Fss fileSize{};
const char* sourceFileName = ""; const char* sourceFileName = "";
const char* destFileName = ""; const char* destFileName = "";
size_t msgsToUserLen = 0; size_t numberOfMsgsToUser = 0;
const MessageToUserTlv* msgsToUserArray = nullptr; const MessageToUserTlv* msgsToUserArray = nullptr;
}; };
@ -65,6 +66,7 @@ struct FileSegmentRecvdParams {
*/ */
class UserBase { class UserBase {
friend class DestHandler; friend class DestHandler;
friend class SourceHandler;
public: public:
explicit UserBase(HasFileSystemIF& vfs); explicit UserBase(HasFileSystemIF& vfs);

@ -1,11 +1,54 @@
#ifndef FSFW_CFDP_HANDLER_DEFS_H #ifndef FSFW_CFDP_HANDLER_DEFS_H
#define 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 { 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 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 { 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); 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 //! [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); 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 } // 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 } // namespace cfdp
#endif // FSFW_CFDP_HANDLER_DEFS_H #endif // FSFW_CFDP_HANDLER_DEFS_H

@ -27,14 +27,15 @@ struct LocalEntityCfg {
}; };
struct RemoteEntityCfg { struct RemoteEntityCfg {
RemoteEntityCfg() = default;
explicit RemoteEntityCfg(EntityId id) : remoteId(std::move(id)) {} explicit RemoteEntityCfg(EntityId id) : remoteId(std::move(id)) {}
EntityId remoteId; EntityId remoteId;
size_t maxFileSegmentLen = 2048; size_t maxFileSegmentLen = 1024;
bool closureRequested = false; bool closureRequested = false;
bool crcOnTransmission = false; bool crcOnTransmission = false;
TransmissionMode defaultTransmissionMode = TransmissionMode::UNACKNOWLEDGED; TransmissionMode defaultTransmissionMode = TransmissionMode::UNACKNOWLEDGED;
ChecksumType defaultChecksum = ChecksumType::NULL_CHECKSUM; ChecksumType defaultChecksum = ChecksumType::NULL_CHECKSUM;
const uint8_t version = CFDP_VERSION_2; uint8_t version = CFDP_VERSION_2;
}; };
} // namespace cfdp } // namespace cfdp

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

@ -1,8 +1,13 @@
#include "EofInfo.h" #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) EntityIdTlv* faultLoc)
: conditionCode(conditionCode), checksum(checksum), fileSize(fileSize), faultLoc(faultLoc) {} : conditionCode(conditionCode),
checksum(checksum),
fileSize(std::move(fileSize)),
faultLoc(faultLoc) {}
EofInfo::EofInfo(EntityIdTlv* faultLoc) EofInfo::EofInfo(EntityIdTlv* faultLoc)
: conditionCode(cfdp::ConditionCode::NO_CONDITION_FIELD), : conditionCode(cfdp::ConditionCode::NO_CONDITION_FIELD),
@ -16,15 +21,15 @@ cfdp::ConditionCode EofInfo::getConditionCode() const { return conditionCode; }
EntityIdTlv* EofInfo::getFaultLoc() const { return faultLoc; } 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) { void EofInfo::setConditionCode(cfdp::ConditionCode conditionCode_) {
this->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) { size_t EofInfo::getSerializedSize(bool fssLarge) {
// Condition code + spare + 4 byte checksum // Condition code + spare + 4 byte checksum
@ -42,6 +47,6 @@ size_t EofInfo::getSerializedSize(bool fssLarge) {
return size; return size;
} }
ReturnValue_t EofInfo::setFileSize(size_t fileSize, bool isLarge) { ReturnValue_t EofInfo::setFileSize(size_t fileSize_, bool isLarge) {
return this->fileSize.setFileSize(fileSize, isLarge); return this->fileSize.setFileSize(fileSize_, isLarge);
} }

@ -1,14 +1,14 @@
#ifndef FSFW_SRC_FSFW_CFDP_PDU_EOFINFO_H_ #ifndef FSFW_SRC_FSFW_CFDP_PDU_EOFINFO_H_
#define 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 "../definitions.h"
#include "fsfw/cfdp/tlv/EntityIdTlv.h" #include "fsfw/cfdp/tlv/EntityIdTlv.h"
struct EofInfo { struct EofInfo {
public: public:
explicit EofInfo(EntityIdTlv* faultLoc = nullptr); 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); EntityIdTlv* faultLoc = nullptr);
size_t getSerializedSize(bool fssLarge = false); size_t getSerializedSize(bool fssLarge = false);
@ -17,7 +17,7 @@ struct EofInfo {
[[nodiscard]] cfdp::ConditionCode getConditionCode() const; [[nodiscard]] cfdp::ConditionCode getConditionCode() const;
[[nodiscard]] EntityIdTlv* getFaultLoc() const; [[nodiscard]] EntityIdTlv* getFaultLoc() const;
cfdp::FileSize& getFileSize(); cfdp::Fss& getFileSize();
void setChecksum(uint32_t checksum); void setChecksum(uint32_t checksum);
void setConditionCode(cfdp::ConditionCode conditionCode); void setConditionCode(cfdp::ConditionCode conditionCode);
void setFaultLoc(EntityIdTlv* faultLoc); void setFaultLoc(EntityIdTlv* faultLoc);
@ -26,7 +26,7 @@ struct EofInfo {
private: private:
cfdp::ConditionCode conditionCode; cfdp::ConditionCode conditionCode;
uint32_t checksum; uint32_t checksum;
cfdp::FileSize fileSize; cfdp::Fss fileSize;
EntityIdTlv* faultLoc = nullptr; EntityIdTlv* faultLoc = nullptr;
}; };

@ -37,7 +37,7 @@ ReturnValue_t FileDataCreator::serialize(uint8_t** buffer, size_t* size, size_t
*buffer += segmentMetadataLen; *buffer += segmentMetadataLen;
*size += segmentMetadataLen; *size += segmentMetadataLen;
} }
cfdp::FileSize& offset = info.getOffset(); cfdp::Fss& offset = info.getOffset();
result = offset.serialize(this->getLargeFileFlag(), buffer, size, maxSize, streamEndianness); result = offset.serialize(this->getLargeFileFlag(), buffer, size, maxSize, streamEndianness);
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
return result; return result;

@ -1,9 +1,9 @@
#include "FileDataInfo.h" #include "FileDataInfo.h"
FileDataInfo::FileDataInfo(cfdp::FileSize &offset, const uint8_t *fileData, size_t fileSize) #include <utility>
: offset(offset), fileData(fileData), fileSize(fileSize) {}
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) { void FileDataInfo::setSegmentMetadataFlag(bool enable) {
if (enable) { if (enable) {
@ -71,7 +71,7 @@ const uint8_t *FileDataInfo::getSegmentMetadata(size_t *segmentMetadataLen_) {
return segmentMetadata; return segmentMetadata;
} }
cfdp::FileSize &FileDataInfo::getOffset() { return offset; } cfdp::Fss &FileDataInfo::getOffset() { return offset; }
void FileDataInfo::setRecordContinuationState(cfdp::RecordContinuationState recContState) { void FileDataInfo::setRecordContinuationState(cfdp::RecordContinuationState recContState) {
this->recContState = recContState; this->recContState = recContState;

@ -1,17 +1,17 @@
#ifndef FSFW_SRC_FSFW_CFDP_PDU_FILEDATAINFO_H_ #ifndef FSFW_SRC_FSFW_CFDP_PDU_FILEDATAINFO_H_
#define 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> #include <fsfw/cfdp/definitions.h>
class FileDataInfo { class FileDataInfo {
public: public:
explicit FileDataInfo(cfdp::FileSize& offset); FileDataInfo() = default;
FileDataInfo(cfdp::FileSize& offset, const uint8_t* fileData, size_t fileSize); FileDataInfo(cfdp::Fss offset, const uint8_t* fileData, size_t fileSize);
[[nodiscard]] size_t getSerializedSize(bool largeFile = false) const; [[nodiscard]] size_t getSerializedSize(bool largeFile = false) const;
cfdp::FileSize& getOffset(); cfdp::Fss& getOffset();
const uint8_t* getFileData(size_t* fileSize = nullptr) const; const uint8_t* getFileData(size_t* fileSize = nullptr) const;
void setFileData(const uint8_t* fileData, size_t fileSize); void setFileData(const uint8_t* fileData, size_t fileSize);
@ -33,7 +33,7 @@ class FileDataInfo {
private: private:
cfdp::SegmentMetadataFlag segmentMetadataFlag = cfdp::SegmentMetadataFlag::NOT_PRESENT; cfdp::SegmentMetadataFlag segmentMetadataFlag = cfdp::SegmentMetadataFlag::NOT_PRESENT;
cfdp::SegmentationControl segCtrl = cfdp::SegmentationControl::NO_RECORD_BOUNDARIES_PRESERVATION; cfdp::SegmentationControl segCtrl = cfdp::SegmentationControl::NO_RECORD_BOUNDARIES_PRESERVATION;
cfdp::FileSize& offset; cfdp::Fss offset;
const uint8_t* fileData = nullptr; const uint8_t* fileData = nullptr;
size_t fileSize = 0; size_t fileSize = 0;
cfdp::RecordContinuationState recContState = cfdp::RecordContinuationState::NO_START_NO_END; cfdp::RecordContinuationState recContState = cfdp::RecordContinuationState::NO_START_NO_END;

@ -103,11 +103,11 @@ void PduHeaderReader::getTransactionSeqNum(cfdp::TransactionSeqNum &seqNum) cons
} }
void PduHeaderReader::assignVarLenField(cfdp::VarLenField *field, cfdp::WidthInBytes width, void PduHeaderReader::assignVarLenField(cfdp::VarLenField *field, cfdp::WidthInBytes width,
void *sourcePtr) const { void *sourcePtr) {
switch (width) { switch (width) {
case (cfdp::WidthInBytes::ONE_BYTE): { case (cfdp::WidthInBytes::ONE_BYTE): {
auto *fieldTyped = static_cast<uint8_t *>(sourcePtr); auto *fieldTyped = static_cast<uint8_t *>(sourcePtr);
field->setValue(width, *fieldTyped); field->setValueAndWidth(width, *fieldTyped);
break; break;
} }
case (cfdp::WidthInBytes::TWO_BYTES): { case (cfdp::WidthInBytes::TWO_BYTES): {
@ -115,7 +115,7 @@ void PduHeaderReader::assignVarLenField(cfdp::VarLenField *field, cfdp::WidthInB
size_t deserSize = 0; size_t deserSize = 0;
SerializeAdapter::deSerialize(&fieldTyped, static_cast<uint8_t *>(sourcePtr), &deserSize, SerializeAdapter::deSerialize(&fieldTyped, static_cast<uint8_t *>(sourcePtr), &deserSize,
SerializeIF::Endianness::NETWORK); SerializeIF::Endianness::NETWORK);
field->setValue(width, fieldTyped); field->setValueAndWidth(width, fieldTyped);
break; break;
} }
case (cfdp::WidthInBytes::FOUR_BYTES): { case (cfdp::WidthInBytes::FOUR_BYTES): {
@ -123,7 +123,15 @@ void PduHeaderReader::assignVarLenField(cfdp::VarLenField *field, cfdp::WidthInB
size_t deserSize = 0; size_t deserSize = 0;
SerializeAdapter::deSerialize(&fieldTyped, static_cast<uint8_t *>(sourcePtr), &deserSize, SerializeAdapter::deSerialize(&fieldTyped, static_cast<uint8_t *>(sourcePtr), &deserSize,
SerializeIF::Endianness::NETWORK); 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; break;
} }
} }

@ -1,6 +1,6 @@
#include "KeepAlivePduCreator.h" #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) { : FileDirectiveCreator(conf, cfdp::FileDirective::KEEP_ALIVE, 4), progress(progress) {
updateDirectiveFieldLen(); updateDirectiveFieldLen();
} }

@ -1,12 +1,12 @@
#ifndef FSFW_CFDP_PDU_KEEPALIVEPDUSERIALIZER_H_ #ifndef FSFW_CFDP_PDU_KEEPALIVEPDUSERIALIZER_H_
#define 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" #include "fsfw/cfdp/pdu/FileDirectiveCreator.h"
class KeepAlivePduCreator : public FileDirectiveCreator { class KeepAlivePduCreator : public FileDirectiveCreator {
public: public:
KeepAlivePduCreator(PduConfig& conf, cfdp::FileSize& progress); KeepAlivePduCreator(PduConfig& conf, cfdp::Fss& progress);
void updateDirectiveFieldLen(); void updateDirectiveFieldLen();
@ -16,7 +16,7 @@ class KeepAlivePduCreator : public FileDirectiveCreator {
Endianness streamEndianness) const override; Endianness streamEndianness) const override;
private: private:
cfdp::FileSize& progress; cfdp::Fss& progress;
}; };
#endif /* FSFW_CFDP_PDU_KEEPALIVEPDUSERIALIZER_H_ */ #endif /* FSFW_CFDP_PDU_KEEPALIVEPDUSERIALIZER_H_ */

@ -1,7 +1,6 @@
#include "KeepAlivePduReader.h" #include "KeepAlivePduReader.h"
KeepAlivePduReader::KeepAlivePduReader(const uint8_t* pduBuf, size_t maxSize, KeepAlivePduReader::KeepAlivePduReader(const uint8_t* pduBuf, size_t maxSize, cfdp::Fss& progress)
cfdp::FileSize& progress)
: FileDirectiveReader(pduBuf, maxSize), progress(progress) {} : FileDirectiveReader(pduBuf, maxSize), progress(progress) {}
ReturnValue_t KeepAlivePduReader::parseData() { ReturnValue_t KeepAlivePduReader::parseData() {
@ -15,4 +14,4 @@ ReturnValue_t KeepAlivePduReader::parseData() {
return progress.deSerialize(&buffer, &remLen, getEndianness()); return progress.deSerialize(&buffer, &remLen, getEndianness());
} }
cfdp::FileSize& KeepAlivePduReader::getProgress() { return progress; } cfdp::Fss& KeepAlivePduReader::getProgress() { return progress; }

@ -1,19 +1,19 @@
#ifndef FSFW_CFDP_PDU_KEEPALIVEREADER_H_ #ifndef FSFW_CFDP_PDU_KEEPALIVEREADER_H_
#define 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" #include "fsfw/cfdp/pdu/FileDirectiveReader.h"
class KeepAlivePduReader : public FileDirectiveReader { class KeepAlivePduReader : public FileDirectiveReader {
public: 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; ReturnValue_t parseData() override;
cfdp::FileSize& getProgress(); cfdp::Fss& getProgress();
private: private:
cfdp::FileSize& progress; cfdp::Fss& progress;
}; };
#endif /* FSFW_CFDP_PDU_KEEPALIVEPDUREADER_H_ */ #endif /* FSFW_CFDP_PDU_KEEPALIVEPDUREADER_H_ */

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

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

@ -1,103 +0,0 @@
#include "MetadataInfo.h"
MetadataInfo::MetadataInfo(bool closureRequested, cfdp::ChecksumType checksumType,
cfdp::FileSize& fileSize, cfdp::StringLv& sourceFileName,
cfdp::StringLv& destFileName)
: MetadataInfo(fileSize, sourceFileName, destFileName) {
this->closureRequested = closureRequested;
this->checksumType = checksumType;
}
MetadataInfo::MetadataInfo(cfdp::FileSize& fileSize, cfdp::StringLv& sourceFileName,
cfdp::StringLv& destFileName)
: fileSize(fileSize), sourceFileName(sourceFileName), destFileName(destFileName) {}
void MetadataInfo::setOptionsArray(cfdp::Tlv** optionsArray_, std::optional<size_t> optionsLen_,
std::optional<size_t> maxOptionsLen_) {
this->optionsArray = optionsArray_;
if (maxOptionsLen_) {
this->maxOptionsLen = maxOptionsLen_.value();
}
if (optionsLen_) {
this->optionsLen = optionsLen_.value();
}
}
cfdp::ChecksumType MetadataInfo::getChecksumType() const { return checksumType; }
void MetadataInfo::setChecksumType(cfdp::ChecksumType checksumType_) {
checksumType = checksumType_;
}
bool MetadataInfo::isClosureRequested() const { return closureRequested; }
void MetadataInfo::setClosureRequested(bool closureRequested_) {
closureRequested = closureRequested_;
}
cfdp::StringLv& MetadataInfo::getDestFileName() { return destFileName; }
cfdp::FileSize& MetadataInfo::getFileSize() { return fileSize; }
ReturnValue_t MetadataInfo::getOptions(cfdp::Tlv*** optionsArray_, size_t* optionsLen_,
size_t* maxOptsLen) {
if (optionsArray_ == nullptr or optionsArray == nullptr) {
return returnvalue::FAILED;
}
*optionsArray_ = optionsArray;
if (optionsLen_ != nullptr) {
*optionsLen_ = this->optionsLen;
}
if (maxOptsLen != nullptr) {
*maxOptsLen = this->maxOptionsLen;
}
return returnvalue::OK;
}
bool MetadataInfo::hasOptions() const {
if (optionsArray != nullptr and optionsLen > 0) {
return true;
}
return false;
}
bool MetadataInfo::canHoldOptions() const {
if (optionsArray != nullptr and maxOptionsLen > 0) {
return true;
}
return false;
}
size_t MetadataInfo::getSerializedSize(bool fssLarge) {
// 1 byte + minimal FSS 4 bytes
size_t size = 5;
if (fssLarge) {
size += 4;
}
size += sourceFileName.getSerializedSize();
size += destFileName.getSerializedSize();
if (hasOptions()) {
for (size_t idx = 0; idx < optionsLen; idx++) {
size += optionsArray[idx]->getSerializedSize();
}
}
return size;
}
void MetadataInfo::setDestFileName(cfdp::StringLv& destFileName_) {
this->destFileName = destFileName_;
}
void MetadataInfo::setSourceFileName(cfdp::StringLv& sourceFileName_) {
this->sourceFileName = sourceFileName_;
}
size_t MetadataInfo::getMaxOptionsLen() const { return maxOptionsLen; }
void MetadataInfo::setMaxOptionsLen(size_t maxOptionsLen_) { this->maxOptionsLen = maxOptionsLen_; }
size_t MetadataInfo::getOptionsLen() const { return optionsLen; }
void MetadataInfo::setOptionsLen(size_t optionsLen_) { this->optionsLen = optionsLen_; }
cfdp::StringLv& MetadataInfo::getSourceFileName() { return sourceFileName; }

@ -1,55 +0,0 @@
#ifndef FSFW_SRC_FSFW_CFDP_PDU_METADATAINFO_H_
#define FSFW_SRC_FSFW_CFDP_PDU_METADATAINFO_H_
#include <optional>
#include "fsfw/cfdp/FileSize.h"
#include "fsfw/cfdp/definitions.h"
#include "fsfw/cfdp/tlv/Lv.h"
#include "fsfw/cfdp/tlv/StringLv.h"
#include "fsfw/cfdp/tlv/Tlv.h"
class MetadataInfo {
public:
MetadataInfo(cfdp::FileSize& fileSize, cfdp::StringLv& sourceFileName,
cfdp::StringLv& destFileName);
MetadataInfo(bool closureRequested, cfdp::ChecksumType checksumType, cfdp::FileSize& fileSize,
cfdp::StringLv& sourceFileName, cfdp::StringLv& destFileName);
size_t getSerializedSize(bool fssLarge = false);
void setOptionsArray(cfdp::Tlv** optionsArray, std::optional<size_t> optionsLen,
std::optional<size_t> maxOptionsLen);
[[nodiscard]] cfdp::ChecksumType getChecksumType() const;
void setChecksumType(cfdp::ChecksumType checksumType);
[[nodiscard]] bool isClosureRequested() const;
void setClosureRequested(bool closureRequested = false);
void setDestFileName(cfdp::StringLv& destFileName);
void setSourceFileName(cfdp::StringLv& sourceFileName);
cfdp::StringLv& getDestFileName();
cfdp::StringLv& getSourceFileName();
cfdp::FileSize& getFileSize();
[[nodiscard]] bool hasOptions() const;
[[nodiscard]] bool canHoldOptions() const;
ReturnValue_t getOptions(cfdp::Tlv*** optionsArray, size_t* optionsLen, size_t* maxOptsLen);
void setOptionsLen(size_t optionsLen);
[[nodiscard]] size_t getOptionsLen() const;
void setMaxOptionsLen(size_t maxOptionsLen);
[[nodiscard]] size_t getMaxOptionsLen() const;
private:
bool closureRequested = false;
cfdp::ChecksumType checksumType = cfdp::ChecksumType::NULL_CHECKSUM;
cfdp::FileSize& fileSize;
cfdp::StringLv& sourceFileName;
cfdp::StringLv& destFileName;
cfdp::Tlv** optionsArray = nullptr;
size_t optionsLen = 0;
size_t maxOptionsLen = 0;
};
#endif /* FSFW_SRC_FSFW_CFDP_PDU_METADATAINFO_H_ */

@ -1,12 +1,26 @@
#include "MetadataPduCreator.h" #include "MetadataPduCreator.h"
MetadataPduCreator::MetadataPduCreator(PduConfig &conf, MetadataInfo &info) MetadataPduCreator::MetadataPduCreator(PduConfig &conf, MetadataGenericInfo &info,
: FileDirectiveCreator(conf, cfdp::FileDirective::METADATA, 5), info(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(); updateDirectiveFieldLen();
} }
void MetadataPduCreator::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 { size_t MetadataPduCreator::getSerializedSize() const {
@ -29,21 +43,18 @@ ReturnValue_t MetadataPduCreator::serialize(uint8_t **buffer, size_t *size, size
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
return result; return result;
} }
result = info.getSourceFileName().serialize(buffer, size, maxSize, streamEndianness); result = srcFileName.serialize(buffer, size, maxSize, streamEndianness);
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
return result; return result;
} }
result = info.getDestFileName().serialize(buffer, size, maxSize, streamEndianness); result = destFileName.serialize(buffer, size, maxSize, streamEndianness);
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
return result; return result;
} }
if (info.hasOptions()) { if (optionsLen > 0 and optionsArray != nullptr) {
cfdp::Tlv **optsArray = nullptr; for (size_t idx = 0; idx < optionsLen; idx++) {
size_t optsLen = 0; result = optionsArray[idx]->serialize(buffer, size, maxSize, streamEndianness);
info.getOptions(&optsArray, &optsLen, nullptr);
for (size_t idx = 0; idx < optsLen; idx++) {
result = optsArray[idx]->serialize(buffer, size, maxSize, streamEndianness);
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
return result; return result;
} }
@ -51,3 +62,5 @@ ReturnValue_t MetadataPduCreator::serialize(uint8_t **buffer, size_t *size, size
} }
return result; return result;
} }
const cfdp::StringLv &MetadataPduCreator::getSourceFileName() const { return srcFileName; }
const cfdp::StringLv &MetadataPduCreator::getDestFileName() const { return destFileName; }

@ -2,22 +2,30 @@
#define FSFW_CFDP_PDU_METADATAPDUCREATOR_H_ #define FSFW_CFDP_PDU_METADATAPDUCREATOR_H_
#include "fsfw/cfdp/pdu/FileDirectiveCreator.h" #include "fsfw/cfdp/pdu/FileDirectiveCreator.h"
#include "fsfw/cfdp/pdu/MetadataInfo.h" #include "fsfw/cfdp/pdu/MetadataGenericInfo.h"
class MetadataPduCreator : public FileDirectiveCreator { class MetadataPduCreator : public FileDirectiveCreator {
public: 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(); void updateDirectiveFieldLen();
[[nodiscard]] size_t getSerializedSize() const override; [[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, ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
Endianness streamEndianness) const override; Endianness streamEndianness) const override;
using FileDirectiveCreator::serialize; using FileDirectiveCreator::serialize;
private: private:
MetadataInfo& info; MetadataGenericInfo& info;
cfdp::StringLv& srcFileName;
cfdp::StringLv& destFileName;
cfdp::Tlv** optionsArray;
size_t optionsLen;
}; };
#endif /* FSFW_CFDP_PDU_METADATAPDUCREATOR_H_ */ #endif /* FSFW_CFDP_PDU_METADATAPDUCREATOR_H_ */

@ -1,9 +1,15 @@
#include "MetadataPduReader.h" #include "MetadataPduReader.h"
MetadataPduReader::MetadataPduReader(const uint8_t* pduBuf, size_t maxSize, MetadataInfo& info) MetadataPduReader::MetadataPduReader(const uint8_t* pduBuf, size_t maxSize,
: FileDirectiveReader(pduBuf, maxSize), info(info) {} MetadataGenericInfo& info, cfdp::Tlv* optionsArray,
size_t optArrayMaxSize)
: FileDirectiveReader(pduBuf, maxSize),
info(info),
optionArray(optionsArray),
optionArrayMaxSize(optArrayMaxSize) {}
ReturnValue_t MetadataPduReader::parseData() { ReturnValue_t MetadataPduReader::parseData() {
parsedOptions = 0;
ReturnValue_t result = FileDirectiveReader::parseData(); ReturnValue_t result = FileDirectiveReader::parseData();
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
return result; return result;
@ -19,39 +25,43 @@ ReturnValue_t MetadataPduReader::parseData() {
remSize -= 1; remSize -= 1;
buf += 1; buf += 1;
auto endianness = getEndianness(); auto endianness = getEndianness();
result = info.getFileSize().deSerialize(&buf, &remSize, endianness); result = info.getMutFileSize().deSerialize(&buf, &remSize, endianness);
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
return result; return result;
} }
result = info.getSourceFileName().deSerialize(&buf, &remSize, endianness); result = srcFileName.deSerialize(&buf, &remSize, endianness);
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
return result; return result;
} }
result = info.getDestFileName().deSerialize(&buf, &remSize, endianness); result = destFileName.deSerialize(&buf, &remSize, endianness);
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
return result; return result;
} }
info.setOptionsLen(0);
if (remSize > 0) { if (remSize > 0) {
if (not info.canHoldOptions()) { if (optionArrayMaxSize == 0 or optionArray == nullptr) {
return cfdp::METADATA_CANT_PARSE_OPTIONS; return cfdp::METADATA_CANT_PARSE_OPTIONS;
} }
cfdp::Tlv** optionsArray = nullptr;
size_t optsMaxLen = 0;
size_t optsIdx = 0; size_t optsIdx = 0;
info.getOptions(&optionsArray, nullptr, &optsMaxLen);
while (remSize > 0) { while (remSize > 0) {
if (optsIdx > optsMaxLen) { if (optsIdx > optionArrayMaxSize) {
return cfdp::METADATA_CANT_PARSE_OPTIONS; return cfdp::METADATA_CANT_PARSE_OPTIONS;
} }
result = optionsArray[optsIdx]->deSerialize(&buf, &remSize, endianness); result = optionArray[optsIdx].deSerialize(&buf, &remSize, endianness);
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
return result; return result;
} }
optsIdx++; optsIdx++;
} }
info.setOptionsLen(optsIdx); parsedOptions = optsIdx;
} }
return result; return result;
} }
size_t MetadataPduReader::getNumberOfParsedOptions() const { return parsedOptions; }
const cfdp::StringLv& MetadataPduReader::getSourceFileName() const { return srcFileName; }
const cfdp::StringLv& MetadataPduReader::getDestFileName() const { return destFileName; }
const MetadataGenericInfo& MetadataPduReader::getGenericInfo() const { return info; }

@ -2,16 +2,28 @@
#define FSFW_CFDP_PDU_METADATAPDUREADER_H_ #define FSFW_CFDP_PDU_METADATAPDUREADER_H_
#include "fsfw/cfdp/pdu/FileDirectiveReader.h" #include "fsfw/cfdp/pdu/FileDirectiveReader.h"
#include "fsfw/cfdp/pdu/MetadataInfo.h" #include "fsfw/cfdp/pdu/MetadataGenericInfo.h"
class MetadataPduReader : public FileDirectiveReader { class MetadataPduReader : public FileDirectiveReader {
public: 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; 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: 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_ */ #endif /* FSFW_CFDP_PDU_METADATAPDUREADER_H_ */

@ -1,6 +1,6 @@
#include "NakInfo.h" #include "NakInfo.h"
NakInfo::NakInfo(cfdp::FileSize startOfScope, cfdp::FileSize endOfScope) NakInfo::NakInfo(cfdp::Fss startOfScope, cfdp::Fss endOfScope)
: startOfScope(startOfScope), endOfScope(endOfScope) {} : startOfScope(startOfScope), endOfScope(endOfScope) {}
size_t NakInfo::getSerializedSize(bool fssLarge) { 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; } size_t NakInfo::getSegmentRequestsLen() const { return segmentRequestsLen; }

@ -3,21 +3,21 @@
#include <utility> #include <utility>
#include "fsfw/cfdp/FileSize.h" #include "fsfw/cfdp/Fss.h"
class NakInfo { class NakInfo {
public: 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, void setSegmentRequests(SegmentRequest* segmentRequests, size_t* segmentRequestLen,
size_t* maxSegmentRequestLen); size_t* maxSegmentRequestLen);
size_t getSerializedSize(bool fssLarge = false); size_t getSerializedSize(bool fssLarge = false);
cfdp::FileSize& getStartOfScope(); cfdp::Fss& getStartOfScope();
cfdp::FileSize& getEndOfScope(); cfdp::Fss& getEndOfScope();
bool hasSegmentRequests() const; bool hasSegmentRequests() const;
bool canHoldSegmentRequests() const; bool canHoldSegmentRequests() const;
@ -31,8 +31,8 @@ class NakInfo {
void setSegmentRequestLen(size_t readLen); void setSegmentRequestLen(size_t readLen);
private: private:
cfdp::FileSize startOfScope; cfdp::Fss startOfScope;
cfdp::FileSize endOfScope; cfdp::Fss endOfScope;
SegmentRequest* segmentRequests = nullptr; SegmentRequest* segmentRequests = nullptr;
size_t segmentRequestsLen = 0; size_t segmentRequestsLen = 0;
size_t maxSegmentRequestsLen = 0; size_t maxSegmentRequestsLen = 0;

@ -4,7 +4,7 @@
#include <vector> #include <vector>
#include "NakInfo.h" #include "NakInfo.h"
#include "fsfw/cfdp/FileSize.h" #include "fsfw/cfdp/Fss.h"
#include "fsfw/cfdp/definitions.h" #include "fsfw/cfdp/definitions.h"
#include "fsfw/cfdp/pdu/FileDirectiveCreator.h" #include "fsfw/cfdp/pdu/FileDirectiveCreator.h"

@ -105,7 +105,8 @@ class PduHeaderReader : public RedirectableDataPointerIF, public PduHeaderIF {
* @return * @return
*/ */
ReturnValue_t setData(uint8_t* dataPtr, size_t maxSize, void* args) override; 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* sourceIdRaw = nullptr;
void* seqNumRaw = nullptr; void* seqNumRaw = nullptr;
void* destIdRaw = nullptr; void* destIdRaw = nullptr;

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

@ -14,23 +14,6 @@ cfdp::Lv::Lv(const std::vector<uint8_t>& data) : value(data.data(), data.size(),
cfdp::Lv::Lv() : value(static_cast<uint8_t*>(nullptr), 0, true) {} cfdp::Lv::Lv() : 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, ReturnValue_t cfdp::Lv::serialize(uint8_t** buffer, size_t* size, size_t maxSize,
Endianness streamEndianness) const { Endianness streamEndianness) const {
if (maxSize < 1) { 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 { size_t cfdp::Lv::getSerializedSize() const {
if (zeroLen) { if (zeroLen or value.getConstBuffer() == nullptr) {
return 1; return 1;
} else if (value.getConstBuffer() == nullptr) {
return 0;
} }
return value.getSerializedSize(); 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 { const uint8_t* cfdp::Lv::getValue(size_t* size) const {
if (size != nullptr) { if (size != nullptr) {
// Length without length field // Length without length field
*size = value.getSerializedSize() - 1; *size = getSerializedSize() - 1;
} }
return value.getConstBuffer(); return value.getConstBuffer();
} }
cfdp::Lv::Lv(cfdp::Lv&& other) noexcept
: value(other.value.getConstBuffer(), other.value.getSerializedSize() - 1, true) {
if (other.value.getSerializedSize() - 1 > 0) {
zeroLen = false;
}
// Leave other class in intact state.
other.zeroLen = false;
other.value = SerialBufferAdapter<uint8_t>();
}
cfdp::Lv& cfdp::Lv::operator=(cfdp::Lv&& other) noexcept {
size_t otherSize = 0;
this->zeroLen = false;
auto* otherVal = const_cast<uint8_t*>(other.getValue(&otherSize));
if (otherVal == nullptr or otherSize == 0) {
this->zeroLen = true;
}
this->value.setConstBuffer(otherVal, otherSize);
// Leave other class in intact state.
other.zeroLen = false;
other.value = SerialBufferAdapter<uint8_t>();
return *this;
}
size_t cfdp::Lv::getValueLen() const { return getSerializedSize() - 1; }
bool cfdp::Lv::isEmpty() const { return zeroLen; }

@ -18,8 +18,12 @@ class Lv : public SerializeIF {
Lv(const uint8_t* value, size_t size); Lv(const uint8_t* value, size_t size);
Lv(); Lv();
Lv(const Lv&); // Semantically, this class is a zero-copy helper, so the copy ctor and copy assigment do not
Lv& operator=(const Lv&); // 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, ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
Endianness streamEndianness) const override; Endianness streamEndianness) const override;
@ -36,6 +40,8 @@ class Lv : public SerializeIF {
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
Endianness streamEndianness) override; Endianness streamEndianness) override;
size_t getValueLen() const;
/** /**
* Get value field and its size. * Get value field and its size.
* @param size Optionally retrieve size. Size will be the size of the actual value field * @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; const uint8_t* getValue(size_t* size) const;
bool isEmpty() const;
private: private:
bool zeroLen = true; bool zeroLen = true;
SerialBufferAdapter<uint8_t> value; SerialBufferAdapter<uint8_t> value;

@ -7,3 +7,22 @@ MessageToUserTlv::MessageToUserTlv() : Tlv() {}
MessageToUserTlv::MessageToUserTlv(const std::vector<uint8_t>& data) MessageToUserTlv::MessageToUserTlv(const std::vector<uint8_t>& data)
: Tlv(cfdp::TlvType::MSG_TO_USER, data.data(), data.size()) {} : Tlv(cfdp::TlvType::MSG_TO_USER, data.data(), data.size()) {}
MessageToUserTlv::MessageToUserTlv(const uint8_t* value, size_t size)
: Tlv(cfdp::TlvType::MSG_TO_USER, value, size) {}
bool MessageToUserTlv::isReservedCfdpMessage(uint8_t& messageType, const uint8_t** msgDataStart,
size_t& msgLen) const {
if (cfdp::Tlv::getLengthField() < 5) {
return false;
}
if (std::strncmp(reinterpret_cast<const char*>(getValue()), "cfdp", 4) == 0) {
messageType = getValue()[4];
if (msgDataStart != nullptr) {
*msgDataStart = getValue() + 5;
}
msgLen = cfdp::Tlv::getSerializedSize() - 5;
return true;
}
return false;
}

@ -9,8 +9,12 @@ class MessageToUserTlv : public cfdp::Tlv {
public: public:
MessageToUserTlv(); MessageToUserTlv();
MessageToUserTlv(uint8_t* value, size_t size); MessageToUserTlv(uint8_t* value, size_t size);
MessageToUserTlv(const uint8_t* value, size_t size);
explicit MessageToUserTlv(const std::vector<uint8_t>& data); explicit MessageToUserTlv(const std::vector<uint8_t>& data);
bool isReservedCfdpMessage(uint8_t& messageType, const uint8_t** msgDataStart,
size_t& msgLen) const;
private: private:
}; };

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

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

@ -7,3 +7,12 @@ cfdp::StringLv::StringLv(const char* filename, size_t len)
: Lv(reinterpret_cast<const uint8_t*>(filename), len) {} : Lv(reinterpret_cast<const uint8_t*>(filename), len) {}
cfdp::StringLv::StringLv() : Lv() {} cfdp::StringLv::StringLv() : Lv() {}
const char* cfdp::StringLv::getCString(size_t& fileSize) const {
return reinterpret_cast<const char*>(getValue(&fileSize));
}
std::string cfdp::StringLv::getString() const {
size_t fileSize;
return {getCString(fileSize), fileSize};
}

@ -13,6 +13,8 @@ class StringLv : public Lv {
explicit StringLv(const std::string& fileName); explicit StringLv(const std::string& fileName);
explicit StringLv(const char* filename, size_t len); 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 // Delete the move constructor to avoid passing in a temporary
StringLv(const std::string&&) = delete; StringLv(const std::string&&) = delete;
}; };

@ -54,6 +54,7 @@ ReturnValue_t cfdp::Tlv::deSerialize(const uint8_t **buffer, size_t *size,
return STREAM_TOO_SHORT; return STREAM_TOO_SHORT;
} }
rawData = *buffer;
uint8_t rawType = **buffer; uint8_t rawType = **buffer;
if (not checkType(rawType)) { if (not checkType(rawType)) {
return INVALID_TLV_TYPE; 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; } uint8_t cfdp::Tlv::getLengthField() const { return this->value.getSerializedSize() - 1; }
void cfdp::Tlv::setType(TlvType type) { this->type = type; } void cfdp::Tlv::setType(TlvType type) { this->type = type; }
const uint8_t *cfdp::Tlv::getRawData() const { return rawData; }

@ -47,6 +47,7 @@ class Tlv : public TlvIF {
void setValue(uint8_t *value, size_t len); void setValue(uint8_t *value, size_t len);
[[nodiscard]] const uint8_t *getValue() const; [[nodiscard]] const uint8_t *getValue() const;
[[nodiscard]] const uint8_t *getRawData() const;
void setType(TlvType type); void setType(TlvType type);
[[nodiscard]] TlvType getType() const override; [[nodiscard]] TlvType getType() const override;
[[nodiscard]] uint8_t getLengthField() const override; [[nodiscard]] uint8_t getLengthField() const override;
@ -55,6 +56,7 @@ class Tlv : public TlvIF {
bool checkType(uint8_t rawType); bool checkType(uint8_t rawType);
bool zeroLen = true; bool zeroLen = true;
const uint8_t *rawData = nullptr;
TlvType type = TlvType::INVALID_TLV; TlvType type = TlvType::INVALID_TLV;
SerialBufferAdapter<uint8_t> value; SerialBufferAdapter<uint8_t> value;
}; };

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

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

@ -23,6 +23,12 @@ class CoordinateTransformations {
static void getEarthRotationMatrix(timeval timeUTC, double matrix[][3]); static void 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: private:
CoordinateTransformations(); CoordinateTransformations();
static void ecfToEci(const double* ecfCoordinates, double* eciCoordinates, static void ecfToEci(const double* ecfCoordinates, double* eciCoordinates,

@ -166,9 +166,9 @@ ReturnValue_t Sgp4Propagator::propagate(double* position, double* velocity, time
timeval timeSinceEpoch = time - epoch; timeval timeSinceEpoch = time - epoch;
double minutesSinceEpoch = timeSinceEpoch.tv_sec / 60. + timeSinceEpoch.tv_usec / 60000000.; double minutesSinceEpoch = timeSinceEpoch.tv_sec / 60. + timeSinceEpoch.tv_usec / 60000000.;
double monthsSinceEpoch = minutesSinceEpoch / 60 / 24 / 30; double daysSinceEpoch = minutesSinceEpoch / 60 / 24;
if ((monthsSinceEpoch > 1) || (monthsSinceEpoch < -1)) { if ((daysSinceEpoch > 7) || (daysSinceEpoch < -7)) {
return TLE_TOO_OLD; return TLE_TOO_OLD;
} }

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

@ -26,6 +26,11 @@ ReturnValue_t DeviceHandlerFailureIsolation::eventReceived(EventMessage* event)
if (isFdirInActionOrAreWeFaulty(event)) { if (isFdirInActionOrAreWeFaulty(event)) {
return returnvalue::OK; 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; ReturnValue_t result = returnvalue::FAILED;
switch (event->getEvent()) { switch (event->getEvent()) {
case HasModesIF::MODE_TRANSITION_FAILED: case HasModesIF::MODE_TRANSITION_FAILED:
@ -186,15 +191,6 @@ void DeviceHandlerFailureIsolation::setFdirState(FDIRState state) {
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); } bool DeviceHandlerFailureIsolation::isFdirActionInProgress() { return (fdirState != NONE); }
void DeviceHandlerFailureIsolation::startRecovery(Event reason) { void DeviceHandlerFailureIsolation::startRecovery(Event reason) {

@ -17,7 +17,6 @@ class DeviceHandlerFailureIsolation : public FailureIsolationBase {
uint8_t eventQueueDepth = 10); uint8_t eventQueueDepth = 10);
~DeviceHandlerFailureIsolation(); ~DeviceHandlerFailureIsolation();
ReturnValue_t initialize(); ReturnValue_t initialize();
void triggerEvent(Event event, uint32_t parameter1 = 0, uint32_t parameter2 = 0);
bool isFdirActionInProgress(); bool isFdirActionInProgress();
virtual ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueId, virtual ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueId,
ParameterWrapper* parameterWrapper, ParameterWrapper* parameterWrapper,
@ -41,6 +40,19 @@ class DeviceHandlerFailureIsolation : public FailureIsolationBase {
static const uint32_t DEFAULT_MAX_MISSED_REPLY_COUNT = 5; static const uint32_t DEFAULT_MAX_MISSED_REPLY_COUNT = 5;
static const uint32_t DEFAULT_MISSED_REPLY_TIME_MS = 10000; 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 ReturnValue_t eventReceived(EventMessage* event);
virtual void eventConfirmed(EventMessage* event); virtual void eventConfirmed(EventMessage* event);
void wasParentsFault(EventMessage* event); void wasParentsFault(EventMessage* event);

@ -85,6 +85,7 @@ class DeviceHandlerIF {
static const ReturnValue_t NO_REPLY_EXPECTED = MAKE_RETURN_CODE(0xA8); 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 NON_OP_TEMPERATURE = MAKE_RETURN_CODE(0xA9);
static const ReturnValue_t COMMAND_NOT_IMPLEMENTED = MAKE_RETURN_CODE(0xAA); 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 // Standard codes used in scanForReply
static const ReturnValue_t CHECKSUM_ERROR = MAKE_RETURN_CODE(0xB0); static const ReturnValue_t CHECKSUM_ERROR = MAKE_RETURN_CODE(0xB0);

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

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

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

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

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

@ -1,9 +1,12 @@
#ifndef MATRIXOPERATIONS_H_ #ifndef MATRIXOPERATIONS_H_
#define MATRIXOPERATIONS_H_ #define MATRIXOPERATIONS_H_
#include <fsfw/retval.h>
#include <stdint.h> #include <stdint.h>
#include <cmath> #include <cmath>
#include <cstring>
#include <utility>
template <typename T1, typename T2 = T1, typename T3 = T2> template <typename T1, typename T2 = T1, typename T3 = T2>
class MatrixOperations { 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_ */ #endif /* MATRIXOPERATIONS_H_ */

@ -39,6 +39,48 @@ void QuaternionOperations::inverse(const double* quaternion, double* inverseQuat
VectorOperations<double>::mulScalar(inverseQuaternion, -1, inverseQuaternion, 3); 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() {} QuaternionOperations::QuaternionOperations() {}
void QuaternionOperations::normalize(const double* quaternion, double* unitQuaternion) { 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);
}

@ -23,6 +23,13 @@ class QuaternionOperations {
static void inverse(const double *quaternion, double *inverseQuaternion); 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 * returns angle in ]-Pi;Pi] or [0;Pi] if abs == true
*/ */

@ -99,6 +99,15 @@ class VectorOperations {
static void copy(const T *in, T *out, uint8_t size) { mulScalar(in, 1, out, size); } 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: private:
VectorOperations(); VectorOperations();
}; };

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

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

@ -123,6 +123,7 @@ class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableOb
StorageManagerIF* tmStore = nullptr; StorageManagerIF* tmStore = nullptr;
private: private:
//! [EXPORT] : [SKIP]
static constexpr ReturnValue_t CONN_BROKEN = returnvalue::makeCode(1, 0); static constexpr ReturnValue_t CONN_BROKEN = returnvalue::makeCode(1, 0);
//! TMTC bridge is cached. //! TMTC bridge is cached.
object_id_t tmtcBridgeId = objects::NO_OBJECT; object_id_t tmtcBridgeId = objects::NO_OBJECT;

@ -38,6 +38,8 @@ class PowerSwitcherComponent : public SystemObject,
protected: protected:
PowerSwitcher switcher; PowerSwitcher switcher;
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
uint32_t *msToReachTheMode) override;
private: private:
MessageQueueIF *queue = nullptr; MessageQueueIF *queue = nullptr;
@ -56,8 +58,6 @@ class PowerSwitcherComponent : public SystemObject,
[[nodiscard]] MessageQueueId_t getCommandQueue() const override; [[nodiscard]] MessageQueueId_t getCommandQueue() const override;
void getMode(Mode_t *mode, Submode_t *submode) override; void getMode(Mode_t *mode, Submode_t *submode) override;
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
uint32_t *msToReachTheMode) override;
void startTransition(Mode_t mode, Submode_t submode) override; void startTransition(Mode_t mode, Submode_t submode) override;
virtual void performFaultyOperation(); virtual void performFaultyOperation();
void setToExternalControl() override; void setToExternalControl() override;

@ -43,6 +43,7 @@ class Service11TelecommandScheduling final : public PusServiceBase {
static constexpr ReturnValue_t INVALID_RELATIVE_TIME = returnvalue::makeCode(CLASS_ID, 4); static constexpr ReturnValue_t INVALID_RELATIVE_TIME = returnvalue::makeCode(CLASS_ID, 4);
static constexpr ReturnValue_t CONTAINED_TC_TOO_SMALL = returnvalue::makeCode(CLASS_ID, 5); static constexpr ReturnValue_t CONTAINED_TC_TOO_SMALL = returnvalue::makeCode(CLASS_ID, 5);
static constexpr ReturnValue_t CONTAINED_TC_CRC_MISSMATCH = returnvalue::makeCode(CLASS_ID, 6); static constexpr ReturnValue_t CONTAINED_TC_CRC_MISSMATCH = returnvalue::makeCode(CLASS_ID, 6);
static constexpr ReturnValue_t MAP_IS_FULL = returnvalue::makeCode(CLASS_ID, 7);
static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PUS_SERVICE_11; static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PUS_SERVICE_11;

@ -150,6 +150,9 @@ inline ReturnValue_t Service11TelecommandScheduling<MAX_NUM_TCS>::handleResetCom
template <size_t MAX_NUM_TCS> template <size_t MAX_NUM_TCS>
inline ReturnValue_t Service11TelecommandScheduling<MAX_NUM_TCS>::doInsertActivity( inline ReturnValue_t Service11TelecommandScheduling<MAX_NUM_TCS>::doInsertActivity(
const uint8_t *data, size_t size) { const uint8_t *data, size_t size) {
if (telecommandMap.full()) {
return MAP_IS_FULL;
}
uint32_t timestamp = 0; uint32_t timestamp = 0;
ReturnValue_t result = SerializeAdapter::deSerialize(&timestamp, &data, &size, DEF_END); ReturnValue_t result = SerializeAdapter::deSerialize(&timestamp, &data, &size, DEF_END);
if (result != returnvalue::OK) { if (result != returnvalue::OK) {

@ -2,9 +2,9 @@
#include <cmath> #include <cmath>
#include "fsfw/events/EventManagerIF.h"
#include "fsfw/pus/servicepackets/Service9Packets.h" #include "fsfw/pus/servicepackets/Service9Packets.h"
#include "fsfw/serviceinterface/ServiceInterface.h" #include "fsfw/returnvalues/returnvalue.h"
#include "fsfw/serialize/SerializeAdapter.h"
#include "fsfw/timemanager/CCSDSTime.h" #include "fsfw/timemanager/CCSDSTime.h"
Service9TimeManagement::Service9TimeManagement(PsbParams params) : PusServiceBase(params) { Service9TimeManagement::Service9TimeManagement(PsbParams params) : PusServiceBase(params) {
@ -18,16 +18,53 @@ ReturnValue_t Service9TimeManagement::performService() { return returnvalue::OK;
ReturnValue_t Service9TimeManagement::handleRequest(uint8_t subservice) { ReturnValue_t Service9TimeManagement::handleRequest(uint8_t subservice) {
switch (subservice) { switch (subservice) {
case Subservice::SET_TIME: { case Subservice::SET_TIME: {
return setTime(); reportCurrentTime(CLOCK_DUMP_BEFORE_SETTING_TIME);
ReturnValue_t result = setTime();
reportCurrentTime(CLOCK_DUMP_AFTER_SETTING_TIME);
return result;
} }
case Subservice::DUMP_TIME: { case Subservice::DUMP_TIME: {
timeval newTime; reportCurrentTime();
Clock::getClock_timeval(&newTime);
uint32_t subsecondMs =
static_cast<uint32_t>(std::floor(static_cast<double>(newTime.tv_usec) / 1000.0));
triggerEvent(CLOCK_DUMP, newTime.tv_sec, subsecondMs);
return returnvalue::OK; return returnvalue::OK;
} }
case Subservice::RELATIVE_TIMESHIFT: {
timeval currentTime;
ReturnValue_t result = Clock::getClock(&currentTime);
if (result != returnvalue::OK) {
return result;
}
reportTime(CLOCK_DUMP_BEFORE_SETTING_TIME, currentTime);
if (currentPacket.getUserDataLen() != 8) {
return AcceptsTelecommandsIF::ILLEGAL_APPLICATION_DATA;
}
size_t deserLen = 8;
int64_t timeshiftNanos = 0;
result = SerializeAdapter::deSerialize(&timeshiftNanos, currentPacket.getUserData(),
&deserLen, SerializeIF::Endianness::NETWORK);
if (result != returnvalue::OK) {
return result;
}
bool positiveShift = true;
if (timeshiftNanos < 0) {
positiveShift = false;
}
timeval offset{};
offset.tv_sec = std::abs(timeshiftNanos) / NANOS_PER_SECOND;
offset.tv_usec = (std::abs(timeshiftNanos) % NANOS_PER_SECOND) / 1000;
timeval newTime;
if (positiveShift) {
newTime = currentTime + offset;
} else {
newTime = currentTime - offset;
}
result = Clock::setClock(&newTime);
if (result == returnvalue::OK) {
reportTime(CLOCK_DUMP_AFTER_SETTING_TIME, newTime);
}
return result;
}
default: default:
return AcceptsTelecommandsIF::INVALID_SUBSERVICE; return AcceptsTelecommandsIF::INVALID_SUBSERVICE;
} }
@ -43,17 +80,20 @@ ReturnValue_t Service9TimeManagement::setTime() {
return result; return result;
} }
timeval time;
Clock::getClock_timeval(&time);
result = Clock::setClock(&timeToSet); result = Clock::setClock(&timeToSet);
if (result != returnvalue::OK) {
if (result == returnvalue::OK) {
timeval newTime;
Clock::getClock_timeval(&newTime);
triggerEvent(CLOCK_SET, time.tv_sec, newTime.tv_sec);
return returnvalue::OK;
} else {
triggerEvent(CLOCK_SET_FAILURE, result, 0); triggerEvent(CLOCK_SET_FAILURE, result, 0);
return returnvalue::FAILED; return returnvalue::FAILED;
} }
return result;
}
void Service9TimeManagement::reportCurrentTime(Event event) {
timeval currentTime{};
Clock::getClock(&currentTime);
triggerEvent(event, currentTime.tv_sec, currentTime.tv_usec);
}
void Service9TimeManagement::reportTime(Event event, timeval time) {
triggerEvent(event, time.tv_sec, time.tv_usec);
} }

@ -1,18 +1,25 @@
#ifndef FSFW_PUS_SERVICE9TIMEMANAGEMENT_H_ #ifndef FSFW_PUS_SERVICE9TIMEMANAGEMENT_H_
#define FSFW_PUS_SERVICE9TIMEMANAGEMENT_H_ #define FSFW_PUS_SERVICE9TIMEMANAGEMENT_H_
#include "fsfw/returnvalues/returnvalue.h"
#include "fsfw/tmtcservices/PusServiceBase.h" #include "fsfw/tmtcservices/PusServiceBase.h"
class Service9TimeManagement : public PusServiceBase { class Service9TimeManagement : public PusServiceBase {
public: public:
static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PUS_SERVICE_9; static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PUS_SERVICE_9;
//!< Clock has been set. P1: old timeval seconds. P2: new timeval seconds. static constexpr uint32_t NANOS_PER_SECOND = 1'000'000'000;
//!< [EXPORT] : [COMMENT] Clock has been set. P1: old timeval seconds. P2: new timeval seconds.
static constexpr Event CLOCK_SET = MAKE_EVENT(0, severity::INFO); static constexpr Event CLOCK_SET = MAKE_EVENT(0, severity::INFO);
//!< Clock dump event. P1: timeval seconds P2: timeval milliseconds. //!< [EXPORT] : [COMMENT] Clock dump event. P1: timeval seconds P2: timeval milliseconds.
static constexpr Event CLOCK_DUMP = MAKE_EVENT(1, severity::INFO); static constexpr Event CLOCK_DUMP_LEGACY = MAKE_EVENT(1, severity::INFO);
//!< Clock could not be set. P1: Returncode. //!< [EXPORT] : [COMMENT] Clock could not be set. P1: Returncode.
static constexpr Event CLOCK_SET_FAILURE = MAKE_EVENT(2, severity::LOW); static constexpr Event CLOCK_SET_FAILURE = MAKE_EVENT(2, severity::LOW);
//!< [EXPORT] : [COMMENT] Clock dump event. P1: timeval seconds P2: timeval microseconds.
static constexpr Event CLOCK_DUMP = MAKE_EVENT(3, severity::INFO);
static constexpr Event CLOCK_DUMP_BEFORE_SETTING_TIME = MAKE_EVENT(4, severity::INFO);
static constexpr Event CLOCK_DUMP_AFTER_SETTING_TIME = MAKE_EVENT(5, severity::INFO);
static constexpr uint8_t CLASS_ID = CLASS_ID::PUS_SERVICE_9; static constexpr uint8_t CLASS_ID = CLASS_ID::PUS_SERVICE_9;
@ -30,12 +37,16 @@ class Service9TimeManagement : public PusServiceBase {
*/ */
ReturnValue_t handleRequest(uint8_t subservice) override; ReturnValue_t handleRequest(uint8_t subservice) override;
void reportCurrentTime(Event eventType = CLOCK_DUMP);
void reportTime(Event event, timeval time);
virtual ReturnValue_t setTime(); virtual ReturnValue_t setTime();
private: private:
enum Subservice { enum Subservice {
SET_TIME = 128, //!< [EXPORT] : [COMMAND] Time command in ASCII, CUC or CDS format SET_TIME = 128, //!< [EXPORT] : [COMMAND] Time command in ASCII, CUC or CDS format
DUMP_TIME = 129, DUMP_TIME = 129,
RELATIVE_TIMESHIFT = 130,
}; };
}; };

@ -61,7 +61,8 @@ enum : uint8_t {
HAS_ACTIONS_IF, // HF HAS_ACTIONS_IF, // HF
DEVICE_COMMUNICATION_IF, // DC DEVICE_COMMUNICATION_IF, // DC
BSP, // BSP BSP, // BSP
CFDP, // CFDP CFDP_BASE, // CFDP
CFDP_HANDLER, // CFDP
TIME_STAMPER_IF, // TSI TIME_STAMPER_IF, // TSI
SGP4PROPAGATOR_CLASS, // SGP4 SGP4PROPAGATOR_CLASS, // SGP4
MUTEX_IF, // MUX MUTEX_IF, // MUX

@ -107,14 +107,6 @@ uint8_t* SerialBufferAdapter<count_t>::getBuffer() {
template <typename count_t> template <typename count_t>
const uint8_t* SerialBufferAdapter<count_t>::getConstBuffer() const { const uint8_t* SerialBufferAdapter<count_t>::getConstBuffer() const {
if (constBuffer == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "SerialBufferAdapter::getConstBuffer:"
" Buffers are unitialized!"
<< std::endl;
#endif
return nullptr;
}
return constBuffer; return constBuffer;
} }

@ -63,7 +63,17 @@ class SerialBufferAdapter : public SerializeIF {
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
Endianness streamEndianness) override; Endianness streamEndianness) override;
/**
* Please note that this function can also return a nullpointer in case the length field contains
* 0.
* @return
*/
uint8_t* getBuffer(); uint8_t* getBuffer();
/**
* Please note that this function can also return a nullpointer in case the length field contains
* 0.
* @return
*/
[[nodiscard]] const uint8_t* getConstBuffer() const; [[nodiscard]] const uint8_t* getConstBuffer() const;
void setConstBuffer(const uint8_t* buf, count_t bufLen); void setConstBuffer(const uint8_t* buf, count_t bufLen);

@ -89,7 +89,7 @@ ReturnValue_t LocalPool::deleteData(store_address_t storeId) {
ReturnValue_t status = returnvalue::OK; ReturnValue_t status = returnvalue::OK;
size_type pageSize = getSubpoolElementSize(storeId.poolIndex); size_type pageSize = getSubpoolElementSize(storeId.poolIndex);
if ((pageSize != 0) and (storeId.packetIndex < numberOfElements[storeId.poolIndex])) { if ((pageSize != 0) and (storeId.packetIndex < numberOfElements[storeId.poolIndex])) {
uint16_t packetPosition = getRawPosition(storeId); size_type packetPosition = getRawPosition(storeId);
uint8_t* ptr = &store[storeId.poolIndex][packetPosition]; uint8_t* ptr = &store[storeId.poolIndex][packetPosition];
std::memset(ptr, 0, pageSize); std::memset(ptr, 0, pageSize);
// Set free list // Set free list

@ -40,7 +40,7 @@ void PusServiceBase::setTaskIF(PeriodicTaskIF* taskHandle_) { this->taskHandle =
void PusServiceBase::handleRequestQueue() { void PusServiceBase::handleRequestQueue() {
TmTcMessage message; TmTcMessage message;
ReturnValue_t result; ReturnValue_t result;
for (uint8_t count = 0; count < PUS_SERVICE_MAX_RECEPTION; count++) { for (uint8_t count = 0; count < psbParams.maxPacketsPerCycle; count++) {
ReturnValue_t status = psbParams.reqQueue->receiveMessage(&message); ReturnValue_t status = psbParams.reqQueue->receiveMessage(&message);
if (status == MessageQueueIF::EMPTY) { if (status == MessageQueueIF::EMPTY) {
break; break;
@ -98,7 +98,7 @@ ReturnValue_t PusServiceBase::initialize() {
} }
if (psbParams.reqQueue == nullptr) { if (psbParams.reqQueue == nullptr) {
ownedQueue = true; ownedQueue = true;
psbParams.reqQueue = QueueFactory::instance()->createMessageQueue(PSB_DEFAULT_QUEUE_DEPTH); psbParams.reqQueue = QueueFactory::instance()->createMessageQueue(psbParams.requestQueueDepth);
} else { } else {
ownedQueue = false; ownedQueue = false;
} }

@ -20,6 +20,14 @@ class StorageManagerIF;
* Configuration parameters for the PUS Service Base * Configuration parameters for the PUS Service Base
*/ */
struct PsbParams { struct PsbParams {
static constexpr uint8_t PSB_DEFAULT_QUEUE_DEPTH = 10;
/**
* This constant sets the maximum number of packets accepted per call.
* Remember that one packet must be completely handled in one
* #handleRequest call.
*/
static constexpr uint8_t MAX_PACKETS_PER_CYCLE = 10;
PsbParams() = default; PsbParams() = default;
PsbParams(uint16_t apid, AcceptsTelemetryIF* tmReceiver) : apid(apid), tmReceiver(tmReceiver) {} PsbParams(uint16_t apid, AcceptsTelemetryIF* tmReceiver) : apid(apid), tmReceiver(tmReceiver) {}
PsbParams(const char* name, uint16_t apid, AcceptsTelemetryIF* tmReceiver) PsbParams(const char* name, uint16_t apid, AcceptsTelemetryIF* tmReceiver)
@ -32,6 +40,9 @@ struct PsbParams {
object_id_t objectId = objects::NO_OBJECT; object_id_t objectId = objects::NO_OBJECT;
uint16_t apid = 0; uint16_t apid = 0;
uint8_t serviceId = 0; uint8_t serviceId = 0;
uint32_t requestQueueDepth = PSB_DEFAULT_QUEUE_DEPTH;
uint32_t maxPacketsPerCycle = MAX_PACKETS_PER_CYCLE;
/** /**
* The default destination ID for generated telemetry. If this is not set, @initialize of PSB * The default destination ID for generated telemetry. If this is not set, @initialize of PSB
* will attempt to find a suitable object with the object ID @PusServiceBase::packetDestination * will attempt to find a suitable object with the object ID @PusServiceBase::packetDestination
@ -100,14 +111,6 @@ class PusServiceBase : public ExecutableObjectIF,
friend void Factory::setStaticFrameworkObjectIds(); friend void Factory::setStaticFrameworkObjectIds();
public: public:
/**
* This constant sets the maximum number of packets accepted per call.
* Remember that one packet must be completely handled in one
* #handleRequest call.
*/
static constexpr uint8_t PUS_SERVICE_MAX_RECEPTION = 10;
static constexpr uint8_t PSB_DEFAULT_QUEUE_DEPTH = 10;
/** /**
* @brief The passed values are set, but inter-object initialization is * @brief The passed values are set, but inter-object initialization is
* done in the initialize method. * done in the initialize method.

@ -23,18 +23,8 @@ TmTcBridge::TmTcBridge(const char* name, object_id_t objectId, object_id_t tcDes
TmTcBridge::~TmTcBridge() { QueueFactory::instance()->deleteMessageQueue(tmTcReceptionQueue); } TmTcBridge::~TmTcBridge() { QueueFactory::instance()->deleteMessageQueue(tmTcReceptionQueue); }
ReturnValue_t TmTcBridge::setNumberOfSentPacketsPerCycle(uint8_t sentPacketsPerCycle) { void TmTcBridge::setNumberOfSentPacketsPerCycle(uint32_t sentPacketsPerCycle_) {
if (sentPacketsPerCycle <= LIMIT_STORED_DATA_SENT_PER_CYCLE) { this->sentPacketsPerCycle = sentPacketsPerCycle_;
this->sentPacketsPerCycle = sentPacketsPerCycle;
return returnvalue::OK;
} else {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "TmTcBridge::setNumberOfSentPacketsPerCycle: Number of "
<< "packets sent per cycle exceeds limits. "
<< "Keeping default value." << std::endl;
#endif
return returnvalue::FAILED;
}
} }
ReturnValue_t TmTcBridge::setMaxNumberOfPacketsStored(unsigned int maxNumberOfPacketsStored) { ReturnValue_t TmTcBridge::setMaxNumberOfPacketsStored(unsigned int maxNumberOfPacketsStored) {
@ -144,8 +134,8 @@ ReturnValue_t TmTcBridge::handleTmQueue() {
#endif #endif
#endif /* FSFW_VERBOSE_LEVEL >= 3 */ #endif /* FSFW_VERBOSE_LEVEL >= 3 */
if (communicationLinkUp == false or packetSentCounter >= sentPacketsPerCycle) { if (!communicationLinkUp or packetSentCounter >= sentPacketsPerCycle) {
ReturnValue_t result = storeDownlinkData(&message); result = storeDownlinkData(&message);
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
tmStore->deleteData(message.getStorageId()); tmStore->deleteData(message.getStorageId());
} }

@ -15,10 +15,9 @@ class TmTcBridge : public AcceptsTelemetryIF,
public ExecutableObjectIF, public ExecutableObjectIF,
public SystemObject { public SystemObject {
public: public:
static constexpr uint8_t LIMIT_STORED_DATA_SENT_PER_CYCLE = 15;
static constexpr unsigned int LIMIT_DOWNLINK_PACKETS_STORED = 500; static constexpr unsigned int LIMIT_DOWNLINK_PACKETS_STORED = 500;
static constexpr uint8_t DEFAULT_STORED_DATA_SENT_PER_CYCLE = 5; static constexpr uint8_t DEFAULT_STORED_DATA_SENT_PER_CYCLE = 20;
static constexpr uint8_t DEFAULT_DOWNLINK_PACKETS_STORED = 10; static constexpr uint8_t DEFAULT_DOWNLINK_PACKETS_STORED = 10;
TmTcBridge(const char* name, object_id_t objectId, object_id_t tcDestination, TmTcBridge(const char* name, object_id_t objectId, object_id_t tcDestination,
@ -32,7 +31,7 @@ class TmTcBridge : public AcceptsTelemetryIF,
* @return -@c returnvalue::OK if value was set successfully * @return -@c returnvalue::OK if value was set successfully
* -@c returnvalue::FAILED otherwise, stored value stays the same * -@c returnvalue::FAILED otherwise, stored value stays the same
*/ */
ReturnValue_t setNumberOfSentPacketsPerCycle(uint8_t sentPacketsPerCycle); void setNumberOfSentPacketsPerCycle(uint32_t sentPacketsPerCycle);
/** /**
* Set number of packets sent per performOperation().Please note that this * Set number of packets sent per performOperation().Please note that this
@ -151,7 +150,7 @@ class TmTcBridge : public AcceptsTelemetryIF,
* This FIFO can be used to store downlink data which can not be sent at the moment. * This FIFO can be used to store downlink data which can not be sent at the moment.
*/ */
DynamicFIFO<store_address_t>* tmFifo = nullptr; DynamicFIFO<store_address_t>* tmFifo = nullptr;
uint8_t sentPacketsPerCycle = DEFAULT_STORED_DATA_SENT_PER_CYCLE; uint32_t sentPacketsPerCycle = DEFAULT_STORED_DATA_SENT_PER_CYCLE;
unsigned int maxNumberOfPacketsStored = DEFAULT_DOWNLINK_PACKETS_STORED; unsigned int maxNumberOfPacketsStored = DEFAULT_DOWNLINK_PACKETS_STORED;
}; };

@ -0,0 +1 @@
target_sources(${LIB_FSFW_NAME} PRIVATE)

@ -0,0 +1,19 @@
#pragma once
#include <cstdint>
class ProvidesSeqCountIF {
public:
virtual ~ProvidesSeqCountIF() = default;
[[nodiscard]] virtual unsigned int bitWidth() const = 0;
virtual uint64_t get() = 0;
virtual void increment() = 0;
virtual uint64_t getAndIncrement() {
uint64_t val = get();
increment();
return val;
}
};

@ -0,0 +1,25 @@
#pragma once
#include <type_traits>
#include "ProvidesSeqCountIF.h"
template <typename T>
class SeqCountProvider : public ProvidesSeqCountIF {
static_assert(std::is_same<T, uint8_t>::value || std::is_same<T, uint16_t>::value ||
std::is_same<T, uint32_t>::value,
"Only uint8_t, uint16_t, and uint32_t are allowed.");
public:
[[nodiscard]] unsigned int bitWidth() const override { return sizeof(T) * 8; }
uint64_t get() override { return counter; }
// I'm also abusing the primitive C variable overflow wrap around here.
void increment() override { counter++; }
private:
T counter{};
};
using SeqCountProviderU8 = SeqCountProvider<uint8_t>;
using SeqCountProviderU16 = SeqCountProvider<uint16_t>;
using SeqCountProviderU32 = SeqCountProvider<uint32_t>;

@ -184,3 +184,11 @@ ReturnValue_t HostFilesystem::getBaseFilename(FilesystemParams params, char *nam
baseNameLen = baseName.size(); baseNameLen = baseName.size();
return returnvalue::OK; return returnvalue::OK;
} }
bool HostFilesystem::getFileSize(FilesystemParams params, uint64_t &fileSize) {
if (!fileExists(params)) {
return false;
}
fileSize = std::filesystem::file_size(params.path);
return true;
}

@ -11,6 +11,7 @@ class HostFilesystem : public HasFileSystemIF {
ReturnValue_t getBaseFilename(FilesystemParams params, char *nameBuf, size_t maxLen, ReturnValue_t getBaseFilename(FilesystemParams params, char *nameBuf, size_t maxLen,
size_t &baseNameLen) override; size_t &baseNameLen) override;
virtual bool getFileSize(FilesystemParams params, uint64_t &fileSize) override;
bool isDirectory(const char *path) override; bool isDirectory(const char *path) override;
bool fileExists(FilesystemParams params) override; bool fileExists(FilesystemParams params) override;
ReturnValue_t truncateFile(FilesystemParams params) override; ReturnValue_t truncateFile(FilesystemParams params) override;

@ -1,6 +1,8 @@
#include <fsfw_hal/linux/serial/helper.h> #include <fsfw_hal/linux/serial/helper.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <termios.h>
#include "FSFWConfig.h"
#include "fsfw/serviceinterface.h" #include "fsfw/serviceinterface.h"
void serial::setMode(struct termios& options, UartModes mode) { void serial::setMode(struct termios& options, UartModes mode) {
@ -108,7 +110,7 @@ void serial::setBaudrate(struct termios& options, UartBaudRate baud) {
#endif // ! __APPLE__ #endif // ! __APPLE__
default: default:
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "UartComIF::configureBaudrate: Baudrate not supported" << std::endl; sif::warning << "serial::configureBaudrate: Baudrate not supported" << std::endl;
#endif #endif
break; break;
} }
@ -153,15 +155,17 @@ int serial::readCountersAndErrors(int serialPort, serial_icounter_struct& icount
} }
void serial::setStopbits(struct termios& options, StopBits bits) { void serial::setStopbits(struct termios& options, StopBits bits) {
// Regular case: One stop bit.
options.c_cflag &= ~CSTOPB;
if (bits == StopBits::TWO_STOP_BITS) { if (bits == StopBits::TWO_STOP_BITS) {
// Use two stop bits // Use two stop bits
options.c_cflag |= CSTOPB; options.c_cflag |= CSTOPB;
} else {
// Clear stop field, only one stop bit used in communication
options.c_cflag &= ~CSTOPB;
} }
} }
void serial::flushRxBuf(int fd) { tcflush(fd, TCIFLUSH); } void serial::flushRxBuf(int fd) { tcflush(fd, TCIFLUSH); }
void serial::flushTxBuf(int fd) { tcflush(fd, TCOFLUSH); }
void serial::flushTxRxBuf(int fd) { tcflush(fd, TCIOFLUSH); } void serial::flushTxRxBuf(int fd) { tcflush(fd, TCIOFLUSH); }

@ -65,6 +65,7 @@ void setParity(struct termios& options, Parity parity);
void ignoreCtrlLines(struct termios& options); void ignoreCtrlLines(struct termios& options);
void flushRxBuf(int fd); void flushRxBuf(int fd);
void flushTxBuf(int fd);
void flushTxRxBuf(int fd); void flushTxRxBuf(int fd);
int readCountersAndErrors(int serialPort, serial_icounter_struct& icounter); int readCountersAndErrors(int serialPort, serial_icounter_struct& icounter);

@ -282,7 +282,7 @@ ReturnValue_t SpiComIF::handlePollingSendOperation(uint8_t *recvPtr, SPI_HandleT
#endif #endif
#endif #endif
spiCookie.setTransferState(spi::TransferStates::FAILURE); spiCookie.setTransferState(spi::TransferStates::FAILURE);
return spi::HAL_TIMEOUT_RETVAL; return spi::TIMEOUT;
} }
case (HAL_ERROR): case (HAL_ERROR):
default: { default: {
@ -296,7 +296,7 @@ ReturnValue_t SpiComIF::handlePollingSendOperation(uint8_t *recvPtr, SPI_HandleT
#endif #endif
#endif #endif
spiCookie.setTransferState(spi::TransferStates::FAILURE); spiCookie.setTransferState(spi::TransferStates::FAILURE);
return spi::HAL_ERROR_RETVAL; return spi::GENERIC_ERROR;
} }
} }
return returnvalue::OK; return returnvalue::OK;

@ -9,11 +9,6 @@
namespace spi { namespace spi {
static constexpr uint8_t HAL_SPI_ID = CLASS_ID::HAL_SPI;
static constexpr ReturnValue_t HAL_TIMEOUT_RETVAL = returnvalue::makeCode(HAL_SPI_ID, 0);
static constexpr ReturnValue_t HAL_BUSY_RETVAL = returnvalue::makeCode(HAL_SPI_ID, 1);
static constexpr ReturnValue_t HAL_ERROR_RETVAL = returnvalue::makeCode(HAL_SPI_ID, 2);
enum class TransferStates { IDLE, WAIT, SUCCESS, FAILURE }; enum class TransferStates { IDLE, WAIT, SUCCESS, FAILURE };
enum SpiBus { SPI_1, SPI_2 }; enum SpiBus { SPI_1, SPI_2 };

@ -32,7 +32,7 @@ void Factory::produceFrameworkObjects(void* args) {
setStaticFrameworkObjectIds(); setStaticFrameworkObjectIds();
new EventManager(objects::EVENT_MANAGER, 120); new EventManager(objects::EVENT_MANAGER, 120);
new HealthTable(objects::HEALTH_TABLE); new HealthTable(objects::HEALTH_TABLE);
new InternalErrorReporter(objects::INTERNAL_ERROR_REPORTER, 20, false, 1.0); new InternalErrorReporter(objects::INTERNAL_ERROR_REPORTER, 20, false, 5.0);
{ {
PoolManager::LocalPoolConfig poolCfg = {{100, 16}, {50, 32}, {25, 64}, {15, 128}, {5, 1024}}; PoolManager::LocalPoolConfig poolCfg = {{100, 16}, {50, 32}, {25, 64}, {15, 128}, {5, 1024}};

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