sequence count init value #81

Merged
muellerr merged 2 commits from meier/sequenceCount into develop 2022-05-11 15:43:50 +02:00
44 changed files with 338 additions and 191 deletions
Showing only changes of commit 025e7647d3 - Show all commits

View File

@ -1,4 +1,5 @@
cmake_minimum_required(VERSION 3.13) cmake_minimum_required(VERSION 3.13)
set(LIB_FSFW_NAME fsfw)
project(${LIB_FSFW_NAME}) project(${LIB_FSFW_NAME})
set(FSFW_VERSION_IF_GIT_FAILS 4) set(FSFW_VERSION_IF_GIT_FAILS 4)
@ -16,11 +17,12 @@ set(FSFW_ETL_LIB_MAJOR_VERSION 20 CACHE STRING
set(FSFW_ETL_LIB_VERSION ${FSFW_ETL_LIB_MAJOR_VERSION}.27.3 CACHE STRING set(FSFW_ETL_LIB_VERSION ${FSFW_ETL_LIB_MAJOR_VERSION}.27.3 CACHE STRING
"ETL library exact version requirement" "ETL library exact version requirement"
) )
set(FSFW_ETL_LINK_TARGET etl::etl)
set(FSFW_CATCH2_LIB_MAJOR_VERSION 3 CACHE STRING set(FSFW_CATCH2_LIB_MAJOR_VERSION 3 CACHE STRING
"Catch2 library major version requirement" "Catch2 library major version requirement"
) )
set(FSFW_CATCH2_LIB_VERSION v${FSFW_CATCH2_LIB_MAJOR_VERSION}.0.0-preview4 CACHE STRING set(FSFW_CATCH2_LIB_VERSION v${FSFW_CATCH2_LIB_MAJOR_VERSION}.0.0-preview5 CACHE STRING
"Catch2 library exact version requirement" "Catch2 library exact version requirement"
) )
@ -57,7 +59,7 @@ option(FSFW_ADD_TMSTORAGE "Compile with tm storage components" OFF)
# Contrib sources # Contrib sources
option(FSFW_ADD_SGP4_PROPAGATOR "Add SGP4 propagator code" OFF) option(FSFW_ADD_SGP4_PROPAGATOR "Add SGP4 propagator code" OFF)
set(LIB_FSFW_NAME fsfw)
set(FSFW_TEST_TGT fsfw-tests) set(FSFW_TEST_TGT fsfw-tests)
set(FSFW_DUMMY_TGT fsfw-dummy) set(FSFW_DUMMY_TGT fsfw-dummy)
@ -110,9 +112,7 @@ if(FSFW_BUILD_UNITTESTS)
GIT_TAG ${FSFW_CATCH2_LIB_VERSION} GIT_TAG ${FSFW_CATCH2_LIB_VERSION}
) )
FetchContent_MakeAvailable(Catch2) list(APPEND FSFW_FETCH_CONTENT_TARGETS Catch2)
#fixes regression -preview4, to be confirmed in later releases
set_target_properties(Catch2 PROPERTIES DEBUG_POSTFIX "")
endif() endif()
set(FSFW_CONFIG_PATH tests/src/fsfw_tests/unit/testcfg) set(FSFW_CONFIG_PATH tests/src/fsfw_tests/unit/testcfg)
@ -135,23 +135,36 @@ endif()
message(STATUS "Finding and/or providing etl library with version ${FSFW_ETL_LIB_MAJOR_VERSION}") message(STATUS "Finding and/or providing etl library with version ${FSFW_ETL_LIB_MAJOR_VERSION}")
# Check whether the user has already installed ETL first # Check whether the user has already installed ETL first
# find_package(${FSFW_ETL_LIB_NAME} ${FSFW_ETL_LIB_MAJOR_VERSION} CONFIG QUIET) find_package(${FSFW_ETL_LIB_NAME} ${FSFW_ETL_LIB_MAJOR_VERSION} CONFIG QUIET)
# Not installed, so use FetchContent to download and provide etl # Not installed, so use FetchContent to download and provide etl
# if(NOT ${FSFW_ETL_LIB_NAME}_FOUND) if(NOT ${FSFW_ETL_LIB_NAME}_FOUND)
message(STATUS message(STATUS
"No etl installation was found with find_package. Installing and providing " "No ETL installation was found with find_package. Installing and providing "
"etl with FetchContent" "etl with FindPackage"
) )
include(FetchContent) include(FetchContent)
FetchContent_Declare( FetchContent_Declare(
${FSFW_ETL_LIB_NAME} ${FSFW_ETL_LIB_NAME}
GIT_REPOSITORY https://github.com/ETLCPP/etl GIT_REPOSITORY https://github.com/ETLCPP/etl
GIT_TAG ${FSFW_ETL_LIB_VERSION} GIT_TAG ${FSFW_ETL_LIB_VERSION}
) )
list(APPEND FSFW_FETCH_CONTENT_TARGETS ${FSFW_ETL_LIB_NAME})
endif()
FetchContent_MakeAvailable(${FSFW_ETL_LIB_NAME}) # The documentation for FetchContent recommends declaring all the dependencies
# endif() # before making them available. We make all declared dependency available here
# after their declaration
if(FSFW_FETCH_CONTENT_TARGETS)
FetchContent_MakeAvailable(${FSFW_FETCH_CONTENT_TARGETS})
if(TARGET ${FSFW_ETL_LIB_NAME})
add_library(${FSFW_ETL_LINK_TARGET} ALIAS ${FSFW_ETL_LIB_NAME})
endif()
if(TARGET Catch2)
# Fixes regression -preview4, to be confirmed in later releases
# Related GitHub issue: https://github.com/catchorg/Catch2/issues/2417
set_target_properties(Catch2 PROPERTIES DEBUG_POSTFIX "")
endif()
endif()
set(FSFW_CORE_INC_PATH "inc") set(FSFW_CORE_INC_PATH "inc")
@ -414,7 +427,7 @@ target_compile_options(${LIB_FSFW_NAME} PRIVATE
) )
target_link_libraries(${LIB_FSFW_NAME} PRIVATE target_link_libraries(${LIB_FSFW_NAME} PRIVATE
etl ${FSFW_ETL_LINK_TARGET}
${FSFW_ADDITIONAL_LINK_LIBS} ${FSFW_ADDITIONAL_LINK_LIBS}
) )

View File

@ -6,3 +6,9 @@ RUN apt-get --yes upgrade
#tzdata is a dependency, won't install otherwise #tzdata is a dependency, won't install otherwise
ARG DEBIAN_FRONTEND=noninteractive ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get --yes install gcc g++ cmake make lcov git valgrind nano iputils-ping RUN apt-get --yes install gcc g++ cmake make lcov git valgrind nano iputils-ping
RUN git clone https://github.com/catchorg/Catch2.git && \
cd Catch2 && \
git checkout v3.0.0-preview5 && \
cmake -Bbuild -H. -DBUILD_TESTING=OFF && \
cmake --build build/ --target install

View File

@ -3,7 +3,7 @@ pipeline {
BUILDDIR = 'build-tests' BUILDDIR = 'build-tests'
} }
agent { agent {
docker { image 'fsfw-ci:d1'} docker { image 'fsfw-ci:d2'}
} }
stages { stages {
stage('Clean') { stage('Clean') {

View File

@ -46,9 +46,9 @@ class GpioIF : public HasReturnvaluesIF {
* an ouput or input gpio. * an ouput or input gpio.
* *
* @param gpioId A unique number which specifies the GPIO to read. * @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_ */ #endif /* COMMON_GPIO_GPIOIF_H_ */

View File

@ -9,7 +9,7 @@ using gpioId_t = uint16_t;
namespace gpio { 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 }; enum class Direction : int { IN = 0, OUT = 1 };

View File

@ -12,9 +12,14 @@ if(FSFW_HAL_LINUX_ADD_PERIPHERAL_DRIVERS)
if(FSFW_HAL_LINUX_ADD_LIBGPIOD) if(FSFW_HAL_LINUX_ADD_LIBGPIOD)
add_subdirectory(gpio) add_subdirectory(gpio)
endif() endif()
add_subdirectory(spi)
add_subdirectory(i2c)
add_subdirectory(uart) add_subdirectory(uart)
# Adding those does not really make sense on Apple systems which
# are generally host systems. It won't even compile as the headers
# are missing
if(NOT APPLE)
add_subdirectory(i2c)
add_subdirectory(spi)
endif()
endif() endif()
add_subdirectory(uio) add_subdirectory(uio)

View File

@ -280,7 +280,7 @@ ReturnValue_t LinuxLibgpioIF::driveGpio(gpioId_t gpioId, GpiodRegularBase& regul
return RETURN_OK; 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); gpioMapIter = gpioMap.find(gpioId);
if (gpioMapIter == gpioMap.end()) { if (gpioMapIter == gpioMap.end()) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
@ -299,7 +299,10 @@ ReturnValue_t LinuxLibgpioIF::readGpio(gpioId_t gpioId, int* gpioState) {
if (regularGpio == nullptr) { if (regularGpio == nullptr) {
return GPIO_TYPE_FAILURE; return GPIO_TYPE_FAILURE;
} }
*gpioState = gpiod_line_get_value(regularGpio->lineHandle); gpioState = static_cast<gpio::Levels>(gpiod_line_get_value(regularGpio->lineHandle));
if (gpioState == gpio::Levels::FAILED) {
return GPIO_GET_VALUE_FAILED;
}
} else { } else {
auto gpioCallback = dynamic_cast<GpioCallback*>(gpioMapIter->second); auto gpioCallback = dynamic_cast<GpioCallback*>(gpioMapIter->second);
if (gpioCallback->callback == nullptr) { if (gpioCallback->callback == nullptr) {

View File

@ -31,14 +31,16 @@ class LinuxLibgpioIF : public GpioIF, public SystemObject {
HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 5); HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 5);
static constexpr ReturnValue_t GPIO_INIT_FAILED = static constexpr ReturnValue_t GPIO_INIT_FAILED =
HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 6); 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); LinuxLibgpioIF(object_id_t objectId);
virtual ~LinuxLibgpioIF(); virtual ~LinuxLibgpioIF();
ReturnValue_t addGpios(GpioCookie* gpioCookie) override; ReturnValue_t addGpios(GpioCookie* gpioCookie) override;
ReturnValue_t pullHigh(gpioId_t gpioId) override; ReturnValue_t pullHigh(gpioId_t gpioId) override;
ReturnValue_t pullLow(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: private:
static const size_t MAX_CHIPNAME_LENGTH = 11; static const size_t MAX_CHIPNAME_LENGTH = 11;

View File

@ -170,18 +170,20 @@ ReturnValue_t I2cComIF::requestReceiveMessage(CookieIF* cookie, size_t requestLe
int readLen = read(fd, replyBuffer, requestLen); int readLen = read(fd, replyBuffer, requestLen);
if (readLen != static_cast<int>(requestLen)) { if (readLen != static_cast<int>(requestLen)) {
#if FSFW_VERBOSE_LEVEL >= 1 and FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_VERBOSE_LEVEL >= 1
sif::error << "I2cComIF::requestReceiveMessage: Reading from I2C " #if FSFW_CPP_OSTREAM_ENABLED == 1
<< "device failed with error code " << errno << ". Description" if (readLen < 0) {
<< " of error: " << strerror(errno) << std::endl; sif::warning << "I2cComIF::requestReceiveMessage: Reading from I2C "
sif::error << "I2cComIF::requestReceiveMessage: Read only " << readLen << " from " << requestLen << "device failed with error code " << errno << " | " << strerror(errno)
<< " bytes" << std::endl; << std::endl;
} else {
sif::warning << "I2cComIF::requestReceiveMessage: Read only " << readLen << " from "
<< requestLen << " bytes" << std::endl;
}
#else
#endif
#endif #endif
i2cDeviceMapIter->second.replyLen = 0; 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; return HasReturnvaluesIF::RETURN_FAILED;
} }

View File

@ -1,4 +1,4 @@
#include "fsfw_hal/linux/spi/SpiCookie.h" #include "SpiCookie.h"
SpiCookie::SpiCookie(address_t spiAddress, gpioId_t chipSelect, std::string spiDev, SpiCookie::SpiCookie(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)

View File

@ -265,6 +265,7 @@ void UartComIF::configureBaudrate(struct termios* options, UartCookie* uartCooki
cfsetispeed(options, B230400); cfsetispeed(options, B230400);
cfsetospeed(options, B230400); cfsetospeed(options, B230400);
break; break;
#ifndef __APPLE__
case UartBaudRate::RATE_460800: case UartBaudRate::RATE_460800:
cfsetispeed(options, B460800); cfsetispeed(options, B460800);
cfsetospeed(options, B460800); cfsetospeed(options, B460800);
@ -313,6 +314,7 @@ void UartComIF::configureBaudrate(struct termios* options, UartCookie* uartCooki
cfsetispeed(options, B4000000); cfsetispeed(options, B4000000);
cfsetospeed(options, B4000000); cfsetospeed(options, B4000000);
break; break;
#endif // ! __APPLE__
default: default:
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "UartComIF::configureBaudrate: Baudrate not supported" << std::endl; sif::warning << "UartComIF::configureBaudrate: Baudrate not supported" << std::endl;

View File

@ -44,7 +44,7 @@ class HeaderSerializer : public SerializeIF, public PduHeaderIF {
cfdp::WidthInBytes getLenEntityIds() const override; cfdp::WidthInBytes getLenEntityIds() const override;
cfdp::WidthInBytes getLenSeqNum() const override; cfdp::WidthInBytes getLenSeqNum() const override;
cfdp::SegmentMetadataFlag getSegmentMetadataFlag() const override; cfdp::SegmentMetadataFlag getSegmentMetadataFlag() const override;
bool hasSegmentMetadataFlag() const; bool hasSegmentMetadataFlag() const override;
void setSegmentationControl(cfdp::SegmentationControl); void setSegmentationControl(cfdp::SegmentationControl);
void getSourceId(cfdp::EntityId& sourceId) const override; void getSourceId(cfdp::EntityId& sourceId) const override;

View File

@ -9,7 +9,7 @@
*/ */
template <typename T, size_t MAX_SIZE, typename count_t = uint8_t> template <typename T, size_t MAX_SIZE, typename count_t = uint8_t>
class FixedArrayList : public ArrayList<T, count_t> { class FixedArrayList : public ArrayList<T, count_t> {
#if !defined(_MSC_VER) #if !defined(_MSC_VER) && !defined(__clang__)
static_assert(MAX_SIZE <= (std::pow(2, sizeof(count_t) * 8) - 1), static_assert(MAX_SIZE <= (std::pow(2, sizeof(count_t) * 8) - 1),
"count_t is not large enough to hold MAX_SIZE"); "count_t is not large enough to hold MAX_SIZE");
#endif #endif

View File

@ -10,7 +10,7 @@ class HybridIterator : public LinkedElement<T>::Iterator, public ArrayList<T, co
HybridIterator() {} HybridIterator() {}
HybridIterator(typename LinkedElement<T>::Iterator *iter) HybridIterator(typename LinkedElement<T>::Iterator *iter)
: LinkedElement<T>::Iterator(*iter), value(iter->value), linked(true) { : LinkedElement<T>::Iterator(*iter), linked(true) {
if (iter != nullptr) { if (iter != nullptr) {
value = iter->value; value = iter->value;
} }

View File

@ -55,7 +55,7 @@ class ControllerBase : public HasModesIF,
virtual void performControlOperation() = 0; virtual void performControlOperation() = 0;
virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
uint32_t *msToReachTheMode) = 0; uint32_t *msToReachTheMode) override = 0;
const object_id_t parentId; const object_id_t parentId;
@ -80,9 +80,9 @@ class ControllerBase : public HasModesIF,
/** Mode helpers */ /** Mode helpers */
virtual void modeChanged(Mode_t mode, Submode_t submode); virtual void modeChanged(Mode_t mode, Submode_t submode);
virtual void startTransition(Mode_t mode, Submode_t submode); virtual void startTransition(Mode_t mode, Submode_t submode) override;
virtual void getMode(Mode_t *mode, Submode_t *submode); virtual void getMode(Mode_t *mode, Submode_t *submode) override;
virtual void setToExternalControl(); virtual void setToExternalControl() override;
virtual void announceMode(bool recursive); virtual void announceMode(bool recursive);
/** HK helpers */ /** HK helpers */
virtual void changeHK(Mode_t mode, Submode_t submode, bool enable); virtual void changeHK(Mode_t mode, Submode_t submode, bool enable);

View File

@ -109,7 +109,7 @@ class PoolDataSetBase : public PoolDataSetIF, public SerializeIF, public HasRetu
*/ */
virtual ReturnValue_t unlockDataPool() override; virtual ReturnValue_t unlockDataPool() override;
virtual uint16_t getFillCount() const; virtual uint16_t getFillCount() const override;
/* SerializeIF implementations */ /* SerializeIF implementations */
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, const size_t maxSize, virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, const size_t maxSize,

View File

@ -94,13 +94,14 @@ ReturnValue_t LocalPoolDataSetBase::serializeWithValidityBuffer(
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
const uint8_t validityMaskSize = std::ceil(static_cast<float>(fillCount) / 8.0); const uint8_t validityMaskSize = std::ceil(static_cast<float>(fillCount) / 8.0);
uint8_t *validityPtr = nullptr; uint8_t *validityPtr = nullptr;
#ifdef _MSC_VER #if defined(_MSC_VER) || defined(__clang__)
/* Use a std::vector here because MSVC will (rightly) not create a fixed size array // Use a std::vector here because MSVC will (rightly) not create a fixed size array
with a non constant size specifier */ // with a non constant size specifier. The Apple compiler (LLVM) will not accept
std::vector<uint8_t> validityMask(validityMaskSize); // the initialization of a variable sized array
std::vector<uint8_t> validityMask(validityMaskSize, 0);
validityPtr = validityMask.data(); validityPtr = validityMask.data();
#else #else
uint8_t validityMask[validityMaskSize] = {0}; uint8_t validityMask[validityMaskSize] = {};
validityPtr = validityMask; validityPtr = validityMask;
#endif #endif
uint8_t validBufferIndex = 0; uint8_t validBufferIndex = 0;

View File

@ -23,8 +23,8 @@ class LocalPoolObjectBase : public PoolVariableIF, public HasReturnvaluesIF, pub
LocalPoolObjectBase(object_id_t poolOwner, lp_id_t poolId, DataSetIF* dataSet = nullptr, LocalPoolObjectBase(object_id_t poolOwner, lp_id_t poolId, DataSetIF* dataSet = nullptr,
pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE); pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE);
void setReadWriteMode(pool_rwm_t newReadWriteMode); void setReadWriteMode(pool_rwm_t newReadWriteMode) override;
pool_rwm_t getReadWriteMode() const; pool_rwm_t getReadWriteMode() const override;
bool isValid() const override; bool isValid() const override;
void setValid(bool valid) override; void setValid(bool valid) override;

View File

@ -243,16 +243,27 @@ ReturnValue_t DeviceHandlerBase::initialize() {
} }
void DeviceHandlerBase::decrementDeviceReplyMap() { void DeviceHandlerBase::decrementDeviceReplyMap() {
bool timedOut = false;
for (std::pair<const DeviceCommandId_t, DeviceReplyInfo>& replyPair : deviceReplyMap) { for (std::pair<const DeviceCommandId_t, DeviceReplyInfo>& 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--; replyPair.second.delayCycles--;
if (replyPair.second.delayCycles == 0) { if (replyPair.second.delayCycles == 0) {
if (replyPair.second.periodic) { if (replyPair.second.periodic) {
replyPair.second.delayCycles = replyPair.second.maxDelayCycles; replyPair.second.delayCycles = replyPair.second.maxDelayCycles;
} }
timedOut = true;
}
}
if (timedOut) {
replyToReply(replyPair.first, replyPair.second, TIMEOUT); replyToReply(replyPair.first, replyPair.second, TIMEOUT);
missedReply(replyPair.first); missedReply(replyPair.first);
} timedOut = false;
replyPair.second.active = false;
} }
} }
} }
@ -416,20 +427,22 @@ ReturnValue_t DeviceHandlerBase::isModeCombinationValid(Mode_t mode, Submode_t s
ReturnValue_t DeviceHandlerBase::insertInCommandAndReplyMap( ReturnValue_t DeviceHandlerBase::insertInCommandAndReplyMap(
DeviceCommandId_t deviceCommand, uint16_t maxDelayCycles, LocalPoolDataSetBase* replyDataSet, 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. // No need to check, as we may try to insert multiple times.
insertInCommandMap(deviceCommand, hasDifferentReplyId, replyId); insertInCommandMap(deviceCommand, hasDifferentReplyId, replyId);
if (hasDifferentReplyId) { if (hasDifferentReplyId) {
return insertInReplyMap(replyId, maxDelayCycles, replyDataSet, replyLen, periodic); return insertInReplyMap(replyId, maxDelayCycles, replyDataSet, replyLen, periodic, countdown);
} else { } else {
return insertInReplyMap(deviceCommand, maxDelayCycles, replyDataSet, replyLen, periodic); return insertInReplyMap(deviceCommand, maxDelayCycles, replyDataSet, replyLen, periodic,
countdown);
} }
} }
ReturnValue_t DeviceHandlerBase::insertInReplyMap(DeviceCommandId_t replyId, ReturnValue_t DeviceHandlerBase::insertInReplyMap(DeviceCommandId_t replyId,
uint16_t maxDelayCycles, uint16_t maxDelayCycles,
LocalPoolDataSetBase* dataSet, size_t replyLen, LocalPoolDataSetBase* dataSet, size_t replyLen,
bool periodic) { bool periodic, Countdown* countdown) {
DeviceReplyInfo info; DeviceReplyInfo info;
info.maxDelayCycles = maxDelayCycles; info.maxDelayCycles = maxDelayCycles;
info.periodic = periodic; info.periodic = periodic;
@ -437,6 +450,10 @@ ReturnValue_t DeviceHandlerBase::insertInReplyMap(DeviceCommandId_t replyId,
info.replyLen = replyLen; info.replyLen = replyLen;
info.dataSet = dataSet; info.dataSet = dataSet;
info.command = deviceCommandMap.end(); info.command = deviceCommandMap.end();
info.countdown = countdown;
if (info.periodic) {
info.active = true;
}
auto resultPair = deviceReplyMap.emplace(replyId, info); auto resultPair = deviceReplyMap.emplace(replyId, info);
if (resultPair.second) { if (resultPair.second) {
return RETURN_OK; return RETURN_OK;
@ -472,7 +489,8 @@ size_t DeviceHandlerBase::getNextReplyLength(DeviceCommandId_t commandId) {
} }
DeviceReplyIter iter = deviceReplyMap.find(replyId); DeviceReplyIter iter = deviceReplyMap.find(replyId);
if (iter != deviceReplyMap.end()) { 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; return iter->second.replyLen;
} }
} }
@ -816,17 +834,18 @@ void DeviceHandlerBase::handleReply(const uint8_t* receivedData, DeviceCommandId
DeviceReplyInfo* info = &(iter->second); DeviceReplyInfo* info = &(iter->second);
if (info->delayCycles != 0) { if ((info->delayCycles != 0 && info->countdown == nullptr) ||
(info->active && info->countdown != nullptr)) {
result = interpretDeviceReply(foundId, receivedData); result = interpretDeviceReply(foundId, receivedData);
if (result == IGNORE_REPLY_DATA) { if (result == IGNORE_REPLY_DATA) {
return; return;
} }
if (info->periodic) { if (info->active && info->countdown != nullptr) {
info->delayCycles = info->maxDelayCycles; disableTimeoutControlledReply(info);
} else { } else if (info->delayCycles != 0) {
info->delayCycles = 0; disableDelayCyclesControlledReply(info);
} }
if (result != RETURN_OK) { if (result != RETURN_OK) {
@ -845,6 +864,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, ReturnValue_t DeviceHandlerBase::getStorageData(store_address_t storageAddress, uint8_t** data,
size_t* len) { size_t* len) {
size_t lenTmp; size_t lenTmp;
@ -970,6 +1007,10 @@ ReturnValue_t DeviceHandlerBase::enableReplyInReplyMap(DeviceCommandMap::iterato
info->delayCycles = info->maxDelayCycles; info->delayCycles = info->maxDelayCycles;
info->command = command; info->command = command;
command->second.expectedReplies = expectedReplies; command->second.expectedReplies = expectedReplies;
if (info->countdown != nullptr) {
info->countdown->resetTimer();
}
info->active = true;
return RETURN_OK; return RETURN_OK;
} else { } else {
return NO_REPLY_EXPECTED; return NO_REPLY_EXPECTED;
@ -1204,7 +1245,8 @@ void DeviceHandlerBase::setParentQueue(MessageQueueId_t parentQueueId) {
bool DeviceHandlerBase::isAwaitingReply() { bool DeviceHandlerBase::isAwaitingReply() {
std::map<DeviceCommandId_t, DeviceReplyInfo>::iterator iter; std::map<DeviceCommandId_t, DeviceReplyInfo>::iterator iter;
for (iter = deviceReplyMap.begin(); iter != deviceReplyMap.end(); ++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; return true;
} }
} }
@ -1360,6 +1402,9 @@ uint8_t DeviceHandlerBase::getReplyDelayCycles(DeviceCommandId_t deviceCommand)
if (iter == deviceReplyMap.end()) { if (iter == deviceReplyMap.end()) {
return 0; return 0;
} }
else if (iter->second.countdown != nullptr) {
return 0;
}
return iter->second.delayCycles; return iter->second.delayCycles;
} }

View File

@ -166,7 +166,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
* @param counter Specifies which Action to perform * @param counter Specifies which Action to perform
* @return RETURN_OK for successful execution * @return RETURN_OK for successful execution
*/ */
virtual ReturnValue_t performOperation(uint8_t counter); virtual ReturnValue_t performOperation(uint8_t counter) override;
/** /**
* @brief Initializes the device handler * @brief Initializes the device handler
@ -176,7 +176,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
* Calls fillCommandAndReplyMap(). * Calls fillCommandAndReplyMap().
* @return * @return
*/ */
virtual ReturnValue_t initialize(); virtual ReturnValue_t initialize() override;
/** /**
* @brief Intialization steps performed after all tasks have been created. * @brief Intialization steps performed after all tasks have been created.
@ -451,6 +451,9 @@ class DeviceHandlerBase : public DeviceHandlerIF,
* by the device repeatedly without request) or not. Default is aperiodic (0). * 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 * Please note that periodic replies are disabled by default. You can enable them with
* #updatePeriodicReply * #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, * @return - @c RETURN_OK when the command was successfully inserted,
* - @c RETURN_FAILED else. * - @c RETURN_FAILED else.
*/ */
@ -458,7 +461,8 @@ class DeviceHandlerBase : public DeviceHandlerIF,
LocalPoolDataSetBase *replyDataSet = nullptr, LocalPoolDataSetBase *replyDataSet = nullptr,
size_t replyLen = 0, bool periodic = false, size_t replyLen = 0, bool periodic = false,
bool hasDifferentReplyId = 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. * @brief This is a helper method to insert replies in the reply map.
* @param deviceCommand Identifier of the reply to add. * @param deviceCommand Identifier of the reply to add.
@ -468,12 +472,15 @@ class DeviceHandlerBase : public DeviceHandlerIF,
* by the device repeatedly without request) or not. Default is aperiodic (0). * 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 * Please note that periodic replies are disabled by default. You can enable them with
* #updatePeriodicReply * #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, * @return - @c RETURN_OK when the command was successfully inserted,
* - @c RETURN_FAILED else. * - @c RETURN_FAILED else.
*/ */
ReturnValue_t insertInReplyMap(DeviceCommandId_t deviceCommand, uint16_t maxDelayCycles, ReturnValue_t insertInReplyMap(DeviceCommandId_t deviceCommand, uint16_t maxDelayCycles,
LocalPoolDataSetBase *dataSet = nullptr, size_t replyLen = 0, 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. * @brief A simple command to add a command to the commandList.
@ -792,6 +799,11 @@ class DeviceHandlerBase : public DeviceHandlerIF,
LocalPoolDataSetBase *dataSet = nullptr; LocalPoolDataSetBase *dataSet = nullptr;
//! The command that expects this reply. //! The command that expects this reply.
DeviceCommandMap::iterator command; 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<DeviceCommandId_t, DeviceReplyInfo>; using DeviceReplyMap = std::map<DeviceCommandId_t, DeviceReplyInfo>;
@ -1068,11 +1080,12 @@ class DeviceHandlerBase : public DeviceHandlerIF,
* @param parameter1 Optional parameter 1 * @param parameter1 Optional parameter 1
* @param parameter2 Optional parameter 2 * @param parameter2 Optional parameter 2
*/ */
void triggerEvent(Event event, uint32_t parameter1 = 0, uint32_t parameter2 = 0); void triggerEvent(Event event, uint32_t parameter1 = 0, uint32_t parameter2 = 0) override;
/** /**
* Same as triggerEvent, but for forwarding if object is used as proxy. * Same as triggerEvent, but for forwarding if object is used as proxy.
*/ */
virtual void forwardEvent(Event event, uint32_t parameter1 = 0, uint32_t parameter2 = 0) const; virtual void forwardEvent(Event event, uint32_t parameter1 = 0,
uint32_t parameter2 = 0) const override;
/** /**
* Checks if current mode is transitional mode. * Checks if current mode is transitional mode.
@ -1253,6 +1266,17 @@ class DeviceHandlerBase : public DeviceHandlerIF,
*/ */
void doGetRead(void); 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. * Retrive data from the #IPCStore.
* *

View File

@ -25,7 +25,7 @@ class MatchTree : public SerializeableMatcherIF<T>, public BinaryTree<Serializea
: BinaryTree<SerializeableMatcherIF<T>>(root.element), maxDepth(maxDepth) {} : BinaryTree<SerializeableMatcherIF<T>>(root.element), maxDepth(maxDepth) {}
MatchTree() : BinaryTree<SerializeableMatcherIF<T>>(), maxDepth(-1) {} MatchTree() : BinaryTree<SerializeableMatcherIF<T>>(), maxDepth(-1) {}
virtual ~MatchTree() {} virtual ~MatchTree() {}
virtual bool match(T number) { return matchesTree(number); } virtual bool match(T number) override { return matchesTree(number); }
bool matchesTree(T number) { bool matchesTree(T number) {
iterator iter = this->begin(); iterator iter = this->begin();
if (iter == this->end()) { if (iter == this->end()) {

View File

@ -15,7 +15,7 @@ class RangeMatcher : public SerializeableMatcherIF<T> {
RangeMatcher(T lowerBound, T upperBound, bool inverted = false) RangeMatcher(T lowerBound, T upperBound, bool inverted = false)
: inverted(inverted), lowerBound(lowerBound), upperBound(upperBound) {} : inverted(inverted), lowerBound(lowerBound), upperBound(upperBound) {}
bool match(T input) { bool match(T input) override {
if (inverted) { if (inverted) {
return !doMatch(input); return !doMatch(input);
} else { } else {

View File

@ -34,7 +34,7 @@ class MonitoringReportContent : public SerialLinkedListAdapter<SerializeIF> {
SerializeElement<T> limitValue; SerializeElement<T> limitValue;
SerializeElement<ReturnValue_t> oldState; SerializeElement<ReturnValue_t> oldState;
SerializeElement<ReturnValue_t> newState; SerializeElement<ReturnValue_t> newState;
uint8_t rawTimestamp[TimeStamperIF::MISSION_TIMESTAMP_SIZE]; uint8_t rawTimestamp[TimeStamperIF::MISSION_TIMESTAMP_SIZE] = {};
SerializeElement<SerialBufferAdapter<uint8_t>> timestampSerializer; SerializeElement<SerialBufferAdapter<uint8_t>> timestampSerializer;
TimeStamperIF* timeStamper; TimeStamperIF* timeStamper;
MonitoringReportContent() MonitoringReportContent()
@ -46,7 +46,6 @@ class MonitoringReportContent : public SerialLinkedListAdapter<SerializeIF> {
limitValue(0), limitValue(0),
oldState(0), oldState(0),
newState(0), newState(0),
rawTimestamp({0}),
timestampSerializer(rawTimestamp, sizeof(rawTimestamp)), timestampSerializer(rawTimestamp, sizeof(rawTimestamp)),
timeStamper(NULL) { timeStamper(NULL) {
setAllNext(); setAllNext();

View File

@ -48,9 +48,10 @@ class SystemObject : public SystemObjectIF {
virtual ~SystemObject(); virtual ~SystemObject();
object_id_t getObjectId() const override; object_id_t getObjectId() const override;
virtual ReturnValue_t initialize() override; virtual ReturnValue_t initialize() override;
virtual ReturnValue_t checkObjectConnections(); virtual ReturnValue_t checkObjectConnections() override;
virtual void forwardEvent(Event event, uint32_t parameter1 = 0, uint32_t parameter2 = 0) const; virtual void forwardEvent(Event event, uint32_t parameter1 = 0,
uint32_t parameter2 = 0) const override;
}; };
#endif /* FSFW_OBJECTMANAGER_SYSTEMOBJECT_H_ */ #endif /* FSFW_OBJECTMANAGER_SYSTEMOBJECT_H_ */

View File

@ -16,11 +16,13 @@
//! Debugging preprocessor define. //! Debugging preprocessor define.
#define FSFW_UDP_RECV_WIRETAPPING_ENABLED 0 #define FSFW_UDP_RECV_WIRETAPPING_ENABLED 0
const timeval UdpTcPollingTask::DEFAULT_TIMEOUT = {0, 500000};
UdpTcPollingTask::UdpTcPollingTask(object_id_t objectId, object_id_t tmtcUdpBridge, UdpTcPollingTask::UdpTcPollingTask(object_id_t objectId, object_id_t tmtcUdpBridge,
size_t maxRecvSize, double timeoutSeconds) size_t maxRecvSize, double timeoutSeconds)
: SystemObject(objectId), tmtcBridgeId(tmtcUdpBridge) { : SystemObject(objectId), tmtcBridgeId(tmtcUdpBridge) {
if (frameSize > 0) { if (maxRecvSize > 0) {
this->frameSize = frameSize; this->frameSize = maxRecvSize;
} else { } else {
this->frameSize = DEFAULT_MAX_RECV_SIZE; this->frameSize = DEFAULT_MAX_RECV_SIZE;
} }
@ -31,22 +33,20 @@ UdpTcPollingTask::UdpTcPollingTask(object_id_t objectId, object_id_t tmtcUdpBrid
receptionBuffer.resize(this->frameSize); receptionBuffer.resize(this->frameSize);
if (timeoutSeconds == -1) { if (timeoutSeconds == -1) {
receptionTimeout = DEFAULT_TIMEOUT; receptionTimeout = UdpTcPollingTask::DEFAULT_TIMEOUT;
} else { } else {
receptionTimeout = timevalOperations::toTimeval(timeoutSeconds); receptionTimeout = timevalOperations::toTimeval(timeoutSeconds);
} }
} }
UdpTcPollingTask::~UdpTcPollingTask() {} [[noreturn]] ReturnValue_t UdpTcPollingTask::performOperation(uint8_t opCode) {
ReturnValue_t UdpTcPollingTask::performOperation(uint8_t opCode) {
/* Sender Address is cached here. */ /* Sender Address is cached here. */
struct sockaddr senderAddress; struct sockaddr senderAddress {};
socklen_t senderAddressSize = sizeof(senderAddress); socklen_t senderAddressSize = sizeof(senderAddress);
/* Poll for new UDP datagrams in permanent loop. */ /* Poll for new UDP datagrams in permanent loop. */
while (true) { while (true) {
int bytesReceived = ssize_t bytesReceived =
recvfrom(this->serverSocket, reinterpret_cast<char*>(receptionBuffer.data()), frameSize, recvfrom(this->serverSocket, reinterpret_cast<char*>(receptionBuffer.data()), frameSize,
receptionFlags, &senderAddress, &senderAddressSize); receptionFlags, &senderAddress, &senderAddressSize);
if (bytesReceived == SOCKET_ERROR) { if (bytesReceived == SOCKET_ERROR) {
@ -70,7 +70,6 @@ ReturnValue_t UdpTcPollingTask::performOperation(uint8_t opCode) {
} }
tmtcBridge->checkAndSetClientAddress(senderAddress); tmtcBridge->checkAndSetClientAddress(senderAddress);
} }
return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t UdpTcPollingTask::handleSuccessfullTcRead(size_t bytesRead) { ReturnValue_t UdpTcPollingTask::handleSuccessfullTcRead(size_t bytesRead) {
@ -155,7 +154,7 @@ void UdpTcPollingTask::setTimeout(double timeoutSeconds) {
#endif #endif
} }
#elif defined(PLATFORM_UNIX) #elif defined(PLATFORM_UNIX)
timeval tval; timeval tval{};
tval = timevalOperations::toTimeval(timeoutSeconds); tval = timevalOperations::toTimeval(timeoutSeconds);
int result = setsockopt(serverSocket, SOL_SOCKET, SO_RCVTIMEO, &tval, sizeof(receptionTimeout)); int result = setsockopt(serverSocket, SOL_SOCKET, SO_RCVTIMEO, &tval, sizeof(receptionTimeout));
if (result == -1) { if (result == -1) {

View File

@ -21,11 +21,11 @@ class UdpTcPollingTask : public TcpIpBase, public SystemObject, public Executabl
public: public:
static constexpr size_t DEFAULT_MAX_RECV_SIZE = 1500; static constexpr size_t DEFAULT_MAX_RECV_SIZE = 1500;
//! 0.5 default milliseconds timeout for now. //! 0.5 default milliseconds timeout for now.
static constexpr timeval DEFAULT_TIMEOUT = {0, 500}; static const timeval DEFAULT_TIMEOUT;
UdpTcPollingTask(object_id_t objectId, object_id_t tmtcUdpBridge, size_t maxRecvSize = 0, UdpTcPollingTask(object_id_t objectId, object_id_t tmtcUdpBridge, size_t maxRecvSize = 0,
double timeoutSeconds = -1); double timeoutSeconds = -1);
virtual ~UdpTcPollingTask(); ~UdpTcPollingTask() override = default;
/** /**
* Turn on optional timeout for UDP polling. In the default mode, * Turn on optional timeout for UDP polling. In the default mode,
@ -34,9 +34,9 @@ class UdpTcPollingTask : public TcpIpBase, public SystemObject, public Executabl
*/ */
void setTimeout(double timeoutSeconds); void setTimeout(double timeoutSeconds);
virtual ReturnValue_t performOperation(uint8_t opCode) override; [[noreturn]] ReturnValue_t performOperation(uint8_t opCode) override;
virtual ReturnValue_t initialize() override; ReturnValue_t initialize() override;
virtual ReturnValue_t initializeAfterTaskCreation() override; ReturnValue_t initializeAfterTaskCreation() override;
protected: protected:
StorageManagerIF* tcStore = nullptr; StorageManagerIF* tcStore = nullptr;
@ -51,7 +51,7 @@ class UdpTcPollingTask : public TcpIpBase, public SystemObject, public Executabl
std::vector<uint8_t> receptionBuffer; std::vector<uint8_t> receptionBuffer;
size_t frameSize = 0; size_t frameSize = 0;
timeval receptionTimeout; timeval receptionTimeout{};
ReturnValue_t handleSuccessfullTcRead(size_t bytesRead); ReturnValue_t handleSuccessfullTcRead(size_t bytesRead);
}; };

View File

@ -20,13 +20,13 @@
const std::string UdpTmTcBridge::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT; const std::string UdpTmTcBridge::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT;
UdpTmTcBridge::UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination, UdpTmTcBridge::UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination,
std::string udpServerPort, object_id_t tmStoreId, const std::string &udpServerPort_, object_id_t tmStoreId,
object_id_t tcStoreId) object_id_t tcStoreId)
: TmTcBridge(objectId, tcDestination, tmStoreId, tcStoreId) { : TmTcBridge(objectId, tcDestination, tmStoreId, tcStoreId) {
if (udpServerPort == "") { if (udpServerPort_.empty()) {
this->udpServerPort = DEFAULT_SERVER_PORT; udpServerPort = DEFAULT_SERVER_PORT;
} else { } else {
this->udpServerPort = udpServerPort; udpServerPort = udpServerPort_;
} }
mutex = MutexFactory::instance()->createMutex(); mutex = MutexFactory::instance()->createMutex();
@ -117,7 +117,7 @@ ReturnValue_t UdpTmTcBridge::sendTm(const uint8_t *data, size_t dataLen) {
tcpip::printAddress(&clientAddress); tcpip::printAddress(&clientAddress);
#endif #endif
int bytesSent = sendto(serverSocket, reinterpret_cast<const char *>(data), dataLen, flags, ssize_t bytesSent = sendto(serverSocket, reinterpret_cast<const char *>(data), dataLen, flags,
&clientAddress, clientAddressLen); &clientAddress, clientAddressLen);
if (bytesSent == SOCKET_ERROR) { if (bytesSent == SOCKET_ERROR) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
@ -150,7 +150,7 @@ void UdpTmTcBridge::checkAndSetClientAddress(sockaddr &newAddress) {
clientAddressLen = sizeof(clientAddress); clientAddressLen = sizeof(clientAddress);
} }
void UdpTmTcBridge::setMutexProperties(MutexIF::TimeoutType timeoutType, dur_millis_t timeoutMs) { void UdpTmTcBridge::setMutexProperties(MutexIF::TimeoutType timeoutType_, dur_millis_t timeoutMs) {
this->timeoutType = timeoutType; timeoutType = timeoutType_;
this->mutexTimeoutMs = timeoutMs; mutexTimeoutMs = timeoutMs;
} }

View File

@ -29,10 +29,10 @@ class UdpTmTcBridge : public TmTcBridge, public TcpIpBase {
/* The ports chosen here should not be used by any other process. */ /* The ports chosen here should not be used by any other process. */
static const std::string DEFAULT_SERVER_PORT; static const std::string DEFAULT_SERVER_PORT;
UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination, std::string udpServerPort = "", UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination,
object_id_t tmStoreId = objects::TM_STORE, const std::string& udpServerPort = "", object_id_t tmStoreId = objects::TM_STORE,
object_id_t tcStoreId = objects::TC_STORE); object_id_t tcStoreId = objects::TC_STORE);
virtual ~UdpTmTcBridge(); ~UdpTmTcBridge() override;
/** /**
* Set properties of internal mutex. * Set properties of internal mutex.
@ -46,12 +46,12 @@ class UdpTmTcBridge : public TmTcBridge, public TcpIpBase {
std::string getUdpPort() const; std::string getUdpPort() const;
protected: protected:
virtual ReturnValue_t sendTm(const uint8_t* data, size_t dataLen) override; ReturnValue_t sendTm(const uint8_t* data, size_t dataLen) override;
private: private:
std::string udpServerPort; std::string udpServerPort;
struct sockaddr clientAddress; struct sockaddr clientAddress = {};
socklen_t clientAddressLen = 0; socklen_t clientAddressLen = 0;
//! Access to the client address is mutex protected as it is set by another task. //! Access to the client address is mutex protected as it is set by another task.

View File

@ -46,7 +46,7 @@ void FixedTimeslotTask::missedDeadlineCounter() {
FixedTimeslotTask::deadlineMissedCount++; FixedTimeslotTask::deadlineMissedCount++;
if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) { if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "PST missed " << FixedTimeslotTask::deadlineMissedCount << " deadlines." sif::warning << "PST missed " << FixedTimeslotTask::deadlineMissedCount << " deadlines"
<< std::endl; << std::endl;
#endif #endif
} }

View File

@ -1,5 +1,4 @@
target_sources(${LIB_FSFW_NAME} target_sources(${LIB_FSFW_NAME} PRIVATE
PRIVATE
Clock.cpp Clock.cpp
FixedTimeslotTask.cpp FixedTimeslotTask.cpp
MessageQueue.cpp MessageQueue.cpp
@ -16,9 +15,13 @@ target_sources(${LIB_FSFW_NAME}
if(UNIX) if(UNIX)
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
target_link_libraries(${LIB_FSFW_NAME} target_link_libraries(${LIB_FSFW_NAME} PRIVATE
PRIVATE
rt
${CMAKE_THREAD_LIBS_INIT} ${CMAKE_THREAD_LIBS_INIT}
) )
if(NOT APPLE)
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
rt
)
endif()
endif() endif()

View File

@ -18,12 +18,12 @@ target_sources(${LIB_FSFW_NAME} PRIVATE
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
target_link_libraries(${LIB_FSFW_NAME} PRIVATE target_link_libraries(${LIB_FSFW_NAME} PUBLIC
${CMAKE_THREAD_LIBS_INIT} ${CMAKE_THREAD_LIBS_INIT}
)
if(NOT APPLE)
target_link_libraries(${LIB_FSFW_NAME} PUBLIC
rt rt
) )
endif()
target_link_libraries(${LIB_FSFW_NAME} INTERFACE
${CMAKE_THREAD_LIBS_INIT}
)

View File

@ -87,7 +87,7 @@ void FixedTimeslotTask::missedDeadlineCounter() {
FixedTimeslotTask::deadlineMissedCount++; FixedTimeslotTask::deadlineMissedCount++;
if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) { if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "PST missed " << FixedTimeslotTask::deadlineMissedCount << " deadlines." sif::warning << "PST missed " << FixedTimeslotTask::deadlineMissedCount << " deadlines"
<< std::endl; << std::endl;
#endif #endif
} }

View File

@ -50,7 +50,7 @@ void FixedTimeslotTask::missedDeadlineCounter() {
FixedTimeslotTask::deadlineMissedCount++; FixedTimeslotTask::deadlineMissedCount++;
if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) { if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "PST missed " << FixedTimeslotTask::deadlineMissedCount << " deadlines." sif::warning << "PST missed " << FixedTimeslotTask::deadlineMissedCount << " deadlines"
<< std::endl; << std::endl;
#endif #endif
} }

View File

@ -54,7 +54,7 @@ class Fuse : public SystemObject,
ReturnValue_t check(); ReturnValue_t check();
uint8_t getFuseId() const; uint8_t getFuseId() const;
ReturnValue_t initialize(); ReturnValue_t initialize() override;
DeviceList devices; DeviceList devices;
ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize, ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize,
SerializeIF::Endianness streamEndianness) const override; SerializeIF::Endianness streamEndianness) const override;

View File

@ -43,7 +43,7 @@ class Service3Housekeeping : public CommandingServiceBase, public AcceptsHkPacke
CommandMessage* optionalNextCommand, object_id_t objectId, CommandMessage* optionalNextCommand, object_id_t objectId,
bool* isStep) override; bool* isStep) override;
virtual MessageQueueId_t getHkQueue() const; virtual MessageQueueId_t getHkQueue() const override;
private: private:
enum class Subservice { enum class Subservice {

View File

@ -155,18 +155,18 @@ class Subsystem : public SubsystemBase, public HasModeSequenceIF {
ReturnValue_t deleteTable(Mode_t id); ReturnValue_t deleteTable(Mode_t id);
virtual void performChildOperation(); virtual void performChildOperation() override;
virtual ReturnValue_t handleCommandMessage(CommandMessage *message); virtual ReturnValue_t handleCommandMessage(CommandMessage *message) override;
bool isFallbackSequence(Mode_t SequenceId); bool isFallbackSequence(Mode_t SequenceId);
bool isTableUsed(Mode_t tableId); bool isTableUsed(Mode_t tableId);
virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
uint32_t *msToReachTheMode); uint32_t *msToReachTheMode) override;
virtual void startTransition(Mode_t mode, Submode_t submode); virtual void startTransition(Mode_t mode, Submode_t submode) override;
void sendSerializablesAsCommandMessage(Command_t command, SerializeIF **elements, uint8_t count); void sendSerializablesAsCommandMessage(Command_t command, SerializeIF **elements, uint8_t count);

View File

@ -137,9 +137,9 @@ class SubsystemBase : public SystemObject,
virtual void getMode(Mode_t *mode, Submode_t *submode) override; virtual void getMode(Mode_t *mode, Submode_t *submode) override;
virtual void setToExternalControl(); virtual void setToExternalControl() override;
virtual void announceMode(bool recursive); virtual void announceMode(bool recursive) override;
virtual void modeChanged(); virtual void modeChanged();
}; };

View File

@ -6,10 +6,6 @@
#include "fsfw/FSFW.h" #include "fsfw/FSFW.h"
CCSDSTime::CCSDSTime() {}
CCSDSTime::~CCSDSTime() {}
ReturnValue_t CCSDSTime::convertToCcsds(Ccs_seconds* to, const Clock::TimeOfDay_t* from) { ReturnValue_t CCSDSTime::convertToCcsds(Ccs_seconds* to, const Clock::TimeOfDay_t* from) {
ReturnValue_t result = checkTimeOfDay(from); ReturnValue_t result = checkTimeOfDay(from);
if (result != RETURN_OK) { if (result != RETURN_OK) {
@ -428,7 +424,7 @@ ReturnValue_t CCSDSTime::convertFromCUC(timeval* to, const uint8_t* from, size_t
from++; from++;
ReturnValue_t result = convertFromCUC(to, pField, from, foundLength, maxLength - 1); ReturnValue_t result = convertFromCUC(to, pField, from, foundLength, maxLength - 1);
if (result == HasReturnvaluesIF::RETURN_OK) { if (result == HasReturnvaluesIF::RETURN_OK) {
if (foundLength != NULL) { if (foundLength != nullptr) {
*foundLength += 1; *foundLength += 1;
} }
} }
@ -588,18 +584,18 @@ ReturnValue_t CCSDSTime::convertFromCUC(timeval* to, uint8_t pField, const uint8
uint8_t nCoarse = ((pField & 0b1100) >> 2) + 1; uint8_t nCoarse = ((pField & 0b1100) >> 2) + 1;
uint8_t nFine = (pField & 0b11); uint8_t nFine = (pField & 0b11);
size_t totalLength = nCoarse + nFine; size_t totalLength = nCoarse + nFine;
if (foundLength != NULL) { if (foundLength != nullptr) {
*foundLength = totalLength; *foundLength = totalLength;
} }
if (totalLength > maxLength) { if (totalLength > maxLength) {
return LENGTH_MISMATCH; return LENGTH_MISMATCH;
} }
for (int count = 0; count < nCoarse; count++) { for (int count = nCoarse; count > 0; count--) {
secs += *from << ((nCoarse * 8 - 8) * (1 + count)); secs += *from << (count * 8 - 8);
from++; from++;
} }
for (int count = 0; count < nFine; count++) { for (int count = nFine; count > 0; count--) {
subSeconds += *from << ((nFine * 8 - 8) * (1 + count)); subSeconds += *from << (count * 8 - 8);
from++; from++;
} }
// Move to POSIX epoch. // Move to POSIX epoch.

View File

@ -161,18 +161,37 @@ class CCSDSTime : public HasReturnvaluesIF {
*/ */
static ReturnValue_t convertFromCcsds(timeval *to, uint8_t const *from, size_t *foundLength, static ReturnValue_t convertFromCcsds(timeval *to, uint8_t const *from, size_t *foundLength,
size_t maxLength); size_t maxLength);
/**
* @brief Currently unsupported conversion due to leapseconds
*
* @param to Time Of Day (UTC)
* @param from Buffer to take the CUC from
* @param length Length of buffer
* @return ReturnValue_t UNSUPPORTED_TIME_FORMAT in any case ATM
*/
static ReturnValue_t convertFromCUC(Clock::TimeOfDay_t *to, uint8_t const *from, uint8_t length); static ReturnValue_t convertFromCUC(Clock::TimeOfDay_t *to, uint8_t const *from, uint8_t length);
/**
* @brief Converts from CCSDS CUC to timeval
*
* If input is CCSDS Epoch this is TAI! -> No leapsecond support.
*
* Currently, it only supports seconds + 2 Byte Subseconds (1/65536 seconds)
*
*
* @param to Timeval to write the result to
* @param from Buffer to read from
* @param foundLength Length found by this function (can be nullptr if unused)
* @param maxLength Max length of the buffer to be read
* @return ReturnValue_t - RETURN_OK if successful
* - LENGTH_MISMATCH if expected length is larger than maxLength
*/
static ReturnValue_t convertFromCUC(timeval *to, uint8_t const *from, size_t *foundLength, static ReturnValue_t convertFromCUC(timeval *to, uint8_t const *from, size_t *foundLength,
size_t maxLength); size_t maxLength);
static ReturnValue_t convertFromCUC(timeval *to, uint8_t pField, uint8_t const *from, static ReturnValue_t convertFromCUC(timeval *to, uint8_t pField, uint8_t const *from,
size_t *foundLength, size_t maxLength); size_t *foundLength, size_t maxLength);
static ReturnValue_t convertFromCCS(timeval *to, uint8_t const *from, size_t *foundLength, static ReturnValue_t convertFromCCS(timeval *to, uint8_t const *from, size_t *foundLength,
size_t maxLength); size_t maxLength);
static ReturnValue_t convertFromCCS(timeval *to, uint8_t pField, uint8_t const *from, static ReturnValue_t convertFromCCS(timeval *to, uint8_t pField, uint8_t const *from,
size_t *foundLength, size_t maxLength); size_t *foundLength, size_t maxLength);
@ -192,8 +211,8 @@ class CCSDSTime : public HasReturnvaluesIF {
static uint32_t subsecondsToMicroseconds(uint16_t subseconds); static uint32_t subsecondsToMicroseconds(uint16_t subseconds);
private: private:
CCSDSTime(); CCSDSTime(){};
virtual ~CCSDSTime(); virtual ~CCSDSTime(){};
/** /**
* checks a ccs time stream for validity * checks a ccs time stream for validity
* *

View File

@ -1,8 +1,13 @@
#include "fsfw/timemanager/Countdown.h" #include "fsfw/timemanager/Countdown.h"
Countdown::Countdown(uint32_t initialTimeout) : timeout(initialTimeout) { Countdown::Countdown(uint32_t initialTimeout, bool startImmediately) : timeout(initialTimeout) {
if (startImmediately) {
setTimeout(initialTimeout); setTimeout(initialTimeout);
} }
else {
timeout = initialTimeout;
}
}
Countdown::~Countdown() {} Countdown::~Countdown() {}

View File

@ -26,8 +26,9 @@ class Countdown {
* Otherwise a call to hasTimedOut might return True. * Otherwise a call to hasTimedOut might return True.
* *
* @param initialTimeout Countdown duration in milliseconds * @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(); ~Countdown();
/** /**
* Call to set a new countdown duration. * Call to set a new countdown duration.

View File

@ -19,8 +19,8 @@ SpacePacket::SpacePacket(uint16_t packetDataLength, bool isTelecommand, uint16_t
SpacePacket::~SpacePacket(void) {} SpacePacket::~SpacePacket(void) {}
bool SpacePacket::addWholeData(const uint8_t* p_Data, uint32_t packet_size) { bool SpacePacket::addWholeData(const uint8_t* p_Data, uint32_t packet_size) {
if (packet_size <= sizeof(this->data)) { if (packet_size <= sizeof(this->localData)) {
memcpy(&this->localData.byteStream, p_Data, packet_size); memcpy(this->localData.byteStream, p_Data, packet_size);
return true; return true;
} else { } else {
return false; return false;

View File

@ -95,7 +95,7 @@ class CommandingServiceBase : public SystemObject,
*/ */
virtual ReturnValue_t performOperation(uint8_t opCode) override; virtual ReturnValue_t performOperation(uint8_t opCode) override;
virtual uint16_t getIdentifier(); virtual uint16_t getIdentifier() override;
/** /**
* Returns the requestQueue MessageQueueId_t * Returns the requestQueue MessageQueueId_t
@ -104,7 +104,7 @@ class CommandingServiceBase : public SystemObject,
* *
* @return requestQueue messageQueueId_t * @return requestQueue messageQueueId_t
*/ */
virtual MessageQueueId_t getRequestQueue(); virtual MessageQueueId_t getRequestQueue() override;
/** /**
* Returns the commandQueue MessageQueueId_t * Returns the commandQueue MessageQueueId_t

View File

@ -179,6 +179,27 @@ TEST_CASE("CCSDSTime Tests", "[TestCCSDSTime]") {
CHECK(todFromCCSDS.second == time.second); CHECK(todFromCCSDS.second == time.second);
CHECK(todFromCCSDS.usecond == 123000); CHECK(todFromCCSDS.usecond == 123000);
} }
SECTION("CUC") {
timeval to;
// seconds = 0x771E960F, microseconds = 0x237
// microseconds = 567000
// This gives 37158.912 1/65536 seconds -> rounded to 37159 -> 0x9127
// This results in -> 567001 us
std::array<uint8_t, 7> cucBuffer = {
CCSDSTime::P_FIELD_CUC_6B_CCSDS, 0x77, 0x1E, 0x96, 0x0F, 0x91, 0x27};
size_t foundLength = 0;
auto result = CCSDSTime::convertFromCUC(&to, cucBuffer.data(), &foundLength, cucBuffer.size());
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
REQUIRE(foundLength == 7);
REQUIRE(to.tv_sec == 1619801999); // TAI (no leap seconds)
REQUIRE(to.tv_usec == 567001);
Clock::TimeOfDay_t tod;
result = CCSDSTime::convertFromCUC(&tod, cucBuffer.data(), cucBuffer.size());
// This test must be changed if this is ever going to be implemented
REQUIRE(result == CCSDSTime::UNSUPPORTED_TIME_FORMAT);
}
SECTION("CCSDS Failures") { SECTION("CCSDS Failures") {
Clock::TimeOfDay_t time; Clock::TimeOfDay_t time;
time.year = 2020; time.year = 2020;