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);