Merge remote-tracking branch 'upstream/development' into mueller/master

This commit is contained in:
Robin Müller 2022-03-28 19:09:27 +02:00
commit 2739328404
No known key found for this signature in database
GPG Key ID: 71B58F8A3CDFA9AC
34 changed files with 507 additions and 145 deletions

View File

@ -12,17 +12,31 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## Changes ## Changes
- HAL Linux SPI: Set the Clock Default State when setting new SPI speed
and mode
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/573
- GPIO HAL: `Direction`, `GpioOperation` and `Levels` are enum classes now, which prevents
name clashes with Windows defines.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/572
- New CMake option `FSFW_HAL_LINUX_ADD_LIBGPIOD` to specifically exclude `gpiod` code.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/572
- HAL Devicehandlers: Periodic printout is run-time configurable now - HAL Devicehandlers: Periodic printout is run-time configurable now
- `oneShotAction` flag in the `TestTask` class is not static anymore - `oneShotAction` flag in the `TestTask` class is not static anymore
- HAL Linux Uart: Baudrate and bits per word are enums now, avoiding misconfigurations
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/585
## Removed ## Removed
- Removed the `HkSwitchHelper`. This module should not be needed anymore, now that the local - Removed the `HkSwitchHelper`. This module should not be needed anymore, now that the local
datapools have been implemented datapools have been implemented.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/557
## Additions ## Additions
- Linux HAL: Add wiretapping option for I2C. Enabled with `FSFW_HAL_I2C_WIRETAPPING` defined to 1 - Linux HAL: Add wiretapping option for I2C. Enabled with `FSFW_HAL_I2C_WIRETAPPING` defined to 1
- Dedicated Version class and constant `fsfw::FSFW_VERSION` containing version information
inside `fsfw/version.h`
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/559
# [v4.0.0] # [v4.0.0]

View File

@ -9,11 +9,11 @@ using gpioId_t = uint16_t;
namespace gpio { namespace gpio {
enum Levels : uint8_t { LOW = 0, HIGH = 1, NONE = 99 }; enum class Levels : int { LOW = 0, HIGH = 1, NONE = 99 };
enum Direction : uint8_t { DIR_IN = 0, DIR_OUT = 1 }; enum class Direction : int { IN = 0, OUT = 1 };
enum GpioOperation { READ, WRITE }; enum class GpioOperation { READ, WRITE };
enum class GpioTypes { enum class GpioTypes {
NONE, NONE,
@ -79,8 +79,13 @@ class GpiodRegularBase : public GpioBase {
class GpiodRegularByChip : public GpiodRegularBase { class GpiodRegularByChip : public GpiodRegularBase {
public: public:
GpiodRegularByChip() GpiodRegularByChip()
<<<<<<< HEAD
: GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_CHIP, std::string(), : GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_CHIP, std::string(),
gpio::Direction::DIR_IN, gpio::LOW, 0) {} gpio::Direction::DIR_IN, gpio::LOW, 0) {}
=======
: GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_CHIP, std::string(), gpio::Direction::IN,
gpio::Levels::LOW, 0) {}
>>>>>>> upstream/development
GpiodRegularByChip(std::string chipname_, int lineNum_, std::string consumer_, GpiodRegularByChip(std::string chipname_, int lineNum_, std::string consumer_,
gpio::Direction direction_, gpio::Levels initValue_) gpio::Direction direction_, gpio::Levels initValue_)
@ -89,8 +94,13 @@ class GpiodRegularByChip : public GpiodRegularBase {
chipname(chipname_) {} chipname(chipname_) {}
GpiodRegularByChip(std::string chipname_, int lineNum_, std::string consumer_) GpiodRegularByChip(std::string chipname_, int lineNum_, std::string consumer_)
<<<<<<< HEAD
: GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_CHIP, consumer_, gpio::Direction::DIR_IN, : GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_CHIP, consumer_, gpio::Direction::DIR_IN,
gpio::LOW, lineNum_), gpio::LOW, lineNum_),
=======
: GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_CHIP, consumer_, gpio::Direction::IN,
gpio::Levels::LOW, lineNum_),
>>>>>>> upstream/development
chipname(chipname_) {} chipname(chipname_) {}
std::string chipname; std::string chipname;
@ -105,8 +115,13 @@ class GpiodRegularByLabel : public GpiodRegularBase {
label(label_) {} label(label_) {}
GpiodRegularByLabel(std::string label_, int lineNum_, std::string consumer_) GpiodRegularByLabel(std::string label_, int lineNum_, std::string consumer_)
<<<<<<< HEAD
: GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_LABEL, consumer_, gpio::Direction::DIR_IN, : GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_LABEL, consumer_, gpio::Direction::DIR_IN,
gpio::LOW, lineNum_), gpio::LOW, lineNum_),
=======
: GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_LABEL, consumer_, gpio::Direction::IN,
gpio::Levels::LOW, lineNum_),
>>>>>>> upstream/development
label(label_) {} label(label_) {}
std::string label; std::string label;
@ -126,8 +141,13 @@ class GpiodRegularByLineName : public GpiodRegularBase {
lineName(lineName_) {} lineName(lineName_) {}
GpiodRegularByLineName(std::string lineName_, std::string consumer_) GpiodRegularByLineName(std::string lineName_, std::string consumer_)
<<<<<<< HEAD
: GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME, consumer_, : GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME, consumer_,
gpio::Direction::DIR_IN, gpio::LOW), gpio::Direction::DIR_IN, gpio::LOW),
=======
: GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME, consumer_, gpio::Direction::IN,
gpio::Levels::LOW),
>>>>>>> upstream/development
lineName(lineName_) {} lineName(lineName_) {}
std::string lineName; std::string lineName;

View File

@ -1,9 +1,6 @@
#include "MgmLIS3MDLHandler.h" #include "MgmLIS3MDLHandler.h"
#include "fsfw/datapool/PoolReadGuard.h" #include "fsfw/datapool/PoolReadGuard.h"
#if FSFW_HAL_LIS3MDL_MGM_DEBUG == 1
#include "fsfw/globalfunctions/PeriodicOperationDivider.h"
#endif
#include <cmath> #include <cmath>

View File

@ -161,11 +161,12 @@ ReturnValue_t LinuxLibgpioIF::configureRegularGpio(gpioId_t gpioId, struct gpiod
consumer = regularGpio.consumer; consumer = regularGpio.consumer;
/* Configure direction and add a description to the GPIO */ /* Configure direction and add a description to the GPIO */
switch (direction) { switch (direction) {
case (gpio::DIR_OUT): { case (gpio::Direction::OUT): {
result = gpiod_line_request_output(lineHandle, consumer.c_str(), regularGpio.initValue); result = gpiod_line_request_output(lineHandle, consumer.c_str(),
static_cast<int>(regularGpio.initValue));
break; break;
} }
case (gpio::DIR_IN): { case (gpio::Direction::IN): {
result = gpiod_line_request_input(lineHandle, consumer.c_str()); result = gpiod_line_request_input(lineHandle, consumer.c_str());
break; break;
} }
@ -211,7 +212,7 @@ ReturnValue_t LinuxLibgpioIF::pullHigh(gpioId_t gpioId) {
if (regularGpio == nullptr) { if (regularGpio == nullptr) {
return GPIO_TYPE_FAILURE; return GPIO_TYPE_FAILURE;
} }
return driveGpio(gpioId, *regularGpio, gpio::HIGH); return driveGpio(gpioId, *regularGpio, gpio::Levels::HIGH);
} else { } else {
auto gpioCallback = dynamic_cast<GpioCallback*>(gpioMapIter->second); auto gpioCallback = dynamic_cast<GpioCallback*>(gpioMapIter->second);
if (gpioCallback->callback == nullptr) { if (gpioCallback->callback == nullptr) {
@ -243,7 +244,7 @@ ReturnValue_t LinuxLibgpioIF::pullLow(gpioId_t gpioId) {
if (regularGpio == nullptr) { if (regularGpio == nullptr) {
return GPIO_TYPE_FAILURE; return GPIO_TYPE_FAILURE;
} }
return driveGpio(gpioId, *regularGpio, gpio::LOW); return driveGpio(gpioId, *regularGpio, gpio::Levels::LOW);
} else { } else {
auto gpioCallback = dynamic_cast<GpioCallback*>(gpioMapIter->second); auto gpioCallback = dynamic_cast<GpioCallback*>(gpioMapIter->second);
if (gpioCallback->callback == nullptr) { if (gpioCallback->callback == nullptr) {
@ -258,11 +259,11 @@ ReturnValue_t LinuxLibgpioIF::pullLow(gpioId_t gpioId) {
ReturnValue_t LinuxLibgpioIF::driveGpio(gpioId_t gpioId, GpiodRegularBase& regularGpio, ReturnValue_t LinuxLibgpioIF::driveGpio(gpioId_t gpioId, GpiodRegularBase& regularGpio,
gpio::Levels logicLevel) { gpio::Levels logicLevel) {
int result = gpiod_line_set_value(regularGpio.lineHandle, logicLevel); int result = gpiod_line_set_value(regularGpio.lineHandle, static_cast<int>(logicLevel));
if (result < 0) { if (result < 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "LinuxLibgpioIF::driveGpio: Failed to pull GPIO with ID " << gpioId sif::warning << "LinuxLibgpioIF::driveGpio: Failed to pull GPIO with ID " << gpioId
<< " to logic level " << logicLevel << std::endl; << " to logic level " << static_cast<int>(logicLevel) << std::endl;
#else #else
sif::printWarning( sif::printWarning(
"LinuxLibgpioIF::driveGpio: Failed to pull GPIO with ID %d to " "LinuxLibgpioIF::driveGpio: Failed to pull GPIO with ID %d to "

View File

@ -401,4 +401,12 @@ void SpiComIF::setSpiSpeedAndMode(int spiFd, spi::SpiModes mode, uint32_t speed)
if (retval != 0) { if (retval != 0) {
utility::handleIoctlError("SpiComIF::setSpiSpeedAndMode: Setting SPI speed failed"); utility::handleIoctlError("SpiComIF::setSpiSpeedAndMode: Setting SPI speed failed");
} }
// This updates the SPI clock default polarity. Only setting the mode does not update
// the line state, which can be an issue on mode switches because the clock line will
// switch the state after the chip select is pulled low
clockUpdateTransfer.len = 0;
retval = ioctl(spiFd, SPI_IOC_MESSAGE(1), &clockUpdateTransfer);
if (retval != 0) {
utility::handleIoctlError("SpiComIF::setSpiSpeedAndMode: Updating SPI default clock failed");
}
} }

View File

@ -74,6 +74,7 @@ class SpiComIF : public DeviceCommunicationIF, public SystemObject {
MutexIF* spiMutex = nullptr; MutexIF* spiMutex = nullptr;
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING; MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING;
uint32_t timeoutMs = 20; uint32_t timeoutMs = 20;
spi_ioc_transfer clockUpdateTransfer = {};
using SpiDeviceMap = std::unordered_map<address_t, SpiInstance>; using SpiDeviceMap = std::unordered_map<address_t, SpiInstance>;
using SpiDeviceMapIter = SpiDeviceMap::iterator; using SpiDeviceMapIter = SpiDeviceMap::iterator;

View File

@ -148,16 +148,16 @@ void UartComIF::setDatasizeOptions(struct termios* options, UartCookie* uartCook
/* Clear size bits */ /* Clear size bits */
options->c_cflag &= ~CSIZE; options->c_cflag &= ~CSIZE;
switch (uartCookie->getBitsPerWord()) { switch (uartCookie->getBitsPerWord()) {
case 5: case BitsPerWord::BITS_5:
options->c_cflag |= CS5; options->c_cflag |= CS5;
break; break;
case 6: case BitsPerWord::BITS_6:
options->c_cflag |= CS6; options->c_cflag |= CS6;
break; break;
case 7: case BitsPerWord::BITS_7:
options->c_cflag |= CS7; options->c_cflag |= CS7;
break; break;
case 8: case BitsPerWord::BITS_8:
options->c_cflag |= CS8; options->c_cflag |= CS8;
break; break;
default: default:
@ -193,123 +193,123 @@ void UartComIF::setFixedOptions(struct termios* options) {
void UartComIF::configureBaudrate(struct termios* options, UartCookie* uartCookie) { void UartComIF::configureBaudrate(struct termios* options, UartCookie* uartCookie) {
switch (uartCookie->getBaudrate()) { switch (uartCookie->getBaudrate()) {
case 50: case UartBaudRate::RATE_50:
cfsetispeed(options, B50); cfsetispeed(options, B50);
cfsetospeed(options, B50); cfsetospeed(options, B50);
break; break;
case 75: case UartBaudRate::RATE_75:
cfsetispeed(options, B75); cfsetispeed(options, B75);
cfsetospeed(options, B75); cfsetospeed(options, B75);
break; break;
case 110: case UartBaudRate::RATE_110:
cfsetispeed(options, B110); cfsetispeed(options, B110);
cfsetospeed(options, B110); cfsetospeed(options, B110);
break; break;
case 134: case UartBaudRate::RATE_134:
cfsetispeed(options, B134); cfsetispeed(options, B134);
cfsetospeed(options, B134); cfsetospeed(options, B134);
break; break;
case 150: case UartBaudRate::RATE_150:
cfsetispeed(options, B150); cfsetispeed(options, B150);
cfsetospeed(options, B150); cfsetospeed(options, B150);
break; break;
case 200: case UartBaudRate::RATE_200:
cfsetispeed(options, B200); cfsetispeed(options, B200);
cfsetospeed(options, B200); cfsetospeed(options, B200);
break; break;
case 300: case UartBaudRate::RATE_300:
cfsetispeed(options, B300); cfsetispeed(options, B300);
cfsetospeed(options, B300); cfsetospeed(options, B300);
break; break;
case 600: case UartBaudRate::RATE_600:
cfsetispeed(options, B600); cfsetispeed(options, B600);
cfsetospeed(options, B600); cfsetospeed(options, B600);
break; break;
case 1200: case UartBaudRate::RATE_1200:
cfsetispeed(options, B1200); cfsetispeed(options, B1200);
cfsetospeed(options, B1200); cfsetospeed(options, B1200);
break; break;
case 1800: case UartBaudRate::RATE_1800:
cfsetispeed(options, B1800); cfsetispeed(options, B1800);
cfsetospeed(options, B1800); cfsetospeed(options, B1800);
break; break;
case 2400: case UartBaudRate::RATE_2400:
cfsetispeed(options, B2400); cfsetispeed(options, B2400);
cfsetospeed(options, B2400); cfsetospeed(options, B2400);
break; break;
case 4800: case UartBaudRate::RATE_4800:
cfsetispeed(options, B4800); cfsetispeed(options, B4800);
cfsetospeed(options, B4800); cfsetospeed(options, B4800);
break; break;
case 9600: case UartBaudRate::RATE_9600:
cfsetispeed(options, B9600); cfsetispeed(options, B9600);
cfsetospeed(options, B9600); cfsetospeed(options, B9600);
break; break;
case 19200: case UartBaudRate::RATE_19200:
cfsetispeed(options, B19200); cfsetispeed(options, B19200);
cfsetospeed(options, B19200); cfsetospeed(options, B19200);
break; break;
case 38400: case UartBaudRate::RATE_38400:
cfsetispeed(options, B38400); cfsetispeed(options, B38400);
cfsetospeed(options, B38400); cfsetospeed(options, B38400);
break; break;
case 57600: case UartBaudRate::RATE_57600:
cfsetispeed(options, B57600); cfsetispeed(options, B57600);
cfsetospeed(options, B57600); cfsetospeed(options, B57600);
break; break;
case 115200: case UartBaudRate::RATE_115200:
cfsetispeed(options, B115200); cfsetispeed(options, B115200);
cfsetospeed(options, B115200); cfsetospeed(options, B115200);
break; break;
case 230400: case UartBaudRate::RATE_230400:
cfsetispeed(options, B230400); cfsetispeed(options, B230400);
cfsetospeed(options, B230400); cfsetospeed(options, B230400);
break; break;
case 460800: case UartBaudRate::RATE_460800:
cfsetispeed(options, B460800); cfsetispeed(options, B460800);
cfsetospeed(options, B460800); cfsetospeed(options, B460800);
break; break;
case 500000: case UartBaudRate::RATE_500000:
cfsetispeed(options, B500000); cfsetispeed(options, B500000);
cfsetospeed(options, B500000); cfsetospeed(options, B500000);
break; break;
case 576000: case UartBaudRate::RATE_576000:
cfsetispeed(options, B576000); cfsetispeed(options, B576000);
cfsetospeed(options, B576000); cfsetospeed(options, B576000);
break; break;
case 921600: case UartBaudRate::RATE_921600:
cfsetispeed(options, B921600); cfsetispeed(options, B921600);
cfsetospeed(options, B921600); cfsetospeed(options, B921600);
break; break;
case 1000000: case UartBaudRate::RATE_1000000:
cfsetispeed(options, B1000000); cfsetispeed(options, B1000000);
cfsetospeed(options, B1000000); cfsetospeed(options, B1000000);
break; break;
case 1152000: case UartBaudRate::RATE_1152000:
cfsetispeed(options, B1152000); cfsetispeed(options, B1152000);
cfsetospeed(options, B1152000); cfsetospeed(options, B1152000);
break; break;
case 1500000: case UartBaudRate::RATE_1500000:
cfsetispeed(options, B1500000); cfsetispeed(options, B1500000);
cfsetospeed(options, B1500000); cfsetospeed(options, B1500000);
break; break;
case 2000000: case UartBaudRate::RATE_2000000:
cfsetispeed(options, B2000000); cfsetispeed(options, B2000000);
cfsetospeed(options, B2000000); cfsetospeed(options, B2000000);
break; break;
case 2500000: case UartBaudRate::RATE_2500000:
cfsetispeed(options, B2500000); cfsetispeed(options, B2500000);
cfsetospeed(options, B2500000); cfsetospeed(options, B2500000);
break; break;
case 3000000: case UartBaudRate::RATE_3000000:
cfsetispeed(options, B3000000); cfsetispeed(options, B3000000);
cfsetospeed(options, B3000000); cfsetospeed(options, B3000000);
break; break;
case 3500000: case UartBaudRate::RATE_3500000:
cfsetispeed(options, B3500000); cfsetispeed(options, B3500000);
cfsetospeed(options, B3500000); cfsetospeed(options, B3500000);
break; break;
case 4000000: case UartBaudRate::RATE_4000000:
cfsetispeed(options, B4000000); cfsetispeed(options, B4000000);
cfsetospeed(options, B4000000); cfsetospeed(options, B4000000);
break; break;

View File

@ -3,7 +3,7 @@
#include <fsfw/serviceinterface.h> #include <fsfw/serviceinterface.h>
UartCookie::UartCookie(object_id_t handlerId, std::string deviceFile, UartModes uartMode, UartCookie::UartCookie(object_id_t handlerId, std::string deviceFile, UartModes uartMode,
uint32_t baudrate, size_t maxReplyLen) UartBaudRate baudrate, size_t maxReplyLen)
: handlerId(handlerId), : handlerId(handlerId),
deviceFile(deviceFile), deviceFile(deviceFile),
uartMode(uartMode), uartMode(uartMode),
@ -12,7 +12,7 @@ UartCookie::UartCookie(object_id_t handlerId, std::string deviceFile, UartModes
UartCookie::~UartCookie() {} UartCookie::~UartCookie() {}
uint32_t UartCookie::getBaudrate() const { return baudrate; } UartBaudRate UartCookie::getBaudrate() const { return baudrate; }
size_t UartCookie::getMaxReplyLen() const { return maxReplyLen; } size_t UartCookie::getMaxReplyLen() const { return maxReplyLen; }
@ -24,23 +24,11 @@ void UartCookie::setParityEven() { parity = Parity::EVEN; }
Parity UartCookie::getParity() const { return parity; } Parity UartCookie::getParity() const { return parity; }
void UartCookie::setBitsPerWord(uint8_t bitsPerWord_) { void UartCookie::setBitsPerWord(BitsPerWord bitsPerWord_) {
switch (bitsPerWord_) {
case 5:
case 6:
case 7:
case 8:
break;
default:
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "UartCookie::setBitsPerWord: Invalid bits per word specified" << std::endl;
#endif
return;
}
bitsPerWord = bitsPerWord_; bitsPerWord = bitsPerWord_;
} }
uint8_t UartCookie::getBitsPerWord() const { return bitsPerWord; } BitsPerWord UartCookie::getBitsPerWord() const { return bitsPerWord; }
StopBits UartCookie::getStopBits() const { return stopBits; } StopBits UartCookie::getStopBits() const { return stopBits; }

View File

@ -12,6 +12,41 @@ enum class StopBits { ONE_STOP_BIT, TWO_STOP_BITS };
enum class UartModes { CANONICAL, NON_CANONICAL }; enum class UartModes { CANONICAL, NON_CANONICAL };
enum class BitsPerWord { BITS_5, BITS_6, BITS_7, BITS_8 };
enum class UartBaudRate {
RATE_50,
RATE_75,
RATE_110,
RATE_134,
RATE_150,
RATE_200,
RATE_300,
RATE_600,
RATE_1200,
RATE_1800,
RATE_2400,
RATE_4800,
RATE_9600,
RATE_19200,
RATE_38400,
RATE_57600,
RATE_115200,
RATE_230400,
RATE_460800,
RATE_500000,
RATE_576000,
RATE_921600,
RATE_1000000,
RATE_1152000,
RATE_1500000,
RATE_2000000,
RATE_2500000,
RATE_3000000,
RATE_3500000,
RATE_4000000
};
/** /**
* @brief Cookie for the UartComIF. There are many options available to configure the UART driver. * @brief Cookie for the UartComIF. There are many options available to configure the UART driver.
* The constructor only requests for common options like the baudrate. Other options can * The constructor only requests for common options like the baudrate. Other options can
@ -27,25 +62,23 @@ class UartCookie : public CookieIF {
* @param uartMode Specify the UART mode. The canonical mode should be used if the * @param uartMode Specify the UART mode. The canonical mode should be used if the
* messages are separated by a delimited character like '\n'. See the * messages are separated by a delimited character like '\n'. See the
* termios documentation for more information * termios documentation for more information
* @param baudrate The baudrate to use for input and output. Possible Baudrates are: 50, * @param baudrate The baudrate to use for input and output.
* 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, B19200,
* 38400, 57600, 115200, 230400, 460800
* @param maxReplyLen The maximum size an object using this cookie expects * @param maxReplyLen The maximum size an object using this cookie expects
* @details * @details
* Default configuration: No parity * Default configuration: No parity
* 8 databits (number of bits transfered with one uart frame) * 8 databits (number of bits transfered with one uart frame)
* One stop bit * One stop bit
*/ */
UartCookie(object_id_t handlerId, std::string deviceFile, UartModes uartMode, uint32_t baudrate, UartCookie(object_id_t handlerId, std::string deviceFile, UartModes uartMode,
size_t maxReplyLen); UartBaudRate baudrate, size_t maxReplyLen);
virtual ~UartCookie(); virtual ~UartCookie();
uint32_t getBaudrate() const; UartBaudRate getBaudrate() const;
size_t getMaxReplyLen() const; size_t getMaxReplyLen() const;
std::string getDeviceFile() const; std::string getDeviceFile() const;
Parity getParity() const; Parity getParity() const;
uint8_t getBitsPerWord() const; BitsPerWord getBitsPerWord() const;
StopBits getStopBits() const; StopBits getStopBits() const;
UartModes getUartMode() const; UartModes getUartMode() const;
object_id_t getHandlerId() const; object_id_t getHandlerId() const;
@ -76,7 +109,7 @@ class UartCookie : public CookieIF {
/** /**
* Function two set number of bits per UART frame. * Function two set number of bits per UART frame.
*/ */
void setBitsPerWord(uint8_t bitsPerWord_); void setBitsPerWord(BitsPerWord bitsPerWord_);
/** /**
* Function to specify the number of stopbits. * Function to specify the number of stopbits.
@ -97,10 +130,10 @@ class UartCookie : public CookieIF {
std::string deviceFile; std::string deviceFile;
const UartModes uartMode; const UartModes uartMode;
bool flushInput = false; bool flushInput = false;
uint32_t baudrate; UartBaudRate baudrate;
size_t maxReplyLen = 0; size_t maxReplyLen = 0;
Parity parity = Parity::NONE; Parity parity = Parity::NONE;
uint8_t bitsPerWord = 8; BitsPerWord bitsPerWord = BitsPerWord::BITS_8;
uint8_t readCycles = 1; uint8_t readCycles = 1;
StopBits stopBits = StopBits::ONE_STOP_BIT; StopBits stopBits = StopBits::ONE_STOP_BIT;
bool replySizeFixed = true; bool replySizeFixed = true;

View File

@ -1,3 +1,7 @@
target_sources(${LIB_FSFW_NAME} PRIVATE
version.cpp
)
# Core # Core
add_subdirectory(action) add_subdirectory(action)

View File

@ -30,6 +30,10 @@
#define FSFW_VERBOSE_LEVEL 1 #define FSFW_VERBOSE_LEVEL 1
#endif /* FSFW_VERBOSE_LEVEL */ #endif /* FSFW_VERBOSE_LEVEL */
#ifndef FSFW_DISABLE_PRINTOUT
#define FSFW_DISABLE_PRINTOUT 0
#endif
#ifndef FSFW_USE_REALTIME_FOR_LINUX #ifndef FSFW_USE_REALTIME_FOR_LINUX
#define FSFW_USE_REALTIME_FOR_LINUX 0 #define FSFW_USE_REALTIME_FOR_LINUX 0
#endif /* FSFW_USE_REALTIME_FOR_LINUX */ #endif /* FSFW_USE_REALTIME_FOR_LINUX */

View File

@ -2,8 +2,8 @@
#define FSFW_VERSION_H_ #define FSFW_VERSION_H_
// Versioning is kept in project CMakeLists.txt file // Versioning is kept in project CMakeLists.txt file
#define FSFW_VERSION @FSFW_VERSION@ #define FSFW_VERSION_MAJOR @FSFW_VERSION@
#define FSFW_SUBVERSION @FSFW_SUBVERSION@ #define FSFW_VERSION_MINOR @FSFW_SUBVERSION@
#define FSFW_REVISION @FSFW_REVISION@ #define FSFW_VERSION_REVISION @FSFW_REVISION@
#endif /* FSFW_VERSION_H_ */ #endif /* FSFW_VERSION_H_ */

View File

@ -7,8 +7,14 @@
// could be moved to more suitable location // could be moved to more suitable location
#include <events/subsystemIdRanges.h> #include <events/subsystemIdRanges.h>
typedef uint16_t EventId_t; using EventId_t = uint16_t;
typedef uint8_t EventSeverity_t; using EventSeverity_t = uint8_t;
using UniqueEventId_t = uint8_t;
namespace severity {
enum Severity : EventSeverity_t { INFO = 1, LOW = 2, MEDIUM = 3, HIGH = 4 };
} // namespace severity
#define MAKE_EVENT(id, severity) (((severity) << 16) + (SUBSYSTEM_ID * 100) + (id)) #define MAKE_EVENT(id, severity) (((severity) << 16) + (SUBSYSTEM_ID * 100) + (id))
@ -20,18 +26,11 @@ constexpr EventId_t getEventId(Event event) { return (event & 0xFFFF); }
constexpr EventSeverity_t getSeverity(Event event) { return ((event >> 16) & 0xFF); } constexpr EventSeverity_t getSeverity(Event event) { return ((event >> 16) & 0xFF); }
constexpr Event makeEvent(uint8_t subsystemId, uint8_t uniqueEventId, constexpr Event makeEvent(uint8_t subsystemId, UniqueEventId_t uniqueEventId,
EventSeverity_t eventSeverity) { EventSeverity_t eventSeverity) {
return (eventSeverity << 16) + (subsystemId * 100) + uniqueEventId; return (eventSeverity << 16) + (subsystemId * 100) + uniqueEventId;
} }
} // namespace event } // namespace event
namespace severity {
static constexpr EventSeverity_t INFO = 1;
static constexpr EventSeverity_t LOW = 2;
static constexpr EventSeverity_t MEDIUM = 3;
static constexpr EventSeverity_t HIGH = 4;
} // namespace severity
#endif /* EVENTOBJECT_EVENT_H_ */ #endif /* EVENTOBJECT_EVENT_H_ */

View File

@ -97,7 +97,11 @@ void PeriodicTask::taskFunctionality() {
ReturnValue_t PeriodicTask::addComponent(object_id_t object) { ReturnValue_t PeriodicTask::addComponent(object_id_t object) {
ExecutableObjectIF* newObject = ObjectManager::instance()->get<ExecutableObjectIF>(object); ExecutableObjectIF* newObject = ObjectManager::instance()->get<ExecutableObjectIF>(object);
if (newObject == nullptr) { return addComponent(newObject);
}
ReturnValue_t PeriodicTask::addComponent(ExecutableObjectIF* object) {
if (object == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "PeriodicTask::addComponent: Invalid object. Make sure" sif::error << "PeriodicTask::addComponent: Invalid object. Make sure"
"it implement ExecutableObjectIF" "it implement ExecutableObjectIF"
@ -105,8 +109,8 @@ ReturnValue_t PeriodicTask::addComponent(object_id_t object) {
#endif #endif
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
objectList.push_back(newObject); objectList.push_back(object);
newObject->setTaskIF(this); object->setTaskIF(this);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }

View File

@ -63,6 +63,16 @@ class PeriodicTask : public PeriodicTaskIF, public FreeRTOSTaskIF {
*/ */
ReturnValue_t addComponent(object_id_t object) override; ReturnValue_t addComponent(object_id_t object) override;
/**
* Adds an object to the list of objects to be executed.
* The objects are executed in the order added.
* @param object Id of the object to add.
* @return
* -@c RETURN_OK on success
* -@c RETURN_FAILED if the object could not be added.
*/
ReturnValue_t addComponent(ExecutableObjectIF* object) override;
uint32_t getPeriodMs() const override; uint32_t getPeriodMs() const override;
ReturnValue_t sleepFor(uint32_t ms) override; ReturnValue_t sleepFor(uint32_t ms) override;

View File

@ -150,17 +150,14 @@ ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from, timeval*
time_tm.tm_hour = from->hour; time_tm.tm_hour = from->hour;
time_tm.tm_min = from->minute; time_tm.tm_min = from->minute;
time_tm.tm_sec = from->second; time_tm.tm_sec = from->second;
time_tm.tm_isdst = 0;
time_t seconds = mktime(&time_tm); time_t seconds = timegm(&time_tm);
to->tv_sec = seconds; to->tv_sec = seconds;
to->tv_usec = from->usecond; to->tv_usec = from->usecond;
// Fails in 2038.. // Fails in 2038..
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "Clock::convertTimeBla: not implemented yet" << std::endl;
#endif
return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) { ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) {

View File

@ -102,11 +102,15 @@ void PeriodicTask::taskFunctionality() {
ReturnValue_t PeriodicTask::addComponent(object_id_t object) { ReturnValue_t PeriodicTask::addComponent(object_id_t object) {
ExecutableObjectIF* newObject = ObjectManager::instance()->get<ExecutableObjectIF>(object); ExecutableObjectIF* newObject = ObjectManager::instance()->get<ExecutableObjectIF>(object);
if (newObject == nullptr) { return addComponent(newObject);
}
ReturnValue_t PeriodicTask::addComponent(ExecutableObjectIF* object) {
if (object == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
newObject->setTaskIF(this); object->setTaskIF(this);
objectList.push_back(newObject); objectList.push_back(object);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }

View File

@ -59,6 +59,16 @@ class PeriodicTask : public PeriodicTaskIF {
*/ */
ReturnValue_t addComponent(object_id_t object); ReturnValue_t addComponent(object_id_t object);
/**
* Adds an object to the list of objects to be executed.
* The objects are executed in the order added.
* @param object pointer to the object to add.
* @return
* -@c RETURN_OK on success
* -@c RETURN_FAILED if the object could not be added.
*/
ReturnValue_t addComponent(ExecutableObjectIF* object);
uint32_t getPeriodMs() const; uint32_t getPeriodMs() const;
ReturnValue_t sleepFor(uint32_t ms); ReturnValue_t sleepFor(uint32_t ms);

View File

@ -140,8 +140,9 @@ ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from, timeval*
fromTm.tm_hour = from->hour; fromTm.tm_hour = from->hour;
fromTm.tm_min = from->minute; fromTm.tm_min = from->minute;
fromTm.tm_sec = from->second; fromTm.tm_sec = from->second;
fromTm.tm_isdst = 0;
to->tv_sec = mktime(&fromTm); to->tv_sec = timegm(&fromTm);
to->tv_usec = from->usecond; to->tv_usec = from->usecond;
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }

View File

@ -28,7 +28,11 @@ void* PeriodicPosixTask::taskEntryPoint(void* arg) {
ReturnValue_t PeriodicPosixTask::addComponent(object_id_t object) { ReturnValue_t PeriodicPosixTask::addComponent(object_id_t object) {
ExecutableObjectIF* newObject = ObjectManager::instance()->get<ExecutableObjectIF>(object); ExecutableObjectIF* newObject = ObjectManager::instance()->get<ExecutableObjectIF>(object);
if (newObject == nullptr) { return addComponent(newObject);
}
ReturnValue_t PeriodicPosixTask::addComponent(ExecutableObjectIF* object) {
if (object == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "PeriodicTask::addComponent: Invalid object. Make sure" sif::error << "PeriodicTask::addComponent: Invalid object. Make sure"
<< " it implements ExecutableObjectIF!" << std::endl; << " it implements ExecutableObjectIF!" << std::endl;
@ -39,8 +43,8 @@ ReturnValue_t PeriodicPosixTask::addComponent(object_id_t object) {
#endif #endif
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
objectList.push_back(newObject); objectList.push_back(object);
newObject->setTaskIF(this); object->setTaskIF(this);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }

View File

@ -42,6 +42,14 @@ class PeriodicPosixTask : public PosixThread, public PeriodicTaskIF {
*/ */
ReturnValue_t addComponent(object_id_t object) override; ReturnValue_t addComponent(object_id_t object) override;
/**
* Adds an object to the list of objects to be executed.
* The objects are executed in the order added.
* @param object pointer to the object to add.
* @return RETURN_OK on success, RETURN_FAILED if the object could not be added.
*/
ReturnValue_t addComponent(ExecutableObjectIF* object) override;
uint32_t getPeriodMs() const override; uint32_t getPeriodMs() const override;
ReturnValue_t sleepFor(uint32_t ms) override; ReturnValue_t sleepFor(uint32_t ms) override;

View File

@ -68,11 +68,15 @@ void PeriodicTask::taskFunctionality() {
ReturnValue_t PeriodicTask::addComponent(object_id_t object) { ReturnValue_t PeriodicTask::addComponent(object_id_t object) {
ExecutableObjectIF* newObject = ObjectManager::instance()->get<ExecutableObjectIF>(object); ExecutableObjectIF* newObject = ObjectManager::instance()->get<ExecutableObjectIF>(object);
if (newObject == nullptr) { return addComponent(newObject);
}
ReturnValue_t PeriodicTask::addComponent(ExecutableObjectIF* object) {
if (object == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
objectList.push_back(newObject); objectList.push_back(object);
newObject->setTaskIF(this); object->setTaskIF(this);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }

View File

@ -59,6 +59,15 @@ class PeriodicTask : public RTEMSTaskBase, public PeriodicTaskIF {
*/ */
ReturnValue_t addComponent(object_id_t object) override; ReturnValue_t addComponent(object_id_t object) override;
/**
* Adds an object to the list of objects to be executed.
* The objects are executed in the order added.
* @param object pointer to the object to add.
* @return RETURN_OK on success, RETURN_FAILED if the object could not be added.
*/
ReturnValue_t addComponent(ExecutableObjectIF* object) override;
uint32_t getPeriodMs() const override; uint32_t getPeriodMs() const override;
ReturnValue_t sleepFor(uint32_t ms) override; ReturnValue_t sleepFor(uint32_t ms) override;

View File

@ -26,21 +26,25 @@ class PeriodicTaskIF {
virtual ReturnValue_t startTask() = 0; virtual ReturnValue_t startTask() = 0;
/** /**
* Add a component (object) to a periodic task. The pointer to the * Add a component (object) to a periodic task.
* task can be set optionally
* @param object * @param object
* Add an object to the task. The most important case is to add an * Add an object to the task. The object needs to implement ExecutableObjectIF
* executable object with a function which will be called regularly
* (see ExecutableObjectIF)
* @param setTaskIF
* Can be used to specify whether the task object pointer is passed
* to the component.
* @return * @return
*/ */
virtual ReturnValue_t addComponent(object_id_t object) { virtual ReturnValue_t addComponent(object_id_t object) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
}; };
/**
* Add an object to a periodic task.
* @param object
* Add an object to the task.
* @return
*/
virtual ReturnValue_t addComponent(ExecutableObjectIF* object) {
return HasReturnvaluesIF::RETURN_FAILED;
};
virtual ReturnValue_t sleepFor(uint32_t ms) = 0; virtual ReturnValue_t sleepFor(uint32_t ms) = 0;
virtual uint32_t getPeriodMs() const = 0; virtual uint32_t getPeriodMs() const = 0;

View File

@ -557,6 +557,35 @@ ReturnValue_t CCSDSTime::convertFromCDS(timeval* to, const uint8_t* from, size_t
return RETURN_OK; return RETURN_OK;
} }
ReturnValue_t CCSDSTime::convertFromCDS(timeval* to, const CCSDSTime::CDS_short* from) {
if (to == nullptr or from == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
uint16_t days = (from->dayMSB << 8) + from->dayLSB;
if (days <= DAYS_CCSDS_TO_UNIX_EPOCH) {
return INVALID_TIME_FORMAT;
}
days -= DAYS_CCSDS_TO_UNIX_EPOCH;
to->tv_sec = days * SECONDS_PER_DAY;
uint32_t msDay =
(from->msDay_hh << 24) + (from->msDay_h << 16) + (from->msDay_l << 8) + from->msDay_ll;
to->tv_sec += (msDay / 1000);
to->tv_usec = (msDay % 1000) * 1000;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t CCSDSTime::convertFromCDS(Clock::TimeOfDay_t* to, const CCSDSTime::CDS_short* from) {
if (to == nullptr or from == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
timeval tempTimeval;
ReturnValue_t result = convertFromCDS(&tempTimeval, from);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
return CCSDSTime::convertTimevalToTimeOfDay(to, &tempTimeval);
}
ReturnValue_t CCSDSTime::convertFromCUC(timeval* to, uint8_t pField, const uint8_t* from, ReturnValue_t CCSDSTime::convertFromCUC(timeval* to, uint8_t pField, const uint8_t* from,
size_t* foundLength, size_t maxLength) { size_t* foundLength, size_t maxLength) {
uint32_t secs = 0; uint32_t secs = 0;

View File

@ -180,6 +180,8 @@ class CCSDSTime : public HasReturnvaluesIF {
static ReturnValue_t convertFromCDS(timeval *to, uint8_t const *from, size_t *foundLength, static ReturnValue_t convertFromCDS(timeval *to, uint8_t const *from, size_t *foundLength,
size_t maxLength); size_t maxLength);
static ReturnValue_t convertFromCDS(timeval *to, const CCSDSTime::CDS_short *from);
static ReturnValue_t convertFromCDS(Clock::TimeOfDay_t *to, const CCSDSTime::CDS_short *from);
static ReturnValue_t convertFromCCS(Clock::TimeOfDay_t *to, uint8_t const *from, static ReturnValue_t convertFromCCS(Clock::TimeOfDay_t *to, uint8_t const *from,
size_t *foundLength, size_t maxLength); size_t *foundLength, size_t maxLength);

View File

@ -1,6 +1,8 @@
#include "fsfw/timemanager/Countdown.h" #include "fsfw/timemanager/Countdown.h"
Countdown::Countdown(uint32_t initialTimeout) : timeout(initialTimeout) {} Countdown::Countdown(uint32_t initialTimeout) : timeout(initialTimeout) {
setTimeout(initialTimeout);
}
Countdown::~Countdown() {} Countdown::~Countdown() {}

22
src/fsfw/version.cpp Normal file
View File

@ -0,0 +1,22 @@
#include "version.h"
#include "fsfw/FSFWVersion.h"
#include <cstdio>
#ifdef major
#undef major
#endif
#ifdef minor
#undef minor
#endif
const fsfw::Version fsfw::FSFW_VERSION = {FSFW_VERSION_MAJOR, FSFW_VERSION_MINOR,
FSFW_VERSION_REVISION};
fsfw::Version::Version(uint32_t major, uint32_t minor, uint32_t revision)
: major(major), minor(minor), revision(revision) {}
void fsfw::Version::getVersion(char* str, size_t maxLen) const {
snprintf(str, maxLen, "%d.%d.%d", major, minor, revision);
}

64
src/fsfw/version.h Normal file
View File

@ -0,0 +1,64 @@
#ifndef FSFW_SRC_FSFW_VERSION_H_
#define FSFW_SRC_FSFW_VERSION_H_
#include "fsfw/FSFW.h"
#if FSFW_CPP_OSTREAM_ENABLED == 1
#include <iostream>
#endif
#include <cstdint>
namespace fsfw {
class Version {
public:
Version(uint32_t major, uint32_t minor, uint32_t revision);
uint32_t major = 0;
uint32_t minor = 0;
uint32_t revision = 0;
friend bool operator==(const Version& v1, const Version& v2) {
return (v1.major == v2.major and v1.minor == v2.minor and v1.revision == v2.revision);
}
friend bool operator!=(const Version& v1, const Version& v2) { return not(v1 == v2); }
friend bool operator<(const Version& v1, const Version& v2) {
return ((v1.major < v2.major) or (v1.major == v2.major and v1.minor < v2.minor) or
(v1.major == v2.major and v1.minor == v2.minor and v1.revision < v2.revision));
}
friend bool operator>(const Version& v1, const Version& v2) {
return not (v1 < v2) and not (v1 == v2);
}
friend bool operator<=(const Version& v1, const Version& v2) { return ((v1 == v2) or (v1 < v2)); }
friend bool operator>=(const Version& v1, const Version& v2) { return ((v1 == v2) or (v1 > v2)); }
#if FSFW_CPP_OSTREAM_ENABLED == 1
/**
* Print format to given ostream using format "major.minor.revision"
* @param os
* @param v
* @return
*/
friend std::ostream& operator<<(std::ostream& os, const Version& v) {
os << v.major << "." << v.minor << "." << v.revision;
return os;
}
#endif
/**
* Get version as format "major.minor.revision"
* @param str
* @param maxLen
*/
void getVersion(char* str, size_t maxLen) const;
};
extern const fsfw::Version FSFW_VERSION;
} // namespace fsfw
#endif /* FSFW_SRC_FSFW_VERSION_H_ */

View File

@ -208,7 +208,7 @@ ReturnValue_t TestDevice::buildNormalModeCommand(DeviceCommandId_t deviceCommand
const uint8_t* commandData, const uint8_t* commandData,
size_t commandDataLen) { size_t commandDataLen) {
if (fullInfoPrintout) { if (fullInfoPrintout) {
#if OBSW_VERBOSE_LEVEL >= 3 #if FSFW_VERBOSE_LEVEL >= 3
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "TestDevice::buildTestCommand1: Building normal command" << std::endl; sif::info << "TestDevice::buildTestCommand1: Building normal command" << std::endl;
#else #else
@ -351,7 +351,7 @@ ReturnValue_t TestDevice::scanForReply(const uint8_t* start, size_t len, DeviceC
switch (pendingCmd) { switch (pendingCmd) {
case (TEST_NORMAL_MODE_CMD): { case (TEST_NORMAL_MODE_CMD): {
if (fullInfoPrintout) { if (fullInfoPrintout) {
#if OBSW_VERBOSE_LEVEL >= 3 #if FSFW_VERBOSE_LEVEL >= 3
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "TestDevice::scanForReply: Reply for normal commnand (ID " sif::info << "TestDevice::scanForReply: Reply for normal commnand (ID "
<< TEST_NORMAL_MODE_CMD << ") received!" << std::endl; << TEST_NORMAL_MODE_CMD << ") received!" << std::endl;
@ -678,7 +678,6 @@ ReturnValue_t TestDevice::getParameter(uint8_t domainId, uint8_t uniqueId,
int32_t newValue = 0; int32_t newValue = 0;
ReturnValue_t result = newValues->getElement<int32_t>(&newValue, 0, 0); ReturnValue_t result = newValues->getElement<int32_t>(&newValue, 0, 0);
if (result == HasReturnvaluesIF::RETURN_OK) { if (result == HasReturnvaluesIF::RETURN_OK) {
#if OBSW_DEVICE_HANDLER_PRINTOUT == 1
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "TestDevice" << deviceIdx sif::info << "TestDevice" << deviceIdx
<< "::getParameter: Setting parameter 1 to " << "::getParameter: Setting parameter 1 to "
@ -688,7 +687,6 @@ ReturnValue_t TestDevice::getParameter(uint8_t domainId, uint8_t uniqueId,
sif::printInfo("TestDevice%d::getParameter: Setting parameter 1 to new value %lu\n", sif::printInfo("TestDevice%d::getParameter: Setting parameter 1 to new value %lu\n",
deviceIdx, static_cast<unsigned long>(newValue)); deviceIdx, static_cast<unsigned long>(newValue));
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ #endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
#endif /* OBSW_DEVICE_HANDLER_PRINTOUT == 1 */
} }
} }
parameterWrapper->set(testParameter1); parameterWrapper->set(testParameter1);
@ -702,7 +700,6 @@ ReturnValue_t TestDevice::getParameter(uint8_t domainId, uint8_t uniqueId,
newValues->getElement<float>(newVector + 2, 0, 2) != RETURN_OK) { newValues->getElement<float>(newVector + 2, 0, 2) != RETURN_OK) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
#if OBSW_DEVICE_HANDLER_PRINTOUT == 1
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "TestDevice" << deviceIdx sif::info << "TestDevice" << deviceIdx
<< "::getParameter: Setting parameter 3 to " << "::getParameter: Setting parameter 3 to "
@ -715,7 +712,6 @@ ReturnValue_t TestDevice::getParameter(uint8_t domainId, uint8_t uniqueId,
"[%f, %f, %f]\n", "[%f, %f, %f]\n",
deviceIdx, newVector[0], newVector[1], newVector[2]); deviceIdx, newVector[0], newVector[1], newVector[2]);
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ #endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
#endif /* OBSW_DEVICE_HANDLER_PRINTOUT == 1 */
} }
parameterWrapper->setVector(vectorFloatParams2); parameterWrapper->setVector(vectorFloatParams2);
break; break;

View File

@ -2,14 +2,13 @@ target_sources(${FSFW_TEST_TGT} PRIVATE
CatchDefinitions.cpp CatchDefinitions.cpp
CatchFactory.cpp CatchFactory.cpp
printChar.cpp printChar.cpp
version.cpp
) )
# if(FSFW_CUSTOM_UNITTEST_RUNNER) target_sources(${FSFW_TEST_TGT} PRIVATE
target_sources(${FSFW_TEST_TGT} PRIVATE CatchRunner.cpp
CatchRunner.cpp CatchSetup.cpp
CatchSetup.cpp )
)
# endif()
add_subdirectory(testcfg) add_subdirectory(testcfg)
add_subdirectory(action) add_subdirectory(action)

View File

@ -1,6 +1,7 @@
#include <fsfw/datapool/PoolReadGuard.h> #include <fsfw/datapool/PoolReadGuard.h>
#include <fsfw/datapoollocal/HasLocalDataPoolIF.h> #include <fsfw/datapoollocal/HasLocalDataPoolIF.h>
#include <fsfw/datapoollocal/StaticLocalDataSet.h> #include <fsfw/datapoollocal/StaticLocalDataSet.h>
#include <fsfw/globalfunctions/timevalOperations.h>
#include <fsfw/housekeeping/HousekeepingSnapshot.h> #include <fsfw/housekeeping/HousekeepingSnapshot.h>
#include <fsfw/ipc/CommandMessageCleaner.h> #include <fsfw/ipc/CommandMessageCleaner.h>
#include <fsfw/objectmanager/ObjectManager.h> #include <fsfw/objectmanager/ObjectManager.h>
@ -93,10 +94,8 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") {
poolOwner->dataset.setChanged(true); poolOwner->dataset.setChanged(true);
/* Store current time, we are going to check the (approximate) time equality later */ /* Store current time, we are going to check the (approximate) time equality later */
CCSDSTime::CDS_short timeCdsNow;
timeval now; timeval now;
Clock::getClock_timeval(&now); Clock::getClock_timeval(&now);
CCSDSTime::convertToCcsds(&timeCdsNow, &now);
/* Trigger generation of snapshot */ /* Trigger generation of snapshot */
REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK); REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK);
@ -131,13 +130,11 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") {
CHECK(newSet.localPoolUint16Vec.value[2] == 42932); CHECK(newSet.localPoolUint16Vec.value[2] == 42932);
/* Now we check that both times are equal */ /* Now we check that both times are equal */
CHECK(cdsShort.pField == timeCdsNow.pField); timeval timeFromHK;
CHECK(cdsShort.dayLSB == Catch::Approx(timeCdsNow.dayLSB).margin(1)); auto result = CCSDSTime::convertFromCDS(&timeFromHK, &cdsShort);
CHECK(cdsShort.dayMSB == Catch::Approx(timeCdsNow.dayMSB).margin(1)); CHECK(result == HasReturnvaluesIF::RETURN_OK);
CHECK(cdsShort.msDay_h == Catch::Approx(timeCdsNow.msDay_h).margin(1)); timeval difference = timeFromHK - now;
CHECK(cdsShort.msDay_hh == Catch::Approx(timeCdsNow.msDay_hh).margin(1)); CHECK(timevalOperations::toDouble(difference) < 1.0);
CHECK(cdsShort.msDay_l == Catch::Approx(timeCdsNow.msDay_l).margin(1));
CHECK(cdsShort.msDay_ll == Catch::Approx(timeCdsNow.msDay_ll).margin(5));
} }
SECTION("VariableSnapshotTest") { SECTION("VariableSnapshotTest") {
@ -158,13 +155,10 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") {
} }
poolVar->setChanged(true); poolVar->setChanged(true);
/* Store current time, we are going to check the (approximate) time equality later */ /* Store current time, we are going to check the (approximate) time equality later */
CCSDSTime::CDS_short timeCdsNow; CCSDSTime::CDS_short timeCdsNow;
timeval now; timeval now;
Clock::getClock_timeval(&now); Clock::getClock_timeval(&now);
CCSDSTime::convertToCcsds(&timeCdsNow, &now);
REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK); REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK);
/* Check update snapshot was sent. */ /* Check update snapshot was sent. */
@ -193,13 +187,11 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") {
CHECK(varCopy.value == 25); CHECK(varCopy.value == 25);
/* Now we check that both times are equal */ /* Now we check that both times are equal */
CHECK(cdsShort.pField == timeCdsNow.pField); timeval timeFromHK;
CHECK(cdsShort.dayLSB == Catch::Approx(timeCdsNow.dayLSB).margin(1)); auto result = CCSDSTime::convertFromCDS(&timeFromHK, &cdsShort);
CHECK(cdsShort.dayMSB == Catch::Approx(timeCdsNow.dayMSB).margin(1)); CHECK(result == HasReturnvaluesIF::RETURN_OK);
CHECK(cdsShort.msDay_h == Catch::Approx(timeCdsNow.msDay_h).margin(1)); timeval difference = timeFromHK - now;
CHECK(cdsShort.msDay_hh == Catch::Approx(timeCdsNow.msDay_hh).margin(1)); CHECK(timevalOperations::toDouble(difference) < 1.0);
CHECK(cdsShort.msDay_l == Catch::Approx(timeCdsNow.msDay_l).margin(1));
CHECK(cdsShort.msDay_ll == Catch::Approx(timeCdsNow.msDay_ll).margin(5));
} }
SECTION("VariableNotificationTest") { SECTION("VariableNotificationTest") {

View File

@ -1,3 +1,4 @@
#include <fsfw/globalfunctions/timevalOperations.h>
#include <fsfw/timemanager/CCSDSTime.h> #include <fsfw/timemanager/CCSDSTime.h>
#include <array> #include <array>
@ -89,4 +90,43 @@ TEST_CASE("CCSDSTime Tests", "[TestCCSDSTime]") {
REQUIRE(timeTo.second == 59); REQUIRE(timeTo.second == 59);
REQUIRE(timeTo.usecond == Catch::Approx(123000)); REQUIRE(timeTo.usecond == Catch::Approx(123000));
} }
SECTION("CDS Conversions") {
// Preperation
Clock::TimeOfDay_t time;
time.year = 2020;
time.month = 2;
time.day = 29;
time.hour = 13;
time.minute = 24;
time.second = 45;
time.usecond = 123456;
timeval timeAsTimeval;
auto result = Clock::convertTimeOfDayToTimeval(&time, &timeAsTimeval);
CHECK(result == HasReturnvaluesIF::RETURN_OK);
CHECK(timeAsTimeval.tv_sec == 1582982685);
CHECK(timeAsTimeval.tv_usec == 123456);
// Conversion to CDS Short
CCSDSTime::CDS_short cdsTime;
result = CCSDSTime::convertToCcsds(&cdsTime, &timeAsTimeval);
CHECK(result == HasReturnvaluesIF::RETURN_OK);
// Days in CCSDS Epoch 22704 (0x58B0)
CHECK(cdsTime.dayMSB == 0x58);
CHECK(cdsTime.dayLSB == 0xB0);
// MS of day 48285123.456 (floored here)
CHECK(cdsTime.msDay_hh == 0x2);
CHECK(cdsTime.msDay_h == 0xE0);
CHECK(cdsTime.msDay_l == 0xC5);
CHECK(cdsTime.msDay_ll == 0xC3);
// Conversion back to timeval
timeval timeReturnAsTimeval;
result = CCSDSTime::convertFromCDS(&timeReturnAsTimeval, &cdsTime);
CHECK(result == HasReturnvaluesIF::RETURN_OK);
// micro seconds precision is lost
timeval difference = timeAsTimeval - timeReturnAsTimeval;
CHECK(difference.tv_usec == 456);
CHECK(difference.tv_sec == 0);
}
} }

View File

@ -0,0 +1,92 @@
#include "fsfw/version.h"
#include <catch2/catch_test_macros.hpp>
#include "fsfw/serviceinterface.h"
#include "fsfw_tests/unit/CatchDefinitions.h"
TEST_CASE("Version API Tests", "[TestVersionAPI]") {
// Check that major version is non-zero
REQUIRE(fsfw::FSFW_VERSION.major > 0);
uint32_t fsfwMajor = fsfw::FSFW_VERSION.major;
REQUIRE(fsfw::Version(255, 0, 0) > fsfw::FSFW_VERSION);
REQUIRE(fsfw::Version(255, 0, 0) >= fsfw::FSFW_VERSION);
REQUIRE(fsfw::Version(0, 0, 0) < fsfw::FSFW_VERSION);
REQUIRE(fsfw::Version(0, 0, 0) <= fsfw::FSFW_VERSION);
fsfw::Version v1 = fsfw::Version(1, 1, 1);
fsfw::Version v2 = fsfw::Version(1, 1, 1);
REQUIRE(v1 == v2);
REQUIRE(not (v1 < v2));
REQUIRE(not (v1 > v2));
REQUIRE(v1 <= v2);
REQUIRE(v1 >= v2);
v1.revision -= 1;
REQUIRE(v1 != v2);
REQUIRE(not (v1 == v2));
REQUIRE(not (v1 > v2));
REQUIRE(not (v1 >= v2));
REQUIRE(v1 < v2);
REQUIRE(v1 <= v2);
v1.revision += 1;
v1.minor -= 1;
REQUIRE(v1 != v2);
REQUIRE(v1 < v2);
REQUIRE(v1 <= v2);
REQUIRE(not (v1 == v2));
REQUIRE(not (v1 > v2));
REQUIRE(not (v1 >= v2));
v1.minor += 1;
v1.major -= 1;
REQUIRE(v1 != v2);
REQUIRE(v1 < v2);
REQUIRE(v1 <= v2);
REQUIRE(not (v1 == v2));
REQUIRE(not (v1 > v2));
REQUIRE(not (v1 >= v2));
v1.major += 1;
REQUIRE(v1 == v2);
REQUIRE(v1 <= v2);
REQUIRE(v1 >= v2);
REQUIRE(not (v1 != v2));
REQUIRE(not (v1 > v2));
REQUIRE(not (v1 < v2));
v1.major += 1;
v1.minor -= 1;
REQUIRE(v1 != v2);
REQUIRE(v1 > v2);
REQUIRE(v1 >= v2);
REQUIRE(not (v1 == v2));
REQUIRE(not (v1 < v2));
REQUIRE(not (v1 <= v2));
v1.major -= 1;
v1.minor += 2;
v1.revision -= 1;
REQUIRE(v1 != v2);
REQUIRE(v1 > v2);
REQUIRE(v1 >= v2);
REQUIRE(not (v1 == v2));
REQUIRE(not (v1 < v2));
REQUIRE(not (v1 <= v2));
v1.minor -= 1;
v1.revision += 2;
REQUIRE(v1 != v2);
REQUIRE(v1 > v2);
REQUIRE(v1 >= v2);
REQUIRE(not (v1 == v2));
REQUIRE(not (v1 < v2));
REQUIRE(not (v1 <= v2));
v1.revision -= 1;
REQUIRE(v1 == v2);
REQUIRE(v1 <= v2);
REQUIRE(v1 >= v2);
REQUIRE(not (v1 != v2));
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "v" << fsfw::FSFW_VERSION << std::endl;
#endif
char verString[10] = {};
fsfw::FSFW_VERSION.getVersion(verString, sizeof(verString));
#if FSFW_DISABLE_PRINTOUT == 0
printf("v%s\n",verString);
#endif
}