diff --git a/CHANGELOG.md b/CHANGELOG.md index 9685b37dd..a500f27dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## Changes +- Bump C++ required version to C++17. Every project which uses the FSFW and every modern + compiler supports it + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/622 - HAL Linux SPI: Set the Clock Default State when setting new SPI speed and mode PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/573 @@ -28,6 +31,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/). creation call. It allows passing context information and an arbitrary user argument into the message queue. Also streamlined and simplified `MessageQueue` implementation for all OSALs PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/583 +- Clock: + - `timeval` to `TimeOfDay_t` + - Added Mutex for gmtime calls: (compare http://www.opengate.at/blog/2020/01/timeless/) + - Moved the statics used by Clock in ClockCommon.cpp to this file + - Better check for leap seconds + - Added Unittests for Clock (only getter) ## Removed @@ -46,8 +55,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## Fixed +- Move some CMake directives further up top so they are not ignored + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/621 - Small bugfix in STM32 HAL for SPI PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/599 +- HAL GPIO: Improved error checking in `LinuxLibgpioIF::configureGpios(...)`. If a GPIO + configuration fails, the function will exit prematurely with a dedicated error code + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/602 # [v4.0.0] diff --git a/CMakeLists.txt b/CMakeLists.txt index d8ca812e0..1df1008b9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,15 @@ cmake_minimum_required(VERSION 3.13) +set(LIB_FSFW_NAME fsfw) +project(${LIB_FSFW_NAME}) + +if(NOT CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 17) + set(CMAKE_CXX_STANDARD_REQUIRED True) +elseif(${CMAKE_CXX_STANDARD} LESS 17) + message(FATAL_ERROR "Compiling the FSFW requires a minimum of C++17 support") +endif() + set(FSFW_VERSION 4) set(FSFW_SUBVERSION 0) set(FSFW_REVISION 0) @@ -10,14 +20,15 @@ set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) set(FSFW_ETL_LIB_MAJOR_VERSION 20 CACHE STRING "ETL library major version requirement" ) -set(FSFW_ETL_LIB_VERSION ${FSFW_ETL_LIB_MAJOR_VERSION}.27.2 CACHE STRING +set(FSFW_ETL_LIB_VERSION ${FSFW_ETL_LIB_MAJOR_VERSION}.27.3 CACHE STRING "ETL library exact version requirement" ) +set(FSFW_ETL_LINK_TARGET etl::etl) set(FSFW_CATCH2_LIB_MAJOR_VERSION 3 CACHE STRING "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" ) @@ -54,11 +65,10 @@ option(FSFW_ADD_TMSTORAGE "Compile with tm storage components" OFF) # Contrib sources option(FSFW_ADD_SGP4_PROPAGATOR "Add SGP4 propagator code" OFF) -set(LIB_FSFW_NAME fsfw) + set(FSFW_TEST_TGT fsfw-tests) set(FSFW_DUMMY_TGT fsfw-dummy) -project(${LIB_FSFW_NAME}) add_library(${LIB_FSFW_NAME}) if(FSFW_BUILD_UNITTESTS) @@ -76,9 +86,7 @@ if(FSFW_BUILD_UNITTESTS) GIT_TAG ${FSFW_CATCH2_LIB_VERSION} ) - FetchContent_MakeAvailable(Catch2) - #fixes regression -preview4, to be confirmed in later releases - set_target_properties(Catch2 PROPERTIES DEBUG_POSTFIX "") + list(APPEND FSFW_FETCH_CONTENT_TARGETS Catch2) endif() set(FSFW_CONFIG_PATH tests/src/fsfw_tests/unit/testcfg) @@ -123,7 +131,22 @@ if(NOT ${FSFW_ETL_LIB_NAME}_FOUND) GIT_TAG ${FSFW_ETL_LIB_VERSION} ) - FetchContent_MakeAvailable(etl) + list(APPEND FSFW_FETCH_CONTENT_TARGETS ${FSFW_ETL_LIB_NAME}) +endif() + +# The documentation for FetchContent recommends declaring all the dependencies +# 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") @@ -138,12 +161,6 @@ target_include_directories(${LIB_FSFW_NAME} INTERFACE ${CMAKE_CURRENT_BINARY_DIR} ) -if(NOT CMAKE_CXX_STANDARD) - set(CMAKE_CXX_STANDARD 11) - set(CMAKE_CXX_STANDARD_REQUIRED True) -elseif(${CMAKE_CXX_STANDARD} LESS 11) - message(FATAL_ERROR "Compiling the FSFW requires a minimum of C++11 support") -endif() # Backwards comptability if(OS_FSFW AND NOT FSFW_OSAL) @@ -387,7 +404,7 @@ target_compile_options(${LIB_FSFW_NAME} PRIVATE ) target_link_libraries(${LIB_FSFW_NAME} PRIVATE - ${FSFW_ETL_LIB_NAME} + ${FSFW_ETL_LINK_TARGET} ${FSFW_ADDITIONAL_LINK_LIBS} ) diff --git a/automation/Dockerfile b/automation/Dockerfile index 9df67fc82..0eb98fbb1 100644 --- a/automation/Dockerfile +++ b/automation/Dockerfile @@ -6,3 +6,9 @@ RUN apt-get --yes upgrade #tzdata is a dependency, won't install otherwise ARG DEBIAN_FRONTEND=noninteractive 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 diff --git a/automation/Jenkinsfile b/automation/Jenkinsfile index d1459e52f..6abf56366 100644 --- a/automation/Jenkinsfile +++ b/automation/Jenkinsfile @@ -3,7 +3,7 @@ pipeline { BUILDDIR = 'build-tests' } agent { - docker { image 'fsfw-ci:d1'} + docker { image 'fsfw-ci:d2'} } stages { stage('Clean') { diff --git a/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp b/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp index 52b6dc07b..644b488dd 100644 --- a/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp +++ b/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp @@ -1,9 +1,9 @@ #include "MgmLIS3MDLHandler.h" -#include "fsfw/datapool/PoolReadGuard.h" - #include +#include "fsfw/datapool/PoolReadGuard.h" + MgmLIS3MDLHandler::MgmLIS3MDLHandler(object_id_t objectId, object_id_t deviceCommunication, CookieIF *comCookie, uint32_t transitionDelay) : DeviceHandlerBase(objectId, deviceCommunication, comCookie), diff --git a/hal/src/fsfw_hal/linux/CMakeLists.txt b/hal/src/fsfw_hal/linux/CMakeLists.txt index 56d4bf489..f6d1a4603 100644 --- a/hal/src/fsfw_hal/linux/CMakeLists.txt +++ b/hal/src/fsfw_hal/linux/CMakeLists.txt @@ -12,9 +12,14 @@ if(FSFW_HAL_LINUX_ADD_PERIPHERAL_DRIVERS) if(FSFW_HAL_LINUX_ADD_LIBGPIOD) add_subdirectory(gpio) endif() - add_subdirectory(spi) - add_subdirectory(i2c) 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() add_subdirectory(uio) diff --git a/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp b/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp index 3b9a21f7f..f46ad3865 100644 --- a/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp +++ b/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp @@ -44,6 +44,7 @@ ReturnValue_t LinuxLibgpioIF::addGpios(GpioCookie* gpioCookie) { } ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) { + ReturnValue_t result = RETURN_OK; for (auto& gpioConfig : mapToAdd) { auto& gpioType = gpioConfig.second->gpioType; switch (gpioType) { @@ -55,7 +56,7 @@ ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) { if (regularGpio == nullptr) { return GPIO_INVALID_INSTANCE; } - configureGpioByChip(gpioConfig.first, *regularGpio); + result = configureGpioByChip(gpioConfig.first, *regularGpio); break; } case (gpio::GpioTypes::GPIO_REGULAR_BY_LABEL): { @@ -63,7 +64,7 @@ ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) { if (regularGpio == nullptr) { return GPIO_INVALID_INSTANCE; } - configureGpioByLabel(gpioConfig.first, *regularGpio); + result = configureGpioByLabel(gpioConfig.first, *regularGpio); break; } case (gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME): { @@ -71,7 +72,7 @@ ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) { if (regularGpio == nullptr) { return GPIO_INVALID_INSTANCE; } - configureGpioByLineName(gpioConfig.first, *regularGpio); + result = configureGpioByLineName(gpioConfig.first, *regularGpio); break; } case (gpio::GpioTypes::CALLBACK): { @@ -83,8 +84,11 @@ ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) { gpioCallback->initValue, gpioCallback->callbackArgs); } } + if (result != RETURN_OK) { + return GPIO_INIT_FAILED; + } } - return RETURN_OK; + return result; } ReturnValue_t LinuxLibgpioIF::configureGpioByLabel(gpioId_t gpioId, diff --git a/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.h b/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.h index 7d49e6e20..fcc9c7753 100644 --- a/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.h +++ b/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.h @@ -29,6 +29,8 @@ class LinuxLibgpioIF : public GpioIF, public SystemObject { HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 4); static constexpr ReturnValue_t GPIO_DUPLICATE_DETECTED = HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 5); + static constexpr ReturnValue_t GPIO_INIT_FAILED = + HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 6); LinuxLibgpioIF(object_id_t objectId); virtual ~LinuxLibgpioIF(); diff --git a/hal/src/fsfw_hal/linux/spi/SpiCookie.cpp b/hal/src/fsfw_hal/linux/spi/SpiCookie.cpp index e6271c5ee..c94fcdf1b 100644 --- a/hal/src/fsfw_hal/linux/spi/SpiCookie.cpp +++ b/hal/src/fsfw_hal/linux/spi/SpiCookie.cpp @@ -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, const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed) diff --git a/hal/src/fsfw_hal/linux/uart/UartComIF.cpp b/hal/src/fsfw_hal/linux/uart/UartComIF.cpp index 5aa721381..72c79df65 100644 --- a/hal/src/fsfw_hal/linux/uart/UartComIF.cpp +++ b/hal/src/fsfw_hal/linux/uart/UartComIF.cpp @@ -265,6 +265,7 @@ void UartComIF::configureBaudrate(struct termios* options, UartCookie* uartCooki cfsetispeed(options, B230400); cfsetospeed(options, B230400); break; +#ifndef __APPLE__ case UartBaudRate::RATE_460800: cfsetispeed(options, B460800); cfsetospeed(options, B460800); @@ -313,6 +314,7 @@ void UartComIF::configureBaudrate(struct termios* options, UartCookie* uartCooki cfsetispeed(options, B4000000); cfsetospeed(options, B4000000); break; +#endif // ! __APPLE__ default: #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "UartComIF::configureBaudrate: Baudrate not supported" << std::endl; diff --git a/hal/src/fsfw_hal/linux/uart/UartCookie.cpp b/hal/src/fsfw_hal/linux/uart/UartCookie.cpp index aa2dd2146..3fedc9d44 100644 --- a/hal/src/fsfw_hal/linux/uart/UartCookie.cpp +++ b/hal/src/fsfw_hal/linux/uart/UartCookie.cpp @@ -24,9 +24,7 @@ void UartCookie::setParityEven() { parity = Parity::EVEN; } Parity UartCookie::getParity() const { return parity; } -void UartCookie::setBitsPerWord(BitsPerWord bitsPerWord_) { - bitsPerWord = bitsPerWord_; -} +void UartCookie::setBitsPerWord(BitsPerWord bitsPerWord_) { bitsPerWord = bitsPerWord_; } BitsPerWord UartCookie::getBitsPerWord() const { return bitsPerWord; } diff --git a/src/fsfw/cfdp/pdu/HeaderSerializer.h b/src/fsfw/cfdp/pdu/HeaderSerializer.h index 8f2fc3fdd..1de97d63d 100644 --- a/src/fsfw/cfdp/pdu/HeaderSerializer.h +++ b/src/fsfw/cfdp/pdu/HeaderSerializer.h @@ -44,7 +44,7 @@ class HeaderSerializer : public SerializeIF, public PduHeaderIF { cfdp::WidthInBytes getLenEntityIds() const override; cfdp::WidthInBytes getLenSeqNum() const override; cfdp::SegmentMetadataFlag getSegmentMetadataFlag() const override; - bool hasSegmentMetadataFlag() const; + bool hasSegmentMetadataFlag() const override; void setSegmentationControl(cfdp::SegmentationControl); void getSourceId(cfdp::EntityId& sourceId) const override; diff --git a/src/fsfw/container/FixedArrayList.h b/src/fsfw/container/FixedArrayList.h index c09a421eb..26a739212 100644 --- a/src/fsfw/container/FixedArrayList.h +++ b/src/fsfw/container/FixedArrayList.h @@ -9,7 +9,7 @@ */ template class FixedArrayList : public ArrayList { -#if !defined(_MSC_VER) +#if !defined(_MSC_VER) && !defined(__clang__) static_assert(MAX_SIZE <= (std::pow(2, sizeof(count_t) * 8) - 1), "count_t is not large enough to hold MAX_SIZE"); #endif diff --git a/src/fsfw/container/HybridIterator.h b/src/fsfw/container/HybridIterator.h index e8b24a3d6..ad000ec25 100644 --- a/src/fsfw/container/HybridIterator.h +++ b/src/fsfw/container/HybridIterator.h @@ -10,16 +10,23 @@ class HybridIterator : public LinkedElement::Iterator, public ArrayList::Iterator *iter) - : LinkedElement::Iterator(*iter), value(iter->value), linked(true) {} + : LinkedElement::Iterator(*iter), linked(true) { + if (iter != nullptr) { + value = iter->value; + } + } - HybridIterator(LinkedElement *start) - : LinkedElement::Iterator(start), value(start->value), linked(true) {} + HybridIterator(LinkedElement *start) : LinkedElement::Iterator(start), linked(true) { + if (start != nullptr) { + value = start->value; + } + } HybridIterator(typename ArrayList::Iterator start, typename ArrayList::Iterator end) : ArrayList::Iterator(start), value(start.value), linked(false), end(end.value) { if (value == this->end) { - value = NULL; + value = nullptr; } } diff --git a/src/fsfw/controller/ControllerBase.h b/src/fsfw/controller/ControllerBase.h index 7032f8171..227b859bf 100644 --- a/src/fsfw/controller/ControllerBase.h +++ b/src/fsfw/controller/ControllerBase.h @@ -55,7 +55,7 @@ class ControllerBase : public HasModesIF, virtual void performControlOperation() = 0; virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, - uint32_t *msToReachTheMode) = 0; + uint32_t *msToReachTheMode) override = 0; const object_id_t parentId; @@ -80,9 +80,9 @@ class ControllerBase : public HasModesIF, /** Mode helpers */ virtual void modeChanged(Mode_t mode, Submode_t submode); - virtual void startTransition(Mode_t mode, Submode_t submode); - virtual void getMode(Mode_t *mode, Submode_t *submode); - virtual void setToExternalControl(); + virtual void startTransition(Mode_t mode, Submode_t submode) override; + virtual void getMode(Mode_t *mode, Submode_t *submode) override; + virtual void setToExternalControl() override; virtual void announceMode(bool recursive); /** HK helpers */ virtual void changeHK(Mode_t mode, Submode_t submode, bool enable); diff --git a/src/fsfw/datapool/PoolDataSetBase.h b/src/fsfw/datapool/PoolDataSetBase.h index 1b4bacdad..dc6ec135a 100644 --- a/src/fsfw/datapool/PoolDataSetBase.h +++ b/src/fsfw/datapool/PoolDataSetBase.h @@ -109,7 +109,7 @@ class PoolDataSetBase : public PoolDataSetIF, public SerializeIF, public HasRetu */ virtual ReturnValue_t unlockDataPool() override; - virtual uint16_t getFillCount() const; + virtual uint16_t getFillCount() const override; /* SerializeIF implementations */ virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, const size_t maxSize, diff --git a/src/fsfw/datapoollocal/LocalDataPoolManager.cpp b/src/fsfw/datapoollocal/LocalDataPoolManager.cpp index 6053bd438..781d8f71f 100644 --- a/src/fsfw/datapoollocal/LocalDataPoolManager.cpp +++ b/src/fsfw/datapoollocal/LocalDataPoolManager.cpp @@ -787,9 +787,9 @@ ReturnValue_t LocalDataPoolManager::generateSetStructurePacket(sid_t sid, bool i // Serialize set packet into store. size_t size = 0; result = setPacket.serialize(&storePtr, &size, expectedSize, SerializeIF::Endianness::BIG); - if(result != HasReturnvaluesIF::RETURN_OK) { - ipcStore->deleteData(storeId); - return result; + if (result != HasReturnvaluesIF::RETURN_OK) { + ipcStore->deleteData(storeId); + return result; } if (expectedSize != size) { printWarningOrError(sif::OutputTypes::OUT_WARNING, "generateSetStructurePacket", @@ -806,8 +806,8 @@ ReturnValue_t LocalDataPoolManager::generateSetStructurePacket(sid_t sid, bool i } result = hkQueue->reply(&reply); - if(result != HasReturnvaluesIF::RETURN_OK) { - ipcStore->deleteData(storeId); + if (result != HasReturnvaluesIF::RETURN_OK) { + ipcStore->deleteData(storeId); } return result; } diff --git a/src/fsfw/datapoollocal/LocalPoolDataSetBase.cpp b/src/fsfw/datapoollocal/LocalPoolDataSetBase.cpp index 4a0762126..62fdb184f 100644 --- a/src/fsfw/datapoollocal/LocalPoolDataSetBase.cpp +++ b/src/fsfw/datapoollocal/LocalPoolDataSetBase.cpp @@ -94,13 +94,14 @@ ReturnValue_t LocalPoolDataSetBase::serializeWithValidityBuffer( ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; const uint8_t validityMaskSize = std::ceil(static_cast(fillCount) / 8.0); uint8_t *validityPtr = nullptr; -#ifdef _MSC_VER - /* Use a std::vector here because MSVC will (rightly) not create a fixed size array - with a non constant size specifier */ - std::vector validityMask(validityMaskSize); +#if defined(_MSC_VER) || defined(__clang__) + // Use a std::vector here because MSVC will (rightly) not create a fixed size array + // with a non constant size specifier. The Apple compiler (LLVM) will not accept + // the initialization of a variable sized array + std::vector validityMask(validityMaskSize, 0); validityPtr = validityMask.data(); #else - uint8_t validityMask[validityMaskSize] = {0}; + uint8_t validityMask[validityMaskSize] = {}; validityPtr = validityMask; #endif uint8_t validBufferIndex = 0; diff --git a/src/fsfw/datapoollocal/LocalPoolObjectBase.h b/src/fsfw/datapoollocal/LocalPoolObjectBase.h index 56e190df1..b2ffa4c18 100644 --- a/src/fsfw/datapoollocal/LocalPoolObjectBase.h +++ b/src/fsfw/datapoollocal/LocalPoolObjectBase.h @@ -23,8 +23,8 @@ class LocalPoolObjectBase : public PoolVariableIF, public HasReturnvaluesIF, pub LocalPoolObjectBase(object_id_t poolOwner, lp_id_t poolId, DataSetIF* dataSet = nullptr, pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE); - void setReadWriteMode(pool_rwm_t newReadWriteMode); - pool_rwm_t getReadWriteMode() const; + void setReadWriteMode(pool_rwm_t newReadWriteMode) override; + pool_rwm_t getReadWriteMode() const override; bool isValid() const override; void setValid(bool valid) override; diff --git a/src/fsfw/devicehandlers/DeviceHandlerBase.cpp b/src/fsfw/devicehandlers/DeviceHandlerBase.cpp index 0e2802ac1..dd9bd5d7d 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerBase.cpp +++ b/src/fsfw/devicehandlers/DeviceHandlerBase.cpp @@ -458,16 +458,15 @@ size_t DeviceHandlerBase::getNextReplyLength(DeviceCommandId_t commandId) { DeviceCommandId_t replyId = NO_COMMAND_ID; DeviceCommandMap::iterator command = cookieInfo.pendingCommand; if (command->second.useAlternativeReplyId) { - replyId = command->second.alternativeReplyId; - } - else { - replyId = commandId; + replyId = command->second.alternativeReplyId; + } else { + replyId = commandId; } DeviceReplyIter iter = deviceReplyMap.find(replyId); if (iter != deviceReplyMap.end()) { - if (iter->second.delayCycles != 0) { - return iter->second.replyLen; - } + if (iter->second.delayCycles != 0) { + return iter->second.replyLen; + } } return 0; } diff --git a/src/fsfw/devicehandlers/DeviceHandlerBase.h b/src/fsfw/devicehandlers/DeviceHandlerBase.h index 5e974831e..5808b8e69 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerBase.h +++ b/src/fsfw/devicehandlers/DeviceHandlerBase.h @@ -163,7 +163,7 @@ class DeviceHandlerBase : public DeviceHandlerIF, * @param counter Specifies which Action to perform * @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 @@ -173,7 +173,7 @@ class DeviceHandlerBase : public DeviceHandlerIF, * Calls fillCommandAndReplyMap(). * @return */ - virtual ReturnValue_t initialize(); + virtual ReturnValue_t initialize() override; /** * @brief Intialization steps performed after all tasks have been created. @@ -1058,11 +1058,11 @@ class DeviceHandlerBase : public DeviceHandlerIF, * @param parameter1 Optional parameter 1 * @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. */ - 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. diff --git a/src/fsfw/globalfunctions/matching/MatchTree.h b/src/fsfw/globalfunctions/matching/MatchTree.h index f7775d45b..ec98e22a7 100644 --- a/src/fsfw/globalfunctions/matching/MatchTree.h +++ b/src/fsfw/globalfunctions/matching/MatchTree.h @@ -25,7 +25,7 @@ class MatchTree : public SerializeableMatcherIF, public BinaryTree>(root.element), maxDepth(maxDepth) {} MatchTree() : BinaryTree>(), maxDepth(-1) {} virtual ~MatchTree() {} - virtual bool match(T number) { return matchesTree(number); } + virtual bool match(T number) override { return matchesTree(number); } bool matchesTree(T number) { iterator iter = this->begin(); if (iter == this->end()) { @@ -179,6 +179,9 @@ class MatchTree : public SerializeableMatcherIF, public BinaryTreematch(number); if (isMatch) { if (iter.left() == this->end()) { diff --git a/src/fsfw/globalfunctions/matching/RangeMatcher.h b/src/fsfw/globalfunctions/matching/RangeMatcher.h index 4e1f39222..c5962ab3e 100644 --- a/src/fsfw/globalfunctions/matching/RangeMatcher.h +++ b/src/fsfw/globalfunctions/matching/RangeMatcher.h @@ -15,7 +15,7 @@ class RangeMatcher : public SerializeableMatcherIF { RangeMatcher(T lowerBound, T upperBound, bool inverted = false) : inverted(inverted), lowerBound(lowerBound), upperBound(upperBound) {} - bool match(T input) { + bool match(T input) override { if (inverted) { return !doMatch(input); } else { diff --git a/src/fsfw/ipc/MessageQueueBase.cpp b/src/fsfw/ipc/MessageQueueBase.cpp index 1b0934ff3..c43670ed5 100644 --- a/src/fsfw/ipc/MessageQueueBase.cpp +++ b/src/fsfw/ipc/MessageQueueBase.cpp @@ -1,9 +1,9 @@ #include "MessageQueueBase.h" -MessageQueueBase::MessageQueueBase(MessageQueueId_t id, MessageQueueId_t defaultDest, - MqArgs* args): id(id) { +MessageQueueBase::MessageQueueBase(MessageQueueId_t id, MessageQueueId_t defaultDest, MqArgs* args) + : id(id) { this->defaultDest = defaultDest; - if(args != nullptr) { + if (args != nullptr) { this->args = *args; } } @@ -23,35 +23,25 @@ ReturnValue_t MessageQueueBase::reply(MessageQueueMessageIF* message) { } ReturnValue_t MessageQueueBase::receiveMessage(MessageQueueMessageIF* message, - MessageQueueId_t* receivedFrom) { + MessageQueueId_t* receivedFrom) { ReturnValue_t status = this->receiveMessage(message); *receivedFrom = this->last; return status; } -MessageQueueId_t MessageQueueBase::getLastPartner() const { - return last; -} +MessageQueueId_t MessageQueueBase::getLastPartner() const { return last; } -MessageQueueId_t MessageQueueBase::getId() const { - return id; -} +MessageQueueId_t MessageQueueBase::getId() const { return id; } -MqArgs& MessageQueueBase::getMqArgs() { - return args; -} +MqArgs& MessageQueueBase::getMqArgs() { return args; } void MessageQueueBase::setDefaultDestination(MessageQueueId_t defaultDestination) { this->defaultDest = defaultDestination; } -MessageQueueId_t MessageQueueBase::getDefaultDestination() const { - return defaultDest; -} +MessageQueueId_t MessageQueueBase::getDefaultDestination() const { return defaultDest; } -bool MessageQueueBase::isDefaultDestinationSet() const { - return (defaultDest != NO_QUEUE); -} +bool MessageQueueBase::isDefaultDestinationSet() const { return (defaultDest != NO_QUEUE); } ReturnValue_t MessageQueueBase::sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message, bool ignoreFault) { diff --git a/src/fsfw/ipc/MessageQueueBase.h b/src/fsfw/ipc/MessageQueueBase.h index 8313f69ac..942b61217 100644 --- a/src/fsfw/ipc/MessageQueueBase.h +++ b/src/fsfw/ipc/MessageQueueBase.h @@ -1,11 +1,11 @@ #ifndef FSFW_SRC_FSFW_IPC_MESSAGEQUEUEBASE_H_ #define FSFW_SRC_FSFW_IPC_MESSAGEQUEUEBASE_H_ -#include #include +#include -class MessageQueueBase: public MessageQueueIF { -public: +class MessageQueueBase : public MessageQueueIF { + public: MessageQueueBase(MessageQueueId_t id, MessageQueueId_t defaultDest, MqArgs* mqArgs); virtual ~MessageQueueBase(); @@ -17,25 +17,24 @@ public: virtual MessageQueueId_t getDefaultDestination() const override; virtual bool isDefaultDestinationSet() const override; virtual ReturnValue_t sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message, - bool ignoreFault) override; + bool ignoreFault) override; virtual ReturnValue_t sendToDefault(MessageQueueMessageIF* message) override; virtual ReturnValue_t reply(MessageQueueMessageIF* message) override; virtual ReturnValue_t receiveMessage(MessageQueueMessageIF* message, - MessageQueueId_t* receivedFrom) override; - virtual ReturnValue_t sendToDefaultFrom(MessageQueueMessageIF* message, - MessageQueueId_t sentFrom, bool ignoreFault = false) override; + MessageQueueId_t* receivedFrom) override; + virtual ReturnValue_t sendToDefaultFrom(MessageQueueMessageIF* message, MessageQueueId_t sentFrom, + bool ignoreFault = false) override; // OSAL specific, forward the abstract function virtual ReturnValue_t receiveMessage(MessageQueueMessageIF* message) = 0; virtual ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message, MessageQueueId_t sentFrom, bool ignoreFault = false) = 0; -protected: + + protected: MessageQueueId_t id = MessageQueueIF::NO_QUEUE; MessageQueueId_t last = MessageQueueIF::NO_QUEUE; MessageQueueId_t defaultDest = MessageQueueIF::NO_QUEUE; MqArgs args = {}; }; - - #endif /* FSFW_SRC_FSFW_IPC_MESSAGEQUEUEBASE_H_ */ diff --git a/src/fsfw/ipc/MessageQueueIF.h b/src/fsfw/ipc/MessageQueueIF.h index d7b6889b6..9532b2d61 100644 --- a/src/fsfw/ipc/MessageQueueIF.h +++ b/src/fsfw/ipc/MessageQueueIF.h @@ -2,6 +2,7 @@ #define FSFW_IPC_MESSAGEQUEUEIF_H_ #include + #include #include "../returnvalues/HasReturnvaluesIF.h" @@ -45,7 +46,8 @@ class MessageQueueIF { virtual ReturnValue_t reply(MessageQueueMessageIF* message) = 0; /** - * @brief This function reads available messages from the message queue and returns the sender. + * @brief This function reads available messages from the message queue and returns the + * sender. * @details * It works identically to the other receiveMessage call, but in addition * returns the sender's queue id. diff --git a/src/fsfw/monitoring/MonitoringMessageContent.h b/src/fsfw/monitoring/MonitoringMessageContent.h index 0ac455ebb..fb3ace3da 100644 --- a/src/fsfw/monitoring/MonitoringMessageContent.h +++ b/src/fsfw/monitoring/MonitoringMessageContent.h @@ -34,7 +34,7 @@ class MonitoringReportContent : public SerialLinkedListAdapter { SerializeElement limitValue; SerializeElement oldState; SerializeElement newState; - uint8_t rawTimestamp[TimeStamperIF::MISSION_TIMESTAMP_SIZE]; + uint8_t rawTimestamp[TimeStamperIF::MISSION_TIMESTAMP_SIZE] = {}; SerializeElement> timestampSerializer; TimeStamperIF* timeStamper; MonitoringReportContent() @@ -46,7 +46,6 @@ class MonitoringReportContent : public SerialLinkedListAdapter { limitValue(0), oldState(0), newState(0), - rawTimestamp({0}), timestampSerializer(rawTimestamp, sizeof(rawTimestamp)), timeStamper(NULL) { setAllNext(); diff --git a/src/fsfw/objectmanager/SystemObject.h b/src/fsfw/objectmanager/SystemObject.h index 6d5b83035..eeb68b8fb 100644 --- a/src/fsfw/objectmanager/SystemObject.h +++ b/src/fsfw/objectmanager/SystemObject.h @@ -48,9 +48,9 @@ class SystemObject : public SystemObjectIF { virtual ~SystemObject(); object_id_t getObjectId() const 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_ */ diff --git a/src/fsfw/osal/common/UdpTcPollingTask.cpp b/src/fsfw/osal/common/UdpTcPollingTask.cpp index ab982a3c8..38fb19211 100644 --- a/src/fsfw/osal/common/UdpTcPollingTask.cpp +++ b/src/fsfw/osal/common/UdpTcPollingTask.cpp @@ -16,11 +16,13 @@ //! Debugging preprocessor define. #define FSFW_UDP_RECV_WIRETAPPING_ENABLED 0 +const timeval UdpTcPollingTask::DEFAULT_TIMEOUT = {0, 500000}; + UdpTcPollingTask::UdpTcPollingTask(object_id_t objectId, object_id_t tmtcUdpBridge, size_t maxRecvSize, double timeoutSeconds) : SystemObject(objectId), tmtcBridgeId(tmtcUdpBridge) { - if (frameSize > 0) { - this->frameSize = frameSize; + if (maxRecvSize > 0) { + this->frameSize = maxRecvSize; } else { this->frameSize = DEFAULT_MAX_RECV_SIZE; } @@ -31,22 +33,20 @@ UdpTcPollingTask::UdpTcPollingTask(object_id_t objectId, object_id_t tmtcUdpBrid receptionBuffer.resize(this->frameSize); if (timeoutSeconds == -1) { - receptionTimeout = DEFAULT_TIMEOUT; + receptionTimeout = UdpTcPollingTask::DEFAULT_TIMEOUT; } else { receptionTimeout = timevalOperations::toTimeval(timeoutSeconds); } } -UdpTcPollingTask::~UdpTcPollingTask() {} - -ReturnValue_t UdpTcPollingTask::performOperation(uint8_t opCode) { +[[noreturn]] ReturnValue_t UdpTcPollingTask::performOperation(uint8_t opCode) { /* Sender Address is cached here. */ - struct sockaddr senderAddress; + struct sockaddr senderAddress {}; socklen_t senderAddressSize = sizeof(senderAddress); /* Poll for new UDP datagrams in permanent loop. */ while (true) { - int bytesReceived = + ssize_t bytesReceived = recvfrom(this->serverSocket, reinterpret_cast(receptionBuffer.data()), frameSize, receptionFlags, &senderAddress, &senderAddressSize); if (bytesReceived == SOCKET_ERROR) { @@ -70,7 +70,6 @@ ReturnValue_t UdpTcPollingTask::performOperation(uint8_t opCode) { } tmtcBridge->checkAndSetClientAddress(senderAddress); } - return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t UdpTcPollingTask::handleSuccessfullTcRead(size_t bytesRead) { @@ -155,7 +154,7 @@ void UdpTcPollingTask::setTimeout(double timeoutSeconds) { #endif } #elif defined(PLATFORM_UNIX) - timeval tval; + timeval tval {}; tval = timevalOperations::toTimeval(timeoutSeconds); int result = setsockopt(serverSocket, SOL_SOCKET, SO_RCVTIMEO, &tval, sizeof(receptionTimeout)); if (result == -1) { diff --git a/src/fsfw/osal/common/UdpTcPollingTask.h b/src/fsfw/osal/common/UdpTcPollingTask.h index afcd32a1b..894716d70 100644 --- a/src/fsfw/osal/common/UdpTcPollingTask.h +++ b/src/fsfw/osal/common/UdpTcPollingTask.h @@ -21,11 +21,11 @@ class UdpTcPollingTask : public TcpIpBase, public SystemObject, public Executabl public: static constexpr size_t DEFAULT_MAX_RECV_SIZE = 1500; //! 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, double timeoutSeconds = -1); - virtual ~UdpTcPollingTask(); + ~UdpTcPollingTask() override = default; /** * 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); - virtual ReturnValue_t performOperation(uint8_t opCode) override; - virtual ReturnValue_t initialize() override; - virtual ReturnValue_t initializeAfterTaskCreation() override; + [[noreturn]] ReturnValue_t performOperation(uint8_t opCode) override; + ReturnValue_t initialize() override; + ReturnValue_t initializeAfterTaskCreation() override; protected: StorageManagerIF* tcStore = nullptr; @@ -51,7 +51,7 @@ class UdpTcPollingTask : public TcpIpBase, public SystemObject, public Executabl std::vector receptionBuffer; size_t frameSize = 0; - timeval receptionTimeout; + timeval receptionTimeout{}; ReturnValue_t handleSuccessfullTcRead(size_t bytesRead); }; diff --git a/src/fsfw/osal/common/UdpTmTcBridge.cpp b/src/fsfw/osal/common/UdpTmTcBridge.cpp index 0efe1c744..6089f266a 100644 --- a/src/fsfw/osal/common/UdpTmTcBridge.cpp +++ b/src/fsfw/osal/common/UdpTmTcBridge.cpp @@ -20,13 +20,13 @@ const std::string UdpTmTcBridge::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT; 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) : TmTcBridge(objectId, tcDestination, tmStoreId, tcStoreId) { - if (udpServerPort == "") { - this->udpServerPort = DEFAULT_SERVER_PORT; + if (udpServerPort_.empty()) { + udpServerPort = DEFAULT_SERVER_PORT; } else { - this->udpServerPort = udpServerPort; + udpServerPort = udpServerPort_; } mutex = MutexFactory::instance()->createMutex(); @@ -117,7 +117,7 @@ ReturnValue_t UdpTmTcBridge::sendTm(const uint8_t *data, size_t dataLen) { tcpip::printAddress(&clientAddress); #endif - int bytesSent = sendto(serverSocket, reinterpret_cast(data), dataLen, flags, + ssize_t bytesSent = sendto(serverSocket, reinterpret_cast(data), dataLen, flags, &clientAddress, clientAddressLen); if (bytesSent == SOCKET_ERROR) { #if FSFW_CPP_OSTREAM_ENABLED == 1 @@ -150,7 +150,7 @@ void UdpTmTcBridge::checkAndSetClientAddress(sockaddr &newAddress) { clientAddressLen = sizeof(clientAddress); } -void UdpTmTcBridge::setMutexProperties(MutexIF::TimeoutType timeoutType, dur_millis_t timeoutMs) { - this->timeoutType = timeoutType; - this->mutexTimeoutMs = timeoutMs; +void UdpTmTcBridge::setMutexProperties(MutexIF::TimeoutType timeoutType_, dur_millis_t timeoutMs) { + timeoutType = timeoutType_; + mutexTimeoutMs = timeoutMs; } diff --git a/src/fsfw/osal/common/UdpTmTcBridge.h b/src/fsfw/osal/common/UdpTmTcBridge.h index 78843ccd3..b0a67430f 100644 --- a/src/fsfw/osal/common/UdpTmTcBridge.h +++ b/src/fsfw/osal/common/UdpTmTcBridge.h @@ -29,10 +29,10 @@ class UdpTmTcBridge : public TmTcBridge, public TcpIpBase { /* The ports chosen here should not be used by any other process. */ 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, const std::string& udpServerPort = "", object_id_t tmStoreId = objects::TM_STORE, object_id_t tcStoreId = objects::TC_STORE); - virtual ~UdpTmTcBridge(); + ~UdpTmTcBridge() override; /** * Set properties of internal mutex. @@ -46,12 +46,12 @@ class UdpTmTcBridge : public TmTcBridge, public TcpIpBase { std::string getUdpPort() const; 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: std::string udpServerPort; - struct sockaddr clientAddress; + struct sockaddr clientAddress = {}; socklen_t clientAddressLen = 0; //! Access to the client address is mutex protected as it is set by another task. diff --git a/src/fsfw/osal/freertos/Clock.cpp b/src/fsfw/osal/freertos/Clock.cpp index 050839684..cabf7d812 100644 --- a/src/fsfw/osal/freertos/Clock.cpp +++ b/src/fsfw/osal/freertos/Clock.cpp @@ -11,9 +11,6 @@ // TODO sanitize input? // TODO much of this code can be reused for tick-only systems -uint16_t Clock::leapSeconds = 0; -MutexIF* Clock::timeMutex = nullptr; - uint32_t Clock::getTicksPerSecond(void) { return 1000; } ReturnValue_t Clock::setClock(const TimeOfDay_t* time) { diff --git a/src/fsfw/osal/freertos/MessageQueue.h b/src/fsfw/osal/freertos/MessageQueue.h index 00dfea680..ee3479aaa 100644 --- a/src/fsfw/osal/freertos/MessageQueue.h +++ b/src/fsfw/osal/freertos/MessageQueue.h @@ -2,6 +2,7 @@ #define FSFW_OSAL_FREERTOS_MESSAGEQUEUE_H_ #include + #include "FreeRTOS.h" #include "TaskManagement.h" #include "fsfw/internalerror/InternalErrorReporterIF.h" diff --git a/src/fsfw/osal/host/CMakeLists.txt b/src/fsfw/osal/host/CMakeLists.txt index 2d29ce5df..8b11a5312 100644 --- a/src/fsfw/osal/host/CMakeLists.txt +++ b/src/fsfw/osal/host/CMakeLists.txt @@ -1,24 +1,27 @@ -target_sources(${LIB_FSFW_NAME} - PRIVATE - Clock.cpp - FixedTimeslotTask.cpp - MessageQueue.cpp - Mutex.cpp - MutexFactory.cpp - PeriodicTask.cpp - QueueFactory.cpp - QueueMapManager.cpp - SemaphoreFactory.cpp - TaskFactory.cpp - taskHelpers.cpp +target_sources(${LIB_FSFW_NAME} PRIVATE + Clock.cpp + FixedTimeslotTask.cpp + MessageQueue.cpp + Mutex.cpp + MutexFactory.cpp + PeriodicTask.cpp + QueueFactory.cpp + QueueMapManager.cpp + SemaphoreFactory.cpp + TaskFactory.cpp + taskHelpers.cpp ) if(UNIX) - find_package(Threads REQUIRED) - - target_link_libraries(${LIB_FSFW_NAME} - PRIVATE - rt - ${CMAKE_THREAD_LIBS_INIT} - ) + find_package(Threads REQUIRED) + + target_link_libraries(${LIB_FSFW_NAME} PRIVATE + ${CMAKE_THREAD_LIBS_INIT} + ) + if(NOT APPLE) + target_link_libraries(${LIB_FSFW_NAME} PRIVATE + rt + ) + endif() + endif() \ No newline at end of file diff --git a/src/fsfw/osal/host/Clock.cpp b/src/fsfw/osal/host/Clock.cpp index d0acdfdf0..19e120b39 100644 --- a/src/fsfw/osal/host/Clock.cpp +++ b/src/fsfw/osal/host/Clock.cpp @@ -2,6 +2,7 @@ #include +#include "fsfw/ipc/MutexGuard.h" #include "fsfw/platform.h" #include "fsfw/serviceinterface/ServiceInterface.h" @@ -11,9 +12,6 @@ #include #endif -uint16_t Clock::leapSeconds = 0; -MutexIF* Clock::timeMutex = NULL; - using SystemClock = std::chrono::system_clock; uint32_t Clock::getTicksPerSecond(void) { @@ -127,6 +125,13 @@ ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) { auto seconds = std::chrono::time_point_cast(now); auto fraction = now - seconds; time_t tt = SystemClock::to_time_t(now); + ReturnValue_t result = checkOrCreateClockMutex(); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + MutexGuard helper(timeMutex); + // gmtime writes its output in a global buffer which is not Thread Safe + // Therefore we have to use a Mutex here struct tm* timeInfo; timeInfo = gmtime(&tt); time->year = timeInfo->tm_year + 1900; diff --git a/src/fsfw/osal/host/MessageQueue.h b/src/fsfw/osal/host/MessageQueue.h index bb4f26a10..4020c6dcc 100644 --- a/src/fsfw/osal/host/MessageQueue.h +++ b/src/fsfw/osal/host/MessageQueue.h @@ -1,17 +1,17 @@ #ifndef FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_ #define FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_ -#include "fsfw/ipc/MessageQueueBase.h" +#include +#include + #include "fsfw/internalerror/InternalErrorReporterIF.h" +#include "fsfw/ipc/MessageQueueBase.h" #include "fsfw/ipc/MessageQueueIF.h" #include "fsfw/ipc/MessageQueueMessage.h" #include "fsfw/ipc/MutexIF.h" #include "fsfw/ipc/definitions.h" #include "fsfw/timemanager/Clock.h" -#include -#include - /** * @brief This class manages sending and receiving of * message queue messages. diff --git a/src/fsfw/osal/linux/CMakeLists.txt b/src/fsfw/osal/linux/CMakeLists.txt index 679b29319..2e88d6d05 100644 --- a/src/fsfw/osal/linux/CMakeLists.txt +++ b/src/fsfw/osal/linux/CMakeLists.txt @@ -1,29 +1,29 @@ target_sources(${LIB_FSFW_NAME} PRIVATE - Clock.cpp - BinarySemaphore.cpp - CountingSemaphore.cpp - FixedTimeslotTask.cpp - InternalErrorCodes.cpp - MessageQueue.cpp - Mutex.cpp - MutexFactory.cpp - PeriodicPosixTask.cpp - PosixThread.cpp - QueueFactory.cpp - SemaphoreFactory.cpp - TaskFactory.cpp - tcpipHelpers.cpp - unixUtility.cpp -) + Clock.cpp + BinarySemaphore.cpp + CountingSemaphore.cpp + FixedTimeslotTask.cpp + InternalErrorCodes.cpp + MessageQueue.cpp + Mutex.cpp + MutexFactory.cpp + PeriodicPosixTask.cpp + PosixThread.cpp + QueueFactory.cpp + SemaphoreFactory.cpp + TaskFactory.cpp + tcpipHelpers.cpp + unixUtility.cpp + ) find_package(Threads REQUIRED) -target_link_libraries(${LIB_FSFW_NAME} PRIVATE - ${CMAKE_THREAD_LIBS_INIT} +target_link_libraries(${LIB_FSFW_NAME} PUBLIC + ${CMAKE_THREAD_LIBS_INIT} + ) + +if(NOT APPLE) + target_link_libraries(${LIB_FSFW_NAME} PUBLIC rt -) - -target_link_libraries(${LIB_FSFW_NAME} INTERFACE - ${CMAKE_THREAD_LIBS_INIT} -) - + ) +endif() diff --git a/src/fsfw/osal/linux/Clock.cpp b/src/fsfw/osal/linux/Clock.cpp index 61eb970ff..534e7e22c 100644 --- a/src/fsfw/osal/linux/Clock.cpp +++ b/src/fsfw/osal/linux/Clock.cpp @@ -8,11 +8,9 @@ #include +#include "fsfw/ipc/MutexGuard.h" #include "fsfw/serviceinterface/ServiceInterface.h" -uint16_t Clock::leapSeconds = 0; -MutexIF* Clock::timeMutex = NULL; - uint32_t Clock::getTicksPerSecond(void) { uint32_t ticks = sysconf(_SC_CLK_TCK); return ticks; @@ -117,7 +115,13 @@ ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) { // TODO errno return HasReturnvaluesIF::RETURN_FAILED; } - + ReturnValue_t result = checkOrCreateClockMutex(); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + MutexGuard helper(timeMutex); + // gmtime writes its output in a global buffer which is not Thread Safe + // Therefore we have to use a Mutex here struct tm* timeInfo; timeInfo = gmtime(&timeUnix.tv_sec); time->year = timeInfo->tm_year + 1900; diff --git a/src/fsfw/osal/linux/MessageQueue.h b/src/fsfw/osal/linux/MessageQueue.h index 8614d101b..108ec797d 100644 --- a/src/fsfw/osal/linux/MessageQueue.h +++ b/src/fsfw/osal/linux/MessageQueue.h @@ -61,8 +61,7 @@ class MessageQueue : public MessageQueueBase { ReturnValue_t receiveMessage(MessageQueueMessageIF* message) override; ReturnValue_t flush(uint32_t* count) override; ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message, - MessageQueueId_t sentFrom, - bool ignoreFault = false) override; + MessageQueueId_t sentFrom, bool ignoreFault = false) override; protected: /** diff --git a/src/fsfw/osal/rtems/Clock.cpp b/src/fsfw/osal/rtems/Clock.cpp index 06b0c1d8d..831c67d43 100644 --- a/src/fsfw/osal/rtems/Clock.cpp +++ b/src/fsfw/osal/rtems/Clock.cpp @@ -6,9 +6,6 @@ #include "fsfw/ipc/MutexGuard.h" #include "fsfw/osal/rtems/RtemsBasic.h" -uint16_t Clock::leapSeconds = 0; -MutexIF* Clock::timeMutex = nullptr; - uint32_t Clock::getTicksPerSecond(void) { rtems_interval ticks_per_second = rtems_clock_get_ticks_per_second(); return static_cast(ticks_per_second); diff --git a/src/fsfw/osal/rtems/MessageQueue.h b/src/fsfw/osal/rtems/MessageQueue.h index 4648fdfa5..bb31a5087 100644 --- a/src/fsfw/osal/rtems/MessageQueue.h +++ b/src/fsfw/osal/rtems/MessageQueue.h @@ -2,6 +2,7 @@ #define FSFW_OSAL_RTEMS_MESSAGEQUEUE_H_ #include + #include "RtemsBasic.h" #include "fsfw/internalerror/InternalErrorReporterIF.h" #include "fsfw/ipc/MessageQueueIF.h" @@ -52,8 +53,8 @@ class MessageQueue : public MessageQueueBase { // Implement non-generic MessageQueueIF functions not handled by MessageQueueBase ReturnValue_t flush(uint32_t* count) override; ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message, - MessageQueueId_t sentFrom = NO_QUEUE, - bool ignoreFault = false) override; + MessageQueueId_t sentFrom = NO_QUEUE, + bool ignoreFault = false) override; private: /** diff --git a/src/fsfw/osal/rtems/PeriodicTask.h b/src/fsfw/osal/rtems/PeriodicTask.h index 24ce4af1e..9f47dfc61 100644 --- a/src/fsfw/osal/rtems/PeriodicTask.h +++ b/src/fsfw/osal/rtems/PeriodicTask.h @@ -59,14 +59,13 @@ class PeriodicTask : public RTEMSTaskBase, public PeriodicTaskIF { */ ReturnValue_t addComponent(object_id_t object) override; -/** + /** * Adds an object to the list of objects to be executed. * The objects are executed in the order added. * @param object pointer to the object to add. * @return RETURN_OK on success, RETURN_FAILED if the object could not be added. */ - ReturnValue_t addComponent(ExecutableObjectIF* object) override; - + ReturnValue_t addComponent(ExecutableObjectIF *object) override; uint32_t getPeriodMs() const override; diff --git a/src/fsfw/power/Fuse.h b/src/fsfw/power/Fuse.h index 0b57a6a90..43896f75a 100644 --- a/src/fsfw/power/Fuse.h +++ b/src/fsfw/power/Fuse.h @@ -54,7 +54,7 @@ class Fuse : public SystemObject, ReturnValue_t check(); uint8_t getFuseId() const; - ReturnValue_t initialize(); + ReturnValue_t initialize() override; DeviceList devices; ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize, SerializeIF::Endianness streamEndianness) const override; diff --git a/src/fsfw/pus/Service3Housekeeping.h b/src/fsfw/pus/Service3Housekeeping.h index c1928891e..70f157625 100644 --- a/src/fsfw/pus/Service3Housekeeping.h +++ b/src/fsfw/pus/Service3Housekeeping.h @@ -43,7 +43,7 @@ class Service3Housekeeping : public CommandingServiceBase, public AcceptsHkPacke CommandMessage* optionalNextCommand, object_id_t objectId, bool* isStep) override; - virtual MessageQueueId_t getHkQueue() const; + virtual MessageQueueId_t getHkQueue() const override; private: enum class Subservice { diff --git a/src/fsfw/subsystem/Subsystem.cpp b/src/fsfw/subsystem/Subsystem.cpp index a837bf83e..ab8c1b168 100644 --- a/src/fsfw/subsystem/Subsystem.cpp +++ b/src/fsfw/subsystem/Subsystem.cpp @@ -30,11 +30,11 @@ ReturnValue_t Subsystem::checkSequence(HybridIterator iter, return FALLBACK_SEQUENCE_DOES_NOT_EXIST; } - if (iter.value == NULL) { + if (iter.value == nullptr) { return NO_TARGET_TABLE; } - for (; iter.value != NULL; ++iter) { + for (; iter.value != nullptr; ++iter) { if (!existsModeTable(iter->getTableId())) { return TABLE_DOES_NOT_EXIST; } else { @@ -66,13 +66,18 @@ HybridIterator Subsystem::getCurrentTable() { void Subsystem::performChildOperation() { if (isInTransition) { if (commandsOutstanding <= 0) { // all children of the current table were commanded and replied - if (currentSequenceIterator.value == NULL) { // we're through with this sequence + if (currentSequenceIterator.value == nullptr) { // we're through with this sequence if (checkStateAgainstTable(currentTargetTable, targetSubmode) == RETURN_OK) { setMode(targetMode, targetSubmode); isInTransition = false; return; } else { - transitionFailed(TARGET_TABLE_NOT_REACHED, getSequence(targetMode)->getTableId()); + Mode_t tableId = 0; + auto seq = getSequence(targetMode); + if (seq.value != nullptr) { + tableId = seq->getTableId(); + } + transitionFailed(TARGET_TABLE_NOT_REACHED, tableId); return; } } @@ -248,10 +253,13 @@ ReturnValue_t Subsystem::handleCommandMessage(CommandMessage *message) { case ModeSequenceMessage::READ_TABLE: { ReturnValue_t result; Mode_t table = ModeSequenceMessage::getSequenceId(message); - EntryPointer *entry = NULL; + EntryPointer *entry = nullptr; result = modeTables.find(table, &entry); - if (result != RETURN_OK) { + if (result != RETURN_OK or entry == nullptr) { replyToCommand(result, 0); + if (entry == nullptr) { + return result; + } } SerializeIF *elements[2]; diff --git a/src/fsfw/subsystem/Subsystem.h b/src/fsfw/subsystem/Subsystem.h index 2c78c8cd3..f1e7228d0 100644 --- a/src/fsfw/subsystem/Subsystem.h +++ b/src/fsfw/subsystem/Subsystem.h @@ -1,14 +1,13 @@ #ifndef FSFW_SUBSYSTEM_SUBSYSTEM_H_ #define FSFW_SUBSYSTEM_SUBSYSTEM_H_ -#include - #include "../container/FixedArrayList.h" #include "../container/FixedMap.h" #include "../container/HybridIterator.h" #include "../container/SinglyLinkedList.h" #include "../serialize/SerialArrayListAdapter.h" #include "SubsystemBase.h" +#include "fsfw/FSFW.h" #include "modes/ModeDefinitions.h" /** @@ -127,18 +126,18 @@ class Subsystem : public SubsystemBase, public HasModeSequenceIF { 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 isTableUsed(Mode_t tableId); 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); diff --git a/src/fsfw/subsystem/SubsystemBase.h b/src/fsfw/subsystem/SubsystemBase.h index 8cfd5be07..52f9891e0 100644 --- a/src/fsfw/subsystem/SubsystemBase.h +++ b/src/fsfw/subsystem/SubsystemBase.h @@ -123,15 +123,15 @@ class SubsystemBase : public SystemObject, virtual void performChildOperation() = 0; virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, - uint32_t *msToReachTheMode) = 0; + uint32_t *msToReachTheMode) override = 0; - virtual void startTransition(Mode_t mode, Submode_t submode) = 0; + virtual void startTransition(Mode_t mode, Submode_t submode) override = 0; - 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) override; virtual void modeChanged(); }; diff --git a/src/fsfw/timemanager/CCSDSTime.cpp b/src/fsfw/timemanager/CCSDSTime.cpp index c5132cbb0..1f84dd03d 100644 --- a/src/fsfw/timemanager/CCSDSTime.cpp +++ b/src/fsfw/timemanager/CCSDSTime.cpp @@ -6,10 +6,6 @@ #include "fsfw/FSFW.h" -CCSDSTime::CCSDSTime() {} - -CCSDSTime::~CCSDSTime() {} - ReturnValue_t CCSDSTime::convertToCcsds(Ccs_seconds* to, const Clock::TimeOfDay_t* from) { ReturnValue_t result = checkTimeOfDay(from); if (result != RETURN_OK) { @@ -91,7 +87,7 @@ ReturnValue_t CCSDSTime::convertFromCDS(Clock::TimeOfDay_t* to, const uint8_t* f if (result != HasReturnvaluesIF::RETURN_OK) { return result; } - return convertTimevalToTimeOfDay(to, &time); + return Clock::convertTimevalToTimeOfDay(&time, to); } ReturnValue_t CCSDSTime::convertFromCCS(Clock::TimeOfDay_t* to, const uint8_t* from, @@ -428,7 +424,7 @@ ReturnValue_t CCSDSTime::convertFromCUC(timeval* to, const uint8_t* from, size_t from++; ReturnValue_t result = convertFromCUC(to, pField, from, foundLength, maxLength - 1); if (result == HasReturnvaluesIF::RETURN_OK) { - if (foundLength != NULL) { + if (foundLength != nullptr) { *foundLength += 1; } } @@ -489,11 +485,6 @@ ReturnValue_t CCSDSTime::checkTimeOfDay(const Clock::TimeOfDay_t* time) { return RETURN_OK; } -ReturnValue_t CCSDSTime::convertTimevalToTimeOfDay(Clock::TimeOfDay_t* to, timeval* from) { - // This is rather tricky. Implement only if needed. Also, if so, move to OSAL. - return UNSUPPORTED_TIME_FORMAT; -} - ReturnValue_t CCSDSTime::convertFromCDS(timeval* to, const uint8_t* from, size_t* foundLength, size_t maxLength) { uint8_t pField = *from; @@ -583,7 +574,7 @@ ReturnValue_t CCSDSTime::convertFromCDS(Clock::TimeOfDay_t* to, const CCSDSTime: if (result != HasReturnvaluesIF::RETURN_OK) { return result; } - return CCSDSTime::convertTimevalToTimeOfDay(to, &tempTimeval); + return Clock::convertTimevalToTimeOfDay(&tempTimeval, to); } ReturnValue_t CCSDSTime::convertFromCUC(timeval* to, uint8_t pField, const uint8_t* from, @@ -593,18 +584,18 @@ ReturnValue_t CCSDSTime::convertFromCUC(timeval* to, uint8_t pField, const uint8 uint8_t nCoarse = ((pField & 0b1100) >> 2) + 1; uint8_t nFine = (pField & 0b11); size_t totalLength = nCoarse + nFine; - if (foundLength != NULL) { + if (foundLength != nullptr) { *foundLength = totalLength; } if (totalLength > maxLength) { return LENGTH_MISMATCH; } - for (int count = 0; count < nCoarse; count++) { - secs += *from << ((nCoarse * 8 - 8) * (1 + count)); + for (int count = nCoarse; count > 0; count--) { + secs += *from << (count * 8 - 8); from++; } - for (int count = 0; count < nFine; count++) { - subSeconds += *from << ((nFine * 8 - 8) * (1 + count)); + for (int count = nFine; count > 0; count--) { + subSeconds += *from << (count * 8 - 8); from++; } // Move to POSIX epoch. diff --git a/src/fsfw/timemanager/CCSDSTime.h b/src/fsfw/timemanager/CCSDSTime.h index 9de41e097..2a2316af8 100644 --- a/src/fsfw/timemanager/CCSDSTime.h +++ b/src/fsfw/timemanager/CCSDSTime.h @@ -161,18 +161,37 @@ class CCSDSTime : public HasReturnvaluesIF { */ static ReturnValue_t convertFromCcsds(timeval *to, uint8_t const *from, size_t *foundLength, 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); - + /** + * @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, size_t maxLength); - static ReturnValue_t convertFromCUC(timeval *to, uint8_t pField, uint8_t const *from, size_t *foundLength, size_t maxLength); static ReturnValue_t convertFromCCS(timeval *to, uint8_t const *from, size_t *foundLength, size_t maxLength); - static ReturnValue_t convertFromCCS(timeval *to, uint8_t pField, uint8_t const *from, size_t *foundLength, size_t maxLength); @@ -192,8 +211,8 @@ class CCSDSTime : public HasReturnvaluesIF { static uint32_t subsecondsToMicroseconds(uint16_t subseconds); private: - CCSDSTime(); - virtual ~CCSDSTime(); + CCSDSTime(){}; + virtual ~CCSDSTime(){}; /** * checks a ccs time stream for validity * @@ -223,7 +242,6 @@ class CCSDSTime : public HasReturnvaluesIF { uint8_t *day); static bool isLeapYear(uint32_t year); - static ReturnValue_t convertTimevalToTimeOfDay(Clock::TimeOfDay_t *to, timeval *from); }; #endif /* FSFW_TIMEMANAGER_CCSDSTIME_H_ */ diff --git a/src/fsfw/timemanager/Clock.h b/src/fsfw/timemanager/Clock.h index 99e8a56ad..75c898e52 100644 --- a/src/fsfw/timemanager/Clock.h +++ b/src/fsfw/timemanager/Clock.h @@ -99,6 +99,13 @@ class Clock { */ static ReturnValue_t getDateAndTime(TimeOfDay_t *time); + /** + * Convert to time of day struct given the POSIX timeval struct + * @param from + * @param to + * @return + */ + static ReturnValue_t convertTimevalToTimeOfDay(const timeval *from, TimeOfDay_t *to); /** * Converts a time of day struct to POSIX seconds. * @param time The time of day as input @@ -166,6 +173,7 @@ class Clock { static MutexIF *timeMutex; static uint16_t leapSeconds; + static bool leapSecondsSet; }; #endif /* FSFW_TIMEMANAGER_CLOCK_H_ */ diff --git a/src/fsfw/timemanager/ClockCommon.cpp b/src/fsfw/timemanager/ClockCommon.cpp index e5749b19f..ca8b12a44 100644 --- a/src/fsfw/timemanager/ClockCommon.cpp +++ b/src/fsfw/timemanager/ClockCommon.cpp @@ -1,7 +1,13 @@ +#include + #include "fsfw/ipc/MutexGuard.h" #include "fsfw/timemanager/Clock.h" -ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval *tt) { +uint16_t Clock::leapSeconds = 0; +MutexIF* Clock::timeMutex = nullptr; +bool Clock::leapSecondsSet = false; + +ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) { uint16_t leapSeconds; ReturnValue_t result = getLeapSeconds(&leapSeconds); if (result != HasReturnvaluesIF::RETURN_OK) { @@ -27,12 +33,16 @@ ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) { MutexGuard helper(timeMutex); leapSeconds = leapSeconds_; + leapSecondsSet = true; return HasReturnvaluesIF::RETURN_OK; } -ReturnValue_t Clock::getLeapSeconds(uint16_t *leapSeconds_) { - if (timeMutex == nullptr) { +ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) { + if (not leapSecondsSet) { + return HasReturnvaluesIF::RETURN_FAILED; + } + if (checkOrCreateClockMutex() != HasReturnvaluesIF::RETURN_OK) { return HasReturnvaluesIF::RETURN_FAILED; } MutexGuard helper(timeMutex); @@ -42,9 +52,32 @@ ReturnValue_t Clock::getLeapSeconds(uint16_t *leapSeconds_) { return HasReturnvaluesIF::RETURN_OK; } +ReturnValue_t Clock::convertTimevalToTimeOfDay(const timeval* from, TimeOfDay_t* to) { + struct tm* timeInfo; + // According to https://en.cppreference.com/w/c/chrono/gmtime, the implementation of gmtime_s + // in the Windows CRT is incompatible with the C standard but this should not be an issue for + // this implementation + ReturnValue_t result = checkOrCreateClockMutex(); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + MutexGuard helper(timeMutex); + // gmtime writes its output in a global buffer which is not Thread Safe + // Therefore we have to use a Mutex here + timeInfo = gmtime(&from->tv_sec); + to->year = timeInfo->tm_year + 1900; + to->month = timeInfo->tm_mon + 1; + to->day = timeInfo->tm_mday; + to->hour = timeInfo->tm_hour; + to->minute = timeInfo->tm_min; + to->second = timeInfo->tm_sec; + to->usecond = from->tv_usec; + return HasReturnvaluesIF::RETURN_OK; +} + ReturnValue_t Clock::checkOrCreateClockMutex() { if (timeMutex == nullptr) { - MutexFactory *mutexFactory = MutexFactory::instance(); + MutexFactory* mutexFactory = MutexFactory::instance(); if (mutexFactory == nullptr) { return HasReturnvaluesIF::RETURN_FAILED; } diff --git a/src/fsfw/tmtcpacket/SpacePacket.cpp b/src/fsfw/tmtcpacket/SpacePacket.cpp index c8ebbd978..16d968fb9 100644 --- a/src/fsfw/tmtcpacket/SpacePacket.cpp +++ b/src/fsfw/tmtcpacket/SpacePacket.cpp @@ -19,8 +19,8 @@ SpacePacket::SpacePacket(uint16_t packetDataLength, bool isTelecommand, uint16_t SpacePacket::~SpacePacket(void) {} bool SpacePacket::addWholeData(const uint8_t* p_Data, uint32_t packet_size) { - if (packet_size <= sizeof(this->data)) { - memcpy(&this->localData.byteStream, p_Data, packet_size); + if (packet_size <= sizeof(this->localData)) { + memcpy(this->localData.byteStream, p_Data, packet_size); return true; } else { return false; diff --git a/src/fsfw/tmtcservices/CommandingServiceBase.h b/src/fsfw/tmtcservices/CommandingServiceBase.h index 0ae195051..867fc2874 100644 --- a/src/fsfw/tmtcservices/CommandingServiceBase.h +++ b/src/fsfw/tmtcservices/CommandingServiceBase.h @@ -95,7 +95,7 @@ class CommandingServiceBase : public SystemObject, */ virtual ReturnValue_t performOperation(uint8_t opCode) override; - virtual uint16_t getIdentifier(); + virtual uint16_t getIdentifier() override; /** * Returns the requestQueue MessageQueueId_t @@ -104,7 +104,7 @@ class CommandingServiceBase : public SystemObject, * * @return requestQueue messageQueueId_t */ - virtual MessageQueueId_t getRequestQueue(); + virtual MessageQueueId_t getRequestQueue() override; /** * Returns the commandQueue MessageQueueId_t diff --git a/tests/src/fsfw_tests/unit/globalfunctions/CMakeLists.txt b/tests/src/fsfw_tests/unit/globalfunctions/CMakeLists.txt index 79f847bff..348b99fc7 100644 --- a/tests/src/fsfw_tests/unit/globalfunctions/CMakeLists.txt +++ b/tests/src/fsfw_tests/unit/globalfunctions/CMakeLists.txt @@ -3,4 +3,5 @@ target_sources(${FSFW_TEST_TGT} PRIVATE testOpDivider.cpp testBitutil.cpp testCRC.cpp + testTimevalOperations.cpp ) diff --git a/tests/src/fsfw_tests/unit/globalfunctions/testTimevalOperations.cpp b/tests/src/fsfw_tests/unit/globalfunctions/testTimevalOperations.cpp new file mode 100644 index 000000000..347d2204e --- /dev/null +++ b/tests/src/fsfw_tests/unit/globalfunctions/testTimevalOperations.cpp @@ -0,0 +1,124 @@ +#include + +#include +#include + +#include "fsfw_tests/unit/CatchDefinitions.h" + +TEST_CASE("TimevalTest", "[timevalOperations]") { + SECTION("Comparison") { + timeval t1; + t1.tv_sec = 1648227422; + t1.tv_usec = 123456; + timeval t2; + t2.tv_sec = 1648227422; + t2.tv_usec = 123456; + REQUIRE(t1 == t2); + REQUIRE(t2 == t1); + REQUIRE_FALSE(t1 != t2); + REQUIRE_FALSE(t2 != t1); + REQUIRE(t1 <= t2); + REQUIRE(t2 <= t1); + REQUIRE(t1 >= t2); + REQUIRE(t2 >= t1); + REQUIRE_FALSE(t1 < t2); + REQUIRE_FALSE(t2 < t1); + REQUIRE_FALSE(t1 > t2); + REQUIRE_FALSE(t2 > t1); + + timeval t3; + t3.tv_sec = 1648227422; + t3.tv_usec = 123457; + REQUIRE_FALSE(t1 == t3); + REQUIRE(t1 != t3); + REQUIRE(t1 <= t3); + REQUIRE_FALSE(t3 <= t1); + REQUIRE_FALSE(t1 >= t3); + REQUIRE(t3 >= t1); + REQUIRE(t1 < t3); + REQUIRE_FALSE(t3 < t1); + REQUIRE_FALSE(t1 > t3); + REQUIRE(t3 > t1); + + timeval t4; + t4.tv_sec = 1648227423; + t4.tv_usec = 123456; + REQUIRE_FALSE(t1 == t4); + REQUIRE(t1 != t4); + REQUIRE(t1 <= t4); + REQUIRE_FALSE(t4 <= t1); + REQUIRE_FALSE(t1 >= t4); + REQUIRE(t4 >= t1); + REQUIRE(t1 < t4); + REQUIRE_FALSE(t4 < t1); + REQUIRE_FALSE(t1 > t4); + REQUIRE(t4 > t1); + } + SECTION("Operators") { + timeval t1; + t1.tv_sec = 1648227422; + t1.tv_usec = 123456; + timeval t2; + t2.tv_sec = 1648227422; + t2.tv_usec = 123456; + timeval t3 = t1 - t2; + REQUIRE(t3.tv_sec == 0); + REQUIRE(t3.tv_usec == 0); + timeval t4 = t1 - t3; + REQUIRE(t4.tv_sec == 1648227422); + REQUIRE(t4.tv_usec == 123456); + timeval t5 = t3 - t1; + REQUIRE(t5.tv_sec == -1648227422); + REQUIRE(t5.tv_usec == -123456); + + timeval t6; + t6.tv_sec = 1648227400; + t6.tv_usec = 999999; + + timeval t7 = t6 + t1; + REQUIRE(t7.tv_sec == (1648227422ull + 1648227400ull + 1ull)); + REQUIRE(t7.tv_usec == 123455); + + timeval t8 = t1 - t6; + REQUIRE(t8.tv_sec == 1648227422 - 1648227400 - 1); + REQUIRE(t8.tv_usec == 123457); + + double scalar = 2; + timeval t9 = t1 * scalar; + REQUIRE(t9.tv_sec == 3296454844); + REQUIRE(t9.tv_usec == 246912); + timeval t10 = scalar * t1; + REQUIRE(t10.tv_sec == 3296454844); + REQUIRE(t10.tv_usec == 246912); + timeval t11 = t6 * scalar; + REQUIRE(t11.tv_sec == (3296454800 + 1)); + REQUIRE(t11.tv_usec == 999998); + + timeval t12 = t1 / scalar; + REQUIRE(t12.tv_sec == 824113711); + REQUIRE(t12.tv_usec == 61728); + + timeval t13 = t6 / scalar; + REQUIRE(t13.tv_sec == 824113700); + // Rounding issue + REQUIRE(t13.tv_usec == 499999); + + double scalar2 = t9 / t1; + REQUIRE(scalar2 == Catch::Approx(2.0)); + double scalar3 = t1 / t6; + REQUIRE(scalar3 == Catch::Approx(1.000000013)); + double scalar4 = t3 / t1; + REQUIRE(scalar4 == Catch::Approx(0)); + double scalar5 = t12 / t1; + REQUIRE(scalar5 == Catch::Approx(0.5)); + } + + SECTION("timevalOperations::toTimeval") { + double seconds = 1648227422.123456; + timeval t1 = timevalOperations::toTimeval(seconds); + REQUIRE(t1.tv_sec == 1648227422); + // Allow 1 usec rounding tolerance + REQUIRE(t1.tv_usec >= 123455); + REQUIRE(t1.tv_usec <= 123457); + } +} \ No newline at end of file diff --git a/tests/src/fsfw_tests/unit/mocks/MessageQueueMockBase.h b/tests/src/fsfw_tests/unit/mocks/MessageQueueMockBase.h index c3d08a86e..4236593ef 100644 --- a/tests/src/fsfw_tests/unit/mocks/MessageQueueMockBase.h +++ b/tests/src/fsfw_tests/unit/mocks/MessageQueueMockBase.h @@ -4,8 +4,8 @@ #include #include -#include "fsfw/ipc/MessageQueueBase.h" #include "fsfw/ipc/CommandMessage.h" +#include "fsfw/ipc/MessageQueueBase.h" #include "fsfw/ipc/MessageQueueIF.h" #include "fsfw/ipc/MessageQueueMessage.h" #include "fsfw_tests/unit/CatchDefinitions.h" @@ -13,7 +13,7 @@ class MessageQueueMockBase : public MessageQueueBase { public: MessageQueueMockBase() - : MessageQueueBase(MessageQueueIF::NO_QUEUE, MessageQueueIF::NO_QUEUE, nullptr) {} + : MessageQueueBase(MessageQueueIF::NO_QUEUE, MessageQueueIF::NO_QUEUE, nullptr) {} uint8_t messageSentCounter = 0; bool messageSent = false; diff --git a/tests/src/fsfw_tests/unit/osal/CMakeLists.txt b/tests/src/fsfw_tests/unit/osal/CMakeLists.txt index 293be2e85..030d363b8 100644 --- a/tests/src/fsfw_tests/unit/osal/CMakeLists.txt +++ b/tests/src/fsfw_tests/unit/osal/CMakeLists.txt @@ -1,4 +1,5 @@ target_sources(${FSFW_TEST_TGT} PRIVATE TestMessageQueue.cpp TestSemaphore.cpp + TestClock.cpp ) diff --git a/tests/src/fsfw_tests/unit/osal/TestClock.cpp b/tests/src/fsfw_tests/unit/osal/TestClock.cpp new file mode 100644 index 000000000..38ec39156 --- /dev/null +++ b/tests/src/fsfw_tests/unit/osal/TestClock.cpp @@ -0,0 +1,86 @@ +#include +#include + +#include +#include +#include + +#include "fsfw_tests/unit/CatchDefinitions.h" + +TEST_CASE("OSAL::Clock Test", "[OSAL::Clock Test]") { + SECTION("Test getClock") { + timeval time; + ReturnValue_t result = Clock::getClock_timeval(&time); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + Clock::TimeOfDay_t timeOfDay; + result = Clock::getDateAndTime(&timeOfDay); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + timeval timeOfDayAsTimeval; + result = Clock::convertTimeOfDayToTimeval(&timeOfDay, &timeOfDayAsTimeval); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + // We require timeOfDayAsTimeval to be larger than time as it + // was request a few ns later + double difference = timevalOperations::toDouble(timeOfDayAsTimeval - time); + CHECK(difference >= 0.0); + CHECK(difference <= 0.005); + + // Conversion in the other direction + Clock::TimeOfDay_t timevalAsTimeOfDay; + result = Clock::convertTimevalToTimeOfDay(&time, &timevalAsTimeOfDay); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + CHECK(timevalAsTimeOfDay.year <= timeOfDay.year); + // TODO We should write TimeOfDay operators! + } + SECTION("Leap seconds") { + uint16_t leapSeconds = 0; + ReturnValue_t result = Clock::getLeapSeconds(&leapSeconds); + REQUIRE(result == HasReturnvaluesIF::RETURN_FAILED); + REQUIRE(leapSeconds == 0); + result = Clock::setLeapSeconds(18); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + result = Clock::getLeapSeconds(&leapSeconds); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(leapSeconds == 18); + } + SECTION("usec Test") { + timeval timeAsTimeval; + ReturnValue_t result = Clock::getClock_timeval(&timeAsTimeval); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + uint64_t timeAsUsec = 0; + result = Clock::getClock_usecs(&timeAsUsec); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + double timeAsUsecDouble = static_cast(timeAsUsec) / 1000000.0; + timeval timeAsUsecTimeval = timevalOperations::toTimeval(timeAsUsecDouble); + double difference = timevalOperations::toDouble(timeAsUsecTimeval - timeAsTimeval); + // We accept 5 ms difference + CHECK(difference >= 0.0); + CHECK(difference <= 0.005); + uint64_t timevalAsUint64 = static_cast(timeAsTimeval.tv_sec) * 1000000ull + + static_cast(timeAsTimeval.tv_usec); + CHECK((timeAsUsec - timevalAsUint64) >= 0); + CHECK((timeAsUsec - timevalAsUint64) <= (5 * 1000)); + } + SECTION("Test j2000") { + double j2000; + timeval time; + time.tv_sec = 1648208539; + time.tv_usec = 0; + ReturnValue_t result = Clock::convertTimevalToJD2000(time, &j2000); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + double correctJ2000 = 2459663.98772 - 2451545.0; + CHECK(j2000 == Catch::Approx(correctJ2000).margin(1.2 * 1e-8)); + } + SECTION("Convert to TT") { + timeval utcTime; + utcTime.tv_sec = 1648208539; + utcTime.tv_usec = 999000; + timeval tt; + ReturnValue_t result = Clock::setLeapSeconds(27); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + result = Clock::convertUTCToTT(utcTime, &tt); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + CHECK(tt.tv_usec == 183000); + // The plus 1 is a own forced overflow of usecs + CHECK(tt.tv_sec == (1648208539 + 27 + 10 + 32 + 1)); + } +} \ No newline at end of file diff --git a/tests/src/fsfw_tests/unit/timemanager/TestCCSDSTime.cpp b/tests/src/fsfw_tests/unit/timemanager/TestCCSDSTime.cpp index 2e80487aa..e96ddfc91 100644 --- a/tests/src/fsfw_tests/unit/timemanager/TestCCSDSTime.cpp +++ b/tests/src/fsfw_tests/unit/timemanager/TestCCSDSTime.cpp @@ -81,7 +81,8 @@ TEST_CASE("CCSDSTime Tests", "[TestCCSDSTime]") { std::string timeAscii = "2022-12-31T23:59:59.123Z"; Clock::TimeOfDay_t timeTo; const uint8_t* timeChar = reinterpret_cast(timeAscii.c_str()); - CCSDSTime::convertFromASCII(&timeTo, timeChar, timeAscii.length()); + auto result = CCSDSTime::convertFromASCII(&timeTo, timeChar, timeAscii.length()); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); REQUIRE(timeTo.year == 2022); REQUIRE(timeTo.month == 12); REQUIRE(timeTo.day == 31); @@ -89,6 +90,19 @@ TEST_CASE("CCSDSTime Tests", "[TestCCSDSTime]") { REQUIRE(timeTo.minute == 59); REQUIRE(timeTo.second == 59); REQUIRE(timeTo.usecond == Catch::Approx(123000)); + + std::string timeAscii2 = "2022-365T23:59:59.123Z"; + const uint8_t* timeChar2 = reinterpret_cast(timeAscii2.c_str()); + Clock::TimeOfDay_t timeTo2; + result = CCSDSTime::convertFromCcsds(&timeTo2, timeChar2, timeAscii2.length()); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + REQUIRE(timeTo2.year == 2022); + REQUIRE(timeTo2.month == 12); + REQUIRE(timeTo2.day == 31); + REQUIRE(timeTo2.hour == 23); + REQUIRE(timeTo2.minute == 59); + REQUIRE(timeTo2.second == 59); + REQUIRE(timeTo2.usecond == Catch::Approx(123000)); } SECTION("CDS Conversions") { @@ -119,6 +133,7 @@ TEST_CASE("CCSDSTime Tests", "[TestCCSDSTime]") { CHECK(cdsTime.msDay_h == 0xE0); CHECK(cdsTime.msDay_l == 0xC5); CHECK(cdsTime.msDay_ll == 0xC3); + CHECK(cdsTime.pField == CCSDSTime::P_FIELD_CDS_SHORT); // Conversion back to timeval timeval timeReturnAsTimeval; @@ -128,5 +143,77 @@ TEST_CASE("CCSDSTime Tests", "[TestCCSDSTime]") { timeval difference = timeAsTimeval - timeReturnAsTimeval; CHECK(difference.tv_usec == 456); CHECK(difference.tv_sec == 0); + + Clock::TimeOfDay_t timeReturnAsTimeOfDay; + result = CCSDSTime::convertFromCDS(&timeReturnAsTimeOfDay, &cdsTime); + CHECK(result == HasReturnvaluesIF::RETURN_OK); + CHECK(timeReturnAsTimeOfDay.year == 2020); + CHECK(timeReturnAsTimeOfDay.month == 2); + CHECK(timeReturnAsTimeOfDay.day == 29); + CHECK(timeReturnAsTimeOfDay.hour == 13); + CHECK(timeReturnAsTimeOfDay.minute == 24); + CHECK(timeReturnAsTimeOfDay.second == 45); + // micro seconds precision is lost + CHECK(timeReturnAsTimeOfDay.usecond == 123000); + + Clock::TimeOfDay_t timeReturnAsTodFromBuffer; + const uint8_t* buffer = reinterpret_cast(&cdsTime); + result = CCSDSTime::convertFromCDS(&timeReturnAsTodFromBuffer, buffer, sizeof(cdsTime)); + REQUIRE(result == HasReturnvaluesIF::RETURN_OK); + CHECK(timeReturnAsTodFromBuffer.year == time.year); + CHECK(timeReturnAsTodFromBuffer.month == time.month); + CHECK(timeReturnAsTodFromBuffer.day == time.day); + CHECK(timeReturnAsTodFromBuffer.hour == time.hour); + CHECK(timeReturnAsTodFromBuffer.minute == time.minute); + CHECK(timeReturnAsTodFromBuffer.second == time.second); + CHECK(timeReturnAsTodFromBuffer.usecond == 123000); + + Clock::TimeOfDay_t todFromCCSDS; + result = CCSDSTime::convertFromCcsds(&todFromCCSDS, buffer, sizeof(cdsTime)); + CHECK(result == HasReturnvaluesIF::RETURN_OK); + CHECK(todFromCCSDS.year == time.year); + CHECK(todFromCCSDS.month == time.month); + CHECK(todFromCCSDS.day == time.day); + CHECK(todFromCCSDS.hour == time.hour); + CHECK(todFromCCSDS.minute == time.minute); + CHECK(todFromCCSDS.second == time.second); + 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 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") { + Clock::TimeOfDay_t time; + time.year = 2020; + time.month = 12; + time.day = 32; + time.hour = 13; + time.minute = 24; + time.second = 45; + time.usecond = 123456; + CCSDSTime::Ccs_mseconds to; + auto result = CCSDSTime::convertToCcsds(&to, &time); + REQUIRE(result == CCSDSTime::INVALID_TIME_FORMAT); + CCSDSTime::Ccs_seconds to2; + result = CCSDSTime::convertToCcsds(&to2, &time); + REQUIRE(result == CCSDSTime::INVALID_TIME_FORMAT); } } \ No newline at end of file