diff --git a/.run/fsfw-tests_coverage.run.xml b/.run/fsfw-tests_coverage.run.xml
deleted file mode 100644
index 49d9b135..00000000
--- a/.run/fsfw-tests_coverage.run.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.run/fsfw.run.xml b/.run/fsfw.run.xml
deleted file mode 100644
index 72f74939..00000000
--- a/.run/fsfw.run.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e4e15eaa..b0e28d11 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -133,7 +133,6 @@ https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/593
- https://gitlab.kitware.com/cmake/cmake/-/issues/21696
Easiest solution for now: Keep this option OFF by default.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/616
-- 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
@@ -148,6 +147,17 @@ https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/593
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/590
- `Subsystem`: New API to add table and sequence entries
+## HAL
+
+- SPI: Cache the SPI device in the communication interface. Architecturally, this makes a
+ lot more sense because each ComIF should be responsible for one SPI bus.
+- SPI: Move the empty transfer to update the line polarity to separate function. This means
+ it is not automatically called when calling the setter function for SPI speed and mode.
+ The user should call this function after locking the CS mutex if multiple SPI devices with
+ differing speeds and modes are attached to one bus.
+- SPI: Getter functions for SPI speed and mode.
+- I2C: Add wiretapping option for I2C. Enabled with `FSFW_HAL_I2C_WIRETAPPING` defined to 1.
+
## Fixed
- TCP TMTC Server: `MutexGuard` was not created properly in
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d8163f3e..15e7662a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -183,15 +183,18 @@ if(FSFW_BUILD_UNITTESTS)
endif()
endif()
-message(STATUS "${MSG_PREFIX} Finding and/or providing ETL library")
+message(
+ STATUS
+ "${MSG_PREFIX} Finding and/or providing etl library with version ${FSFW_ETL_LIB_MAJOR_VERSION}"
+)
# Check whether the user has already installed ETL first
-find_package(${FSFW_ETL_LIB_NAME} ${FSFW_ETL_LIB_MAJOR_VERSION} QUIET)
+find_package(${FSFW_ETL_LIB_NAME} ${FSFW_ETL_LIB_MAJOR_VERSION} CONFIG QUIET)
# Not installed, so use FetchContent to download and provide etl
if(NOT ${FSFW_ETL_LIB_NAME}_FOUND)
message(
STATUS
- "No ETL installation was found with find_package. Installing and providing "
+ "${MSG_PREFIX} No ETL installation was found with find_package. Installing and providing "
"etl with FindPackage")
include(FetchContent)
diff --git a/hal/src/fsfw_hal/common/gpio/GpioIF.h b/hal/src/fsfw_hal/common/gpio/GpioIF.h
index 5cca1481..f8ef9d9c 100644
--- a/hal/src/fsfw_hal/common/gpio/GpioIF.h
+++ b/hal/src/fsfw_hal/common/gpio/GpioIF.h
@@ -46,9 +46,9 @@ class GpioIF : public HasReturnvaluesIF {
* an ouput or input gpio.
*
* @param gpioId A unique number which specifies the GPIO to read.
- * @param gpioState State of GPIO will be written to this pointer.
+ * @param gpioState State of GPIO will be written to this reference
*/
- virtual ReturnValue_t readGpio(gpioId_t gpioId, int* gpioState) = 0;
+ virtual ReturnValue_t readGpio(gpioId_t gpioId, gpio::Levels& gpioState) = 0;
};
#endif /* COMMON_GPIO_GPIOIF_H_ */
diff --git a/hal/src/fsfw_hal/common/gpio/gpioDefinitions.h b/hal/src/fsfw_hal/common/gpio/gpioDefinitions.h
index eb90629e..a15ffbc0 100644
--- a/hal/src/fsfw_hal/common/gpio/gpioDefinitions.h
+++ b/hal/src/fsfw_hal/common/gpio/gpioDefinitions.h
@@ -9,7 +9,7 @@ using gpioId_t = uint16_t;
namespace gpio {
-enum class Levels : int { LOW = 0, HIGH = 1, NONE = 99 };
+enum class Levels : int { LOW = 0, HIGH = 1, FAILED = -1, NONE = 99 };
enum class Direction : int { IN = 0, OUT = 1 };
diff --git a/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.cpp b/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.cpp
index 94e1331c..3dd19275 100644
--- a/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.cpp
+++ b/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.cpp
@@ -252,6 +252,7 @@ ReturnValue_t GyroHandlerL3GD20H::initializeLocalDataPool(localpool::DataPool &l
localDataPoolMap.emplace(L3GD20H::ANG_VELOC_Y, new PoolEntry({0.0}));
localDataPoolMap.emplace(L3GD20H::ANG_VELOC_Z, new PoolEntry({0.0}));
localDataPoolMap.emplace(L3GD20H::TEMPERATURE, new PoolEntry({0.0}));
+ poolManager.subscribeForPeriodicPacket(dataset.getSid(), false, 10.0, false);
return HasReturnvaluesIF::RETURN_OK;
}
diff --git a/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp b/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp
index 644b488d..ee45056a 100644
--- a/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp
+++ b/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp
@@ -375,13 +375,16 @@ float MgmLIS3MDLHandler::getSensitivityFactor(MGMLIS3MDL::Sensitivies sens) {
ReturnValue_t MgmLIS3MDLHandler::enableTemperatureSensor(const uint8_t *commandData,
size_t commandDataLen) {
+ if (commandData == nullptr) {
+ return INVALID_COMMAND_PARAMETER;
+ }
triggerEvent(CHANGE_OF_SETUP_PARAMETER);
uint32_t size = 2;
commandBuffer[0] = writeCommand(MGMLIS3MDL::CTRL_REG1);
if (commandDataLen > 1) {
return INVALID_NUMBER_OR_LENGTH_OF_PARAMETERS;
}
- switch (*commandData) {
+ switch (commandData[0]) {
case (MGMLIS3MDL::ON): {
commandBuffer[1] = registers[0] | (1 << 7);
break;
@@ -472,6 +475,7 @@ ReturnValue_t MgmLIS3MDLHandler::initializeLocalDataPool(localpool::DataPool &lo
localDataPoolMap.emplace(MGMLIS3MDL::FIELD_STRENGTH_Y, new PoolEntry({0.0}));
localDataPoolMap.emplace(MGMLIS3MDL::FIELD_STRENGTH_Z, new PoolEntry({0.0}));
localDataPoolMap.emplace(MGMLIS3MDL::TEMPERATURE_CELCIUS, new PoolEntry({0.0}));
+ poolManager.subscribeForPeriodicPacket(dataset.getSid(), false, 10.0, false);
return HasReturnvaluesIF::RETURN_OK;
}
diff --git a/hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.cpp b/hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.cpp
index f9929d63..3396ea15 100644
--- a/hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.cpp
+++ b/hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.cpp
@@ -312,6 +312,7 @@ ReturnValue_t MgmRM3100Handler::initializeLocalDataPool(localpool::DataPool &loc
localDataPoolMap.emplace(RM3100::FIELD_STRENGTH_X, new PoolEntry({0.0}));
localDataPoolMap.emplace(RM3100::FIELD_STRENGTH_Y, new PoolEntry({0.0}));
localDataPoolMap.emplace(RM3100::FIELD_STRENGTH_Z, new PoolEntry({0.0}));
+ poolManager.subscribeForPeriodicPacket(primaryDataset.getSid(), false, 10.0, false);
return HasReturnvaluesIF::RETURN_OK;
}
diff --git a/hal/src/fsfw_hal/linux/CommandExecutor.cpp b/hal/src/fsfw_hal/linux/CommandExecutor.cpp
index 49c44ebf..3887964d 100644
--- a/hal/src/fsfw_hal/linux/CommandExecutor.cpp
+++ b/hal/src/fsfw_hal/linux/CommandExecutor.cpp
@@ -32,6 +32,8 @@ ReturnValue_t CommandExecutor::execute() {
} else if (state == States::PENDING) {
return COMMAND_PENDING;
}
+ // Reset data in read vector
+ std::memset(readVec.data(), 0, readVec.size());
currentCmdFile = popen(currentCmd.c_str(), "r");
if (currentCmdFile == nullptr) {
lastError = errno;
@@ -205,3 +207,5 @@ ReturnValue_t CommandExecutor::executeBlocking() {
}
return HasReturnvaluesIF::RETURN_OK;
}
+
+const std::vector& CommandExecutor::getReadVector() const { return readVec; }
diff --git a/hal/src/fsfw_hal/linux/CommandExecutor.h b/hal/src/fsfw_hal/linux/CommandExecutor.h
index 90662c0f..5d403848 100644
--- a/hal/src/fsfw_hal/linux/CommandExecutor.h
+++ b/hal/src/fsfw_hal/linux/CommandExecutor.h
@@ -109,6 +109,8 @@ class CommandExecutor {
*/
void reset();
+ const std::vector& getReadVector() const;
+
private:
std::string currentCmd;
bool blocking = true;
diff --git a/hal/src/fsfw_hal/linux/UnixFileGuard.cpp b/hal/src/fsfw_hal/linux/UnixFileGuard.cpp
index 41293815..3e916ba2 100644
--- a/hal/src/fsfw_hal/linux/UnixFileGuard.cpp
+++ b/hal/src/fsfw_hal/linux/UnixFileGuard.cpp
@@ -6,7 +6,7 @@
#include "fsfw/FSFW.h"
#include "fsfw/serviceinterface.h"
-UnixFileGuard::UnixFileGuard(std::string device, int* fileDescriptor, int flags,
+UnixFileGuard::UnixFileGuard(const std::string& device, int* fileDescriptor, int flags,
std::string diagnosticPrefix)
: fileDescriptor(fileDescriptor) {
if (fileDescriptor == nullptr) {
diff --git a/hal/src/fsfw_hal/linux/UnixFileGuard.h b/hal/src/fsfw_hal/linux/UnixFileGuard.h
index d94234b6..04f379d6 100644
--- a/hal/src/fsfw_hal/linux/UnixFileGuard.h
+++ b/hal/src/fsfw_hal/linux/UnixFileGuard.h
@@ -15,7 +15,7 @@ class UnixFileGuard {
static constexpr ReturnValue_t OPEN_FILE_FAILED = 1;
- UnixFileGuard(std::string device, int* fileDescriptor, int flags,
+ UnixFileGuard(const std::string& device, int* fileDescriptor, int flags,
std::string diagnosticPrefix = "");
virtual ~UnixFileGuard();
diff --git a/hal/src/fsfw_hal/linux/gpio/Gpio.h b/hal/src/fsfw_hal/linux/gpio/Gpio.h
new file mode 100644
index 00000000..40cc1df5
--- /dev/null
+++ b/hal/src/fsfw_hal/linux/gpio/Gpio.h
@@ -0,0 +1,27 @@
+#ifndef FSFW_HAL_SRC_FSFW_HAL_LINUX_GPIO_GPIO_H_
+#define FSFW_HAL_SRC_FSFW_HAL_LINUX_GPIO_GPIO_H_
+
+#include "fsfw_hal/common/gpio/GpioIF.h"
+#include "fsfw_hal/common/gpio/gpioDefinitions.h"
+
+/**
+ * @brief Additional abstraction layer for handling GPIOs.
+ *
+ * @author J. Meier
+ */
+class Gpio {
+ public:
+ Gpio(gpioId_t gpioId, GpioIF* gpioIF) : gpioId(gpioId), gpioIF(gpioIF) {
+ if (gpioIF == nullptr) {
+ sif::error << "Gpio::Gpio: Invalid GpioIF" << std::endl;
+ }
+ }
+ ReturnValue_t pullHigh() { return gpioIF->pullHigh(gpioId); }
+ ReturnValue_t pullLow() { return gpioIF->pullLow(gpioId); }
+
+ private:
+ gpioId_t gpioId = gpio::NO_GPIO;
+ GpioIF* gpioIF = nullptr;
+};
+
+#endif /* FSFW_HAL_SRC_FSFW_HAL_LINUX_GPIO_GPIO_H_ */
diff --git a/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp b/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp
index 15061d14..335150dc 100644
--- a/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp
+++ b/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp
@@ -294,7 +294,7 @@ ReturnValue_t LinuxLibgpioIF::driveGpio(gpioId_t gpioId, GpiodRegularBase& regul
return RETURN_OK;
}
-ReturnValue_t LinuxLibgpioIF::readGpio(gpioId_t gpioId, int* gpioState) {
+ReturnValue_t LinuxLibgpioIF::readGpio(gpioId_t gpioId, gpio::Levels& gpioState) {
gpioMapIter = gpioMap.find(gpioId);
if (gpioMapIter == gpioMap.end()) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
@@ -313,7 +313,10 @@ ReturnValue_t LinuxLibgpioIF::readGpio(gpioId_t gpioId, int* gpioState) {
if (regularGpio == nullptr) {
return GPIO_TYPE_FAILURE;
}
- *gpioState = gpiod_line_get_value(regularGpio->lineHandle);
+ gpioState = static_cast(gpiod_line_get_value(regularGpio->lineHandle));
+ if (gpioState == gpio::Levels::FAILED) {
+ return GPIO_GET_VALUE_FAILED;
+ }
} else {
auto gpioCallback = dynamic_cast(gpioMapIter->second);
if (gpioCallback->callback == nullptr) {
diff --git a/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.h b/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.h
index fcc9c775..a50e480d 100644
--- a/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.h
+++ b/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.h
@@ -31,14 +31,16 @@ class LinuxLibgpioIF : public GpioIF, public SystemObject {
HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 5);
static constexpr ReturnValue_t GPIO_INIT_FAILED =
HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 6);
-
+ // Will be returned if getting the line value failed. Error type will be set to errno in this case
+ static constexpr ReturnValue_t GPIO_GET_VALUE_FAILED =
+ HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 7);
LinuxLibgpioIF(object_id_t objectId);
virtual ~LinuxLibgpioIF();
ReturnValue_t addGpios(GpioCookie* gpioCookie) override;
ReturnValue_t pullHigh(gpioId_t gpioId) override;
ReturnValue_t pullLow(gpioId_t gpioId) override;
- ReturnValue_t readGpio(gpioId_t gpioId, int* gpioState) override;
+ ReturnValue_t readGpio(gpioId_t gpioId, gpio::Levels& gpioState) override;
private:
static const size_t MAX_CHIPNAME_LENGTH = 11;
diff --git a/hal/src/fsfw_hal/linux/i2c/I2cComIF.cpp b/hal/src/fsfw_hal/linux/i2c/I2cComIF.cpp
index 4f53dc1f..1740b022 100644
--- a/hal/src/fsfw_hal/linux/i2c/I2cComIF.cpp
+++ b/hal/src/fsfw_hal/linux/i2c/I2cComIF.cpp
@@ -170,18 +170,20 @@ ReturnValue_t I2cComIF::requestReceiveMessage(CookieIF* cookie, size_t requestLe
int readLen = read(fd, replyBuffer, requestLen);
if (readLen != static_cast(requestLen)) {
-#if FSFW_VERBOSE_LEVEL >= 1 and FSFW_CPP_OSTREAM_ENABLED == 1
- sif::error << "I2cComIF::requestReceiveMessage: Reading from I2C "
- << "device failed with error code " << errno << ". Description"
- << " of error: " << strerror(errno) << std::endl;
- sif::error << "I2cComIF::requestReceiveMessage: Read only " << readLen << " from " << requestLen
- << " bytes" << std::endl;
+#if FSFW_VERBOSE_LEVEL >= 1
+#if FSFW_CPP_OSTREAM_ENABLED == 1
+ if (readLen < 0) {
+ sif::warning << "I2cComIF::requestReceiveMessage: Reading from I2C "
+ << "device failed with error code " << errno << " | " << strerror(errno)
+ << std::endl;
+ } else {
+ sif::warning << "I2cComIF::requestReceiveMessage: Read only " << readLen << " from "
+ << requestLen << " bytes" << std::endl;
+ }
+#else
+#endif
#endif
i2cDeviceMapIter->second.replyLen = 0;
-#if FSFW_CPP_OSTREAM_ENABLED == 1
- sif::debug << "I2cComIF::requestReceiveMessage: Read " << readLen << " of " << requestLen
- << " bytes" << std::endl;
-#endif
return HasReturnvaluesIF::RETURN_FAILED;
}
diff --git a/hal/src/fsfw_hal/linux/spi/ManualCsLockGuard.h b/hal/src/fsfw_hal/linux/spi/ManualCsLockGuard.h
new file mode 100644
index 00000000..b282bcc0
--- /dev/null
+++ b/hal/src/fsfw_hal/linux/spi/ManualCsLockGuard.h
@@ -0,0 +1,43 @@
+#pragma once
+
+#include "fsfw/ipc/MutexIF.h"
+#include "fsfw/returnvalues/HasReturnvaluesIF.h"
+#include "fsfw_hal/common/gpio/GpioIF.h"
+
+class ManualCsLockWrapper : public HasReturnvaluesIF {
+ public:
+ ManualCsLockWrapper(MutexIF* lock, GpioIF* gpioIF, SpiCookie* cookie,
+ MutexIF::TimeoutType type = MutexIF::TimeoutType::BLOCKING,
+ uint32_t timeoutMs = 0)
+ : lock(lock), gpioIF(gpioIF), cookie(cookie), type(type), timeoutMs(timeoutMs) {
+ if (cookie == nullptr) {
+ // TODO: Error? Or maybe throw exception..
+ return;
+ }
+ cookie->setCsLockManual(true);
+ lockResult = lock->lockMutex(type, timeoutMs);
+ if (lockResult != RETURN_OK) {
+ return;
+ }
+ gpioResult = gpioIF->pullLow(cookie->getChipSelectPin());
+ }
+
+ ~ManualCsLockWrapper() {
+ if (gpioResult == RETURN_OK) {
+ gpioIF->pullHigh(cookie->getChipSelectPin());
+ }
+ cookie->setCsLockManual(false);
+ if (lockResult == RETURN_OK) {
+ lock->unlockMutex();
+ }
+ }
+ ReturnValue_t lockResult;
+ ReturnValue_t gpioResult;
+
+ private:
+ MutexIF* lock;
+ GpioIF* gpioIF;
+ SpiCookie* cookie;
+ MutexIF::TimeoutType type;
+ uint32_t timeoutMs = 0;
+};
diff --git a/hal/src/fsfw_hal/linux/spi/SpiComIF.cpp b/hal/src/fsfw_hal/linux/spi/SpiComIF.cpp
index b06def69..e684b302 100644
--- a/hal/src/fsfw_hal/linux/spi/SpiComIF.cpp
+++ b/hal/src/fsfw_hal/linux/spi/SpiComIF.cpp
@@ -15,8 +15,8 @@
#include "fsfw_hal/linux/spi/SpiCookie.h"
#include "fsfw_hal/linux/utility.h"
-SpiComIF::SpiComIF(object_id_t objectId, GpioIF* gpioComIF)
- : SystemObject(objectId), gpioComIF(gpioComIF) {
+SpiComIF::SpiComIF(object_id_t objectId, std::string devname, GpioIF* gpioComIF)
+ : SystemObject(objectId), gpioComIF(gpioComIF), dev(std::move(devname)) {
if (gpioComIF == nullptr) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
@@ -27,7 +27,7 @@ SpiComIF::SpiComIF(object_id_t objectId, GpioIF* gpioComIF)
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
}
- spiMutex = MutexFactory::instance()->createMutex();
+ csMutex = MutexFactory::instance()->createMutex();
}
ReturnValue_t SpiComIF::initializeInterface(CookieIF* cookie) {
@@ -85,8 +85,7 @@ ReturnValue_t SpiComIF::initializeInterface(CookieIF* cookie) {
spiCookie->getSpiParameters(spiMode, spiSpeed, ¶ms);
int fileDescriptor = 0;
- UnixFileGuard fileHelper(spiCookie->getSpiDevice(), &fileDescriptor, O_RDWR,
- "SpiComIF::initializeInterface");
+ UnixFileGuard fileHelper(dev, &fileDescriptor, O_RDWR, "SpiComIF::initializeInterface");
if (fileHelper.getOpenResult() != HasReturnvaluesIF::RETURN_OK) {
return fileHelper.getOpenResult();
}
@@ -182,8 +181,7 @@ ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie* spiCookie, const
int retval = 0;
/* Prepare transfer */
int fileDescriptor = 0;
- std::string device = spiCookie->getSpiDevice();
- UnixFileGuard fileHelper(device, &fileDescriptor, O_RDWR, "SpiComIF::sendMessage");
+ UnixFileGuard fileHelper(dev, &fileDescriptor, O_RDWR, "SpiComIF::sendMessage");
if (fileHelper.getOpenResult() != HasReturnvaluesIF::RETURN_OK) {
return OPENING_FILE_FAILED;
}
@@ -196,20 +194,27 @@ ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie* spiCookie, const
bool fullDuplex = spiCookie->isFullDuplex();
gpioId_t gpioId = spiCookie->getChipSelectPin();
+ bool csLockManual = spiCookie->getCsLockManual();
- /* Pull SPI CS low. For now, no support for active high given */
- if (gpioId != gpio::NO_GPIO) {
- result = spiMutex->lockMutex(timeoutType, timeoutMs);
+ MutexIF::TimeoutType csType;
+ dur_millis_t csTimeout = 0;
+ // Pull SPI CS low. For now, no support for active high given
+ if (gpioId != gpio::NO_GPIO and not csLockManual) {
+ spiCookie->getMutexParams(csType, csTimeout);
+ result = csMutex->lockMutex(csType, csTimeout);
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;
+ sif::error << "SpiComIF::sendMessage: Failed to lock mutex with code "
+ << "0x" << std::hex << std::setfill('0') << std::setw(4) << result << std::dec
+ << std::endl;
#else
- sif::printError("SpiComIF::sendMessage: Failed to lock mutex\n");
+ sif::printError("SpiComIF::sendMessage: Failed to lock mutex with code %d\n", result);
#endif
#endif
return result;
}
+ updateLinePolarity(fileDescriptor);
result = gpioComIF->pullLow(gpioId);
if (result != HasReturnvaluesIF::RETURN_OK) {
#if FSFW_VERBOSE_LEVEL >= 1
@@ -221,6 +226,8 @@ ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie* spiCookie, const
#endif
return result;
}
+ } else {
+ updateLinePolarity(fileDescriptor);
}
/* Execute transfer */
@@ -248,9 +255,9 @@ ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie* spiCookie, const
}
}
- if (gpioId != gpio::NO_GPIO) {
+ if (gpioId != gpio::NO_GPIO and not csLockManual) {
gpioComIF->pullHigh(gpioId);
- result = spiMutex->unlockMutex();
+ result = csMutex->unlockMutex();
if (result != RETURN_OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "SpiComIF::sendMessage: Failed to unlock mutex" << std::endl;
@@ -278,9 +285,8 @@ ReturnValue_t SpiComIF::requestReceiveMessage(CookieIF* cookie, size_t requestLe
ReturnValue_t SpiComIF::performHalfDuplexReception(SpiCookie* spiCookie) {
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
- std::string device = spiCookie->getSpiDevice();
int fileDescriptor = 0;
- UnixFileGuard fileHelper(device, &fileDescriptor, O_RDWR, "SpiComIF::requestReceiveMessage");
+ UnixFileGuard fileHelper(dev, &fileDescriptor, O_RDWR, "SpiComIF::requestReceiveMessage");
if (fileHelper.getOpenResult() != HasReturnvaluesIF::RETURN_OK) {
return OPENING_FILE_FAILED;
}
@@ -292,12 +298,22 @@ ReturnValue_t SpiComIF::performHalfDuplexReception(SpiCookie* spiCookie) {
return result;
}
+ bool csLockManual = spiCookie->getCsLockManual();
gpioId_t gpioId = spiCookie->getChipSelectPin();
- if (gpioId != gpio::NO_GPIO) {
- result = spiMutex->lockMutex(timeoutType, timeoutMs);
+ MutexIF::TimeoutType csType;
+ dur_millis_t csTimeout = 0;
+ if (gpioId != gpio::NO_GPIO and not csLockManual) {
+ spiCookie->getMutexParams(csType, csTimeout);
+ result = csMutex->lockMutex(csType, csTimeout);
if (result != RETURN_OK) {
+#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
- sif::error << "SpiComIF::getSendSuccess: Failed to lock mutex" << std::endl;
+ sif::error << "SpiComIF::sendMessage: Failed to lock mutex with code "
+ << "0x" << std::hex << std::setfill('0') << std::setw(4) << result << std::dec
+ << std::endl;
+#else
+ sif::printError("SpiComIF::sendMessage: Failed to lock mutex with code %d\n", result);
+#endif
#endif
return result;
}
@@ -315,9 +331,9 @@ ReturnValue_t SpiComIF::performHalfDuplexReception(SpiCookie* spiCookie) {
result = HALF_DUPLEX_TRANSFER_FAILED;
}
- if (gpioId != gpio::NO_GPIO) {
+ if (gpioId != gpio::NO_GPIO and not csLockManual) {
gpioComIF->pullHigh(gpioId);
- result = spiMutex->unlockMutex();
+ result = csMutex->unlockMutex();
if (result != RETURN_OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "SpiComIF::getSendSuccess: Failed to unlock mutex" << std::endl;
@@ -346,15 +362,7 @@ ReturnValue_t SpiComIF::readReceivedMessage(CookieIF* cookie, uint8_t** buffer,
return HasReturnvaluesIF::RETURN_OK;
}
-MutexIF* SpiComIF::getMutex(MutexIF::TimeoutType* timeoutType, uint32_t* timeoutMs) {
- if (timeoutType != nullptr) {
- *timeoutType = this->timeoutType;
- }
- if (timeoutMs != nullptr) {
- *timeoutMs = this->timeoutMs;
- }
- return spiMutex;
-}
+MutexIF* SpiComIF::getCsMutex() { return csMutex; }
void SpiComIF::performSpiWiretapping(SpiCookie* spiCookie) {
if (spiCookie == nullptr) {
@@ -401,11 +409,27 @@ void SpiComIF::setSpiSpeedAndMode(int spiFd, spi::SpiModes mode, uint32_t speed)
if (retval != 0) {
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
+}
+
+void SpiComIF::getSpiSpeedAndMode(int spiFd, spi::SpiModes& mode, uint32_t& speed) const {
+ uint8_t tmpMode = 0;
+ int retval = ioctl(spiFd, SPI_IOC_RD_MODE, &tmpMode);
+ if (retval != 0) {
+ utility::handleIoctlError("SpiComIF::getSpiSpeedAndMode: Reading SPI mode failed");
+ }
+ mode = static_cast(tmpMode);
+
+ retval = ioctl(spiFd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
+ if (retval != 0) {
+ utility::handleIoctlError("SpiComIF::getSpiSpeedAndMode: Getting SPI speed failed");
+ }
+}
+
+const std::string& SpiComIF::getSpiDev() const { return dev; }
+
+void SpiComIF::updateLinePolarity(int spiFd) {
clockUpdateTransfer.len = 0;
- retval = ioctl(spiFd, SPI_IOC_MESSAGE(1), &clockUpdateTransfer);
+ int retval = ioctl(spiFd, SPI_IOC_MESSAGE(1), &clockUpdateTransfer);
if (retval != 0) {
utility::handleIoctlError("SpiComIF::setSpiSpeedAndMode: Updating SPI default clock failed");
}
diff --git a/hal/src/fsfw_hal/linux/spi/SpiComIF.h b/hal/src/fsfw_hal/linux/spi/SpiComIF.h
index 357afa2f..52673457 100644
--- a/hal/src/fsfw_hal/linux/spi/SpiComIF.h
+++ b/hal/src/fsfw_hal/linux/spi/SpiComIF.h
@@ -22,17 +22,17 @@ class SpiCookie;
*/
class SpiComIF : public DeviceCommunicationIF, public SystemObject {
public:
- static constexpr uint8_t spiRetvalId = CLASS_ID::HAL_SPI;
+ static constexpr uint8_t CLASS_ID = CLASS_ID::HAL_SPI;
static constexpr ReturnValue_t OPENING_FILE_FAILED =
- HasReturnvaluesIF::makeReturnCode(spiRetvalId, 0);
+ HasReturnvaluesIF::makeReturnCode(CLASS_ID, 0);
/* Full duplex (ioctl) transfer failure */
static constexpr ReturnValue_t FULL_DUPLEX_TRANSFER_FAILED =
- HasReturnvaluesIF::makeReturnCode(spiRetvalId, 1);
+ HasReturnvaluesIF::makeReturnCode(CLASS_ID, 1);
/* Half duplex (read/write) transfer failure */
static constexpr ReturnValue_t HALF_DUPLEX_TRANSFER_FAILED =
- HasReturnvaluesIF::makeReturnCode(spiRetvalId, 2);
+ HasReturnvaluesIF::makeReturnCode(CLASS_ID, 2);
- SpiComIF(object_id_t objectId, GpioIF* gpioComIF);
+ SpiComIF(object_id_t objectId, std::string devname, GpioIF* gpioComIF);
ReturnValue_t initializeInterface(CookieIF* cookie) override;
ReturnValue_t sendMessage(CookieIF* cookie, const uint8_t* sendData, size_t sendLen) override;
@@ -44,7 +44,8 @@ class SpiComIF : public DeviceCommunicationIF, public SystemObject {
* @brief This function returns the mutex which can be used to protect the spi bus when
* the chip select must be driven from outside of the com if.
*/
- MutexIF* getMutex(MutexIF::TimeoutType* timeoutType = nullptr, uint32_t* timeoutMs = nullptr);
+ MutexIF* getCsMutex();
+ void setMutexParams(MutexIF::TimeoutType timeoutType, uint32_t timeoutMs);
/**
* Perform a regular send operation using Linux iotcl. This is public so it can be used
@@ -59,6 +60,20 @@ class SpiComIF : public DeviceCommunicationIF, public SystemObject {
GpioIF* getGpioInterface();
void setSpiSpeedAndMode(int spiFd, spi::SpiModes mode, uint32_t speed);
+ void getSpiSpeedAndMode(int spiFd, spi::SpiModes& mode, uint32_t& speed) const;
+
+ /**
+ * 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.
+ *
+ * It is recommended to call this function after #setSpiSpeedAndMode and after locking the
+ * CS mutex if the SPI bus has multiple SPI devices with different speed and SPI modes attached.
+ * @param spiFd
+ */
+ void updateLinePolarity(int spiFd);
+
+ const std::string& getSpiDev() const;
void performSpiWiretapping(SpiCookie* spiCookie);
ReturnValue_t getReadBuffer(address_t spiAddress, uint8_t** buffer);
@@ -70,10 +85,14 @@ class SpiComIF : public DeviceCommunicationIF, public SystemObject {
};
GpioIF* gpioComIF = nullptr;
-
- MutexIF* spiMutex = nullptr;
- MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING;
- uint32_t timeoutMs = 20;
+ std::string dev = "";
+ /**
+ * Protects the chip select operations. Lock when GPIO is pulled low, unlock after it was
+ * pulled high
+ */
+ MutexIF* csMutex = nullptr;
+ // MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING;
+ // uint32_t timeoutMs = DEFAULT_MUTEX_TIMEOUT;
spi_ioc_transfer clockUpdateTransfer = {};
using SpiDeviceMap = std::unordered_map;
diff --git a/hal/src/fsfw_hal/linux/spi/SpiCookie.cpp b/hal/src/fsfw_hal/linux/spi/SpiCookie.cpp
index c94fcdf1..e61703e6 100644
--- a/hal/src/fsfw_hal/linux/spi/SpiCookie.cpp
+++ b/hal/src/fsfw_hal/linux/spi/SpiCookie.cpp
@@ -1,26 +1,25 @@
#include "SpiCookie.h"
-SpiCookie::SpiCookie(address_t spiAddress, gpioId_t chipSelect, std::string spiDev,
- const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed)
- : SpiCookie(spi::SpiComIfModes::REGULAR, spiAddress, chipSelect, spiDev, maxSize, spiMode,
- spiSpeed, nullptr, nullptr) {}
-
-SpiCookie::SpiCookie(address_t spiAddress, std::string spiDev, const size_t maxSize,
+SpiCookie::SpiCookie(address_t spiAddress, gpioId_t chipSelect, const size_t maxSize,
spi::SpiModes spiMode, uint32_t spiSpeed)
- : SpiCookie(spiAddress, gpio::NO_GPIO, spiDev, maxSize, spiMode, spiSpeed) {}
+ : SpiCookie(spi::SpiComIfModes::REGULAR, spiAddress, chipSelect, maxSize, spiMode, spiSpeed,
+ nullptr, nullptr) {}
-SpiCookie::SpiCookie(address_t spiAddress, gpioId_t chipSelect, std::string spiDev,
- const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed,
+SpiCookie::SpiCookie(address_t spiAddress, const size_t maxSize, spi::SpiModes spiMode,
+ uint32_t spiSpeed)
+ : SpiCookie(spiAddress, gpio::NO_GPIO, maxSize, spiMode, spiSpeed) {}
+
+SpiCookie::SpiCookie(address_t spiAddress, gpioId_t chipSelect, const size_t maxSize,
+ spi::SpiModes spiMode, uint32_t spiSpeed,
spi::send_callback_function_t callback, void* args)
- : SpiCookie(spi::SpiComIfModes::CALLBACK, spiAddress, chipSelect, spiDev, maxSize, spiMode,
- spiSpeed, callback, args) {}
+ : SpiCookie(spi::SpiComIfModes::CALLBACK, spiAddress, chipSelect, maxSize, spiMode, spiSpeed,
+ callback, args) {}
SpiCookie::SpiCookie(spi::SpiComIfModes comIfMode, address_t spiAddress, gpioId_t chipSelect,
- std::string spiDev, const size_t maxSize, spi::SpiModes spiMode,
- uint32_t spiSpeed, spi::send_callback_function_t callback, void* args)
+ const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed,
+ spi::send_callback_function_t callback, void* args)
: spiAddress(spiAddress),
chipSelectPin(chipSelect),
- spiDevice(spiDev),
comIfMode(comIfMode),
maxSize(maxSize),
spiMode(spiMode),
@@ -50,8 +49,6 @@ size_t SpiCookie::getMaxBufferSize() const { return maxSize; }
address_t SpiCookie::getSpiAddress() const { return spiAddress; }
-std::string SpiCookie::getSpiDevice() const { return spiDevice; }
-
void SpiCookie::setThreeWireSpi(bool enable) { uncommonParameters.threeWireSpi = enable; }
void SpiCookie::setLsbFirst(bool enable) { uncommonParameters.lsbFirst = enable; }
@@ -107,3 +104,17 @@ void SpiCookie::getCallback(spi::send_callback_function_t* callback, void** args
*callback = this->sendCallback;
*args = this->callbackArgs;
}
+
+void SpiCookie::setCsLockManual(bool enable) { manualCsLock = enable; }
+
+bool SpiCookie::getCsLockManual() const { return manualCsLock; }
+
+void SpiCookie::getMutexParams(MutexIF::TimeoutType& csTimeoutType, dur_millis_t& csTimeout) const {
+ csTimeoutType = this->csTimeoutType;
+ csTimeout = this->csTimeout;
+}
+
+void SpiCookie::setMutexParams(MutexIF::TimeoutType csTimeoutType, dur_millis_t csTimeout) {
+ this->csTimeoutType = csTimeoutType;
+ this->csTimeout = csTimeout;
+}
diff --git a/hal/src/fsfw_hal/linux/spi/SpiCookie.h b/hal/src/fsfw_hal/linux/spi/SpiCookie.h
index 5f4bf2d5..2104e2eb 100644
--- a/hal/src/fsfw_hal/linux/spi/SpiCookie.h
+++ b/hal/src/fsfw_hal/linux/spi/SpiCookie.h
@@ -2,6 +2,8 @@
#define LINUX_SPI_SPICOOKIE_H_
#include
+#include
+#include
#include
#include "../../common/gpio/gpioDefinitions.h"
@@ -20,6 +22,8 @@
*/
class SpiCookie : public CookieIF {
public:
+ static constexpr dur_millis_t DEFAULT_MUTEX_TIMEOUT = 20;
+
/**
* Each SPI device will have a corresponding cookie. The cookie is used by the communication
* interface and contains device specific information like the largest expected size to be
@@ -29,23 +33,22 @@ class SpiCookie : public CookieIF {
* @param spiDev
* @param maxSize
*/
- SpiCookie(address_t spiAddress, gpioId_t chipSelect, std::string spiDev, const size_t maxSize,
- spi::SpiModes spiMode, uint32_t spiSpeed);
+ SpiCookie(address_t spiAddress, gpioId_t chipSelect, const size_t maxSize, spi::SpiModes spiMode,
+ uint32_t spiSpeed);
/**
* Like constructor above, but without a dedicated GPIO CS. Can be used for hardware
* slave select or if CS logic is performed with decoders.
*/
- SpiCookie(address_t spiAddress, std::string spiDev, const size_t maxReplySize,
- spi::SpiModes spiMode, uint32_t spiSpeed);
+ SpiCookie(address_t spiAddress, const size_t maxReplySize, spi::SpiModes spiMode,
+ uint32_t spiSpeed);
/**
* Use the callback mode of the SPI communication interface. The user can pass the callback
* function here or by using the setter function #setCallbackMode
*/
- SpiCookie(address_t spiAddress, gpioId_t chipSelect, std::string spiDev, const size_t maxSize,
- spi::SpiModes spiMode, uint32_t spiSpeed, spi::send_callback_function_t callback,
- void* args);
+ SpiCookie(address_t spiAddress, gpioId_t chipSelect, const size_t maxSize, spi::SpiModes spiMode,
+ uint32_t spiSpeed, spi::send_callback_function_t callback, void* args);
/**
* Get the callback function
@@ -55,7 +58,6 @@ class SpiCookie : public CookieIF {
void getCallback(spi::send_callback_function_t* callback, void** args);
address_t getSpiAddress() const;
- std::string getSpiDevice() const;
gpioId_t getChipSelectPin() const;
size_t getMaxBufferSize() const;
@@ -139,9 +141,42 @@ class SpiCookie : public CookieIF {
*/
void activateCsDeselect(bool deselectCs, uint16_t delayUsecs);
+ void getMutexParams(MutexIF::TimeoutType& csTimeoutType, dur_millis_t& csTimeout) const;
+ void setMutexParams(MutexIF::TimeoutType csTimeoutType, dur_millis_t csTimeout);
+
+ void setCsLockManual(bool enable);
+ bool getCsLockManual() const;
+
spi_ioc_transfer* getTransferStructHandle();
private:
+ address_t spiAddress;
+ gpioId_t chipSelectPin;
+
+ spi::SpiComIfModes comIfMode;
+
+ // Required for regular mode
+ const size_t maxSize;
+ spi::SpiModes spiMode;
+ /**
+ * If this is set to true, the SPI ComIF will not perform any mutex locking for the
+ * CS mechanism. The user is responsible to locking and unlocking the mutex for the
+ * whole duration of the transfers.
+ */
+ bool manualCsLock = false;
+ uint32_t spiSpeed;
+ bool halfDuplex = false;
+
+ MutexIF::TimeoutType csTimeoutType = MutexIF::TimeoutType::WAITING;
+ dur_millis_t csTimeout = DEFAULT_MUTEX_TIMEOUT;
+
+ // Required for callback mode
+ spi::send_callback_function_t sendCallback = nullptr;
+ void* callbackArgs = nullptr;
+
+ struct spi_ioc_transfer spiTransferStruct = {};
+ UncommonParameters uncommonParameters;
+
/**
* Internal constructor which initializes every field
* @param spiAddress
@@ -154,27 +189,8 @@ class SpiCookie : public CookieIF {
* @param args
*/
SpiCookie(spi::SpiComIfModes comIfMode, address_t spiAddress, gpioId_t chipSelect,
- std::string spiDev, const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed,
+ const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed,
spi::send_callback_function_t callback, void* args);
-
- address_t spiAddress;
- gpioId_t chipSelectPin;
- std::string spiDevice;
-
- spi::SpiComIfModes comIfMode;
-
- // Required for regular mode
- const size_t maxSize;
- spi::SpiModes spiMode;
- uint32_t spiSpeed;
- bool halfDuplex = false;
-
- // Required for callback mode
- spi::send_callback_function_t sendCallback = nullptr;
- void* callbackArgs = nullptr;
-
- struct spi_ioc_transfer spiTransferStruct = {};
- UncommonParameters uncommonParameters;
};
#endif /* LINUX_SPI_SPICOOKIE_H_ */
diff --git a/hal/src/fsfw_hal/linux/uart/UartCookie.cpp b/hal/src/fsfw_hal/linux/uart/UartCookie.cpp
index 3fedc9d4..31dbc903 100644
--- a/hal/src/fsfw_hal/linux/uart/UartCookie.cpp
+++ b/hal/src/fsfw_hal/linux/uart/UartCookie.cpp
@@ -2,8 +2,8 @@
#include
-UartCookie::UartCookie(object_id_t handlerId, std::string deviceFile, UartModes uartMode,
- UartBaudRate baudrate, size_t maxReplyLen)
+UartCookie::UartCookie(object_id_t handlerId, std::string deviceFile, UartBaudRate baudrate,
+ size_t maxReplyLen, UartModes uartMode)
: handlerId(handlerId),
deviceFile(deviceFile),
uartMode(uartMode),
diff --git a/hal/src/fsfw_hal/linux/uart/UartCookie.h b/hal/src/fsfw_hal/linux/uart/UartCookie.h
index 6840b352..cae33d58 100644
--- a/hal/src/fsfw_hal/linux/uart/UartCookie.h
+++ b/hal/src/fsfw_hal/linux/uart/UartCookie.h
@@ -69,8 +69,8 @@ class UartCookie : public CookieIF {
* 8 databits (number of bits transfered with one uart frame)
* One stop bit
*/
- UartCookie(object_id_t handlerId, std::string deviceFile, UartModes uartMode,
- UartBaudRate baudrate, size_t maxReplyLen);
+ UartCookie(object_id_t handlerId, std::string deviceFile, UartBaudRate baudrate,
+ size_t maxReplyLen, UartModes uartMode = UartModes::NON_CANONICAL);
virtual ~UartCookie();
diff --git a/scripts/auto-formatter.sh b/scripts/auto-formatter.sh
index 405d1268..7e1b596d 100755
--- a/scripts/auto-formatter.sh
+++ b/scripts/auto-formatter.sh
@@ -3,6 +3,12 @@ if [[ ! -f README.md ]]; then
cd ..
fi
+folder_list=(
+ "./src"
+ "./hal"
+ "./tests"
+)
+
cmake_fmt="cmake-format"
file_selectors="-iname CMakeLists.txt"
if command -v ${cmake_fmt} &> /dev/null; then
@@ -15,9 +21,10 @@ fi
cpp_format="clang-format"
file_selectors="-iname *.h -o -iname *.cpp -o -iname *.c -o -iname *.tpp"
if command -v ${cpp_format} &> /dev/null; then
- find ./src ${file_selectors} | xargs ${cpp_format} --style=file -i
- find ./hal ${file_selectors} | xargs ${cpp_format} --style=file -i
- find ./tests ${file_selectors} | xargs ${cpp_format} --style=file -i
+ for dir in ${folder_list[@]}; do
+ echo "Auto-formatting ${dir} recursively"
+ find ${dir} ${file_selectors} | xargs clang-format --style=file -i
+ done
else
echo "No ${cpp_format} tool found, not formatting C++/C files"
fi
diff --git a/src/fsfw/action/CommandActionHelper.h b/src/fsfw/action/CommandActionHelper.h
index dd8ad7f1..3b8acb04 100644
--- a/src/fsfw/action/CommandActionHelper.h
+++ b/src/fsfw/action/CommandActionHelper.h
@@ -16,8 +16,8 @@ class CommandActionHelper {
public:
CommandActionHelper(CommandsActionsIF* owner);
virtual ~CommandActionHelper();
- ReturnValue_t commandAction(object_id_t commandTo, ActionId_t actionId, const uint8_t* data,
- uint32_t size);
+ ReturnValue_t commandAction(object_id_t commandTo, ActionId_t actionId,
+ const uint8_t* data = nullptr, uint32_t size = 0);
ReturnValue_t commandAction(object_id_t commandTo, ActionId_t actionId, SerializeIF* data);
ReturnValue_t initialize();
ReturnValue_t handleReply(CommandMessage* reply);
diff --git a/src/fsfw/cfdp/CFDPHandler.cpp b/src/fsfw/cfdp/CFDPHandler.cpp
index 96baa98c..09a24186 100644
--- a/src/fsfw/cfdp/CFDPHandler.cpp
+++ b/src/fsfw/cfdp/CFDPHandler.cpp
@@ -12,7 +12,9 @@ object_id_t CFDPHandler::packetDestination = 0;
CFDPHandler::CFDPHandler(object_id_t setObjectId, CFDPDistributor* dist)
: SystemObject(setObjectId) {
- requestQueue = QueueFactory::instance()->createMessageQueue(CFDP_HANDLER_MAX_RECEPTION);
+ auto mqArgs = MqArgs(setObjectId, static_cast(this));
+ requestQueue = QueueFactory::instance()->createMessageQueue(
+ CFDP_HANDLER_MAX_RECEPTION, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
distributor = dist;
}
diff --git a/src/fsfw/controller/ControllerBase.cpp b/src/fsfw/controller/ControllerBase.cpp
index 953dacb4..0e4ff970 100644
--- a/src/fsfw/controller/ControllerBase.cpp
+++ b/src/fsfw/controller/ControllerBase.cpp
@@ -13,7 +13,9 @@ ControllerBase::ControllerBase(object_id_t setObjectId, object_id_t parentId,
submode(SUBMODE_NONE),
modeHelper(this),
healthHelper(this, setObjectId) {
- commandQueue = QueueFactory::instance()->createMessageQueue(commandQueueDepth);
+ auto mqArgs = MqArgs(setObjectId, static_cast(this));
+ commandQueue = QueueFactory::instance()->createMessageQueue(
+ commandQueueDepth, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
}
ControllerBase::~ControllerBase() { QueueFactory::instance()->deleteMessageQueue(commandQueue); }
diff --git a/src/fsfw/datapool/PoolEntry.cpp b/src/fsfw/datapool/PoolEntry.cpp
index fd110e6c..9138a705 100644
--- a/src/fsfw/datapool/PoolEntry.cpp
+++ b/src/fsfw/datapool/PoolEntry.cpp
@@ -7,24 +7,26 @@
#include "fsfw/serviceinterface/ServiceInterface.h"
template
-PoolEntry::PoolEntry(std::initializer_list initValue, bool setValid)
- : length(static_cast(initValue.size())), valid(setValid) {
- this->address = new T[this->length];
- if (initValue.size() == 0) {
- std::memset(this->address, 0, this->getByteSize());
- } else {
- std::copy(initValue.begin(), initValue.end(), this->address);
+PoolEntry::PoolEntry(uint8_t len, bool setValid) : length(len), valid(setValid) {
+ this->address = new T[this->length]();
+ std::memset(this->address, 0, this->getByteSize());
+}
+
+template
+PoolEntry::PoolEntry(std::initializer_list initValues, bool setValid)
+ : length(static_cast(initValues.size())), valid(setValid) {
+ this->address = new T[this->length]();
+ if (initValues.size() > 0) {
+ std::copy(initValues.begin(), initValues.end(), this->address);
}
}
template
-PoolEntry::PoolEntry(T* initValue, uint8_t setLength, bool setValid)
+PoolEntry::PoolEntry(const T* initValue, uint8_t setLength, bool setValid)
: length(setLength), valid(setValid) {
- this->address = new T[this->length];
+ this->address = new T[this->length]();
if (initValue != nullptr) {
std::memcpy(this->address, initValue, this->getByteSize());
- } else {
- std::memset(this->address, 0, this->getByteSize());
}
}
diff --git a/src/fsfw/datapool/PoolEntry.h b/src/fsfw/datapool/PoolEntry.h
index d3d80f09..4010f78d 100644
--- a/src/fsfw/datapool/PoolEntry.h
+++ b/src/fsfw/datapool/PoolEntry.h
@@ -33,6 +33,9 @@ class PoolEntry : public PoolEntryIF {
"instead! The ECSS standard defines a boolean as a one bit "
"field. Therefore it is preferred to store a boolean as an "
"uint8_t");
+
+ PoolEntry(uint8_t len = 1, bool setValid = false);
+
/**
* @brief In the classe's constructor, space is allocated on the heap and
* potential initialization values are copied to that space.
@@ -49,7 +52,7 @@ class PoolEntry : public PoolEntryIF {
* @param setValid
* Sets the initialization flag. It is invalid by default.
*/
- PoolEntry(std::initializer_list initValue = {0}, bool setValid = false);
+ PoolEntry(std::initializer_list initValue, bool setValid = false);
/**
* @brief In the classe's constructor, space is allocated on the heap and
@@ -62,7 +65,7 @@ class PoolEntry : public PoolEntryIF {
* @param setValid
* Sets the initialization flag. It is invalid by default.
*/
- PoolEntry(T* initValue, uint8_t setLength = 1, bool setValid = false);
+ PoolEntry(const T* initValue, uint8_t setLength = 1, bool setValid = false);
//! Explicitely deleted copy ctor, copying is not allowed.
PoolEntry(const PoolEntry&) = delete;
diff --git a/src/fsfw/datapoollocal/LocalDataPoolManager.cpp b/src/fsfw/datapoollocal/LocalDataPoolManager.cpp
index 215d1753..f61980c6 100644
--- a/src/fsfw/datapoollocal/LocalDataPoolManager.cpp
+++ b/src/fsfw/datapoollocal/LocalDataPoolManager.cpp
@@ -577,6 +577,10 @@ ReturnValue_t LocalDataPoolManager::handleHousekeepingMessage(CommandMessage* me
CommandMessage reply;
if (result != HasReturnvaluesIF::RETURN_OK) {
+ if (result == WRONG_HK_PACKET_TYPE) {
+ printWarningOrError(sif::OutputTypes::OUT_WARNING, "handleHousekeepingMessage",
+ WRONG_HK_PACKET_TYPE);
+ }
HousekeepingMessage::setHkRequestFailureReply(&reply, sid, result);
} else {
HousekeepingMessage::setHkRequestSuccessReply(&reply, sid);
@@ -834,6 +838,8 @@ void LocalDataPoolManager::printWarningOrError(sif::OutputTypes outputType,
errorPrint = "Dataset not found";
} else if (error == POOLOBJECT_NOT_FOUND) {
errorPrint = "Pool Object not found";
+ } else if (error == WRONG_HK_PACKET_TYPE) {
+ errorPrint = "Wrong Packet Type";
} else if (error == HasReturnvaluesIF::RETURN_FAILED) {
if (outputType == sif::OutputTypes::OUT_WARNING) {
errorPrint = "Generic Warning";
diff --git a/src/fsfw/datapoollocal/LocalPoolDataSetBase.h b/src/fsfw/datapoollocal/LocalPoolDataSetBase.h
index 17cf8be2..9166cf34 100644
--- a/src/fsfw/datapoollocal/LocalPoolDataSetBase.h
+++ b/src/fsfw/datapoollocal/LocalPoolDataSetBase.h
@@ -162,6 +162,7 @@ class LocalPoolDataSetBase : public PoolDataSetBase, public MarkChangedIF {
object_id_t getCreatorObjectId();
bool getReportingEnabled() const;
+ void setReportingEnabled(bool enabled);
/**
* Returns the current periodic HK generation interval this set
@@ -189,7 +190,6 @@ class LocalPoolDataSetBase : public PoolDataSetBase, public MarkChangedIF {
* Used for periodic generation.
*/
bool reportingEnabled = false;
- void setReportingEnabled(bool enabled);
void initializePeriodicHelper(float collectionInterval, dur_millis_t minimumPeriodicInterval,
uint8_t nonDiagIntervalFactor = 5);
diff --git a/src/fsfw/devicehandlers/AssemblyBase.cpp b/src/fsfw/devicehandlers/AssemblyBase.cpp
index c29022e5..414098ad 100644
--- a/src/fsfw/devicehandlers/AssemblyBase.cpp
+++ b/src/fsfw/devicehandlers/AssemblyBase.cpp
@@ -26,11 +26,7 @@ void AssemblyBase::performChildOperation() {
void AssemblyBase::startTransition(Mode_t mode, Submode_t submode) {
doStartTransition(mode, submode);
- if (modeHelper.isForced()) {
- triggerEvent(FORCING_MODE, mode, submode);
- } else {
- triggerEvent(CHANGING_MODE, mode, submode);
- }
+ triggerModeHelperEvents(mode, submode);
}
void AssemblyBase::doStartTransition(Mode_t mode, Submode_t submode) {
@@ -77,9 +73,10 @@ bool AssemblyBase::handleChildrenChangedHealth() {
}
HealthState healthState = healthHelper.healthTable->getHealth(iter->first);
if (healthState == HasHealthIF::NEEDS_RECOVERY) {
- triggerEvent(TRYING_RECOVERY);
+ triggerEvent(TRYING_RECOVERY, iter->first, 0);
recoveryState = RECOVERY_STARTED;
recoveringDevice = iter;
+ // The user needs to take care of commanding the children off in commandChildren
doStartTransition(targetMode, targetSubmode);
} else {
triggerEvent(CHILD_CHANGED_HEALTH);
@@ -228,6 +225,9 @@ ReturnValue_t AssemblyBase::handleHealthReply(CommandMessage* message) {
bool AssemblyBase::checkAndHandleRecovery() {
switch (recoveryState) {
case RECOVERY_STARTED:
+ // The recovery was already start in #handleChildrenChangedHealth and we just need
+ // to wait for an off time period.
+ // TODO: make time period configurable
recoveryState = RECOVERY_WAIT;
recoveryOffTimer.resetTimer();
return true;
@@ -266,3 +266,11 @@ void AssemblyBase::overwriteDeviceHealth(object_id_t objectId, HasHealthIF::Heal
modeHelper.setForced(true);
sendHealthCommand(childrenMap[objectId].commandQueue, EXTERNAL_CONTROL);
}
+
+void AssemblyBase::triggerModeHelperEvents(Mode_t mode, Submode_t submode) {
+ if (modeHelper.isForced()) {
+ triggerEvent(FORCING_MODE, mode, submode);
+ } else {
+ triggerEvent(CHANGING_MODE, mode, submode);
+ }
+}
diff --git a/src/fsfw/devicehandlers/AssemblyBase.h b/src/fsfw/devicehandlers/AssemblyBase.h
index 3e235928..a6e6e3db 100644
--- a/src/fsfw/devicehandlers/AssemblyBase.h
+++ b/src/fsfw/devicehandlers/AssemblyBase.h
@@ -12,7 +12,8 @@
* Documentation: Dissertation Baetz p.156, 157.
*
* This class reduces the complexity of controller components which would
- * otherwise be needed for the handling of redundant devices.
+ * otherwise be needed for the handling of redundant devices. However, it can also be used to
+ * manage the mode keeping and recovery of non-redundant devices
*
* The template class monitors mode and health state of its children
* and checks availability of devices on every detected change.
@@ -26,11 +27,9 @@
*
* Important:
*
- * The implementation must call registerChild(object_id_t child)
- * for all commanded children during initialization.
+ * The implementation must call #registerChild for all commanded children during initialization.
* The implementation must call the initialization function of the base class.
* (This will call the function in SubsystemBase)
- *
*/
class AssemblyBase : public SubsystemBase {
public:
@@ -47,13 +46,14 @@ class AssemblyBase : public SubsystemBase {
protected:
/**
- * Command children to reach [mode,submode] combination
- * Can be done by setting #commandsOutstanding correctly,
- * or using executeTable()
+ * Command children to reach [mode,submode] combination. Can be done by setting
+ * #commandsOutstanding correctly, or using #executeTable. In case of an FDIR recovery,
+ * the user needs to ensure that the target devices are healthy. If a device is not healthy,
+ * a recovery might be on-going and the device needs to be commanded to off first.
* @param mode
* @param submode
* @return
- * - @c RETURN_OK if ok
+ * - @c RETURN_OK if OK
* - @c NEED_SECOND_STEP if children need to be commanded again
*/
virtual ReturnValue_t commandChildren(Mode_t mode, Submode_t submode) = 0;
@@ -120,8 +120,19 @@ class AssemblyBase : public SubsystemBase {
virtual ReturnValue_t handleHealthReply(CommandMessage *message);
- virtual void performChildOperation();
+ /**
+ * @brief Default periodic handler
+ * @details
+ * This is the default periodic handler which will be called by the SubsystemBase
+ * performOperation. It performs the child transitions or reacts to changed health/mode states
+ * of children objects
+ */
+ virtual void performChildOperation() override;
+ /**
+ * This function handles changed mode or health states of children
+ * @return
+ */
bool handleChildrenChanged();
/**
@@ -134,12 +145,37 @@ class AssemblyBase : public SubsystemBase {
bool handleChildrenChangedHealth();
+ /**
+ * Core transition handler. The default implementation will only do something if
+ * #commandsOutstanding is smaller or equal to zero, which means that all mode commands
+ * from the #doPerformTransition call were executed successfully.
+ *
+ * Unless a second step was requested, the function will then use #checkChildrenState to
+ * determine whether the target mode was reached.
+ *
+ * There is some special handling for certain (internal) modes:
+ * - A second step is necessary. #commandChildren will be performed again
+ * - The device health was overwritten. #commandChildren will be called
+ * - A recovery is ongoing. #checkAndHandleRecovery will be called.
+ */
virtual void handleChildrenTransition();
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, uint32_t *msToReachTheMode);
+ /**
+ * Calls #doStartTransition and triggers an informative event as well that the mode will
+ * change
+ * @param mode
+ * @param submode
+ */
virtual void startTransition(Mode_t mode, Submode_t submode);
+ /**
+ * This function starts the transition by setting the internal #targetSubmode and #targetMode
+ * variables and then calling the #commandChildren function.
+ * @param mode
+ * @param submode
+ */
virtual void doStartTransition(Mode_t mode, Submode_t submode);
virtual bool isInTransition();
@@ -160,7 +196,7 @@ class AssemblyBase : public SubsystemBase {
* Manages recovery of a device
* @return true if recovery is still ongoing, false else.
*/
- bool checkAndHandleRecovery();
+ virtual bool checkAndHandleRecovery();
/**
* Helper method to overwrite health state of one of the children.
@@ -168,6 +204,8 @@ class AssemblyBase : public SubsystemBase {
* @param objectId Must be a registered child.
*/
void overwriteDeviceHealth(object_id_t objectId, HasHealthIF::HealthState oldHealth);
+
+ void triggerModeHelperEvents(Mode_t mode, Submode_t submode);
};
#endif /* FSFW_DEVICEHANDLERS_ASSEMBLYBASE_H_ */
diff --git a/src/fsfw/devicehandlers/DeviceHandlerBase.cpp b/src/fsfw/devicehandlers/DeviceHandlerBase.cpp
index dd9bd5d7..a7ce2870 100644
--- a/src/fsfw/devicehandlers/DeviceHandlerBase.cpp
+++ b/src/fsfw/devicehandlers/DeviceHandlerBase.cpp
@@ -39,8 +39,9 @@ DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, object_id_t device
childTransitionDelay(5000),
transitionSourceMode(_MODE_POWER_DOWN),
transitionSourceSubMode(SUBMODE_NONE) {
+ auto mqArgs = MqArgs(setObjectId, static_cast(this));
commandQueue = QueueFactory::instance()->createMessageQueue(
- cmdQueueSize, MessageQueueMessage::MAX_MESSAGE_SIZE);
+ cmdQueueSize, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
insertInCommandMap(RAW_COMMAND_ID);
cookieInfo.state = COOKIE_UNUSED;
cookieInfo.pendingCommand = deviceCommandMap.end();
@@ -48,9 +49,6 @@ DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, object_id_t device
printWarningOrError(sif::OutputTypes::OUT_ERROR, "DeviceHandlerBase",
HasReturnvaluesIF::RETURN_FAILED, "Invalid cookie");
}
- if (this->fdirInstance == nullptr) {
- this->fdirInstance = new DeviceHandlerFailureIsolation(setObjectId, defaultFdirParentId);
- }
}
void DeviceHandlerBase::setHkDestination(object_id_t hkDestination) {
@@ -126,6 +124,18 @@ ReturnValue_t DeviceHandlerBase::initialize() {
if (result != RETURN_OK) {
return result;
}
+ if (this->fdirInstance == nullptr) {
+ this->fdirInstance =
+ new DeviceHandlerFailureIsolation(this->getObjectId(), defaultFdirParentId);
+ }
+
+ if (this->parent != objects::NO_OBJECT) {
+ HasModesIF* modeIF = ObjectManager::instance()->get(this->parent);
+ HasHealthIF* healthIF = ObjectManager::instance()->get(this->parent);
+ if (modeIF != nullptr and healthIF != nullptr) {
+ setParentQueue(modeIF->getCommandQueue());
+ }
+ }
communicationInterface =
ObjectManager::instance()->get(deviceCommunicationId);
@@ -233,17 +243,28 @@ ReturnValue_t DeviceHandlerBase::initialize() {
}
void DeviceHandlerBase::decrementDeviceReplyMap() {
+ bool timedOut = false;
for (std::pair& replyPair : deviceReplyMap) {
- if (replyPair.second.delayCycles != 0) {
+ if (replyPair.second.countdown != nullptr && replyPair.second.active) {
+ if (replyPair.second.countdown->hasTimedOut()) {
+ timedOut = true;
+ }
+ }
+ if (replyPair.second.delayCycles != 0 && replyPair.second.countdown == nullptr) {
replyPair.second.delayCycles--;
if (replyPair.second.delayCycles == 0) {
if (replyPair.second.periodic) {
replyPair.second.delayCycles = replyPair.second.maxDelayCycles;
}
- replyToReply(replyPair.first, replyPair.second, TIMEOUT);
- missedReply(replyPair.first);
+ timedOut = true;
}
}
+ if (timedOut) {
+ replyToReply(replyPair.first, replyPair.second, TIMEOUT);
+ missedReply(replyPair.first);
+ timedOut = false;
+ replyPair.second.active = false;
+ }
}
}
@@ -352,14 +373,12 @@ void DeviceHandlerBase::doStateMachine() {
}
} break;
case _MODE_WAIT_OFF: {
- uint32_t currentUptime;
- Clock::getUptime(¤tUptime);
-
if (powerSwitcher == nullptr) {
setMode(MODE_OFF);
break;
}
-
+ uint32_t currentUptime;
+ Clock::getUptime(¤tUptime);
if (currentUptime - timeoutStart >= powerSwitcher->getSwitchDelayMs()) {
triggerEvent(MODE_TRANSITION_FAILED, PowerSwitchIF::SWITCH_TIMEOUT, 0);
setMode(MODE_ERROR_ON);
@@ -408,20 +427,22 @@ ReturnValue_t DeviceHandlerBase::isModeCombinationValid(Mode_t mode, Submode_t s
ReturnValue_t DeviceHandlerBase::insertInCommandAndReplyMap(
DeviceCommandId_t deviceCommand, uint16_t maxDelayCycles, LocalPoolDataSetBase* replyDataSet,
- size_t replyLen, bool periodic, bool hasDifferentReplyId, DeviceCommandId_t replyId) {
+ size_t replyLen, bool periodic, bool hasDifferentReplyId, DeviceCommandId_t replyId,
+ Countdown* countdown) {
// No need to check, as we may try to insert multiple times.
insertInCommandMap(deviceCommand, hasDifferentReplyId, replyId);
if (hasDifferentReplyId) {
- return insertInReplyMap(replyId, maxDelayCycles, replyDataSet, replyLen, periodic);
+ return insertInReplyMap(replyId, maxDelayCycles, replyDataSet, replyLen, periodic, countdown);
} else {
- return insertInReplyMap(deviceCommand, maxDelayCycles, replyDataSet, replyLen, periodic);
+ return insertInReplyMap(deviceCommand, maxDelayCycles, replyDataSet, replyLen, periodic,
+ countdown);
}
}
ReturnValue_t DeviceHandlerBase::insertInReplyMap(DeviceCommandId_t replyId,
uint16_t maxDelayCycles,
LocalPoolDataSetBase* dataSet, size_t replyLen,
- bool periodic) {
+ bool periodic, Countdown* countdown) {
DeviceReplyInfo info;
info.maxDelayCycles = maxDelayCycles;
info.periodic = periodic;
@@ -429,6 +450,10 @@ ReturnValue_t DeviceHandlerBase::insertInReplyMap(DeviceCommandId_t replyId,
info.replyLen = replyLen;
info.dataSet = dataSet;
info.command = deviceCommandMap.end();
+ info.countdown = countdown;
+ if (info.periodic) {
+ info.active = true;
+ }
auto resultPair = deviceReplyMap.emplace(replyId, info);
if (resultPair.second) {
return RETURN_OK;
@@ -464,7 +489,8 @@ size_t DeviceHandlerBase::getNextReplyLength(DeviceCommandId_t commandId) {
}
DeviceReplyIter iter = deviceReplyMap.find(replyId);
if (iter != deviceReplyMap.end()) {
- if (iter->second.delayCycles != 0) {
+ if ((iter->second.delayCycles != 0 && iter->second.countdown == nullptr) ||
+ (iter->second.active && iter->second.countdown != nullptr)) {
return iter->second.replyLen;
}
}
@@ -546,6 +572,9 @@ void DeviceHandlerBase::setMode(Mode_t newMode, uint8_t newSubmode) {
mode = newMode;
modeChanged();
setNormalDatapoolEntriesInvalid();
+ if (newMode == MODE_OFF) {
+ disableCommandsAndReplies();
+ }
if (!isTransitionalMode()) {
modeHelper.modeChanged(newMode, newSubmode);
announceMode(false);
@@ -808,17 +837,18 @@ void DeviceHandlerBase::handleReply(const uint8_t* receivedData, DeviceCommandId
DeviceReplyInfo* info = &(iter->second);
- if (info->delayCycles != 0) {
+ if ((info->delayCycles != 0 && info->countdown == nullptr) ||
+ (info->active && info->countdown != nullptr)) {
result = interpretDeviceReply(foundId, receivedData);
if (result == IGNORE_REPLY_DATA) {
return;
}
- if (info->periodic) {
- info->delayCycles = info->maxDelayCycles;
- } else {
- info->delayCycles = 0;
+ if (info->active && info->countdown != nullptr) {
+ disableTimeoutControlledReply(info);
+ } else if (info->delayCycles != 0) {
+ disableDelayCyclesControlledReply(info);
}
if (result != RETURN_OK) {
@@ -837,6 +867,24 @@ void DeviceHandlerBase::handleReply(const uint8_t* receivedData, DeviceCommandId
}
}
+void DeviceHandlerBase::disableTimeoutControlledReply(DeviceReplyInfo* info) {
+ if (info->periodic) {
+ info->countdown->resetTimer();
+ } else {
+ info->active = false;
+ info->countdown->timeOut();
+ }
+}
+
+void DeviceHandlerBase::disableDelayCyclesControlledReply(DeviceReplyInfo* info) {
+ if (info->periodic) {
+ info->delayCycles = info->maxDelayCycles;
+ } else {
+ info->delayCycles = 0;
+ info->active = false;
+ }
+}
+
ReturnValue_t DeviceHandlerBase::getStorageData(store_address_t storageAddress, uint8_t** data,
size_t* len) {
size_t lenTmp;
@@ -962,6 +1010,10 @@ ReturnValue_t DeviceHandlerBase::enableReplyInReplyMap(DeviceCommandMap::iterato
info->delayCycles = info->maxDelayCycles;
info->command = command;
command->second.expectedReplies = expectedReplies;
+ if (info->countdown != nullptr) {
+ info->countdown->resetTimer();
+ }
+ info->active = true;
return RETURN_OK;
} else {
return NO_REPLY_EXPECTED;
@@ -1196,7 +1248,8 @@ void DeviceHandlerBase::setParentQueue(MessageQueueId_t parentQueueId) {
bool DeviceHandlerBase::isAwaitingReply() {
std::map::iterator iter;
for (iter = deviceReplyMap.begin(); iter != deviceReplyMap.end(); ++iter) {
- if (iter->second.delayCycles != 0) {
+ if ((iter->second.delayCycles != 0 && iter->second.countdown == nullptr) ||
+ (iter->second.active && iter->second.countdown != nullptr)) {
return true;
}
}
@@ -1351,6 +1404,8 @@ uint8_t DeviceHandlerBase::getReplyDelayCycles(DeviceCommandId_t deviceCommand)
DeviceReplyMap::iterator iter = deviceReplyMap.find(deviceCommand);
if (iter == deviceReplyMap.end()) {
return 0;
+ } else if (iter->second.countdown != nullptr) {
+ return 0;
}
return iter->second.delayCycles;
}
@@ -1399,6 +1454,8 @@ void DeviceHandlerBase::setTaskIF(PeriodicTaskIF* task) { executingTask = task;
void DeviceHandlerBase::debugInterface(uint8_t positionTracker, object_id_t objectId,
uint32_t parameter) {}
+Submode_t DeviceHandlerBase::getInitialSubmode() { return SUBMODE_NONE; }
+
void DeviceHandlerBase::performOperationHook() {}
ReturnValue_t DeviceHandlerBase::initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
@@ -1421,7 +1478,7 @@ ReturnValue_t DeviceHandlerBase::initializeAfterTaskCreation() {
this->poolManager.initializeAfterTaskCreation();
if (setStartupImmediately) {
- startTransition(MODE_ON, SUBMODE_NONE);
+ startTransition(MODE_ON, getInitialSubmode());
}
return HasReturnvaluesIF::RETURN_OK;
}
@@ -1505,3 +1562,29 @@ MessageQueueId_t DeviceHandlerBase::getCommanderQueueId(DeviceCommandId_t replyI
}
return commandIter->second.sendReplyTo;
}
+
+void DeviceHandlerBase::setCustomFdir(FailureIsolationBase* fdir) { this->fdirInstance = fdir; }
+
+void DeviceHandlerBase::setParent(object_id_t parent) { this->parent = parent; }
+
+void DeviceHandlerBase::setPowerSwitcher(PowerSwitchIF* switcher) {
+ this->powerSwitcher = switcher;
+}
+
+void DeviceHandlerBase::disableCommandsAndReplies() {
+ for (auto& command : deviceCommandMap) {
+ if (command.second.isExecuting) {
+ command.second.isExecuting = false;
+ }
+ }
+ for (auto& reply : deviceReplyMap) {
+ if (!reply.second.periodic) {
+ if (reply.second.countdown != nullptr) {
+ reply.second.countdown->timeOut();
+ } else {
+ reply.second.delayCycles = 0;
+ }
+ reply.second.active = false;
+ }
+ }
+}
diff --git a/src/fsfw/devicehandlers/DeviceHandlerBase.h b/src/fsfw/devicehandlers/DeviceHandlerBase.h
index 84dcb8dc..58e54da0 100644
--- a/src/fsfw/devicehandlers/DeviceHandlerBase.h
+++ b/src/fsfw/devicehandlers/DeviceHandlerBase.h
@@ -103,6 +103,9 @@ class DeviceHandlerBase : public DeviceHandlerIF,
DeviceHandlerBase(object_id_t setObjectId, object_id_t deviceCommunication, CookieIF *comCookie,
FailureIsolationBase *fdirInstance = nullptr, size_t cmdQueueSize = 20);
+ void setCustomFdir(FailureIsolationBase *fdir);
+ void setParent(object_id_t parent);
+ void setPowerSwitcher(PowerSwitchIF *switcher);
void setHkDestination(object_id_t hkDestination);
/**
@@ -448,6 +451,9 @@ class DeviceHandlerBase : public DeviceHandlerIF,
* by the device repeatedly without request) or not. Default is aperiodic (0).
* Please note that periodic replies are disabled by default. You can enable them with
* #updatePeriodicReply
+ * @param countdown Instead of using maxDelayCycles to timeout a device reply it is also possible
+ * to provide a pointer to a Countdown object which will signal the timeout
+ * when expired
* @return - @c RETURN_OK when the command was successfully inserted,
* - @c RETURN_FAILED else.
*/
@@ -455,22 +461,26 @@ class DeviceHandlerBase : public DeviceHandlerIF,
LocalPoolDataSetBase *replyDataSet = nullptr,
size_t replyLen = 0, bool periodic = false,
bool hasDifferentReplyId = false,
- DeviceCommandId_t replyId = 0);
+ DeviceCommandId_t replyId = 0,
+ Countdown *countdown = nullptr);
/**
* @brief This is a helper method to insert replies in the reply map.
* @param deviceCommand Identifier of the reply to add.
* @param maxDelayCycles The maximum number of delay cycles the reply waits
- * until it times out.
+ * until it times out.
* @param periodic Indicates if the command is periodic (i.e. it is sent
- * by the device repeatedly without request) or not. Default is aperiodic (0).
- * Please note that periodic replies are disabled by default. You can enable them with
- * #updatePeriodicReply
+ * by the device repeatedly without request) or not. Default is aperiodic (0).
+ * Please note that periodic replies are disabled by default. You can enable them with
+ * #updatePeriodicReply
+ * @param countdown Instead of using maxDelayCycles to timeout a device reply it is also possible
+ * to provide a pointer to a Countdown object which will signal the timeout
+ * when expired
* @return - @c RETURN_OK when the command was successfully inserted,
* - @c RETURN_FAILED else.
*/
ReturnValue_t insertInReplyMap(DeviceCommandId_t deviceCommand, uint16_t maxDelayCycles,
LocalPoolDataSetBase *dataSet = nullptr, size_t replyLen = 0,
- bool periodic = false);
+ bool periodic = false, Countdown *countdown = nullptr);
/**
* @brief A simple command to add a command to the commandList.
@@ -649,6 +659,12 @@ class DeviceHandlerBase : public DeviceHandlerIF,
virtual void debugInterface(uint8_t positionTracker = 0, object_id_t objectId = 0,
uint32_t parameter = 0);
+ /**
+ * @brief Can be overwritten by a child to specify the initial submode when device has been set
+ * to startup immediately.
+ */
+ virtual Submode_t getInitialSubmode();
+
protected:
static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_BASE;
@@ -767,11 +783,18 @@ class DeviceHandlerBase : public DeviceHandlerIF,
* This is used to keep track of pending replies.
*/
struct DeviceReplyInfo {
+ //! For Command-Reply combinations:
//! The maximum number of cycles the handler should wait for a reply
//! to this command.
+ //!
+ //! Reply Only:
+ //! For periodic replies, this variable will be the number of delay cycles between the replies.
+ //! For the non-periodic variant, this variable is not used as there is no meaningful
+ //! definition for delay
uint16_t maxDelayCycles;
- //! The currently remaining cycles the handler should wait for a reply,
- //! 0 means there is no reply expected
+ //! This variable will be set to #maxDelayCycles if a reply is expected.
+ //! For non-periodic replies without a command, this variable is unused.
+ //! A runtime value of 0 means there is no reply is currently expected.
uint16_t delayCycles;
size_t replyLen = 0; //!< Expected size of the reply.
//! if this is !=0, the delayCycles will not be reset to 0 but to
@@ -783,6 +806,11 @@ class DeviceHandlerBase : public DeviceHandlerIF,
LocalPoolDataSetBase *dataSet = nullptr;
//! The command that expects this reply.
DeviceCommandMap::iterator command;
+ //! Instead of using delayCycles to specify the maximum time to wait for the device reply, it
+ //! is also possible specify a countdown
+ Countdown *countdown = nullptr;
+ //! will be set to true when reply is enabled
+ bool active = false;
};
using DeviceReplyMap = std::map;
@@ -822,6 +850,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
/** Pointer to the used FDIR instance. If not provided by child,
* default class is instantiated. */
FailureIsolationBase *fdirInstance;
+ object_id_t parent = objects::NO_OBJECT;
//! To correctly delete the default instance.
bool defaultFDIRUsed;
@@ -1244,6 +1273,17 @@ class DeviceHandlerBase : public DeviceHandlerIF,
*/
void doGetRead(void);
+ /**
+ * @brief Handles disabling of replies which use a timeout to detect missed replies.
+ */
+ void disableTimeoutControlledReply(DeviceReplyInfo *info);
+
+ /**
+ * @brief Handles disabling of replies which use a number of maximum delay cycles to detect
+ * missed replies.
+ */
+ void disableDelayCyclesControlledReply(DeviceReplyInfo *info);
+
/**
* Retrive data from the #IPCStore.
*
@@ -1285,6 +1325,11 @@ class DeviceHandlerBase : public DeviceHandlerIF,
void printWarningOrError(sif::OutputTypes errorType, const char *functionName,
ReturnValue_t errorCode = HasReturnvaluesIF::RETURN_FAILED,
const char *errorPrint = nullptr);
+
+ /**
+ * @brief Disables all commands and replies when device is set to MODE_OFF
+ */
+ void disableCommandsAndReplies();
};
#endif /* FSFW_DEVICEHANDLERS_DEVICEHANDLERBASE_H_ */
diff --git a/src/fsfw/devicehandlers/DeviceHandlerFailureIsolation.cpp b/src/fsfw/devicehandlers/DeviceHandlerFailureIsolation.cpp
index 48783c20..88fba19f 100644
--- a/src/fsfw/devicehandlers/DeviceHandlerFailureIsolation.cpp
+++ b/src/fsfw/devicehandlers/DeviceHandlerFailureIsolation.cpp
@@ -29,6 +29,7 @@ ReturnValue_t DeviceHandlerFailureIsolation::eventReceived(EventMessage* event)
switch (event->getEvent()) {
case HasModesIF::MODE_TRANSITION_FAILED:
case HasModesIF::OBJECT_IN_INVALID_MODE:
+ case DeviceHandlerIF::DEVICE_WANTS_HARD_REBOOT:
// We'll try a recovery as long as defined in MAX_REBOOT.
// Might cause some AssemblyBase cycles, so keep number low.
handleRecovery(event->getEvent());
diff --git a/src/fsfw/devicehandlers/DeviceHandlerIF.h b/src/fsfw/devicehandlers/DeviceHandlerIF.h
index 1fc63d3b..1ea742f7 100644
--- a/src/fsfw/devicehandlers/DeviceHandlerIF.h
+++ b/src/fsfw/devicehandlers/DeviceHandlerIF.h
@@ -109,6 +109,7 @@ class DeviceHandlerIF {
static const Event INVALID_DEVICE_COMMAND = MAKE_EVENT(8, severity::LOW);
static const Event MONITORING_LIMIT_EXCEEDED = MAKE_EVENT(9, severity::LOW);
static const Event MONITORING_AMBIGUOUS = MAKE_EVENT(10, severity::HIGH);
+ static const Event DEVICE_WANTS_HARD_REBOOT = MAKE_EVENT(11, severity::HIGH);
static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_IF;
diff --git a/src/fsfw/devicehandlers/HealthDevice.cpp b/src/fsfw/devicehandlers/HealthDevice.cpp
index a626fa6c..5514b65f 100644
--- a/src/fsfw/devicehandlers/HealthDevice.cpp
+++ b/src/fsfw/devicehandlers/HealthDevice.cpp
@@ -8,7 +8,9 @@ HealthDevice::HealthDevice(object_id_t setObjectId, MessageQueueId_t parentQueue
parentQueue(parentQueue),
commandQueue(),
healthHelper(this, setObjectId) {
- commandQueue = QueueFactory::instance()->createMessageQueue(3);
+ auto mqArgs = MqArgs(setObjectId, static_cast(this));
+ commandQueue = QueueFactory::instance()->createMessageQueue(
+ 3, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
}
HealthDevice::~HealthDevice() { QueueFactory::instance()->deleteMessageQueue(commandQueue); }
diff --git a/src/fsfw/events/EventManager.cpp b/src/fsfw/events/EventManager.cpp
index aaa7d6c5..824682da 100644
--- a/src/fsfw/events/EventManager.cpp
+++ b/src/fsfw/events/EventManager.cpp
@@ -18,8 +18,9 @@ const LocalPool::LocalPoolConfig EventManager::poolConfig = {
EventManager::EventManager(object_id_t setObjectId)
: SystemObject(setObjectId), factoryBackend(0, poolConfig, false, true) {
mutex = MutexFactory::instance()->createMutex();
- eventReportQueue = QueueFactory::instance()->createMessageQueue(MAX_EVENTS_PER_CYCLE,
- EventMessage::EVENT_MESSAGE_SIZE);
+ auto mqArgs = MqArgs(setObjectId, static_cast(this));
+ eventReportQueue = QueueFactory::instance()->createMessageQueue(
+ MAX_EVENTS_PER_CYCLE, EventMessage::EVENT_MESSAGE_SIZE, &mqArgs);
}
EventManager::~EventManager() {
@@ -46,9 +47,20 @@ ReturnValue_t EventManager::performOperation(uint8_t opCode) {
void EventManager::notifyListeners(EventMessage* message) {
lockMutex();
- for (auto iter = listenerList.begin(); iter != listenerList.end(); ++iter) {
- if (iter->second.match(message)) {
- MessageQueueSenderIF::sendMessage(iter->first, message, message->getSender());
+ for (auto& listener : listenerList) {
+ if (listener.second.match(message)) {
+ ReturnValue_t result =
+ MessageQueueSenderIF::sendMessage(listener.first, message, message->getSender());
+ if (result != HasReturnvaluesIF::RETURN_OK) {
+#if FSFW_CPP_OSTREAM_ENABLED == 1
+ sif::error << std::hex << "EventManager::notifyListeners: MSG to 0x" << std::setfill('0')
+ << std::setw(8) << listener.first << " failed with result 0x" << std::setw(4)
+ << result << std::setfill(' ') << std::endl;
+#else
+ sif::printError("Sending message to listener 0x%08x failed with result %04x\n",
+ listener.first, result);
+#endif
+ }
}
}
unlockMutex();
@@ -189,4 +201,19 @@ void EventManager::printUtility(sif::OutputTypes printType, EventMessage* messag
}
}
+void EventManager::printListeners() {
+#if FSFW_CPP_OSTREAM_ENABLED == 1
+ sif::info << "Event manager listener MQ IDs:" << std::setfill('0') << std::hex << std::endl;
+ for (auto& listener : listenerList) {
+ sif::info << "0x" << std::setw(8) << listener.first << std::endl;
+ }
+ sif::info << std::dec << std::setfill(' ');
+#else
+ sif::printInfo("Event manager listener MQ IDs:\n");
+ for (auto& listener : listenerList) {
+ sif::printInfo("0x%08x\n", listener.first);
+ }
+#endif
+}
+
#endif /* FSFW_OBJ_EVENT_TRANSLATION == 1 */
diff --git a/src/fsfw/events/EventManager.h b/src/fsfw/events/EventManager.h
index f2d642ff..e2a8dd95 100644
--- a/src/fsfw/events/EventManager.h
+++ b/src/fsfw/events/EventManager.h
@@ -42,6 +42,7 @@ class EventManager : public EventManagerIF, public ExecutableObjectIF, public Sy
object_id_t reporterFrom = 0, object_id_t reporterTo = 0,
bool reporterInverted = false);
ReturnValue_t performOperation(uint8_t opCode);
+ void printListeners();
protected:
MessageQueueIF* eventReportQueue = nullptr;
diff --git a/src/fsfw/fdir/FailureIsolationBase.cpp b/src/fsfw/fdir/FailureIsolationBase.cpp
index fedef869..c17cf624 100644
--- a/src/fsfw/fdir/FailureIsolationBase.cpp
+++ b/src/fsfw/fdir/FailureIsolationBase.cpp
@@ -9,8 +9,9 @@
FailureIsolationBase::FailureIsolationBase(object_id_t owner, object_id_t parent,
uint8_t messageDepth, uint8_t parameterDomainBase)
: ownerId(owner), faultTreeParent(parent), parameterDomainBase(parameterDomainBase) {
- eventQueue =
- QueueFactory::instance()->createMessageQueue(messageDepth, EventMessage::EVENT_MESSAGE_SIZE);
+ auto mqArgs = MqArgs(owner, static_cast(this));
+ eventQueue = QueueFactory::instance()->createMessageQueue(
+ messageDepth, EventMessage::EVENT_MESSAGE_SIZE, &mqArgs);
}
FailureIsolationBase::~FailureIsolationBase() {
@@ -51,11 +52,12 @@ ReturnValue_t FailureIsolationBase::initialize() {
ObjectManager::instance()->get(faultTreeParent);
if (parentIF == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
- sif::error << "FailureIsolationBase::intialize: Parent object"
- << "invalid." << std::endl;
-#endif
-#if FSFW_CPP_OSTREAM_ENABLED == 1
- sif::error << "Make sure it implements ConfirmsFailuresIF." << std::endl;
+ sif::error << "FailureIsolationBase::intialize: Parent object "
+ << "invalid" << std::endl;
+ sif::error << "Make sure it implements ConfirmsFailuresIF" << std::endl;
+#else
+ sif::printError("FailureIsolationBase::intialize: Parent object invalid\n");
+ sif::printError("Make sure it implements ConfirmsFailuresIF\n");
#endif
return ObjectManagerIF::CHILD_INIT_FAILED;
return RETURN_FAILED;
diff --git a/src/fsfw/fdir/FailureIsolationBase.h b/src/fsfw/fdir/FailureIsolationBase.h
index 85d18add..7d128083 100644
--- a/src/fsfw/fdir/FailureIsolationBase.h
+++ b/src/fsfw/fdir/FailureIsolationBase.h
@@ -14,13 +14,12 @@ class FailureIsolationBase : public HasReturnvaluesIF,
public HasParametersIF {
public:
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::FDIR_1;
- static const Event FDIR_CHANGED_STATE =
- MAKE_EVENT(1, severity::INFO); //!< FDIR has an internal state, which changed from par2
- //!< (oldState) to par1 (newState).
- static const Event FDIR_STARTS_RECOVERY = MAKE_EVENT(
- 2, severity::MEDIUM); //!< FDIR tries to restart device. Par1: event that caused recovery.
- static const Event FDIR_TURNS_OFF_DEVICE = MAKE_EVENT(
- 3, severity::MEDIUM); //!< FDIR turns off device. Par1: event that caused recovery.
+ //! FDIR has an internal state, which changed from par2 (oldState) to par1 (newState).
+ static const Event FDIR_CHANGED_STATE = MAKE_EVENT(1, severity::INFO);
+ //! FDIR tries to restart device. Par1: event that caused recovery.
+ static const Event FDIR_STARTS_RECOVERY = MAKE_EVENT(2, severity::MEDIUM);
+ //! FDIR turns off device. Par1: event that caused recovery.
+ static const Event FDIR_TURNS_OFF_DEVICE = MAKE_EVENT(3, severity::MEDIUM);
FailureIsolationBase(object_id_t owner, object_id_t parent = objects::NO_OBJECT,
uint8_t messageDepth = 10, uint8_t parameterDomainBase = 0xF0);
diff --git a/src/fsfw/globalfunctions/CMakeLists.txt b/src/fsfw/globalfunctions/CMakeLists.txt
index cfa02696..cf8a25d5 100644
--- a/src/fsfw/globalfunctions/CMakeLists.txt
+++ b/src/fsfw/globalfunctions/CMakeLists.txt
@@ -4,6 +4,7 @@ target_sources(
AsciiConverter.cpp
CRC.cpp
DleEncoder.cpp
+ DleParser.cpp
PeriodicOperationDivider.cpp
timevalOperations.cpp
Type.cpp
diff --git a/src/fsfw/globalfunctions/DleParser.cpp b/src/fsfw/globalfunctions/DleParser.cpp
new file mode 100644
index 00000000..f326f837
--- /dev/null
+++ b/src/fsfw/globalfunctions/DleParser.cpp
@@ -0,0 +1,230 @@
+#include "DleParser.h"
+
+#include
+
+#include
+
+DleParser::DleParser(SimpleRingBuffer& decodeRingBuf, DleEncoder& decoder, BufPair encodedBuf,
+ BufPair decodedBuf, UserHandler handler, void* args)
+ : decodeRingBuf(decodeRingBuf),
+ decoder(decoder),
+ encodedBuf(encodedBuf),
+ decodedBuf(decodedBuf),
+ handler(handler),
+ ctx(args) {
+ if (handler == nullptr) {
+#if FSFW_CPP_OSTREAM_ENABLED == 1
+ sif::error << "DleParser::DleParser: Invalid user handler" << std::endl;
+#else
+ sif::printError("DleParser::DleParser: Invalid user handler\n");
+#endif
+ }
+}
+
+ReturnValue_t DleParser::passData(uint8_t* data, size_t len) {
+ if (data == nullptr or len == 0 or handler == nullptr) {
+ return RETURN_FAILED;
+ }
+ size_t copyIntoRingBufFromHere = 0;
+ size_t copyAmount = len;
+ size_t startIdx = 0;
+ ReturnValue_t result = RETURN_OK;
+ bool startFoundInThisPacket = false;
+ for (size_t idx = 0; idx < len; idx++) {
+ if (data[idx] == DleEncoder::STX_CHAR) {
+ if (not startFound and not startFoundInThisPacket) {
+ startIdx = idx;
+ copyIntoRingBufFromHere = idx;
+ copyAmount = len - idx;
+ } else {
+ // Maybe print warning, should not happen
+ decodeRingBuf.clear();
+ ErrorInfo info;
+ info.len = idx;
+ prepareErrorContext(ErrorTypes::CONSECUTIVE_STX_CHARS, info);
+ handler(ctx);
+ copyIntoRingBufFromHere = idx;
+ copyAmount = len - idx;
+ }
+ startFound = true;
+ startFoundInThisPacket = true;
+ } else if (data[idx] == DleEncoder::ETX_CHAR) {
+ if (startFoundInThisPacket) {
+ size_t readLen = 0;
+ size_t decodedLen = 0;
+ result = decoder.decode(data + startIdx, idx + 1 - startIdx, &readLen, decodedBuf.first,
+ decodedBuf.second, &decodedLen);
+ if (result == HasReturnvaluesIF::RETURN_OK) {
+ ctx.setType(ContextType::PACKET_FOUND);
+ ctx.decodedPacket.first = decodedBuf.first;
+ ctx.decodedPacket.second = decodedLen;
+ this->handler(ctx);
+ } else if (result == DleEncoder::STREAM_TOO_SHORT) {
+ ErrorInfo info;
+ info.res = result;
+ prepareErrorContext(ErrorTypes::DECODING_BUF_TOO_SMALL, info);
+ handler(ctx);
+ } else {
+ ErrorInfo info;
+ info.res = result;
+ prepareErrorContext(ErrorTypes::DECODING_BUF_TOO_SMALL, info);
+ handler(ctx);
+ }
+ decodeRingBuf.clear();
+ if ((idx + 1) < len) {
+ copyIntoRingBufFromHere = idx + 1;
+ copyAmount = len - idx - 1;
+ } else {
+ copyAmount = 0;
+ }
+ } else if (startFound) {
+ // ETX found but STX was found in another mini packet. Reconstruct the full packet
+ // to decode it
+ result = decodeRingBuf.writeData(data, idx + 1);
+ if (result != HasReturnvaluesIF::RETURN_OK) {
+ ErrorInfo info;
+ info.res = result;
+ prepareErrorContext(ErrorTypes::RING_BUF_ERROR, info);
+ handler(ctx);
+ }
+ size_t fullEncodedLen = decodeRingBuf.getAvailableReadData();
+ if (fullEncodedLen > encodedBuf.second) {
+ ErrorInfo info;
+ info.len = fullEncodedLen;
+ prepareErrorContext(ErrorTypes::ENCODED_BUF_TOO_SMALL, info);
+ handler(ctx);
+ decodeRingBuf.clear();
+ } else {
+ size_t decodedLen = 0;
+ size_t readLen = 0;
+ decodeRingBuf.readData(encodedBuf.first, fullEncodedLen, true);
+ result = decoder.decode(encodedBuf.first, fullEncodedLen, &readLen, decodedBuf.first,
+ decodedBuf.second, &decodedLen);
+ if (result == HasReturnvaluesIF::RETURN_OK) {
+ if (this->handler != nullptr) {
+ ctx.setType(ContextType::PACKET_FOUND);
+ ctx.decodedPacket.first = decodedBuf.first;
+ ctx.decodedPacket.second = decodedLen;
+ this->handler(ctx);
+ }
+ } else if (result == DleEncoder::STREAM_TOO_SHORT) {
+ ErrorInfo info;
+ info.res = result;
+ prepareErrorContext(ErrorTypes::DECODING_BUF_TOO_SMALL, info);
+ handler(ctx);
+ } else {
+ ErrorInfo info;
+ info.res = result;
+ prepareErrorContext(ErrorTypes::DECODE_ERROR, info);
+ handler(ctx);
+ }
+ decodeRingBuf.clear();
+ startFound = false;
+ startFoundInThisPacket = false;
+ if ((idx + 1) < len) {
+ copyIntoRingBufFromHere = idx + 1;
+ copyAmount = len - idx - 1;
+ } else {
+ copyAmount = 0;
+ }
+ }
+ } else {
+ // End data without preceeding STX
+ ErrorInfo info;
+ info.len = idx + 1;
+ prepareErrorContext(ErrorTypes::CONSECUTIVE_ETX_CHARS, info);
+ handler(ctx);
+ decodeRingBuf.clear();
+ if ((idx + 1) < len) {
+ copyIntoRingBufFromHere = idx + 1;
+ copyAmount = len - idx - 1;
+ } else {
+ copyAmount = 0;
+ }
+ }
+ startFoundInThisPacket = false;
+ startFound = false;
+ }
+ }
+ if (copyAmount > 0) {
+ result = decodeRingBuf.writeData(data + copyIntoRingBufFromHere, copyAmount);
+ if (result != HasReturnvaluesIF::RETURN_OK) {
+ ErrorInfo info;
+ info.res = result;
+ prepareErrorContext(ErrorTypes::RING_BUF_ERROR, info);
+ handler(ctx);
+ }
+ }
+ return RETURN_OK;
+}
+
+void DleParser::defaultFoundPacketHandler(uint8_t* packet, size_t len, void* args) {
+#if FSFW_VERBOSE_LEVEL >= 1
+#if FSFW_CPP_OSTREAM_ENABLED == 1
+ sif::info << "DleParserBase::handleFoundPacket: Detected DLE packet with " << len << " bytes"
+ << std::endl;
+#else
+ sif::printInfo("DleParserBase::handleFoundPacket: Detected DLE packet with %d bytes\n", len);
+#endif
+#endif
+}
+
+void DleParser::defaultErrorHandler(ErrorTypes err, ErrorInfo ctx) {
+ switch (err) {
+ case (ErrorTypes::NONE): {
+ errorPrinter("No error");
+ break;
+ }
+ case (ErrorTypes::DECODE_ERROR): {
+ errorPrinter("Decode Error");
+ break;
+ }
+ case (ErrorTypes::RING_BUF_ERROR): {
+ errorPrinter("Ring Buffer Error");
+ break;
+ }
+ case (ErrorTypes::ENCODED_BUF_TOO_SMALL):
+ case (ErrorTypes::DECODING_BUF_TOO_SMALL): {
+ char opt[64];
+ snprintf(opt, sizeof(opt), ": Too small for packet with length %zu", ctx.len);
+ if (err == ErrorTypes::ENCODED_BUF_TOO_SMALL) {
+ errorPrinter("Encoded buf too small", opt);
+ } else {
+ errorPrinter("Decoding buf too small", opt);
+ }
+ break;
+ }
+ case (ErrorTypes::CONSECUTIVE_STX_CHARS): {
+ errorPrinter("Consecutive STX chars detected");
+ break;
+ }
+ case (ErrorTypes::CONSECUTIVE_ETX_CHARS): {
+ errorPrinter("Consecutive ETX chars detected");
+ break;
+ }
+ }
+}
+
+void DleParser::errorPrinter(const char* str, const char* opt) {
+ if (opt == nullptr) {
+ opt = "";
+ }
+#if FSFW_VERBOSE_LEVEL >= 1
+#if FSFW_CPP_OSTREAM_ENABLED == 1
+ sif::info << "DleParserBase::handleParseError: " << str << opt << std::endl;
+#else
+ sif::printInfo("DleParserBase::handleParseError: %s%s\n", str, opt);
+#endif
+#endif
+}
+
+void DleParser::prepareErrorContext(ErrorTypes err, ErrorInfo info) {
+ ctx.setType(ContextType::ERROR);
+ ctx.error.first = err;
+ ctx.error.second = info;
+}
+
+void DleParser::reset() {
+ startFound = false;
+ decodeRingBuf.clear();
+}
diff --git a/src/fsfw/globalfunctions/DleParser.h b/src/fsfw/globalfunctions/DleParser.h
new file mode 100644
index 00000000..e8ee61d9
--- /dev/null
+++ b/src/fsfw/globalfunctions/DleParser.h
@@ -0,0 +1,124 @@
+#pragma once
+
+#include
+#include
+#include
+
+#include
+#include
+
+/**
+ * @brief This base helper class can be used to extract DLE encoded packets from a data stream
+ * @details
+ * The core API of the parser takes received packets which can contains DLE packets. The parser
+ * can deal with DLE packets split across multiple packets. It does so by using a dedicated
+ * decoding ring buffer. The user can process received packets and detect errors by
+ * overriding two provided virtual methods. This also allows detecting multiple DLE packets
+ * inside one passed packet.
+ */
+class DleParser : public HasReturnvaluesIF {
+ public:
+ using BufPair = std::pair;
+
+ enum class ContextType { PACKET_FOUND, ERROR };
+
+ enum class ErrorTypes {
+ NONE,
+ ENCODED_BUF_TOO_SMALL,
+ DECODING_BUF_TOO_SMALL,
+ DECODE_ERROR,
+ RING_BUF_ERROR,
+ CONSECUTIVE_STX_CHARS,
+ CONSECUTIVE_ETX_CHARS
+ };
+
+ union ErrorInfo {
+ size_t len;
+ ReturnValue_t res;
+ };
+
+ using ErrorPair = std::pair;
+
+ struct Context {
+ public:
+ Context(void* args) : userArgs(args) { setType(ContextType::PACKET_FOUND); }
+
+ void setType(ContextType type) {
+ if (type == ContextType::PACKET_FOUND) {
+ error.first = ErrorTypes::NONE;
+ error.second.len = 0;
+ } else {
+ decodedPacket.first = nullptr;
+ decodedPacket.second = 0;
+ }
+ }
+
+ ContextType getType() const { return type; }
+
+ BufPair decodedPacket = {};
+ ErrorPair error;
+ void* userArgs;
+
+ private:
+ ContextType type;
+ };
+
+ using UserHandler = void (*)(const Context& ctx);
+
+ /**
+ * Base class constructor
+ * @param decodeRingBuf Ring buffer used to store multiple packets to allow detecting DLE packets
+ * split across multiple packets
+ * @param decoder Decoder instance
+ * @param encodedBuf Buffer used to store encoded packets. It has to be large enough to hold
+ * the largest expected encoded DLE packet size
+ * @param decodedBuf Buffer used to store decoded packets. It has to be large enough to hold the
+ * largest expected decoded DLE packet size
+ * @param handler Function which will be called on a found packet
+ * @param args Arbitrary user argument
+ */
+ DleParser(SimpleRingBuffer& decodeRingBuf, DleEncoder& decoder, BufPair encodedBuf,
+ BufPair decodedBuf, UserHandler handler, void* args);
+
+ /**
+ * This function allows to pass new data into the parser. It then scans for DLE packets
+ * automatically and inserts (part of) the packet into a ring buffer if necessary.
+ * @param data
+ * @param len
+ * @return
+ */
+ ReturnValue_t passData(uint8_t* data, size_t len);
+
+ /**
+ * Example found packet handler
+ * function call
+ * @param packet Decoded packet
+ * @param len Length of detected packet
+ */
+ void defaultFoundPacketHandler(uint8_t* packet, size_t len, void* args);
+ /**
+ * Will be called if an error occured in the #passData call
+ * @param err
+ * @param ctx Context information depending on the error type
+ * - For buffer length errors, will be set to the detected packet length which is too large
+ * - For decode or ring buffer errors, will be set to the result returned from the failed call
+ */
+ static void defaultErrorHandler(ErrorTypes err, ErrorInfo ctx);
+
+ static void errorPrinter(const char* str, const char* opt = nullptr);
+
+ void prepareErrorContext(ErrorTypes err, ErrorInfo ctx);
+ /**
+ * Resets the parser by resetting the internal states and clearing the decoding ring buffer
+ */
+ void reset();
+
+ private:
+ SimpleRingBuffer& decodeRingBuf;
+ DleEncoder& decoder;
+ BufPair encodedBuf;
+ BufPair decodedBuf;
+ UserHandler handler = nullptr;
+ Context ctx;
+ bool startFound = false;
+};
diff --git a/src/fsfw/health/HasHealthIF.h b/src/fsfw/health/HasHealthIF.h
index 41abeef3..9b5ea6d2 100644
--- a/src/fsfw/health/HasHealthIF.h
+++ b/src/fsfw/health/HasHealthIF.h
@@ -16,26 +16,27 @@ class HasHealthIF {
};
static const uint8_t INTERFACE_ID = CLASS_ID::HAS_HEALTH_IF;
- static const ReturnValue_t OBJECT_NOT_HEALTHY = MAKE_RETURN_CODE(1);
- static const ReturnValue_t INVALID_HEALTH_STATE = MAKE_RETURN_CODE(2);
+ static constexpr ReturnValue_t OBJECT_NOT_HEALTHY =
+ HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 1);
+ static constexpr ReturnValue_t INVALID_HEALTH_STATE =
+ HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 2);
+ static constexpr ReturnValue_t IS_EXTERNALLY_CONTROLLED =
+ HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 3);
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::SYSTEM_MANAGER_1;
+ //! P1: New Health, P2: Old Health
static const Event HEALTH_INFO = MAKE_EVENT(6, severity::INFO);
static const Event CHILD_CHANGED_HEALTH = MAKE_EVENT(7, severity::INFO);
static const Event CHILD_PROBLEMS = MAKE_EVENT(8, severity::LOW);
- static const Event OVERWRITING_HEALTH =
- MAKE_EVENT(9, severity::LOW); //!< Assembly overwrites health information of children to keep
- //!< satellite alive.
- static const Event TRYING_RECOVERY =
- MAKE_EVENT(10, severity::MEDIUM); //!< Someone starts a recovery of a component (typically
- //!< power-cycle). No parameters.
- static const Event RECOVERY_STEP =
- MAKE_EVENT(11, severity::MEDIUM); //!< Recovery is ongoing. Comes twice during recovery. P1:
- //!< 0 for the first, 1 for the second event. P2: 0
- static const Event RECOVERY_DONE = MAKE_EVENT(
- 12,
- severity::MEDIUM); //!< Recovery was completed. Not necessarily successful. No parameters.
-
+ //! Assembly overwrites health information of children to keep satellite alive.
+ static const Event OVERWRITING_HEALTH = MAKE_EVENT(9, severity::LOW);
+ //! Someone starts a recovery of a component (typically power-cycle). No parameters.
+ static const Event TRYING_RECOVERY = MAKE_EVENT(10, severity::MEDIUM);
+ //! Recovery is ongoing. Comes twice during recovery.
+ //! P1: 0 for the first, 1 for the second event. P2: 0
+ static const Event RECOVERY_STEP = MAKE_EVENT(11, severity::MEDIUM);
+ //! Recovery was completed. Not necessarily successful. No parameters.
+ static const Event RECOVERY_DONE = MAKE_EVENT(12, severity::MEDIUM);
virtual ~HasHealthIF() {}
virtual MessageQueueId_t getCommandQueue() const = 0;
diff --git a/src/fsfw/internalerror/InternalErrorReporter.cpp b/src/fsfw/internalerror/InternalErrorReporter.cpp
index fa16ec3f..a3f9645b 100644
--- a/src/fsfw/internalerror/InternalErrorReporter.cpp
+++ b/src/fsfw/internalerror/InternalErrorReporter.cpp
@@ -7,11 +7,13 @@
InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId, uint32_t messageQueueDepth)
: SystemObject(setObjectId),
- commandQueue(QueueFactory::instance()->createMessageQueue(messageQueueDepth)),
poolManager(this, commandQueue),
internalErrorSid(setObjectId, InternalErrorDataset::ERROR_SET_ID),
internalErrorDataset(this) {
mutex = MutexFactory::instance()->createMutex();
+ auto mqArgs = MqArgs(setObjectId, static_cast(this));
+ commandQueue = QueueFactory::instance()->createMessageQueue(
+ messageQueueDepth, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
}
InternalErrorReporter::~InternalErrorReporter() { MutexFactory::instance()->deleteMutex(mutex); }
@@ -36,15 +38,14 @@ ReturnValue_t InternalErrorReporter::performOperation(uint8_t opCode) {
if ((newQueueHits > 0) or (newTmHits > 0) or (newStoreHits > 0)) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "InternalErrorReporter::performOperation: Errors "
- << "occured!" << std::endl;
- sif::debug << "Queue errors: " << newQueueHits << std::endl;
- sif::debug << "TM errors: " << newTmHits << std::endl;
- sif::debug << "Store errors: " << newStoreHits << std::endl;
+ << "occured: Queue | TM | Store : " << newQueueHits << " | " << newTmHits << " | "
+ << newStoreHits << std::endl;
#else
- sif::printDebug("InternalErrorReporter::performOperation: Errors occured!\n");
- sif::printDebug("Queue errors: %lu\n", static_cast(newQueueHits));
- sif::printDebug("TM errors: %lu\n", static_cast(newTmHits));
- sif::printDebug("Store errors: %lu\n", static_cast(newStoreHits));
+ sif::printDebug(
+ "InternalErrorReporter::performOperation: Errors occured: Queue | TM | Store: %lu | %lu "
+ "| %lu\n",
+ static_cast(newQueueHits), static_cast(newTmHits),
+ static_cast(newStoreHits));
#endif
}
}
diff --git a/src/fsfw/ipc/CommandMessageIF.h b/src/fsfw/ipc/CommandMessageIF.h
index aea08203..3c31a184 100644
--- a/src/fsfw/ipc/CommandMessageIF.h
+++ b/src/fsfw/ipc/CommandMessageIF.h
@@ -34,7 +34,7 @@ class CommandMessageIF {
static const Command_t CMD_NONE = MAKE_COMMAND_ID(0);
static const Command_t REPLY_COMMAND_OK = MAKE_COMMAND_ID(1);
//! Reply indicating that the current command was rejected,
- //! par1 should contain the error code
+ //! Parameter 1 should contain the error code
static const Command_t REPLY_REJECTED = MAKE_COMMAND_ID(2);
virtual ~CommandMessageIF(){};
diff --git a/src/fsfw/modes/HasModesIF.h b/src/fsfw/modes/HasModesIF.h
index 0ebe77d8..57c4fb66 100644
--- a/src/fsfw/modes/HasModesIF.h
+++ b/src/fsfw/modes/HasModesIF.h
@@ -19,32 +19,33 @@ class HasModesIF {
static const ReturnValue_t INVALID_SUBMODE = MAKE_RETURN_CODE(0x04);
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::SYSTEM_MANAGER;
- static const Event CHANGING_MODE =
- MAKE_EVENT(0, severity::INFO); //!< An object announces changing the mode. p1: target mode.
- //!< p2: target submode
- static const Event MODE_INFO = MAKE_EVENT(
- 1,
- severity::INFO); //!< An Object announces its mode; parameter1 is mode, parameter2 is submode
+ //! An object announces changing the mode. p1: target mode. p2: target submode
+ static const Event CHANGING_MODE = MAKE_EVENT(0, severity::INFO);
+ //! An Object announces its mode; parameter1 is mode, parameter2 is submode
+ static const Event MODE_INFO = MAKE_EVENT(1, severity::INFO);
static const Event FALLBACK_FAILED = MAKE_EVENT(2, severity::HIGH);
static const Event MODE_TRANSITION_FAILED = MAKE_EVENT(3, severity::LOW);
static const Event CANT_KEEP_MODE = MAKE_EVENT(4, severity::HIGH);
- static const Event OBJECT_IN_INVALID_MODE =
- MAKE_EVENT(5, severity::LOW); //!< Indicates a bug or configuration failure: Object is in a
- //!< mode it should never be in.
- static const Event FORCING_MODE = MAKE_EVENT(
- 6, severity::MEDIUM); //!< The mode is changed, but for some reason, the change is forced,
- //!< i.e. EXTERNAL_CONTROL ignored. p1: target mode. p2: target submode
- static const Event MODE_CMD_REJECTED =
- MAKE_EVENT(7, severity::LOW); //!< A mode command was rejected by the called object. Par1:
- //!< called object id, Par2: return code.
+ //! Indicates a bug or configuration failure: Object is in a mode it should never be in.
+ static const Event OBJECT_IN_INVALID_MODE = MAKE_EVENT(5, severity::LOW);
+ //! The mode is changed, but for some reason, the change is forced, i.e. EXTERNAL_CONTROL ignored.
+ //! p1: target mode. p2: target submode
+ static const Event FORCING_MODE = MAKE_EVENT(6, severity::MEDIUM);
+ //! A mode command was rejected by the called object. Par1: called object id, Par2: return code.
+ static const Event MODE_CMD_REJECTED = MAKE_EVENT(7, severity::LOW);
- static const Mode_t MODE_ON =
- 1; //!< The device is powered and ready to perform operations. In this mode, no commands are
- //!< sent by the device handler itself, but direct commands van be commanded and will be
- //!< interpreted
- static const Mode_t MODE_OFF = 0; //!< The device is powered off. The only command accepted in
- //!< this mode is a mode change to on.
- static const Submode_t SUBMODE_NONE = 0; //!< To avoid checks against magic number "0".
+ //! The device is powered and ready to perform operations. In this mode, no commands are
+ //! sent by the device handler itself, but direct commands van be commanded and will be
+ //! interpreted
+ static constexpr Mode_t MODE_ON = 1;
+ //! The device is powered off. The only command accepted in this mode is a mode change to on.
+ static constexpr Mode_t MODE_OFF = 0;
+
+ static constexpr Mode_t MODE_INVALID = -1;
+ static constexpr Mode_t MODE_UNDEFINED = -2;
+
+ //! To avoid checks against magic number "0".
+ static const Submode_t SUBMODE_NONE = 0;
virtual ~HasModesIF() {}
virtual MessageQueueId_t getCommandQueue() const = 0;
diff --git a/src/fsfw/objectmanager/ObjectManager.cpp b/src/fsfw/objectmanager/ObjectManager.cpp
index 2017938a..39fef5b5 100644
--- a/src/fsfw/objectmanager/ObjectManager.cpp
+++ b/src/fsfw/objectmanager/ObjectManager.cpp
@@ -95,13 +95,16 @@ void ObjectManager::initialize() {
for (auto const& it : objectList) {
result = it.second->initialize();
if (result != RETURN_OK) {
+#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
- object_id_t var = it.first;
sif::error << "ObjectManager::initialize: Object 0x" << std::hex << std::setw(8)
- << std::setfill('0') << var
- << " failed to "
- "initialize with code 0x"
- << result << std::dec << std::setfill(' ') << std::endl;
+ << std::setfill('0') << it.first << " failed to initialize with code 0x" << result
+ << std::dec << std::setfill(' ') << std::endl;
+#else
+ sif::printError(
+ "ObjectManager::initialize: Object 0x%08x failed to initialize with code 0x%04x\n", var,
+ it.first);
+#endif
#endif
errorCount++;
}
diff --git a/src/fsfw/osal/CMakeLists.txt b/src/fsfw/osal/CMakeLists.txt
index 50fd6102..d0aea96a 100644
--- a/src/fsfw/osal/CMakeLists.txt
+++ b/src/fsfw/osal/CMakeLists.txt
@@ -16,7 +16,9 @@ elseif(FSFW_OSAL MATCHES "host")
else()
- message(WARNING "The OS_FSFW variable was not set. Assuming host OS..")
+ message(
+ WARNING
+ "${MSG_PREFIX} The FSFW_OSAL variable was not set. Assuming host OS..")
# Not set. Assumuing this is a host build, try to determine host OS
if(WIN32)
add_subdirectory(host)
diff --git a/src/fsfw/parameters/HasParametersIF.h b/src/fsfw/parameters/HasParametersIF.h
index 48557b4a..e95b69ab 100644
--- a/src/fsfw/parameters/HasParametersIF.h
+++ b/src/fsfw/parameters/HasParametersIF.h
@@ -66,7 +66,7 @@ class HasParametersIF {
* @param newValues
* @param startAtIndex Linear index, runs left to right, top to bottom for
* matrix indexes.
- * @return
+ * @return RETURN_OK if parameter is valid and a set function of the parameter wrapper was called.
*/
virtual ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueIdentifier,
ParameterWrapper *parameterWrapper,
diff --git a/src/fsfw/parameters/ParameterWrapper.cpp b/src/fsfw/parameters/ParameterWrapper.cpp
index 27552290..e772f1b6 100644
--- a/src/fsfw/parameters/ParameterWrapper.cpp
+++ b/src/fsfw/parameters/ParameterWrapper.cpp
@@ -211,9 +211,13 @@ ReturnValue_t ParameterWrapper::copyFrom(const ParameterWrapper *from,
if (data == nullptr) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
- sif::warning << "ParameterWrapper::copyFrom: Called on read-only variable!" << std::endl;
+ sif::warning << "ParameterWrapper::copyFrom: Called on read-only variable or "
+ "data pointer not set"
+ << std::endl;
#else
- sif::printWarning("ParameterWrapper::copyFrom: Called on read-only variable!\n");
+ sif::printWarning(
+ "ParameterWrapper::copyFrom: Called on read-only variable "
+ "or data pointer not set\n");
#endif
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
return READONLY;
@@ -222,9 +226,9 @@ ReturnValue_t ParameterWrapper::copyFrom(const ParameterWrapper *from,
if (from->readonlyData == nullptr) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
- sif::warning << "ParameterWrapper::copyFrom: Source not set!" << std::endl;
+ sif::warning << "ParameterWrapper::copyFrom: Source not set" << std::endl;
#else
- sif::printWarning("ParameterWrapper::copyFrom: Source not set!\n");
+ sif::printWarning("ParameterWrapper::copyFrom: Source not set\n");
#endif
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
return SOURCE_NOT_SET;
@@ -233,9 +237,9 @@ ReturnValue_t ParameterWrapper::copyFrom(const ParameterWrapper *from,
if (type != from->type) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
- sif::warning << "ParameterWrapper::copyFrom: Datatype missmatch!" << std::endl;
+ sif::warning << "ParameterWrapper::copyFrom: Datatype missmatch" << std::endl;
#else
- sif::printWarning("ParameterWrapper::copyFrom: Datatype missmatch!\n");
+ sif::printWarning("ParameterWrapper::copyFrom: Datatype missmatch\n");
#endif
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
return DATATYPE_MISSMATCH;
@@ -245,9 +249,9 @@ ReturnValue_t ParameterWrapper::copyFrom(const ParameterWrapper *from,
if (rows == 0 or columns == 0) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
- sif::warning << "ParameterWrapper::copyFrom: Columns or rows zero!" << std::endl;
+ sif::warning << "ParameterWrapper::copyFrom: Columns or rows zero" << std::endl;
#else
- sif::printWarning("ParameterWrapper::copyFrom: Columns or rows zero!\n");
+ sif::printWarning("ParameterWrapper::copyFrom: Columns or rows zero\n");
#endif
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
return COLUMN_OR_ROWS_ZERO;
diff --git a/src/fsfw/power/PowerSwitchIF.h b/src/fsfw/power/PowerSwitchIF.h
index bc883fbc..c2727158 100644
--- a/src/fsfw/power/PowerSwitchIF.h
+++ b/src/fsfw/power/PowerSwitchIF.h
@@ -29,9 +29,9 @@ class PowerSwitchIF : public HasReturnvaluesIF {
static const ReturnValue_t FUSE_ON = MAKE_RETURN_CODE(3);
static const ReturnValue_t FUSE_OFF = MAKE_RETURN_CODE(4);
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PCDU_2;
- static const Event SWITCH_WENT_OFF = MAKE_EVENT(
- 0, severity::LOW); //!< Someone detected that a switch went off which shouldn't. Severity:
- //!< Low, Parameter1: switchId1, Parameter2: switchId2
+ //!< Someone detected that a switch went off which shouldn't. Severity:
+ //!< Low, Parameter1: switchId1, Parameter2: switchId2
+ static const Event SWITCH_WENT_OFF = MAKE_EVENT(0, severity::LOW);
/**
* send a direct command to the Power Unit to enable/disable the specified switch.
*
diff --git a/src/fsfw/pus/Service11TelecommandScheduling.tpp b/src/fsfw/pus/Service11TelecommandScheduling.tpp
index 968a59ff..af121c5c 100644
--- a/src/fsfw/pus/Service11TelecommandScheduling.tpp
+++ b/src/fsfw/pus/Service11TelecommandScheduling.tpp
@@ -78,7 +78,7 @@ inline ReturnValue_t Service11TelecommandScheduling::performService
// NOTE: The iterator is increased in the loop here. Increasing the iterator as for-loop arg
// does not work in this case as we are deleting the current element here.
for (auto it = telecommandMap.begin(); it != telecommandMap.end();) {
- if (it->first <= tNow.tv_sec) {
+ if (it->first <= static_cast(tNow.tv_sec)) {
if (schedulingEnabled) {
// release tc
TmTcMessage releaseMsg(it->second.storeAddr);
diff --git a/src/fsfw/pus/Service1TelecommandVerification.cpp b/src/fsfw/pus/Service1TelecommandVerification.cpp
index 13d6a1c4..772137dd 100644
--- a/src/fsfw/pus/Service1TelecommandVerification.cpp
+++ b/src/fsfw/pus/Service1TelecommandVerification.cpp
@@ -16,7 +16,9 @@ Service1TelecommandVerification::Service1TelecommandVerification(object_id_t obj
apid(apid),
serviceId(serviceId),
targetDestination(targetDestination) {
- tmQueue = QueueFactory::instance()->createMessageQueue(messageQueueDepth);
+ auto mqArgs = MqArgs(objectId, static_cast(this));
+ tmQueue = QueueFactory::instance()->createMessageQueue(
+ messageQueueDepth, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
}
Service1TelecommandVerification::~Service1TelecommandVerification() {
diff --git a/src/fsfw/pus/Service3Housekeeping.cpp b/src/fsfw/pus/Service3Housekeeping.cpp
index 07574783..97addd7c 100644
--- a/src/fsfw/pus/Service3Housekeeping.cpp
+++ b/src/fsfw/pus/Service3Housekeeping.cpp
@@ -208,17 +208,17 @@ ReturnValue_t Service3Housekeeping::handleReply(const CommandMessage* reply,
ReturnValue_t error = HasReturnvaluesIF::RETURN_FAILED;
HousekeepingMessage::getHkRequestFailureReply(reply, &error);
failureParameter2 = error;
- return CommandingServiceBase::EXECUTION_COMPLETE;
+ return RETURN_FAILED;
}
default:
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "Service3Housekeeping::handleReply: Invalid reply with "
- << "reply command " << command << "!" << std::endl;
+ << "reply command " << command << std::endl;
#else
sif::printWarning(
"Service3Housekeeping::handleReply: Invalid reply with "
- "reply command %hu!\n",
+ "reply command %hu\n",
command);
#endif
return CommandingServiceBase::INVALID_REPLY;
@@ -248,19 +248,25 @@ void Service3Housekeeping::handleUnrequestedReply(CommandMessage* reply) {
case (HousekeepingMessage::HK_REQUEST_FAILURE): {
break;
}
+ case (CommandMessage::REPLY_REJECTED): {
+ sif::warning << "Service3Housekeeping::handleUnrequestedReply: Unexpected reply "
+ "rejected with error code"
+ << reply->getParameter() << std::endl;
+ break;
+ }
default: {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "Service3Housekeeping::handleUnrequestedReply: Invalid reply with reply "
"command "
- << command << "!" << std::endl;
+ << command << "" << std::endl;
#else
sif::printWarning(
"Service3Housekeeping::handleUnrequestedReply: Invalid reply with "
- "reply command %hu!\n",
+ "reply command %hu\n",
command);
#endif
- return;
+ break;
}
}
@@ -275,6 +281,7 @@ void Service3Housekeeping::handleUnrequestedReply(CommandMessage* reply) {
"Could not generate reply!\n");
#endif
}
+ CommandingServiceBase::handleUnrequestedReply(reply);
}
MessageQueueId_t Service3Housekeeping::getHkQueue() const { return commandQueue->getId(); }
diff --git a/src/fsfw/pus/Service5EventReporting.cpp b/src/fsfw/pus/Service5EventReporting.cpp
index 987217dc..fd08970c 100644
--- a/src/fsfw/pus/Service5EventReporting.cpp
+++ b/src/fsfw/pus/Service5EventReporting.cpp
@@ -12,7 +12,9 @@ Service5EventReporting::Service5EventReporting(object_id_t objectId, uint16_t ap
uint32_t messageQueueDepth)
: PusServiceBase(objectId, apid, serviceId),
maxNumberReportsPerCycle(maxNumberReportsPerCycle) {
- eventQueue = QueueFactory::instance()->createMessageQueue(messageQueueDepth);
+ auto mqArgs = MqArgs(objectId, static_cast(this));
+ eventQueue = QueueFactory::instance()->createMessageQueue(
+ messageQueueDepth, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
}
Service5EventReporting::~Service5EventReporting() {
@@ -36,9 +38,6 @@ ReturnValue_t Service5EventReporting::performService() {
}
}
}
-#if FSFW_CPP_OSTREAM_ENABLED == 1
- sif::warning << "Service5EventReporting::generateEventReport: Too many events" << std::endl;
-#endif
return HasReturnvaluesIF::RETURN_OK;
}
diff --git a/src/fsfw/pus/Service5EventReporting.h b/src/fsfw/pus/Service5EventReporting.h
index 74264130..c1032d18 100644
--- a/src/fsfw/pus/Service5EventReporting.h
+++ b/src/fsfw/pus/Service5EventReporting.h
@@ -41,7 +41,7 @@
class Service5EventReporting : public PusServiceBase {
public:
Service5EventReporting(object_id_t objectId, uint16_t apid, uint8_t serviceId,
- size_t maxNumberReportsPerCycle = 10, uint32_t messageQueueDepth = 10);
+ size_t maxNumberReportsPerCycle, uint32_t messageQueueDepth);
virtual ~Service5EventReporting();
/***
diff --git a/src/fsfw/pus/Service9TimeManagement.h b/src/fsfw/pus/Service9TimeManagement.h
index 9369e207..1bea2f51 100644
--- a/src/fsfw/pus/Service9TimeManagement.h
+++ b/src/fsfw/pus/Service9TimeManagement.h
@@ -6,10 +6,10 @@
class Service9TimeManagement : public PusServiceBase {
public:
static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PUS_SERVICE_9;
- static constexpr Event CLOCK_SET =
- MAKE_EVENT(0, severity::INFO); //!< Clock has been set. P1: New Uptime. P2: Old Uptime
- static constexpr Event CLOCK_SET_FAILURE =
- MAKE_EVENT(1, severity::LOW); //!< Clock could not be set. P1: Returncode.
+ //!< Clock has been set. P1: New Uptime. P2: Old Uptime
+ static constexpr Event CLOCK_SET = MAKE_EVENT(0, severity::INFO);
+ //!< Clock could not be set. P1: Returncode.
+ static constexpr Event CLOCK_SET_FAILURE = MAKE_EVENT(1, severity::LOW);
static constexpr uint8_t CLASS_ID = CLASS_ID::PUS_SERVICE_9;
diff --git a/src/fsfw/subsystem/Subsystem.h b/src/fsfw/subsystem/Subsystem.h
index 855c8f7a..f4e73117 100644
--- a/src/fsfw/subsystem/Subsystem.h
+++ b/src/fsfw/subsystem/Subsystem.h
@@ -33,8 +33,12 @@ struct SequenceEntry : public TableSequenceBase {
};
/**
- * @brief TODO: documentation missing
+ * @brief This class extends the SubsystemBase to perform the management of mode tables
+ * and mode sequences
* @details
+ * This class is able to use mode tables and sequences to command all its children into the
+ * right mode. Fallback sequences can be used to handle failed transitions or have a fallback
+ * in case a component can't keep its current mode.
*/
class Subsystem : public SubsystemBase, public HasModeSequenceIF {
public:
diff --git a/src/fsfw/subsystem/SubsystemBase.cpp b/src/fsfw/subsystem/SubsystemBase.cpp
index 104db3c3..aec96434 100644
--- a/src/fsfw/subsystem/SubsystemBase.cpp
+++ b/src/fsfw/subsystem/SubsystemBase.cpp
@@ -8,11 +8,13 @@ SubsystemBase::SubsystemBase(object_id_t setObjectId, object_id_t parent, Mode_t
uint16_t commandQueueDepth)
: SystemObject(setObjectId),
mode(initialMode),
- commandQueue(QueueFactory::instance()->createMessageQueue(commandQueueDepth,
- CommandMessage::MAX_MESSAGE_SIZE)),
healthHelper(this, setObjectId),
modeHelper(this),
- parentId(parent) {}
+ parentId(parent) {
+ auto mqArgs = MqArgs(setObjectId, static_cast(this));
+ commandQueue = QueueFactory::instance()->createMessageQueue(
+ commandQueueDepth, CommandMessage::MAX_MESSAGE_SIZE, &mqArgs);
+}
SubsystemBase::~SubsystemBase() { QueueFactory::instance()->deleteMessageQueue(commandQueue); }
@@ -31,8 +33,9 @@ ReturnValue_t SubsystemBase::registerChild(object_id_t objectId) {
info.mode = MODE_OFF;
}
} else {
+ // intentional to force an initial command during system startup
info.commandQueue = child->getCommandQueue();
- info.mode = -1; // intentional to force an initial command during system startup
+ info.mode = HasModesIF::MODE_UNDEFINED;
}
info.submode = SUBMODE_NONE;
diff --git a/src/fsfw/subsystem/SubsystemBase.h b/src/fsfw/subsystem/SubsystemBase.h
index 52f9891e..bafb7fb1 100644
--- a/src/fsfw/subsystem/SubsystemBase.h
+++ b/src/fsfw/subsystem/SubsystemBase.h
@@ -15,7 +15,14 @@
/**
* @defgroup subsystems Subsystem Objects
- * Contains all Subsystem and Assemblies
+ * All Subsystem and Assemblies can derive from this class. It contains helper classes to
+ * perform mode and health handling, which allows OBSW developers to build a mode tree for
+ * the whole satellite.
+ *
+ * Aside from setting up a mode tree and being able to executing mode tables, this class does not
+ * provide an implementation on what to do with the features. To build a mode tree, helper classes
+ * like the #AssemblyBase or the #Subsystem class extend and use the functionality of the base
+ * class.
*/
class SubsystemBase : public SystemObject,
public HasModesIF,
@@ -96,6 +103,7 @@ class SubsystemBase : public SystemObject,
Submode_t targetSubmode);
/**
+ * This function takes care of sending all according mode commands specified inside a mode table.
* We need to know the target Submode, as children are able to inherit the submode
* Still, we have a default for all child implementations which do not use submode inheritance
*/
diff --git a/src/fsfw/tcdistribution/TcDistributor.cpp b/src/fsfw/tcdistribution/TcDistributor.cpp
index a650546c..408e736e 100644
--- a/src/fsfw/tcdistribution/TcDistributor.cpp
+++ b/src/fsfw/tcdistribution/TcDistributor.cpp
@@ -5,7 +5,9 @@
#include "fsfw/tmtcservices/TmTcMessage.h"
TcDistributor::TcDistributor(object_id_t objectId) : SystemObject(objectId) {
- tcQueue = QueueFactory::instance()->createMessageQueue(DISTRIBUTER_MAX_PACKETS);
+ auto mqArgs = MqArgs(objectId);
+ tcQueue = QueueFactory::instance()->createMessageQueue(
+ DISTRIBUTER_MAX_PACKETS, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
}
TcDistributor::~TcDistributor() { QueueFactory::instance()->deleteMessageQueue(tcQueue); }
diff --git a/src/fsfw/thermal/AbstractTemperatureSensor.cpp b/src/fsfw/thermal/AbstractTemperatureSensor.cpp
index 68cd3aca..f7b31386 100644
--- a/src/fsfw/thermal/AbstractTemperatureSensor.cpp
+++ b/src/fsfw/thermal/AbstractTemperatureSensor.cpp
@@ -4,14 +4,13 @@
AbstractTemperatureSensor::AbstractTemperatureSensor(object_id_t setObjectid,
ThermalModuleIF *thermalModule)
- : SystemObject(setObjectid),
- commandQueue(NULL),
- healthHelper(this, setObjectid),
- parameterHelper(this) {
- if (thermalModule != NULL) {
+ : SystemObject(setObjectid), healthHelper(this, setObjectid), parameterHelper(this) {
+ if (thermalModule != nullptr) {
thermalModule->registerSensor(this);
}
- commandQueue = QueueFactory::instance()->createMessageQueue();
+ auto mqArgs = MqArgs(setObjectid, static_cast(this));
+ commandQueue = QueueFactory::instance()->createMessageQueue(
+ 3, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
}
AbstractTemperatureSensor::~AbstractTemperatureSensor() {
diff --git a/src/fsfw/thermal/AbstractTemperatureSensor.h b/src/fsfw/thermal/AbstractTemperatureSensor.h
index 0c6493fe..b790b0ca 100644
--- a/src/fsfw/thermal/AbstractTemperatureSensor.h
+++ b/src/fsfw/thermal/AbstractTemperatureSensor.h
@@ -51,7 +51,7 @@ class AbstractTemperatureSensor : public HasHealthIF,
HasHealthIF::HealthState getHealth();
protected:
- MessageQueueIF* commandQueue;
+ MessageQueueIF* commandQueue = nullptr;
HealthHelper healthHelper;
ParameterHelper parameterHelper;
diff --git a/src/fsfw/thermal/Heater.cpp b/src/fsfw/thermal/Heater.cpp
index 4f0f8060..46f5c822 100644
--- a/src/fsfw/thermal/Heater.cpp
+++ b/src/fsfw/thermal/Heater.cpp
@@ -12,7 +12,9 @@ Heater::Heater(uint32_t objectId, uint8_t switch0, uint8_t switch1)
switch1(switch1),
heaterOnCountdown(10800000) /*about two orbits*/,
parameterHelper(this) {
- eventQueue = QueueFactory::instance()->createMessageQueue();
+ auto mqArgs = MqArgs(objectId, static_cast(this));
+ eventQueue = QueueFactory::instance()->createMessageQueue(
+ 3, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
}
Heater::~Heater() { QueueFactory::instance()->deleteMessageQueue(eventQueue); }
diff --git a/src/fsfw/thermal/ThermalComponentIF.h b/src/fsfw/thermal/ThermalComponentIF.h
index 0c50fbad..3a9f3f2d 100644
--- a/src/fsfw/thermal/ThermalComponentIF.h
+++ b/src/fsfw/thermal/ThermalComponentIF.h
@@ -13,9 +13,9 @@ class ThermalComponentIF : public HasParametersIF {
static const Event COMPONENT_TEMP_HIGH = MAKE_EVENT(2, severity::LOW);
static const Event COMPONENT_TEMP_OOL_LOW = MAKE_EVENT(3, severity::LOW);
static const Event COMPONENT_TEMP_OOL_HIGH = MAKE_EVENT(4, severity::LOW);
- static const Event TEMP_NOT_IN_OP_RANGE = MAKE_EVENT(
- 5, severity::LOW); //!< Is thrown when a device should start-up, but the temperature is out
- //!< of OP range. P1: thermalState of the component, P2: 0
+ //!< Is thrown when a device should start-up, but the temperature is out
+ //!< of OP range. P1: thermalState of the component, P2: 0
+ static const Event TEMP_NOT_IN_OP_RANGE = MAKE_EVENT(5, severity::LOW);
static const uint8_t INTERFACE_ID = CLASS_ID::THERMAL_COMPONENT_IF;
static const ReturnValue_t INVALID_TARGET_STATE = MAKE_RETURN_CODE(1);
diff --git a/src/fsfw/timemanager/Countdown.cpp b/src/fsfw/timemanager/Countdown.cpp
index a8ba78cb..334883ae 100644
--- a/src/fsfw/timemanager/Countdown.cpp
+++ b/src/fsfw/timemanager/Countdown.cpp
@@ -1,7 +1,11 @@
#include "fsfw/timemanager/Countdown.h"
-Countdown::Countdown(uint32_t initialTimeout) : timeout(initialTimeout) {
- setTimeout(initialTimeout);
+Countdown::Countdown(uint32_t initialTimeout, bool startImmediately) : timeout(initialTimeout) {
+ if (startImmediately) {
+ setTimeout(initialTimeout);
+ } else {
+ timeout = initialTimeout;
+ }
}
Countdown::~Countdown() {}
diff --git a/src/fsfw/timemanager/Countdown.h b/src/fsfw/timemanager/Countdown.h
index 44be2b1a..26534789 100644
--- a/src/fsfw/timemanager/Countdown.h
+++ b/src/fsfw/timemanager/Countdown.h
@@ -26,8 +26,9 @@ class Countdown {
* Otherwise a call to hasTimedOut might return True.
*
* @param initialTimeout Countdown duration in milliseconds
+ * @param startImmediately Set to false if countdown should not be started immediately
*/
- Countdown(uint32_t initialTimeout = 0);
+ Countdown(uint32_t initialTimeout = 0, bool startImmediately = true);
~Countdown();
/**
* Call to set a new countdown duration.
diff --git a/src/fsfw/tmstorage/TmStoreBackendIF.h b/src/fsfw/tmstorage/TmStoreBackendIF.h
index d9f1a17b..1e08342a 100644
--- a/src/fsfw/tmstorage/TmStoreBackendIF.h
+++ b/src/fsfw/tmstorage/TmStoreBackendIF.h
@@ -33,50 +33,47 @@ class TmStoreBackendIF : public HasParametersIF {
static const ReturnValue_t INVALID_REQUEST = MAKE_RETURN_CODE(15);
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::MEMORY;
- static const Event STORE_SEND_WRITE_FAILED =
- MAKE_EVENT(0, severity::LOW); //!< Initiating sending data to store failed. Low, par1:
- //!< returnCode, par2: integer (debug info)
- static const Event STORE_WRITE_FAILED = MAKE_EVENT(
- 1, severity::LOW); //!< Data was sent, but writing failed. Low, par1: returnCode, par2: 0
- static const Event STORE_SEND_READ_FAILED =
- MAKE_EVENT(2, severity::LOW); //!< Initiating reading data from store failed. Low, par1:
- //!< returnCode, par2: 0
- static const Event STORE_READ_FAILED = MAKE_EVENT(
- 3, severity::LOW); //!< Data was requested, but access failed. Low, par1: returnCode, par2: 0
- static const Event UNEXPECTED_MSG =
- MAKE_EVENT(4, severity::LOW); //!< An unexpected TM packet or data message occurred. Low,
- //!< par1: 0, par2: integer (debug info)
- static const Event STORING_FAILED = MAKE_EVENT(
- 5, severity::LOW); //!< Storing data failed. May simply be a full store. Low, par1:
- //!< returnCode, par2: integer (sequence count of failed packet).
- static const Event TM_DUMP_FAILED =
- MAKE_EVENT(6, severity::LOW); //!< Dumping retrieved data failed. Low, par1: returnCode,
- //!< par2: integer (sequence count of failed packet).
- static const Event STORE_INIT_FAILED =
- MAKE_EVENT(7, severity::LOW); //!< Corrupted init data or read error. Low, par1: returnCode,
- //!< par2: integer (debug info)
- static const Event STORE_INIT_EMPTY = MAKE_EVENT(
- 8, severity::INFO); //!< Store was not initialized. Starts empty. Info, parameters both zero.
- static const Event STORE_CONTENT_CORRUPTED =
- MAKE_EVENT(9, severity::LOW); //!< Data was read out, but it is inconsistent. Low par1:
- //!< Memory address of corruption, par2: integer (debug info)
- static const Event STORE_INITIALIZE =
- MAKE_EVENT(10, severity::INFO); //!< Info event indicating the store will be initialized,
- //!< either at boot or after IOB switch. Info. pars: 0
- static const Event INIT_DONE = MAKE_EVENT(
- 11, severity::INFO); //!< Info event indicating the store was successfully initialized,
- //!< either at boot or after IOB switch. Info. pars: 0
- static const Event DUMP_FINISHED = MAKE_EVENT(
- 12, severity::INFO); //!< Info event indicating that dumping finished successfully. par1:
- //!< Number of dumped packets. par2: APID/SSC (16bits each)
- static const Event DELETION_FINISHED = MAKE_EVENT(
- 13, severity::INFO); //!< Info event indicating that deletion finished successfully. par1:
- //!< Number of deleted packets. par2: APID/SSC (16bits each)
- static const Event DELETION_FAILED = MAKE_EVENT(
- 14,
- severity::LOW); //!< Info event indicating that something went wrong during deletion. pars: 0
- static const Event AUTO_CATALOGS_SENDING_FAILED =
- MAKE_EVENT(15, severity::INFO); //!< Info that the a auto catalog report failed
+ //! Initiating sending data to store failed. Low, par1:
+ //! returnCode, par2: integer (debug info)
+ static const Event STORE_SEND_WRITE_FAILED = MAKE_EVENT(0, severity::LOW);
+ //! Data was sent, but writing failed. Low, par1: returnCode, par2: 0
+ static const Event STORE_WRITE_FAILED = MAKE_EVENT(1, severity::LOW);
+ //! Initiating reading data from store failed. Low, par1: returnCode, par2: 0
+ static const Event STORE_SEND_READ_FAILED = MAKE_EVENT(2, severity::LOW);
+ //! Data was requested, but access failed. Low, par1: returnCode, par2: 0
+ static const Event STORE_READ_FAILED = MAKE_EVENT(3, severity::LOW);
+ //! An unexpected TM packet or data message occurred. Low, par1: 0, par2: integer (debug info)
+ static const Event UNEXPECTED_MSG = MAKE_EVENT(4, severity::LOW);
+ //! Storing data failed. May simply be a full store. Low, par1: returnCode,
+ //! par2: integer (sequence count of failed packet).
+ static const Event STORING_FAILED = MAKE_EVENT(5, severity::LOW);
+ //! Dumping retrieved data failed. Low, par1: returnCode,
+ //! par2: integer (sequence count of failed packet).
+ static const Event TM_DUMP_FAILED = MAKE_EVENT(6, severity::LOW);
+ //! Corrupted init data or read error. Low, par1: returnCode, par2: integer (debug info)
+ //! Store was not initialized. Starts empty. Info, parameters both zero.
+ static const Event STORE_INIT_FAILED = MAKE_EVENT(7, severity::LOW);
+ //! Data was read out, but it is inconsistent. Low par1:
+ //! Memory address of corruption, par2: integer (debug info)
+ static const Event STORE_INIT_EMPTY = MAKE_EVENT(8, severity::INFO);
+
+ static const Event STORE_CONTENT_CORRUPTED = MAKE_EVENT(9, severity::LOW);
+ //! Info event indicating the store will be initialized, either at boot or after IOB switch.
+ //! Info. pars: 0
+ static const Event STORE_INITIALIZE = MAKE_EVENT(10, severity::INFO);
+ //! Info event indicating the store was successfully initialized, either at boot or after
+ //! IOB switch. Info. pars: 0
+ static const Event INIT_DONE = MAKE_EVENT(11, severity::INFO);
+ //! Info event indicating that dumping finished successfully.
+ //! par1: Number of dumped packets. par2: APID/SSC (16bits each)
+ static const Event DUMP_FINISHED = MAKE_EVENT(12, severity::INFO);
+ //! Info event indicating that deletion finished successfully.
+ //! par1:Number of deleted packets. par2: APID/SSC (16bits each)
+ static const Event DELETION_FINISHED = MAKE_EVENT(13, severity::INFO);
+ //! Info event indicating that something went wrong during deletion. pars: 0
+ static const Event DELETION_FAILED = MAKE_EVENT(14, severity::LOW);
+ //! Info that the a auto catalog report failed
+ static const Event AUTO_CATALOGS_SENDING_FAILED = MAKE_EVENT(15, severity::INFO);
virtual ~TmStoreBackendIF() {}
diff --git a/src/fsfw/tmtcpacket/SpacePacket.h b/src/fsfw/tmtcpacket/SpacePacket.h
index 10140db1..dc45576e 100644
--- a/src/fsfw/tmtcpacket/SpacePacket.h
+++ b/src/fsfw/tmtcpacket/SpacePacket.h
@@ -25,7 +25,7 @@ class SpacePacket : public SpacePacketBase {
* @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,
+ SpacePacket(uint16_t packetDataLength = 0, bool isTelecommand = false,
uint16_t apid = APID_IDLE_PACKET, uint16_t sequenceCount = 0);
/**
* The class's default destructor.
diff --git a/src/fsfw/tmtcservices/CommandingServiceBase.cpp b/src/fsfw/tmtcservices/CommandingServiceBase.cpp
index bbdf8d2a..1bbd7fd1 100644
--- a/src/fsfw/tmtcservices/CommandingServiceBase.cpp
+++ b/src/fsfw/tmtcservices/CommandingServiceBase.cpp
@@ -20,8 +20,10 @@ CommandingServiceBase::CommandingServiceBase(object_id_t setObjectId, uint16_t a
service(service),
timeoutSeconds(commandTimeoutSeconds),
commandMap(numberOfParallelCommands) {
- commandQueue = QueueFactory::instance()->createMessageQueue(queueDepth);
- requestQueue = QueueFactory::instance()->createMessageQueue(queueDepth);
+ auto mqArgs = MqArgs(setObjectId, static_cast(this));
+ size_t mqSz = MessageQueueMessage::MAX_MESSAGE_SIZE;
+ commandQueue = QueueFactory::instance()->createMessageQueue(queueDepth, mqSz, &mqArgs);
+ requestQueue = QueueFactory::instance()->createMessageQueue(queueDepth, mqSz, &mqArgs);
}
void CommandingServiceBase::setPacketSource(object_id_t packetSource) {
diff --git a/src/fsfw/tmtcservices/PusServiceBase.cpp b/src/fsfw/tmtcservices/PusServiceBase.cpp
index 3af2b82c..565ac5cd 100644
--- a/src/fsfw/tmtcservices/PusServiceBase.cpp
+++ b/src/fsfw/tmtcservices/PusServiceBase.cpp
@@ -13,7 +13,9 @@ object_id_t PusServiceBase::packetDestination = 0;
PusServiceBase::PusServiceBase(object_id_t setObjectId, uint16_t setApid, uint8_t setServiceId)
: SystemObject(setObjectId), apid(setApid), serviceId(setServiceId) {
- requestQueue = QueueFactory::instance()->createMessageQueue(PUS_SERVICE_MAX_RECEPTION);
+ auto mqArgs = MqArgs(setObjectId, static_cast(this));
+ requestQueue = QueueFactory::instance()->createMessageQueue(
+ PUS_SERVICE_MAX_RECEPTION, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
}
PusServiceBase::~PusServiceBase() { QueueFactory::instance()->deleteMessageQueue(requestQueue); }
diff --git a/src/fsfw/tmtcservices/SourceSequenceCounter.h b/src/fsfw/tmtcservices/SourceSequenceCounter.h
index e981a945..34346726 100644
--- a/src/fsfw/tmtcservices/SourceSequenceCounter.h
+++ b/src/fsfw/tmtcservices/SourceSequenceCounter.h
@@ -5,10 +5,10 @@
class SourceSequenceCounter {
private:
- uint16_t sequenceCount;
+ uint16_t sequenceCount = 0;
public:
- SourceSequenceCounter() : sequenceCount(0) {}
+ SourceSequenceCounter(uint16_t initialSequenceCount = 0) : sequenceCount(initialSequenceCount) {}
void increment() {
sequenceCount = (sequenceCount + 1) % (SpacePacketBase::LIMIT_SEQUENCE_COUNT);
}
@@ -19,6 +19,20 @@ class SourceSequenceCounter {
void reset(uint16_t toValue = 0) {
sequenceCount = toValue % (SpacePacketBase::LIMIT_SEQUENCE_COUNT);
}
+ SourceSequenceCounter& operator++(int) {
+ this->increment();
+ return *this;
+ }
+ SourceSequenceCounter& operator--(int) {
+ this->decrement();
+ return *this;
+ }
+ SourceSequenceCounter& operator=(const uint16_t& newCount) {
+ sequenceCount = newCount;
+ return *this;
+ }
+
+ operator uint16_t() { return this->get(); }
};
#endif /* FSFW_TMTCSERVICES_SOURCESEQUENCECOUNTER_H_ */
diff --git a/src/fsfw/tmtcservices/TmTcBridge.cpp b/src/fsfw/tmtcservices/TmTcBridge.cpp
index 8ea67119..4fa07c14 100644
--- a/src/fsfw/tmtcservices/TmTcBridge.cpp
+++ b/src/fsfw/tmtcservices/TmTcBridge.cpp
@@ -15,7 +15,9 @@ TmTcBridge::TmTcBridge(object_id_t objectId, object_id_t tcDestination, object_i
tcDestination(tcDestination)
{
- tmTcReceptionQueue = QueueFactory::instance()->createMessageQueue(TMTC_RECEPTION_QUEUE_DEPTH);
+ auto mqArgs = MqArgs(objectId, static_cast(this));
+ tmTcReceptionQueue = QueueFactory::instance()->createMessageQueue(
+ TMTC_RECEPTION_QUEUE_DEPTH, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
}
TmTcBridge::~TmTcBridge() { QueueFactory::instance()->deleteMessageQueue(tmTcReceptionQueue); }
@@ -34,7 +36,7 @@ ReturnValue_t TmTcBridge::setNumberOfSentPacketsPerCycle(uint8_t sentPacketsPerC
}
}
-ReturnValue_t TmTcBridge::setMaxNumberOfPacketsStored(uint8_t maxNumberOfPacketsStored) {
+ReturnValue_t TmTcBridge::setMaxNumberOfPacketsStored(unsigned int maxNumberOfPacketsStored) {
if (maxNumberOfPacketsStored <= LIMIT_DOWNLINK_PACKETS_STORED) {
this->maxNumberOfPacketsStored = maxNumberOfPacketsStored;
return RETURN_OK;
@@ -172,15 +174,18 @@ ReturnValue_t TmTcBridge::storeDownlinkData(TmTcMessage* message) {
}
if (tmFifo->full()) {
+ if (warningSwitch) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
- sif::warning << "TmTcBridge::storeDownlinkData: TM downlink max. number "
- "of stored packet IDs reached!"
- << std::endl;
+ sif::warning << "TmTcBridge::storeDownlinkData: TM downlink max. number "
+ "of stored packet IDs reached!"
+ << std::endl;
#else
- sif::printWarning(
- "TmTcBridge::storeDownlinkData: TM downlink max. number "
- "of stored packet IDs reached!\n");
+ sif::printWarning(
+ "TmTcBridge::storeDownlinkData: TM downlink max. number "
+ "of stored packet IDs reached!\n");
#endif
+ warningSwitch = true;
+ }
if (overwriteOld) {
tmFifo->retrieve(&storeId);
tmStore->deleteData(storeId);
diff --git a/src/fsfw/tmtcservices/TmTcBridge.h b/src/fsfw/tmtcservices/TmTcBridge.h
index 237f1f3e..679ab2ef 100644
--- a/src/fsfw/tmtcservices/TmTcBridge.h
+++ b/src/fsfw/tmtcservices/TmTcBridge.h
@@ -18,7 +18,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 = 200;
+ static constexpr unsigned int LIMIT_DOWNLINK_PACKETS_STORED = 1000;
static constexpr uint8_t DEFAULT_STORED_DATA_SENT_PER_CYCLE = 5;
static constexpr uint8_t DEFAULT_DOWNLINK_PACKETS_STORED = 10;
@@ -43,7 +43,7 @@ class TmTcBridge : public AcceptsTelemetryIF,
* @return -@c RETURN_OK if value was set successfully
* -@c RETURN_FAILED otherwise, stored value stays the same
*/
- ReturnValue_t setMaxNumberOfPacketsStored(uint8_t maxNumberOfPacketsStored);
+ ReturnValue_t setMaxNumberOfPacketsStored(unsigned int maxNumberOfPacketsStored);
/**
* This will set up the bridge to overwrite old data in the FIFO.
@@ -72,6 +72,8 @@ class TmTcBridge : public AcceptsTelemetryIF,
virtual uint16_t getIdentifier() override;
virtual MessageQueueId_t getRequestQueue() override;
+ bool warningSwitch = true;
+
protected:
//! Cached for initialize function.
object_id_t tmStoreId = objects::NO_OBJECT;
@@ -150,7 +152,7 @@ class TmTcBridge : public AcceptsTelemetryIF,
*/
DynamicFIFO* tmFifo = nullptr;
uint8_t sentPacketsPerCycle = DEFAULT_STORED_DATA_SENT_PER_CYCLE;
- uint8_t maxNumberOfPacketsStored = DEFAULT_DOWNLINK_PACKETS_STORED;
+ unsigned int maxNumberOfPacketsStored = DEFAULT_DOWNLINK_PACKETS_STORED;
};
#endif /* FSFW_TMTCSERVICES_TMTCBRIDGE_H_ */
diff --git a/tests/src/fsfw_tests/unit/hal/testCommandExecutor.cpp b/tests/src/fsfw_tests/unit/hal/testCommandExecutor.cpp
index 09d31280..6af101dd 100644
--- a/tests/src/fsfw_tests/unit/hal/testCommandExecutor.cpp
+++ b/tests/src/fsfw_tests/unit/hal/testCommandExecutor.cpp
@@ -78,7 +78,7 @@ TEST_CASE("Command Executor", "[cmd-exec]") {
REQUIRE(result != CommandExecutor::COMMAND_ERROR);
// This ensures that the tests do not block indefinitely
usleep(500);
- REQUIRE(limitIdx < 500);
+ REQUIRE(limitIdx < 50000);
}
limitIdx = 0;
CHECK(bytesHaveBeenRead == true);