Compare commits
135 Commits
possible_t
...
354e158cc1
Author | SHA1 | Date | |
---|---|---|---|
354e158cc1 | |||
5ee315f8ca | |||
69922e77c5 | |||
01e380c858 | |||
6881c6b66a | |||
d4bdf314f7 | |||
be8623a4f8 | |||
304d7e8e32 | |||
f2020b2492 | |||
5a045d03a5 | |||
c7ce568a30 | |||
80ccaede02 | |||
5fd7a8c9b7 | |||
254aac51ec | |||
9b7da4d9e6 | |||
71036bf6b1 | |||
d6b3167922 | |||
68fe94d594 | |||
62a6e5da0b | |||
45c0074bd7 | |||
df0adfb33c | |||
98deac1ef1 | |||
ba6cbde28a | |||
a84c770dfb | |||
9546495507 | |||
e227b5dead | |||
9db5f893d7 | |||
4b3e753e19 | |||
36607c8764 | |||
b88e6c0713 | |||
6ee2c65187 | |||
2b6c996364 | |||
dabb488c9d | |||
![]() |
16b125ef6c | ||
![]() |
10f8a0fd0e | ||
![]() |
48a24d7dba | ||
e0671a395e | |||
665be0d417 | |||
![]() |
e7df520780 | ||
dd610f0d7e | |||
0987a160c9 | |||
ceeb0c5388 | |||
91f7184ebb | |||
e1a85b47c5 | |||
a3eb870ba0 | |||
ed2263b5f7 | |||
dccc2f0ba7 | |||
350fbc385c | |||
c9b343ebcd | |||
81c33d2dc6 | |||
29c74283f1 | |||
c51d2df43d | |||
d3b83f3cf9 | |||
60229da670 | |||
5c56eda610 | |||
3d1be94e12 | |||
8e65d2d3fc | |||
8374d495fa | |||
e02879184b | |||
![]() |
70a3749dbe | ||
87b68e84be | |||
7000ba05c5 | |||
9948c4f31d | |||
784a0140f4 | |||
635432d7ba | |||
e8050183f4 | |||
7d44aab98e | |||
4489a61a00 | |||
b1a56a71cd | |||
6d0d04ac23 | |||
8f3edc90ba | |||
7b5334ccec | |||
a58016859b | |||
0df8d35802 | |||
823c6ec5fc | |||
bc6b29e652 | |||
d986ab7720 | |||
bdd7d59d82 | |||
edf33cc10a | |||
6db5011b14 | |||
97494a84df | |||
40adca5f1d | |||
a8167f5431 | |||
41f3d7cf9a | |||
e6e1936293 | |||
15f35f200a | |||
6b20bb197a | |||
215d01b3ca | |||
dfe49cc1e5 | |||
73eb11f4f1 | |||
924c150af2 | |||
469eba3ce2 | |||
fd2916af11 | |||
afd375a7f8 | |||
5454169e20 | |||
7d0377845b | |||
882da68a2f | |||
04a1fe7f10 | |||
5f79f987ae | |||
1183e5739d | |||
e3697d6d8c | |||
406b77ea81 | |||
8a9eb27458 | |||
1ac372cb89 | |||
fb36dc4501 | |||
ba5e2ad8bb | |||
5a6c81130d | |||
22e29144b6 | |||
52bff3985f | |||
![]() |
133820f463 | ||
![]() |
8d3fceea8f | ||
3704d2b829 | |||
6073abb12d | |||
47bec654a0 | |||
b2c102b2c1 | |||
4202205182 | |||
c8472beb5f | |||
1a4a85ceb2 | |||
7922bf76da | |||
bb88490cc6 | |||
296c587e3d | |||
0ff81294e7 | |||
b6e243b8b3 | |||
3bbcc42d39 | |||
fc4324a2fa | |||
54c028f913 | |||
1f6a5e635f | |||
c5b4b01362 | |||
c5420c7b53 | |||
3e422f51bd | |||
d1be0f9843 | |||
![]() |
b83259592a | ||
a7a4e0f219 | |||
bdc5f593e2 | |||
10f7185e81 |
@@ -9,12 +9,13 @@ using gpioId_t = uint16_t;
|
||||
|
||||
namespace gpio {
|
||||
|
||||
enum Levels {
|
||||
enum Levels: uint8_t {
|
||||
LOW = 0,
|
||||
HIGH = 1
|
||||
HIGH = 1,
|
||||
NONE = 99
|
||||
};
|
||||
|
||||
enum Direction {
|
||||
enum Direction: uint8_t {
|
||||
IN = 0,
|
||||
OUT = 1
|
||||
};
|
||||
@@ -24,15 +25,18 @@ enum GpioOperation {
|
||||
WRITE
|
||||
};
|
||||
|
||||
enum GpioTypes {
|
||||
enum class GpioTypes {
|
||||
NONE,
|
||||
GPIO_REGULAR,
|
||||
GPIO_REGULAR_BY_CHIP,
|
||||
GPIO_REGULAR_BY_LABEL,
|
||||
GPIO_REGULAR_BY_LINE_NAME,
|
||||
CALLBACK
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
@@ -56,7 +60,7 @@ public:
|
||||
GpioBase() = default;
|
||||
|
||||
GpioBase(gpio::GpioTypes gpioType, std::string consumer, gpio::Direction direction,
|
||||
int initValue):
|
||||
gpio::Levels initValue):
|
||||
gpioType(gpioType), consumer(consumer),direction(direction), initValue(initValue) {}
|
||||
|
||||
virtual~ GpioBase() {};
|
||||
@@ -65,34 +69,90 @@ public:
|
||||
gpio::GpioTypes gpioType = gpio::GpioTypes::NONE;
|
||||
std::string consumer;
|
||||
gpio::Direction direction = gpio::Direction::IN;
|
||||
int initValue = 0;
|
||||
gpio::Levels initValue = gpio::Levels::NONE;
|
||||
};
|
||||
|
||||
class GpiodRegular: public GpioBase {
|
||||
class GpiodRegularBase: public GpioBase {
|
||||
public:
|
||||
GpiodRegular() :
|
||||
GpioBase(gpio::GpioTypes::GPIO_REGULAR, std::string(), gpio::Direction::IN, 0) {
|
||||
}
|
||||
;
|
||||
|
||||
GpiodRegular(std::string chipname_, int lineNum_, std::string consumer_,
|
||||
gpio::Direction direction_, int initValue_) :
|
||||
GpioBase(gpio::GpioTypes::GPIO_REGULAR, consumer_, direction_, initValue_),
|
||||
chipname(chipname_), lineNum(lineNum_) {
|
||||
GpiodRegularBase(gpio::GpioTypes gpioType, std::string consumer, gpio::Direction direction,
|
||||
gpio::Levels initValue, int lineNum):
|
||||
GpioBase(gpioType, consumer, direction, initValue), lineNum(lineNum) {
|
||||
}
|
||||
|
||||
GpiodRegular(std::string chipname_, int lineNum_, std::string consumer_) :
|
||||
GpioBase(gpio::GpioTypes::GPIO_REGULAR, consumer_, gpio::Direction::IN, 0),
|
||||
chipname(chipname_), 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) {
|
||||
}
|
||||
std::string chipname;
|
||||
|
||||
int lineNum = 0;
|
||||
struct gpiod_line* lineHandle = nullptr;
|
||||
};
|
||||
|
||||
class GpiodRegularByChip: public GpiodRegularBase {
|
||||
public:
|
||||
GpiodRegularByChip() :
|
||||
GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_CHIP,
|
||||
std::string(), gpio::Direction::IN, gpio::LOW, 0) {
|
||||
}
|
||||
|
||||
GpiodRegularByChip(std::string chipname_, int lineNum_, std::string consumer_,
|
||||
gpio::Direction direction_, gpio::Levels initValue_) :
|
||||
GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_CHIP,
|
||||
consumer_, direction_, initValue_, lineNum_),
|
||||
chipname(chipname_){
|
||||
}
|
||||
|
||||
GpiodRegularByChip(std::string chipname_, int lineNum_, std::string consumer_) :
|
||||
GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_CHIP, consumer_,
|
||||
gpio::Direction::IN, gpio::LOW, lineNum_),
|
||||
chipname(chipname_) {
|
||||
}
|
||||
|
||||
std::string chipname;
|
||||
};
|
||||
|
||||
class GpiodRegularByLabel: public GpiodRegularBase {
|
||||
public:
|
||||
GpiodRegularByLabel(std::string label_, int lineNum_, std::string consumer_,
|
||||
gpio::Direction direction_, gpio::Levels initValue_) :
|
||||
GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_LABEL, consumer_,
|
||||
direction_, initValue_, lineNum_),
|
||||
label(label_) {
|
||||
}
|
||||
|
||||
GpiodRegularByLabel(std::string label_, int lineNum_, std::string consumer_) :
|
||||
GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_LABEL, consumer_,
|
||||
gpio::Direction::IN, gpio::LOW, lineNum_),
|
||||
label(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 {
|
||||
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):
|
||||
GpioBase(gpio::GpioTypes::CALLBACK, consumer, direction_, initValue_),
|
||||
callback(callback), callbackArgs(callbackArgs) {}
|
||||
|
@@ -73,7 +73,7 @@ ReturnValue_t MgmLIS3MDLHandler::buildTransitionDeviceCommand(
|
||||
switch (internalState) {
|
||||
case(InternalState::STATE_NONE):
|
||||
case(InternalState::STATE_NORMAL): {
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
return DeviceHandlerBase::NOTHING_TO_SEND;
|
||||
}
|
||||
case(InternalState::STATE_FIRST_CONTACT): {
|
||||
*id = MGMLIS3MDL::IDENTIFY_DEVICE;
|
||||
|
@@ -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/GpioCookie.h"
|
||||
|
||||
#include <fsfw/serviceinterface/ServiceInterface.h>
|
||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||
|
||||
#include <utility>
|
||||
#include <unistd.h>
|
||||
@@ -20,7 +21,7 @@ LinuxLibgpioIF::~LinuxLibgpioIF() {
|
||||
ReturnValue_t LinuxLibgpioIF::addGpios(GpioCookie* gpioCookie) {
|
||||
ReturnValue_t result;
|
||||
if(gpioCookie == nullptr) {
|
||||
sif::error << "LinuxLibgpioIF::initialize: Invalid cookie" << std::endl;
|
||||
sif::error << "LinuxLibgpioIF::addGpios: Invalid cookie" << std::endl;
|
||||
return RETURN_FAILED;
|
||||
}
|
||||
|
||||
@@ -45,16 +46,33 @@ ReturnValue_t LinuxLibgpioIF::addGpios(GpioCookie* gpioCookie) {
|
||||
|
||||
ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) {
|
||||
for(auto& gpioConfig: mapToAdd) {
|
||||
switch(gpioConfig.second->gpioType) {
|
||||
auto& gpioType = gpioConfig.second->gpioType;
|
||||
switch(gpioType) {
|
||||
case(gpio::GpioTypes::NONE): {
|
||||
return GPIO_INVALID_INSTANCE;
|
||||
}
|
||||
case(gpio::GpioTypes::GPIO_REGULAR): {
|
||||
GpiodRegular* regularGpio = dynamic_cast<GpiodRegular*>(gpioConfig.second);
|
||||
case(gpio::GpioTypes::GPIO_REGULAR_BY_CHIP): {
|
||||
auto regularGpio = dynamic_cast<GpiodRegularByChip*>(gpioConfig.second);
|
||||
if(regularGpio == nullptr) {
|
||||
return GPIO_INVALID_INSTANCE;
|
||||
}
|
||||
configureRegularGpio(gpioConfig.first, regularGpio);
|
||||
configureGpioByChip(gpioConfig.first, *regularGpio);
|
||||
break;
|
||||
}
|
||||
case(gpio::GpioTypes::GPIO_REGULAR_BY_LABEL):{
|
||||
auto regularGpio = dynamic_cast<GpiodRegularByLabel*>(gpioConfig.second);
|
||||
if(regularGpio == nullptr) {
|
||||
return GPIO_INVALID_INSTANCE;
|
||||
}
|
||||
configureGpioByLabel(gpioConfig.first, *regularGpio);
|
||||
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): {
|
||||
@@ -70,57 +88,88 @@ ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) {
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t LinuxLibgpioIF::configureRegularGpio(gpioId_t gpioId, GpiodRegular *regularGpio) {
|
||||
std::string chipname;
|
||||
ReturnValue_t LinuxLibgpioIF::configureGpioByLabel(gpioId_t gpioId,
|
||||
GpiodRegularByLabel &gpioByLabel) {
|
||||
std::string& label = gpioByLabel.label;
|
||||
struct gpiod_chip* chip = gpiod_chip_open_by_label(label.c_str());
|
||||
if (chip == nullptr) {
|
||||
sif::warning << "LinuxLibgpioIF::configureGpioByLabel: Failed to open gpio from gpio "
|
||||
<< "group with label " << label << ". Gpio ID: " << gpioId << std::endl;
|
||||
return RETURN_FAILED;
|
||||
|
||||
}
|
||||
std::string failOutput = "label: " + label;
|
||||
return configureRegularGpio(gpioId, chip, gpioByLabel, failOutput);
|
||||
}
|
||||
|
||||
ReturnValue_t LinuxLibgpioIF::configureGpioByChip(gpioId_t gpioId,
|
||||
GpiodRegularByChip &gpioByChip) {
|
||||
std::string& chipname = gpioByChip.chipname;
|
||||
struct gpiod_chip* chip = gpiod_chip_open_by_name(chipname.c_str());
|
||||
if (chip == nullptr) {
|
||||
sif::warning << "LinuxLibgpioIF::configureGpioByChip: Failed to open chip "
|
||||
<< chipname << ". Gpio ID: " << gpioId << std::endl;
|
||||
return RETURN_FAILED;
|
||||
}
|
||||
std::string failOutput = "chipname: " + chipname;
|
||||
return configureRegularGpio(gpioId, chip, gpioByChip, failOutput);
|
||||
}
|
||||
|
||||
ReturnValue_t LinuxLibgpioIF::configureGpioByLineName(gpioId_t gpioId,
|
||||
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;
|
||||
struct gpiod_chip *chip;
|
||||
gpio::Direction direction;
|
||||
std::string consumer;
|
||||
struct gpiod_line *lineHandle;
|
||||
int result = 0;
|
||||
|
||||
chipname = regularGpio->chipname;
|
||||
chip = gpiod_chip_open_by_name(chipname.c_str());
|
||||
if (!chip) {
|
||||
sif::warning << "LinuxLibgpioIF::configureRegularGpio: Failed to open chip "
|
||||
<< chipname << ". Gpio ID: " << gpioId << std::endl;
|
||||
return RETURN_FAILED;
|
||||
}
|
||||
|
||||
lineNum = regularGpio->lineNum;
|
||||
lineNum = regularGpio.lineNum;
|
||||
lineHandle = gpiod_chip_get_line(chip, lineNum);
|
||||
if (!lineHandle) {
|
||||
sif::debug << "LinuxLibgpioIF::configureRegularGpio: Failed to open line " << std::endl;
|
||||
sif::debug << "GPIO ID: " << gpioId << ", line number: " << lineNum <<
|
||||
", chipname: " << chipname << std::endl;
|
||||
sif::debug << "Check if linux GPIO configuration has changed. " << std::endl;
|
||||
sif::warning << "LinuxLibgpioIF::configureRegularGpio: Failed to open line " << std::endl;
|
||||
sif::warning << "GPIO ID: " << gpioId << ", line number: " << lineNum <<
|
||||
", " << failOutput << std::endl;
|
||||
sif::warning << "Check if Linux GPIO configuration has changed. " << std::endl;
|
||||
gpiod_chip_close(chip);
|
||||
return RETURN_FAILED;
|
||||
}
|
||||
|
||||
direction = regularGpio->direction;
|
||||
consumer = regularGpio->consumer;
|
||||
direction = regularGpio.direction;
|
||||
consumer = regularGpio.consumer;
|
||||
/* Configure direction and add a description to the GPIO */
|
||||
switch (direction) {
|
||||
case(gpio::OUT): {
|
||||
result = gpiod_line_request_output(lineHandle, consumer.c_str(),
|
||||
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;
|
||||
}
|
||||
regularGpio.initValue);
|
||||
break;
|
||||
}
|
||||
case(gpio::IN): {
|
||||
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;
|
||||
}
|
||||
default: {
|
||||
@@ -129,12 +178,24 @@ ReturnValue_t LinuxLibgpioIF::configureRegularGpio(gpioId_t gpioId, GpiodRegular
|
||||
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
|
||||
* read states of GPIOs.
|
||||
*/
|
||||
regularGpio->lineHandle = lineHandle;
|
||||
regularGpio.lineHandle = lineHandle;
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
@@ -145,8 +206,15 @@ ReturnValue_t LinuxLibgpioIF::pullHigh(gpioId_t gpioId) {
|
||||
return UNKNOWN_GPIO_ID;
|
||||
}
|
||||
|
||||
if(gpioMapIter->second->gpioType == gpio::GpioTypes::GPIO_REGULAR) {
|
||||
return driveGpio(gpioId, dynamic_cast<GpiodRegular*>(gpioMapIter->second), 1);
|
||||
auto gpioType = gpioMapIter->second->gpioType;
|
||||
if (gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_CHIP
|
||||
or gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_LABEL
|
||||
or gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME) {
|
||||
auto regularGpio = dynamic_cast<GpiodRegularBase*>(gpioMapIter->second);
|
||||
if(regularGpio == nullptr) {
|
||||
return GPIO_TYPE_FAILURE;
|
||||
}
|
||||
return driveGpio(gpioId, *regularGpio, gpio::HIGH);
|
||||
}
|
||||
else {
|
||||
auto gpioCallback = dynamic_cast<GpioCallback*>(gpioMapIter->second);
|
||||
@@ -154,7 +222,7 @@ ReturnValue_t LinuxLibgpioIF::pullHigh(gpioId_t gpioId) {
|
||||
return GPIO_INVALID_INSTANCE;
|
||||
}
|
||||
gpioCallback->callback(gpioMapIter->first, gpio::GpioOperation::WRITE,
|
||||
1, gpioCallback->callbackArgs);
|
||||
gpio::Levels::HIGH, gpioCallback->callbackArgs);
|
||||
return RETURN_OK;
|
||||
}
|
||||
return GPIO_TYPE_FAILURE;
|
||||
@@ -163,12 +231,23 @@ ReturnValue_t LinuxLibgpioIF::pullHigh(gpioId_t gpioId) {
|
||||
ReturnValue_t LinuxLibgpioIF::pullLow(gpioId_t gpioId) {
|
||||
gpioMapIter = gpioMap.find(gpioId);
|
||||
if (gpioMapIter == gpioMap.end()) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
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;
|
||||
}
|
||||
|
||||
if(gpioMapIter->second->gpioType == gpio::GpioTypes::GPIO_REGULAR) {
|
||||
return driveGpio(gpioId, dynamic_cast<GpiodRegular*>(gpioMapIter->second), 0);
|
||||
auto& gpioType = gpioMapIter->second->gpioType;
|
||||
if (gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_CHIP
|
||||
or gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_LABEL
|
||||
or gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME) {
|
||||
auto regularGpio = dynamic_cast<GpiodRegularBase*>(gpioMapIter->second);
|
||||
if(regularGpio == nullptr) {
|
||||
return GPIO_TYPE_FAILURE;
|
||||
}
|
||||
return driveGpio(gpioId, *regularGpio, gpio::LOW);
|
||||
}
|
||||
else {
|
||||
auto gpioCallback = dynamic_cast<GpioCallback*>(gpioMapIter->second);
|
||||
@@ -176,22 +255,23 @@ ReturnValue_t LinuxLibgpioIF::pullLow(gpioId_t gpioId) {
|
||||
return GPIO_INVALID_INSTANCE;
|
||||
}
|
||||
gpioCallback->callback(gpioMapIter->first, gpio::GpioOperation::WRITE,
|
||||
0, gpioCallback->callbackArgs);
|
||||
gpio::Levels::LOW, gpioCallback->callbackArgs);
|
||||
return RETURN_OK;
|
||||
}
|
||||
return GPIO_TYPE_FAILURE;
|
||||
}
|
||||
|
||||
ReturnValue_t LinuxLibgpioIF::driveGpio(gpioId_t gpioId,
|
||||
GpiodRegular* regularGpio, unsigned int logicLevel) {
|
||||
if(regularGpio == nullptr) {
|
||||
return GPIO_TYPE_FAILURE;
|
||||
}
|
||||
|
||||
int result = gpiod_line_set_value(regularGpio->lineHandle, logicLevel);
|
||||
GpiodRegularBase& regularGpio, gpio::Levels logicLevel) {
|
||||
int result = gpiod_line_set_value(regularGpio.lineHandle, logicLevel);
|
||||
if (result < 0) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "LinuxLibgpioIF::driveGpio: Failed to pull GPIO with ID " << gpioId <<
|
||||
" 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;
|
||||
}
|
||||
|
||||
@@ -201,22 +281,33 @@ ReturnValue_t LinuxLibgpioIF::driveGpio(gpioId_t gpioId,
|
||||
ReturnValue_t LinuxLibgpioIF::readGpio(gpioId_t gpioId, int* gpioState) {
|
||||
gpioMapIter = gpioMap.find(gpioId);
|
||||
if (gpioMapIter == gpioMap.end()){
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
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;
|
||||
}
|
||||
|
||||
if(gpioMapIter->second->gpioType == gpio::GpioTypes::GPIO_REGULAR) {
|
||||
GpiodRegular* regularGpio = dynamic_cast<GpiodRegular*>(gpioMapIter->second);
|
||||
auto gpioType = gpioMapIter->second->gpioType;
|
||||
if (gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_CHIP
|
||||
or gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_LABEL
|
||||
or gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME) {
|
||||
auto regularGpio = dynamic_cast<GpiodRegularBase*>(gpioMapIter->second);
|
||||
if(regularGpio == nullptr) {
|
||||
return GPIO_TYPE_FAILURE;
|
||||
}
|
||||
*gpioState = gpiod_line_get_value(regularGpio->lineHandle);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -225,13 +316,15 @@ ReturnValue_t LinuxLibgpioIF::checkForConflicts(GpioMap& mapToAdd){
|
||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
||||
for(auto& gpioConfig: mapToAdd) {
|
||||
switch(gpioConfig.second->gpioType) {
|
||||
case(gpio::GpioTypes::GPIO_REGULAR): {
|
||||
auto regularGpio = dynamic_cast<GpiodRegular*>(gpioConfig.second);
|
||||
case(gpio::GpioTypes::GPIO_REGULAR_BY_CHIP):
|
||||
case(gpio::GpioTypes::GPIO_REGULAR_BY_LABEL):
|
||||
case(gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME): {
|
||||
auto regularGpio = dynamic_cast<GpiodRegularBase*>(gpioConfig.second);
|
||||
if(regularGpio == nullptr) {
|
||||
return GPIO_TYPE_FAILURE;
|
||||
}
|
||||
/* Check for conflicts and remove duplicates if necessary */
|
||||
result = checkForConflictsRegularGpio(gpioConfig.first, regularGpio, mapToAdd);
|
||||
// Check for conflicts and remove duplicates if necessary
|
||||
result = checkForConflictsById(gpioConfig.first, gpioConfig.second->gpioType, mapToAdd);
|
||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||
status = result;
|
||||
}
|
||||
@@ -242,15 +335,22 @@ ReturnValue_t LinuxLibgpioIF::checkForConflicts(GpioMap& mapToAdd){
|
||||
if(callbackGpio == nullptr) {
|
||||
return GPIO_TYPE_FAILURE;
|
||||
}
|
||||
/* Check for conflicts and remove duplicates if necessary */
|
||||
result = checkForConflictsCallbackGpio(gpioConfig.first, callbackGpio, mapToAdd);
|
||||
// Check for conflicts and remove duplicates if necessary
|
||||
result = checkForConflictsById(gpioConfig.first,
|
||||
gpioConfig.second->gpioType, mapToAdd);
|
||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||
status = result;
|
||||
}
|
||||
break;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -258,48 +358,86 @@ ReturnValue_t LinuxLibgpioIF::checkForConflicts(GpioMap& mapToAdd){
|
||||
}
|
||||
|
||||
|
||||
ReturnValue_t LinuxLibgpioIF::checkForConflictsRegularGpio(gpioId_t gpioIdToCheck,
|
||||
GpiodRegular* gpioToCheck, GpioMap& mapToAdd) {
|
||||
/* Cross check with private map */
|
||||
ReturnValue_t LinuxLibgpioIF::checkForConflictsById(gpioId_t gpioIdToCheck,
|
||||
gpio::GpioTypes expectedType, GpioMap& mapToAdd) {
|
||||
// Cross check with private map
|
||||
gpioMapIter = gpioMap.find(gpioIdToCheck);
|
||||
if(gpioMapIter != gpioMap.end()) {
|
||||
if(gpioMapIter->second->gpioType != gpio::GpioTypes::GPIO_REGULAR) {
|
||||
sif::warning << "LinuxLibgpioIF::checkForConflicts: ID already exists for different "
|
||||
"GPIO type" << gpioIdToCheck << ". Removing duplicate." << std::endl;
|
||||
mapToAdd.erase(gpioIdToCheck);
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
auto& gpioType = gpioMapIter->second->gpioType;
|
||||
bool eraseDuplicateDifferentType = false;
|
||||
switch(expectedType) {
|
||||
case(gpio::GpioTypes::NONE): {
|
||||
break;
|
||||
}
|
||||
auto ownRegularGpio = dynamic_cast<GpiodRegular*>(gpioMapIter->second);
|
||||
if(ownRegularGpio == nullptr) {
|
||||
return GPIO_TYPE_FAILURE;
|
||||
case(gpio::GpioTypes::GPIO_REGULAR_BY_CHIP):
|
||||
case(gpio::GpioTypes::GPIO_REGULAR_BY_LABEL):
|
||||
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
|
||||
already exists */
|
||||
sif::warning << "LinuxLibgpioIF::checkForConflictsRegularGpio: Duplicate GPIO definition"
|
||||
<< " detected. Duplicate will be removed from map to add." << std::endl;
|
||||
// Remove element from map to add because a entry for this GPIO already exists
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "LinuxLibgpioIF::checkForConflictsRegularGpio: Duplicate GPIO "
|
||||
"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);
|
||||
return GPIO_DUPLICATE_DETECTED;
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t LinuxLibgpioIF::checkForConflictsCallbackGpio(gpioId_t gpioIdToCheck,
|
||||
GpioCallback *callbackGpio, GpioMap& mapToAdd) {
|
||||
/* Cross check with private map */
|
||||
gpioMapIter = gpioMap.find(gpioIdToCheck);
|
||||
if(gpioMapIter != gpioMap.end()) {
|
||||
if(gpioMapIter->second->gpioType != gpio::GpioTypes::CALLBACK) {
|
||||
sif::warning << "LinuxLibgpioIF::checkForConflicts: ID already exists for different "
|
||||
"GPIO type" << gpioIdToCheck << ". Removing duplicate." << std::endl;
|
||||
mapToAdd.erase(gpioIdToCheck);
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
void LinuxLibgpioIF::parseFindeLineResult(int result, std::string& lineName) {
|
||||
switch (result) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
case LINE_NOT_EXISTS:
|
||||
case LINE_ERROR: {
|
||||
sif::warning << "LinuxLibgpioIF::parseFindeLineResult: Line with name " << lineName <<
|
||||
" does not exist" << std::endl;
|
||||
break;
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,18 +1,19 @@
|
||||
#ifndef LINUX_GPIO_LINUXLIBGPIOIF_H_
|
||||
#define LINUX_GPIO_LINUXLIBGPIOIF_H_
|
||||
|
||||
#include "../../common/gpio/GpioIF.h"
|
||||
#include <returnvalues/classIds.h>
|
||||
#include <fsfw/objectmanager/SystemObject.h>
|
||||
#include "fsfw/returnvalues/FwClassIds.h"
|
||||
#include "fsfw_hal/common/gpio/GpioIF.h"
|
||||
#include "fsfw/objectmanager/SystemObject.h"
|
||||
|
||||
class GpioCookie;
|
||||
class GpiodRegularIF;
|
||||
|
||||
/**
|
||||
* @brief This class implements the GpioIF for a linux based system. The
|
||||
* implementation is based on the libgpiod lib which requires linux 4.8
|
||||
* or higher.
|
||||
* @note The Petalinux SDK from Xilinx supports libgpiod since Petalinux
|
||||
* 2019.1.
|
||||
* @brief This class implements the GpioIF for a linux based system.
|
||||
* @details
|
||||
* 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 2019.1.
|
||||
*/
|
||||
class LinuxLibgpioIF : public GpioIF, public SystemObject {
|
||||
public:
|
||||
@@ -27,6 +28,8 @@ public:
|
||||
HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 3);
|
||||
static constexpr ReturnValue_t GPIO_INVALID_INSTANCE =
|
||||
HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 4);
|
||||
static constexpr ReturnValue_t GPIO_DUPLICATE_DETECTED =
|
||||
HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 5);
|
||||
|
||||
LinuxLibgpioIF(object_id_t objectId);
|
||||
virtual ~LinuxLibgpioIF();
|
||||
@@ -37,7 +40,13 @@ public:
|
||||
ReturnValue_t readGpio(gpioId_t gpioId, int* gpioState) override;
|
||||
|
||||
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;
|
||||
GpioUnorderedMapIter gpioMapIter;
|
||||
|
||||
@@ -47,9 +56,15 @@ private:
|
||||
* @param gpioId The GPIO ID of the GPIO to drive.
|
||||
* @param logiclevel The logic level to set. O or 1.
|
||||
*/
|
||||
ReturnValue_t driveGpio(gpioId_t gpioId, GpiodRegular* regularGpio, unsigned int logiclevel);
|
||||
ReturnValue_t driveGpio(gpioId_t gpioId, GpiodRegularBase& regularGpio,
|
||||
gpio::Levels logicLevel);
|
||||
|
||||
ReturnValue_t configureRegularGpio(gpioId_t gpioId, GpiodRegular* regularGpio);
|
||||
ReturnValue_t configureGpioByLabel(gpioId_t gpioId, GpiodRegularByLabel& gpioByLabel);
|
||||
ReturnValue_t configureGpioByChip(gpioId_t gpioId, GpiodRegularByChip& gpioByChip);
|
||||
ReturnValue_t configureGpioByLineName(gpioId_t gpioId,
|
||||
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
|
||||
@@ -62,16 +77,15 @@ private:
|
||||
*/
|
||||
ReturnValue_t checkForConflicts(GpioMap& mapToAdd);
|
||||
|
||||
ReturnValue_t checkForConflictsRegularGpio(gpioId_t gpiodId, GpiodRegular* regularGpio,
|
||||
ReturnValue_t checkForConflictsById(gpioId_t gpiodId, gpio::GpioTypes type,
|
||||
GpioMap& mapToAdd);
|
||||
ReturnValue_t checkForConflictsCallbackGpio(gpioId_t gpiodId, GpioCallback* regularGpio,
|
||||
GpioMap& mapToAdd);
|
||||
|
||||
/**
|
||||
* @brief Performs the initial configuration of all GPIOs specified in the GpioMap mapToAdd.
|
||||
*/
|
||||
ReturnValue_t configureGpios(GpioMap& mapToAdd);
|
||||
|
||||
void parseFindeLineResult(int result, std::string& lineName);
|
||||
};
|
||||
|
||||
#endif /* LINUX_GPIO_LINUXLIBGPIOIF_H_ */
|
||||
|
@@ -12,7 +12,7 @@ ReturnValue_t gpio::createRpiGpioConfig(GpioCookie* cookie, gpioId_t gpioId, int
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
|
||||
GpiodRegular* config = new GpiodRegular();
|
||||
auto config = new GpiodRegularByChip();
|
||||
/* Default chipname for Raspberry Pi. There is still gpiochip1 for expansion, but most users
|
||||
will not need this */
|
||||
config->chipname = "gpiochip0";
|
||||
|
@@ -141,8 +141,8 @@ ReturnValue_t SpiComIF::sendMessage(CookieIF *cookie, const uint8_t *sendData, s
|
||||
if(sendLen > spiCookie->getMaxBufferSize()) {
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "SpiComIF::sendMessage: Too much data sent, send length" << sendLen <<
|
||||
"larger than maximum buffer length" << spiCookie->getMaxBufferSize() << std::endl;
|
||||
sif::warning << "SpiComIF::sendMessage: Too much data sent, send length " << sendLen <<
|
||||
"larger than maximum buffer length " << spiCookie->getMaxBufferSize() << std::endl;
|
||||
#else
|
||||
sif::printWarning("SpiComIF::sendMessage: Too much data sent, send length %lu larger "
|
||||
"than maximum buffer length %lu!\n", static_cast<unsigned long>(sendLen),
|
||||
@@ -197,12 +197,26 @@ ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie *spiCookie, const
|
||||
if(gpioId != gpio::NO_GPIO) {
|
||||
result = spiMutex->lockMutex(timeoutType, timeoutMs);
|
||||
if (result != RETURN_OK) {
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "SpiComIF::sendMessage: Failed to lock mutex" << std::endl;
|
||||
#else
|
||||
sif::printError("SpiComIF::sendMessage: Failed to lock mutex\n");
|
||||
#endif
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
ReturnValue_t result = gpioComIF->pullLow(gpioId);
|
||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "SpiComIF::sendMessage: Pulling low CS pin failed" << std::endl;
|
||||
#else
|
||||
sif::printWarning("SpiComIF::sendMessage: Pulling low CS pin failed");
|
||||
#endif
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
gpioComIF->pullLow(gpioId);
|
||||
}
|
||||
|
||||
/* Execute transfer */
|
||||
@@ -213,7 +227,7 @@ ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie *spiCookie, const
|
||||
utility::handleIoctlError("SpiComIF::sendMessage: ioctl error.");
|
||||
result = FULL_DUPLEX_TRANSFER_FAILED;
|
||||
}
|
||||
#if FSFW_HAL_LINUX_SPI_WIRETAPPING == 1
|
||||
#if FSFW_HAL_SPI_WIRETAPPING == 1
|
||||
performSpiWiretapping(spiCookie);
|
||||
#endif /* FSFW_LINUX_SPI_WIRETAPPING == 1 */
|
||||
}
|
||||
@@ -384,11 +398,11 @@ GpioIF* SpiComIF::getGpioInterface() {
|
||||
void SpiComIF::setSpiSpeedAndMode(int spiFd, spi::SpiModes mode, uint32_t speed) {
|
||||
int retval = ioctl(spiFd, SPI_IOC_WR_MODE, reinterpret_cast<uint8_t*>(&mode));
|
||||
if(retval != 0) {
|
||||
utility::handleIoctlError("SpiTestClass::performRm3100Test: Setting SPI mode failed!");
|
||||
utility::handleIoctlError("SpiComIF::setSpiSpeedAndMode: Setting SPI mode failed");
|
||||
}
|
||||
|
||||
retval = ioctl(spiFd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
|
||||
if(retval != 0) {
|
||||
utility::handleIoctlError("SpiTestClass::performRm3100Test: Setting SPI speed failed!");
|
||||
utility::handleIoctlError("SpiComIF::setSpiSpeedAndMode: Setting SPI speed failed");
|
||||
}
|
||||
}
|
||||
|
@@ -16,6 +16,15 @@
|
||||
#cmakedefine FSFW_ADD_MONITORING
|
||||
#cmakedefine FSFW_ADD_SGP4_PROPAGATOR
|
||||
|
||||
#ifndef FSFW_TCP_RECV_WIRETAPPING_ENABLED
|
||||
#define FSFW_TCP_RECV_WIRETAPPING_ENABLED 0
|
||||
#endif
|
||||
|
||||
// Can be used for low-level debugging of the SPI bus
|
||||
#ifndef FSFW_HAL_SPI_WIRETAPPING
|
||||
#define FSFW_HAL_SPI_WIRETAPPING 0
|
||||
#endif
|
||||
|
||||
#ifndef FSFW_HAL_L3GD20_GYRO_DEBUG
|
||||
#define FSFW_HAL_L3GD20_GYRO_DEBUG 0
|
||||
#endif /* FSFW_HAL_L3GD20_GYRO_DEBUG */
|
||||
|
@@ -5,8 +5,7 @@
|
||||
#include <cstddef>
|
||||
|
||||
/**
|
||||
* @brief Circular buffer implementation, useful for buffering
|
||||
* into data streams.
|
||||
* @brief Circular buffer implementation, useful for buffering into data streams.
|
||||
* @details
|
||||
* Note that the deleteData() has to be called to increment the read pointer.
|
||||
* This class allocated dynamically, so
|
||||
@@ -20,8 +19,8 @@ public:
|
||||
* @param size
|
||||
* @param overwriteOld If the ring buffer is overflowing at a write
|
||||
* operation, the oldest data will be overwritten.
|
||||
* @param maxExcessBytes These additional bytes will be allocated in addtion
|
||||
* to the specified size to accomodate contiguous write operations
|
||||
* @param maxExcessBytes These additional bytes will be allocated in addition
|
||||
* to the specified size to accommodate continuous write operations
|
||||
* with getFreeElement.
|
||||
*
|
||||
*/
|
||||
@@ -32,10 +31,10 @@ public:
|
||||
* @param buffer
|
||||
* @param size
|
||||
* @param overwriteOld
|
||||
* If the ring buffer is overflowing at a write operartion, the oldest data
|
||||
* If the ring buffer is overflowing at a write operation, the oldest data
|
||||
* will be overwritten.
|
||||
* @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
|
||||
* size
|
||||
*/
|
||||
@@ -48,7 +47,7 @@ public:
|
||||
* Write to circular buffer and increment write pointer by amount.
|
||||
* @param data
|
||||
* @param amount
|
||||
* @return -@c RETURN_OK if write operation was successfull
|
||||
* @return -@c RETURN_OK if write operation was successful
|
||||
* -@c RETURN_FAILED if
|
||||
*/
|
||||
ReturnValue_t writeData(const uint8_t* data, size_t amount);
|
||||
@@ -108,7 +107,7 @@ public:
|
||||
* Delete data by incrementing read pointer.
|
||||
* @param amount
|
||||
* @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
|
||||
* @param trueAmount [out]
|
||||
* If deleteRemaining was set to true, the amount deleted will be assigned
|
||||
|
@@ -7,7 +7,7 @@
|
||||
|
||||
/**
|
||||
* @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
|
||||
* Documentation: Dissertation Baetz p.156, 157.
|
||||
*
|
||||
|
@@ -85,9 +85,10 @@ public:
|
||||
* Called by DHB in the GET_WRITE doGetWrite().
|
||||
* Get send confirmation that the data in sendMessage() was sent successfully.
|
||||
* @param cookie
|
||||
* @return - @c RETURN_OK if data was sent successfull
|
||||
* - Everything else triggers falure event with
|
||||
* returnvalue as parameter 1
|
||||
* @return
|
||||
* - @c RETURN_OK if data was sent successfully but a reply is expected
|
||||
* - 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;
|
||||
|
||||
|
@@ -334,8 +334,7 @@ protected:
|
||||
* - @c RETURN_OK to send command after #rawPacket and #rawPacketLen
|
||||
* have been set.
|
||||
* - @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
|
||||
* to finish the command handling.
|
||||
* be used if no reply is expected
|
||||
* - Anything else triggers an event with the return code as a parameter as well as a
|
||||
* step reply failed with the return code
|
||||
*/
|
||||
|
@@ -120,7 +120,8 @@ public:
|
||||
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 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 COMMAND_NOT_IMPLEMENTED = MAKE_RETURN_CODE(0xAA);
|
||||
|
||||
|
@@ -2,43 +2,42 @@
|
||||
|
||||
|
||||
PeriodicOperationDivider::PeriodicOperationDivider(uint32_t divider,
|
||||
bool resetAutomatically): resetAutomatically(resetAutomatically),
|
||||
counter(divider), divider(divider) {
|
||||
bool resetAutomatically): resetAutomatically(resetAutomatically),
|
||||
counter(divider), divider(divider) {
|
||||
}
|
||||
|
||||
bool PeriodicOperationDivider::checkAndIncrement() {
|
||||
bool opNecessary = check();
|
||||
if(opNecessary) {
|
||||
if(resetAutomatically) {
|
||||
counter = 0;
|
||||
}
|
||||
return opNecessary;
|
||||
}
|
||||
counter ++;
|
||||
return opNecessary;
|
||||
counter++;
|
||||
bool opNecessary = check();
|
||||
if(opNecessary) {
|
||||
if(resetAutomatically) {
|
||||
resetCounter();
|
||||
}
|
||||
}
|
||||
return opNecessary;
|
||||
}
|
||||
|
||||
bool PeriodicOperationDivider::check() {
|
||||
if(counter >= divider) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
if(counter >= divider) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void PeriodicOperationDivider::resetCounter() {
|
||||
counter = 0;
|
||||
counter = 0;
|
||||
}
|
||||
|
||||
void PeriodicOperationDivider::setDivider(uint32_t newDivider) {
|
||||
divider = newDivider;
|
||||
divider = newDivider;
|
||||
}
|
||||
|
||||
uint32_t PeriodicOperationDivider::getCounter() const {
|
||||
return counter;
|
||||
return counter;
|
||||
}
|
||||
|
||||
uint32_t PeriodicOperationDivider::getDivider() const {
|
||||
return divider;
|
||||
return divider;
|
||||
}
|
||||
|
@@ -13,51 +13,51 @@
|
||||
*/
|
||||
class PeriodicOperationDivider {
|
||||
public:
|
||||
/**
|
||||
* Initialize with the desired divider and specify whether the internal
|
||||
* counter will be reset automatically.
|
||||
* @param divider
|
||||
* @param resetAutomatically
|
||||
*/
|
||||
PeriodicOperationDivider(uint32_t divider, bool resetAutomatically = true);
|
||||
/**
|
||||
* Initialize with the desired divider and specify whether the internal
|
||||
* counter will be reset automatically.
|
||||
* @param divider
|
||||
* @param resetAutomatically
|
||||
*/
|
||||
PeriodicOperationDivider(uint32_t divider, bool resetAutomatically = true);
|
||||
|
||||
|
||||
/**
|
||||
* Check whether operation is necessary.
|
||||
* If an operation is necessary and the class has been
|
||||
* configured to be reset automatically, the counter will be reset.
|
||||
*
|
||||
* @return
|
||||
* -@c true if the counter is larger or equal to the divider
|
||||
* -@c false otherwise
|
||||
*/
|
||||
bool checkAndIncrement();
|
||||
/**
|
||||
* Check whether operation is necessary.
|
||||
* If an operation is necessary and the class has been
|
||||
* configured to be reset automatically, the counter will be reset.
|
||||
*
|
||||
* @return
|
||||
* -@c true if the counter is larger or equal to the divider
|
||||
* -@c false otherwise
|
||||
*/
|
||||
bool checkAndIncrement();
|
||||
|
||||
/**
|
||||
* Checks whether an operation is necessary.
|
||||
* This function will not increment the counter!
|
||||
* @return
|
||||
* -@c true if the counter is larger or equal to the divider
|
||||
* -@c false otherwise
|
||||
*/
|
||||
bool check();
|
||||
/**
|
||||
* Checks whether an operation is necessary.
|
||||
* This function will not increment the counter!
|
||||
* @return
|
||||
* -@c true if the counter is larger or equal to the divider
|
||||
* -@c false otherwise
|
||||
*/
|
||||
bool check();
|
||||
|
||||
/**
|
||||
* Can be used to reset the counter to 0 manually.
|
||||
*/
|
||||
void resetCounter();
|
||||
uint32_t getCounter() const;
|
||||
/**
|
||||
* Can be used to reset the counter to 0 manually.
|
||||
*/
|
||||
void resetCounter();
|
||||
uint32_t getCounter() const;
|
||||
|
||||
/**
|
||||
* Can be used to set a new divider value.
|
||||
* @param newDivider
|
||||
*/
|
||||
void setDivider(uint32_t newDivider);
|
||||
uint32_t getDivider() const;
|
||||
/**
|
||||
* Can be used to set a new divider value.
|
||||
* @param newDivider
|
||||
*/
|
||||
void setDivider(uint32_t newDivider);
|
||||
uint32_t getDivider() const;
|
||||
private:
|
||||
bool resetAutomatically = true;
|
||||
uint32_t counter = 0;
|
||||
uint32_t divider = 0;
|
||||
bool resetAutomatically = true;
|
||||
uint32_t counter = 0;
|
||||
uint32_t divider = 0;
|
||||
};
|
||||
|
||||
|
||||
|
@@ -81,7 +81,7 @@ public:
|
||||
* @param args Any other arguments which an implementation might require
|
||||
* @return
|
||||
*/
|
||||
virtual ReturnValue_t deleteFile(const char* repositoryPath,
|
||||
virtual ReturnValue_t removeFile(const char* repositoryPath,
|
||||
const char* filename, void* args = nullptr) = 0;
|
||||
|
||||
/**
|
||||
|
@@ -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/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/ipc/MessageQueueSenderIF.h"
|
||||
#include "fsfw/ipc/MutexGuard.h"
|
||||
#include "fsfw/objectmanager/ObjectManager.h"
|
||||
|
||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||
#include "fsfw/tmtcservices/TmTcMessage.h"
|
||||
|
||||
@@ -18,19 +22,14 @@
|
||||
#include <netdb.h>
|
||||
#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;
|
||||
|
||||
TcpTmTcServer::TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge,
|
||||
size_t receptionBufferSize, std::string customTcpServerPort):
|
||||
SystemObject(objectId), tmtcBridgeId(tmtcTcpBridge),
|
||||
tcpPort(customTcpServerPort), receptionBuffer(receptionBufferSize) {
|
||||
if(tcpPort == "") {
|
||||
tcpPort = DEFAULT_SERVER_PORT;
|
||||
}
|
||||
size_t receptionBufferSize, size_t ringBufferSize, std::string customTcpServerPort,
|
||||
ReceptionModes receptionMode):
|
||||
SystemObject(objectId), tmtcBridgeId(tmtcTcpBridge), receptionMode(receptionMode),
|
||||
tcpConfig(customTcpServerPort), receptionBuffer(receptionBufferSize),
|
||||
ringBuffer(ringBufferSize, true) {
|
||||
}
|
||||
|
||||
ReturnValue_t TcpTmTcServer::initialize() {
|
||||
@@ -41,6 +40,17 @@ ReturnValue_t TcpTmTcServer::initialize() {
|
||||
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);
|
||||
if (tcStore == nullptr) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
@@ -63,7 +73,7 @@ ReturnValue_t TcpTmTcServer::initialize() {
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
|
||||
// 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) {
|
||||
handleError(Protocol::TCP, ErrorSources::GETADDRINFO_CALL);
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
@@ -105,7 +115,7 @@ ReturnValue_t TcpTmTcServer::performOperation(uint8_t opCode) {
|
||||
|
||||
// Listen for connection requests permanently for lifetime of program
|
||||
while(true) {
|
||||
retval = listen(listenerTcpSocket, tcpBacklog);
|
||||
retval = listen(listenerTcpSocket, tcpConfig.tcpBacklog);
|
||||
if(retval == SOCKET_ERROR) {
|
||||
handleError(Protocol::TCP, ErrorSources::LISTEN_CALL, 500);
|
||||
continue;
|
||||
@@ -123,11 +133,12 @@ ReturnValue_t TcpTmTcServer::performOperation(uint8_t opCode) {
|
||||
handleServerOperation(connSocket);
|
||||
|
||||
// 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) {
|
||||
handleError(Protocol::TCP, ErrorSources::SHUTDOWN_CALL);
|
||||
}
|
||||
closeSocket(connSocket);
|
||||
connSocket = 0;
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
@@ -144,51 +155,94 @@ ReturnValue_t TcpTmTcServer::initializeAfterTaskCreation() {
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
void TcpTmTcServer::handleServerOperation(socket_t connSocket) {
|
||||
int retval = 0;
|
||||
do {
|
||||
// Read all telecommands sent by the client
|
||||
retval = recv(connSocket,
|
||||
void TcpTmTcServer::handleServerOperation(socket_t& connSocket) {
|
||||
#if defined PLATFORM_WIN
|
||||
setSocketNonBlocking(connSocket);
|
||||
#endif
|
||||
|
||||
while (true) {
|
||||
int retval = recv(
|
||||
connSocket,
|
||||
reinterpret_cast<char*>(receptionBuffer.data()),
|
||||
receptionBuffer.capacity(),
|
||||
tcpFlags);
|
||||
if (retval > 0) {
|
||||
handleTcReception(retval);
|
||||
tcpConfig.tcpFlags
|
||||
);
|
||||
if(retval == 0) {
|
||||
// Client closed connection
|
||||
return;
|
||||
}
|
||||
else if(retval == 0) {
|
||||
// Client has finished sending telecommands, send telemetry now
|
||||
handleTmSending(connSocket);
|
||||
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 {
|
||||
// Should not happen
|
||||
tcpip::handleError(tcpip::Protocol::TCP, tcpip::ErrorSources::RECV_CALL);
|
||||
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 {
|
||||
tcpip::handleError(tcpip::Protocol::TCP, tcpip::ErrorSources::RECV_CALL, 300);
|
||||
}
|
||||
}
|
||||
} while(retval > 0);
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t TcpTmTcServer::handleTcReception(size_t bytesRecvd) {
|
||||
#if FSFW_TCP_RECV_WIRETAPPING_ENABLED == 1
|
||||
arrayprinter::print(receptionBuffer.data(), bytesRead);
|
||||
#endif
|
||||
ReturnValue_t TcpTmTcServer::handleTcReception(uint8_t* spacePacket, size_t packetSize) {
|
||||
if(wiretappingEnabled) {
|
||||
sif::info << "Received TC:" << std::endl;
|
||||
arrayprinter::print(spacePacket, packetSize);
|
||||
}
|
||||
|
||||
if(spacePacket == nullptr or packetSize == 0) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
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 FSFW_VERBOSE_LEVEL >= 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning<< "TcpTmTcServer::handleServerOperation: Data storage failed." << std::endl;
|
||||
sif::warning << "Packet size: " << bytesRecvd << std::endl;
|
||||
sif::warning << "TcpTmTcServer::handleServerOperation: Data storage with packet size" <<
|
||||
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_VERBOSE_LEVEL >= 1 */
|
||||
return result;
|
||||
}
|
||||
|
||||
TmTcMessage message(storeId);
|
||||
|
||||
result = MessageQueueSenderIF::sendMessage(targetTcDestination, &message);
|
||||
result = MessageQueueSenderIF::sendMessage(targetTcDestination, &message);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "UdpTcPollingTask::handleSuccessfullTcRead: "
|
||||
sif::warning << "TcpTmTcServer::handleServerOperation: "
|
||||
" 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_VERBOSE_LEVEL >= 1 */
|
||||
tcStore->deleteData(storeId);
|
||||
@@ -196,21 +250,26 @@ ReturnValue_t TcpTmTcServer::handleTcReception(size_t bytesRecvd) {
|
||||
return result;
|
||||
}
|
||||
|
||||
void TcpTmTcServer::setTcpBacklog(uint8_t tcpBacklog) {
|
||||
this->tcpBacklog = tcpBacklog;
|
||||
}
|
||||
|
||||
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
|
||||
MutexGuard(tmtcBridge->mutex, tmtcBridge->timeoutType, tmtcBridge->mutexTimeoutMs);
|
||||
store_address_t storeId;
|
||||
while((not tmtcBridge->tmFifo->empty()) and
|
||||
(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
|
||||
ConstStorageAccessor storeAccessor(storeId);
|
||||
@@ -218,13 +277,130 @@ ReturnValue_t TcpTmTcServer::handleTmSending(socket_t connSocket) {
|
||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
if(wiretappingEnabled) {
|
||||
sif::info << "Sending TM:" << std::endl;
|
||||
arrayprinter::print(storeAccessor.data(), storeAccessor.size());
|
||||
}
|
||||
int retval = send(connSocket,
|
||||
reinterpret_cast<const char*>(storeAccessor.data()),
|
||||
storeAccessor.size(),
|
||||
tcpTmFlags);
|
||||
if(retval != static_cast<int>(storeAccessor.size())) {
|
||||
tcpip::handleError(tcpip::Protocol::TCP, tcpip::ErrorSources::SEND_CALL);
|
||||
tcpConfig.tcpTmFlags);
|
||||
if(retval == static_cast<int>(storeAccessor.size())) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
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
|
||||
|
@@ -6,6 +6,7 @@
|
||||
#include "fsfw/platform.h"
|
||||
#include "fsfw/osal/common/tcpipHelpers.h"
|
||||
#include "fsfw/ipc/messageQueueDefinitions.h"
|
||||
#include "fsfw/container/SimpleRingBuffer.h"
|
||||
#include "fsfw/ipc/MessageQueueIF.h"
|
||||
#include "fsfw/objectmanager/frameworkObjects.h"
|
||||
#include "fsfw/objectmanager/SystemObject.h"
|
||||
@@ -20,6 +21,7 @@
|
||||
#include <vector>
|
||||
|
||||
class TcpTmTcBridge;
|
||||
class SpacePacketParser;
|
||||
|
||||
/**
|
||||
* @brief TCP server implementation
|
||||
@@ -42,9 +44,38 @@ class TcpTmTcServer:
|
||||
public TcpIpBase,
|
||||
public ExecutableObjectIF {
|
||||
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 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
|
||||
@@ -55,11 +86,21 @@ public:
|
||||
* @param customTcpServerPort The user can specify another port than the default (7301) here.
|
||||
*/
|
||||
TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge,
|
||||
size_t receptionBufferSize = ETHERNET_MTU_SIZE + 1,
|
||||
std::string customTcpServerPort = "");
|
||||
size_t receptionBufferSize = RING_BUFFER_SIZE,
|
||||
size_t ringBufferSize = RING_BUFFER_SIZE,
|
||||
std::string customTcpServerPort = DEFAULT_SERVER_PORT,
|
||||
ReceptionModes receptionMode = ReceptionModes::SPACE_PACKETS);
|
||||
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 performOperation(uint8_t opCode) override;
|
||||
@@ -71,25 +112,33 @@ protected:
|
||||
StorageManagerIF* tcStore = nullptr;
|
||||
StorageManagerIF* tmStore = nullptr;
|
||||
private:
|
||||
static constexpr ReturnValue_t CONN_BROKEN = HasReturnvaluesIF::makeReturnCode(1, 0);
|
||||
//! TMTC bridge is cached.
|
||||
object_id_t tmtcBridgeId = objects::NO_OBJECT;
|
||||
TcpTmTcBridge* tmtcBridge = nullptr;
|
||||
bool wiretappingEnabled = false;
|
||||
|
||||
std::string tcpPort;
|
||||
int tcpFlags = 0;
|
||||
socket_t listenerTcpSocket = 0;
|
||||
ReceptionModes receptionMode;
|
||||
TcpConfig tcpConfig;
|
||||
struct sockaddr tcpAddress;
|
||||
socket_t listenerTcpSocket = 0;
|
||||
|
||||
MessageQueueId_t targetTcDestination = MessageQueueIF::NO_QUEUE;
|
||||
int tcpAddrLen = sizeof(tcpAddress);
|
||||
int tcpBacklog = 3;
|
||||
|
||||
std::vector<uint8_t> receptionBuffer;
|
||||
int tcpSockOpt = 0;
|
||||
int tcpTmFlags = 0;
|
||||
SimpleRingBuffer ringBuffer;
|
||||
std::vector<uint16_t> validPacketIds;
|
||||
SpacePacketParser* spacePacketParser = nullptr;
|
||||
uint8_t lastRingBufferSize = 0;
|
||||
|
||||
void handleServerOperation(socket_t connSocket);
|
||||
ReturnValue_t handleTcReception(size_t bytesRecvd);
|
||||
ReturnValue_t handleTmSending(socket_t connSocket);
|
||||
virtual void handleServerOperation(socket_t& connSocket);
|
||||
ReturnValue_t handleTcReception(uint8_t* spacePacket, size_t packetSize);
|
||||
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_ */
|
||||
|
@@ -16,6 +16,7 @@ target_sources(${LIB_FSFW_NAME}
|
||||
Timer.cpp
|
||||
tcpipHelpers.cpp
|
||||
unixUtility.cpp
|
||||
CommandExecutor.cpp
|
||||
)
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
|
185
src/fsfw/osal/linux/CommandExecutor.cpp
Normal file
185
src/fsfw/osal/linux/CommandExecutor.cpp
Normal file
@@ -0,0 +1,185 @@
|
||||
#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) {
|
||||
sif::error << funcName << " pclose failed with code " <<
|
||||
lastError << ": " << strerror(lastError) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
sif::warning << "CommandExecutor::check: "
|
||||
"No bytes read after poll event.." << std::endl;
|
||||
break;
|
||||
}
|
||||
else if(readBytes > 0) {
|
||||
bytesRead = true;
|
||||
if(printOutput) {
|
||||
// It is assumed the command output is line terminated
|
||||
sif::info << currentCmd << " | " << readVec.data();
|
||||
}
|
||||
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
|
||||
sif::warning << "CommandExecutor::check: Error " << errno << ": " <<
|
||||
strerror(errno) << std::endl;
|
||||
}
|
||||
}
|
||||
else if(waiter.revents & POLLERR) {
|
||||
sif::warning << "CommandExecuter::check: Poll error" << std::endl;
|
||||
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) {
|
||||
sif::info << currentCmd << " | " << output;
|
||||
}
|
||||
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;
|
||||
}
|
134
src/fsfw/osal/linux/CommandExecutor.h
Normal file
134
src/fsfw/osal/linux/CommandExecutor.h
Normal 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_ */
|
@@ -285,10 +285,10 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
|
||||
|
||||
utility::printUnixErrorGeneric(CLASS_NAME, "sendMessageFromMessageQueue", "EBADF");
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "mq_send to: " << sendTo << " sent from "
|
||||
<< sentFrom << "failed" << std::endl;
|
||||
sif::warning << "mq_send to " << sendTo << " sent from "
|
||||
<< sentFrom << " failed" << std::endl;
|
||||
#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
|
||||
return DESTINATION_INVALID;
|
||||
}
|
||||
|
@@ -27,6 +27,7 @@ int Timer::setTimer(uint32_t intervalMs) {
|
||||
timer.it_value.tv_nsec = (intervalMs * 1000000) % (1000000000);
|
||||
timer.it_interval.tv_sec = 0;
|
||||
timer.it_interval.tv_nsec = 0;
|
||||
set = true;
|
||||
return timer_settime(timerId, 0, &timer, NULL);
|
||||
}
|
||||
|
||||
@@ -43,3 +44,14 @@ int Timer::getTimer(uint32_t* remainingTimeMs){
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
bool Timer::isSet() const {
|
||||
return this->set;
|
||||
}
|
||||
|
||||
void Timer::resetTimer() {
|
||||
if(not this->set) {
|
||||
set = false;
|
||||
}
|
||||
setTimer(0);
|
||||
}
|
||||
|
@@ -38,7 +38,11 @@ public:
|
||||
*/
|
||||
int getTimer(uint32_t* remainingTimeMs);
|
||||
|
||||
bool isSet() const;
|
||||
void resetTimer();
|
||||
|
||||
private:
|
||||
bool set = true;
|
||||
timer_t timerId;
|
||||
};
|
||||
|
||||
|
@@ -41,8 +41,7 @@ ReturnValue_t Service5EventReporting::performService() {
|
||||
}
|
||||
}
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::debug << "Service5EventReporting::generateEventReport:"
|
||||
" Too many events" << std::endl;
|
||||
sif::warning << "Service5EventReporting::generateEventReport: Too many events" << std::endl;
|
||||
#endif
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
@@ -64,8 +63,11 @@ ReturnValue_t Service5EventReporting::generateEventReport(
|
||||
requestQueue->getDefaultDestination(),requestQueue->getId());
|
||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::debug << "Service5EventReporting::generateEventReport:"
|
||||
" Could not send TM packet" << std::endl;
|
||||
sif::warning << "Service5EventReporting::generateEventReport: "
|
||||
"Could not send TM packet" << std::endl;
|
||||
#else
|
||||
sif::printWarning("Service5EventReporting::generateEventReport: "
|
||||
"Could not send TM packet\n");
|
||||
#endif
|
||||
}
|
||||
return result;
|
||||
|
@@ -33,8 +33,8 @@ ReturnValue_t Service8FunctionManagement::getMessageQueueAndObject(
|
||||
if(tcDataLen < sizeof(object_id_t)) {
|
||||
return CommandingServiceBase::INVALID_TC;
|
||||
}
|
||||
SerializeAdapter::deSerialize(objectId, &tcData,
|
||||
&tcDataLen, SerializeIF::Endianness::BIG);
|
||||
// Can't fail, size was checked before
|
||||
SerializeAdapter::deSerialize(objectId, &tcData, &tcDataLen, SerializeIF::Endianness::BIG);
|
||||
|
||||
return checkInterfaceAndAcquireMessageQueue(id,objectId);
|
||||
}
|
||||
|
@@ -72,12 +72,15 @@ enum: uint8_t {
|
||||
PUS_SERVICE_3, //PUS3
|
||||
PUS_SERVICE_9, //PUS9
|
||||
FILE_SYSTEM, //FILS
|
||||
LINUX_OSAL, //UXOS
|
||||
HAL_SPI, //HSPI
|
||||
HAL_UART, //HURT
|
||||
HAL_I2C, //HI2C
|
||||
HAL_GPIO, //HGIO
|
||||
FIXED_SLOT_TASK_IF, //FTIF
|
||||
MGM_LIS3MDL, //MGMLIS3
|
||||
MGM_RM3100, //MGMRM3100
|
||||
SPACE_PACKET_PARSER, //SPPA
|
||||
FW_CLASS_ID_COUNT // [EXPORT] : [END]
|
||||
|
||||
};
|
||||
|
@@ -22,9 +22,9 @@ public:
|
||||
* @param number
|
||||
* @return
|
||||
*/
|
||||
static constexpr ReturnValue_t makeReturnCode(uint8_t interfaceId,
|
||||
static constexpr ReturnValue_t makeReturnCode(uint8_t classId,
|
||||
uint8_t number) {
|
||||
return (static_cast<ReturnValue_t>(interfaceId) << 8) + number;
|
||||
return (static_cast<ReturnValue_t>(classId) << 8) + number;
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -62,7 +62,8 @@ protected:
|
||||
struct ChildInfo {
|
||||
MessageQueueId_t commandQueue;
|
||||
Mode_t mode;
|
||||
Submode_t submode;bool healthChanged;
|
||||
Submode_t submode;
|
||||
bool healthChanged;
|
||||
};
|
||||
|
||||
Mode_t mode;
|
||||
|
@@ -1,4 +1,5 @@
|
||||
#include "fsfw/tasks/FixedSlotSequence.h"
|
||||
#include "fsfw/tasks/FixedTimeslotTaskIF.h"
|
||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||
#include <cstdlib>
|
||||
|
||||
@@ -92,10 +93,9 @@ void FixedSlotSequence::addSlot(object_id_t componentId, uint32_t slotTimeMs,
|
||||
ReturnValue_t FixedSlotSequence::checkSequence() const {
|
||||
if(slotList.empty()) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "FixedSlotSequence::checkSequence:"
|
||||
<< " Slot list is empty!" << std::endl;
|
||||
sif::warning << "FixedSlotSequence::checkSequence: Slot list is empty!" << std::endl;
|
||||
#endif
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
return FixedTimeslotTaskIF::SLOT_LIST_EMPTY;
|
||||
}
|
||||
|
||||
if(customCheckFunction != nullptr) {
|
||||
|
@@ -2,7 +2,7 @@
|
||||
#define FSFW_TASKS_FIXEDSLOTSEQUENCE_H_
|
||||
|
||||
#include "FixedSequenceSlot.h"
|
||||
#include "../objectmanager/SystemObject.h"
|
||||
#include "fsfw/objectmanager/SystemObject.h"
|
||||
|
||||
#include <set>
|
||||
|
||||
@@ -136,6 +136,7 @@ public:
|
||||
* @details
|
||||
* Checks if timing is ok (must be ascending) and if all handlers were found.
|
||||
* @return
|
||||
* - SLOT_LIST_EMPTY if the slot list is empty
|
||||
*/
|
||||
ReturnValue_t checkSequence() const;
|
||||
|
||||
@@ -147,6 +148,7 @@ public:
|
||||
* The general check will be continued for now if the custom check function
|
||||
* fails but a diagnostic debug output will be given.
|
||||
* @param customCheckFunction
|
||||
*
|
||||
*/
|
||||
void addCustomCheck(ReturnValue_t (*customCheckFunction)(const SlotList &));
|
||||
|
||||
|
@@ -2,7 +2,8 @@
|
||||
#define FRAMEWORK_TASKS_FIXEDTIMESLOTTASKIF_H_
|
||||
|
||||
#include "PeriodicTaskIF.h"
|
||||
#include "../objectmanager/ObjectManagerIF.h"
|
||||
#include "fsfw/objectmanager/ObjectManagerIF.h"
|
||||
#include "fsfw/returnvalues/FwClassIds.h"
|
||||
|
||||
/**
|
||||
* @brief Following the same principle as the base class IF.
|
||||
@@ -12,6 +13,8 @@ class FixedTimeslotTaskIF : public PeriodicTaskIF {
|
||||
public:
|
||||
virtual ~FixedTimeslotTaskIF() {}
|
||||
|
||||
static constexpr ReturnValue_t SLOT_LIST_EMPTY = HasReturnvaluesIF::makeReturnCode(
|
||||
CLASS_ID::FIXED_SLOT_TASK_IF, 0);
|
||||
/**
|
||||
* Add an object with a slot time and the execution step to the task.
|
||||
* The execution step will be passed to the object (e.g. as an operation
|
||||
|
@@ -1,5 +1,8 @@
|
||||
#ifndef FRAMEWORK_TASKS_TYPEDEF_H_
|
||||
#define FRAMEWORK_TASKS_TYPEDEF_H_
|
||||
#ifndef FSFW_TASKS_TYPEDEF_H_
|
||||
#define FSFW_TASKS_TYPEDEF_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
|
||||
typedef const char* TaskName;
|
||||
typedef uint32_t TaskPriority;
|
||||
@@ -7,4 +10,4 @@ typedef size_t TaskStackSize;
|
||||
typedef double TaskPeriod;
|
||||
typedef void (*TaskDeadlineMissedFunction)();
|
||||
|
||||
#endif /* FRAMEWORK_TASKS_TYPEDEF_H_ */
|
||||
#endif /* FSFW_TASKS_TYPEDEF_H_ */
|
||||
|
@@ -29,12 +29,31 @@ PUSDistributor::TcMqMapIter PUSDistributor::selectDestination() {
|
||||
tcStatus = checker.checkPacket(currentPacket);
|
||||
if(tcStatus != HasReturnvaluesIF::RETURN_OK) {
|
||||
#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
|
||||
sif::debug << "PUSDistributor::handlePacket: Packet format invalid, code " <<
|
||||
static_cast<int>(tcStatus) << std::endl;
|
||||
sif::warning << "PUSDistributor::handlePacket: Packet format invalid, "
|
||||
<< keyword << " error" << std::endl;
|
||||
#else
|
||||
sif::printDebug("PUSDistributor::handlePacket: Packet format invalid, code %d\n",
|
||||
static_cast<int>(tcStatus));
|
||||
sif::printWarning("PUSDistributor::handlePacket: Packet format invalid, "
|
||||
"%s error\n", keyword);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
@@ -15,56 +15,70 @@
|
||||
*/
|
||||
class SpacePacket: public SpacePacketBase {
|
||||
public:
|
||||
static const uint16_t PACKET_MAX_SIZE = 1024;
|
||||
/**
|
||||
* The constructor initializes the packet and sets all header information
|
||||
* according to the passed parameters.
|
||||
* @param packetDataLength Sets the packet data length field and therefore specifies the size of the packet.
|
||||
* @param isTelecommand Sets the packet type field to either TC (true) or TM (false).
|
||||
* @param apid Sets the packet's APID field. The default value describes an idle packet.
|
||||
* @param sequenceCount ets the packet's Source Sequence Count field.
|
||||
*/
|
||||
SpacePacket(uint16_t packetDataLength, bool isTelecommand = false,
|
||||
uint16_t apid = APID_IDLE_PACKET, uint16_t sequenceCount = 0);
|
||||
/**
|
||||
* The class's default destructor.
|
||||
*/
|
||||
virtual ~SpacePacket();
|
||||
/**
|
||||
* With this call, the complete data content (including the CCSDS Primary
|
||||
* Header) is overwritten with the byte stream given.
|
||||
* @param p_data Pointer to data to overwrite the content with
|
||||
* @param packet_size Size of the data
|
||||
* @return @li \c true if packet_size is smaller than \c MAX_PACKET_SIZE.
|
||||
* @li \c false else.
|
||||
*/
|
||||
bool addWholeData(const uint8_t* p_data, uint32_t packet_size);
|
||||
static const uint16_t PACKET_MAX_SIZE = 1024;
|
||||
/**
|
||||
* The constructor initializes the packet and sets all header information
|
||||
* according to the passed parameters.
|
||||
* @param packetDataLength Sets the packet data length field and therefore specifies
|
||||
* the size of the packet.
|
||||
* @param isTelecommand Sets the packet type field to either TC (true) or TM (false).
|
||||
* @param apid Sets the packet's APID field. The default value describes an idle packet.
|
||||
* @param sequenceCount ets the packet's Source Sequence Count field.
|
||||
*/
|
||||
SpacePacket(uint16_t packetDataLength, bool isTelecommand = false,
|
||||
uint16_t apid = APID_IDLE_PACKET, uint16_t sequenceCount = 0);
|
||||
/**
|
||||
* The class's default destructor.
|
||||
*/
|
||||
virtual ~SpacePacket();
|
||||
|
||||
/**
|
||||
* With this call, the complete data content (including the CCSDS Primary
|
||||
* Header) is overwritten with the byte stream given.
|
||||
* @param p_data Pointer to data to overwrite the content with
|
||||
* @param packet_size Size of the data
|
||||
* @return @li \c true if packet_size is smaller than \c MAX_PACKET_SIZE.
|
||||
* @li \c false else.
|
||||
*/
|
||||
bool addWholeData(const uint8_t* p_data, uint32_t packet_size);
|
||||
protected:
|
||||
/**
|
||||
* This structure defines the data structure of a Space Packet as local data.
|
||||
* There's a buffer which corresponds to the Space Packet Data Field with a
|
||||
* maximum size of \c PACKET_MAX_SIZE.
|
||||
*/
|
||||
struct PacketStructured {
|
||||
CCSDSPrimaryHeader header;
|
||||
uint8_t buffer[PACKET_MAX_SIZE];
|
||||
};
|
||||
/**
|
||||
* This union simplifies accessing the full data content of the Space Packet.
|
||||
* This is achieved by putting the \c PacketStructured struct in a union with
|
||||
* a plain buffer.
|
||||
*/
|
||||
union SpacePacketData {
|
||||
PacketStructured fields;
|
||||
uint8_t byteStream[PACKET_MAX_SIZE + sizeof(CCSDSPrimaryHeader)];
|
||||
};
|
||||
/**
|
||||
* This is the data representation of the class.
|
||||
* It is a struct of CCSDS Primary Header and a data field, which again is
|
||||
* packed in an union, so the data can be accessed as a byte stream without
|
||||
* a cast.
|
||||
*/
|
||||
SpacePacketData localData;
|
||||
/**
|
||||
* This structure defines the data structure of a Space Packet as local data.
|
||||
* There's a buffer which corresponds to the Space Packet Data Field with a
|
||||
* maximum size of \c PACKET_MAX_SIZE.
|
||||
*/
|
||||
struct PacketStructured {
|
||||
CCSDSPrimaryHeader header;
|
||||
uint8_t buffer[PACKET_MAX_SIZE];
|
||||
};
|
||||
/**
|
||||
* This union simplifies accessing the full data content of the Space Packet.
|
||||
* This is achieved by putting the \c PacketStructured struct in a union with
|
||||
* a plain buffer.
|
||||
*/
|
||||
union SpacePacketData {
|
||||
PacketStructured fields;
|
||||
uint8_t byteStream[PACKET_MAX_SIZE + sizeof(CCSDSPrimaryHeader)];
|
||||
};
|
||||
/**
|
||||
* This is the data representation of the class.
|
||||
* It is a struct of CCSDS Primary Header and a data field, which again is
|
||||
* packed in an union, so the data can be accessed as a byte stream without
|
||||
* a cast.
|
||||
*/
|
||||
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_ */
|
||||
|
@@ -3,8 +3,8 @@
|
||||
|
||||
#include <cstring>
|
||||
|
||||
SpacePacketBase::SpacePacketBase( const uint8_t* set_address ) {
|
||||
this->data = (SpacePacketPointer*) set_address;
|
||||
SpacePacketBase::SpacePacketBase(const uint8_t* setAddress) {
|
||||
this->data = reinterpret_cast<SpacePacketPointer*>(const_cast<uint8_t*>(setAddress));
|
||||
}
|
||||
|
||||
SpacePacketBase::~SpacePacketBase() {
|
||||
@@ -12,94 +12,112 @@ SpacePacketBase::~SpacePacketBase() {
|
||||
|
||||
//CCSDS Methods:
|
||||
uint8_t SpacePacketBase::getPacketVersionNumber( void ) {
|
||||
return (this->data->header.packet_id_h & 0b11100000) >> 5;
|
||||
return (this->data->header.packet_id_h & 0b11100000) >> 5;
|
||||
}
|
||||
|
||||
void SpacePacketBase::initSpacePacketHeader(bool isTelecommand,
|
||||
bool hasSecondaryHeader, uint16_t apid, uint16_t sequenceCount) {
|
||||
//reset header to zero:
|
||||
memset(data,0, sizeof(this->data->header) );
|
||||
//Set TC/TM bit.
|
||||
data->header.packet_id_h = ((isTelecommand? 1 : 0)) << 4;
|
||||
//Set secondaryHeader bit
|
||||
data->header.packet_id_h |= ((hasSecondaryHeader? 1 : 0)) << 3;
|
||||
this->setAPID( apid );
|
||||
//Always initialize as standalone packets.
|
||||
data->header.sequence_control_h = 0b11000000;
|
||||
setPacketSequenceCount(sequenceCount);
|
||||
|
||||
ReturnValue_t SpacePacketBase::initSpacePacketHeader(bool isTelecommand,
|
||||
bool hasSecondaryHeader, uint16_t apid, uint16_t sequenceCount) {
|
||||
if(data == nullptr) {
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "SpacePacketBase::initSpacePacketHeader: Data pointer is invalid"
|
||||
<< std::endl;
|
||||
#else
|
||||
sif::printWarning("SpacePacketBase::initSpacePacketHeader: Data pointer is invalid!\n");
|
||||
#endif
|
||||
#endif
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
//reset header to zero:
|
||||
memset(data, 0, sizeof(this->data->header) );
|
||||
//Set TC/TM bit.
|
||||
data->header.packet_id_h = ((isTelecommand? 1 : 0)) << 4;
|
||||
//Set secondaryHeader bit
|
||||
data->header.packet_id_h |= ((hasSecondaryHeader? 1 : 0)) << 3;
|
||||
this->setAPID( apid );
|
||||
//Always initialize as standalone packets.
|
||||
data->header.sequence_control_h = 0b11000000;
|
||||
setPacketSequenceCount(sequenceCount);
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
bool SpacePacketBase::isTelecommand( void ) {
|
||||
return (this->data->header.packet_id_h & 0b00010000) >> 4;
|
||||
return (this->data->header.packet_id_h & 0b00010000) >> 4;
|
||||
}
|
||||
|
||||
bool SpacePacketBase::hasSecondaryHeader( void ) {
|
||||
return (this->data->header.packet_id_h & 0b00001000) >> 3;
|
||||
return (this->data->header.packet_id_h & 0b00001000) >> 3;
|
||||
}
|
||||
|
||||
uint16_t SpacePacketBase::getPacketId() {
|
||||
return ( (this->data->header.packet_id_h) << 8 ) +
|
||||
this->data->header.packet_id_l;
|
||||
return ( (this->data->header.packet_id_h) << 8 ) +
|
||||
this->data->header.packet_id_l;
|
||||
}
|
||||
|
||||
uint16_t SpacePacketBase::getAPID( void ) const {
|
||||
return ( (this->data->header.packet_id_h & 0b00000111) << 8 ) +
|
||||
this->data->header.packet_id_l;
|
||||
return ( (this->data->header.packet_id_h & 0b00000111) << 8 ) +
|
||||
this->data->header.packet_id_l;
|
||||
}
|
||||
|
||||
void SpacePacketBase::setAPID( uint16_t new_apid ) {
|
||||
//Use first three bits of new APID, but keep rest of packet id as it was (see specification).
|
||||
this->data->header.packet_id_h = (this->data->header.packet_id_h & 0b11111000) | ( ( new_apid & 0x0700 ) >> 8 );
|
||||
this->data->header.packet_id_l = ( new_apid & 0x00FF );
|
||||
// Use first three bits of new APID, but keep rest of packet id as it was (see specification).
|
||||
this->data->header.packet_id_h = (this->data->header.packet_id_h & 0b11111000) |
|
||||
( ( new_apid & 0x0700 ) >> 8 );
|
||||
this->data->header.packet_id_l = ( new_apid & 0x00FF );
|
||||
}
|
||||
|
||||
void SpacePacketBase::setSequenceFlags( uint8_t sequenceflags ) {
|
||||
this->data->header.sequence_control_h &= 0x3F;
|
||||
this->data->header.sequence_control_h |= sequenceflags << 6;
|
||||
}
|
||||
|
||||
uint16_t SpacePacketBase::getPacketSequenceControl( void ) {
|
||||
return ( (this->data->header.sequence_control_h) << 8 )
|
||||
+ this->data->header.sequence_control_l;
|
||||
return ( (this->data->header.sequence_control_h) << 8 )
|
||||
+ this->data->header.sequence_control_l;
|
||||
}
|
||||
|
||||
uint8_t SpacePacketBase::getSequenceFlags( void ) {
|
||||
return (this->data->header.sequence_control_h & 0b11000000) >> 6 ;
|
||||
return (this->data->header.sequence_control_h & 0b11000000) >> 6 ;
|
||||
}
|
||||
|
||||
uint16_t SpacePacketBase::getPacketSequenceCount( void ) const {
|
||||
return ( (this->data->header.sequence_control_h & 0b00111111) << 8 )
|
||||
+ this->data->header.sequence_control_l;
|
||||
return ( (this->data->header.sequence_control_h & 0b00111111) << 8 )
|
||||
+ this->data->header.sequence_control_l;
|
||||
}
|
||||
|
||||
void SpacePacketBase::setPacketSequenceCount( uint16_t new_count) {
|
||||
this->data->header.sequence_control_h = ( this->data->header.sequence_control_h & 0b11000000 ) | ( ( (new_count%LIMIT_SEQUENCE_COUNT) & 0x3F00 ) >> 8 );
|
||||
this->data->header.sequence_control_l = ( (new_count%LIMIT_SEQUENCE_COUNT) & 0x00FF );
|
||||
this->data->header.sequence_control_h = ( this->data->header.sequence_control_h & 0b11000000 ) |
|
||||
( ( (new_count%LIMIT_SEQUENCE_COUNT) & 0x3F00 ) >> 8 );
|
||||
this->data->header.sequence_control_l = ( (new_count%LIMIT_SEQUENCE_COUNT) & 0x00FF );
|
||||
}
|
||||
|
||||
uint16_t SpacePacketBase::getPacketDataLength() const {
|
||||
return ( (this->data->header.packet_length_h) << 8 )
|
||||
+ this->data->header.packet_length_l;
|
||||
return ( (this->data->header.packet_length_h) << 8 )
|
||||
+ this->data->header.packet_length_l;
|
||||
}
|
||||
|
||||
void SpacePacketBase::setPacketDataLength( uint16_t new_length) {
|
||||
this->data->header.packet_length_h = ( ( new_length & 0xFF00 ) >> 8 );
|
||||
this->data->header.packet_length_l = ( new_length & 0x00FF );
|
||||
this->data->header.packet_length_h = ( ( new_length & 0xFF00 ) >> 8 );
|
||||
this->data->header.packet_length_l = ( new_length & 0x00FF );
|
||||
}
|
||||
|
||||
size_t SpacePacketBase::getFullSize() {
|
||||
//+1 is done because size in packet data length field is: size of data field -1
|
||||
return this->getPacketDataLength() + sizeof(this->data->header) + 1;
|
||||
// +1 is done because size in packet data length field is: size of data field -1
|
||||
return this->getPacketDataLength() + sizeof(this->data->header) + 1;
|
||||
}
|
||||
|
||||
uint8_t* SpacePacketBase::getWholeData() {
|
||||
return (uint8_t*)this->data;
|
||||
return (uint8_t*)this->data;
|
||||
}
|
||||
|
||||
void SpacePacketBase::setData( const uint8_t* p_Data ) {
|
||||
this->data = (SpacePacketPointer*)p_Data;
|
||||
this->data = (SpacePacketPointer*)p_Data;
|
||||
}
|
||||
|
||||
uint32_t SpacePacketBase::getApidAndSequenceCount() const {
|
||||
return (getAPID() << 16) + getPacketSequenceCount();
|
||||
return (getAPID() << 16) + getPacketSequenceCount();
|
||||
}
|
||||
|
||||
uint8_t* SpacePacketBase::getPacketData() {
|
||||
return &(data->packet_data);
|
||||
return &(data->packet_data);
|
||||
}
|
||||
|
@@ -2,6 +2,8 @@
|
||||
#define FSFW_TMTCPACKET_SPACEPACKETBASE_H_
|
||||
|
||||
#include "ccsds_header.h"
|
||||
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
/**
|
||||
@@ -20,8 +22,8 @@
|
||||
* @ingroup tmtcpackets
|
||||
*/
|
||||
struct SpacePacketPointer {
|
||||
CCSDSPrimaryHeader header;
|
||||
uint8_t packet_data;
|
||||
CCSDSPrimaryHeader header;
|
||||
uint8_t packet_data;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -37,143 +39,151 @@ struct SpacePacketPointer {
|
||||
*/
|
||||
class SpacePacketBase {
|
||||
protected:
|
||||
/**
|
||||
* A pointer to a structure which defines the data structure of
|
||||
* the packet header.
|
||||
* To be hardware-safe, all elements are of byte size.
|
||||
*/
|
||||
SpacePacketPointer* data;
|
||||
/**
|
||||
* A pointer to a structure which defines the data structure of
|
||||
* the packet header.
|
||||
* To be hardware-safe, all elements are of byte size.
|
||||
*/
|
||||
SpacePacketPointer* data;
|
||||
public:
|
||||
static const uint16_t LIMIT_APID = 2048; //2^1
|
||||
static const uint16_t LIMIT_SEQUENCE_COUNT = 16384; // 2^14
|
||||
static const uint16_t APID_IDLE_PACKET = 0x7FF;
|
||||
static const uint8_t TELECOMMAND_PACKET = 1;
|
||||
static const uint8_t TELEMETRY_PACKET = 0;
|
||||
/**
|
||||
* This definition defines the CRC size in byte.
|
||||
*/
|
||||
static const uint8_t CRC_SIZE = 2;
|
||||
/**
|
||||
* This is the minimum size of a SpacePacket.
|
||||
*/
|
||||
static const uint16_t MINIMUM_SIZE = sizeof(CCSDSPrimaryHeader) + CRC_SIZE;
|
||||
/**
|
||||
* This is the default constructor.
|
||||
* It sets its internal data pointer to the address passed.
|
||||
* @param set_address The position where the packet data lies.
|
||||
*/
|
||||
SpacePacketBase( const uint8_t* set_address );
|
||||
/**
|
||||
* No data is allocated, so the destructor is empty.
|
||||
*/
|
||||
virtual ~SpacePacketBase();
|
||||
static const uint16_t LIMIT_APID = 2048; //2^1
|
||||
static const uint16_t LIMIT_SEQUENCE_COUNT = 16384; // 2^14
|
||||
static const uint16_t APID_IDLE_PACKET = 0x7FF;
|
||||
static const uint8_t TELECOMMAND_PACKET = 1;
|
||||
static const uint8_t TELEMETRY_PACKET = 0;
|
||||
/**
|
||||
* This definition defines the CRC size in byte.
|
||||
*/
|
||||
static const uint8_t CRC_SIZE = 2;
|
||||
/**
|
||||
* This is the minimum size of a SpacePacket.
|
||||
*/
|
||||
static const uint16_t MINIMUM_SIZE = sizeof(CCSDSPrimaryHeader) + CRC_SIZE;
|
||||
/**
|
||||
* This is the default constructor.
|
||||
* It sets its internal data pointer to the address passed.
|
||||
* @param set_address The position where the packet data lies.
|
||||
*/
|
||||
SpacePacketBase( const uint8_t* set_address );
|
||||
/**
|
||||
* No data is allocated, so the destructor is empty.
|
||||
*/
|
||||
virtual ~SpacePacketBase();
|
||||
|
||||
//CCSDS Methods:
|
||||
/**
|
||||
* Getter for the packet version number field.
|
||||
* @return Returns the highest three bit of the packet in one byte.
|
||||
*/
|
||||
uint8_t getPacketVersionNumber( void );
|
||||
/**
|
||||
* This method checks the type field in the header.
|
||||
* This bit specifies, if the command is interpreted as Telecommand of
|
||||
* as Telemetry. For a Telecommand, the bit is set.
|
||||
* @return Returns true if the bit is set and false if not.
|
||||
*/
|
||||
bool isTelecommand( void );
|
||||
//CCSDS Methods
|
||||
|
||||
void initSpacePacketHeader(bool isTelecommand, bool hasSecondaryHeader,
|
||||
uint16_t apid, uint16_t sequenceCount = 0);
|
||||
/**
|
||||
* The CCSDS header provides a secondary header flag (the fifth-highest bit),
|
||||
* which is checked with this method.
|
||||
* @return Returns true if the bit is set and false if not.
|
||||
*/
|
||||
bool hasSecondaryHeader( void );
|
||||
/**
|
||||
* Returns the complete first two bytes of the packet, which together form
|
||||
* the CCSDS packet id.
|
||||
* @return The CCSDS packet id.
|
||||
*/
|
||||
uint16_t getPacketId( void );
|
||||
/**
|
||||
* Returns the APID of a packet, which are the lowest 11 bit of the packet
|
||||
* id.
|
||||
* @return The CCSDS APID.
|
||||
*/
|
||||
uint16_t getAPID( void ) const;
|
||||
/**
|
||||
* Sets the APID of a packet, which are the lowest 11 bit of the packet
|
||||
* id.
|
||||
* @param The APID to set. The highest five bits of the parameter are
|
||||
* ignored.
|
||||
*/
|
||||
void setAPID( uint16_t setAPID );
|
||||
/**
|
||||
* Returns the CCSDS packet sequence control field, which are the third and
|
||||
* the fourth byte of the CCSDS primary header.
|
||||
* @return The CCSDS packet sequence control field.
|
||||
*/
|
||||
uint16_t getPacketSequenceControl( void );
|
||||
/**
|
||||
* Returns the SequenceFlags, which are the highest two bit of the packet
|
||||
* sequence control field.
|
||||
* @return The CCSDS sequence flags.
|
||||
*/
|
||||
uint8_t getSequenceFlags( void );
|
||||
/**
|
||||
* Returns the packet sequence count, which are the lowest 14 bit of the
|
||||
* packet sequence control field.
|
||||
* @return The CCSDS sequence count.
|
||||
*/
|
||||
uint16_t getPacketSequenceCount( void ) const;
|
||||
/**
|
||||
* Sets the packet sequence count, which are the lowest 14 bit of the
|
||||
* packet sequence control field.
|
||||
* setCount is modulo-divided by \c LIMIT_SEQUENCE_COUNT to avoid overflows.
|
||||
* @param setCount The value to set the count to.
|
||||
*/
|
||||
void setPacketSequenceCount( uint16_t setCount );
|
||||
/**
|
||||
* Returns the packet data length, which is the fifth and sixth byte of the
|
||||
* CCSDS Primary Header. The packet data length is the size of every kind
|
||||
* of data \b after the CCSDS Primary Header \b -1.
|
||||
* @return
|
||||
* The CCSDS packet data length. uint16_t is sufficient,
|
||||
* because this is limit in CCSDS standard
|
||||
*/
|
||||
uint16_t getPacketDataLength(void) const;
|
||||
/**
|
||||
* Sets the packet data length, which is the fifth and sixth byte of the
|
||||
* CCSDS Primary Header.
|
||||
* @param setLength The value of the length to set. It must fit the true
|
||||
* CCSDS packet data length . The packet data length is
|
||||
* the size of every kind of data \b after the CCSDS
|
||||
* Primary Header \b -1.
|
||||
*/
|
||||
void setPacketDataLength( uint16_t setLength );
|
||||
/**
|
||||
* Getter for the packet version number field.
|
||||
* @return Returns the highest three bit of the packet in one byte.
|
||||
*/
|
||||
uint8_t getPacketVersionNumber( void );
|
||||
/**
|
||||
* This method checks the type field in the header.
|
||||
* This bit specifies, if the command is interpreted as Telecommand of
|
||||
* as Telemetry. For a Telecommand, the bit is set.
|
||||
* @return Returns true if the bit is set and false if not.
|
||||
*/
|
||||
bool isTelecommand( void );
|
||||
|
||||
//Helper methods:
|
||||
/**
|
||||
* This method returns a raw uint8_t pointer to the packet.
|
||||
* @return A \c uint8_t pointer to the first byte of the CCSDS primary header.
|
||||
*/
|
||||
virtual uint8_t* getWholeData( void );
|
||||
ReturnValue_t initSpacePacketHeader(bool isTelecommand, bool hasSecondaryHeader,
|
||||
uint16_t apid, uint16_t sequenceCount = 0);
|
||||
/**
|
||||
* The CCSDS header provides a secondary header flag (the fifth-highest bit),
|
||||
* which is checked with this method.
|
||||
* @return Returns true if the bit is set and false if not.
|
||||
*/
|
||||
bool hasSecondaryHeader( void );
|
||||
/**
|
||||
* Returns the complete first two bytes of the packet, which together form
|
||||
* the CCSDS packet id.
|
||||
* @return The CCSDS packet id.
|
||||
*/
|
||||
uint16_t getPacketId( void );
|
||||
/**
|
||||
* Returns the APID of a packet, which are the lowest 11 bit of the packet
|
||||
* id.
|
||||
* @return The CCSDS APID.
|
||||
*/
|
||||
uint16_t getAPID( void ) const;
|
||||
/**
|
||||
* Sets the APID of a packet, which are the lowest 11 bit of the packet
|
||||
* id.
|
||||
* @param The APID to set. The highest five bits of the parameter are
|
||||
* ignored.
|
||||
*/
|
||||
void setAPID( uint16_t setAPID );
|
||||
|
||||
uint8_t* getPacketData();
|
||||
/**
|
||||
* With this method, the packet data pointer can be redirected to another
|
||||
* location.
|
||||
* @param p_Data A pointer to another raw Space Packet.
|
||||
*/
|
||||
virtual void setData( const uint8_t* p_Data );
|
||||
/**
|
||||
* This method returns the full raw packet size.
|
||||
* @return The full size of the packet in bytes.
|
||||
*/
|
||||
size_t getFullSize();
|
||||
/**
|
||||
* Sets the sequence flags of a packet, which are bit 17 and 18 in the space packet header.
|
||||
* @param The sequence flags to set
|
||||
*/
|
||||
void setSequenceFlags( uint8_t sequenceflags );
|
||||
|
||||
uint32_t getApidAndSequenceCount() const;
|
||||
/**
|
||||
* Returns the CCSDS packet sequence control field, which are the third and
|
||||
* the fourth byte of the CCSDS primary header.
|
||||
* @return The CCSDS packet sequence control field.
|
||||
*/
|
||||
uint16_t getPacketSequenceControl( void );
|
||||
/**
|
||||
* Returns the SequenceFlags, which are the highest two bit of the packet
|
||||
* sequence control field.
|
||||
* @return The CCSDS sequence flags.
|
||||
*/
|
||||
uint8_t getSequenceFlags( void );
|
||||
/**
|
||||
* Returns the packet sequence count, which are the lowest 14 bit of the
|
||||
* packet sequence control field.
|
||||
* @return The CCSDS sequence count.
|
||||
*/
|
||||
uint16_t getPacketSequenceCount( void ) const;
|
||||
/**
|
||||
* Sets the packet sequence count, which are the lowest 14 bit of the
|
||||
* packet sequence control field.
|
||||
* setCount is modulo-divided by \c LIMIT_SEQUENCE_COUNT to avoid overflows.
|
||||
* @param setCount The value to set the count to.
|
||||
*/
|
||||
void setPacketSequenceCount( uint16_t setCount );
|
||||
/**
|
||||
* Returns the packet data length, which is the fifth and sixth byte of the
|
||||
* CCSDS Primary Header. The packet data length is the size of every kind
|
||||
* of data \b after the CCSDS Primary Header \b -1.
|
||||
* @return
|
||||
* The CCSDS packet data length. uint16_t is sufficient,
|
||||
* because this is limit in CCSDS standard
|
||||
*/
|
||||
uint16_t getPacketDataLength(void) const;
|
||||
/**
|
||||
* Sets the packet data length, which is the fifth and sixth byte of the
|
||||
* CCSDS Primary Header.
|
||||
* @param setLength The value of the length to set. It must fit the true
|
||||
* CCSDS packet data length . The packet data length is
|
||||
* the size of every kind of data \b after the CCSDS
|
||||
* Primary Header \b -1.
|
||||
*/
|
||||
void setPacketDataLength( uint16_t setLength );
|
||||
|
||||
// Helper methods
|
||||
/**
|
||||
* This method returns a raw uint8_t pointer to the packet.
|
||||
* @return A \c uint8_t pointer to the first byte of the CCSDS primary header.
|
||||
*/
|
||||
virtual uint8_t* getWholeData( void );
|
||||
|
||||
uint8_t* getPacketData();
|
||||
/**
|
||||
* With this method, the packet data pointer can be redirected to another
|
||||
* location.
|
||||
* @param p_Data A pointer to another raw Space Packet.
|
||||
*/
|
||||
virtual void setData( const uint8_t* p_Data );
|
||||
/**
|
||||
* This method returns the full raw packet size.
|
||||
* @return The full size of the packet in bytes.
|
||||
*/
|
||||
size_t getFullSize();
|
||||
|
||||
uint32_t getApidAndSequenceCount() const;
|
||||
|
||||
};
|
||||
|
||||
|
@@ -53,11 +53,14 @@ uint8_t* TmPacketPusC::getPacketTimeRaw() const{
|
||||
|
||||
}
|
||||
|
||||
void TmPacketPusC::initializeTmPacket(uint16_t apid, uint8_t service,
|
||||
ReturnValue_t TmPacketPusC::initializeTmPacket(uint16_t apid, uint8_t service,
|
||||
uint8_t subservice, uint16_t packetSubcounter, uint16_t destinationId,
|
||||
uint8_t timeRefField) {
|
||||
//Set primary header:
|
||||
initSpacePacketHeader(false, true, apid);
|
||||
ReturnValue_t result = initSpacePacketHeader(false, true, apid);
|
||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
//Set data Field Header:
|
||||
//First, set to zero.
|
||||
memset(&tmData->dataField, 0, sizeof(tmData->dataField));
|
||||
@@ -76,6 +79,7 @@ void TmPacketPusC::initializeTmPacket(uint16_t apid, uint8_t service,
|
||||
timeStamper->addTimeStamp(tmData->dataField.time,
|
||||
sizeof(tmData->dataField.time));
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
void TmPacketPusC::setSourceDataSize(uint16_t size) {
|
||||
|
@@ -100,7 +100,7 @@ protected:
|
||||
* @param subservice PUS Subservice
|
||||
* @param packetSubcounter Additional subcounter used.
|
||||
*/
|
||||
void initializeTmPacket(uint16_t apid, uint8_t service, uint8_t subservice,
|
||||
ReturnValue_t initializeTmPacket(uint16_t apid, uint8_t service, uint8_t subservice,
|
||||
uint16_t packetSubcounter, uint16_t destinationId = 0, uint8_t timeRefField = 0);
|
||||
|
||||
/**
|
||||
|
@@ -43,27 +43,55 @@ TmPacketStoredPusC::TmPacketStoredPusC(uint16_t apid, uint8_t service,
|
||||
return;
|
||||
}
|
||||
size_t sourceDataSize = 0;
|
||||
if (content != NULL) {
|
||||
if (content != nullptr) {
|
||||
sourceDataSize += content->getSerializedSize();
|
||||
}
|
||||
if (header != NULL) {
|
||||
if (header != nullptr) {
|
||||
sourceDataSize += header->getSerializedSize();
|
||||
}
|
||||
uint8_t *p_data = NULL;
|
||||
ReturnValue_t returnValue = store->getFreeElement(&storeAddress,
|
||||
(getPacketMinimumSize() + sourceDataSize), &p_data);
|
||||
uint8_t *pData = nullptr;
|
||||
size_t sizeToReserve = getPacketMinimumSize() + sourceDataSize;
|
||||
ReturnValue_t returnValue = store->getFreeElement(&storeAddress, sizeToReserve, &pData);
|
||||
if (returnValue != store->RETURN_OK) {
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
switch(returnValue) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
case(StorageManagerIF::DATA_STORAGE_FULL): {
|
||||
sif::warning << "TmPacketStoredPusC::TmPacketStoredPusC: Store full for packet with "
|
||||
"size " << sizeToReserve << std::endl;
|
||||
break;
|
||||
}
|
||||
case(StorageManagerIF::DATA_TOO_LARGE): {
|
||||
sif::warning << "TmPacketStoredPusC::TmPacketStoredPusC: Data with size " <<
|
||||
sizeToReserve << " too large" << std::endl;
|
||||
break;
|
||||
}
|
||||
#else
|
||||
case(StorageManagerIF::DATA_STORAGE_FULL): {
|
||||
sif::printWarning("TmPacketStoredPusC::TmPacketStoredPusC: Store full for packet with "
|
||||
"size %d\n", sizeToReserve);
|
||||
break;
|
||||
}
|
||||
case(StorageManagerIF::DATA_TOO_LARGE): {
|
||||
sif::printWarning("TmPacketStoredPusC::TmPacketStoredPusC: Data with size "
|
||||
"%d too large\n", sizeToReserve);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
TmPacketStoredBase::checkAndReportLostTm();
|
||||
return;
|
||||
}
|
||||
setData(p_data);
|
||||
setData(pData);
|
||||
initializeTmPacket(apid, service, subservice, packetSubcounter, destinationId, timeRefField);
|
||||
uint8_t *putDataHere = getSourceData();
|
||||
size_t size = 0;
|
||||
if (header != NULL) {
|
||||
if (header != nullptr) {
|
||||
header->serialize(&putDataHere, &size, sourceDataSize,
|
||||
SerializeIF::Endianness::BIG);
|
||||
}
|
||||
if (content != NULL) {
|
||||
if (content != nullptr) {
|
||||
content->serialize(&putDataHere, &size, sourceDataSize,
|
||||
SerializeIF::Endianness::BIG);
|
||||
}
|
||||
|
@@ -6,4 +6,5 @@ target_sources(${LIB_FSFW_NAME}
|
||||
TmTcBridge.cpp
|
||||
TmTcMessage.cpp
|
||||
VerificationReporter.cpp
|
||||
SpacePacketParser.cpp
|
||||
)
|
77
src/fsfw/tmtcservices/SpacePacketParser.cpp
Normal file
77
src/fsfw/tmtcservices/SpacePacketParser.cpp
Normal 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);
|
||||
}
|
||||
}
|
78
src/fsfw/tmtcservices/SpacePacketParser.h
Normal file
78
src/fsfw/tmtcservices/SpacePacketParser.h
Normal 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_ */
|
@@ -19,7 +19,7 @@ class TmTcBridge : public AcceptsTelemetryIF,
|
||||
public:
|
||||
static constexpr uint8_t TMTC_RECEPTION_QUEUE_DEPTH = 20;
|
||||
static constexpr uint8_t LIMIT_STORED_DATA_SENT_PER_CYCLE = 15;
|
||||
static constexpr uint8_t LIMIT_DOWNLINK_PACKETS_STORED = 20;
|
||||
static constexpr uint8_t LIMIT_DOWNLINK_PACKETS_STORED = 200;
|
||||
|
||||
static constexpr uint8_t DEFAULT_STORED_DATA_SENT_PER_CYCLE = 5;
|
||||
static constexpr uint8_t DEFAULT_DOWNLINK_PACKETS_STORED = 10;
|
||||
|
@@ -1,11 +1,9 @@
|
||||
target_sources(${TARGET_NAME}
|
||||
PRIVATE
|
||||
ipc/MissionMessageTypes.cpp
|
||||
pollingsequence/PollingSequenceFactory.cpp
|
||||
target_sources(${TARGET_NAME} PRIVATE
|
||||
ipc/MissionMessageTypes.cpp
|
||||
pollingsequence/PollingSequenceFactory.cpp
|
||||
)
|
||||
|
||||
# Add include paths for the executable
|
||||
target_include_directories(${TARGET_NAME}
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
target_include_directories(${TARGET_NAME} PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
Reference in New Issue
Block a user