Compare commits

...

156 Commits

Author SHA1 Message Date
0dedd8f2a1 Merge branch 'mueller/cmd-executor' into mueller/master 2021-10-11 20:06:10 +02:00
d693817158 added cmakelists source addition 2021-10-11 20:05:11 +02:00
f3dbf68f7c moved command executor 2021-10-11 20:03:29 +02:00
4130dd9e32 using cmakelists from upstream 2021-10-11 19:38:53 +02:00
2e37bd73e2 deleted timer object 2021-10-11 19:35:35 +02:00
ad68802fe4 Merge branch 'develop' into eive/develop 2021-10-11 19:21:48 +02:00
b985bf5167 Merge pull request 'meier/tcpFix' (#23) from meier/tcpFix into eive/develop
Reviewed-on: #23
2021-10-09 13:28:49 +02:00
Jakob Meier
a578f0390b tcp server also parses TCs when client closes connection 2021-10-08 13:51:32 +02:00
Jakob Meier
8e65833d60 added bind call error string 2021-10-08 13:24:51 +02:00
b6e4b1fc72 Merge pull request 'FSFW Update' (#22) from mueller/fsfw-update into eive/develop
Reviewed-on: #22
2021-10-06 17:50:51 +02:00
db801a0ecc removed unneeded static constexpr 2021-10-05 13:17:34 +02:00
3502ddca7f using pus version enum now 2021-10-05 13:14:26 +02:00
2124f36e36 moved store failure to separate function 2021-10-05 12:50:39 +02:00
91f43d00a2 moved store failure to separate function 2021-10-05 12:47:30 +02:00
a8a1148c65 fixes for PUS A stored 2021-10-05 12:39:57 +02:00
94bd4c7b56 using correct version number now 2021-10-05 01:23:56 +02:00
16fb87e02e Merge pull request 'FSFW Update' (#21) from mueller/unittest-fixes into eive/develop
Reviewed-on: #21
2021-09-29 15:45:39 +02:00
7a3dfc2592 Merge branch 'eive/develop' into mueller/unittest-fixes 2021-09-29 11:35:12 +02:00
3d0ce19981 additional options for c ustom main 2021-09-29 10:58:01 +02:00
04cb8e82f1 improvements and fixes 2021-09-29 10:52:21 +02:00
354e158cc1 format fixes 2021-09-29 09:30:50 +02:00
5ee315f8ca put functions in namespace 2021-09-28 17:42:55 +02:00
69922e77c5 this should work for both OSes 2021-09-28 17:38:35 +02:00
01e380c858 windows fixes 2021-09-28 17:36:27 +02:00
6881c6b66a class id renamed 2021-09-28 16:32:43 +02:00
d4bdf314f7 C++11 adaptions 2021-09-28 16:31:53 +02:00
be8623a4f8 delay configurable 2021-09-28 15:32:58 +02:00
304d7e8e32 space packet parser cleaned up, documentation 2021-09-28 15:30:31 +02:00
f2020b2492 removed obsolete empty ctor 2021-09-28 15:12:23 +02:00
5a045d03a5 wiretapping in runtime config now 2021-09-28 15:10:50 +02:00
c7ce568a30 added function to determine space packet ID
from APID
2021-09-28 14:50:50 +02:00
80ccaede02 refactored space packet parser 2021-09-28 14:14:59 +02:00
5fd7a8c9b7 smaller tweaks 2021-09-28 11:03:17 +02:00
254aac51ec cleaning up 2021-09-28 10:57:21 +02:00
9b7da4d9e6 fixing last bugs 2021-09-27 20:00:01 +02:00
71036bf6b1 something wrong with the socket.. 2021-09-27 18:35:50 +02:00
d6b3167922 tcp keep open implementation done 2021-09-27 18:05:45 +02:00
68fe94d594 PusParser integration 2021-09-27 16:15:51 +02:00
62a6e5da0b added PUS again 2021-09-27 16:11:48 +02:00
45c0074bd7 printout improvements 2021-09-27 15:50:23 +02:00
df0adfb33c added new tcp code 2021-09-27 15:35:09 +02:00
ac2b196883 Merge pull request 'Update Linux GPIO' (#20) from mueller/update-linux-gpio into eive/develop
Reviewed-on: #20
2021-09-27 15:28:19 +02:00
98deac1ef1 Merge branch 'mueller/tm-stack-robustness' into mueller/master 2021-09-27 11:07:02 +02:00
ba6cbde28a Increased TM stack robustness
1. More nullptr check
2. returnvalue for inititalize function which can fail
2021-09-27 11:05:26 +02:00
a84c770dfb type improvements and bugfixes 2021-09-27 10:51:31 +02:00
9546495507 improvements for linux libgpioIF 2021-09-27 10:38:47 +02:00
e227b5dead Merge remote-tracking branch 'origin/eive/develop' into mueller/master 2021-09-27 10:09:31 +02:00
9db5f893d7 Merge pull request 'meier/gpioOpenByLineName' (#19) from meier/gpioOpenByLineName into eive/develop
Reviewed-on: #19
2021-09-27 10:09:13 +02:00
4b3e753e19 Merge branch 'eive/develop' into meier/gpioOpenByLineName 2021-09-27 10:08:04 +02:00
36607c8764 Merge branch 'mueller/added-missing-devicehandlers' into mueller/master 2021-09-26 22:45:58 +02:00
b88e6c0713 Merge branch 'mueller/added-missing-devicehandlers' into mueller/master 2021-09-26 22:39:36 +02:00
6ee2c65187 Merge remote-tracking branch 'upstream/development' into mueller/master 2021-09-26 22:21:22 +02:00
2b6c996364 Merge branch 'mueller/devicehandler-package' into mueller/master 2021-09-25 16:42:49 +02:00
dabb488c9d Merge pull request 'MgmLIS3MDLHandler fix in buildTransitionDeviceCommand' (#18) from meier/fixMgmLIS3MDLHandler into eive/develop
Reviewed-on: #18
2021-09-25 16:37:10 +02:00
Jakob Meier
16b125ef6c Merge branch 'meier/fixMgmLIS3MDLHandler' into meier/gpioOpenByLineName 2021-09-24 15:37:49 +02:00
Jakob Meier
10f8a0fd0e MgmLIS3MDLHandler fix in buildTransitionDeviceCommand 2021-09-24 15:33:55 +02:00
Jakob Meier
48a24d7dba removed gpio type GPIO_REGULAR 2021-09-24 10:21:40 +02:00
e0671a395e indentation 2021-09-23 18:14:40 +02:00
665be0d417 better name for wiretapping define 2021-09-23 18:05:17 +02:00
Jakob Meier
e7df520780 fixed merge conflicts 2021-09-23 17:54:41 +02:00
dd610f0d7e Merge branch 'mueller/master' into eive/develop 2021-09-23 17:34:24 +02:00
0987a160c9 new retval for empty slot list 2021-09-23 17:33:45 +02:00
ceeb0c5388 Merge branch 'eive/develop' of https://egit.irs.uni-stuttgart.de/eive/fsfw into eive/develop 2021-09-23 17:14:31 +02:00
91f7184ebb Merge branch 'mueller/master' into eive/develop 2021-09-23 17:14:25 +02:00
e1a85b47c5 tiny tweaks 2021-09-23 17:13:53 +02:00
a3eb870ba0 Corrected comment 2021-09-23 16:45:37 +02:00
ed2263b5f7 Merge pull request 'Improvements for devices' (#17) from mueller/acs-board-improvements into eive/develop
Reviewed-on: #17
2021-09-23 15:59:20 +02:00
dccc2f0ba7 printout fix SpiComIF 2021-09-23 15:57:50 +02:00
350fbc385c small tweak 2021-09-23 15:22:27 +02:00
c9b343ebcd op divider fixes 2021-09-23 15:20:10 +02:00
81c33d2dc6 added functions to set x,y,z limits 2021-09-23 14:56:20 +02:00
29c74283f1 sanity checks 2021-09-22 18:36:53 +02:00
c51d2df43d printout fix 2021-09-22 16:00:18 +02:00
d3b83f3cf9 API made more consistent 2021-09-22 15:02:34 +02:00
60229da670 Merge pull request 'GPIO Refactoring' (#16) from mueller/gpio-refactoring into eive/develop
Reviewed-on: #16
2021-09-22 14:39:53 +02:00
5c56eda610 fix for raspberry pi code 2021-09-22 12:19:30 +02:00
3d1be94e12 more checks and printouts 2021-09-21 19:27:33 +02:00
8e65d2d3fc refactored GPIO components 2021-09-21 17:31:03 +02:00
8374d495fa Merge remote-tracking branch 'origin/eive/develop' into mueller/master 2021-09-21 16:02:41 +02:00
e02879184b Merge pull request 'added option to open gpio by label instead of gpiochip*' (#15) from meier/gpioOpenByLabel into eive/develop
Reviewed-on: #15
2021-09-21 16:01:28 +02:00
Jakob Meier
70a3749dbe added option to open gpio by label instead of gpiochip* 2021-09-20 18:38:18 +02:00
87b68e84be Merge branch 'mueller/master' of https://egit.irs.uni-stuttgart.de/eive/fsfw into mueller/master 2021-09-20 18:33:03 +02:00
7000ba05c5 Merge pull request 'Update EIVE FSFW' (#14) from mueller/master into eive/develop
Reviewed-on: #14
2021-09-20 18:32:47 +02:00
9948c4f31d Merge branch 'eive/develop' into mueller/master 2021-09-20 18:32:28 +02:00
784a0140f4 tweak op divider divisor 2021-09-20 18:31:52 +02:00
635432d7ba missing return 2021-09-20 18:29:57 +02:00
e8050183f4 better printout 2021-09-17 16:52:31 +02:00
7d44aab98e some tweaks for op divider 2021-09-17 13:07:43 +02:00
4489a61a00 Merge pull request 'Update FSFW' (#13) from mueller/update-fsfw into eive/develop
Reviewed-on: #13
2021-09-17 07:55:57 +02:00
b1a56a71cd Added LIS3MDL to FSFW, per op divider tweak 2021-09-16 18:50:20 +02:00
6d0d04ac23 minor bugfix 2021-09-16 17:33:37 +02:00
8f3edc90ba Merge branch 'eive/develop' into mueller/update-fsfw 2021-09-16 11:43:30 +02:00
7b5334ccec Merge remote-tracking branch 'upstream/development' into eive/develop 2021-09-16 11:40:12 +02:00
a58016859b Merge branch 'develop' into mueller/master 2021-09-16 11:38:56 +02:00
0df8d35802 comment format 2021-09-16 11:36:32 +02:00
823c6ec5fc added RM3100 handler 2021-09-16 11:33:50 +02:00
bc6b29e652 use warning instead of debug 2021-09-15 18:48:09 +02:00
d986ab7720 bugfix for TM packet stored PUS C 2021-09-15 18:37:44 +02:00
bdd7d59d82 reverted some changes 2021-09-15 17:05:52 +02:00
edf33cc10a Merge remote-tracking branch 'upstream/development' into mueller/master 2021-09-15 16:57:42 +02:00
6db5011b14 spi and gyro l3g updates 2021-09-15 16:55:24 +02:00
97494a84df Merge remote-tracking branch 'upstream/development' into mueller/master 2021-09-13 10:59:26 +02:00
40adca5f1d set reply recipient 2021-09-08 17:24:33 +02:00
a8167f5431 added another helper function 2021-09-08 17:02:08 +02:00
41f3d7cf9a better name for function 2021-09-08 16:58:30 +02:00
e6e1936293 Merge remote-tracking branch 'origin/mueller/dhb-periodoc-reply-fix' into mueller/master 2021-09-08 16:21:13 +02:00
15f35f200a Merge remote-tracking branch 'origin/mueller/dhb-bugfixes-improvements' into mueller/master 2021-09-08 16:20:42 +02:00
6b20bb197a Merge branch 'development' into mueller/dhb-bugfixes-improvements 2021-09-08 16:20:04 +02:00
215d01b3ca Merge branch 'mueller/dhb-bugfixes-improvements' into mueller/master 2021-09-08 16:09:03 +02:00
dfe49cc1e5 DHB improvements 2021-09-08 16:08:13 +02:00
73eb11f4f1 bugfixes and improvements 2021-09-08 16:01:46 +02:00
924c150af2 Possible bugfix in DHB
The delayCycles variables needs to be initialized differently
for periodic replies.
It is initialized to the maxDelayCycles value now
2021-09-06 12:05:30 +02:00
469eba3ce2 raised limit 2021-09-06 11:35:14 +02:00
fd2916af11 moved TCP cfg 2021-08-23 09:40:02 +02:00
afd375a7f8 minor fix for canonical read handling 2021-08-22 20:24:50 +02:00
5454169e20 UartComIF: set O_NONBLOCK in canonical mode
When using the non-canonical mode, the file descriptor can be opened
in blocking mode because the VTIME and VMIN termios parameters are
used to configure non-blocking mode. However, in canonical mode, the fd needs to be opened with O_NONBLOCK
2021-08-22 19:48:35 +02:00
7d0377845b printout for unknown command 2021-08-20 15:46:34 +02:00
882da68a2f Merge branch 'mueller/unix-file-guard-fix' into mueller/master 2021-08-19 17:17:03 +02:00
04a1fe7f10 Merge pull request 'Update FSFW' (#12) from mueller/update-fsfw into eive/develop
Reviewed-on: #12
2021-08-18 12:47:31 +02:00
5f79f987ae Merge branch 'eive/develop' into mueller/update-fsfw 2021-08-18 11:27:02 +02:00
1183e5739d using upstream action helper
Will be merged upstream soon
2021-08-18 11:23:45 +02:00
e3697d6d8c fixed printout 2021-08-17 19:50:01 +02:00
406b77ea81 moved SPI wiretapping cfg 2021-08-17 16:34:25 +02:00
8a9eb27458 Merge pull request 'FSFW Update' (#11) from mueller/master into eive/develop
Reviewed-on: #11
2021-08-11 13:13:11 +02:00
1ac372cb89 getter function for UDP port 2021-08-09 18:22:22 +02:00
fb36dc4501 More improvements for TCP/UDP port definition 2021-08-09 18:12:25 +02:00
ba5e2ad8bb Cleaning up TCP and UDP code
Same port number used as before, but some inconsistencies fixed
2021-08-09 16:57:24 +02:00
5a6c81130d Merge remote-tracking branch 'upstream/development' into mueller/master 2021-08-09 16:18:38 +02:00
22e29144b6 Merge remote-tracking branch 'origin/eive/develop' into mueller/master 2021-08-09 11:12:37 +02:00
52bff3985f Merge pull request 'set sequence flags in space packet base' (#9) from meier/spacePacketFlag into eive/develop
Reviewed-on: #9
2021-08-09 11:11:46 +02:00
Jakob.Meier
133820f463 Merge branch 'eive/develop' into meier/spacePacketFlag 2021-08-08 15:32:24 +02:00
Jakob.Meier
8d3fceea8f set sequence flags in space packet base 2021-08-08 15:26:18 +02:00
3704d2b829 bugfix 2021-08-05 18:24:56 +02:00
6073abb12d added some utility to timer module 2021-08-05 18:13:01 +02:00
47bec654a0 Merge pull request 'Update EIVE FSFW' (#8) from mueller/master into eive/develop
Reviewed-on: #8
2021-08-05 16:35:23 +02:00
b2c102b2c1 Service Interface and Bugfix
1. Service Interface looks better now
2. Bugfix in CommandExecutor blocking mode
2021-08-05 16:13:22 +02:00
4202205182 getter function for current state 2021-08-05 16:02:17 +02:00
c8472beb5f added new command executor 2021-08-05 15:42:47 +02:00
1a4a85ceb2 Merge branch 'mueller/master' of https://egit.irs.uni-stuttgart.de/eive/fsfw into mueller/master 2021-08-03 18:38:27 +02:00
7922bf76da corrected README 2021-08-03 18:38:18 +02:00
bb88490cc6 Merge remote-tracking branch 'upstream/mueller/restructuring' into mueller/master 2021-08-03 15:55:38 +02:00
296c587e3d additional nullptr check 2021-08-03 15:29:22 +02:00
0ff81294e7 Merge branch 'eive/develop' of https://egit.irs.uni-stuttgart.de/eive/fsfw into eive/develop 2021-08-02 12:49:50 +02:00
b6e243b8b3 var name clarification 2021-08-02 12:49:40 +02:00
3bbcc42d39 Merge pull request 'type missmatch' (#7) from mohr-patch-1 into eive/develop
Reviewed-on: #7
2021-07-26 19:04:06 +02:00
fc4324a2fa type missmatch 2021-07-26 18:35:53 +02:00
54c028f913 naming adaptions 2021-07-26 13:50:45 +02:00
1f6a5e635f naming fixes 2021-07-26 11:46:58 +02:00
c5b4b01362 Merge branch 'mueller/master' into eive/develop 2021-07-24 15:04:01 +02:00
c5420c7b53 bumped subversion 2021-07-24 14:39:43 +02:00
3e422f51bd corrected version number 2021-07-24 13:43:13 +02:00
d1be0f9843 Merge pull request 'Update framework' (#6) from mueller/master into eive/develop
Reviewed-on: #6
2021-07-23 18:26:39 +02:00
Jakob.Meier
b83259592a uart flush function 2021-07-23 18:06:36 +02:00
a7a4e0f219 api consistent now 2021-07-19 19:03:20 +02:00
bdc5f593e2 Merge remote-tracking branch 'upstream/mueller/master' into mueller/master 2021-07-19 18:50:20 +02:00
10f7185e81 added includes 2021-07-19 13:08:40 +02:00
29 changed files with 1231 additions and 320 deletions

View File

@@ -9,12 +9,13 @@ using gpioId_t = uint16_t;
namespace gpio { namespace gpio {
enum Levels { enum Levels: uint8_t {
LOW = 0, LOW = 0,
HIGH = 1 HIGH = 1,
NONE = 99
}; };
enum Direction { enum Direction: uint8_t {
IN = 0, IN = 0,
OUT = 1 OUT = 1
}; };
@@ -24,16 +25,18 @@ enum GpioOperation {
WRITE WRITE
}; };
enum GpioTypes { enum class GpioTypes {
NONE, NONE,
GPIO_REGULAR_BY_CHIP, GPIO_REGULAR_BY_CHIP,
GPIO_REGULAR_BY_LABEL, GPIO_REGULAR_BY_LABEL,
GPIO_REGULAR_BY_LINE_NAME,
CALLBACK CALLBACK
}; };
static constexpr gpioId_t NO_GPIO = -1; static constexpr gpioId_t NO_GPIO = -1;
using gpio_cb_t = void (*) (gpioId_t gpioId, gpio::GpioOperation gpioOp, int value, void* args); using gpio_cb_t = void (*) (gpioId_t gpioId, gpio::GpioOperation gpioOp, gpio::Levels value,
void* args);
} }
@@ -57,7 +60,7 @@ public:
GpioBase() = default; GpioBase() = default;
GpioBase(gpio::GpioTypes gpioType, std::string consumer, gpio::Direction direction, GpioBase(gpio::GpioTypes gpioType, std::string consumer, gpio::Direction direction,
int initValue): gpio::Levels initValue):
gpioType(gpioType), consumer(consumer),direction(direction), initValue(initValue) {} gpioType(gpioType), consumer(consumer),direction(direction), initValue(initValue) {}
virtual~ GpioBase() {}; virtual~ GpioBase() {};
@@ -66,15 +69,21 @@ public:
gpio::GpioTypes gpioType = gpio::GpioTypes::NONE; gpio::GpioTypes gpioType = gpio::GpioTypes::NONE;
std::string consumer; std::string consumer;
gpio::Direction direction = gpio::Direction::IN; gpio::Direction direction = gpio::Direction::IN;
int initValue = 0; gpio::Levels initValue = gpio::Levels::NONE;
}; };
class GpiodRegularBase: public GpioBase { class GpiodRegularBase: public GpioBase {
public: public:
GpiodRegularBase(gpio::GpioTypes gpioType, std::string consumer, gpio::Direction direction, GpiodRegularBase(gpio::GpioTypes gpioType, std::string consumer, gpio::Direction direction,
int initValue, int lineNum): GpioBase(gpioType, consumer, direction, initValue), gpio::Levels initValue, int lineNum):
lineNum(lineNum) { GpioBase(gpioType, consumer, direction, initValue), lineNum(lineNum) {
} }
// line number will be configured at a later point for the open by line name configuration
GpiodRegularBase(gpio::GpioTypes gpioType, std::string consumer, gpio::Direction direction,
gpio::Levels initValue): GpioBase(gpioType, consumer, direction, initValue) {
}
int lineNum = 0; int lineNum = 0;
struct gpiod_line* lineHandle = nullptr; struct gpiod_line* lineHandle = nullptr;
}; };
@@ -87,7 +96,7 @@ public:
} }
GpiodRegularByChip(std::string chipname_, int lineNum_, std::string consumer_, GpiodRegularByChip(std::string chipname_, int lineNum_, std::string consumer_,
gpio::Direction direction_, int initValue_) : gpio::Direction direction_, gpio::Levels initValue_) :
GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_CHIP, GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_CHIP,
consumer_, direction_, initValue_, lineNum_), consumer_, direction_, initValue_, lineNum_),
chipname(chipname_){ chipname(chipname_){
@@ -105,7 +114,7 @@ public:
class GpiodRegularByLabel: public GpiodRegularBase { class GpiodRegularByLabel: public GpiodRegularBase {
public: public:
GpiodRegularByLabel(std::string label_, int lineNum_, std::string consumer_, GpiodRegularByLabel(std::string label_, int lineNum_, std::string consumer_,
gpio::Direction direction_, int initValue_) : gpio::Direction direction_, gpio::Levels initValue_) :
GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_LABEL, consumer_, GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_LABEL, consumer_,
direction_, initValue_, lineNum_), direction_, initValue_, lineNum_),
label(label_) { label(label_) {
@@ -120,9 +129,30 @@ public:
std::string label; std::string label;
}; };
/**
* @brief Passing this GPIO configuration to the GPIO IF object will try to open the GPIO by its
* line name. This line name can be set in the device tree and must be unique. Otherwise
* the driver will open the first line with the given name.
*/
class GpiodRegularByLineName: public GpiodRegularBase {
public:
GpiodRegularByLineName(std::string lineName_, std::string consumer_, gpio::Direction direction_,
gpio::Levels initValue_) :
GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME, consumer_, direction_,
initValue_), lineName(lineName_) {
}
GpiodRegularByLineName(std::string lineName_, std::string consumer_) :
GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME, consumer_,
gpio::Direction::IN, gpio::LOW), lineName(lineName_) {
}
std::string lineName;
};
class GpioCallback: public GpioBase { class GpioCallback: public GpioBase {
public: public:
GpioCallback(std::string consumer, gpio::Direction direction_, int initValue_, GpioCallback(std::string consumer, gpio::Direction direction_, gpio::Levels initValue_,
gpio::gpio_cb_t callback, void* callbackArgs): gpio::gpio_cb_t callback, void* callbackArgs):
GpioBase(gpio::GpioTypes::CALLBACK, consumer, direction_, initValue_), GpioBase(gpio::GpioTypes::CALLBACK, consumer, direction_, initValue_),
callback(callback), callbackArgs(callbackArgs) {} callback(callback), callbackArgs(callbackArgs) {}

View File

@@ -73,7 +73,7 @@ ReturnValue_t MgmLIS3MDLHandler::buildTransitionDeviceCommand(
switch (internalState) { switch (internalState) {
case(InternalState::STATE_NONE): case(InternalState::STATE_NONE):
case(InternalState::STATE_NORMAL): { case(InternalState::STATE_NORMAL): {
return HasReturnvaluesIF::RETURN_OK; return DeviceHandlerBase::NOTHING_TO_SEND;
} }
case(InternalState::STATE_FIRST_CONTACT): { case(InternalState::STATE_FIRST_CONTACT): {
*id = MGMLIS3MDL::IDENTIFY_DEVICE; *id = MGMLIS3MDL::IDENTIFY_DEVICE;

View File

@@ -4,6 +4,7 @@ endif()
target_sources(${LIB_FSFW_NAME} PRIVATE target_sources(${LIB_FSFW_NAME} PRIVATE
UnixFileGuard.cpp UnixFileGuard.cpp
CommandExecutor.cpp
utility.cpp utility.cpp
) )

View File

@@ -0,0 +1,210 @@
#include "CommandExecutor.h"
#include "fsfw/serviceinterface.h"
#include "fsfw/container/SimpleRingBuffer.h"
#include "fsfw/container/DynamicFIFO.h"
#include <unistd.h>
#include <cstring>
CommandExecutor::CommandExecutor(const size_t maxSize):
readVec(maxSize) {
waiter.events = POLLIN;
}
ReturnValue_t CommandExecutor::load(std::string command, bool blocking, bool printOutput) {
if(state == States::PENDING) {
return COMMAND_PENDING;
}
currentCmd = command;
this->blocking = blocking;
this->printOutput = printOutput;
if(state == States::IDLE) {
state = States::COMMAND_LOADED;
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t CommandExecutor::execute() {
if(state == States::IDLE) {
return NO_COMMAND_LOADED_OR_PENDING;
}
else if(state == States::PENDING) {
return COMMAND_PENDING;
}
currentCmdFile = popen(currentCmd.c_str(), "r");
if(currentCmdFile == nullptr) {
lastError = errno;
return HasReturnvaluesIF::RETURN_FAILED;
}
if(blocking) {
return executeBlocking();
}
else {
currentFd = fileno(currentCmdFile);
waiter.fd = currentFd;
}
state = States::PENDING;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t CommandExecutor::close() {
if(state == States::PENDING) {
// Attempt to close process, irrespective of if it is running or not
if(currentCmdFile != nullptr) {
pclose(currentCmdFile);
}
}
return HasReturnvaluesIF::RETURN_OK;
}
void CommandExecutor::printLastError(std::string funcName) const {
if(lastError != 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << funcName << " pclose failed with code " << lastError << ": " <<
strerror(lastError) << std::endl;
#else
sif::printError("%s pclose failed with code %d: %s\n",
funcName, lastError, strerror(lastError));
#endif
}
}
void CommandExecutor::setRingBuffer(SimpleRingBuffer *ringBuffer,
DynamicFIFO<uint16_t>* sizesFifo) {
this->ringBuffer = ringBuffer;
this->sizesFifo = sizesFifo;
}
ReturnValue_t CommandExecutor::check(bool& bytesRead) {
if(blocking) {
return HasReturnvaluesIF::RETURN_OK;
}
switch(state) {
case(States::IDLE):
case(States::COMMAND_LOADED): {
return NO_COMMAND_LOADED_OR_PENDING;
}
case(States::PENDING): {
break;
}
}
int result = poll(&waiter, 1, 0);
switch(result) {
case(0): {
return HasReturnvaluesIF::RETURN_OK;
break;
}
case(1): {
if (waiter.revents & POLLIN) {
ssize_t readBytes = read(currentFd, readVec.data(), readVec.size());
if(readBytes == 0) {
// Should not happen
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "CommandExecutor::check: No bytes read "
"after poll event.." << std::endl;
#else
sif::printWarning("CommandExecutor::check: No bytes read after poll event..\n");
#endif
break;
}
else if(readBytes > 0) {
bytesRead = true;
if(printOutput) {
// It is assumed the command output is line terminated
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << currentCmd << " | " << readVec.data();
#else
sif::printInfo("%s | %s", currentCmd, readVec.data());
#endif
}
if(ringBuffer != nullptr) {
ringBuffer->writeData(reinterpret_cast<const uint8_t*>(
readVec.data()), readBytes);
}
if(sizesFifo != nullptr) {
if(not sizesFifo->full()) {
sizesFifo->insert(readBytes);
}
}
return BYTES_READ;
}
else {
// Should also not happen
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "CommandExecutor::check: Error " << errno << ": " <<
strerror(errno) << std::endl;
#else
sif::printWarning("CommandExecutor::check: Error %d: %s\n", errno, strerror(errno));
#endif
}
}
else if(waiter.revents & POLLERR) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "CommandExecuter::check: Poll error" << std::endl;
#else
sif::printWarning("CommandExecuter::check: Poll error\n");
#endif
return COMMAND_ERROR;
}
else if(waiter.revents & POLLHUP) {
int result = pclose(currentCmdFile);
if(result != 0) {
lastError = result;
return HasReturnvaluesIF::RETURN_FAILED;
}
state = States::IDLE;
currentCmdFile = nullptr;
currentFd = 0;
return EXECUTION_FINISHED;
}
break;
}
}
return HasReturnvaluesIF::RETURN_OK;
}
void CommandExecutor::reset() {
CommandExecutor::close();
currentCmdFile = nullptr;
currentFd = 0;
state = States::IDLE;
}
int CommandExecutor::getLastError() const {
return this->lastError;
}
CommandExecutor::States CommandExecutor::getCurrentState() const {
return state;
}
ReturnValue_t CommandExecutor::executeBlocking() {
while(fgets(readVec.data(), readVec.size(), currentCmdFile) != nullptr) {
std::string output(readVec.data());
if(printOutput) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << currentCmd << " | " << output;
#else
sif::printInfo("%s | %s", currentCmd, output);
#endif
}
if(ringBuffer != nullptr) {
ringBuffer->writeData(reinterpret_cast<const uint8_t*>(output.data()), output.size());
}
if(sizesFifo != nullptr) {
if(not sizesFifo->full()) {
sizesFifo->insert(output.size());
}
}
}
int result = pclose(currentCmdFile);
if(result != 0) {
lastError = result;
return HasReturnvaluesIF::RETURN_FAILED;
}
return HasReturnvaluesIF::RETURN_OK;
}

View File

@@ -0,0 +1,134 @@
#ifndef FSFW_SRC_FSFW_OSAL_LINUX_COMMANDEXECUTOR_H_
#define FSFW_SRC_FSFW_OSAL_LINUX_COMMANDEXECUTOR_H_
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
#include "fsfw/returnvalues/FwClassIds.h"
#include <poll.h>
#include <string>
#include <vector>
class SimpleRingBuffer;
template <typename T> class DynamicFIFO;
/**
* @brief Helper class to execute shell commands in blocking and non-blocking mode
* @details
* This class is able to execute processes by using the Linux popen call. It also has the
* capability of writing the read output of a process into a provided ring buffer.
*
* The executor works by first loading the command which should be executed and specifying
* whether it should be executed blocking or non-blocking. After that, execution can be started
* with the execute command. In blocking mode, the execute command will block until the command
* has finished
*/
class CommandExecutor {
public:
enum class States {
IDLE,
COMMAND_LOADED,
PENDING
};
static constexpr uint8_t CLASS_ID = CLASS_ID::LINUX_OSAL;
//! [EXPORT] : [COMMENT] Execution of the current command has finished
static constexpr ReturnValue_t EXECUTION_FINISHED =
HasReturnvaluesIF::makeReturnCode(CLASS_ID, 0);
//! [EXPORT] : [COMMENT] Command is pending. This will also be returned if the user tries
//! to load another command but a command is still pending
static constexpr ReturnValue_t COMMAND_PENDING =
HasReturnvaluesIF::makeReturnCode(CLASS_ID, 1);
//! [EXPORT] : [COMMENT] Some bytes have been read from the executing process
static constexpr ReturnValue_t BYTES_READ =
HasReturnvaluesIF::makeReturnCode(CLASS_ID, 2);
//! [EXPORT] : [COMMENT] Command execution failed
static constexpr ReturnValue_t COMMAND_ERROR =
HasReturnvaluesIF::makeReturnCode(CLASS_ID, 3);
//! [EXPORT] : [COMMENT]
static constexpr ReturnValue_t NO_COMMAND_LOADED_OR_PENDING =
HasReturnvaluesIF::makeReturnCode(CLASS_ID, 4);
static constexpr ReturnValue_t PCLOSE_CALL_ERROR =
HasReturnvaluesIF::makeReturnCode(CLASS_ID, 6);
/**
* Constructor. Is initialized with maximum size of internal buffer to read data from the
* executed process.
* @param maxSize
*/
CommandExecutor(const size_t maxSize);
/**
* Load a new command which should be executed
* @param command
* @param blocking
* @param printOutput
* @return
*/
ReturnValue_t load(std::string command, bool blocking, bool printOutput = true);
/**
* Execute the loaded command.
* @return
* - In blocking mode, it will return RETURN_FAILED if
* the result of the system call was not 0. The error value can be accessed using
* getLastError
* - In non-blocking mode, this call will start
* the execution and then return RETURN_OK
*/
ReturnValue_t execute();
/**
* Only used in non-blocking mode. Checks the currently running command.
* @param bytesRead Will be set to the number of bytes read, if bytes have been read
* @return
* - BYTES_READ if bytes have been read from the executing process. It is recommended to call
* check again after this
* - RETURN_OK execution is pending, but no bytes have been read from the executing process
* - RETURN_FAILED if execution has failed, error value can be accessed using getLastError
* - EXECUTION_FINISHED if the process was executed successfully
* - COMMAND_ERROR internal poll error
*/
ReturnValue_t check(bool& bytesRead);
/**
* Abort the current command. Should normally not be necessary, check can be used to find
* out whether command execution was successful
* @return RETURN_OK
*/
ReturnValue_t close();
States getCurrentState() const;
int getLastError() const;
void printLastError(std::string funcName) const;
/**
* Assign a ring buffer and a FIFO which will be filled by the executor with the output
* read from the started process
* @param ringBuffer
* @param sizesFifo
*/
void setRingBuffer(SimpleRingBuffer* ringBuffer, DynamicFIFO<uint16_t>* sizesFifo);
/**
* Reset the executor. This calls close internally and then reset the state machine so new
* commands can be loaded and executed
*/
void reset();
private:
std::string currentCmd;
bool blocking = true;
FILE* currentCmdFile = nullptr;
int currentFd = 0;
bool printOutput = true;
std::vector<char> readVec;
struct pollfd waiter {};
SimpleRingBuffer* ringBuffer = nullptr;
DynamicFIFO<uint16_t>* sizesFifo = nullptr;
States state = States::IDLE;
int lastError = 0;
ReturnValue_t executeBlocking();
};
#endif /* FSFW_SRC_FSFW_OSAL_LINUX_COMMANDEXECUTOR_H_ */

View File

@@ -1,8 +1,9 @@
#include "fsfw_hal/linux/gpio/LinuxLibgpioIF.h" #include "LinuxLibgpioIF.h"
#include "fsfw_hal/common/gpio/gpioDefinitions.h" #include "fsfw_hal/common/gpio/gpioDefinitions.h"
#include "fsfw_hal/common/gpio/GpioCookie.h" #include "fsfw_hal/common/gpio/GpioCookie.h"
#include <fsfw/serviceinterface/ServiceInterface.h> #include "fsfw/serviceinterface/ServiceInterface.h"
#include <utility> #include <utility>
#include <unistd.h> #include <unistd.h>
@@ -66,6 +67,14 @@ ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) {
configureGpioByLabel(gpioConfig.first, *regularGpio); configureGpioByLabel(gpioConfig.first, *regularGpio);
break; break;
} }
case(gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME):{
auto regularGpio = dynamic_cast<GpiodRegularByLineName*>(gpioConfig.second);
if(regularGpio == nullptr) {
return GPIO_INVALID_INSTANCE;
}
configureGpioByLineName(gpioConfig.first, *regularGpio);
break;
}
case(gpio::GpioTypes::CALLBACK): { case(gpio::GpioTypes::CALLBACK): {
auto gpioCallback = dynamic_cast<GpioCallback*>(gpioConfig.second); auto gpioCallback = dynamic_cast<GpioCallback*>(gpioConfig.second);
if(gpioCallback->callback == nullptr) { if(gpioCallback->callback == nullptr) {
@@ -84,13 +93,13 @@ ReturnValue_t LinuxLibgpioIF::configureGpioByLabel(gpioId_t gpioId,
std::string& label = gpioByLabel.label; std::string& label = gpioByLabel.label;
struct gpiod_chip* chip = gpiod_chip_open_by_label(label.c_str()); struct gpiod_chip* chip = gpiod_chip_open_by_label(label.c_str());
if (chip == nullptr) { if (chip == nullptr) {
sif::warning << "LinuxLibgpioIF::configureRegularGpio: Failed to open gpio from gpio " sif::warning << "LinuxLibgpioIF::configureGpioByLabel: Failed to open gpio from gpio "
<< "group with label " << label << ". Gpio ID: " << gpioId << std::endl; << "group with label " << label << ". Gpio ID: " << gpioId << std::endl;
return RETURN_FAILED; return RETURN_FAILED;
} }
std::string failOutput = "label: " + label; std::string failOutput = "label: " + label;
return configureRegularGpio(gpioId, gpioByLabel.gpioType, chip, gpioByLabel, failOutput); return configureRegularGpio(gpioId, chip, gpioByLabel, failOutput);
} }
ReturnValue_t LinuxLibgpioIF::configureGpioByChip(gpioId_t gpioId, ReturnValue_t LinuxLibgpioIF::configureGpioByChip(gpioId_t gpioId,
@@ -98,16 +107,41 @@ ReturnValue_t LinuxLibgpioIF::configureGpioByChip(gpioId_t gpioId,
std::string& chipname = gpioByChip.chipname; std::string& chipname = gpioByChip.chipname;
struct gpiod_chip* chip = gpiod_chip_open_by_name(chipname.c_str()); struct gpiod_chip* chip = gpiod_chip_open_by_name(chipname.c_str());
if (chip == nullptr) { if (chip == nullptr) {
sif::warning << "LinuxLibgpioIF::configureRegularGpio: Failed to open chip " sif::warning << "LinuxLibgpioIF::configureGpioByChip: Failed to open chip "
<< chipname << ". Gpio ID: " << gpioId << std::endl; << chipname << ". Gpio ID: " << gpioId << std::endl;
return RETURN_FAILED; return RETURN_FAILED;
} }
std::string failOutput = "chipname: " + chipname; std::string failOutput = "chipname: " + chipname;
return configureRegularGpio(gpioId, gpioByChip.gpioType, chip, gpioByChip, failOutput); return configureRegularGpio(gpioId, chip, gpioByChip, failOutput);
} }
ReturnValue_t LinuxLibgpioIF::configureRegularGpio(gpioId_t gpioId, gpio::GpioTypes gpioType, ReturnValue_t LinuxLibgpioIF::configureGpioByLineName(gpioId_t gpioId,
struct gpiod_chip* chip, GpiodRegularBase& regularGpio, std::string failOutput) { GpiodRegularByLineName &gpioByLineName) {
std::string& lineName = gpioByLineName.lineName;
char chipname[MAX_CHIPNAME_LENGTH];
unsigned int lineOffset;
int result = gpiod_ctxless_find_line(lineName.c_str(), chipname, MAX_CHIPNAME_LENGTH,
&lineOffset);
if (result != LINE_FOUND) {
parseFindeLineResult(result, lineName);
return RETURN_FAILED;
}
gpioByLineName.lineNum = static_cast<int>(lineOffset);
struct gpiod_chip* chip = gpiod_chip_open_by_name(chipname);
if (chip == nullptr) {
sif::warning << "LinuxLibgpioIF::configureGpioByLineName: Failed to open chip "
<< chipname << ". <Gpio ID: " << gpioId << std::endl;
return RETURN_FAILED;
}
std::string failOutput = "line name: " + lineName;
return configureRegularGpio(gpioId, chip, gpioByLineName, failOutput);
}
ReturnValue_t LinuxLibgpioIF::configureRegularGpio(gpioId_t gpioId, struct gpiod_chip* chip,
GpiodRegularBase& regularGpio, std::string failOutput) {
unsigned int lineNum; unsigned int lineNum;
gpio::Direction direction; gpio::Direction direction;
std::string consumer; std::string consumer;
@@ -132,22 +166,10 @@ ReturnValue_t LinuxLibgpioIF::configureRegularGpio(gpioId_t gpioId, gpio::GpioTy
case(gpio::OUT): { case(gpio::OUT): {
result = gpiod_line_request_output(lineHandle, consumer.c_str(), result = gpiod_line_request_output(lineHandle, consumer.c_str(),
regularGpio.initValue); regularGpio.initValue);
if (result < 0) {
sif::error << "LinuxLibgpioIF::configureRegularGpio: Failed to request line " << lineNum <<
" from GPIO instance with ID: " << gpioId << std::endl;
gpiod_line_release(lineHandle);
return RETURN_FAILED;
}
break; break;
} }
case(gpio::IN): { case(gpio::IN): {
result = gpiod_line_request_input(lineHandle, consumer.c_str()); result = gpiod_line_request_input(lineHandle, consumer.c_str());
if (result < 0) {
sif::error << "LinuxLibgpioIF::configureGpios: Failed to request line "
<< lineNum << " from GPIO instance with ID: " << gpioId << std::endl;
gpiod_line_release(lineHandle);
return RETURN_FAILED;
}
break; break;
} }
default: { default: {
@@ -156,6 +178,18 @@ ReturnValue_t LinuxLibgpioIF::configureRegularGpio(gpioId_t gpioId, gpio::GpioTy
return GPIO_INVALID_INSTANCE; return GPIO_INVALID_INSTANCE;
} }
if (result < 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "LinuxLibgpioIF::configureRegularGpio: Failed to request line " <<
lineNum << " from GPIO instance with ID: " << gpioId << std::endl;
#else
sif::printError("LinuxLibgpioIF::configureRegularGpio: "
"Failed to request line %d from GPIO instance with ID: %d\n", lineNum, gpioId);
#endif
gpiod_line_release(lineHandle);
return RETURN_FAILED;
}
} }
/** /**
* Write line handle to GPIO configuration instance so it can later be used to set or * Write line handle to GPIO configuration instance so it can later be used to set or
@@ -173,8 +207,9 @@ ReturnValue_t LinuxLibgpioIF::pullHigh(gpioId_t gpioId) {
} }
auto gpioType = gpioMapIter->second->gpioType; auto gpioType = gpioMapIter->second->gpioType;
if(gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_CHIP or if (gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_CHIP
gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_LABEL) { or gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_LABEL
or gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME) {
auto regularGpio = dynamic_cast<GpiodRegularBase*>(gpioMapIter->second); auto regularGpio = dynamic_cast<GpiodRegularBase*>(gpioMapIter->second);
if(regularGpio == nullptr) { if(regularGpio == nullptr) {
return GPIO_TYPE_FAILURE; return GPIO_TYPE_FAILURE;
@@ -187,7 +222,7 @@ ReturnValue_t LinuxLibgpioIF::pullHigh(gpioId_t gpioId) {
return GPIO_INVALID_INSTANCE; return GPIO_INVALID_INSTANCE;
} }
gpioCallback->callback(gpioMapIter->first, gpio::GpioOperation::WRITE, gpioCallback->callback(gpioMapIter->first, gpio::GpioOperation::WRITE,
1, gpioCallback->callbackArgs); gpio::Levels::HIGH, gpioCallback->callbackArgs);
return RETURN_OK; return RETURN_OK;
} }
return GPIO_TYPE_FAILURE; return GPIO_TYPE_FAILURE;
@@ -196,13 +231,18 @@ ReturnValue_t LinuxLibgpioIF::pullHigh(gpioId_t gpioId) {
ReturnValue_t LinuxLibgpioIF::pullLow(gpioId_t gpioId) { ReturnValue_t LinuxLibgpioIF::pullLow(gpioId_t gpioId) {
gpioMapIter = gpioMap.find(gpioId); gpioMapIter = gpioMap.find(gpioId);
if (gpioMapIter == gpioMap.end()) { if (gpioMapIter == gpioMap.end()) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "LinuxLibgpioIF::pullLow: Unknown GPIO ID " << gpioId << std::endl; sif::warning << "LinuxLibgpioIF::pullLow: Unknown GPIO ID " << gpioId << std::endl;
#else
sif::printWarning("LinuxLibgpioIF::pullLow: Unknown GPIO ID %d\n", gpioId);
#endif
return UNKNOWN_GPIO_ID; return UNKNOWN_GPIO_ID;
} }
auto& gpioType = gpioMapIter->second->gpioType; auto& gpioType = gpioMapIter->second->gpioType;
if(gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_CHIP or if (gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_CHIP
gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_LABEL) { or gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_LABEL
or gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME) {
auto regularGpio = dynamic_cast<GpiodRegularBase*>(gpioMapIter->second); auto regularGpio = dynamic_cast<GpiodRegularBase*>(gpioMapIter->second);
if(regularGpio == nullptr) { if(regularGpio == nullptr) {
return GPIO_TYPE_FAILURE; return GPIO_TYPE_FAILURE;
@@ -215,7 +255,7 @@ ReturnValue_t LinuxLibgpioIF::pullLow(gpioId_t gpioId) {
return GPIO_INVALID_INSTANCE; return GPIO_INVALID_INSTANCE;
} }
gpioCallback->callback(gpioMapIter->first, gpio::GpioOperation::WRITE, gpioCallback->callback(gpioMapIter->first, gpio::GpioOperation::WRITE,
0, gpioCallback->callbackArgs); gpio::Levels::LOW, gpioCallback->callbackArgs);
return RETURN_OK; return RETURN_OK;
} }
return GPIO_TYPE_FAILURE; return GPIO_TYPE_FAILURE;
@@ -225,8 +265,13 @@ ReturnValue_t LinuxLibgpioIF::driveGpio(gpioId_t gpioId,
GpiodRegularBase& regularGpio, gpio::Levels logicLevel) { GpiodRegularBase& regularGpio, gpio::Levels logicLevel) {
int result = gpiod_line_set_value(regularGpio.lineHandle, logicLevel); int result = gpiod_line_set_value(regularGpio.lineHandle, logicLevel);
if (result < 0) { if (result < 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "LinuxLibgpioIF::driveGpio: Failed to pull GPIO with ID " << gpioId << sif::warning << "LinuxLibgpioIF::driveGpio: Failed to pull GPIO with ID " << gpioId <<
" to logic level " << logicLevel << std::endl; " to logic level " << logicLevel << std::endl;
#else
sif::printWarning("LinuxLibgpioIF::driveGpio: Failed to pull GPIO with ID %d to "
"logic level %d\n", gpioId, logicLevel);
#endif
return DRIVE_GPIO_FAILURE; return DRIVE_GPIO_FAILURE;
} }
@@ -236,12 +281,18 @@ ReturnValue_t LinuxLibgpioIF::driveGpio(gpioId_t gpioId,
ReturnValue_t LinuxLibgpioIF::readGpio(gpioId_t gpioId, int* gpioState) { ReturnValue_t LinuxLibgpioIF::readGpio(gpioId_t gpioId, int* gpioState) {
gpioMapIter = gpioMap.find(gpioId); gpioMapIter = gpioMap.find(gpioId);
if (gpioMapIter == gpioMap.end()){ if (gpioMapIter == gpioMap.end()){
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "LinuxLibgpioIF::readGpio: Unknown GPIOD ID " << gpioId << std::endl; sif::warning << "LinuxLibgpioIF::readGpio: Unknown GPIOD ID " << gpioId << std::endl;
#else
sif::printWarning("LinuxLibgpioIF::readGpio: Unknown GPIOD ID %d\n", gpioId);
#endif
return UNKNOWN_GPIO_ID; return UNKNOWN_GPIO_ID;
} }
auto gpioType = gpioMapIter->second->gpioType; auto gpioType = gpioMapIter->second->gpioType;
if(gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_CHIP or if (gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_CHIP
gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_LABEL) { or gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_LABEL
or gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME) {
auto regularGpio = dynamic_cast<GpiodRegularBase*>(gpioMapIter->second); auto regularGpio = dynamic_cast<GpiodRegularBase*>(gpioMapIter->second);
if(regularGpio == nullptr) { if(regularGpio == nullptr) {
return GPIO_TYPE_FAILURE; return GPIO_TYPE_FAILURE;
@@ -249,10 +300,14 @@ ReturnValue_t LinuxLibgpioIF::readGpio(gpioId_t gpioId, int* gpioState) {
*gpioState = gpiod_line_get_value(regularGpio->lineHandle); *gpioState = gpiod_line_get_value(regularGpio->lineHandle);
} }
else { else {
auto gpioCallback = dynamic_cast<GpioCallback*>(gpioMapIter->second);
if(gpioCallback->callback == nullptr) {
return GPIO_INVALID_INSTANCE;
}
gpioCallback->callback(gpioMapIter->first, gpio::GpioOperation::READ,
gpio::Levels::NONE, gpioCallback->callbackArgs);
return RETURN_OK;
} }
return RETURN_OK; return RETURN_OK;
} }
@@ -262,13 +317,14 @@ ReturnValue_t LinuxLibgpioIF::checkForConflicts(GpioMap& mapToAdd){
for(auto& gpioConfig: mapToAdd) { for(auto& gpioConfig: mapToAdd) {
switch(gpioConfig.second->gpioType) { switch(gpioConfig.second->gpioType) {
case(gpio::GpioTypes::GPIO_REGULAR_BY_CHIP): case(gpio::GpioTypes::GPIO_REGULAR_BY_CHIP):
case(gpio::GpioTypes::GPIO_REGULAR_BY_LABEL): { case(gpio::GpioTypes::GPIO_REGULAR_BY_LABEL):
case(gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME): {
auto regularGpio = dynamic_cast<GpiodRegularBase*>(gpioConfig.second); auto regularGpio = dynamic_cast<GpiodRegularBase*>(gpioConfig.second);
if(regularGpio == nullptr) { if(regularGpio == nullptr) {
return GPIO_TYPE_FAILURE; return GPIO_TYPE_FAILURE;
} }
/* Check for conflicts and remove duplicates if necessary */ // Check for conflicts and remove duplicates if necessary
result = checkForConflictsRegularGpio(gpioConfig.first, *regularGpio, mapToAdd); result = checkForConflictsById(gpioConfig.first, gpioConfig.second->gpioType, mapToAdd);
if(result != HasReturnvaluesIF::RETURN_OK) { if(result != HasReturnvaluesIF::RETURN_OK) {
status = result; status = result;
} }
@@ -279,66 +335,108 @@ ReturnValue_t LinuxLibgpioIF::checkForConflicts(GpioMap& mapToAdd){
if(callbackGpio == nullptr) { if(callbackGpio == nullptr) {
return GPIO_TYPE_FAILURE; return GPIO_TYPE_FAILURE;
} }
/* Check for conflicts and remove duplicates if necessary */ // Check for conflicts and remove duplicates if necessary
result = checkForConflictsCallbackGpio(gpioConfig.first, callbackGpio, mapToAdd); result = checkForConflictsById(gpioConfig.first,
gpioConfig.second->gpioType, mapToAdd);
if(result != HasReturnvaluesIF::RETURN_OK) { if(result != HasReturnvaluesIF::RETURN_OK) {
status = result; status = result;
} }
break; break;
} }
default: { default: {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "Invalid GPIO type detected for GPIO ID " << gpioConfig.first
<< std::endl;
#else
sif::printWarning("Invalid GPIO type detected for GPIO ID %d\n", gpioConfig.first);
#endif
status = GPIO_TYPE_FAILURE;
} }
} }
} }
return status; return status;
} }
ReturnValue_t LinuxLibgpioIF::checkForConflictsById(gpioId_t gpioIdToCheck,
ReturnValue_t LinuxLibgpioIF::checkForConflictsRegularGpio(gpioId_t gpioIdToCheck, gpio::GpioTypes expectedType, GpioMap& mapToAdd) {
GpiodRegularBase& gpioToCheck, GpioMap& mapToAdd) { // Cross check with private map
/* Cross check with private map */
gpioMapIter = gpioMap.find(gpioIdToCheck); gpioMapIter = gpioMap.find(gpioIdToCheck);
if(gpioMapIter != gpioMap.end()) { if(gpioMapIter != gpioMap.end()) {
auto& gpioType = gpioMapIter->second->gpioType; auto& gpioType = gpioMapIter->second->gpioType;
if(gpioType != gpio::GpioTypes::GPIO_REGULAR_BY_CHIP and bool eraseDuplicateDifferentType = false;
gpioType != gpio::GpioTypes::GPIO_REGULAR_BY_LABEL) { switch(expectedType) {
sif::warning << "LinuxLibgpioIF::checkForConflicts: ID already exists for different " case(gpio::GpioTypes::NONE): {
"GPIO type" << gpioIdToCheck << ". Removing duplicate." << std::endl; break;
mapToAdd.erase(gpioIdToCheck);
return HasReturnvaluesIF::RETURN_OK;
} }
auto ownRegularGpio = dynamic_cast<GpiodRegularBase*>(gpioMapIter->second); case(gpio::GpioTypes::GPIO_REGULAR_BY_CHIP):
if(ownRegularGpio == nullptr) { case(gpio::GpioTypes::GPIO_REGULAR_BY_LABEL):
return GPIO_TYPE_FAILURE; case(gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME): {
if(gpioType == gpio::GpioTypes::NONE or gpioType == gpio::GpioTypes::CALLBACK) {
eraseDuplicateDifferentType = true;
}
break;
}
case(gpio::GpioTypes::CALLBACK): {
if(gpioType != gpio::GpioTypes::CALLBACK) {
eraseDuplicateDifferentType = true;
}
}
}
if(eraseDuplicateDifferentType) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "LinuxLibgpioIF::checkForConflicts: ID already exists for "
"different GPIO type " << gpioIdToCheck <<
". Removing duplicate from map to add" << std::endl;
#else
sif::printWarning("LinuxLibgpioIF::checkForConflicts: ID already exists for "
"different GPIO type %d. Removing duplicate from map to add\n", gpioIdToCheck);
#endif
mapToAdd.erase(gpioIdToCheck);
return GPIO_DUPLICATE_DETECTED;
} }
/* Remove element from map to add because a entry for this GPIO // Remove element from map to add because a entry for this GPIO already exists
already exists */ #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "LinuxLibgpioIF::checkForConflictsRegularGpio: Duplicate GPIO definition" sif::warning << "LinuxLibgpioIF::checkForConflictsRegularGpio: Duplicate GPIO "
<< " detected. Duplicate will be removed from map to add." << std::endl; "definition with ID " << gpioIdToCheck << " detected. " <<
"Duplicate will be removed from map to add" << std::endl;
#else
sif::printWarning("LinuxLibgpioIF::checkForConflictsRegularGpio: Duplicate GPIO definition "
"with ID %d detected. Duplicate will be removed from map to add\n", gpioIdToCheck);
#endif
mapToAdd.erase(gpioIdToCheck); mapToAdd.erase(gpioIdToCheck);
return GPIO_DUPLICATE_DETECTED;
} }
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t LinuxLibgpioIF::checkForConflictsCallbackGpio(gpioId_t gpioIdToCheck, void LinuxLibgpioIF::parseFindeLineResult(int result, std::string& lineName) {
GpioCallback *callbackGpio, GpioMap& mapToAdd) { switch (result) {
/* Cross check with private map */ #if FSFW_CPP_OSTREAM_ENABLED == 1
gpioMapIter = gpioMap.find(gpioIdToCheck); case LINE_NOT_EXISTS:
if(gpioMapIter != gpioMap.end()) { case LINE_ERROR: {
if(gpioMapIter->second->gpioType != gpio::GpioTypes::CALLBACK) { sif::warning << "LinuxLibgpioIF::parseFindeLineResult: Line with name " << lineName <<
sif::warning << "LinuxLibgpioIF::checkForConflicts: ID already exists for different " " does not exist" << std::endl;
"GPIO type" << gpioIdToCheck << ". Removing duplicate." << std::endl; break;
mapToAdd.erase(gpioIdToCheck); }
return HasReturnvaluesIF::RETURN_OK; default: {
sif::warning << "LinuxLibgpioIF::parseFindeLineResult: Unknown return code for line "
"with name " << lineName << std::endl;
break;
}
#else
case LINE_NOT_EXISTS:
case LINE_ERROR: {
sif::printWarning("LinuxLibgpioIF::parseFindeLineResult: Line with name %s "
"does not exist\n", lineName);
break;
}
default: {
sif::printWarning("LinuxLibgpioIF::parseFindeLineResult: Unknown return code for line "
"with name %s\n", lineName);
break;
}
#endif
} }
/* Remove element from map to add because a entry for this GPIO
already exists */
sif::warning << "LinuxLibgpioIF::checkForConflictsRegularGpio: Duplicate GPIO definition"
<< " detected. Duplicate will be removed from map to add." << std::endl;
mapToAdd.erase(gpioIdToCheck);
}
return HasReturnvaluesIF::RETURN_OK;
} }

View File

@@ -1,19 +1,19 @@
#ifndef LINUX_GPIO_LINUXLIBGPIOIF_H_ #ifndef LINUX_GPIO_LINUXLIBGPIOIF_H_
#define LINUX_GPIO_LINUXLIBGPIOIF_H_ #define LINUX_GPIO_LINUXLIBGPIOIF_H_
#include "../../common/gpio/GpioIF.h" #include "fsfw/returnvalues/FwClassIds.h"
#include <returnvalues/classIds.h> #include "fsfw_hal/common/gpio/GpioIF.h"
#include <fsfw/objectmanager/SystemObject.h> #include "fsfw/objectmanager/SystemObject.h"
class GpioCookie; class GpioCookie;
class GpiodRegularIF; class GpiodRegularIF;
/** /**
* @brief This class implements the GpioIF for a linux based system. The * @brief This class implements the GpioIF for a linux based system.
* implementation is based on the libgpiod lib which requires linux 4.8 * @details
* or higher. * This implementation is based on the libgpiod lib which requires Linux 4.8 or higher.
* @note The Petalinux SDK from Xilinx supports libgpiod since Petalinux * @note
* 2019.1. * The Petalinux SDK from Xilinx supports libgpiod since Petalinux 2019.1.
*/ */
class LinuxLibgpioIF : public GpioIF, public SystemObject { class LinuxLibgpioIF : public GpioIF, public SystemObject {
public: public:
@@ -28,6 +28,8 @@ public:
HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 3); HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 3);
static constexpr ReturnValue_t GPIO_INVALID_INSTANCE = static constexpr ReturnValue_t GPIO_INVALID_INSTANCE =
HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 4); HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 4);
static constexpr ReturnValue_t GPIO_DUPLICATE_DETECTED =
HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 5);
LinuxLibgpioIF(object_id_t objectId); LinuxLibgpioIF(object_id_t objectId);
virtual ~LinuxLibgpioIF(); virtual ~LinuxLibgpioIF();
@@ -38,7 +40,13 @@ public:
ReturnValue_t readGpio(gpioId_t gpioId, int* gpioState) override; ReturnValue_t readGpio(gpioId_t gpioId, int* gpioState) override;
private: private:
/* Holds the information and configuration of all used GPIOs */
static const size_t MAX_CHIPNAME_LENGTH = 11;
static const int LINE_NOT_EXISTS = 0;
static const int LINE_ERROR = -1;
static const int LINE_FOUND = 1;
// Holds the information and configuration of all used GPIOs
GpioUnorderedMap gpioMap; GpioUnorderedMap gpioMap;
GpioUnorderedMapIter gpioMapIter; GpioUnorderedMapIter gpioMapIter;
@@ -53,8 +61,10 @@ private:
ReturnValue_t configureGpioByLabel(gpioId_t gpioId, GpiodRegularByLabel& gpioByLabel); ReturnValue_t configureGpioByLabel(gpioId_t gpioId, GpiodRegularByLabel& gpioByLabel);
ReturnValue_t configureGpioByChip(gpioId_t gpioId, GpiodRegularByChip& gpioByChip); ReturnValue_t configureGpioByChip(gpioId_t gpioId, GpiodRegularByChip& gpioByChip);
ReturnValue_t configureRegularGpio(gpioId_t gpioId, gpio::GpioTypes gpioType, ReturnValue_t configureGpioByLineName(gpioId_t gpioId,
struct gpiod_chip* chip, GpiodRegularBase& regularGpio, std::string failOutput); GpiodRegularByLineName &gpioByLineName);
ReturnValue_t configureRegularGpio(gpioId_t gpioId, struct gpiod_chip* chip,
GpiodRegularBase& regularGpio, std::string failOutput);
/** /**
* @brief This function checks if GPIOs are already registered and whether * @brief This function checks if GPIOs are already registered and whether
@@ -67,9 +77,7 @@ private:
*/ */
ReturnValue_t checkForConflicts(GpioMap& mapToAdd); ReturnValue_t checkForConflicts(GpioMap& mapToAdd);
ReturnValue_t checkForConflictsRegularGpio(gpioId_t gpiodId, GpiodRegularBase& regularGpio, ReturnValue_t checkForConflictsById(gpioId_t gpiodId, gpio::GpioTypes type,
GpioMap& mapToAdd);
ReturnValue_t checkForConflictsCallbackGpio(gpioId_t gpiodId, GpioCallback* regularGpio,
GpioMap& mapToAdd); GpioMap& mapToAdd);
/** /**
@@ -77,6 +85,7 @@ private:
*/ */
ReturnValue_t configureGpios(GpioMap& mapToAdd); ReturnValue_t configureGpios(GpioMap& mapToAdd);
void parseFindeLineResult(int result, std::string& lineName);
}; };
#endif /* LINUX_GPIO_LINUXLIBGPIOIF_H_ */ #endif /* LINUX_GPIO_LINUXLIBGPIOIF_H_ */

View File

@@ -18,6 +18,10 @@
// FSFW core defines // FSFW core defines
#ifndef FSFW_TCP_RECV_WIRETAPPING_ENABLED
#define FSFW_TCP_RECV_WIRETAPPING_ENABLED 0
#endif
#ifndef FSFW_CPP_OSTREAM_ENABLED #ifndef FSFW_CPP_OSTREAM_ENABLED
#define FSFW_CPP_OSTREAM_ENABLED 1 #define FSFW_CPP_OSTREAM_ENABLED 1
#endif /* FSFW_CPP_OSTREAM_ENABLED */ #endif /* FSFW_CPP_OSTREAM_ENABLED */

View File

@@ -5,8 +5,7 @@
#include <cstddef> #include <cstddef>
/** /**
* @brief Circular buffer implementation, useful for buffering * @brief Circular buffer implementation, useful for buffering into data streams.
* into data streams.
* @details * @details
* Note that the deleteData() has to be called to increment the read pointer. * Note that the deleteData() has to be called to increment the read pointer.
* This class allocated dynamically, so * This class allocated dynamically, so
@@ -20,8 +19,8 @@ public:
* @param size * @param size
* @param overwriteOld If the ring buffer is overflowing at a write * @param overwriteOld If the ring buffer is overflowing at a write
* operation, the oldest data will be overwritten. * operation, the oldest data will be overwritten.
* @param maxExcessBytes These additional bytes will be allocated in addtion * @param maxExcessBytes These additional bytes will be allocated in addition
* to the specified size to accomodate contiguous write operations * to the specified size to accommodate continuous write operations
* with getFreeElement. * with getFreeElement.
* *
*/ */
@@ -32,10 +31,10 @@ public:
* @param buffer * @param buffer
* @param size * @param size
* @param overwriteOld * @param overwriteOld
* If the ring buffer is overflowing at a write operartion, the oldest data * If the ring buffer is overflowing at a write operation, the oldest data
* will be overwritten. * will be overwritten.
* @param maxExcessBytes * @param maxExcessBytes
* If the buffer can accomodate additional bytes for contigous write * If the buffer can accommodate additional bytes for contiguous write
* operations with getFreeElement, this is the maximum allowed additional * operations with getFreeElement, this is the maximum allowed additional
* size * size
*/ */
@@ -48,7 +47,7 @@ public:
* Write to circular buffer and increment write pointer by amount. * Write to circular buffer and increment write pointer by amount.
* @param data * @param data
* @param amount * @param amount
* @return -@c RETURN_OK if write operation was successfull * @return -@c RETURN_OK if write operation was successful
* -@c RETURN_FAILED if * -@c RETURN_FAILED if
*/ */
ReturnValue_t writeData(const uint8_t* data, size_t amount); ReturnValue_t writeData(const uint8_t* data, size_t amount);
@@ -108,7 +107,7 @@ public:
* Delete data by incrementing read pointer. * Delete data by incrementing read pointer.
* @param amount * @param amount
* @param deleteRemaining * @param deleteRemaining
* If the amount specified is larger than the remaing size to read and this * If the amount specified is larger than the remaining size to read and this
* is set to true, the remaining amount will be deleted as well * is set to true, the remaining amount will be deleted as well
* @param trueAmount [out] * @param trueAmount [out]
* If deleteRemaining was set to true, the amount deleted will be assigned * If deleteRemaining was set to true, the amount deleted will be assigned

View File

@@ -7,7 +7,7 @@
/** /**
* @brief Base class to implement reconfiguration and failure handling for * @brief Base class to implement reconfiguration and failure handling for
* redundant devices by monitoring their modes health states. * redundant devices by monitoring their modes and health states.
* @details * @details
* Documentation: Dissertation Baetz p.156, 157. * Documentation: Dissertation Baetz p.156, 157.
* *

View File

@@ -85,9 +85,10 @@ public:
* Called by DHB in the GET_WRITE doGetWrite(). * Called by DHB in the GET_WRITE doGetWrite().
* Get send confirmation that the data in sendMessage() was sent successfully. * Get send confirmation that the data in sendMessage() was sent successfully.
* @param cookie * @param cookie
* @return - @c RETURN_OK if data was sent successfull * @return
* - Everything else triggers falure event with * - @c RETURN_OK if data was sent successfully but a reply is expected
* returnvalue as parameter 1 * - NO_REPLY_EXPECTED if data was sent successfully and no reply is expected
* - Everything else to indicate failure
*/ */
virtual ReturnValue_t getSendSuccess(CookieIF *cookie) = 0; virtual ReturnValue_t getSendSuccess(CookieIF *cookie) = 0;

View File

@@ -334,8 +334,7 @@ protected:
* - @c RETURN_OK to send command after #rawPacket and #rawPacketLen * - @c RETURN_OK to send command after #rawPacket and #rawPacketLen
* have been set. * have been set.
* - @c HasActionsIF::EXECUTION_COMPLETE to generate a finish reply immediately. This can * - @c HasActionsIF::EXECUTION_COMPLETE to generate a finish reply immediately. This can
* be used if no reply is expected. Otherwise, the developer can call #actionHelper.finish * be used if no reply is expected
* to finish the command handling.
* - Anything else triggers an event with the return code as a parameter as well as a * - Anything else triggers an event with the return code as a parameter as well as a
* step reply failed with the return code * step reply failed with the return code
*/ */

View File

@@ -120,7 +120,8 @@ public:
static const ReturnValue_t WRONG_MODE_FOR_COMMAND = MAKE_RETURN_CODE(0xA5); static const ReturnValue_t WRONG_MODE_FOR_COMMAND = MAKE_RETURN_CODE(0xA5);
static const ReturnValue_t TIMEOUT = MAKE_RETURN_CODE(0xA6); static const ReturnValue_t TIMEOUT = MAKE_RETURN_CODE(0xA6);
static const ReturnValue_t BUSY = MAKE_RETURN_CODE(0xA7); static const ReturnValue_t BUSY = MAKE_RETURN_CODE(0xA7);
static const ReturnValue_t NO_REPLY_EXPECTED = MAKE_RETURN_CODE(0xA8); //!< Used to indicate that this is a command-only command. //!< Used to indicate that this is a command-only command.
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);

View File

@@ -7,14 +7,13 @@ PeriodicOperationDivider::PeriodicOperationDivider(uint32_t divider,
} }
bool PeriodicOperationDivider::checkAndIncrement() { bool PeriodicOperationDivider::checkAndIncrement() {
counter++;
bool opNecessary = check(); bool opNecessary = check();
if(opNecessary) { if(opNecessary) {
if(resetAutomatically) { if(resetAutomatically) {
counter = 0; resetCounter();
} }
return opNecessary;
} }
counter ++;
return opNecessary; return opNecessary;
} }

View File

@@ -81,7 +81,7 @@ public:
* @param args Any other arguments which an implementation might require * @param args Any other arguments which an implementation might require
* @return * @return
*/ */
virtual ReturnValue_t deleteFile(const char* repositoryPath, virtual ReturnValue_t removeFile(const char* repositoryPath,
const char* filename, void* args = nullptr) = 0; const char* filename, void* args = nullptr) = 0;
/** /**

View File

@@ -1,13 +1,17 @@
#include "fsfw/osal/common/TcpTmTcServer.h"
#include "fsfw/osal/common/TcpTmTcBridge.h"
#include "fsfw/osal/common/tcpipHelpers.h"
#include "fsfw/platform.h" #include "fsfw/platform.h"
#include "fsfw/FSFW.h"
#include "TcpTmTcServer.h"
#include "TcpTmTcBridge.h"
#include "tcpipHelpers.h"
#include "fsfw/tmtcservices/SpacePacketParser.h"
#include "fsfw/tasks/TaskFactory.h"
#include "fsfw/globalfunctions/arrayprinter.h"
#include "fsfw/container/SharedRingBuffer.h" #include "fsfw/container/SharedRingBuffer.h"
#include "fsfw/ipc/MessageQueueSenderIF.h" #include "fsfw/ipc/MessageQueueSenderIF.h"
#include "fsfw/ipc/MutexGuard.h" #include "fsfw/ipc/MutexGuard.h"
#include "fsfw/objectmanager/ObjectManager.h" #include "fsfw/objectmanager/ObjectManager.h"
#include "fsfw/serviceinterface/ServiceInterface.h" #include "fsfw/serviceinterface/ServiceInterface.h"
#include "fsfw/tmtcservices/TmTcMessage.h" #include "fsfw/tmtcservices/TmTcMessage.h"
@@ -18,19 +22,14 @@
#include <netdb.h> #include <netdb.h>
#endif #endif
#ifndef FSFW_TCP_RECV_WIRETAPPING_ENABLED
#define FSFW_TCP_RECV_WIRETAPPING_ENABLED 0
#endif
const std::string TcpTmTcServer::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT; const std::string TcpTmTcServer::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT;
TcpTmTcServer::TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge, TcpTmTcServer::TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge,
size_t receptionBufferSize, std::string customTcpServerPort): size_t receptionBufferSize, size_t ringBufferSize, std::string customTcpServerPort,
SystemObject(objectId), tmtcBridgeId(tmtcTcpBridge), ReceptionModes receptionMode):
tcpPort(customTcpServerPort), receptionBuffer(receptionBufferSize) { SystemObject(objectId), tmtcBridgeId(tmtcTcpBridge), receptionMode(receptionMode),
if(tcpPort == "") { tcpConfig(customTcpServerPort), receptionBuffer(receptionBufferSize),
tcpPort = DEFAULT_SERVER_PORT; ringBuffer(ringBufferSize, true) {
}
} }
ReturnValue_t TcpTmTcServer::initialize() { ReturnValue_t TcpTmTcServer::initialize() {
@@ -41,6 +40,17 @@ ReturnValue_t TcpTmTcServer::initialize() {
return result; return result;
} }
switch(receptionMode) {
case(ReceptionModes::SPACE_PACKETS): {
spacePacketParser = new SpacePacketParser(validPacketIds);
if(spacePacketParser == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
#if defined PLATFORM_UNIX
tcpConfig.tcpFlags |= MSG_DONTWAIT;
#endif
}
}
tcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TC_STORE); tcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TC_STORE);
if (tcStore == nullptr) { if (tcStore == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
@@ -63,7 +73,7 @@ ReturnValue_t TcpTmTcServer::initialize() {
hints.ai_flags = AI_PASSIVE; hints.ai_flags = AI_PASSIVE;
// Listen to all addresses (0.0.0.0) by using AI_PASSIVE in the hint flags // Listen to all addresses (0.0.0.0) by using AI_PASSIVE in the hint flags
retval = getaddrinfo(nullptr, tcpPort.c_str(), &hints, &addrResult); retval = getaddrinfo(nullptr, tcpConfig.tcpPort.c_str(), &hints, &addrResult);
if (retval != 0) { if (retval != 0) {
handleError(Protocol::TCP, ErrorSources::GETADDRINFO_CALL); handleError(Protocol::TCP, ErrorSources::GETADDRINFO_CALL);
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
@@ -105,7 +115,7 @@ ReturnValue_t TcpTmTcServer::performOperation(uint8_t opCode) {
// Listen for connection requests permanently for lifetime of program // Listen for connection requests permanently for lifetime of program
while(true) { while(true) {
retval = listen(listenerTcpSocket, tcpBacklog); retval = listen(listenerTcpSocket, tcpConfig.tcpBacklog);
if(retval == SOCKET_ERROR) { if(retval == SOCKET_ERROR) {
handleError(Protocol::TCP, ErrorSources::LISTEN_CALL, 500); handleError(Protocol::TCP, ErrorSources::LISTEN_CALL, 500);
continue; continue;
@@ -123,11 +133,12 @@ ReturnValue_t TcpTmTcServer::performOperation(uint8_t opCode) {
handleServerOperation(connSocket); handleServerOperation(connSocket);
// Done, shut down connection and go back to listening for client requests // Done, shut down connection and go back to listening for client requests
retval = shutdown(connSocket, SHUT_SEND); retval = shutdown(connSocket, SHUT_BOTH);
if(retval != 0) { if(retval != 0) {
handleError(Protocol::TCP, ErrorSources::SHUTDOWN_CALL); handleError(Protocol::TCP, ErrorSources::SHUTDOWN_CALL);
} }
closeSocket(connSocket); closeSocket(connSocket);
connSocket = 0;
} }
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
@@ -144,41 +155,88 @@ ReturnValue_t TcpTmTcServer::initializeAfterTaskCreation() {
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
void TcpTmTcServer::handleServerOperation(socket_t connSocket) { void TcpTmTcServer::handleServerOperation(socket_t& connSocket) {
int retval = 0; #if defined PLATFORM_WIN
do { setSocketNonBlocking(connSocket);
// Read all telecommands sent by the client #endif
retval = recv(connSocket,
while (true) {
int retval = recv(
connSocket,
reinterpret_cast<char*>(receptionBuffer.data()), reinterpret_cast<char*>(receptionBuffer.data()),
receptionBuffer.capacity(), receptionBuffer.capacity(),
tcpFlags); tcpConfig.tcpFlags
if (retval > 0) { );
handleTcReception(retval); if(retval == 0) {
size_t availableReadData = ringBuffer.getAvailableReadData();
if(availableReadData > lastRingBufferSize) {
handleTcRingBufferData(availableReadData);
}
return;
}
else if(retval > 0) {
// The ring buffer was configured for overwrite, so the returnvalue does not need to
// be checked for now
ringBuffer.writeData(receptionBuffer.data(), retval);
}
else if(retval < 0) {
int errorValue = getLastSocketError();
#if defined PLATFORM_UNIX
int wouldBlockValue = EAGAIN;
#elif defined PLATFORM_WIN
int wouldBlockValue = WSAEWOULDBLOCK;
#endif
if(errorValue == wouldBlockValue) {
// No data available. Check whether any packets have been read, then send back
// telemetry if available
bool tcAvailable = false;
bool tmSent = false;
size_t availableReadData = ringBuffer.getAvailableReadData();
if(availableReadData > lastRingBufferSize) {
tcAvailable = true;
handleTcRingBufferData(availableReadData);
}
ReturnValue_t result = handleTmSending(connSocket, tmSent);
if(result == CONN_BROKEN) {
return;
}
if(not tcAvailable and not tmSent) {
TaskFactory::delayTask(tcpConfig.tcpLoopDelay);
} }
else if(retval == 0) {
// Client has finished sending telecommands, send telemetry now
handleTmSending(connSocket);
} }
else { else {
// Should not happen tcpip::handleError(tcpip::Protocol::TCP, tcpip::ErrorSources::RECV_CALL, 300);
tcpip::handleError(tcpip::Protocol::TCP, tcpip::ErrorSources::RECV_CALL); }
}
} }
} while(retval > 0);
} }
ReturnValue_t TcpTmTcServer::handleTcReception(size_t bytesRecvd) { ReturnValue_t TcpTmTcServer::handleTcReception(uint8_t* spacePacket, size_t packetSize) {
#if FSFW_TCP_RECV_WIRETAPPING_ENABLED == 1 if(wiretappingEnabled) {
arrayprinter::print(receptionBuffer.data(), bytesRead); #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "Received TC:" << std::endl;
#else
sif::printInfo("Received TC:\n");
#endif #endif
arrayprinter::print(spacePacket, packetSize);
}
if(spacePacket == nullptr or packetSize == 0) {
return HasReturnvaluesIF::RETURN_FAILED;
}
store_address_t storeId; store_address_t storeId;
ReturnValue_t result = tcStore->addData(&storeId, receptionBuffer.data(), bytesRecvd); ReturnValue_t result = tcStore->addData(&storeId, spacePacket, packetSize);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
#if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning<< "TcpTmTcServer::handleServerOperation: Data storage failed." << std::endl; sif::warning << "TcpTmTcServer::handleServerOperation: Data storage with packet size" <<
sif::warning << "Packet size: " << bytesRecvd << std::endl; packetSize << " failed" << std::endl;
#else
sif::printWarning("TcpTmTcServer::handleServerOperation: Data storage with packet size %d "
"failed\n", packetSize);
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ #endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
#endif /* FSFW_VERBOSE_LEVEL >= 1 */ #endif /* FSFW_VERBOSE_LEVEL >= 1 */
return result;
} }
TmTcMessage message(storeId); TmTcMessage message(storeId);
@@ -187,8 +245,11 @@ ReturnValue_t TcpTmTcServer::handleTcReception(size_t bytesRecvd) {
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
#if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "UdpTcPollingTask::handleSuccessfullTcRead: " sif::warning << "TcpTmTcServer::handleServerOperation: "
" Sending message to queue failed" << std::endl; " Sending message to queue failed" << std::endl;
#else
sif::printWarning("TcpTmTcServer::handleServerOperation: "
" Sending message to queue failed\n");
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ #endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
#endif /* FSFW_VERBOSE_LEVEL >= 1 */ #endif /* FSFW_VERBOSE_LEVEL >= 1 */
tcStore->deleteData(storeId); tcStore->deleteData(storeId);
@@ -196,21 +257,26 @@ ReturnValue_t TcpTmTcServer::handleTcReception(size_t bytesRecvd) {
return result; return result;
} }
void TcpTmTcServer::setTcpBacklog(uint8_t tcpBacklog) {
this->tcpBacklog = tcpBacklog;
}
std::string TcpTmTcServer::getTcpPort() const { std::string TcpTmTcServer::getTcpPort() const {
return tcpPort; return tcpConfig.tcpPort;
} }
ReturnValue_t TcpTmTcServer::handleTmSending(socket_t connSocket) { void TcpTmTcServer::setSpacePacketParsingOptions(std::vector<uint16_t> validPacketIds) {
this->validPacketIds = validPacketIds;
}
TcpTmTcServer::TcpConfig& TcpTmTcServer::getTcpConfigStruct() {
return tcpConfig;
}
ReturnValue_t TcpTmTcServer::handleTmSending(socket_t connSocket, bool& tmSent) {
// Access to the FIFO is mutex protected because it is filled by the bridge // Access to the FIFO is mutex protected because it is filled by the bridge
MutexGuard(tmtcBridge->mutex, tmtcBridge->timeoutType, tmtcBridge->mutexTimeoutMs); MutexGuard(tmtcBridge->mutex, tmtcBridge->timeoutType, tmtcBridge->mutexTimeoutMs);
store_address_t storeId; store_address_t storeId;
while((not tmtcBridge->tmFifo->empty()) and while((not tmtcBridge->tmFifo->empty()) and
(tmtcBridge->packetSentCounter < tmtcBridge->sentPacketsPerCycle)) { (tmtcBridge->packetSentCounter < tmtcBridge->sentPacketsPerCycle)) {
tmtcBridge->tmFifo->retrieve(&storeId); // Send can fail, so only peek from the FIFO
tmtcBridge->tmFifo->peek(&storeId);
// Using the store accessor will take care of deleting TM from the store automatically // Using the store accessor will take care of deleting TM from the store automatically
ConstStorageAccessor storeAccessor(storeId); ConstStorageAccessor storeAccessor(storeId);
@@ -218,13 +284,134 @@ ReturnValue_t TcpTmTcServer::handleTmSending(socket_t connSocket) {
if(result != HasReturnvaluesIF::RETURN_OK) { if(result != HasReturnvaluesIF::RETURN_OK) {
return result; return result;
} }
if(wiretappingEnabled) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "Sending TM:" << std::endl;
#else
sif::printInfo("Sending TM:\n");
#endif
arrayprinter::print(storeAccessor.data(), storeAccessor.size());
}
int retval = send(connSocket, int retval = send(connSocket,
reinterpret_cast<const char*>(storeAccessor.data()), reinterpret_cast<const char*>(storeAccessor.data()),
storeAccessor.size(), storeAccessor.size(),
tcpTmFlags); tcpConfig.tcpTmFlags);
if(retval != static_cast<int>(storeAccessor.size())) { if(retval == static_cast<int>(storeAccessor.size())) {
tcpip::handleError(tcpip::Protocol::TCP, tcpip::ErrorSources::SEND_CALL); // Packet sent, clear FIFO entry
tmtcBridge->tmFifo->pop();
tmSent = true;
}
else if(retval <= 0) {
// Assume that the client has closed the connection here for now
handleSocketError(storeAccessor);
return CONN_BROKEN;
} }
} }
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t TcpTmTcServer::handleTcRingBufferData(size_t availableReadData) {
ReturnValue_t status = HasReturnvaluesIF::RETURN_OK;
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
size_t readAmount = availableReadData;
lastRingBufferSize = availableReadData;
if(readAmount >= ringBuffer.getMaxSize()) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
// Possible configuration error, too much data or/and data coming in too fast,
// requiring larger buffers
sif::warning << "TcpTmTcServer::handleServerOperation: Ring buffer reached " <<
"fill count" << std::endl;
#else
sif::printWarning("TcpTmTcServer::handleServerOperation: Ring buffer reached "
"fill count");
#endif
#endif
}
if(readAmount >= receptionBuffer.size()) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
// Possible configuration error, too much data or/and data coming in too fast,
// requiring larger buffers
sif::warning << "TcpTmTcServer::handleServerOperation: "
"Reception buffer too small " << std::endl;
#else
sif::printWarning("TcpTmTcServer::handleServerOperation: Reception buffer too small\n");
#endif
#endif
readAmount = receptionBuffer.size();
}
ringBuffer.readData(receptionBuffer.data(), readAmount, true);
const uint8_t* bufPtr = receptionBuffer.data();
const uint8_t** bufPtrPtr = &bufPtr;
size_t startIdx = 0;
size_t foundSize = 0;
size_t readLen = 0;
while(readLen < readAmount) {
result = spacePacketParser->parseSpacePackets(bufPtrPtr, readAmount,
startIdx, foundSize, readLen);
switch(result) {
case(SpacePacketParser::NO_PACKET_FOUND):
case(SpacePacketParser::SPLIT_PACKET): {
break;
}
case(HasReturnvaluesIF::RETURN_OK): {
result = handleTcReception(receptionBuffer.data() + startIdx, foundSize);
if(result != HasReturnvaluesIF::RETURN_OK) {
status = result;
}
}
}
ringBuffer.deleteData(foundSize);
lastRingBufferSize = ringBuffer.getAvailableReadData();
std::memset(receptionBuffer.data() + startIdx, 0, foundSize);
}
return status;
}
void TcpTmTcServer::enableWiretapping(bool enable) {
this->wiretappingEnabled = enable;
}
void TcpTmTcServer::handleSocketError(ConstStorageAccessor &accessor) {
// Don't delete data
accessor.release();
auto socketError = getLastSocketError();
switch(socketError) {
#if defined PLATFORM_WIN
case(WSAECONNRESET): {
// See https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-send
// Remote client might have shut down connection
return;
}
#else
case(EPIPE): {
// See https://man7.org/linux/man-pages/man2/send.2.html
// Remote client might have shut down connection
return;
}
#endif
default: {
tcpip::handleError(tcpip::Protocol::TCP, tcpip::ErrorSources::SEND_CALL);
}
}
}
#if defined PLATFORM_WIN
void TcpTmTcServer::setSocketNonBlocking(socket_t &connSocket) {
u_long iMode = 1;
int iResult = ioctlsocket(connSocket, FIONBIO, &iMode);
if(iResult != NO_ERROR) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "TcpTmTcServer::handleServerOperation: Setting socket"
" non-blocking failed with error " << iResult;
#else
sif::printWarning("TcpTmTcServer::handleServerOperation: Setting socket"
" non-blocking failed with error %d\n", iResult);
#endif
#endif
}
}
#endif

View File

@@ -6,6 +6,7 @@
#include "fsfw/platform.h" #include "fsfw/platform.h"
#include "fsfw/osal/common/tcpipHelpers.h" #include "fsfw/osal/common/tcpipHelpers.h"
#include "fsfw/ipc/messageQueueDefinitions.h" #include "fsfw/ipc/messageQueueDefinitions.h"
#include "fsfw/container/SimpleRingBuffer.h"
#include "fsfw/ipc/MessageQueueIF.h" #include "fsfw/ipc/MessageQueueIF.h"
#include "fsfw/objectmanager/frameworkObjects.h" #include "fsfw/objectmanager/frameworkObjects.h"
#include "fsfw/objectmanager/SystemObject.h" #include "fsfw/objectmanager/SystemObject.h"
@@ -20,6 +21,7 @@
#include <vector> #include <vector>
class TcpTmTcBridge; class TcpTmTcBridge;
class SpacePacketParser;
/** /**
* @brief TCP server implementation * @brief TCP server implementation
@@ -42,9 +44,38 @@ class TcpTmTcServer:
public TcpIpBase, public TcpIpBase,
public ExecutableObjectIF { public ExecutableObjectIF {
public: public:
enum class ReceptionModes {
SPACE_PACKETS
};
struct TcpConfig {
public:
TcpConfig(std::string tcpPort): tcpPort(tcpPort) {}
/**
* Passed to the recv call
*/
int tcpFlags = 0;
int tcpBacklog = 3;
/**
* If no telecommands packets are being received and no telemetry is being sent,
* the TCP server will delay periodically by this amount to decrease the CPU load
*/
uint32_t tcpLoopDelay = DEFAULT_LOOP_DELAY_MS ;
/**
* Passed to the send call
*/
int tcpTmFlags = 0;
const std::string tcpPort;
};
static const std::string DEFAULT_SERVER_PORT; static const std::string DEFAULT_SERVER_PORT;
static constexpr size_t ETHERNET_MTU_SIZE = 1500; static constexpr size_t ETHERNET_MTU_SIZE = 1500;
static constexpr size_t RING_BUFFER_SIZE = ETHERNET_MTU_SIZE * 3;
static constexpr uint32_t DEFAULT_LOOP_DELAY_MS = 200;
/** /**
* TCP Server Constructor * TCP Server Constructor
@@ -55,11 +86,21 @@ public:
* @param customTcpServerPort The user can specify another port than the default (7301) here. * @param customTcpServerPort The user can specify another port than the default (7301) here.
*/ */
TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge, TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge,
size_t receptionBufferSize = ETHERNET_MTU_SIZE + 1, size_t receptionBufferSize = RING_BUFFER_SIZE,
std::string customTcpServerPort = ""); size_t ringBufferSize = RING_BUFFER_SIZE,
std::string customTcpServerPort = DEFAULT_SERVER_PORT,
ReceptionModes receptionMode = ReceptionModes::SPACE_PACKETS);
virtual~ TcpTmTcServer(); virtual~ TcpTmTcServer();
void setTcpBacklog(uint8_t tcpBacklog); void enableWiretapping(bool enable);
/**
* Get a handle to the TCP configuration struct, which can be used to configure TCP
* properties
* @return
*/
TcpConfig& getTcpConfigStruct();
void setSpacePacketParsingOptions(std::vector<uint16_t> validPacketIds);
ReturnValue_t initialize() override; ReturnValue_t initialize() override;
ReturnValue_t performOperation(uint8_t opCode) override; ReturnValue_t performOperation(uint8_t opCode) override;
@@ -71,25 +112,33 @@ protected:
StorageManagerIF* tcStore = nullptr; StorageManagerIF* tcStore = nullptr;
StorageManagerIF* tmStore = nullptr; StorageManagerIF* tmStore = nullptr;
private: private:
static constexpr ReturnValue_t CONN_BROKEN = HasReturnvaluesIF::makeReturnCode(1, 0);
//! TMTC bridge is cached. //! TMTC bridge is cached.
object_id_t tmtcBridgeId = objects::NO_OBJECT; object_id_t tmtcBridgeId = objects::NO_OBJECT;
TcpTmTcBridge* tmtcBridge = nullptr; TcpTmTcBridge* tmtcBridge = nullptr;
bool wiretappingEnabled = false;
std::string tcpPort; ReceptionModes receptionMode;
int tcpFlags = 0; TcpConfig tcpConfig;
socket_t listenerTcpSocket = 0;
struct sockaddr tcpAddress; struct sockaddr tcpAddress;
socket_t listenerTcpSocket = 0;
MessageQueueId_t targetTcDestination = MessageQueueIF::NO_QUEUE; MessageQueueId_t targetTcDestination = MessageQueueIF::NO_QUEUE;
int tcpAddrLen = sizeof(tcpAddress);
int tcpBacklog = 3;
std::vector<uint8_t> receptionBuffer; std::vector<uint8_t> receptionBuffer;
int tcpSockOpt = 0; SimpleRingBuffer ringBuffer;
int tcpTmFlags = 0; std::vector<uint16_t> validPacketIds;
SpacePacketParser* spacePacketParser = nullptr;
uint8_t lastRingBufferSize = 0;
void handleServerOperation(socket_t connSocket); virtual void handleServerOperation(socket_t& connSocket);
ReturnValue_t handleTcReception(size_t bytesRecvd); ReturnValue_t handleTcReception(uint8_t* spacePacket, size_t packetSize);
ReturnValue_t handleTmSending(socket_t connSocket); ReturnValue_t handleTmSending(socket_t connSocket, bool& tmSent);
ReturnValue_t handleTcRingBufferData(size_t availableReadData);
void handleSocketError(ConstStorageAccessor& accessor);
#if defined PLATFORM_WIN
void setSocketNonBlocking(socket_t& connSocket);
#endif
}; };
#endif /* FSFW_OSAL_COMMON_TCP_TMTC_SERVER_H_ */ #endif /* FSFW_OSAL_COMMON_TCP_TMTC_SERVER_H_ */

View File

@@ -21,6 +21,9 @@ void tcpip::determineErrorStrings(Protocol protocol, ErrorSources errorSrc, std:
if(errorSrc == ErrorSources::SETSOCKOPT_CALL) { if(errorSrc == ErrorSources::SETSOCKOPT_CALL) {
srcString = "setsockopt call"; srcString = "setsockopt call";
} }
if(errorSrc == ErrorSources::BIND_CALL) {
srcString = "bind call";
}
else if(errorSrc == ErrorSources::SOCKET_CALL) { else if(errorSrc == ErrorSources::SOCKET_CALL) {
srcString = "socket call"; srcString = "socket call";
} }

View File

@@ -1,5 +1,4 @@
target_sources(${LIB_FSFW_NAME} target_sources(${LIB_FSFW_NAME} PRIVATE
PRIVATE
Clock.cpp Clock.cpp
BinarySemaphore.cpp BinarySemaphore.cpp
CountingSemaphore.cpp CountingSemaphore.cpp

View File

@@ -285,10 +285,10 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
utility::printUnixErrorGeneric(CLASS_NAME, "sendMessageFromMessageQueue", "EBADF"); utility::printUnixErrorGeneric(CLASS_NAME, "sendMessageFromMessageQueue", "EBADF");
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "mq_send to: " << sendTo << " sent from " sif::warning << "mq_send to " << sendTo << " sent from "
<< sentFrom << " failed" << std::endl; << sentFrom << " failed" << std::endl;
#else #else
sif::printWarning("mq_send to: %d sent from %d failed\n", sendTo, sentFrom); sif::printWarning("mq_send to %d sent from %d failed\n", sendTo, sentFrom);
#endif #endif
return DESTINATION_INVALID; return DESTINATION_INVALID;
} }

View File

@@ -80,6 +80,7 @@ enum: uint8_t {
FIXED_SLOT_TASK_IF, //FTIF FIXED_SLOT_TASK_IF, //FTIF
MGM_LIS3MDL, //MGMLIS3 MGM_LIS3MDL, //MGMLIS3
MGM_RM3100, //MGMRM3100 MGM_RM3100, //MGMRM3100
SPACE_PACKET_PARSER, //SPPA
FW_CLASS_ID_COUNT // [EXPORT] : [END] FW_CLASS_ID_COUNT // [EXPORT] : [END]
}; };

View File

@@ -62,7 +62,8 @@ protected:
struct ChildInfo { struct ChildInfo {
MessageQueueId_t commandQueue; MessageQueueId_t commandQueue;
Mode_t mode; Mode_t mode;
Submode_t submode;bool healthChanged; Submode_t submode;
bool healthChanged;
}; };
Mode_t mode; Mode_t mode;

View File

@@ -29,12 +29,31 @@ PUSDistributor::TcMqMapIter PUSDistributor::selectDestination() {
tcStatus = checker.checkPacket(currentPacket); tcStatus = checker.checkPacket(currentPacket);
if(tcStatus != HasReturnvaluesIF::RETURN_OK) { if(tcStatus != HasReturnvaluesIF::RETURN_OK) {
#if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_VERBOSE_LEVEL >= 1
std::string keyword;
if(tcStatus == TcPacketCheck::INCORRECT_CHECKSUM) {
keyword = "checksum";
}
else if(tcStatus == TcPacketCheck::INCORRECT_PRIMARY_HEADER) {
keyword = "incorrect primary header";
}
else if(tcStatus == TcPacketCheck::ILLEGAL_APID) {
keyword = "illegal APID";
}
else if(tcStatus == TcPacketCheck::INCORRECT_SECONDARY_HEADER) {
keyword = "incorrect secondary header";
}
else if(tcStatus == TcPacketCheck::INCOMPLETE_PACKET) {
keyword = "incomplete packet";
}
else {
keyword = "unnamed error";
}
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "PUSDistributor::handlePacket: Packet format invalid, code " << sif::warning << "PUSDistributor::handlePacket: Packet format invalid, "
static_cast<int>(tcStatus) << std::endl; << keyword << " error" << std::endl;
#else #else
sif::printDebug("PUSDistributor::handlePacket: Packet format invalid, code %d\n", sif::printWarning("PUSDistributor::handlePacket: Packet format invalid, "
static_cast<int>(tcStatus)); "%s error\n", keyword);
#endif #endif
#endif #endif
} }

View File

@@ -40,6 +40,7 @@ public:
* @li \c false else. * @li \c false else.
*/ */
bool addWholeData(const uint8_t* p_data, uint32_t packet_size); bool addWholeData(const uint8_t* p_data, uint32_t packet_size);
protected: protected:
/** /**
* This structure defines the data structure of a Space Packet as local data. * This structure defines the data structure of a Space Packet as local data.
@@ -68,4 +69,16 @@ protected:
SpacePacketData localData; SpacePacketData localData;
}; };
namespace spacepacket {
constexpr uint16_t getTcSpacePacketIdFromApid(uint16_t apid) {
return (0x18 << 8) | (((apid >> 8) & 0x07) << 8) | (apid & 0x00ff);
}
constexpr uint16_t getTmSpacePacketIdFromApid(uint16_t apid) {
return (0x08 << 8) | (((apid >> 8) & 0x07) << 8) | (apid & 0x00ff);
}
}
#endif /* SPACEPACKET_H_ */ #endif /* SPACEPACKET_H_ */

View File

@@ -6,4 +6,5 @@ target_sources(${LIB_FSFW_NAME}
TmTcBridge.cpp TmTcBridge.cpp
TmTcMessage.cpp TmTcMessage.cpp
VerificationReporter.cpp VerificationReporter.cpp
SpacePacketParser.cpp
) )

View File

@@ -0,0 +1,77 @@
#include <fsfw/serviceinterface/ServiceInterface.h>
#include <fsfw/tmtcservices/SpacePacketParser.h>
#include <algorithm>
SpacePacketParser::SpacePacketParser(std::vector<uint16_t> validPacketIds):
validPacketIds(validPacketIds) {
}
ReturnValue_t SpacePacketParser::parseSpacePackets(const uint8_t *buffer,
const size_t maxSize, size_t& startIndex, size_t& foundSize) {
const uint8_t** tempPtr = &buffer;
size_t readLen = 0;
return parseSpacePackets(tempPtr, maxSize, startIndex, foundSize, readLen);
}
ReturnValue_t SpacePacketParser::parseSpacePackets(const uint8_t **buffer, const size_t maxSize,
size_t &startIndex, size_t &foundSize, size_t& readLen) {
if(buffer == nullptr or maxSize < 5) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "SpacePacketParser::parseSpacePackets: Frame invalid" << std::endl;
#else
sif::printWarning("SpacePacketParser::parseSpacePackets: Frame invalid\n");
#endif
return HasReturnvaluesIF::RETURN_FAILED;
}
const uint8_t* bufPtr = *buffer;
auto verifyLengthField = [&](size_t idx) {
uint16_t lengthField = bufPtr[idx + 4] << 8 | bufPtr[idx + 5];
size_t packetSize = lengthField + 7;
startIndex = idx;
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
if(lengthField == 0) {
// Skip whole header for now
foundSize = 6;
result = NO_PACKET_FOUND;
}
else if(packetSize + idx > maxSize) {
// Don't increment buffer and read length here, user has to decide what to do
foundSize = packetSize;
return SPLIT_PACKET;
}
else {
foundSize = packetSize;
}
*buffer += foundSize;
readLen += idx + foundSize;
return result;
};
size_t idx = 0;
// Space packet ID as start marker
if(validPacketIds.size() > 0) {
while(idx < maxSize - 5) {
uint16_t currentPacketId = bufPtr[idx] << 8 | bufPtr[idx + 1];
if(std::find(validPacketIds.begin(), validPacketIds.end(), currentPacketId) !=
validPacketIds.end()) {
if(idx + 5 >= maxSize) {
return SPLIT_PACKET;
}
return verifyLengthField(idx);
}
else {
idx++;
}
}
startIndex = 0;
foundSize = maxSize;
*buffer += foundSize;
readLen += foundSize;
return NO_PACKET_FOUND;
}
// Assume that the user verified a valid start of a space packet
else {
return verifyLengthField(idx);
}
}

View File

@@ -0,0 +1,78 @@
#ifndef FRAMEWORK_TMTCSERVICES_PUSPARSER_H_
#define FRAMEWORK_TMTCSERVICES_PUSPARSER_H_
#include "fsfw/container/DynamicFIFO.h"
#include "fsfw/returnvalues/FwClassIds.h"
#include <utility>
#include <cstdint>
/**
* @brief This small helper class scans a given buffer for space packets.
* Can be used if space packets are serialized in a tightly packed frame.
* @details
* The parser uses the length field field and the 16-bit TC packet ID of the space packets to find
* find space packets in a given data stream
* @author R. Mueller
*/
class SpacePacketParser {
public:
//! The first entry is the index inside the buffer while the second index
//! is the size of the PUS packet starting at that index.
using IndexSizePair = std::pair<size_t, size_t>;
static constexpr uint8_t INTERFACE_ID = CLASS_ID::SPACE_PACKET_PARSER;
static constexpr ReturnValue_t NO_PACKET_FOUND = MAKE_RETURN_CODE(0x00);
static constexpr ReturnValue_t SPLIT_PACKET = MAKE_RETURN_CODE(0x01);
/**
* @brief Parser constructor.
* @param validPacketIds This vector contains the allowed 16-bit TC packet ID start markers
* The parser will search for these stark markers to detect the start of a space packet.
* It is also possible to pass an empty vector here, but this is not recommended.
* If an empty vector is passed, the parser will assume that the start of the given stream
* contains the start of a new space packet.
*/
SpacePacketParser(std::vector<uint16_t> validPacketIds);
/**
* Parse a given frame for space packets but also increment the given buffer and assign the
* total number of bytes read so far
* @param buffer Parser will look for space packets in this buffer
* @param maxSize Maximum size of the buffer
* @param startIndex Start index of a found space packet
* @param foundSize Found size of the space packet
* @param readLen Length read so far. This value is incremented by the number of parsed
* bytes which also includes the size of a found packet
* -@c NO_PACKET_FOUND if no packet was found in the given buffer or the length field is
* invalid. foundSize will be set to the size of the space packet header. buffer and
* readLen will be incremented accordingly.
* -@c SPLIT_PACKET if a packet was found but the detected size exceeds maxSize. foundSize
* will be set to the detected packet size and startIndex will be set to the start of the
* detected packet. buffer and read length will not be incremented but the found length
* will be assigned.
* -@c RETURN_OK if a packet was found
*/
ReturnValue_t parseSpacePackets(const uint8_t **buffer, const size_t maxSize,
size_t& startIndex, size_t& foundSize, size_t& readLen);
/**
* Parse a given frame for space packets
* @param buffer Parser will look for space packets in this buffer
* @param maxSize Maximum size of the buffer
* @param startIndex Start index of a found space packet
* @param foundSize Found size of the space packet
* -@c NO_PACKET_FOUND if no packet was found in the given buffer or the length field is
* invalid. foundSize will be set to the size of the space packet header
* -@c SPLIT_PACKET if a packet was found but the detected size exceeds maxSize. foundSize
* will be set to the detected packet size and startIndex will be set to the start of the
* detected packet
* -@c RETURN_OK if a packet was found
*/
ReturnValue_t parseSpacePackets(const uint8_t* buffer, const size_t maxSize,
size_t& startIndex, size_t& foundSize);
private:
std::vector<uint16_t> validPacketIds;
};
#endif /* FRAMEWORK_TMTCSERVICES_PUSPARSER_H_ */

View File

@@ -1,11 +1,9 @@
target_sources(${TARGET_NAME} target_sources(${TARGET_NAME} PRIVATE
PRIVATE
ipc/MissionMessageTypes.cpp ipc/MissionMessageTypes.cpp
pollingsequence/PollingSequenceFactory.cpp pollingsequence/PollingSequenceFactory.cpp
) )
# Add include paths for the executable # Add include paths for the executable
target_include_directories(${TARGET_NAME} target_include_directories(${TARGET_NAME} PUBLIC
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}
) )