diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d28c5c6..4713ed17 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 @@ -22,18 +25,56 @@ and this project adheres to [Semantic Versioning](http://semver.org/). PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/572 - HAL Devicehandlers: Periodic printout is run-time configurable now - `oneShotAction` flag in the `TestTask` class is not static anymore -- HAL Linux Uart: Baudrate and bits per word are enums now, avoiding misconfigurations - PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/585 +- Major update for version handling, using `git describe` to fetch version information with git. + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/601 + - Add helper functions provided by [`cmake-modules`](https://github.com/bilke/cmake-modules) + manually now. Those should not change too often and only a small subset is needed + - Separate folder for easier update and for distinction + - LICENSE file included + - use `int` for version numbers to allow unset or uninitialized version + - Initialize Version object with numbers set to -1 + - Instead of hardcoding the git hash, it is now retrieved from git + - `Version` now allows specifying additional version information like the git SHA1 hash and the + versions since the last tag + - Additional information is set to the last part of the git describe output for `FSFW_VERSION` now. + - Version still need to be hand-updated if the FSFW is not included as a submodule for now. - IPC Message Queue Handling: Allow passing an optional `MqArgs` argument into the MessageQueue 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) + +### HAL + +- HAL Linux Uart: Baudrate and bits per word are enums now, avoiding misconfigurations + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/585 +- HAL Linux SPI: Set the Clock Default State when setting new SPI speed + and mode + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/573 +- GPIO HAL: `Direction`, `GpioOperation` and `Levels` are enum classes now, which prevents + name clashes with Windows defines. + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/572 +- HAL Linux Uart: Baudrate and bits per word are enums now, avoiding misconfigurations + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/585 + +### Time + +PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/584 and +https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/593 + +- `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) + +### Power + +- `PowerSwitchIF`: Remove `const` specifier from `sendSwitchCommand` and `sendFuseOnCommand` and + also specify a `ReturnValue_t` return type + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/590 +- Extend `PowerSwitcher` module to optionally check current state when calling `turnOn` or + `turnOff`. Tis can be helpful to avoid commanding switches which do not need commanding + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/590 ## Removed @@ -43,15 +84,45 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## Additions +- LTO support: Allow using LTO/IPO by setting `FSFW_ENABLE_LTO=1`. CMake is able to detect whether + the user compiler supports IPO/LPO. LTO is on by default now. Most modern compilers support it, + can make good use of it and it usually makes the code faster and/or smaller. + After some more research: + Enabling LTO will actually cause the compiler to only produce thin LTO by adding + `-flto -fno-fat-lto-objects` to the compiler options. I am not sure this is an ideal choice + because if an application linking against the FSFW does not use LTO, there can be compile + issues (e.g. observed when compiling the FSFW tests without LTO). This is a known issue as + can be seen in the multiple CMake issues for it: + - https://gitlab.kitware.com/cmake/cmake/-/issues/22913, + - https://gitlab.kitware.com/cmake/cmake/-/issues/16808, + - https://gitlab.kitware.com/cmake/cmake/-/issues/21696 + Easiest solution for now: Keep this option OFF by default. + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/616 - Linux HAL: Add wiretapping option for I2C. Enabled with `FSFW_HAL_I2C_WIRETAPPING` defined to 1 - Dedicated Version class and constant `fsfw::FSFW_VERSION` containing version information inside `fsfw/version.h` PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/559 +- Added generic PUS TC Scheduler Service 11. It depends on the new added Emebeded Template Library + (ETL) dependency. + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/594 - Added ETL dependency and improved library dependency management PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/592 +- Add a `DummyPowerSwitcher` module which can be useful for test setups when no PCDU is available + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/590 +- New typedef for switcher type + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/590 +- `Subsystem`: New API to add table and sequence entries ## Fixed +- TCP TMTC Server: `MutexGuard` was not created properly in + `TcpTmTcServer::handleTmSending(socket_t connSocket, bool& tmSent)` call. + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/618 +- Fix infinite recursion in `prepareHealthSetReply` of PUS Health Service 201. + Is not currently used right now but might be used in the future + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/617 +- 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 diff --git a/CMakeLists.txt b/CMakeLists.txt index bfe3da84..40c0b879 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,40 +1,113 @@ cmake_minimum_required(VERSION 3.13) -set(FSFW_VERSION 4) -set(FSFW_SUBVERSION 0) -set(FSFW_REVISION 0) +set(MSG_PREFIX "fsfw |") # Add the cmake folder so the FindSphinx module is found -set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") +list(APPEND CMAKE_MODULE_PATH + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake-modules/bilke") +list(APPEND CMAKE_MODULE_PATH + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake-modules/rpavlik") -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.3 CACHE STRING - "ETL library exact version requirement" -) -set(FSFW_ETL_LINK_TARGET etl::etl) +# ############################################################################## +# Version file handling # +# ############################################################################## -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-preview5 CACHE STRING - "Catch2 library exact version requirement" -) +set(FSFW_VERSION_IF_GIT_FAILS 4) +set(FSFW_SUBVERSION_IF_GIT_FAILS 0) +set(FSFW_REVISION_IF_GIT_FAILS 0) -set(FSFW_ETL_LIB_NAME etl) - -option(FSFW_GENERATE_SECTIONS - "Generate function and data sections. Required to remove unused code" ON -) -if(FSFW_GENERATE_SECTIONS) - option(FSFW_REMOVE_UNUSED_CODE "Remove unused code" ON) +set(FSFW_GIT_VER_HANDLING_OK FALSE) +# Version handling +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git) + message(STATUS "${MSG_PREFIX} Determining version information with git") + include(FsfwHelpers) + determine_version_with_git("--exclude" "docker_*") + if(GIT_INFO) + set(FSFW_GIT_INFO + ${GIT_INFO} + CACHE STRING "Version information retrieved with git describe") + list(GET FSFW_GIT_INFO 1 FSFW_VERSION) + list(GET FSFW_GIT_INFO 2 FSFW_SUBVERSION) + list(GET FSFW_GIT_INFO 3 FSFW_REVISION) + list(GET FSFW_GIT_INFO 4 FSFW_VCS_INFO) + if(NOT FSFW_VERSION) + set(FSFW_VERSION ${FSFW_VERSION_IF_GIT_FAILS}) + endif() + if(NOT FSFW_SUBVERSION) + set(FSFW_SUBVERSION ${FSFW_SUBVERSION_IF_GIT_FAILS}) + endif() + if(NOT FSFW_REVISION) + set(FSFW_REVISION ${FSFW_REVISION_IF_GIT_FAILS}) + endif() + set(FSFW_GIT_VER_HANDLING_OK TRUE) + else() + set(FSFW_GIT_VER_HANDLING_OK FALSE) + endif() +endif() +if(NOT FSFW_GIT_VER_HANDLING_OK) + set(FSFW_VERSION ${FSFW_VERSION_IF_GIT_FAILS}) + set(FSFW_SUBVERSION ${FSFW_SUBVERSION_IF_GIT_FAILS}) + set(FSFW_REVISION ${FSFW_REVISION_IF_GIT_FAILS}) endif() -option(FSFW_BUILD_UNITTESTS "Build unittest binary in addition to static library" OFF) +set(LIB_FSFW_NAME fsfw) +project(${LIB_FSFW_NAME} + VERSION ${FSFW_VERSION}.${FSFW_SUBVERSION}.${FSFW_REVISION}) + +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 + "${MSG_PREFIX} Compiling the FSFW requires a minimum of C++17 support") +endif() + +set(FSFW_SOURCES_DIR "${CMAKE_SOURCE_DIR}/src/fsfw") + +set(FSFW_ETL_LIB_NAME etl) +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.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-preview5 + CACHE STRING "Catch2 library exact version requirement") + +# Keep this off by default for now. See PR: +# https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/616 for information which +# keeping this on by default is problematic +option( + FSFW_ENABLE_IPO + "Enable interprocedural optimization or link-time optimization if available" + OFF) +if(FSFW_ENABLE_IPO) + include(CheckIPOSupported) + check_ipo_supported(RESULT IPO_SUPPORTED OUTPUT IPO_ERROR) + if(NOT IPO_SUPPORTED) + message(STATUS "FSFW | IPO/LTO not supported: ${IPO_ERROR}") + endif() +endif() + +option(FSFW_GENERATE_SECTIONS + "Generate function and data sections. Required to remove unused code" ON) +if(FSFW_GENERATE_SECTIONS) + option(FSFW_REMOVE_UNUSED_CODE "Remove unused code" ON) +endif() + +option(FSFW_BUILD_UNITTESTS + "Build unittest binary in addition to static library" OFF) option(FSFW_BUILD_DOCS "Build documentation with Sphinx and Doxygen" OFF) if(FSFW_BUILD_UNITTESTS) - option(FSFW_TESTS_GEN_COV "Generate coverage data for unittests" ON) + option(FSFW_TESTS_GEN_COV "Generate coverage data for unittests" ON) endif() option(FSFW_WARNING_SHADOW_LOCAL_GCC "Enable -Wshadow=local warning in GCC" ON) @@ -55,89 +128,93 @@ 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) - message(STATUS "Building the FSFW unittests in addition to the static library") - # Check whether the user has already installed Catch2 first - find_package(Catch2 ${FSFW_CATCH2_LIB_MAJOR_VERSION}) - # Not installed, so use FetchContent to download and provide Catch2 - if(NOT Catch2_FOUND) - message(STATUS "Catch2 installation not found. Downloading Catch2 library with FetchContent") - include(FetchContent) - - FetchContent_Declare( - Catch2 - GIT_REPOSITORY https://github.com/catchorg/Catch2.git - GIT_TAG ${FSFW_CATCH2_LIB_VERSION} - ) - - list(APPEND FSFW_FETCH_CONTENT_TARGETS Catch2) - endif() - - set(FSFW_CONFIG_PATH tests/src/fsfw_tests/unit/testcfg) - configure_file(tests/src/fsfw_tests/unit/testcfg/FSFWConfig.h.in FSFWConfig.h) - configure_file(tests/src/fsfw_tests/unit/testcfg/TestsConfig.h.in tests/TestsConfig.h) - - project(${FSFW_TEST_TGT} CXX C) - add_executable(${FSFW_TEST_TGT}) - - if(FSFW_TESTS_GEN_COV) - message(STATUS "Generating coverage data for the library") - message(STATUS "Targets linking against ${LIB_FSFW_NAME} " - "will be compiled with coverage data as well" - ) - include(FetchContent) - FetchContent_Declare( - cmake-modules - GIT_REPOSITORY https://github.com/bilke/cmake-modules.git - ) - FetchContent_MakeAvailable(cmake-modules) - set(CMAKE_BUILD_TYPE "Debug") - list(APPEND CMAKE_MODULE_PATH ${cmake-modules_SOURCE_DIR}) - include(CodeCoverage) - endif() +if(IPO_SUPPORTED AND FSFW_ENABLE_IPO) + set_property(TARGET ${LIB_FSFW_NAME} PROPERTY INTERPROCEDURAL_OPTIMIZATION + TRUE) endif() -message(STATUS "Finding and/or providing ETL library") +if(FSFW_BUILD_UNITTESTS) + message( + STATUS + "${MSG_PREFIX} Building the FSFW unittests in addition to the static library" + ) + # Check whether the user has already installed Catch2 first + find_package(Catch2 ${FSFW_CATCH2_LIB_MAJOR_VERSION}) + # Not installed, so use FetchContent to download and provide Catch2 + if(NOT Catch2_FOUND) + message( + STATUS + "${MSG_PREFIX} Catch2 installation not found. Downloading Catch2 library with FetchContent" + ) + include(FetchContent) + + FetchContent_Declare( + Catch2 + GIT_REPOSITORY https://github.com/catchorg/Catch2.git + GIT_TAG ${FSFW_CATCH2_LIB_VERSION}) + + list(APPEND FSFW_FETCH_CONTENT_TARGETS Catch2) + endif() + + set(FSFW_CONFIG_PATH tests/src/fsfw_tests/unit/testcfg) + configure_file(tests/src/fsfw_tests/unit/testcfg/FSFWConfig.h.in FSFWConfig.h) + configure_file(tests/src/fsfw_tests/unit/testcfg/TestsConfig.h.in + tests/TestsConfig.h) + + project(${FSFW_TEST_TGT} CXX C) + add_executable(${FSFW_TEST_TGT}) + if(IPO_SUPPORTED AND FSFW_ENABLE_IPO) + set_property(TARGET ${FSFW_TEST_TGT} PROPERTY INTERPROCEDURAL_OPTIMIZATION + TRUE) + endif() + + if(FSFW_TESTS_GEN_COV) + message(STATUS "${MSG_PREFIX} Generating coverage data for the library") + message(STATUS "${MSG_PREFIX} Targets linking against ${LIB_FSFW_NAME} " + "will be compiled with coverage data as well") + set(CMAKE_BUILD_TYPE "Debug") + include(CodeCoverage) + endif() +endif() + +message(STATUS "${MSG_PREFIX} Finding and/or providing ETL library") # Check whether the user has already installed ETL first find_package(${FSFW_ETL_LIB_NAME} ${FSFW_ETL_LIB_MAJOR_VERSION} QUIET) # Not installed, so use FetchContent to download and provide etl if(NOT ${FSFW_ETL_LIB_NAME}_FOUND) - message(STATUS - "No ETL installation was found with find_package. Installing and providing " - "etl with FindPackage" - ) - include(FetchContent) + message( + STATUS + "No ETL installation was found with find_package. Installing and providing " + "etl with FindPackage") + include(FetchContent) - FetchContent_Declare( - ${FSFW_ETL_LIB_NAME} - GIT_REPOSITORY https://github.com/ETLCPP/etl - GIT_TAG ${FSFW_ETL_LIB_VERSION} - ) + FetchContent_Declare( + ${FSFW_ETL_LIB_NAME} + GIT_REPOSITORY https://github.com/ETLCPP/etl + GIT_TAG ${FSFW_ETL_LIB_VERSION}) - list(APPEND FSFW_FETCH_CONTENT_TARGETS ${FSFW_ETL_LIB_NAME}) + 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() + 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") @@ -145,275 +222,242 @@ set(FSFW_CORE_INC_PATH "inc") set_property(CACHE FSFW_OSAL PROPERTY STRINGS host linux rtems freertos) # For configure files -target_include_directories(${LIB_FSFW_NAME} PRIVATE - ${CMAKE_CURRENT_BINARY_DIR} -) -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() +target_include_directories(${LIB_FSFW_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) +target_include_directories(${LIB_FSFW_NAME} + INTERFACE ${CMAKE_CURRENT_BINARY_DIR}) # Backwards comptability if(OS_FSFW AND NOT FSFW_OSAL) - message(WARNING "Please pass the FSFW OSAL as FSFW_OSAL instead of OS_FSFW") - set(FSFW_OSAL OS_FSFW) + message( + WARNING + "${MSG_PREFIX} Please pass the FSFW OSAL as FSFW_OSAL instead of OS_FSFW") + set(FSFW_OSAL OS_FSFW) endif() if(NOT FSFW_OSAL) - message(STATUS "No OS for FSFW via FSFW_OSAL set. Assuming host OS") - # Assume host OS and autodetermine from OS_FSFW - if(UNIX) - set(FSFW_OSAL "linux" - CACHE STRING - "OS abstraction layer used in the FSFW" - ) - elseif(WIN32) - set(FSFW_OSAL "host" - CACHE STRING "OS abstraction layer used in the FSFW" - ) - endif() - + message(STATUS "No OS for FSFW via FSFW_OSAL set. Assuming host OS") + # Assume host OS and autodetermine from OS_FSFW + if(UNIX) + set(FSFW_OSAL + "linux" + CACHE STRING "OS abstraction layer used in the FSFW") + elseif(WIN32) + set(FSFW_OSAL + "host" + CACHE STRING "OS abstraction layer used in the FSFW") + endif() endif() set(FSFW_OSAL_DEFINITION FSFW_OSAL_HOST) if(FSFW_OSAL MATCHES host) - set(FSFW_OS_NAME "Host") - set(FSFW_OSAL_HOST ON) + set(FSFW_OS_NAME "Host") + set(FSFW_OSAL_HOST ON) elseif(FSFW_OSAL MATCHES linux) - set(FSFW_OS_NAME "Linux") - set(FSFW_OSAL_LINUX ON) + set(FSFW_OS_NAME "Linux") + set(FSFW_OSAL_LINUX ON) elseif(FSFW_OSAL MATCHES freertos) - set(FSFW_OS_NAME "FreeRTOS") - set(FSFW_OSAL_FREERTOS ON) - target_link_libraries(${LIB_FSFW_NAME} PRIVATE - ${LIB_OS_NAME} - ) + set(FSFW_OS_NAME "FreeRTOS") + set(FSFW_OSAL_FREERTOS ON) + target_link_libraries(${LIB_FSFW_NAME} PRIVATE ${LIB_OS_NAME}) elseif(FSFW_OSAL STREQUAL rtems) - set(FSFW_OS_NAME "RTEMS") - set(FSFW_OSAL_RTEMS ON) + set(FSFW_OS_NAME "RTEMS") + set(FSFW_OSAL_RTEMS ON) else() - message(WARNING - "Invalid operating system for FSFW specified! Setting to host.." - ) - set(FSFW_OS_NAME "Host") - set(OS_FSFW "host") + message( + WARNING + "${MSG_PREFIX} Invalid operating system for FSFW specified! Setting to host.." + ) + set(FSFW_OS_NAME "Host") + set(OS_FSFW "host") endif() configure_file(src/fsfw/FSFW.h.in fsfw/FSFW.h) configure_file(src/fsfw/FSFWVersion.h.in fsfw/FSFWVersion.h) -message(STATUS "Compiling FSFW for the ${FSFW_OS_NAME} operating system.") +message( + STATUS "${MSG_PREFIX} Compiling FSFW for the ${FSFW_OS_NAME} operating system" +) add_subdirectory(src) add_subdirectory(tests) if(FSFW_ADD_HAL) - add_subdirectory(hal) + add_subdirectory(hal) endif() add_subdirectory(contrib) if(FSFW_BUILD_DOCS) - add_subdirectory(docs) + add_subdirectory(docs) endif() if(FSFW_BUILD_UNITTESTS) - if(FSFW_TESTS_GEN_COV) - if(CMAKE_COMPILER_IS_GNUCXX) - include(CodeCoverage) + if(FSFW_TESTS_GEN_COV) + if(CMAKE_COMPILER_IS_GNUCXX) + include(CodeCoverage) - # Remove quotes. - separate_arguments(COVERAGE_COMPILER_FLAGS - NATIVE_COMMAND "${COVERAGE_COMPILER_FLAGS}" - ) + # Remove quotes. + separate_arguments(COVERAGE_COMPILER_FLAGS NATIVE_COMMAND + "${COVERAGE_COMPILER_FLAGS}") - # Add compile options manually, we don't want coverage for Catch2 - target_compile_options(${FSFW_TEST_TGT} PRIVATE - "${COVERAGE_COMPILER_FLAGS}" - ) - target_compile_options(${LIB_FSFW_NAME} PRIVATE - "${COVERAGE_COMPILER_FLAGS}" - ) + # Add compile options manually, we don't want coverage for Catch2 + target_compile_options(${FSFW_TEST_TGT} + PRIVATE "${COVERAGE_COMPILER_FLAGS}") + target_compile_options(${LIB_FSFW_NAME} + PRIVATE "${COVERAGE_COMPILER_FLAGS}") - # Exclude directories here - if(WIN32) - set(GCOVR_ADDITIONAL_ARGS - "--exclude-throw-branches" - "--exclude-unreachable-branches" - ) - set(COVERAGE_EXCLUDES - "/c/msys64/mingw64/*" "*/fsfw_hal/*" - ) - elseif(UNIX) - set(COVERAGE_EXCLUDES - "/usr/include/*" "/usr/bin/*" "Catch2/*" - "/usr/local/include/*" "*/fsfw_tests/*" - "*/catch2-src/*" "*/fsfw_hal/*" - ) - endif() + # Exclude directories here + if(WIN32) + set(GCOVR_ADDITIONAL_ARGS "--exclude-throw-branches" + "--exclude-unreachable-branches") + set(COVERAGE_EXCLUDES "/c/msys64/mingw64/*" "*/fsfw_hal/*") + elseif(UNIX) + set(COVERAGE_EXCLUDES + "/usr/include/*" + "/usr/bin/*" + "Catch2/*" + "/usr/local/include/*" + "*/fsfw_tests/*" + "*/catch2-src/*" + "*/fsfw_hal/*") + endif() - target_link_options(${FSFW_TEST_TGT} PRIVATE - -fprofile-arcs - -ftest-coverage - ) - target_link_options(${LIB_FSFW_NAME} PRIVATE - -fprofile-arcs - -ftest-coverage - ) - # Need to specify this as an interface, otherwise there will the compile issues - target_link_options(${LIB_FSFW_NAME} INTERFACE - -fprofile-arcs - -ftest-coverage - ) + target_link_options(${FSFW_TEST_TGT} PRIVATE -fprofile-arcs + -ftest-coverage) + target_link_options(${LIB_FSFW_NAME} PRIVATE -fprofile-arcs + -ftest-coverage) + # Need to specify this as an interface, otherwise there will the compile + # issues + target_link_options(${LIB_FSFW_NAME} INTERFACE -fprofile-arcs + -ftest-coverage) - if(WIN32) - setup_target_for_coverage_gcovr_html( - NAME ${FSFW_TEST_TGT}_coverage - EXECUTABLE ${FSFW_TEST_TGT} - DEPENDENCIES ${FSFW_TEST_TGT} - ) - else() - setup_target_for_coverage_lcov( - NAME ${FSFW_TEST_TGT}_coverage - EXECUTABLE ${FSFW_TEST_TGT} - DEPENDENCIES ${FSFW_TEST_TGT} - ) - endif() - endif() + if(WIN32) + setup_target_for_coverage_gcovr_html( + NAME ${FSFW_TEST_TGT}_coverage EXECUTABLE ${FSFW_TEST_TGT} + DEPENDENCIES ${FSFW_TEST_TGT}) + else() + setup_target_for_coverage_lcov( + NAME ${FSFW_TEST_TGT}_coverage EXECUTABLE ${FSFW_TEST_TGT} + DEPENDENCIES ${FSFW_TEST_TGT}) + endif() endif() - target_link_libraries(${FSFW_TEST_TGT} PRIVATE Catch2::Catch2 ${LIB_FSFW_NAME}) + endif() + target_link_libraries(${FSFW_TEST_TGT} PRIVATE Catch2::Catch2 + ${LIB_FSFW_NAME}) endif() -# The project CMakeLists file has to set the FSFW_CONFIG_PATH and add it. -# If this is not given, we include the default configuration and emit a warning. +# The project CMakeLists file has to set the FSFW_CONFIG_PATH and add it. If +# this is not given, we include the default configuration and emit a warning. if(NOT FSFW_CONFIG_PATH) - set(DEF_CONF_PATH misc/defaultcfg/fsfwconfig) - if(NOT FSFW_BUILD_DOCS) - message(WARNING "Flight Software Framework configuration path not set!") - message(WARNING "Setting default configuration from ${DEF_CONF_PATH} ..") - endif() - add_subdirectory(${DEF_CONF_PATH}) - set(FSFW_CONFIG_PATH ${DEF_CONF_PATH}) + set(DEF_CONF_PATH misc/defaultcfg/fsfwconfig) + if(NOT FSFW_BUILD_DOCS) + message( + WARNING + "${MSG_PREFIX} Flight Software Framework configuration path not set") + message( + WARNING + "${MSG_PREFIX} Setting default configuration from ${DEF_CONF_PATH} ..") + endif() + add_subdirectory(${DEF_CONF_PATH}) + set(FSFW_CONFIG_PATH ${DEF_CONF_PATH}) endif() -# FSFW might be part of a possibly complicated folder structure, so we -# extract the absolute path of the fsfwconfig folder. +# FSFW might be part of a possibly complicated folder structure, so we extract +# the absolute path of the fsfwconfig folder. if(IS_ABSOLUTE ${FSFW_CONFIG_PATH}) - set(FSFW_CONFIG_PATH_ABSOLUTE ${FSFW_CONFIG_PATH}) + set(FSFW_CONFIG_PATH_ABSOLUTE ${FSFW_CONFIG_PATH}) else() - get_filename_component(FSFW_CONFIG_PATH_ABSOLUTE - ${FSFW_CONFIG_PATH} REALPATH BASE_DIR ${CMAKE_SOURCE_DIR} - ) + get_filename_component(FSFW_CONFIG_PATH_ABSOLUTE ${FSFW_CONFIG_PATH} REALPATH + BASE_DIR ${CMAKE_SOURCE_DIR}) endif() foreach(INCLUDE_PATH ${FSFW_ADDITIONAL_INC_PATHS}) - if(IS_ABSOLUTE ${INCLUDE_PATH}) - set(CURR_ABS_INC_PATH "${INCLUDE_PATH}") - else() - get_filename_component(CURR_ABS_INC_PATH - ${INCLUDE_PATH} REALPATH BASE_DIR ${CMAKE_SOURCE_DIR}) - endif() + if(IS_ABSOLUTE ${INCLUDE_PATH}) + set(CURR_ABS_INC_PATH "${INCLUDE_PATH}") + else() + get_filename_component(CURR_ABS_INC_PATH ${INCLUDE_PATH} REALPATH BASE_DIR + ${CMAKE_SOURCE_DIR}) + endif() - if(CMAKE_VERBOSE) - message(STATUS "FSFW include path: ${CURR_ABS_INC_PATH}") - endif() + if(CMAKE_VERBOSE) + message(STATUS "FSFW include path: ${CURR_ABS_INC_PATH}") + endif() - list(APPEND FSFW_ADD_INC_PATHS_ABS ${CURR_ABS_INC_PATH}) + list(APPEND FSFW_ADD_INC_PATHS_ABS ${CURR_ABS_INC_PATH}) endforeach() if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - if(NOT DEFINED FSFW_WARNING_FLAGS) - set(FSFW_WARNING_FLAGS - -Wall - -Wextra - -Wimplicit-fallthrough=1 - -Wno-unused-parameter - -Wno-psabi - -Wduplicated-cond # check for duplicate conditions - -Wduplicated-branches # check for duplicate branches - -Wlogical-op # Search for bitwise operations instead of logical - -Wnull-dereference # Search for NULL dereference - -Wundef # Warn if undefind marcos are used - -Wformat=2 # Format string problem detection - -Wformat-overflow=2 # Formatting issues in printf - -Wformat-truncation=2 # Formatting issues in printf - -Wformat-security # Search for dangerous printf operations - -Wstrict-overflow=3 # Warn if integer overflows might happen - -Warray-bounds=2 # Some array bounds violations will be found - -Wshift-overflow=2 # Search for bit left shift overflows ( for --xml and --html output respectively. +# This will allow for Multiple Output Formats at the same time by making use of GCOVR_ADDITIONAL_ARGS, e.g. GCOVR_ADDITIONAL_ARGS "--txt". +# +# USAGE: +# +# 1. Copy this file into your cmake modules path. +# +# 2. Add the following line to your CMakeLists.txt (best inside an if-condition +# using a CMake option() to enable it just optionally): +# include(CodeCoverage) +# +# 3. Append necessary compiler flags for all supported source files: +# append_coverage_compiler_flags() +# Or for specific target: +# append_coverage_compiler_flags_to_target(YOUR_TARGET_NAME) +# +# 3.a (OPTIONAL) Set appropriate optimization flags, e.g. -O0, -O1 or -Og +# +# 4. If you need to exclude additional directories from the report, specify them +# using full paths in the COVERAGE_EXCLUDES variable before calling +# setup_target_for_coverage_*(). +# Example: +# set(COVERAGE_EXCLUDES +# '${PROJECT_SOURCE_DIR}/src/dir1/*' +# '/path/to/my/src/dir2/*') +# Or, use the EXCLUDE argument to setup_target_for_coverage_*(). +# Example: +# setup_target_for_coverage_lcov( +# NAME coverage +# EXECUTABLE testrunner +# EXCLUDE "${PROJECT_SOURCE_DIR}/src/dir1/*" "/path/to/my/src/dir2/*") +# +# 4.a NOTE: With CMake 3.4+, COVERAGE_EXCLUDES or EXCLUDE can also be set +# relative to the BASE_DIRECTORY (default: PROJECT_SOURCE_DIR) +# Example: +# set(COVERAGE_EXCLUDES "dir1/*") +# setup_target_for_coverage_gcovr_html( +# NAME coverage +# EXECUTABLE testrunner +# BASE_DIRECTORY "${PROJECT_SOURCE_DIR}/src" +# EXCLUDE "dir2/*") +# +# 5. Use the functions described below to create a custom make target which +# runs your test executable and produces a code coverage report. +# +# 6. Build a Debug build: +# cmake -DCMAKE_BUILD_TYPE=Debug .. +# make +# make my_coverage_target +# + +include(CMakeParseArguments) + +option(CODE_COVERAGE_VERBOSE "Verbose information" FALSE) + +# Check prereqs +find_program( GCOV_PATH gcov ) +find_program( LCOV_PATH NAMES lcov lcov.bat lcov.exe lcov.perl) +find_program( FASTCOV_PATH NAMES fastcov fastcov.py ) +find_program( GENHTML_PATH NAMES genhtml genhtml.perl genhtml.bat ) +find_program( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/scripts/test) +find_program( CPPFILT_PATH NAMES c++filt ) + +if(NOT GCOV_PATH) + message(FATAL_ERROR "gcov not found! Aborting...") +endif() # NOT GCOV_PATH + +get_property(LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) +list(GET LANGUAGES 0 LANG) + +if("${CMAKE_${LANG}_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang") + if("${CMAKE_${LANG}_COMPILER_VERSION}" VERSION_LESS 3) + message(FATAL_ERROR "Clang version must be 3.0.0 or greater! Aborting...") + endif() +elseif(NOT CMAKE_COMPILER_IS_GNUCXX) + if("${CMAKE_Fortran_COMPILER_ID}" MATCHES "[Ff]lang") + # Do nothing; exit conditional without error if true + elseif("${CMAKE_Fortran_COMPILER_ID}" MATCHES "GNU") + # Do nothing; exit conditional without error if true + else() + message(FATAL_ERROR "Compiler is not GNU gcc! Aborting...") + endif() +endif() + +set(COVERAGE_COMPILER_FLAGS "-g -fprofile-arcs -ftest-coverage" + CACHE INTERNAL "") +if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)") + include(CheckCXXCompilerFlag) + check_cxx_compiler_flag(-fprofile-abs-path HAVE_fprofile_abs_path) + if(HAVE_fprofile_abs_path) + set(COVERAGE_COMPILER_FLAGS "${COVERAGE_COMPILER_FLAGS} -fprofile-abs-path") + endif() +endif() + +set(CMAKE_Fortran_FLAGS_COVERAGE + ${COVERAGE_COMPILER_FLAGS} + CACHE STRING "Flags used by the Fortran compiler during coverage builds." + FORCE ) +set(CMAKE_CXX_FLAGS_COVERAGE + ${COVERAGE_COMPILER_FLAGS} + CACHE STRING "Flags used by the C++ compiler during coverage builds." + FORCE ) +set(CMAKE_C_FLAGS_COVERAGE + ${COVERAGE_COMPILER_FLAGS} + CACHE STRING "Flags used by the C compiler during coverage builds." + FORCE ) +set(CMAKE_EXE_LINKER_FLAGS_COVERAGE + "" + CACHE STRING "Flags used for linking binaries during coverage builds." + FORCE ) +set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE + "" + CACHE STRING "Flags used by the shared libraries linker during coverage builds." + FORCE ) +mark_as_advanced( + CMAKE_Fortran_FLAGS_COVERAGE + CMAKE_CXX_FLAGS_COVERAGE + CMAKE_C_FLAGS_COVERAGE + CMAKE_EXE_LINKER_FLAGS_COVERAGE + CMAKE_SHARED_LINKER_FLAGS_COVERAGE ) + +get_property(GENERATOR_IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(NOT (CMAKE_BUILD_TYPE STREQUAL "Debug" OR GENERATOR_IS_MULTI_CONFIG)) + message(WARNING "Code coverage results with an optimised (non-Debug) build may be misleading") +endif() # NOT (CMAKE_BUILD_TYPE STREQUAL "Debug" OR GENERATOR_IS_MULTI_CONFIG) + +if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_Fortran_COMPILER_ID STREQUAL "GNU") + link_libraries(gcov) +endif() + +# Defines a target for running and collection code coverage information +# Builds dependencies, runs the given executable and outputs reports. +# NOTE! The executable should always have a ZERO as exit code otherwise +# the coverage generation will not complete. +# +# setup_target_for_coverage_lcov( +# NAME testrunner_coverage # New target name +# EXECUTABLE testrunner -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR +# DEPENDENCIES testrunner # Dependencies to build first +# BASE_DIRECTORY "../" # Base directory for report +# # (defaults to PROJECT_SOURCE_DIR) +# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative +# # to BASE_DIRECTORY, with CMake 3.4+) +# NO_DEMANGLE # Don't demangle C++ symbols +# # even if c++filt is found +# ) +function(setup_target_for_coverage_lcov) + + set(options NO_DEMANGLE) + set(oneValueArgs BASE_DIRECTORY NAME) + set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES LCOV_ARGS GENHTML_ARGS) + cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if(NOT LCOV_PATH) + message(FATAL_ERROR "lcov not found! Aborting...") + endif() # NOT LCOV_PATH + + if(NOT GENHTML_PATH) + message(FATAL_ERROR "genhtml not found! Aborting...") + endif() # NOT GENHTML_PATH + + # Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR + if(DEFINED Coverage_BASE_DIRECTORY) + get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE) + else() + set(BASEDIR ${PROJECT_SOURCE_DIR}) + endif() + + # Collect excludes (CMake 3.4+: Also compute absolute paths) + set(LCOV_EXCLUDES "") + foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_LCOV_EXCLUDES}) + if(CMAKE_VERSION VERSION_GREATER 3.4) + get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR}) + endif() + list(APPEND LCOV_EXCLUDES "${EXCLUDE}") + endforeach() + list(REMOVE_DUPLICATES LCOV_EXCLUDES) + + # Conditional arguments + if(CPPFILT_PATH AND NOT ${Coverage_NO_DEMANGLE}) + set(GENHTML_EXTRA_ARGS "--demangle-cpp") + endif() + + # Setting up commands which will be run to generate coverage data. + # Cleanup lcov + set(LCOV_CLEAN_CMD + ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -directory . + -b ${BASEDIR} --zerocounters + ) + # Create baseline to make sure untouched files show up in the report + set(LCOV_BASELINE_CMD + ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -c -i -d . -b + ${BASEDIR} -o ${Coverage_NAME}.base + ) + # Run tests + set(LCOV_EXEC_TESTS_CMD + ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS} + ) + # Capturing lcov counters and generating report + set(LCOV_CAPTURE_CMD + ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --directory . -b + ${BASEDIR} --capture --output-file ${Coverage_NAME}.capture + ) + # add baseline counters + set(LCOV_BASELINE_COUNT_CMD + ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -a ${Coverage_NAME}.base + -a ${Coverage_NAME}.capture --output-file ${Coverage_NAME}.total + ) + # filter collected data to final coverage report + set(LCOV_FILTER_CMD + ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --remove + ${Coverage_NAME}.total ${LCOV_EXCLUDES} --output-file ${Coverage_NAME}.info + ) + # Generate HTML output + set(LCOV_GEN_HTML_CMD + ${GENHTML_PATH} ${GENHTML_EXTRA_ARGS} ${Coverage_GENHTML_ARGS} -o + ${Coverage_NAME} ${Coverage_NAME}.info + ) + + + if(CODE_COVERAGE_VERBOSE) + message(STATUS "Executed command report") + message(STATUS "Command to clean up lcov: ") + string(REPLACE ";" " " LCOV_CLEAN_CMD_SPACED "${LCOV_CLEAN_CMD}") + message(STATUS "${LCOV_CLEAN_CMD_SPACED}") + + message(STATUS "Command to create baseline: ") + string(REPLACE ";" " " LCOV_BASELINE_CMD_SPACED "${LCOV_BASELINE_CMD}") + message(STATUS "${LCOV_BASELINE_CMD_SPACED}") + + message(STATUS "Command to run the tests: ") + string(REPLACE ";" " " LCOV_EXEC_TESTS_CMD_SPACED "${LCOV_EXEC_TESTS_CMD}") + message(STATUS "${LCOV_EXEC_TESTS_CMD_SPACED}") + + message(STATUS "Command to capture counters and generate report: ") + string(REPLACE ";" " " LCOV_CAPTURE_CMD_SPACED "${LCOV_CAPTURE_CMD}") + message(STATUS "${LCOV_CAPTURE_CMD_SPACED}") + + message(STATUS "Command to add baseline counters: ") + string(REPLACE ";" " " LCOV_BASELINE_COUNT_CMD_SPACED "${LCOV_BASELINE_COUNT_CMD}") + message(STATUS "${LCOV_BASELINE_COUNT_CMD_SPACED}") + + message(STATUS "Command to filter collected data: ") + string(REPLACE ";" " " LCOV_FILTER_CMD_SPACED "${LCOV_FILTER_CMD}") + message(STATUS "${LCOV_FILTER_CMD_SPACED}") + + message(STATUS "Command to generate lcov HTML output: ") + string(REPLACE ";" " " LCOV_GEN_HTML_CMD_SPACED "${LCOV_GEN_HTML_CMD}") + message(STATUS "${LCOV_GEN_HTML_CMD_SPACED}") + endif() + + # Setup target + add_custom_target(${Coverage_NAME} + COMMAND ${LCOV_CLEAN_CMD} + COMMAND ${LCOV_BASELINE_CMD} + COMMAND ${LCOV_EXEC_TESTS_CMD} + COMMAND ${LCOV_CAPTURE_CMD} + COMMAND ${LCOV_BASELINE_COUNT_CMD} + COMMAND ${LCOV_FILTER_CMD} + COMMAND ${LCOV_GEN_HTML_CMD} + + # Set output files as GENERATED (will be removed on 'make clean') + BYPRODUCTS + ${Coverage_NAME}.base + ${Coverage_NAME}.capture + ${Coverage_NAME}.total + ${Coverage_NAME}.info + ${Coverage_NAME}/index.html + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + DEPENDS ${Coverage_DEPENDENCIES} + VERBATIM # Protect arguments to commands + COMMENT "Resetting code coverage counters to zero.\nProcessing code coverage counters and generating report." + ) + + # Show where to find the lcov info report + add_custom_command(TARGET ${Coverage_NAME} POST_BUILD + COMMAND ; + COMMENT "Lcov code coverage info report saved in ${Coverage_NAME}.info." + ) + + # Show info where to find the report + add_custom_command(TARGET ${Coverage_NAME} POST_BUILD + COMMAND ; + COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report." + ) + +endfunction() # setup_target_for_coverage_lcov + +# Defines a target for running and collection code coverage information +# Builds dependencies, runs the given executable and outputs reports. +# NOTE! The executable should always have a ZERO as exit code otherwise +# the coverage generation will not complete. +# +# setup_target_for_coverage_gcovr_xml( +# NAME ctest_coverage # New target name +# EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR +# DEPENDENCIES executable_target # Dependencies to build first +# BASE_DIRECTORY "../" # Base directory for report +# # (defaults to PROJECT_SOURCE_DIR) +# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative +# # to BASE_DIRECTORY, with CMake 3.4+) +# ) +# The user can set the variable GCOVR_ADDITIONAL_ARGS to supply additional flags to the +# GCVOR command. +function(setup_target_for_coverage_gcovr_xml) + + set(options NONE) + set(oneValueArgs BASE_DIRECTORY NAME) + set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES) + cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if(NOT GCOVR_PATH) + message(FATAL_ERROR "gcovr not found! Aborting...") + endif() # NOT GCOVR_PATH + + # Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR + if(DEFINED Coverage_BASE_DIRECTORY) + get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE) + else() + set(BASEDIR ${PROJECT_SOURCE_DIR}) + endif() + + # Collect excludes (CMake 3.4+: Also compute absolute paths) + set(GCOVR_EXCLUDES "") + foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_GCOVR_EXCLUDES}) + if(CMAKE_VERSION VERSION_GREATER 3.4) + get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR}) + endif() + list(APPEND GCOVR_EXCLUDES "${EXCLUDE}") + endforeach() + list(REMOVE_DUPLICATES GCOVR_EXCLUDES) + + # Combine excludes to several -e arguments + set(GCOVR_EXCLUDE_ARGS "") + foreach(EXCLUDE ${GCOVR_EXCLUDES}) + list(APPEND GCOVR_EXCLUDE_ARGS "-e") + list(APPEND GCOVR_EXCLUDE_ARGS "${EXCLUDE}") + endforeach() + + # Set up commands which will be run to generate coverage data + # Run tests + set(GCOVR_XML_EXEC_TESTS_CMD + ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS} + ) + # Running gcovr + set(GCOVR_XML_CMD + ${GCOVR_PATH} --xml ${Coverage_NAME}.xml -r ${BASEDIR} ${GCOVR_ADDITIONAL_ARGS} + ${GCOVR_EXCLUDE_ARGS} --object-directory=${PROJECT_BINARY_DIR} + ) + + if(CODE_COVERAGE_VERBOSE) + message(STATUS "Executed command report") + + message(STATUS "Command to run tests: ") + string(REPLACE ";" " " GCOVR_XML_EXEC_TESTS_CMD_SPACED "${GCOVR_XML_EXEC_TESTS_CMD}") + message(STATUS "${GCOVR_XML_EXEC_TESTS_CMD_SPACED}") + + message(STATUS "Command to generate gcovr XML coverage data: ") + string(REPLACE ";" " " GCOVR_XML_CMD_SPACED "${GCOVR_XML_CMD}") + message(STATUS "${GCOVR_XML_CMD_SPACED}") + endif() + + add_custom_target(${Coverage_NAME} + COMMAND ${GCOVR_XML_EXEC_TESTS_CMD} + COMMAND ${GCOVR_XML_CMD} + + BYPRODUCTS ${Coverage_NAME}.xml + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + DEPENDS ${Coverage_DEPENDENCIES} + VERBATIM # Protect arguments to commands + COMMENT "Running gcovr to produce Cobertura code coverage report." + ) + + # Show info where to find the report + add_custom_command(TARGET ${Coverage_NAME} POST_BUILD + COMMAND ; + COMMENT "Cobertura code coverage report saved in ${Coverage_NAME}.xml." + ) +endfunction() # setup_target_for_coverage_gcovr_xml + +# Defines a target for running and collection code coverage information +# Builds dependencies, runs the given executable and outputs reports. +# NOTE! The executable should always have a ZERO as exit code otherwise +# the coverage generation will not complete. +# +# setup_target_for_coverage_gcovr_html( +# NAME ctest_coverage # New target name +# EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR +# DEPENDENCIES executable_target # Dependencies to build first +# BASE_DIRECTORY "../" # Base directory for report +# # (defaults to PROJECT_SOURCE_DIR) +# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative +# # to BASE_DIRECTORY, with CMake 3.4+) +# ) +# The user can set the variable GCOVR_ADDITIONAL_ARGS to supply additional flags to the +# GCVOR command. +function(setup_target_for_coverage_gcovr_html) + + set(options NONE) + set(oneValueArgs BASE_DIRECTORY NAME) + set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES) + cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if(NOT GCOVR_PATH) + message(FATAL_ERROR "gcovr not found! Aborting...") + endif() # NOT GCOVR_PATH + + # Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR + if(DEFINED Coverage_BASE_DIRECTORY) + get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE) + else() + set(BASEDIR ${PROJECT_SOURCE_DIR}) + endif() + + # Collect excludes (CMake 3.4+: Also compute absolute paths) + set(GCOVR_EXCLUDES "") + foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_GCOVR_EXCLUDES}) + if(CMAKE_VERSION VERSION_GREATER 3.4) + get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR}) + endif() + list(APPEND GCOVR_EXCLUDES "${EXCLUDE}") + endforeach() + list(REMOVE_DUPLICATES GCOVR_EXCLUDES) + + # Combine excludes to several -e arguments + set(GCOVR_EXCLUDE_ARGS "") + foreach(EXCLUDE ${GCOVR_EXCLUDES}) + list(APPEND GCOVR_EXCLUDE_ARGS "-e") + list(APPEND GCOVR_EXCLUDE_ARGS "${EXCLUDE}") + endforeach() + + # Set up commands which will be run to generate coverage data + # Run tests + set(GCOVR_HTML_EXEC_TESTS_CMD + ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS} + ) + # Create folder + set(GCOVR_HTML_FOLDER_CMD + ${CMAKE_COMMAND} -E make_directory ${PROJECT_BINARY_DIR}/${Coverage_NAME} + ) + # Running gcovr + set(GCOVR_HTML_CMD + ${GCOVR_PATH} --html ${Coverage_NAME}/index.html --html-details -r ${BASEDIR} ${GCOVR_ADDITIONAL_ARGS} + ${GCOVR_EXCLUDE_ARGS} --object-directory=${PROJECT_BINARY_DIR} + ) + + if(CODE_COVERAGE_VERBOSE) + message(STATUS "Executed command report") + + message(STATUS "Command to run tests: ") + string(REPLACE ";" " " GCOVR_HTML_EXEC_TESTS_CMD_SPACED "${GCOVR_HTML_EXEC_TESTS_CMD}") + message(STATUS "${GCOVR_HTML_EXEC_TESTS_CMD_SPACED}") + + message(STATUS "Command to create a folder: ") + string(REPLACE ";" " " GCOVR_HTML_FOLDER_CMD_SPACED "${GCOVR_HTML_FOLDER_CMD}") + message(STATUS "${GCOVR_HTML_FOLDER_CMD_SPACED}") + + message(STATUS "Command to generate gcovr HTML coverage data: ") + string(REPLACE ";" " " GCOVR_HTML_CMD_SPACED "${GCOVR_HTML_CMD}") + message(STATUS "${GCOVR_HTML_CMD_SPACED}") + endif() + + add_custom_target(${Coverage_NAME} + COMMAND ${GCOVR_HTML_EXEC_TESTS_CMD} + COMMAND ${GCOVR_HTML_FOLDER_CMD} + COMMAND ${GCOVR_HTML_CMD} + + BYPRODUCTS ${PROJECT_BINARY_DIR}/${Coverage_NAME}/index.html # report directory + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + DEPENDS ${Coverage_DEPENDENCIES} + VERBATIM # Protect arguments to commands + COMMENT "Running gcovr to produce HTML code coverage report." + ) + + # Show info where to find the report + add_custom_command(TARGET ${Coverage_NAME} POST_BUILD + COMMAND ; + COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report." + ) + +endfunction() # setup_target_for_coverage_gcovr_html + +# Defines a target for running and collection code coverage information +# Builds dependencies, runs the given executable and outputs reports. +# NOTE! The executable should always have a ZERO as exit code otherwise +# the coverage generation will not complete. +# +# setup_target_for_coverage_fastcov( +# NAME testrunner_coverage # New target name +# EXECUTABLE testrunner -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR +# DEPENDENCIES testrunner # Dependencies to build first +# BASE_DIRECTORY "../" # Base directory for report +# # (defaults to PROJECT_SOURCE_DIR) +# EXCLUDE "src/dir1/" "src/dir2/" # Patterns to exclude. +# NO_DEMANGLE # Don't demangle C++ symbols +# # even if c++filt is found +# SKIP_HTML # Don't create html report +# POST_CMD perl -i -pe s!${PROJECT_SOURCE_DIR}/!!g ctest_coverage.json # E.g. for stripping source dir from file paths +# ) +function(setup_target_for_coverage_fastcov) + + set(options NO_DEMANGLE SKIP_HTML) + set(oneValueArgs BASE_DIRECTORY NAME) + set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES FASTCOV_ARGS GENHTML_ARGS POST_CMD) + cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if(NOT FASTCOV_PATH) + message(FATAL_ERROR "fastcov not found! Aborting...") + endif() + + if(NOT Coverage_SKIP_HTML AND NOT GENHTML_PATH) + message(FATAL_ERROR "genhtml not found! Aborting...") + endif() + + # Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR + if(Coverage_BASE_DIRECTORY) + get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE) + else() + set(BASEDIR ${PROJECT_SOURCE_DIR}) + endif() + + # Collect excludes (Patterns, not paths, for fastcov) + set(FASTCOV_EXCLUDES "") + foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_FASTCOV_EXCLUDES}) + list(APPEND FASTCOV_EXCLUDES "${EXCLUDE}") + endforeach() + list(REMOVE_DUPLICATES FASTCOV_EXCLUDES) + + # Conditional arguments + if(CPPFILT_PATH AND NOT ${Coverage_NO_DEMANGLE}) + set(GENHTML_EXTRA_ARGS "--demangle-cpp") + endif() + + # Set up commands which will be run to generate coverage data + set(FASTCOV_EXEC_TESTS_CMD ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}) + + set(FASTCOV_CAPTURE_CMD ${FASTCOV_PATH} ${Coverage_FASTCOV_ARGS} --gcov ${GCOV_PATH} + --search-directory ${BASEDIR} + --process-gcno + --output ${Coverage_NAME}.json + --exclude ${FASTCOV_EXCLUDES} + --exclude ${FASTCOV_EXCLUDES} + ) + + set(FASTCOV_CONVERT_CMD ${FASTCOV_PATH} + -C ${Coverage_NAME}.json --lcov --output ${Coverage_NAME}.info + ) + + if(Coverage_SKIP_HTML) + set(FASTCOV_HTML_CMD ";") + else() + set(FASTCOV_HTML_CMD ${GENHTML_PATH} ${GENHTML_EXTRA_ARGS} ${Coverage_GENHTML_ARGS} + -o ${Coverage_NAME} ${Coverage_NAME}.info + ) + endif() + + set(FASTCOV_POST_CMD ";") + if(Coverage_POST_CMD) + set(FASTCOV_POST_CMD ${Coverage_POST_CMD}) + endif() + + if(CODE_COVERAGE_VERBOSE) + message(STATUS "Code coverage commands for target ${Coverage_NAME} (fastcov):") + + message(" Running tests:") + string(REPLACE ";" " " FASTCOV_EXEC_TESTS_CMD_SPACED "${FASTCOV_EXEC_TESTS_CMD}") + message(" ${FASTCOV_EXEC_TESTS_CMD_SPACED}") + + message(" Capturing fastcov counters and generating report:") + string(REPLACE ";" " " FASTCOV_CAPTURE_CMD_SPACED "${FASTCOV_CAPTURE_CMD}") + message(" ${FASTCOV_CAPTURE_CMD_SPACED}") + + message(" Converting fastcov .json to lcov .info:") + string(REPLACE ";" " " FASTCOV_CONVERT_CMD_SPACED "${FASTCOV_CONVERT_CMD}") + message(" ${FASTCOV_CONVERT_CMD_SPACED}") + + if(NOT Coverage_SKIP_HTML) + message(" Generating HTML report: ") + string(REPLACE ";" " " FASTCOV_HTML_CMD_SPACED "${FASTCOV_HTML_CMD}") + message(" ${FASTCOV_HTML_CMD_SPACED}") + endif() + if(Coverage_POST_CMD) + message(" Running post command: ") + string(REPLACE ";" " " FASTCOV_POST_CMD_SPACED "${FASTCOV_POST_CMD}") + message(" ${FASTCOV_POST_CMD_SPACED}") + endif() + endif() + + # Setup target + add_custom_target(${Coverage_NAME} + + # Cleanup fastcov + COMMAND ${FASTCOV_PATH} ${Coverage_FASTCOV_ARGS} --gcov ${GCOV_PATH} + --search-directory ${BASEDIR} + --zerocounters + + COMMAND ${FASTCOV_EXEC_TESTS_CMD} + COMMAND ${FASTCOV_CAPTURE_CMD} + COMMAND ${FASTCOV_CONVERT_CMD} + COMMAND ${FASTCOV_HTML_CMD} + COMMAND ${FASTCOV_POST_CMD} + + # Set output files as GENERATED (will be removed on 'make clean') + BYPRODUCTS + ${Coverage_NAME}.info + ${Coverage_NAME}.json + ${Coverage_NAME}/index.html # report directory + + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + DEPENDS ${Coverage_DEPENDENCIES} + VERBATIM # Protect arguments to commands + COMMENT "Resetting code coverage counters to zero. Processing code coverage counters and generating report." + ) + + set(INFO_MSG "fastcov code coverage info report saved in ${Coverage_NAME}.info and ${Coverage_NAME}.json.") + if(NOT Coverage_SKIP_HTML) + string(APPEND INFO_MSG " Open ${PROJECT_BINARY_DIR}/${Coverage_NAME}/index.html in your browser to view the coverage report.") + endif() + # Show where to find the fastcov info report + add_custom_command(TARGET ${Coverage_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E echo ${INFO_MSG} + ) + +endfunction() # setup_target_for_coverage_fastcov + +function(append_coverage_compiler_flags) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE) + set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE) + message(STATUS "Appending code coverage compiler flags: ${COVERAGE_COMPILER_FLAGS}") +endfunction() # append_coverage_compiler_flags + +# Setup coverage for specific library +function(append_coverage_compiler_flags_to_target name) + target_compile_options(${name} + PRIVATE ${COVERAGE_COMPILER_FLAGS}) +endfunction() diff --git a/cmake/cmake-modules/bilke/LICENSE_1_0.txt b/cmake/cmake-modules/bilke/LICENSE_1_0.txt new file mode 100644 index 00000000..36b7cd93 --- /dev/null +++ b/cmake/cmake-modules/bilke/LICENSE_1_0.txt @@ -0,0 +1,23 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/cmake/cmake-modules/rpavlik/GetGitRevisionDescription.cmake b/cmake/cmake-modules/rpavlik/GetGitRevisionDescription.cmake new file mode 100644 index 00000000..69ef78b2 --- /dev/null +++ b/cmake/cmake-modules/rpavlik/GetGitRevisionDescription.cmake @@ -0,0 +1,284 @@ +# - Returns a version string from Git +# +# These functions force a re-configure on each git commit so that you can +# trust the values of the variables in your build system. +# +# get_git_head_revision( [ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR]) +# +# Returns the refspec and sha hash of the current head revision +# +# git_describe( [ ...]) +# +# Returns the results of git describe on the source tree, and adjusting +# the output so that it tests false if an error occurs. +# +# git_describe_working_tree( [ ...]) +# +# Returns the results of git describe on the working tree (--dirty option), +# and adjusting the output so that it tests false if an error occurs. +# +# git_get_exact_tag( [ ...]) +# +# Returns the results of git describe --exact-match on the source tree, +# and adjusting the output so that it tests false if there was no exact +# matching tag. +# +# git_local_changes() +# +# Returns either "CLEAN" or "DIRTY" with respect to uncommitted changes. +# Uses the return code of "git diff-index --quiet HEAD --". +# Does not regard untracked files. +# +# Requires CMake 2.6 or newer (uses the 'function' command) +# +# Original Author: +# 2009-2020 Ryan Pavlik +# http://academic.cleardefinition.com +# +# Copyright 2009-2013, Iowa State University. +# Copyright 2013-2020, Ryan Pavlik +# Copyright 2013-2020, Contributors +# SPDX-License-Identifier: BSL-1.0 +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +if(__get_git_revision_description) + return() +endif() +set(__get_git_revision_description YES) + +# We must run the following at "include" time, not at function call time, +# to find the path to this module rather than the path to a calling list file +get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH) + +# Function _git_find_closest_git_dir finds the next closest .git directory +# that is part of any directory in the path defined by _start_dir. +# The result is returned in the parent scope variable whose name is passed +# as variable _git_dir_var. If no .git directory can be found, the +# function returns an empty string via _git_dir_var. +# +# Example: Given a path C:/bla/foo/bar and assuming C:/bla/.git exists and +# neither foo nor bar contain a file/directory .git. This wil return +# C:/bla/.git +# +function(_git_find_closest_git_dir _start_dir _git_dir_var) + set(cur_dir "${_start_dir}") + set(git_dir "${_start_dir}/.git") + while(NOT EXISTS "${git_dir}") + # .git dir not found, search parent directories + set(git_previous_parent "${cur_dir}") + get_filename_component(cur_dir "${cur_dir}" DIRECTORY) + if(cur_dir STREQUAL git_previous_parent) + # We have reached the root directory, we are not in git + set(${_git_dir_var} + "" + PARENT_SCOPE) + return() + endif() + set(git_dir "${cur_dir}/.git") + endwhile() + set(${_git_dir_var} + "${git_dir}" + PARENT_SCOPE) +endfunction() + +function(get_git_head_revision _refspecvar _hashvar) + _git_find_closest_git_dir("${CMAKE_CURRENT_SOURCE_DIR}" GIT_DIR) + + if("${ARGN}" STREQUAL "ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR") + set(ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR TRUE) + else() + set(ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR FALSE) + endif() + if(NOT "${GIT_DIR}" STREQUAL "") + file(RELATIVE_PATH _relative_to_source_dir "${CMAKE_SOURCE_DIR}" + "${GIT_DIR}") + if("${_relative_to_source_dir}" MATCHES "[.][.]" AND NOT ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR) + # We've gone above the CMake root dir. + set(GIT_DIR "") + endif() + endif() + if("${GIT_DIR}" STREQUAL "") + set(${_refspecvar} + "GITDIR-NOTFOUND" + PARENT_SCOPE) + set(${_hashvar} + "GITDIR-NOTFOUND" + PARENT_SCOPE) + return() + endif() + + # Check if the current source dir is a git submodule or a worktree. + # In both cases .git is a file instead of a directory. + # + if(NOT IS_DIRECTORY ${GIT_DIR}) + # The following git command will return a non empty string that + # points to the super project working tree if the current + # source dir is inside a git submodule. + # Otherwise the command will return an empty string. + # + execute_process( + COMMAND "${GIT_EXECUTABLE}" rev-parse + --show-superproject-working-tree + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + OUTPUT_VARIABLE out + ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) + if(NOT "${out}" STREQUAL "") + # If out is empty, GIT_DIR/CMAKE_CURRENT_SOURCE_DIR is in a submodule + file(READ ${GIT_DIR} submodule) + string(REGEX REPLACE "gitdir: (.*)$" "\\1" GIT_DIR_RELATIVE + ${submodule}) + string(STRIP ${GIT_DIR_RELATIVE} GIT_DIR_RELATIVE) + get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH) + get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE} + ABSOLUTE) + set(HEAD_SOURCE_FILE "${GIT_DIR}/HEAD") + else() + # GIT_DIR/CMAKE_CURRENT_SOURCE_DIR is in a worktree + file(READ ${GIT_DIR} worktree_ref) + # The .git directory contains a path to the worktree information directory + # inside the parent git repo of the worktree. + # + string(REGEX REPLACE "gitdir: (.*)$" "\\1" git_worktree_dir + ${worktree_ref}) + string(STRIP ${git_worktree_dir} git_worktree_dir) + _git_find_closest_git_dir("${git_worktree_dir}" GIT_DIR) + set(HEAD_SOURCE_FILE "${git_worktree_dir}/HEAD") + endif() + else() + set(HEAD_SOURCE_FILE "${GIT_DIR}/HEAD") + endif() + set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data") + if(NOT EXISTS "${GIT_DATA}") + file(MAKE_DIRECTORY "${GIT_DATA}") + endif() + + if(NOT EXISTS "${HEAD_SOURCE_FILE}") + return() + endif() + set(HEAD_FILE "${GIT_DATA}/HEAD") + configure_file("${HEAD_SOURCE_FILE}" "${HEAD_FILE}" COPYONLY) + + configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in" + "${GIT_DATA}/grabRef.cmake" @ONLY) + include("${GIT_DATA}/grabRef.cmake") + + set(${_refspecvar} + "${HEAD_REF}" + PARENT_SCOPE) + set(${_hashvar} + "${HEAD_HASH}" + PARENT_SCOPE) +endfunction() + +function(git_describe _var) + if(NOT GIT_FOUND) + find_package(Git QUIET) + endif() + get_git_head_revision(refspec hash) + if(NOT GIT_FOUND) + set(${_var} + "GIT-NOTFOUND" + PARENT_SCOPE) + return() + endif() + if(NOT hash) + set(${_var} + "HEAD-HASH-NOTFOUND" + PARENT_SCOPE) + return() + endif() + + # TODO sanitize + #if((${ARGN}" MATCHES "&&") OR + # (ARGN MATCHES "||") OR + # (ARGN MATCHES "\\;")) + # message("Please report the following error to the project!") + # message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}") + #endif() + + #message(STATUS "Arguments to execute_process: ${ARGN}") + + execute_process( + COMMAND "${GIT_EXECUTABLE}" describe --tags --always ${hash} ${ARGN} + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + RESULT_VARIABLE res + OUTPUT_VARIABLE out + ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) + if(NOT res EQUAL 0) + set(out "${out}-${res}-NOTFOUND") + endif() + + set(${_var} + "${out}" + PARENT_SCOPE) +endfunction() + +function(git_describe_working_tree _var) + if(NOT GIT_FOUND) + find_package(Git QUIET) + endif() + if(NOT GIT_FOUND) + set(${_var} + "GIT-NOTFOUND" + PARENT_SCOPE) + return() + endif() + + execute_process( + COMMAND "${GIT_EXECUTABLE}" describe --dirty ${ARGN} + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + RESULT_VARIABLE res + OUTPUT_VARIABLE out + ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) + if(NOT res EQUAL 0) + set(out "${out}-${res}-NOTFOUND") + endif() + + set(${_var} + "${out}" + PARENT_SCOPE) +endfunction() + +function(git_get_exact_tag _var) + git_describe(out --exact-match ${ARGN}) + set(${_var} + "${out}" + PARENT_SCOPE) +endfunction() + +function(git_local_changes _var) + if(NOT GIT_FOUND) + find_package(Git QUIET) + endif() + get_git_head_revision(refspec hash) + if(NOT GIT_FOUND) + set(${_var} + "GIT-NOTFOUND" + PARENT_SCOPE) + return() + endif() + if(NOT hash) + set(${_var} + "HEAD-HASH-NOTFOUND" + PARENT_SCOPE) + return() + endif() + + execute_process( + COMMAND "${GIT_EXECUTABLE}" diff-index --quiet HEAD -- + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + RESULT_VARIABLE res + OUTPUT_VARIABLE out + ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) + if(res EQUAL 0) + set(${_var} + "CLEAN" + PARENT_SCOPE) + else() + set(${_var} + "DIRTY" + PARENT_SCOPE) + endif() +endfunction() diff --git a/cmake/cmake-modules/rpavlik/GetGitRevisionDescription.cmake.in b/cmake/cmake-modules/rpavlik/GetGitRevisionDescription.cmake.in new file mode 100644 index 00000000..66eee637 --- /dev/null +++ b/cmake/cmake-modules/rpavlik/GetGitRevisionDescription.cmake.in @@ -0,0 +1,43 @@ +# +# Internal file for GetGitRevisionDescription.cmake +# +# Requires CMake 2.6 or newer (uses the 'function' command) +# +# Original Author: +# 2009-2010 Ryan Pavlik +# http://academic.cleardefinition.com +# Iowa State University HCI Graduate Program/VRAC +# +# Copyright 2009-2012, Iowa State University +# Copyright 2011-2015, Contributors +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) +# SPDX-License-Identifier: BSL-1.0 + +set(HEAD_HASH) + +file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024) + +string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS) +if(HEAD_CONTENTS MATCHES "ref") + # named branch + string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}") + if(EXISTS "@GIT_DIR@/${HEAD_REF}") + configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY) + else() + configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY) + file(READ "@GIT_DATA@/packed-refs" PACKED_REFS) + if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}") + set(HEAD_HASH "${CMAKE_MATCH_1}") + endif() + endif() +else() + # detached HEAD + configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY) +endif() + +if(NOT HEAD_HASH) + file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024) + string(STRIP "${HEAD_HASH}" HEAD_HASH) +endif() diff --git a/cmake/cmake-modules/rpavlik/LICENSES/BSD-3-Clause.txt b/cmake/cmake-modules/rpavlik/LICENSES/BSD-3-Clause.txt new file mode 100644 index 00000000..0741db78 --- /dev/null +++ b/cmake/cmake-modules/rpavlik/LICENSES/BSD-3-Clause.txt @@ -0,0 +1,26 @@ +Copyright (c) . All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/cmake/cmake-modules/rpavlik/LICENSES/BSL-1.0.txt b/cmake/cmake-modules/rpavlik/LICENSES/BSL-1.0.txt new file mode 100644 index 00000000..cff35365 --- /dev/null +++ b/cmake/cmake-modules/rpavlik/LICENSES/BSL-1.0.txt @@ -0,0 +1,23 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, execute, +and transmit the Software, and to prepare derivative works of the Software, +and to permit third-parties to whom the Software is furnished to do so, all +subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, must +be included in all copies of the Software, in whole or in part, and all derivative +works of the Software, unless such copies or derivative works are solely in +the form of machine-executable object code generated by a source language +processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES +OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/cmake/cmake-modules/rpavlik/LICENSE_1_0.txt b/cmake/cmake-modules/rpavlik/LICENSE_1_0.txt new file mode 100644 index 00000000..36b7cd93 --- /dev/null +++ b/cmake/cmake-modules/rpavlik/LICENSE_1_0.txt @@ -0,0 +1,23 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp b/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp index f46ad386..15061d14 100644 --- a/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp +++ b/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp @@ -20,7 +20,9 @@ LinuxLibgpioIF::~LinuxLibgpioIF() { ReturnValue_t LinuxLibgpioIF::addGpios(GpioCookie* gpioCookie) { ReturnValue_t result; if (gpioCookie == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "LinuxLibgpioIF::addGpios: Invalid cookie" << std::endl; +#endif return RETURN_FAILED; } @@ -96,8 +98,10 @@ ReturnValue_t LinuxLibgpioIF::configureGpioByLabel(gpioId_t gpioId, std::string& label = gpioByLabel.label; struct gpiod_chip* chip = gpiod_chip_open_by_label(label.c_str()); if (chip == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "LinuxLibgpioIF::configureGpioByLabel: Failed to open gpio from gpio " << "group with label " << label << ". Gpio ID: " << gpioId << std::endl; +#endif return RETURN_FAILED; } std::string failOutput = "label: " + label; @@ -108,8 +112,10 @@ ReturnValue_t LinuxLibgpioIF::configureGpioByChip(gpioId_t gpioId, GpiodRegularB std::string& chipname = gpioByChip.chipname; struct gpiod_chip* chip = gpiod_chip_open_by_name(chipname.c_str()); if (chip == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "LinuxLibgpioIF::configureGpioByChip: Failed to open chip " << chipname << ". Gpio ID: " << gpioId << std::endl; +#endif return RETURN_FAILED; } std::string failOutput = "chipname: " + chipname; @@ -133,8 +139,10 @@ ReturnValue_t LinuxLibgpioIF::configureGpioByLineName(gpioId_t gpioId, struct gpiod_chip* chip = gpiod_chip_open_by_name(chipname); if (chip == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "LinuxLibgpioIF::configureGpioByLineName: Failed to open chip " << chipname << ". /dev/null; then + ${cmake_fmt} -i CMakeLists.txt + find ./src ${file_selectors} | xargs ${cmake_fmt} -i +else + echo "No ${cmake_fmt} tool found, not formatting CMake files" +fi + +cpp_format="clang-format" +file_selectors="-iname *.h -o -iname *.cpp -o -iname *.c -o -iname *.tpp" +if command -v ${cpp_format} &> /dev/null; then + find ./src ${file_selectors} | xargs ${cpp_format} --style=file -i + find ./hal ${file_selectors} | xargs ${cpp_format} --style=file -i + find ./tests ${file_selectors} | xargs ${cpp_format} --style=file -i +else + echo "No ${cpp_format} tool found, not formatting C++/C files" +fi diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ed2f2522..34f21c2f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,9 +1,6 @@ -target_include_directories(${LIB_FSFW_NAME} PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR} -) +target_include_directories(${LIB_FSFW_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) -target_include_directories(${LIB_FSFW_NAME} INTERFACE - ${CMAKE_CURRENT_SOURCE_DIR} -) +target_include_directories(${LIB_FSFW_NAME} + INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) add_subdirectory(fsfw) diff --git a/src/fsfw/CMakeLists.txt b/src/fsfw/CMakeLists.txt index efb9f6c7..1daad714 100644 --- a/src/fsfw/CMakeLists.txt +++ b/src/fsfw/CMakeLists.txt @@ -1,6 +1,4 @@ -target_sources(${LIB_FSFW_NAME} PRIVATE - version.cpp -) +target_sources(${LIB_FSFW_NAME} PRIVATE version.cpp) # Core @@ -37,22 +35,22 @@ add_subdirectory(tmtcservices) # Optional if(FSFW_ADD_MONITORING) -add_subdirectory(monitoring) + add_subdirectory(monitoring) endif() if(FSFW_ADD_PUS) - add_subdirectory(pus) + add_subdirectory(pus) endif() if(FSFW_ADD_TMSTORAGE) - add_subdirectory(tmstorage) + add_subdirectory(tmstorage) endif() if(FSFW_ADD_COORDINATES) - add_subdirectory(coordinates) + add_subdirectory(coordinates) endif() if(FSFW_ADD_RMAP) - add_subdirectory(rmap) + add_subdirectory(rmap) endif() if(FSFW_ADD_DATALINKLAYER) - add_subdirectory(datalinklayer) + add_subdirectory(datalinklayer) endif() # OSAL diff --git a/src/fsfw/FSFWVersion.h.in b/src/fsfw/FSFWVersion.h.in index 19a56214..caff1efb 100644 --- a/src/fsfw/FSFWVersion.h.in +++ b/src/fsfw/FSFWVersion.h.in @@ -1,9 +1,11 @@ #ifndef FSFW_VERSION_H_ #define FSFW_VERSION_H_ -// Versioning is kept in project CMakeLists.txt file -#define FSFW_VERSION_MAJOR @FSFW_VERSION@ -#define FSFW_VERSION_MINOR @FSFW_SUBVERSION@ -#define FSFW_VERSION_REVISION @FSFW_REVISION@ +// Versioning is managed in project CMakeLists.txt file +static constexpr int FSFW_VERSION_MAJOR = @FSFW_VERSION@; +static constexpr int FSFW_VERSION_MINOR = @FSFW_SUBVERSION@; +static constexpr int FSFW_VERSION_REVISION = @FSFW_REVISION@; +// Also contains CST (Commits since tag) information +static const char FSFW_VCS_INFO[] = "@FSFW_VCS_INFO@"; #endif /* FSFW_VERSION_H_ */ diff --git a/src/fsfw/action/CMakeLists.txt b/src/fsfw/action/CMakeLists.txt index f9ac451d..7fb397af 100644 --- a/src/fsfw/action/CMakeLists.txt +++ b/src/fsfw/action/CMakeLists.txt @@ -1,7 +1,3 @@ -target_sources(${LIB_FSFW_NAME} - PRIVATE - ActionHelper.cpp - ActionMessage.cpp - CommandActionHelper.cpp - SimpleActionHelper.cpp -) \ No newline at end of file +target_sources( + ${LIB_FSFW_NAME} PRIVATE ActionHelper.cpp ActionMessage.cpp + CommandActionHelper.cpp SimpleActionHelper.cpp) diff --git a/src/fsfw/cfdp/CMakeLists.txt b/src/fsfw/cfdp/CMakeLists.txt index 908dc32a..0b926a9a 100644 --- a/src/fsfw/cfdp/CMakeLists.txt +++ b/src/fsfw/cfdp/CMakeLists.txt @@ -1,7 +1,4 @@ -target_sources(${LIB_FSFW_NAME} PRIVATE - CFDPHandler.cpp - CFDPMessage.cpp -) +target_sources(${LIB_FSFW_NAME} PRIVATE CFDPHandler.cpp CFDPMessage.cpp) add_subdirectory(pdu) add_subdirectory(tlv) diff --git a/src/fsfw/cfdp/pdu/CMakeLists.txt b/src/fsfw/cfdp/pdu/CMakeLists.txt index 931db306..4f345bdc 100644 --- a/src/fsfw/cfdp/pdu/CMakeLists.txt +++ b/src/fsfw/cfdp/pdu/CMakeLists.txt @@ -1,32 +1,30 @@ -target_sources(${LIB_FSFW_NAME} PRIVATE - PduConfig.cpp - VarLenField.cpp - HeaderSerializer.cpp - HeaderDeserializer.cpp - FileDirectiveDeserializer.cpp - FileDirectiveSerializer.cpp - - AckInfo.cpp - AckPduSerializer.cpp - AckPduDeserializer.cpp - EofInfo.cpp - EofPduSerializer.cpp - EofPduDeserializer.cpp - NakInfo.cpp - NakPduSerializer.cpp - NakPduDeserializer.cpp - FinishedInfo.cpp - FinishedPduSerializer.cpp - FinishedPduDeserializer.cpp - MetadataInfo.cpp - MetadataPduSerializer.cpp - MetadataPduDeserializer.cpp - KeepAlivePduSerializer.cpp - KeepAlivePduDeserializer.cpp - PromptPduSerializer.cpp - PromptPduDeserializer.cpp - - FileDataSerializer.cpp - FileDataDeserializer.cpp - FileDataInfo.cpp -) \ No newline at end of file +target_sources( + ${LIB_FSFW_NAME} + PRIVATE PduConfig.cpp + VarLenField.cpp + HeaderSerializer.cpp + HeaderDeserializer.cpp + FileDirectiveDeserializer.cpp + FileDirectiveSerializer.cpp + AckInfo.cpp + AckPduSerializer.cpp + AckPduDeserializer.cpp + EofInfo.cpp + EofPduSerializer.cpp + EofPduDeserializer.cpp + NakInfo.cpp + NakPduSerializer.cpp + NakPduDeserializer.cpp + FinishedInfo.cpp + FinishedPduSerializer.cpp + FinishedPduDeserializer.cpp + MetadataInfo.cpp + MetadataPduSerializer.cpp + MetadataPduDeserializer.cpp + KeepAlivePduSerializer.cpp + KeepAlivePduDeserializer.cpp + PromptPduSerializer.cpp + PromptPduDeserializer.cpp + FileDataSerializer.cpp + FileDataDeserializer.cpp + FileDataInfo.cpp) diff --git a/src/fsfw/cfdp/tlv/CMakeLists.txt b/src/fsfw/cfdp/tlv/CMakeLists.txt index 24459cf8..cdf7b44a 100644 --- a/src/fsfw/cfdp/tlv/CMakeLists.txt +++ b/src/fsfw/cfdp/tlv/CMakeLists.txt @@ -1,10 +1,10 @@ -target_sources(${LIB_FSFW_NAME} PRIVATE - EntityIdTlv.cpp - FilestoreRequestTlv.cpp - FilestoreResponseTlv.cpp - Lv.cpp - Tlv.cpp - FlowLabelTlv.cpp - MessageToUserTlv.cpp - FaultHandlerOverrideTlv.cpp -) \ No newline at end of file +target_sources( + ${LIB_FSFW_NAME} + PRIVATE EntityIdTlv.cpp + FilestoreRequestTlv.cpp + FilestoreResponseTlv.cpp + Lv.cpp + Tlv.cpp + FlowLabelTlv.cpp + MessageToUserTlv.cpp + FaultHandlerOverrideTlv.cpp) diff --git a/src/fsfw/container/CMakeLists.txt b/src/fsfw/container/CMakeLists.txt index 13eced1d..52087ff0 100644 --- a/src/fsfw/container/CMakeLists.txt +++ b/src/fsfw/container/CMakeLists.txt @@ -1,5 +1,2 @@ -target_sources(${LIB_FSFW_NAME} - PRIVATE - SharedRingBuffer.cpp - SimpleRingBuffer.cpp -) \ No newline at end of file +target_sources(${LIB_FSFW_NAME} PRIVATE SharedRingBuffer.cpp + SimpleRingBuffer.cpp) diff --git a/src/fsfw/container/FIFOBase.tpp b/src/fsfw/container/FIFOBase.tpp index 2e6a3829..91804b6c 100644 --- a/src/fsfw/container/FIFOBase.tpp +++ b/src/fsfw/container/FIFOBase.tpp @@ -5,89 +5,88 @@ #error Include FIFOBase.h before FIFOBase.tpp! #endif -template -inline FIFOBase::FIFOBase(T* values, const size_t maxCapacity): - maxCapacity(maxCapacity), values(values){}; +template +inline FIFOBase::FIFOBase(T* values, const size_t maxCapacity) + : maxCapacity(maxCapacity), values(values){}; -template +template inline ReturnValue_t FIFOBase::insert(T value) { - if (full()) { - return FULL; - } else { - values[writeIndex] = value; - writeIndex = next(writeIndex); - ++currentSize; - return HasReturnvaluesIF::RETURN_OK; - } + if (full()) { + return FULL; + } else { + values[writeIndex] = value; + writeIndex = next(writeIndex); + ++currentSize; + return HasReturnvaluesIF::RETURN_OK; + } }; -template +template inline ReturnValue_t FIFOBase::retrieve(T* value) { - if (empty()) { - return EMPTY; - } else { - if (value == nullptr){ - return HasReturnvaluesIF::RETURN_FAILED; - } - *value = values[readIndex]; - readIndex = next(readIndex); - --currentSize; - return HasReturnvaluesIF::RETURN_OK; + if (empty()) { + return EMPTY; + } else { + if (value == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; } + *value = values[readIndex]; + readIndex = next(readIndex); + --currentSize; + return HasReturnvaluesIF::RETURN_OK; + } }; -template +template inline ReturnValue_t FIFOBase::peek(T* value) { - if(empty()) { - return EMPTY; - } else { - if (value == nullptr){ - return HasReturnvaluesIF::RETURN_FAILED; - } - *value = values[readIndex]; - return HasReturnvaluesIF::RETURN_OK; + if (empty()) { + return EMPTY; + } else { + if (value == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; } + *value = values[readIndex]; + return HasReturnvaluesIF::RETURN_OK; + } }; -template +template inline ReturnValue_t FIFOBase::pop() { - T value; - return this->retrieve(&value); + T value; + return this->retrieve(&value); }; -template +template inline bool FIFOBase::empty() { - return (currentSize == 0); + return (currentSize == 0); }; -template +template inline bool FIFOBase::full() { - return (currentSize == maxCapacity); + return (currentSize == maxCapacity); } -template +template inline size_t FIFOBase::size() { - return currentSize; + return currentSize; } -template +template inline size_t FIFOBase::next(size_t current) { - ++current; - if (current == maxCapacity) { - current = 0; - } - return current; + ++current; + if (current == maxCapacity) { + current = 0; + } + return current; } -template +template inline size_t FIFOBase::getMaxCapacity() const { - return maxCapacity; + return maxCapacity; } - -template -inline void FIFOBase::setContainer(T *data) { - this->values = data; +template +inline void FIFOBase::setContainer(T* data) { + this->values = data; } #endif diff --git a/src/fsfw/container/FixedArrayList.h b/src/fsfw/container/FixedArrayList.h index 26a73921..fc8be393 100644 --- a/src/fsfw/container/FixedArrayList.h +++ b/src/fsfw/container/FixedArrayList.h @@ -2,6 +2,7 @@ #define FIXEDARRAYLIST_H_ #include +#include #include "ArrayList.h" /** @@ -9,10 +10,9 @@ */ template class FixedArrayList : public ArrayList { -#if !defined(_MSC_VER) && !defined(__clang__) - static_assert(MAX_SIZE <= (std::pow(2, sizeof(count_t) * 8) - 1), + static_assert(MAX_SIZE <= std::numeric_limits::max(), "count_t is not large enough to hold MAX_SIZE"); -#endif + private: T data[MAX_SIZE]; diff --git a/src/fsfw/container/FixedOrderedMultimap.tpp b/src/fsfw/container/FixedOrderedMultimap.tpp index 294a161f..fd58bc44 100644 --- a/src/fsfw/container/FixedOrderedMultimap.tpp +++ b/src/fsfw/container/FixedOrderedMultimap.tpp @@ -1,109 +1,109 @@ #ifndef FRAMEWORK_CONTAINER_FIXEDORDEREDMULTIMAP_TPP_ #define FRAMEWORK_CONTAINER_FIXEDORDEREDMULTIMAP_TPP_ - -template -inline ReturnValue_t FixedOrderedMultimap::insert(key_t key, T value, Iterator *storedValue) { - if (_size == theMap.maxSize()) { - return MAP_FULL; - } - size_t position = findNicePlace(key); - memmove(static_cast(&theMap[position + 1]),static_cast(&theMap[position]), - (_size - position) * sizeof(std::pair)); - theMap[position].first = key; - theMap[position].second = value; - ++_size; - if (storedValue != nullptr) { - *storedValue = Iterator(&theMap[position]); - } - return HasReturnvaluesIF::RETURN_OK; +template +inline ReturnValue_t FixedOrderedMultimap::insert(key_t key, T value, + Iterator *storedValue) { + if (_size == theMap.maxSize()) { + return MAP_FULL; + } + size_t position = findNicePlace(key); + memmove(static_cast(&theMap[position + 1]), static_cast(&theMap[position]), + (_size - position) * sizeof(std::pair)); + theMap[position].first = key; + theMap[position].second = value; + ++_size; + if (storedValue != nullptr) { + *storedValue = Iterator(&theMap[position]); + } + return HasReturnvaluesIF::RETURN_OK; } -template +template inline ReturnValue_t FixedOrderedMultimap::insert(std::pair pair) { - return insert(pair.first, pair.second); + return insert(pair.first, pair.second); } -template +template inline ReturnValue_t FixedOrderedMultimap::exists(key_t key) const { - ReturnValue_t result = KEY_DOES_NOT_EXIST; - if (findFirstIndex(key) < _size) { - result = HasReturnvaluesIF::RETURN_OK; - } - return result; + ReturnValue_t result = KEY_DOES_NOT_EXIST; + if (findFirstIndex(key) < _size) { + result = HasReturnvaluesIF::RETURN_OK; + } + return result; } -template +template inline ReturnValue_t FixedOrderedMultimap::erase(Iterator *iter) { - size_t i; - if ((i = findFirstIndex((*iter).value->first)) >= _size) { - return KEY_DOES_NOT_EXIST; - } - removeFromPosition(i); - if (*iter != begin()) { - (*iter)--; - } else { - *iter = begin(); - } - return HasReturnvaluesIF::RETURN_OK; + size_t i; + if ((i = findFirstIndex((*iter).value->first)) >= _size) { + return KEY_DOES_NOT_EXIST; + } + removeFromPosition(i); + if (*iter != begin()) { + (*iter)--; + } else { + *iter = begin(); + } + return HasReturnvaluesIF::RETURN_OK; } -template +template inline ReturnValue_t FixedOrderedMultimap::erase(key_t key) { - size_t i; - if ((i = findFirstIndex(key)) >= _size) { - return KEY_DOES_NOT_EXIST; - } - do { - removeFromPosition(i); - i = findFirstIndex(key, i); - } while (i < _size); - return HasReturnvaluesIF::RETURN_OK; + size_t i; + if ((i = findFirstIndex(key)) >= _size) { + return KEY_DOES_NOT_EXIST; + } + do { + removeFromPosition(i); + i = findFirstIndex(key, i); + } while (i < _size); + return HasReturnvaluesIF::RETURN_OK; } -template +template inline ReturnValue_t FixedOrderedMultimap::find(key_t key, T **value) const { - ReturnValue_t result = exists(key); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - *value = &theMap[findFirstIndex(key)].second; - return HasReturnvaluesIF::RETURN_OK; + ReturnValue_t result = exists(key); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + *value = &theMap[findFirstIndex(key)].second; + return HasReturnvaluesIF::RETURN_OK; } -template -inline size_t FixedOrderedMultimap::findFirstIndex(key_t key, size_t startAt) const { - if (startAt >= _size) { - return startAt + 1; +template +inline size_t FixedOrderedMultimap::findFirstIndex(key_t key, + size_t startAt) const { + if (startAt >= _size) { + return startAt + 1; + } + size_t i = startAt; + for (i = startAt; i < _size; ++i) { + if (theMap[i].first == key) { + return i; } - size_t i = startAt; - for (i = startAt; i < _size; ++i) { - if (theMap[i].first == key) { - return i; - } - } - return i; + } + return i; } -template +template inline size_t FixedOrderedMultimap::findNicePlace(key_t key) const { - size_t i = 0; - for (i = 0; i < _size; ++i) { - if (myComp(key, theMap[i].first)) { - return i; - } + size_t i = 0; + for (i = 0; i < _size; ++i) { + if (myComp(key, theMap[i].first)) { + return i; } - return i; + } + return i; } -template +template inline void FixedOrderedMultimap::removeFromPosition(size_t position) { - if (_size <= position) { - return; - } - memmove(static_cast(&theMap[position]), static_cast(&theMap[position + 1]), - (_size - position - 1) * sizeof(std::pair)); - --_size; + if (_size <= position) { + return; + } + memmove(static_cast(&theMap[position]), static_cast(&theMap[position + 1]), + (_size - position - 1) * sizeof(std::pair)); + --_size; } - #endif /* FRAMEWORK_CONTAINER_FIXEDORDEREDMULTIMAP_TPP_ */ diff --git a/src/fsfw/controller/CMakeLists.txt b/src/fsfw/controller/CMakeLists.txt index 550acfcd..c8c000d8 100644 --- a/src/fsfw/controller/CMakeLists.txt +++ b/src/fsfw/controller/CMakeLists.txt @@ -1,4 +1,2 @@ -target_sources(${LIB_FSFW_NAME} PRIVATE - ControllerBase.cpp - ExtendedControllerBase.cpp -) \ No newline at end of file +target_sources(${LIB_FSFW_NAME} PRIVATE ControllerBase.cpp + ExtendedControllerBase.cpp) diff --git a/src/fsfw/coordinates/CMakeLists.txt b/src/fsfw/coordinates/CMakeLists.txt index a1fa1e52..15452b1c 100644 --- a/src/fsfw/coordinates/CMakeLists.txt +++ b/src/fsfw/coordinates/CMakeLists.txt @@ -1,5 +1,2 @@ -target_sources(${LIB_FSFW_NAME} - PRIVATE - CoordinateTransformations.cpp - Sgp4Propagator.cpp -) \ No newline at end of file +target_sources(${LIB_FSFW_NAME} PRIVATE CoordinateTransformations.cpp + Sgp4Propagator.cpp) diff --git a/src/fsfw/datalinklayer/CMakeLists.txt b/src/fsfw/datalinklayer/CMakeLists.txt index 148e7c5d..cc18088f 100644 --- a/src/fsfw/datalinklayer/CMakeLists.txt +++ b/src/fsfw/datalinklayer/CMakeLists.txt @@ -1,12 +1,11 @@ -target_sources(${LIB_FSFW_NAME} - PRIVATE - Clcw.cpp - DataLinkLayer.cpp - Farm1StateLockout.cpp - Farm1StateOpen.cpp - Farm1StateWait.cpp - MapPacketExtraction.cpp - TcTransferFrame.cpp - TcTransferFrameLocal.cpp - VirtualChannelReception.cpp -) \ No newline at end of file +target_sources( + ${LIB_FSFW_NAME} + PRIVATE Clcw.cpp + DataLinkLayer.cpp + Farm1StateLockout.cpp + Farm1StateOpen.cpp + Farm1StateWait.cpp + MapPacketExtraction.cpp + TcTransferFrame.cpp + TcTransferFrameLocal.cpp + VirtualChannelReception.cpp) diff --git a/src/fsfw/datapool/CMakeLists.txt b/src/fsfw/datapool/CMakeLists.txt index be4606aa..b2ac592c 100644 --- a/src/fsfw/datapool/CMakeLists.txt +++ b/src/fsfw/datapool/CMakeLists.txt @@ -1,4 +1 @@ -target_sources(${LIB_FSFW_NAME} PRIVATE - PoolDataSetBase.cpp - PoolEntry.cpp -) \ No newline at end of file +target_sources(${LIB_FSFW_NAME} PRIVATE PoolDataSetBase.cpp PoolEntry.cpp) diff --git a/src/fsfw/datapoollocal/CMakeLists.txt b/src/fsfw/datapoollocal/CMakeLists.txt index e2db39eb..749ef688 100644 --- a/src/fsfw/datapoollocal/CMakeLists.txt +++ b/src/fsfw/datapoollocal/CMakeLists.txt @@ -1,10 +1,6 @@ -target_sources(${LIB_FSFW_NAME} - PRIVATE - LocalDataPoolManager.cpp - LocalDataSet.cpp - LocalPoolDataSetBase.cpp - LocalPoolObjectBase.cpp - SharedLocalDataSet.cpp -) +target_sources( + ${LIB_FSFW_NAME} + PRIVATE LocalDataPoolManager.cpp LocalDataSet.cpp LocalPoolDataSetBase.cpp + LocalPoolObjectBase.cpp SharedLocalDataSet.cpp) -add_subdirectory(internal) \ No newline at end of file +add_subdirectory(internal) diff --git a/src/fsfw/datapoollocal/LocalPoolVariable.tpp b/src/fsfw/datapoollocal/LocalPoolVariable.tpp index 9bb30611..f800dfd3 100644 --- a/src/fsfw/datapoollocal/LocalPoolVariable.tpp +++ b/src/fsfw/datapoollocal/LocalPoolVariable.tpp @@ -5,205 +5,189 @@ #error Include LocalPoolVariable.h before LocalPoolVariable.tpp! #endif -template -inline LocalPoolVariable::LocalPoolVariable(HasLocalDataPoolIF* hkOwner, - lp_id_t poolId, DataSetIF* dataSet, pool_rwm_t setReadWriteMode): - LocalPoolObjectBase(poolId, hkOwner, dataSet, setReadWriteMode) {} +template +inline LocalPoolVariable::LocalPoolVariable(HasLocalDataPoolIF* hkOwner, lp_id_t poolId, + DataSetIF* dataSet, pool_rwm_t setReadWriteMode) + : LocalPoolObjectBase(poolId, hkOwner, dataSet, setReadWriteMode) {} -template -inline LocalPoolVariable::LocalPoolVariable(object_id_t poolOwner, - lp_id_t poolId, DataSetIF *dataSet, pool_rwm_t setReadWriteMode): - LocalPoolObjectBase(poolOwner, poolId, dataSet, setReadWriteMode) {} +template +inline LocalPoolVariable::LocalPoolVariable(object_id_t poolOwner, lp_id_t poolId, + DataSetIF* dataSet, pool_rwm_t setReadWriteMode) + : LocalPoolObjectBase(poolOwner, poolId, dataSet, setReadWriteMode) {} +template +inline LocalPoolVariable::LocalPoolVariable(gp_id_t globalPoolId, DataSetIF* dataSet, + pool_rwm_t setReadWriteMode) + : LocalPoolObjectBase(globalPoolId.objectId, globalPoolId.localPoolId, dataSet, + setReadWriteMode) {} -template -inline LocalPoolVariable::LocalPoolVariable(gp_id_t globalPoolId, - DataSetIF *dataSet, pool_rwm_t setReadWriteMode): - LocalPoolObjectBase(globalPoolId.objectId, globalPoolId.localPoolId, - dataSet, setReadWriteMode){} - - -template -inline ReturnValue_t LocalPoolVariable::read( - MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) { - if(hkManager == nullptr) { - return readWithoutLock(); - } - MutexIF* mutex = LocalDpManagerAttorney::getMutexHandle(*hkManager); - ReturnValue_t result = mutex->lockMutex(timeoutType, timeoutMs); - if(result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - result = readWithoutLock(); - mutex->unlockMutex(); +template +inline ReturnValue_t LocalPoolVariable::read(MutexIF::TimeoutType timeoutType, + uint32_t timeoutMs) { + if (hkManager == nullptr) { + return readWithoutLock(); + } + MutexIF* mutex = LocalDpManagerAttorney::getMutexHandle(*hkManager); + ReturnValue_t result = mutex->lockMutex(timeoutType, timeoutMs); + if (result != HasReturnvaluesIF::RETURN_OK) { return result; + } + result = readWithoutLock(); + mutex->unlockMutex(); + return result; } -template +template inline ReturnValue_t LocalPoolVariable::readWithoutLock() { - if(readWriteMode == pool_rwm_t::VAR_WRITE) { - object_id_t targetObjectId = hkManager->getCreatorObjectId(); - reportReadCommitError("LocalPoolVector", - PoolVariableIF::INVALID_READ_WRITE_MODE, true, targetObjectId, - localPoolId); - return PoolVariableIF::INVALID_READ_WRITE_MODE; - } + if (readWriteMode == pool_rwm_t::VAR_WRITE) { + object_id_t targetObjectId = hkManager->getCreatorObjectId(); + reportReadCommitError("LocalPoolVector", PoolVariableIF::INVALID_READ_WRITE_MODE, true, + targetObjectId, localPoolId); + return PoolVariableIF::INVALID_READ_WRITE_MODE; + } - PoolEntry* poolEntry = nullptr; - ReturnValue_t result = LocalDpManagerAttorney::fetchPoolEntry(*hkManager, localPoolId, - &poolEntry); - if(result != RETURN_OK) { - object_id_t ownerObjectId = hkManager->getCreatorObjectId(); - reportReadCommitError("LocalPoolVariable", result, - false, ownerObjectId, localPoolId); - return result; - } - - this->value = *(poolEntry->getDataPtr()); - this->valid = poolEntry->getValid(); - return RETURN_OK; -} - -template -inline ReturnValue_t LocalPoolVariable::commit(bool setValid, - MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) { - this->setValid(setValid); - return commit(timeoutType, timeoutMs); -} - -template -inline ReturnValue_t LocalPoolVariable::commit( - MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) { - if(hkManager == nullptr) { - return commitWithoutLock(); - } - MutexIF* mutex = LocalDpManagerAttorney::getMutexHandle(*hkManager); - ReturnValue_t result = mutex->lockMutex(timeoutType, timeoutMs); - if(result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - result = commitWithoutLock(); - mutex->unlockMutex(); + PoolEntry* poolEntry = nullptr; + ReturnValue_t result = + LocalDpManagerAttorney::fetchPoolEntry(*hkManager, localPoolId, &poolEntry); + if (result != RETURN_OK) { + object_id_t ownerObjectId = hkManager->getCreatorObjectId(); + reportReadCommitError("LocalPoolVariable", result, false, ownerObjectId, localPoolId); return result; + } + + this->value = *(poolEntry->getDataPtr()); + this->valid = poolEntry->getValid(); + return RETURN_OK; } -template +template +inline ReturnValue_t LocalPoolVariable::commit(bool setValid, MutexIF::TimeoutType timeoutType, + uint32_t timeoutMs) { + this->setValid(setValid); + return commit(timeoutType, timeoutMs); +} + +template +inline ReturnValue_t LocalPoolVariable::commit(MutexIF::TimeoutType timeoutType, + uint32_t timeoutMs) { + if (hkManager == nullptr) { + return commitWithoutLock(); + } + MutexIF* mutex = LocalDpManagerAttorney::getMutexHandle(*hkManager); + ReturnValue_t result = mutex->lockMutex(timeoutType, timeoutMs); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = commitWithoutLock(); + mutex->unlockMutex(); + return result; +} + +template inline ReturnValue_t LocalPoolVariable::commitWithoutLock() { - if(readWriteMode == pool_rwm_t::VAR_READ) { - object_id_t targetObjectId = hkManager->getCreatorObjectId(); - reportReadCommitError("LocalPoolVector", - PoolVariableIF::INVALID_READ_WRITE_MODE, false, targetObjectId, - localPoolId); - return PoolVariableIF::INVALID_READ_WRITE_MODE; - } + if (readWriteMode == pool_rwm_t::VAR_READ) { + object_id_t targetObjectId = hkManager->getCreatorObjectId(); + reportReadCommitError("LocalPoolVector", PoolVariableIF::INVALID_READ_WRITE_MODE, false, + targetObjectId, localPoolId); + return PoolVariableIF::INVALID_READ_WRITE_MODE; + } - PoolEntry* poolEntry = nullptr; - ReturnValue_t result = LocalDpManagerAttorney::fetchPoolEntry(*hkManager, localPoolId, - &poolEntry); - if(result != RETURN_OK) { - object_id_t ownerObjectId = hkManager->getCreatorObjectId(); - reportReadCommitError("LocalPoolVariable", result, - false, ownerObjectId, localPoolId); - return result; - } + PoolEntry* poolEntry = nullptr; + ReturnValue_t result = + LocalDpManagerAttorney::fetchPoolEntry(*hkManager, localPoolId, &poolEntry); + if (result != RETURN_OK) { + object_id_t ownerObjectId = hkManager->getCreatorObjectId(); + reportReadCommitError("LocalPoolVariable", result, false, ownerObjectId, localPoolId); + return result; + } - *(poolEntry->getDataPtr()) = this->value; - poolEntry->setValid(this->valid); - return RETURN_OK; + *(poolEntry->getDataPtr()) = this->value; + poolEntry->setValid(this->valid); + return RETURN_OK; } -template -inline ReturnValue_t LocalPoolVariable::serialize(uint8_t** buffer, - size_t* size, const size_t max_size, - SerializeIF::Endianness streamEndianness) const { - return SerializeAdapter::serialize(&value, - buffer, size ,max_size, streamEndianness); +template +inline ReturnValue_t LocalPoolVariable::serialize( + uint8_t** buffer, size_t* size, const size_t max_size, + SerializeIF::Endianness streamEndianness) const { + return SerializeAdapter::serialize(&value, buffer, size, max_size, streamEndianness); } -template +template inline size_t LocalPoolVariable::getSerializedSize() const { - return SerializeAdapter::getSerializedSize(&value); + return SerializeAdapter::getSerializedSize(&value); } -template -inline ReturnValue_t LocalPoolVariable::deSerialize(const uint8_t** buffer, - size_t* size, SerializeIF::Endianness streamEndianness) { - return SerializeAdapter::deSerialize(&value, buffer, size, streamEndianness); +template +inline ReturnValue_t LocalPoolVariable::deSerialize(const uint8_t** buffer, size_t* size, + SerializeIF::Endianness streamEndianness) { + return SerializeAdapter::deSerialize(&value, buffer, size, streamEndianness); } #if FSFW_CPP_OSTREAM_ENABLED == 1 -template -inline std::ostream& operator<< (std::ostream &out, - const LocalPoolVariable &var) { - out << var.value; - return out; +template +inline std::ostream& operator<<(std::ostream& out, const LocalPoolVariable& var) { + out << var.value; + return out; } #endif -template +template inline LocalPoolVariable::operator T() const { - return value; + return value; } -template -inline LocalPoolVariable & LocalPoolVariable::operator=( - const T& newValue) { - value = newValue; - return *this; +template +inline LocalPoolVariable& LocalPoolVariable::operator=(const T& newValue) { + value = newValue; + return *this; } -template -inline LocalPoolVariable& LocalPoolVariable::operator =( - const LocalPoolVariable& newPoolVariable) { - value = newPoolVariable.value; - return *this; +template +inline LocalPoolVariable& LocalPoolVariable::operator=( + const LocalPoolVariable& newPoolVariable) { + value = newPoolVariable.value; + return *this; } -template -inline bool LocalPoolVariable::operator ==( - const LocalPoolVariable &other) const { - return this->value == other.value; +template +inline bool LocalPoolVariable::operator==(const LocalPoolVariable& other) const { + return this->value == other.value; } -template -inline bool LocalPoolVariable::operator ==(const T &other) const { - return this->value == other; +template +inline bool LocalPoolVariable::operator==(const T& other) const { + return this->value == other; } - -template -inline bool LocalPoolVariable::operator !=( - const LocalPoolVariable &other) const { - return not (*this == other); +template +inline bool LocalPoolVariable::operator!=(const LocalPoolVariable& other) const { + return not(*this == other); } -template -inline bool LocalPoolVariable::operator !=(const T &other) const { - return not (*this == other); +template +inline bool LocalPoolVariable::operator!=(const T& other) const { + return not(*this == other); } - -template -inline bool LocalPoolVariable::operator <( - const LocalPoolVariable &other) const { - return this->value < other.value; +template +inline bool LocalPoolVariable::operator<(const LocalPoolVariable& other) const { + return this->value < other.value; } -template -inline bool LocalPoolVariable::operator <(const T &other) const { - return this->value < other; +template +inline bool LocalPoolVariable::operator<(const T& other) const { + return this->value < other; } - -template -inline bool LocalPoolVariable::operator >( - const LocalPoolVariable &other) const { - return not (*this < other); +template +inline bool LocalPoolVariable::operator>(const LocalPoolVariable& other) const { + return not(*this < other); } -template -inline bool LocalPoolVariable::operator >(const T &other) const { - return not (*this < other); +template +inline bool LocalPoolVariable::operator>(const T& other) const { + return not(*this < other); } #endif /* FSFW_DATAPOOLLOCAL_LOCALPOOLVARIABLE_TPP_ */ diff --git a/src/fsfw/datapoollocal/LocalPoolVector.tpp b/src/fsfw/datapoollocal/LocalPoolVector.tpp index 044b8fa7..a2c2b752 100644 --- a/src/fsfw/datapoollocal/LocalPoolVector.tpp +++ b/src/fsfw/datapoollocal/LocalPoolVector.tpp @@ -5,174 +5,172 @@ #error Include LocalPoolVector.h before LocalPoolVector.tpp! #endif -template -inline LocalPoolVector::LocalPoolVector( - HasLocalDataPoolIF* hkOwner, lp_id_t poolId, DataSetIF* dataSet, - pool_rwm_t setReadWriteMode): - LocalPoolObjectBase(poolId, hkOwner, dataSet, setReadWriteMode) {} +template +inline LocalPoolVector::LocalPoolVector(HasLocalDataPoolIF* hkOwner, lp_id_t poolId, + DataSetIF* dataSet, + pool_rwm_t setReadWriteMode) + : LocalPoolObjectBase(poolId, hkOwner, dataSet, setReadWriteMode) {} -template -inline LocalPoolVector::LocalPoolVector(object_id_t poolOwner, - lp_id_t poolId, DataSetIF *dataSet, pool_rwm_t setReadWriteMode): - LocalPoolObjectBase(poolOwner, poolId, dataSet, setReadWriteMode) {} +template +inline LocalPoolVector::LocalPoolVector(object_id_t poolOwner, lp_id_t poolId, + DataSetIF* dataSet, + pool_rwm_t setReadWriteMode) + : LocalPoolObjectBase(poolOwner, poolId, dataSet, setReadWriteMode) {} -template -inline LocalPoolVector::LocalPoolVector(gp_id_t globalPoolId, - DataSetIF *dataSet, pool_rwm_t setReadWriteMode): - LocalPoolObjectBase(globalPoolId.objectId, globalPoolId.localPoolId, - dataSet, setReadWriteMode) {} +template +inline LocalPoolVector::LocalPoolVector(gp_id_t globalPoolId, DataSetIF* dataSet, + pool_rwm_t setReadWriteMode) + : LocalPoolObjectBase(globalPoolId.objectId, globalPoolId.localPoolId, dataSet, + setReadWriteMode) {} -template -inline ReturnValue_t LocalPoolVector::read( - MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) { - MutexGuard(LocalDpManagerAttorney::getMutexHandle(*hkManager), timeoutType, timeoutMs); - return readWithoutLock(); +template +inline ReturnValue_t LocalPoolVector::read(MutexIF::TimeoutType timeoutType, + uint32_t timeoutMs) { + MutexGuard(LocalDpManagerAttorney::getMutexHandle(*hkManager), timeoutType, timeoutMs); + return readWithoutLock(); } -template +template inline ReturnValue_t LocalPoolVector::readWithoutLock() { - if(readWriteMode == pool_rwm_t::VAR_WRITE) { - object_id_t targetObjectId = hkManager->getCreatorObjectId(); - reportReadCommitError("LocalPoolVector", - PoolVariableIF::INVALID_READ_WRITE_MODE, true, targetObjectId, - localPoolId); - return PoolVariableIF::INVALID_READ_WRITE_MODE; - } + if (readWriteMode == pool_rwm_t::VAR_WRITE) { + object_id_t targetObjectId = hkManager->getCreatorObjectId(); + reportReadCommitError("LocalPoolVector", PoolVariableIF::INVALID_READ_WRITE_MODE, true, + targetObjectId, localPoolId); + return PoolVariableIF::INVALID_READ_WRITE_MODE; + } - PoolEntry* poolEntry = nullptr; - ReturnValue_t result = LocalDpManagerAttorney::fetchPoolEntry(*hkManager, localPoolId, - &poolEntry); - memset(this->value, 0, vectorSize * sizeof(T)); + PoolEntry* poolEntry = nullptr; + ReturnValue_t result = + LocalDpManagerAttorney::fetchPoolEntry(*hkManager, localPoolId, &poolEntry); + memset(this->value, 0, vectorSize * sizeof(T)); - if(result != RETURN_OK) { - object_id_t targetObjectId = hkManager->getCreatorObjectId(); - reportReadCommitError("LocalPoolVector", result, true, targetObjectId, - localPoolId); - return result; - } - std::memcpy(this->value, poolEntry->getDataPtr(), poolEntry->getByteSize()); - this->valid = poolEntry->getValid(); - return RETURN_OK; + if (result != RETURN_OK) { + object_id_t targetObjectId = hkManager->getCreatorObjectId(); + reportReadCommitError("LocalPoolVector", result, true, targetObjectId, localPoolId); + return result; + } + std::memcpy(this->value, poolEntry->getDataPtr(), poolEntry->getByteSize()); + this->valid = poolEntry->getValid(); + return RETURN_OK; } -template +template inline ReturnValue_t LocalPoolVector::commit(bool valid, - MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) { - this->setValid(valid); - return commit(timeoutType, timeoutMs); + MutexIF::TimeoutType timeoutType, + uint32_t timeoutMs) { + this->setValid(valid); + return commit(timeoutType, timeoutMs); } -template -inline ReturnValue_t LocalPoolVector::commit( - MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) { - MutexGuard(LocalDpManagerAttorney::getMutexHandle(*hkManager), timeoutType, timeoutMs); - return commitWithoutLock(); +template +inline ReturnValue_t LocalPoolVector::commit(MutexIF::TimeoutType timeoutType, + uint32_t timeoutMs) { + MutexGuard(LocalDpManagerAttorney::getMutexHandle(*hkManager), timeoutType, timeoutMs); + return commitWithoutLock(); } -template +template inline ReturnValue_t LocalPoolVector::commitWithoutLock() { - if(readWriteMode == pool_rwm_t::VAR_READ) { - object_id_t targetObjectId = hkManager->getCreatorObjectId(); - reportReadCommitError("LocalPoolVector", - PoolVariableIF::INVALID_READ_WRITE_MODE, false, targetObjectId, - localPoolId); - return PoolVariableIF::INVALID_READ_WRITE_MODE; - } - PoolEntry* poolEntry = nullptr; - ReturnValue_t result = LocalDpManagerAttorney::fetchPoolEntry(*hkManager, localPoolId, - &poolEntry); - if(result != RETURN_OK) { - object_id_t targetObjectId = hkManager->getCreatorObjectId(); - reportReadCommitError("LocalPoolVector", result, false, targetObjectId, - localPoolId); - return result; - } - std::memcpy(poolEntry->getDataPtr(), this->value, poolEntry->getByteSize()); - poolEntry->setValid(this->valid); - return RETURN_OK; -} - -template -inline T& LocalPoolVector::operator [](size_t i) { - if(i < vectorSize) { - return value[i]; - } - // If this happens, I have to set some value. I consider this - // a configuration error, but I wont exit here. -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "LocalPoolVector: Invalid index. Setting or returning" - " last value!" << std::endl; -#else - sif::printWarning("LocalPoolVector: Invalid index. Setting or returning" - " last value!\n"); -#endif - return value[vectorSize - 1]; -} - -template -inline const T& LocalPoolVector::operator [](size_t i) const { - if(i < vectorSize) { - return value[i]; - } - // If this happens, I have to set some value. I consider this - // a configuration error, but I wont exit here. -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "LocalPoolVector: Invalid index. Setting or returning" - " last value!" << std::endl; -#else - sif::printWarning("LocalPoolVector: Invalid index. Setting or returning" - " last value!\n"); -#endif - return value[vectorSize - 1]; -} - -template -inline ReturnValue_t LocalPoolVector::serialize(uint8_t** buffer, - size_t* size, size_t maxSize, - SerializeIF::Endianness streamEndianness) const { - ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; - for (uint16_t i = 0; i < vectorSize; i++) { - result = SerializeAdapter::serialize(&(value[i]), buffer, size, - maxSize, streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - break; - } - } + if (readWriteMode == pool_rwm_t::VAR_READ) { + object_id_t targetObjectId = hkManager->getCreatorObjectId(); + reportReadCommitError("LocalPoolVector", PoolVariableIF::INVALID_READ_WRITE_MODE, false, + targetObjectId, localPoolId); + return PoolVariableIF::INVALID_READ_WRITE_MODE; + } + PoolEntry* poolEntry = nullptr; + ReturnValue_t result = + LocalDpManagerAttorney::fetchPoolEntry(*hkManager, localPoolId, &poolEntry); + if (result != RETURN_OK) { + object_id_t targetObjectId = hkManager->getCreatorObjectId(); + reportReadCommitError("LocalPoolVector", result, false, targetObjectId, localPoolId); return result; + } + std::memcpy(poolEntry->getDataPtr(), this->value, poolEntry->getByteSize()); + poolEntry->setValid(this->valid); + return RETURN_OK; } -template +template +inline T& LocalPoolVector::operator[](size_t i) { + if (i < vectorSize) { + return value[i]; + } + // If this happens, I have to set some value. I consider this + // a configuration error, but I wont exit here. +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "LocalPoolVector: Invalid index. Setting or returning" + " last value!" + << std::endl; +#else + sif::printWarning( + "LocalPoolVector: Invalid index. Setting or returning" + " last value!\n"); +#endif + return value[vectorSize - 1]; +} + +template +inline const T& LocalPoolVector::operator[](size_t i) const { + if (i < vectorSize) { + return value[i]; + } + // If this happens, I have to set some value. I consider this + // a configuration error, but I wont exit here. +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "LocalPoolVector: Invalid index. Setting or returning" + " last value!" + << std::endl; +#else + sif::printWarning( + "LocalPoolVector: Invalid index. Setting or returning" + " last value!\n"); +#endif + return value[vectorSize - 1]; +} + +template +inline ReturnValue_t LocalPoolVector::serialize( + uint8_t** buffer, size_t* size, size_t maxSize, + SerializeIF::Endianness streamEndianness) const { + ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; + for (uint16_t i = 0; i < vectorSize; i++) { + result = SerializeAdapter::serialize(&(value[i]), buffer, size, maxSize, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + break; + } + } + return result; +} + +template inline size_t LocalPoolVector::getSerializedSize() const { - return vectorSize * SerializeAdapter::getSerializedSize(value); + return vectorSize * SerializeAdapter::getSerializedSize(value); } -template +template inline ReturnValue_t LocalPoolVector::deSerialize( - const uint8_t** buffer, size_t* size, - SerializeIF::Endianness streamEndianness) { - ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; - for (uint16_t i = 0; i < vectorSize; i++) { - result = SerializeAdapter::deSerialize(&(value[i]), buffer, size, - streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - break; - } + const uint8_t** buffer, size_t* size, SerializeIF::Endianness streamEndianness) { + ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; + for (uint16_t i = 0; i < vectorSize; i++) { + result = SerializeAdapter::deSerialize(&(value[i]), buffer, size, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + break; } - return result; + } + return result; } #if FSFW_CPP_OSTREAM_ENABLED == 1 -template -inline std::ostream& operator<< (std::ostream &out, - const LocalPoolVector &var) { - out << "Vector: ["; - for(int i = 0;i < vectorSize; i++) { - out << var.value[i]; - if(i < vectorSize - 1) { - out << ", "; - } +template +inline std::ostream& operator<<(std::ostream& out, const LocalPoolVector& var) { + out << "Vector: ["; + for (int i = 0; i < vectorSize; i++) { + out << var.value[i]; + if (i < vectorSize - 1) { + out << ", "; } - out << "]"; - return out; + } + out << "]"; + return out; } #endif diff --git a/src/fsfw/datapoollocal/internal/CMakeLists.txt b/src/fsfw/datapoollocal/internal/CMakeLists.txt index 554f3b88..6585d06e 100644 --- a/src/fsfw/datapoollocal/internal/CMakeLists.txt +++ b/src/fsfw/datapoollocal/internal/CMakeLists.txt @@ -1,5 +1,2 @@ -target_sources(${LIB_FSFW_NAME} - PRIVATE - HasLocalDpIFUserAttorney.cpp - HasLocalDpIFManagerAttorney.cpp -) +target_sources(${LIB_FSFW_NAME} PRIVATE HasLocalDpIFUserAttorney.cpp + HasLocalDpIFManagerAttorney.cpp) diff --git a/src/fsfw/devicehandlers/CMakeLists.txt b/src/fsfw/devicehandlers/CMakeLists.txt index 50c1008f..180a89da 100644 --- a/src/fsfw/devicehandlers/CMakeLists.txt +++ b/src/fsfw/devicehandlers/CMakeLists.txt @@ -1,11 +1,10 @@ -target_sources(${LIB_FSFW_NAME} - PRIVATE - AssemblyBase.cpp - ChildHandlerBase.cpp - ChildHandlerFDIR.cpp - DeviceHandlerBase.cpp - DeviceHandlerFailureIsolation.cpp - DeviceHandlerMessage.cpp - DeviceTmReportingWrapper.cpp - HealthDevice.cpp -) \ No newline at end of file +target_sources( + ${LIB_FSFW_NAME} + PRIVATE AssemblyBase.cpp + ChildHandlerBase.cpp + ChildHandlerFDIR.cpp + DeviceHandlerBase.cpp + DeviceHandlerFailureIsolation.cpp + DeviceHandlerMessage.cpp + DeviceTmReportingWrapper.cpp + HealthDevice.cpp) diff --git a/src/fsfw/devicehandlers/DeviceHandlerBase.h b/src/fsfw/devicehandlers/DeviceHandlerBase.h index cefc4740..1e1803e8 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerBase.h +++ b/src/fsfw/devicehandlers/DeviceHandlerBase.h @@ -1074,7 +1074,8 @@ class DeviceHandlerBase : public DeviceHandlerIF, /** * 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 override; + 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/events/CMakeLists.txt b/src/fsfw/events/CMakeLists.txt index 28eec772..704cca85 100644 --- a/src/fsfw/events/CMakeLists.txt +++ b/src/fsfw/events/CMakeLists.txt @@ -1,6 +1,3 @@ -target_sources(${LIB_FSFW_NAME} PRIVATE - EventManager.cpp - EventMessage.cpp -) +target_sources(${LIB_FSFW_NAME} PRIVATE EventManager.cpp EventMessage.cpp) add_subdirectory(eventmatching) diff --git a/src/fsfw/events/eventmatching/CMakeLists.txt b/src/fsfw/events/eventmatching/CMakeLists.txt index 81ff9ed8..a9f9c7b3 100644 --- a/src/fsfw/events/eventmatching/CMakeLists.txt +++ b/src/fsfw/events/eventmatching/CMakeLists.txt @@ -1,7 +1,3 @@ -target_sources(${LIB_FSFW_NAME} - PRIVATE - EventIdRangeMatcher.cpp - EventMatchTree.cpp - ReporterRangeMatcher.cpp - SeverityRangeMatcher.cpp -) \ No newline at end of file +target_sources( + ${LIB_FSFW_NAME} PRIVATE EventIdRangeMatcher.cpp EventMatchTree.cpp + ReporterRangeMatcher.cpp SeverityRangeMatcher.cpp) diff --git a/src/fsfw/events/fwSubsystemIdRanges.h b/src/fsfw/events/fwSubsystemIdRanges.h index 21123600..fa4351e9 100644 --- a/src/fsfw/events/fwSubsystemIdRanges.h +++ b/src/fsfw/events/fwSubsystemIdRanges.h @@ -27,6 +27,7 @@ enum : uint8_t { PUS_SERVICE_6 = 86, PUS_SERVICE_8 = 88, PUS_SERVICE_9 = 89, + PUS_SERVICE_11 = 91, PUS_SERVICE_17 = 97, PUS_SERVICE_23 = 103, MGM_LIS3MDL = 106, diff --git a/src/fsfw/fdir/CMakeLists.txt b/src/fsfw/fdir/CMakeLists.txt index f5ffbba8..d41ee2eb 100644 --- a/src/fsfw/fdir/CMakeLists.txt +++ b/src/fsfw/fdir/CMakeLists.txt @@ -1,6 +1,3 @@ -target_sources(${LIB_FSFW_NAME} - PRIVATE - EventCorrelation.cpp - FailureIsolationBase.cpp - FaultCounter.cpp -) \ No newline at end of file +target_sources( + ${LIB_FSFW_NAME} PRIVATE EventCorrelation.cpp FailureIsolationBase.cpp + FaultCounter.cpp) diff --git a/src/fsfw/globalfunctions/CMakeLists.txt b/src/fsfw/globalfunctions/CMakeLists.txt index 5ccd3c4c..cfa02696 100644 --- a/src/fsfw/globalfunctions/CMakeLists.txt +++ b/src/fsfw/globalfunctions/CMakeLists.txt @@ -1,13 +1,12 @@ -target_sources(${LIB_FSFW_NAME} - PRIVATE - arrayprinter.cpp - AsciiConverter.cpp - CRC.cpp - DleEncoder.cpp - PeriodicOperationDivider.cpp - timevalOperations.cpp - Type.cpp - bitutility.cpp -) +target_sources( + ${LIB_FSFW_NAME} + PRIVATE arrayprinter.cpp + AsciiConverter.cpp + CRC.cpp + DleEncoder.cpp + PeriodicOperationDivider.cpp + timevalOperations.cpp + Type.cpp + bitutility.cpp) add_subdirectory(math) diff --git a/src/fsfw/globalfunctions/math/CMakeLists.txt b/src/fsfw/globalfunctions/math/CMakeLists.txt index a9c4ded7..1eeb69b5 100644 --- a/src/fsfw/globalfunctions/math/CMakeLists.txt +++ b/src/fsfw/globalfunctions/math/CMakeLists.txt @@ -1,4 +1 @@ -target_sources(${LIB_FSFW_NAME} - PRIVATE - QuaternionOperations.cpp -) +target_sources(${LIB_FSFW_NAME} PRIVATE QuaternionOperations.cpp) diff --git a/src/fsfw/health/CMakeLists.txt b/src/fsfw/health/CMakeLists.txt index d5f3ccd3..37e4ce48 100644 --- a/src/fsfw/health/CMakeLists.txt +++ b/src/fsfw/health/CMakeLists.txt @@ -1,6 +1,2 @@ -target_sources(${LIB_FSFW_NAME} - PRIVATE - HealthHelper.cpp - HealthMessage.cpp - HealthTable.cpp -) \ No newline at end of file +target_sources(${LIB_FSFW_NAME} PRIVATE HealthHelper.cpp HealthMessage.cpp + HealthTable.cpp) diff --git a/src/fsfw/housekeeping/CMakeLists.txt b/src/fsfw/housekeeping/CMakeLists.txt index fecad2e3..236d3204 100644 --- a/src/fsfw/housekeeping/CMakeLists.txt +++ b/src/fsfw/housekeeping/CMakeLists.txt @@ -1,5 +1,2 @@ -target_sources(${LIB_FSFW_NAME} - PRIVATE - HousekeepingMessage.cpp - PeriodicHousekeepingHelper.cpp -) \ No newline at end of file +target_sources(${LIB_FSFW_NAME} PRIVATE HousekeepingMessage.cpp + PeriodicHousekeepingHelper.cpp) diff --git a/src/fsfw/internalerror/CMakeLists.txt b/src/fsfw/internalerror/CMakeLists.txt index 2b383914..87d3c3f7 100644 --- a/src/fsfw/internalerror/CMakeLists.txt +++ b/src/fsfw/internalerror/CMakeLists.txt @@ -1,4 +1 @@ -target_sources(${LIB_FSFW_NAME} - PRIVATE - InternalErrorReporter.cpp -) \ No newline at end of file +target_sources(${LIB_FSFW_NAME} PRIVATE InternalErrorReporter.cpp) diff --git a/src/fsfw/ipc/CMakeLists.txt b/src/fsfw/ipc/CMakeLists.txt index 3bfe510d..92b91f35 100644 --- a/src/fsfw/ipc/CMakeLists.txt +++ b/src/fsfw/ipc/CMakeLists.txt @@ -1,6 +1,3 @@ -target_sources(${LIB_FSFW_NAME} PRIVATE - CommandMessage.cpp - CommandMessageCleaner.cpp - MessageQueueMessage.cpp - MessageQueueBase.cpp -) \ No newline at end of file +target_sources( + ${LIB_FSFW_NAME} PRIVATE CommandMessage.cpp CommandMessageCleaner.cpp + MessageQueueMessage.cpp MessageQueueBase.cpp) diff --git a/src/fsfw/memory/CMakeLists.txt b/src/fsfw/memory/CMakeLists.txt index c713cd42..9e591bae 100644 --- a/src/fsfw/memory/CMakeLists.txt +++ b/src/fsfw/memory/CMakeLists.txt @@ -1,5 +1,2 @@ -target_sources(${LIB_FSFW_NAME} PRIVATE - MemoryHelper.cpp - MemoryMessage.cpp - GenericFileSystemMessage.cpp -) \ No newline at end of file +target_sources(${LIB_FSFW_NAME} PRIVATE MemoryHelper.cpp MemoryMessage.cpp + GenericFileSystemMessage.cpp) diff --git a/src/fsfw/modes/CMakeLists.txt b/src/fsfw/modes/CMakeLists.txt index 8e5c719b..4eef58e0 100644 --- a/src/fsfw/modes/CMakeLists.txt +++ b/src/fsfw/modes/CMakeLists.txt @@ -1,5 +1 @@ -target_sources(${LIB_FSFW_NAME} - PRIVATE - ModeHelper.cpp - ModeMessage.cpp -) \ No newline at end of file +target_sources(${LIB_FSFW_NAME} PRIVATE ModeHelper.cpp ModeMessage.cpp) diff --git a/src/fsfw/monitoring/CMakeLists.txt b/src/fsfw/monitoring/CMakeLists.txt index d26e807c..48f945b5 100644 --- a/src/fsfw/monitoring/CMakeLists.txt +++ b/src/fsfw/monitoring/CMakeLists.txt @@ -1,5 +1,2 @@ -target_sources(${LIB_FSFW_NAME} - PRIVATE - LimitViolationReporter.cpp - MonitoringMessage.cpp -) \ No newline at end of file +target_sources(${LIB_FSFW_NAME} PRIVATE LimitViolationReporter.cpp + MonitoringMessage.cpp) diff --git a/src/fsfw/objectmanager/CMakeLists.txt b/src/fsfw/objectmanager/CMakeLists.txt index 72aaec89..c71f43aa 100644 --- a/src/fsfw/objectmanager/CMakeLists.txt +++ b/src/fsfw/objectmanager/CMakeLists.txt @@ -1,5 +1 @@ -target_sources(${LIB_FSFW_NAME} - PRIVATE - ObjectManager.cpp - SystemObject.cpp -) \ No newline at end of file +target_sources(${LIB_FSFW_NAME} PRIVATE ObjectManager.cpp SystemObject.cpp) diff --git a/src/fsfw/objectmanager/SystemObject.h b/src/fsfw/objectmanager/SystemObject.h index eeb68b8f..c541ac5e 100644 --- a/src/fsfw/objectmanager/SystemObject.h +++ b/src/fsfw/objectmanager/SystemObject.h @@ -50,7 +50,8 @@ class SystemObject : public SystemObjectIF { virtual ReturnValue_t initialize() override; virtual ReturnValue_t checkObjectConnections() override; - virtual void forwardEvent(Event event, uint32_t parameter1 = 0, uint32_t parameter2 = 0) const override; + 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/objectmanager/frameworkObjects.h b/src/fsfw/objectmanager/frameworkObjects.h index cc233c0f..cddc6ba2 100644 --- a/src/fsfw/objectmanager/frameworkObjects.h +++ b/src/fsfw/objectmanager/frameworkObjects.h @@ -14,6 +14,7 @@ enum framework_objects : object_id_t { PUS_SERVICE_5_EVENT_REPORTING = 0x53000005, PUS_SERVICE_8_FUNCTION_MGMT = 0x53000008, PUS_SERVICE_9_TIME_MGMT = 0x53000009, + PUS_SERVICE_11_TC_SCHEDULER = 0x53000011, PUS_SERVICE_17_TEST = 0x53000017, PUS_SERVICE_20_PARAMETERS = 0x53000020, PUS_SERVICE_200_MODE_MGMT = 0x53000200, diff --git a/src/fsfw/osal/CMakeLists.txt b/src/fsfw/osal/CMakeLists.txt index f3c5cfad..50fd6102 100644 --- a/src/fsfw/osal/CMakeLists.txt +++ b/src/fsfw/osal/CMakeLists.txt @@ -1,35 +1,33 @@ # Check the OS_FSFW variable if(FSFW_OSAL MATCHES "freertos") - add_subdirectory(freertos) + add_subdirectory(freertos) elseif(FSFW_OSAL MATCHES "rtems") - add_subdirectory(rtems) + add_subdirectory(rtems) elseif(FSFW_OSAL MATCHES "linux") - add_subdirectory(linux) + add_subdirectory(linux) elseif(FSFW_OSAL MATCHES "host") - add_subdirectory(host) - if (WIN32) - add_subdirectory(windows) - elseif(UNIX) - # We still need to pull in some Linux specific sources - target_sources(${LIB_FSFW_NAME} PUBLIC - linux/tcpipHelpers.cpp - ) - endif () + add_subdirectory(host) + if(WIN32) + add_subdirectory(windows) + elseif(UNIX) + # We still need to pull in some Linux specific sources + target_sources(${LIB_FSFW_NAME} PUBLIC linux/tcpipHelpers.cpp) + endif() else() - message(WARNING "The OS_FSFW variable was not set. Assuming host OS..") - # Not set. Assumuing this is a host build, try to determine host OS - if (WIN32) - add_subdirectory(host) - add_subdirectory(windows) - elseif (UNIX) - add_subdirectory(linux) - else () - # MacOS or other OSes have not been tested yet / are not supported. - message(FATAL_ERROR "The host OS could not be determined! Aborting.") - endif() + message(WARNING "The OS_FSFW variable was not set. Assuming host OS..") + # Not set. Assumuing this is a host build, try to determine host OS + if(WIN32) + add_subdirectory(host) + add_subdirectory(windows) + elseif(UNIX) + add_subdirectory(linux) + else() + # MacOS or other OSes have not been tested yet / are not supported. + message(FATAL_ERROR "The host OS could not be determined! Aborting.") + endif() endif() -add_subdirectory(common) \ No newline at end of file +add_subdirectory(common) diff --git a/src/fsfw/osal/common/CMakeLists.txt b/src/fsfw/osal/common/CMakeLists.txt index b7c8c033..c0814172 100644 --- a/src/fsfw/osal/common/CMakeLists.txt +++ b/src/fsfw/osal/common/CMakeLists.txt @@ -1,17 +1,10 @@ if(DEFINED WIN32 OR DEFINED UNIX) - target_sources(${LIB_FSFW_NAME} PRIVATE - tcpipCommon.cpp - TcpIpBase.cpp - UdpTcPollingTask.cpp - UdpTmTcBridge.cpp - TcpTmTcServer.cpp - TcpTmTcBridge.cpp - ) + target_sources( + ${LIB_FSFW_NAME} + PRIVATE tcpipCommon.cpp TcpIpBase.cpp UdpTcPollingTask.cpp + UdpTmTcBridge.cpp TcpTmTcServer.cpp TcpTmTcBridge.cpp) endif() if(WIN32) - target_link_libraries(${LIB_FSFW_NAME} PRIVATE - wsock32 - ws2_32 - ) -endif() \ No newline at end of file + target_link_libraries(${LIB_FSFW_NAME} PRIVATE wsock32 ws2_32) +endif() diff --git a/src/fsfw/osal/common/TcpTmTcServer.cpp b/src/fsfw/osal/common/TcpTmTcServer.cpp index 2e6910c5..a8890006 100644 --- a/src/fsfw/osal/common/TcpTmTcServer.cpp +++ b/src/fsfw/osal/common/TcpTmTcServer.cpp @@ -19,6 +19,8 @@ #include #elif defined(PLATFORM_UNIX) #include + +#include #endif const std::string TcpTmTcServer::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT; @@ -29,7 +31,7 @@ TcpTmTcServer::TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge, : SystemObject(objectId), tmtcBridgeId(tmtcTcpBridge), receptionMode(receptionMode), - tcpConfig(customTcpServerPort), + tcpConfig(std::move(customTcpServerPort)), receptionBuffer(receptionBufferSize), ringBuffer(ringBufferSize, true) {} @@ -103,12 +105,12 @@ ReturnValue_t TcpTmTcServer::initialize() { TcpTmTcServer::~TcpTmTcServer() { closeSocket(listenerTcpSocket); } -ReturnValue_t TcpTmTcServer::performOperation(uint8_t opCode) { +[[noreturn]] ReturnValue_t TcpTmTcServer::performOperation(uint8_t opCode) { using namespace tcpip; // If a connection is accepted, the corresponding socket will be assigned to the new socket socket_t connSocket = 0; - // sockaddr clientSockAddr = {}; - // socklen_t connectorSockAddrLen = 0; + sockaddr clientSockAddr = {}; + socklen_t connectorSockAddrLen = 0; int retval = 0; // Listen for connection requests permanently for lifetime of program @@ -119,8 +121,7 @@ ReturnValue_t TcpTmTcServer::performOperation(uint8_t opCode) { continue; } - // connSocket = accept(listenerTcpSocket, &clientSockAddr, &connectorSockAddrLen); - connSocket = accept(listenerTcpSocket, nullptr, nullptr); + connSocket = accept(listenerTcpSocket, &clientSockAddr, &connectorSockAddrLen); if (connSocket == INVALID_SOCKET) { handleError(Protocol::TCP, ErrorSources::ACCEPT_CALL, 500); @@ -135,10 +136,10 @@ ReturnValue_t TcpTmTcServer::performOperation(uint8_t opCode) { if (retval != 0) { handleError(Protocol::TCP, ErrorSources::SHUTDOWN_CALL); } + closeSocket(connSocket); connSocket = 0; } - return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t TcpTmTcServer::initializeAfterTaskCreation() { @@ -159,8 +160,8 @@ void TcpTmTcServer::handleServerOperation(socket_t& connSocket) { #endif while (true) { - int retval = recv(connSocket, reinterpret_cast(receptionBuffer.data()), - receptionBuffer.capacity(), tcpConfig.tcpFlags); + ssize_t retval = recv(connSocket, reinterpret_cast(receptionBuffer.data()), + receptionBuffer.capacity(), tcpConfig.tcpFlags); if (retval == 0) { size_t availableReadData = ringBuffer.getAvailableReadData(); if (availableReadData > lastRingBufferSize) { @@ -252,17 +253,17 @@ ReturnValue_t TcpTmTcServer::handleTcReception(uint8_t* spacePacket, size_t pack return result; } -std::string TcpTmTcServer::getTcpPort() const { return tcpConfig.tcpPort; } +const std::string& TcpTmTcServer::getTcpPort() const { return tcpConfig.tcpPort; } -void TcpTmTcServer::setSpacePacketParsingOptions(std::vector validPacketIds) { - this->validPacketIds = validPacketIds; +void TcpTmTcServer::setSpacePacketParsingOptions(std::vector validPacketIds_) { + this->validPacketIds = std::move(validPacketIds_); } TcpTmTcServer::TcpConfig& TcpTmTcServer::getTcpConfigStruct() { return tcpConfig; } ReturnValue_t TcpTmTcServer::handleTmSending(socket_t connSocket, bool& tmSent) { // Access to the FIFO is mutex protected because it is filled by the bridge - MutexGuard(tmtcBridge->mutex, tmtcBridge->timeoutType, tmtcBridge->mutexTimeoutMs); + MutexGuard mg(tmtcBridge->mutex, tmtcBridge->timeoutType, tmtcBridge->mutexTimeoutMs); store_address_t storeId; while ((not tmtcBridge->tmFifo->empty()) and (tmtcBridge->packetSentCounter < tmtcBridge->sentPacketsPerCycle)) { @@ -283,8 +284,8 @@ ReturnValue_t TcpTmTcServer::handleTmSending(socket_t connSocket, bool& tmSent) #endif arrayprinter::print(storeAccessor.data(), storeAccessor.size()); } - int retval = send(connSocket, reinterpret_cast(storeAccessor.data()), - storeAccessor.size(), tcpConfig.tcpTmFlags); + ssize_t retval = send(connSocket, reinterpret_cast(storeAccessor.data()), + storeAccessor.size(), tcpConfig.tcpTmFlags); if (retval == static_cast(storeAccessor.size())) { // Packet sent, clear FIFO entry tmtcBridge->tmFifo->pop(); @@ -339,6 +340,9 @@ ReturnValue_t TcpTmTcServer::handleTcRingBufferData(size_t availableReadData) { size_t foundSize = 0; size_t readLen = 0; while (readLen < readAmount) { + if (spacePacketParser == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } result = spacePacketParser->parseSpacePackets(bufPtrPtr, readAmount, startIdx, foundSize, readLen); switch (result) { diff --git a/src/fsfw/osal/common/TcpTmTcServer.h b/src/fsfw/osal/common/TcpTmTcServer.h index d062a0ce..faf6e0a1 100644 --- a/src/fsfw/osal/common/TcpTmTcServer.h +++ b/src/fsfw/osal/common/TcpTmTcServer.h @@ -17,6 +17,7 @@ #endif #include +#include #include class TcpTmTcBridge; @@ -44,7 +45,7 @@ class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableOb struct TcpConfig { public: - TcpConfig(std::string tcpPort) : tcpPort(tcpPort) {} + explicit TcpConfig(std::string tcpPort) : tcpPort(std::move(tcpPort)) {} /** * Passed to the recv call @@ -84,7 +85,7 @@ class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableOb size_t ringBufferSize = RING_BUFFER_SIZE, std::string customTcpServerPort = DEFAULT_SERVER_PORT, ReceptionModes receptionMode = ReceptionModes::SPACE_PACKETS); - virtual ~TcpTmTcServer(); + ~TcpTmTcServer() override; void enableWiretapping(bool enable); @@ -97,10 +98,10 @@ class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableOb void setSpacePacketParsingOptions(std::vector validPacketIds); ReturnValue_t initialize() override; - ReturnValue_t performOperation(uint8_t opCode) override; + [[noreturn]] ReturnValue_t performOperation(uint8_t opCode) override; ReturnValue_t initializeAfterTaskCreation() override; - std::string getTcpPort() const; + [[nodiscard]] const std::string& getTcpPort() const; protected: StorageManagerIF* tcStore = nullptr; @@ -115,7 +116,7 @@ class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableOb ReceptionModes receptionMode; TcpConfig tcpConfig; - struct sockaddr tcpAddress; + struct sockaddr tcpAddress = {}; socket_t listenerTcpSocket = 0; MessageQueueId_t targetTcDestination = MessageQueueIF::NO_QUEUE; diff --git a/src/fsfw/osal/common/UdpTcPollingTask.cpp b/src/fsfw/osal/common/UdpTcPollingTask.cpp index 38fb1921..bcc8e9e3 100644 --- a/src/fsfw/osal/common/UdpTcPollingTask.cpp +++ b/src/fsfw/osal/common/UdpTcPollingTask.cpp @@ -154,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/UdpTmTcBridge.cpp b/src/fsfw/osal/common/UdpTmTcBridge.cpp index 6089f266..e3cad58f 100644 --- a/src/fsfw/osal/common/UdpTmTcBridge.cpp +++ b/src/fsfw/osal/common/UdpTmTcBridge.cpp @@ -20,7 +20,7 @@ const std::string UdpTmTcBridge::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT; UdpTmTcBridge::UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination, - const 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_.empty()) { @@ -118,7 +118,7 @@ ReturnValue_t UdpTmTcBridge::sendTm(const uint8_t *data, size_t dataLen) { #endif ssize_t bytesSent = sendto(serverSocket, reinterpret_cast(data), dataLen, flags, - &clientAddress, clientAddressLen); + &clientAddress, clientAddressLen); if (bytesSent == SOCKET_ERROR) { #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "TmTcUdpBridge::sendTm: Send operation failed." << std::endl; diff --git a/src/fsfw/osal/common/UdpTmTcBridge.h b/src/fsfw/osal/common/UdpTmTcBridge.h index b0a67430..92829c46 100644 --- a/src/fsfw/osal/common/UdpTmTcBridge.h +++ b/src/fsfw/osal/common/UdpTmTcBridge.h @@ -29,8 +29,8 @@ 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, const std::string& udpServerPort = "", - object_id_t tmStoreId = objects::TM_STORE, + 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); ~UdpTmTcBridge() override; diff --git a/src/fsfw/osal/freertos/CMakeLists.txt b/src/fsfw/osal/freertos/CMakeLists.txt index 40bdcd0f..cb6ac55a 100644 --- a/src/fsfw/osal/freertos/CMakeLists.txt +++ b/src/fsfw/osal/freertos/CMakeLists.txt @@ -1,32 +1,30 @@ -target_sources(${LIB_FSFW_NAME} - PRIVATE - Clock.cpp - FixedTimeslotTask.cpp - BinarySemaphore.cpp - BinSemaphUsingTask.cpp - CountingSemaphore.cpp - CountingSemaphUsingTask.cpp - MessageQueue.cpp - Mutex.cpp - MutexFactory.cpp - PeriodicTask.cpp - QueueFactory.cpp - SemaphoreFactory.cpp - TaskFactory.cpp - Timekeeper.cpp - TaskManagement.cpp - QueueMapManager.cpp -) +target_sources( + ${LIB_FSFW_NAME} + PRIVATE Clock.cpp + FixedTimeslotTask.cpp + BinarySemaphore.cpp + BinSemaphUsingTask.cpp + CountingSemaphore.cpp + CountingSemaphUsingTask.cpp + MessageQueue.cpp + Mutex.cpp + MutexFactory.cpp + PeriodicTask.cpp + QueueFactory.cpp + SemaphoreFactory.cpp + TaskFactory.cpp + Timekeeper.cpp + TaskManagement.cpp + QueueMapManager.cpp) -# FreeRTOS is required to link the FSFW now. It is recommended to compile -# FreeRTOS as a static library and set LIB_OS_NAME to the target name of the +# FreeRTOS is required to link the FSFW now. It is recommended to compile +# FreeRTOS as a static library and set LIB_OS_NAME to the target name of the # library. if(NOT LIB_OS_NAME) - message(STATUS - "LIB_OS_NAME is empty. Make sure to include the FreeRTOS header path properly." - ) + message( + STATUS + "LIB_OS_NAME is empty. Make sure to include the FreeRTOS header path properly." + ) else() - target_link_libraries(${LIB_FSFW_NAME} PRIVATE - ${LIB_OS_NAME} - ) + target_link_libraries(${LIB_FSFW_NAME} PRIVATE ${LIB_OS_NAME}) endif() diff --git a/src/fsfw/osal/host/CMakeLists.txt b/src/fsfw/osal/host/CMakeLists.txt index 8b11a531..95ab25c9 100644 --- a/src/fsfw/osal/host/CMakeLists.txt +++ b/src/fsfw/osal/host/CMakeLists.txt @@ -1,27 +1,23 @@ -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 - ${CMAKE_THREAD_LIBS_INIT} - ) + target_link_libraries(${LIB_FSFW_NAME} PRIVATE ${CMAKE_THREAD_LIBS_INIT}) if(NOT APPLE) - target_link_libraries(${LIB_FSFW_NAME} PRIVATE - rt - ) + target_link_libraries(${LIB_FSFW_NAME} PRIVATE rt) endif() -endif() \ No newline at end of file +endif() diff --git a/src/fsfw/osal/linux/CMakeLists.txt b/src/fsfw/osal/linux/CMakeLists.txt index 2e88d6d0..72a62b86 100644 --- a/src/fsfw/osal/linux/CMakeLists.txt +++ b/src/fsfw/osal/linux/CMakeLists.txt @@ -1,29 +1,25 @@ -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 - ) +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) find_package(Threads REQUIRED) -target_link_libraries(${LIB_FSFW_NAME} PUBLIC - ${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} PUBLIC rt) endif() diff --git a/src/fsfw/osal/rtems/CMakeLists.txt b/src/fsfw/osal/rtems/CMakeLists.txt index 734566a3..1b47e1b9 100644 --- a/src/fsfw/osal/rtems/CMakeLists.txt +++ b/src/fsfw/osal/rtems/CMakeLists.txt @@ -1,20 +1,17 @@ -target_sources(${LIB_FSFW_NAME} - PRIVATE - Clock.cpp - CpuUsage.cpp - InitTask.cpp - InternalErrorCodes.cpp - MessageQueue.cpp - PeriodicTask.cpp - Mutex.cpp - MutexFactory.cpp - FixedTimeslotTask.cpp - QueueFactory.cpp - RtemsBasic.cpp - RTEMSTaskBase.cpp - TaskFactory.cpp - BinarySemaphore.cpp - SemaphoreFactory.cpp -) - - +target_sources( + ${LIB_FSFW_NAME} + PRIVATE Clock.cpp + CpuUsage.cpp + InitTask.cpp + InternalErrorCodes.cpp + MessageQueue.cpp + PeriodicTask.cpp + Mutex.cpp + MutexFactory.cpp + FixedTimeslotTask.cpp + QueueFactory.cpp + RtemsBasic.cpp + RTEMSTaskBase.cpp + TaskFactory.cpp + BinarySemaphore.cpp + SemaphoreFactory.cpp) diff --git a/src/fsfw/osal/windows/CMakeLists.txt b/src/fsfw/osal/windows/CMakeLists.txt index 36a54765..e961b25b 100644 --- a/src/fsfw/osal/windows/CMakeLists.txt +++ b/src/fsfw/osal/windows/CMakeLists.txt @@ -1,4 +1 @@ -target_sources(${LIB_FSFW_NAME} PRIVATE - tcpipHelpers.cpp - winTaskHelpers.cpp -) +target_sources(${LIB_FSFW_NAME} PRIVATE tcpipHelpers.cpp winTaskHelpers.cpp) diff --git a/src/fsfw/parameters/CMakeLists.txt b/src/fsfw/parameters/CMakeLists.txt index fb5e4590..98a8085c 100644 --- a/src/fsfw/parameters/CMakeLists.txt +++ b/src/fsfw/parameters/CMakeLists.txt @@ -1,6 +1,3 @@ -target_sources(${LIB_FSFW_NAME} - PRIVATE - ParameterHelper.cpp - ParameterMessage.cpp - ParameterWrapper.cpp -) \ No newline at end of file +target_sources( + ${LIB_FSFW_NAME} PRIVATE ParameterHelper.cpp ParameterMessage.cpp + ParameterWrapper.cpp) diff --git a/src/fsfw/power/CMakeLists.txt b/src/fsfw/power/CMakeLists.txt index 1c625db1..b4ab0006 100644 --- a/src/fsfw/power/CMakeLists.txt +++ b/src/fsfw/power/CMakeLists.txt @@ -1,7 +1,4 @@ -target_sources(${LIB_FSFW_NAME} - PRIVATE - Fuse.cpp - PowerComponent.cpp - PowerSensor.cpp - PowerSwitcher.cpp -) \ No newline at end of file +target_sources( + ${LIB_FSFW_NAME} + PRIVATE Fuse.cpp PowerComponent.cpp PowerSensor.cpp PowerSwitcher.cpp + DummyPowerSwitcher.cpp PowerSwitcherComponent.cpp) diff --git a/src/fsfw/power/DummyPowerSwitcher.cpp b/src/fsfw/power/DummyPowerSwitcher.cpp new file mode 100644 index 00000000..48ab22c6 --- /dev/null +++ b/src/fsfw/power/DummyPowerSwitcher.cpp @@ -0,0 +1,47 @@ +#include "DummyPowerSwitcher.h" + +DummyPowerSwitcher::DummyPowerSwitcher(object_id_t objectId, size_t numberOfSwitches, + size_t numberOfFuses, bool registerGlobally, + uint32_t switchDelayMs) + : SystemObject(objectId, registerGlobally), + switcherList(numberOfSwitches), + fuseList(numberOfFuses), + switchDelayMs(switchDelayMs) {} + +void DummyPowerSwitcher::setInitialSwitcherList(std::vector switcherList) { + this->switcherList = switcherList; +} + +void DummyPowerSwitcher::setInitialFusesList(std::vector fuseList) { + this->fuseList = fuseList; +} + +ReturnValue_t DummyPowerSwitcher::sendSwitchCommand(power::Switch_t switchNr, ReturnValue_t onOff) { + if (switchNr < switcherList.size()) { + switcherList[switchNr] = onOff; + } + return RETURN_FAILED; +} + +ReturnValue_t DummyPowerSwitcher::sendFuseOnCommand(uint8_t fuseNr) { + if (fuseNr < fuseList.size()) { + fuseList[fuseNr] = FUSE_ON; + } + return RETURN_FAILED; +} + +ReturnValue_t DummyPowerSwitcher::getSwitchState(power::Switch_t switchNr) const { + if (switchNr < switcherList.size()) { + return switcherList[switchNr]; + } + return HasReturnvaluesIF::RETURN_FAILED; +} + +ReturnValue_t DummyPowerSwitcher::getFuseState(uint8_t fuseNr) const { + if (fuseNr < fuseList.size()) { + return fuseList[fuseNr]; + } + return HasReturnvaluesIF::RETURN_FAILED; +} + +uint32_t DummyPowerSwitcher::getSwitchDelayMs(void) const { return switchDelayMs; } diff --git a/src/fsfw/power/DummyPowerSwitcher.h b/src/fsfw/power/DummyPowerSwitcher.h new file mode 100644 index 00000000..6ccd8dd7 --- /dev/null +++ b/src/fsfw/power/DummyPowerSwitcher.h @@ -0,0 +1,38 @@ +#ifndef FSFW_SRC_FSFW_POWER_DUMMYPOWERSWITCHER_H_ +#define FSFW_SRC_FSFW_POWER_DUMMYPOWERSWITCHER_H_ + +#include +#include + +#include "PowerSwitchIF.h" +#include "definitions.h" +#include "fsfw/objectmanager/SystemObject.h" + +/** + * @brief This component can be used to simulate a power switcher like a + * Power Control Distribution Unit (PCDU) + * @details + * The dummy switcher will simply cache the commanded fuse and switch states and return them + * in the according switch getter functions. In that sense, it simulates an ideal PCDU. + */ +class DummyPowerSwitcher : public SystemObject, public PowerSwitchIF { + public: + DummyPowerSwitcher(object_id_t objectId, size_t numberOfSwitches, size_t numberOfFuses, + bool registerGlobally = true, uint32_t switchDelayMs = 5000); + + void setInitialSwitcherList(std::vector switcherList); + void setInitialFusesList(std::vector switcherList); + + virtual ReturnValue_t sendSwitchCommand(power::Switch_t switchNr, ReturnValue_t onOff) override; + virtual ReturnValue_t sendFuseOnCommand(uint8_t fuseNr) override; + virtual ReturnValue_t getSwitchState(power::Switch_t switchNr) const override; + virtual ReturnValue_t getFuseState(uint8_t fuseNr) const override; + virtual uint32_t getSwitchDelayMs(void) const override; + + private: + std::vector switcherList; + std::vector fuseList; + uint32_t switchDelayMs = 5000; +}; + +#endif /* FSFW_SRC_FSFW_POWER_DUMMYPOWERSWITCHER_H_ */ diff --git a/src/fsfw/power/Fuse.h b/src/fsfw/power/Fuse.h index 787fa38d..43896f75 100644 --- a/src/fsfw/power/Fuse.h +++ b/src/fsfw/power/Fuse.h @@ -34,14 +34,14 @@ class Fuse : public SystemObject, }; static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PCDU_1; - static const Event FUSE_CURRENT_HIGH = MAKE_EVENT( - 1, severity::LOW); //!< PSS detected that current on a fuse is totally out of bounds. - static const Event FUSE_WENT_OFF = - MAKE_EVENT(2, severity::LOW); //!< PSS detected a fuse that went off. - static const Event POWER_ABOVE_HIGH_LIMIT = - MAKE_EVENT(4, severity::LOW); //!< PSS detected a fuse that violates its limits. - static const Event POWER_BELOW_LOW_LIMIT = - MAKE_EVENT(5, severity::LOW); //!< PSS detected a fuse that violates its limits. + //! PSS detected that current on a fuse is totally out of bounds. + static const Event FUSE_CURRENT_HIGH = MAKE_EVENT(1, severity::LOW); + //! PSS detected a fuse that went off. + static const Event FUSE_WENT_OFF = MAKE_EVENT(2, severity::LOW); + //! PSS detected a fuse that violates its limits. + static const Event POWER_ABOVE_HIGH_LIMIT = MAKE_EVENT(4, severity::LOW); + //! PSS detected a fuse that violates its limits. + static const Event POWER_BELOW_LOW_LIMIT = MAKE_EVENT(5, severity::LOW); typedef std::list DeviceList; Fuse(object_id_t fuseObjectId, uint8_t fuseId, sid_t variableSet, VariableIds ids, diff --git a/src/fsfw/power/PowerSwitchIF.h b/src/fsfw/power/PowerSwitchIF.h index a31d8971..bc883fbc 100644 --- a/src/fsfw/power/PowerSwitchIF.h +++ b/src/fsfw/power/PowerSwitchIF.h @@ -3,6 +3,7 @@ #include "../events/Event.h" #include "../returnvalues/HasReturnvaluesIF.h" +#include "definitions.h" /** * * @brief This interface defines a connection to a device that is capable of @@ -37,11 +38,11 @@ class PowerSwitchIF : public HasReturnvaluesIF { * @param switchNr * @param onOff on == @c SWITCH_ON; off != @c SWITCH_ON */ - virtual void sendSwitchCommand(uint8_t switchNr, ReturnValue_t onOff) const = 0; + virtual ReturnValue_t sendSwitchCommand(power::Switch_t switchNr, ReturnValue_t onOff) = 0; /** * Sends a command to the Power Unit to enable a certain fuse. */ - virtual void sendFuseOnCommand(uint8_t fuseNr) const = 0; + virtual ReturnValue_t sendFuseOnCommand(uint8_t fuseNr) = 0; /** * get the state of the Switches. @@ -51,7 +52,7 @@ class PowerSwitchIF : public HasReturnvaluesIF { * - @c SWITCH_OFF if the specified switch is off. * - @c RETURN_FAILED if an error occured */ - virtual ReturnValue_t getSwitchState(uint8_t switchNr) const = 0; + virtual ReturnValue_t getSwitchState(power::Switch_t switchNr) const = 0; /** * get state of a fuse. * @param fuseNr diff --git a/src/fsfw/power/PowerSwitcher.cpp b/src/fsfw/power/PowerSwitcher.cpp index 0a3f8521..7608c6e7 100644 --- a/src/fsfw/power/PowerSwitcher.cpp +++ b/src/fsfw/power/PowerSwitcher.cpp @@ -1,19 +1,12 @@ #include "fsfw/power/PowerSwitcher.h" +#include "definitions.h" #include "fsfw/objectmanager/ObjectManager.h" #include "fsfw/serviceinterface/ServiceInterface.h" -PowerSwitcher::PowerSwitcher(uint8_t setSwitch1, uint8_t setSwitch2, - PowerSwitcher::State_t setStartState) - : state(setStartState), firstSwitch(setSwitch1), secondSwitch(setSwitch2) {} - -ReturnValue_t PowerSwitcher::initialize(object_id_t powerSwitchId) { - power = ObjectManager::instance()->get(powerSwitchId); - if (power == nullptr) { - return HasReturnvaluesIF::RETURN_FAILED; - } - return HasReturnvaluesIF::RETURN_OK; -} +PowerSwitcher::PowerSwitcher(PowerSwitchIF* switcher, power::Switch_t setSwitch1, + power::Switch_t setSwitch2, PowerSwitcher::State_t setStartState) + : power(switcher), state(setStartState), firstSwitch(setSwitch1), secondSwitch(setSwitch2) {} ReturnValue_t PowerSwitcher::getStateOfSwitches() { SwitchReturn_t result = howManySwitches(); @@ -52,18 +45,37 @@ void PowerSwitcher::commandSwitches(ReturnValue_t onOff) { return; } -void PowerSwitcher::turnOn() { +void PowerSwitcher::turnOn(bool checkCurrentState) { + if (checkCurrentState) { + if (getStateOfSwitches() == PowerSwitchIF::SWITCH_ON) { + state = SWITCH_IS_ON; + return; + } + } commandSwitches(PowerSwitchIF::SWITCH_ON); state = WAIT_ON; } -void PowerSwitcher::turnOff() { +void PowerSwitcher::turnOff(bool checkCurrentState) { + if (checkCurrentState) { + if (getStateOfSwitches() == PowerSwitchIF::SWITCH_OFF) { + state = SWITCH_IS_OFF; + return; + } + } commandSwitches(PowerSwitchIF::SWITCH_OFF); state = WAIT_OFF; } +bool PowerSwitcher::active() { + if (state == WAIT_OFF or state == WAIT_ON) { + return true; + } + return false; +} + PowerSwitcher::SwitchReturn_t PowerSwitcher::howManySwitches() { - if (secondSwitch == NO_SWITCH) { + if (secondSwitch == power::NO_SWITCH) { return ONE_SWITCH; } else { return TWO_SWITCHES; diff --git a/src/fsfw/power/PowerSwitcher.h b/src/fsfw/power/PowerSwitcher.h index c72c241d..279ffacf 100644 --- a/src/fsfw/power/PowerSwitcher.h +++ b/src/fsfw/power/PowerSwitcher.h @@ -14,28 +14,29 @@ class PowerSwitcher : public HasReturnvaluesIF { SWITCH_IS_OFF, SWITCH_IS_ON, }; - State_t state; + static const uint8_t INTERFACE_ID = CLASS_ID::POWER_SWITCHER; static const ReturnValue_t IN_POWER_TRANSITION = MAKE_RETURN_CODE(1); static const ReturnValue_t SWITCH_STATE_MISMATCH = MAKE_RETURN_CODE(2); - PowerSwitcher(uint8_t setSwitch1, uint8_t setSwitch2 = NO_SWITCH, + PowerSwitcher(PowerSwitchIF* switcher, power::Switch_t setSwitch1, + power::Switch_t setSwitch2 = power::NO_SWITCH, State_t setStartState = SWITCH_IS_OFF); - ReturnValue_t initialize(object_id_t powerSwitchId); - void turnOn(); - void turnOff(); + void turnOn(bool checkCurrentState = true); + void turnOff(bool checkCurrentState = true); + bool active(); void doStateMachine(); State_t getState(); ReturnValue_t checkSwitchState(); uint32_t getSwitchDelay(); - uint8_t getFirstSwitch() const; - uint8_t getSecondSwitch() const; + power::Switch_t getFirstSwitch() const; + power::Switch_t getSecondSwitch() const; private: - uint8_t firstSwitch; - uint8_t secondSwitch; PowerSwitchIF* power = nullptr; + State_t state; + power::Switch_t firstSwitch = power::NO_SWITCH; + power::Switch_t secondSwitch = power::NO_SWITCH; - static const uint8_t NO_SWITCH = 0xFF; enum SwitchReturn_t { ONE_SWITCH = 1, TWO_SWITCHES = 2 }; ReturnValue_t getStateOfSwitches(); void commandSwitches(ReturnValue_t onOff); diff --git a/src/fsfw/power/PowerSwitcherComponent.cpp b/src/fsfw/power/PowerSwitcherComponent.cpp new file mode 100644 index 00000000..9c1ed4cf --- /dev/null +++ b/src/fsfw/power/PowerSwitcherComponent.cpp @@ -0,0 +1,107 @@ +#include "PowerSwitcherComponent.h" + +#include +#include + +PowerSwitcherComponent::PowerSwitcherComponent(object_id_t objectId, PowerSwitchIF *pwrSwitcher, + power::Switch_t pwrSwitch) + : SystemObject(objectId), + switcher(pwrSwitcher, pwrSwitch), + modeHelper(this), + healthHelper(this, objectId) { + queue = QueueFactory::instance()->createMessageQueue(); +} + +ReturnValue_t PowerSwitcherComponent::performOperation(uint8_t opCode) { + ReturnValue_t result; + CommandMessage command; + + for (result = queue->receiveMessage(&command); result == RETURN_OK; + result = queue->receiveMessage(&command)) { + result = healthHelper.handleHealthCommand(&command); + if (result == RETURN_OK) { + continue; + } + + result = modeHelper.handleModeCommand(&command); + if (result == RETURN_OK) { + continue; + } + } + if (switcher.active()) { + switcher.doStateMachine(); + auto currState = switcher.getState(); + if (currState == PowerSwitcher::SWITCH_IS_OFF) { + setMode(MODE_OFF, 0); + } else if (currState == PowerSwitcher::SWITCH_IS_ON) { + setMode(MODE_ON, 0); + } + } + return RETURN_OK; +} + +ReturnValue_t PowerSwitcherComponent::initialize() { + ReturnValue_t result = modeHelper.initialize(); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = healthHelper.initialize(); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + return SystemObject::initialize(); +} + +MessageQueueId_t PowerSwitcherComponent::getCommandQueue() const { return queue->getId(); } + +void PowerSwitcherComponent::getMode(Mode_t *mode, Submode_t *submode) { + *mode = this->mode; + *submode = this->submode; +} + +ReturnValue_t PowerSwitcherComponent::setHealth(HealthState health) { + healthHelper.setHealth(health); + return RETURN_OK; +} + +ReturnValue_t PowerSwitcherComponent::checkModeCommand(Mode_t mode, Submode_t submode, + uint32_t *msToReachTheMode) { + *msToReachTheMode = 5000; + if (mode != MODE_ON and mode != MODE_OFF) { + return TRANS_NOT_ALLOWED; + } + return RETURN_OK; +} + +void PowerSwitcherComponent::startTransition(Mode_t mode, Submode_t submode) { + if (mode == MODE_OFF) { + switcher.turnOff(true); + switcher.doStateMachine(); + if (switcher.getState() == PowerSwitcher::SWITCH_IS_OFF) { + setMode(MODE_OFF, 0); + } + } else if (mode == MODE_ON) { + switcher.turnOn(true); + switcher.doStateMachine(); + if (switcher.getState() == PowerSwitcher::SWITCH_IS_ON) { + setMode(MODE_ON, 0); + } + } +} + +void PowerSwitcherComponent::setToExternalControl() { + healthHelper.setHealth(HasHealthIF::EXTERNAL_CONTROL); +} + +void PowerSwitcherComponent::announceMode(bool recursive) { + triggerEvent(MODE_INFO, mode, submode); +} + +void PowerSwitcherComponent::setMode(Mode_t newMode, Submode_t newSubmode) { + this->mode = newMode; + this->submode = newSubmode; + modeHelper.modeChanged(mode, submode); + announceMode(false); +} + +HasHealthIF::HealthState PowerSwitcherComponent::getHealth() { return healthHelper.getHealth(); } diff --git a/src/fsfw/power/PowerSwitcherComponent.h b/src/fsfw/power/PowerSwitcherComponent.h new file mode 100644 index 00000000..a3ed640e --- /dev/null +++ b/src/fsfw/power/PowerSwitcherComponent.h @@ -0,0 +1,62 @@ +#ifndef _FSFW_POWER_POWERSWITCHERCOMPONENT_H_ +#define _FSFW_POWER_POWERSWITCHERCOMPONENT_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +class PowerSwitchIF; + +/** + * @brief Allows to create an power switch object with its own mode and health + * @details + * This basic component allows to create an object which is solely responsible for managing a + * switch. It also has a mode and a health by implementing the respective interface components + * which allows integrating this component into a system mode tree. + * + * Commanding this component to MODE_OFF will cause the switcher to turn the switch off while + * commanding in to MODE_ON will cause the switcher to turn the switch on. + */ +class PowerSwitcherComponent : public SystemObject, + public HasReturnvaluesIF, + public ExecutableObjectIF, + public HasModesIF, + public HasHealthIF { + public: + PowerSwitcherComponent(object_id_t objectId, PowerSwitchIF *pwrSwitcher, + power::Switch_t pwrSwitch); + + private: + MessageQueueIF *queue = nullptr; + PowerSwitcher switcher; + + Mode_t mode = MODE_OFF; + Submode_t submode = 0; + + ModeHelper modeHelper; + HealthHelper healthHelper; + + void setMode(Mode_t newMode, Submode_t newSubmode); + + virtual ReturnValue_t performOperation(uint8_t opCode) override; + + ReturnValue_t initialize() override; + + MessageQueueId_t getCommandQueue() const override; + void getMode(Mode_t *mode, Submode_t *submode) override; + ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, + uint32_t *msToReachTheMode) override; + void startTransition(Mode_t mode, Submode_t submode) override; + void setToExternalControl() override; + void announceMode(bool recursive) override; + + ReturnValue_t setHealth(HealthState health) override; + HasHealthIF::HealthState getHealth() override; +}; + +#endif /* _FSFW_POWER_POWERSWITCHERCOMPONENT_H_ */ diff --git a/src/fsfw/power/definitions.h b/src/fsfw/power/definitions.h new file mode 100644 index 00000000..ed2a0037 --- /dev/null +++ b/src/fsfw/power/definitions.h @@ -0,0 +1,13 @@ +#ifndef FSFW_SRC_FSFW_POWER_DEFINITIONS_H_ +#define FSFW_SRC_FSFW_POWER_DEFINITIONS_H_ + +#include + +namespace power { + +using Switch_t = uint8_t; +static constexpr Switch_t NO_SWITCH = 0xFF; + +} // namespace power + +#endif /* FSFW_SRC_FSFW_POWER_DEFINITIONS_H_ */ diff --git a/src/fsfw/pus/CMakeLists.txt b/src/fsfw/pus/CMakeLists.txt index 8b55adf0..35b35bea 100644 --- a/src/fsfw/pus/CMakeLists.txt +++ b/src/fsfw/pus/CMakeLists.txt @@ -1,12 +1,12 @@ -target_sources(${LIB_FSFW_NAME} PRIVATE - Service1TelecommandVerification.cpp - Service2DeviceAccess.cpp - Service3Housekeeping.cpp - Service5EventReporting.cpp - Service8FunctionManagement.cpp - Service9TimeManagement.cpp - Service17Test.cpp - Service20ParameterManagement.cpp - CService200ModeCommanding.cpp - CService201HealthCommanding.cpp -) \ No newline at end of file +target_sources( + ${LIB_FSFW_NAME} + PRIVATE Service1TelecommandVerification.cpp + Service2DeviceAccess.cpp + Service3Housekeeping.cpp + Service5EventReporting.cpp + Service8FunctionManagement.cpp + Service9TimeManagement.cpp + Service17Test.cpp + Service20ParameterManagement.cpp + CService200ModeCommanding.cpp + CService201HealthCommanding.cpp) diff --git a/src/fsfw/pus/CService201HealthCommanding.cpp b/src/fsfw/pus/CService201HealthCommanding.cpp index 4d9806f9..644e0d7c 100644 --- a/src/fsfw/pus/CService201HealthCommanding.cpp +++ b/src/fsfw/pus/CService201HealthCommanding.cpp @@ -13,8 +13,6 @@ CService201HealthCommanding::CService201HealthCommanding(object_id_t objectId, u : CommandingServiceBase(objectId, apid, serviceId, numParallelCommands, commandTimeoutSeconds) { } -CService201HealthCommanding::~CService201HealthCommanding() {} - ReturnValue_t CService201HealthCommanding::isValidSubservice(uint8_t subservice) { switch (subservice) { case (Subservice::COMMAND_SET_HEALTH): @@ -43,8 +41,8 @@ ReturnValue_t CService201HealthCommanding::getMessageQueueAndObject(uint8_t subs } ReturnValue_t CService201HealthCommanding::checkInterfaceAndAcquireMessageQueue( - MessageQueueId_t *messageQueueToSet, object_id_t *objectId) { - HasHealthIF *destination = ObjectManager::instance()->get(*objectId); + MessageQueueId_t *messageQueueToSet, const object_id_t *objectId) { + auto *destination = ObjectManager::instance()->get(*objectId); if (destination == nullptr) { return CommandingServiceBase::INVALID_OBJECT; } @@ -77,6 +75,10 @@ ReturnValue_t CService201HealthCommanding::prepareCommand(CommandMessage *messag HealthMessage::setHealthMessage(message, HealthMessage::HEALTH_ANNOUNCE_ALL); break; } + default: { + // Should never happen, subservice was already checked + result = RETURN_FAILED; + } } return result; } @@ -95,10 +97,10 @@ ReturnValue_t CService201HealthCommanding::handleReply(const CommandMessage *rep } // Not used for now, health state already reported by event -ReturnValue_t CService201HealthCommanding::prepareHealthSetReply(const CommandMessage *reply) { - prepareHealthSetReply(reply); - uint8_t health = static_cast(HealthMessage::getHealth(reply)); - uint8_t oldHealth = static_cast(HealthMessage::getOldHealth(reply)); +[[maybe_unused]] ReturnValue_t CService201HealthCommanding::prepareHealthSetReply( + const CommandMessage *reply) { + auto health = static_cast(HealthMessage::getHealth(reply)); + auto oldHealth = static_cast(HealthMessage::getOldHealth(reply)); HealthSetReply healthSetReply(health, oldHealth); return sendTmPacket(Subservice::REPLY_HEALTH_SET, &healthSetReply); } diff --git a/src/fsfw/pus/CService201HealthCommanding.h b/src/fsfw/pus/CService201HealthCommanding.h index 5e52ab39..71b7caa0 100644 --- a/src/fsfw/pus/CService201HealthCommanding.h +++ b/src/fsfw/pus/CService201HealthCommanding.h @@ -1,7 +1,7 @@ #ifndef FSFW_PUS_CSERVICE201HEALTHCOMMANDING_H_ #define FSFW_PUS_CSERVICE201HEALTHCOMMANDING_H_ -#include "../tmtcservices/CommandingServiceBase.h" +#include "fsfw/tmtcservices/CommandingServiceBase.h" /** * @brief Custom PUS service to set health of all objects @@ -21,7 +21,7 @@ class CService201HealthCommanding : public CommandingServiceBase { public: CService201HealthCommanding(object_id_t objectId, uint16_t apid, uint8_t serviceId, uint8_t numParallelCommands = 4, uint16_t commandTimeoutSeconds = 60); - virtual ~CService201HealthCommanding(); + ~CService201HealthCommanding() override = default; protected: /* CSB abstract function implementations */ @@ -38,12 +38,10 @@ class CService201HealthCommanding : public CommandingServiceBase { bool *isStep) override; private: - ReturnValue_t checkAndAcquireTargetID(object_id_t *objectIdToSet, const uint8_t *tcData, - size_t tcDataLen); - ReturnValue_t checkInterfaceAndAcquireMessageQueue(MessageQueueId_t *MessageQueueToSet, - object_id_t *objectId); + static ReturnValue_t checkInterfaceAndAcquireMessageQueue(MessageQueueId_t *MessageQueueToSet, + const object_id_t *objectId); - ReturnValue_t prepareHealthSetReply(const CommandMessage *reply); + [[maybe_unused]] ReturnValue_t prepareHealthSetReply(const CommandMessage *reply); enum Subservice { //! [EXPORT] : [TC] Set health of target object diff --git a/src/fsfw/pus/Service11TelecommandScheduling.h b/src/fsfw/pus/Service11TelecommandScheduling.h new file mode 100644 index 00000000..0fed8bca --- /dev/null +++ b/src/fsfw/pus/Service11TelecommandScheduling.h @@ -0,0 +1,203 @@ +#ifndef MISSION_PUS_SERVICE11TELECOMMANDSCHEDULING_H_ +#define MISSION_PUS_SERVICE11TELECOMMANDSCHEDULING_H_ + +#include +#include +#include + +#include "fsfw/FSFW.h" +#include "fsfw/returnvalues/FwClassIds.h" + +/** + * @brief: PUS-Service 11 - Telecommand scheduling. + * @details: + * PUS-Service 11 - Telecommand scheduling. + * Full documentation: ECSS-E-ST-70-41C, p. 168: + * ST[11] time-based scheduling + * + * This service provides the capability to command pre-loaded + * application processes (telecommands) by releasing them at their + * due-time. + * References to telecommands are stored together with their due-timepoints + * and are released at their corresponding due-time. + * + * Necessary subservice functionalities are implemented. + * Those are: + * TC[11,4] activity insertion + * TC[11,5] activity deletion + * TC[11,6] filter-based activity deletion + * TC[11,7] activity time-shift + * TC[11,8] filter-based activity time-shift + * + * Groups are not supported. + * This service remains always enabled. Sending a disable-request has no effect. + */ +template +class Service11TelecommandScheduling final : public PusServiceBase { + public: + static constexpr uint8_t CLASS_ID = CLASS_ID::PUS_SERVICE_11; + + static constexpr ReturnValue_t INVALID_TYPE_TIME_WINDOW = + HasReturnvaluesIF::makeReturnCode(CLASS_ID, 1); + static constexpr ReturnValue_t TIMESHIFTING_NOT_POSSIBLE = + HasReturnvaluesIF::makeReturnCode(CLASS_ID, 2); + static constexpr ReturnValue_t INVALID_RELATIVE_TIME = + HasReturnvaluesIF::makeReturnCode(CLASS_ID, 3); + + static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PUS_SERVICE_11; + + //! [EXPORT] : [COMMENT] Deletion of a TC from the map failed. + //! P1: First 32 bit of request ID, P2. Last 32 bit of Request ID + static constexpr Event TC_DELETION_FAILED = event::makeEvent(SUBSYSTEM_ID, 0, severity::MEDIUM); + + // The types of PUS-11 subservices + enum Subservice : uint8_t { + ENABLE_SCHEDULING = 1, + DISABLE_SCHEDULING = 2, + RESET_SCHEDULING = 3, + INSERT_ACTIVITY = 4, + DELETE_ACTIVITY = 5, + FILTER_DELETE_ACTIVITY = 6, + TIMESHIFT_ACTIVITY = 7, + FILTER_TIMESHIFT_ACTIVITY = 8, + DETAIL_REPORT = 9, + TIMEBASE_SCHEDULE_DETAIL_REPORT = 10, + TIMESHIFT_ALL_SCHEDULE_ACTIVITIES = 15 + }; + + // The types of time windows for TC[11,6] and TC[11,8], as defined in ECSS-E-ST-70-41C, + // requirement 8.11.3c (p. 507) + enum TypeOfTimeWindow : uint32_t { + SELECT_ALL = 0, + FROM_TIMETAG_TO_TIMETAG = 1, + FROM_TIMETAG = 2, + TO_TIMETAG = 3 + }; + + Service11TelecommandScheduling(object_id_t objectId, uint16_t apid, uint8_t serviceId, + AcceptsTelecommandsIF* tcRecipient, + uint16_t releaseTimeMarginSeconds = DEFAULT_RELEASE_TIME_MARGIN, + bool debugMode = false); + + ~Service11TelecommandScheduling() override; + + void enableExpiredTcDeletion(); + void disableExpiredTcDeletion(); + + /** PusServiceBase overrides */ + ReturnValue_t handleRequest(uint8_t subservice) override; + ReturnValue_t performService() override; + ReturnValue_t initialize() override; + + private: + struct TelecommandStruct { + uint64_t requestId{}; + uint32_t seconds{}; + store_address_t storeAddr; // uint16 + }; + + static constexpr uint16_t DEFAULT_RELEASE_TIME_MARGIN = 5; + + // minimum release time offset to insert into schedule + const uint16_t RELEASE_TIME_MARGIN_SECONDS = 5; + + /** + * By default, the scheduling will be disabled. This is a standard requirement + */ + bool schedulingEnabled = false; + bool deleteExpiredTcWhenDisabled = true; + bool debugMode = false; + StorageManagerIF* tcStore = nullptr; + AcceptsTelecommandsIF* tcRecipient = nullptr; + MessageQueueId_t recipientMsgQueueId = 0; + + /** + * The telecommand map uses the exectution time as a Unix time stamp as + * the key. This is mapped to a generic telecommand struct. + */ + using TelecommandMap = etl::multimap; + using TcMapIter = typename TelecommandMap::iterator; + + TelecommandMap telecommandMap; + + ReturnValue_t handleResetCommand(); + /** + * @brief Logic to be performed on an incoming TC[11,4]. + * @return RETURN_OK if successful + */ + ReturnValue_t doInsertActivity(const uint8_t* data, size_t size); + + /** + * @brief Logic to be performed on an incoming TC[11,5]. + * @return RETURN_OK if successful + */ + ReturnValue_t doDeleteActivity(const uint8_t* data, size_t size); + + /** + * @brief Logic to be performed on an incoming TC[11,6]. + * @return RETURN_OK if successful + */ + ReturnValue_t doFilterDeleteActivity(const uint8_t* data, size_t size); + + /** + * @brief Logic to be performed on an incoming TC[11,7]. + * @return RETURN_OK if successful + */ + ReturnValue_t doTimeshiftActivity(const uint8_t* data, size_t size); + + /** + * @brief Logic to be performed on an incoming TC[11,8]. + * @return RETURN_OK if successful + */ + ReturnValue_t doFilterTimeshiftActivity(const uint8_t* data, size_t size); + + /** + * @brief Extracts the Request ID from the Application Data of a TC by utilizing a ctor of the + * class TcPacketPus. + * NOTE: This only works if the payload data is a TC (e.g. not for TC[11,5] which does not + * send a TC as payload)! + * @param data The Application data of the TC (get via getApplicationData()). + * @return requestId + */ + uint64_t getRequestIdFromDataTC(const uint8_t* data) const; + + /** + * @brief Extracts the Request ID from the Application Data directly, assuming it is packed + * as follows (acc. to ECSS): | source ID (uint32) | apid (uint32) | ssc (uint32) |. + * @param data Pointer to first byte described data + * @param dataSize Remaining size of data NOTE: non-const, this is modified by the function + * @param [out] requestId Request ID + * @return RETURN_OK if successful + */ + ReturnValue_t getRequestIdFromData(const uint8_t*& data, size_t& dataSize, uint64_t& requestId); + + /** + * @brief Builds the Request ID from its three elements. + * @param sourceId Source ID + * @param apid Application Process ID (APID) + * @param ssc Source Sequence Count + * @return Request ID + */ + [[nodiscard]] uint64_t buildRequestId(uint32_t sourceId, uint16_t apid, uint16_t ssc) const; + + /** + * @brief Gets the filter range for filter TCs from a data packet + * @param data TC data + * @param dataSize TC data size + * @param [out] itBegin Begin of filter range + * @param [out] itEnd End of filter range + * @return RETURN_OK if successful + */ + ReturnValue_t getMapFilterFromData(const uint8_t*& data, size_t& size, TcMapIter& itBegin, + TcMapIter& itEnd); + + ReturnValue_t handleInvalidData(const char* ctx); + /** + * @brief Prints content of multimap. Use for simple debugging only. + */ + void debugPrintMultimapContent() const; +}; + +#include "Service11TelecommandScheduling.tpp" + +#endif /* MISSION_PUS_SERVICE11TELECOMMANDSCHEDULING_H_ */ diff --git a/src/fsfw/pus/Service11TelecommandScheduling.tpp b/src/fsfw/pus/Service11TelecommandScheduling.tpp new file mode 100644 index 00000000..cb43e8e8 --- /dev/null +++ b/src/fsfw/pus/Service11TelecommandScheduling.tpp @@ -0,0 +1,645 @@ +#pragma once + +#include + +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/serialize/SerializeAdapter.h" +#include "fsfw/serviceinterface.h" +#include "fsfw/tmtcservices/AcceptsTelecommandsIF.h" + +static constexpr auto DEF_END = SerializeIF::Endianness::BIG; + +template +inline Service11TelecommandScheduling::Service11TelecommandScheduling( + object_id_t objectId, uint16_t apid, uint8_t serviceId, AcceptsTelecommandsIF *tcRecipient, + uint16_t releaseTimeMarginSeconds, bool debugMode) + : PusServiceBase(objectId, apid, serviceId), + RELEASE_TIME_MARGIN_SECONDS(releaseTimeMarginSeconds), + debugMode(debugMode), + tcRecipient(tcRecipient) {} + +template +inline Service11TelecommandScheduling::~Service11TelecommandScheduling() = default; + +template +inline ReturnValue_t Service11TelecommandScheduling::handleRequest( + uint8_t subservice) { + if (debugMode) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "PUS11::handleRequest: Handling request " << static_cast(subservice); +#else + sif::printInfo("PUS11::handleRequest: Handling request %d\n", subservice); +#endif + } + // Get de-serialized Timestamp + const uint8_t *data = currentPacket.getApplicationData(); + size_t size = currentPacket.getApplicationDataSize(); + if (data == nullptr) { + return handleInvalidData("handleRequest"); + } + switch (subservice) { + case Subservice::ENABLE_SCHEDULING: { + schedulingEnabled = true; + break; + } + case Subservice::DISABLE_SCHEDULING: { + schedulingEnabled = false; + break; + } + case Subservice::RESET_SCHEDULING: { + return handleResetCommand(); + } + case Subservice::INSERT_ACTIVITY: + return doInsertActivity(data, size); + case Subservice::DELETE_ACTIVITY: + return doDeleteActivity(data, size); + case Subservice::FILTER_DELETE_ACTIVITY: + return doFilterDeleteActivity(data, size); + case Subservice::TIMESHIFT_ACTIVITY: + return doTimeshiftActivity(data, size); + case Subservice::FILTER_TIMESHIFT_ACTIVITY: + return doFilterTimeshiftActivity(data, size); + default: + return AcceptsTelecommandsIF::INVALID_SUBSERVICE; + } + return RETURN_OK; +} + +template +inline ReturnValue_t Service11TelecommandScheduling::performService() { + if (not schedulingEnabled) { + return RETURN_OK; + } + // get current time as UNIX timestamp + timeval tNow = {}; + Clock::getClock_timeval(&tNow); + + // TODO: Optionally limit the max number of released TCs per cycle? + // NOTE: The iterator is increased in the loop here. Increasing the iterator as for-loop arg + // does not work in this case as we are deleting the current element here. + for (auto it = telecommandMap.begin(); it != telecommandMap.end();) { + if (it->first <= tNow.tv_sec) { + if (schedulingEnabled) { + // release tc + TmTcMessage releaseMsg(it->second.storeAddr); + auto sendRet = this->requestQueue->sendMessage(recipientMsgQueueId, &releaseMsg, false); + + if (sendRet != HasReturnvaluesIF::RETURN_OK) { + return sendRet; + } + if (debugMode) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "Released TC & erased it from TC map" << std::endl; +#else + sif::printInfo("Released TC & erased it from TC map\n"); +#endif + } + telecommandMap.erase(it++); + } else if (deleteExpiredTcWhenDisabled) { + telecommandMap.erase(it++); + } + continue; + } + it++; + } + + return HasReturnvaluesIF::RETURN_OK; +} + +template +inline ReturnValue_t Service11TelecommandScheduling::initialize() { + ReturnValue_t res = PusServiceBase::initialize(); + if (res != HasReturnvaluesIF::RETURN_OK) { + return res; + } + + tcStore = ObjectManager::instance()->get(objects::TC_STORE); + if (!tcStore) { + return ObjectManagerIF::CHILD_INIT_FAILED; + } + + if (tcRecipient == nullptr) { + return ObjectManagerIF::CHILD_INIT_FAILED; + } + recipientMsgQueueId = tcRecipient->getRequestQueue(); + + return res; +} + +template +inline ReturnValue_t Service11TelecommandScheduling::handleResetCommand() { + for (auto it = telecommandMap.begin(); it != telecommandMap.end(); it++) { + ReturnValue_t result = tcStore->deleteData(it->second.storeAddr); + if (result != RETURN_OK) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + // This should not happen + sif::warning << "Service11TelecommandScheduling::handleRequestDeleting: Deletion failed" + << std::endl; +#else + sif::printWarning("Service11TelecommandScheduling::handleRequestDeleting: Deletion failed\n"); +#endif + triggerEvent(TC_DELETION_FAILED, (it->second.requestId >> 32) & 0xffffffff, + it->second.requestId & 0xffffffff); + } + } + telecommandMap.clear(); + return RETURN_OK; +} + +template +inline ReturnValue_t Service11TelecommandScheduling::doInsertActivity( + const uint8_t *data, size_t size) { + uint32_t timestamp = 0; + ReturnValue_t result = SerializeAdapter::deSerialize(×tamp, &data, &size, DEF_END); + if (result != RETURN_OK) { + return result; + } + + // Insert possible if sched. time is above margin + // (See requirement for Time margin) + timeval tNow = {}; + Clock::getClock_timeval(&tNow); + if (timestamp - tNow.tv_sec <= RELEASE_TIME_MARGIN_SECONDS) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "Service11TelecommandScheduling::doInsertActivity: Release time too close to " + "current time" + << std::endl; +#else + sif::printWarning( + "Service11TelecommandScheduling::doInsertActivity: Release time too close to current " + "time\n"); +#endif + return RETURN_FAILED; + } + + // store currentPacket and receive the store address + store_address_t addr{}; + if (tcStore->addData(&addr, data, size) != RETURN_OK || + addr.raw == storeId::INVALID_STORE_ADDRESS) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "Service11TelecommandScheduling::doInsertActivity: Adding data to TC Store failed" + << std::endl; +#else + sif::printError( + "Service11TelecommandScheduling::doInsertActivity: Adding data to TC Store failed\n"); +#endif + return RETURN_FAILED; + } + + // insert into multimap with new store address + TelecommandStruct tc; + tc.seconds = timestamp; + tc.storeAddr = addr; + tc.requestId = + getRequestIdFromDataTC(data); // TODO: Missing sanity check of the returned request id + + auto it = telecommandMap.insert(std::pair(timestamp, tc)); + if (it == telecommandMap.end()) { + return RETURN_FAILED; + } + + if (debugMode) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "PUS11::doInsertActivity: Inserted into Multimap:" << std::endl; +#else + sif::printInfo("PUS11::doInsertActivity: Inserted into Multimap:\n"); +#endif + debugPrintMultimapContent(); + } + return HasReturnvaluesIF::RETURN_OK; +} + +template +inline ReturnValue_t Service11TelecommandScheduling::doDeleteActivity( + const uint8_t *data, size_t size) { + // Get request ID + uint64_t requestId; + ReturnValue_t result = getRequestIdFromData(data, size, requestId); + if (result != RETURN_OK) { + return result; + } + + // DEBUG + if (debugMode) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "PUS11::doDeleteActivity: requestId: " << requestId << std::endl; +#else + sif::printInfo("PUS11::doDeleteActivity: requestId: %d\n", requestId); +#endif + } + + TcMapIter tcToDelete; // handle to the TC to be deleted, can be used if counter is valid + int tcToDeleteCount = 0; // counter of all found TCs. Should be 1. + + for (auto it = telecommandMap.begin(); it != telecommandMap.end(); it++) { + if (it->second.requestId == requestId) { + tcToDelete = it; + tcToDeleteCount++; + } + } + + // check if 1 explicit TC is found via request ID + if (tcToDeleteCount == 0 || tcToDeleteCount > 1) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "Service11TelecommandScheduling::doDeleteActivity: No or more than 1 TC found. " + "Cannot explicitly delete TC" + << std::endl; +#else + sif::printWarning( + "Service11TelecommandScheduling::doDeleteActivity: No or more than 1 TC found. " + "Cannot explicitly delete TC"); +#endif + return RETURN_FAILED; + } + + // delete packet from store + if (tcStore->deleteData(tcToDelete->second.storeAddr) != RETURN_OK) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "Service11TelecommandScheduling::doDeleteActivity: Could not delete TC from Store" + << std::endl; +#else + sif::printError( + "Service11TelecommandScheduling::doDeleteActivity: Could not delete TC from Store\n"); +#endif + return RETURN_FAILED; + } + + telecommandMap.erase(tcToDelete); + if (debugMode) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "PUS11::doDeleteActivity: Deleted TC from map" << std::endl; +#else + sif::printInfo("PUS11::doDeleteActivity: Deleted TC from map\n"); +#endif + } + + return RETURN_OK; +} + +template +inline ReturnValue_t Service11TelecommandScheduling::doFilterDeleteActivity( + const uint8_t *data, size_t size) { + TcMapIter itBegin; + TcMapIter itEnd; + + ReturnValue_t result = getMapFilterFromData(data, size, itBegin, itEnd); + // get the filter window as map range via dedicated method + if (result != RETURN_OK) { + return result; + } + + int deletedTCs = 0; + for (TcMapIter it = itBegin; it != itEnd; it++) { + // delete packet from store + if (tcStore->deleteData(it->second.storeAddr) != RETURN_OK) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "Service11TelecommandScheduling::doFilterDeleteActivity: Could not delete TC " + "from Store" + << std::endl; +#else + sif::printError( + "Service11TelecommandScheduling::doFilterDeleteActivity: Could not delete TC from " + "Store\n"); +#endif + continue; + } + deletedTCs++; + } + + // NOTE: Spec says this function erases all elements including itBegin but not itEnd, + // see here: https://www.cplusplus.com/reference/map/multimap/erase/ + // Therefore we need to increase itEnd by 1. (Note that end() returns the "past-the-end" iterator) + if (itEnd != telecommandMap.end()) { + itEnd++; + } + + telecommandMap.erase(itBegin, itEnd); + + if (debugMode) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "PUS11::doFilterDeleteActivity: Deleted " << deletedTCs << " TCs" << std::endl; +#else + sif::printInfo("PUS11::doFilterDeleteActivity: Deleted %d TCs\n", deletedTCs); +#endif + } + return RETURN_OK; +} + +template +inline ReturnValue_t Service11TelecommandScheduling::doTimeshiftActivity( + const uint8_t *data, size_t size) { + // Get relative time + uint32_t relativeTime = 0; + ReturnValue_t result = SerializeAdapter::deSerialize(&relativeTime, &data, &size, DEF_END); + if (result != RETURN_OK) { + return result; + } + if (relativeTime == 0) { + return INVALID_RELATIVE_TIME; + } + // TODO further check sanity of the relative time? + + // Get request ID + uint64_t requestId; + result = getRequestIdFromData(data, size, requestId); + if (result != RETURN_OK) { + return result; + } + + if (debugMode) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "PUS11::doTimeshiftActivity: requestId: " << requestId << std::endl; +#else + sif::printInfo("PUS11::doTimeshiftActivity: requestId: %d\n", requestId); +#endif + } + + // NOTE: Despite having C++17 ETL multimap has no member function extract :( + + TcMapIter tcToTimeshiftIt; + int tcToTimeshiftCount = 0; + + for (auto it = telecommandMap.begin(); it != telecommandMap.end(); it++) { + if (it->second.requestId == requestId) { + tcToTimeshiftIt = it; + tcToTimeshiftCount++; + } + } + + if (tcToTimeshiftCount == 0 || tcToTimeshiftCount > 1) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "Service11TelecommandScheduling::doTimeshiftActivity: Either 0 or more than 1 " + "TCs found. No explicit timeshifting " + "possible" + << std::endl; + +#else + sif::printWarning( + "Service11TelecommandScheduling::doTimeshiftActivity: Either 0 or more than 1 TCs found. " + "No explicit timeshifting possible\n"); +#endif + return TIMESHIFTING_NOT_POSSIBLE; + } + + // temporarily hold the item + TelecommandStruct tempTc(tcToTimeshiftIt->second); + uint32_t tempKey = tcToTimeshiftIt->first + relativeTime; + + // delete old entry from the mm + telecommandMap.erase(tcToTimeshiftIt); + + // and then insert it again as new entry + telecommandMap.insert(std::make_pair(tempKey, tempTc)); + + if (debugMode) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "PUS11::doTimeshiftActivity: Shifted TC" << std::endl; +#else + sif::printDebug("PUS11::doTimeshiftActivity: Shifted TC\n"); +#endif + debugPrintMultimapContent(); + } + + return RETURN_OK; +} + +template +inline ReturnValue_t Service11TelecommandScheduling::doFilterTimeshiftActivity( + const uint8_t *data, size_t size) { + // Get relative time + uint32_t relativeTime = 0; + ReturnValue_t result = SerializeAdapter::deSerialize(&relativeTime, &data, &size, DEF_END); + if (result != RETURN_OK) { + return result; + } + if (relativeTime == 0) { + return INVALID_RELATIVE_TIME; + } + + // Do time window + TcMapIter itBegin; + TcMapIter itEnd; + result = getMapFilterFromData(data, size, itBegin, itEnd); + if (result != RETURN_OK) { + return result; + } + + int shiftedItemsCount = 0; + for (auto it = itBegin; it != itEnd;) { + // temporarily hold the item + TelecommandStruct tempTc(it->second); + uint32_t tempKey = it->first + relativeTime; + + // delete the old entry from the mm + telecommandMap.erase(it++); + + // and then insert it again as new entry + telecommandMap.insert(std::make_pair(tempKey, tempTc)); + shiftedItemsCount++; + } + + if (debugMode) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "PUS11::doFilterTimeshiftActivity: shiftedItemsCount: " << shiftedItemsCount + << std::endl; +#else + sif::printInfo("PUS11::doFilterTimeshiftActivity: shiftedItemsCount: %d\n", shiftedItemsCount); +#endif + debugPrintMultimapContent(); + } + + if (shiftedItemsCount > 0) { + return RETURN_OK; + } + return RETURN_FAILED; +} + +template +inline uint64_t Service11TelecommandScheduling::getRequestIdFromDataTC( + const uint8_t *data) const { + TcPacketPus mask(data); + + uint32_t sourceId = mask.getSourceId(); + uint16_t apid = mask.getAPID(); + uint16_t sequenceCount = mask.getPacketSequenceCount(); + + return buildRequestId(sourceId, apid, sequenceCount); +} + +template +inline ReturnValue_t Service11TelecommandScheduling::getRequestIdFromData( + const uint8_t *&data, size_t &dataSize, uint64_t &requestId) { + uint32_t srcId = 0; + uint16_t apid = 0; + uint16_t ssc = 0; + + ReturnValue_t result = SerializeAdapter::deSerialize(&srcId, &data, &dataSize, DEF_END); + if (result != RETURN_OK) { + return result; + } + result = SerializeAdapter::deSerialize(&apid, &data, &dataSize, DEF_END); + if (result != RETURN_OK) { + return result; + } + result = SerializeAdapter::deSerialize(&ssc, &data, &dataSize, DEF_END); + if (result != RETURN_OK) { + return result; + } + requestId = buildRequestId(srcId, apid, ssc); + + return RETURN_OK; +} + +template +inline uint64_t Service11TelecommandScheduling::buildRequestId(uint32_t sourceId, + uint16_t apid, + uint16_t ssc) const { + auto sourceId64 = static_cast(sourceId); + auto apid64 = static_cast(apid); + auto ssc64 = static_cast(ssc); + + return (sourceId64 << 32) | (apid64 << 16) | ssc64; +} + +template +inline ReturnValue_t Service11TelecommandScheduling::getMapFilterFromData( + const uint8_t *&data, size_t &dataSize, TcMapIter &itBegin, TcMapIter &itEnd) { + // get filter type first + uint32_t typeRaw = 0; + ReturnValue_t result = SerializeAdapter::deSerialize(&typeRaw, &data, &dataSize, DEF_END); + if (result != RETURN_OK) { + return result; + } + + if (typeRaw > 3) { + return INVALID_TYPE_TIME_WINDOW; + } + auto type = static_cast(typeRaw); + + // we now have the type of delete activity - so now we set the range to delete, + // according to the type of time window. + // NOTE: Blocks are used in this switch-case statement so that timestamps can be + // cleanly redefined for each case. + switch (type) { + case TypeOfTimeWindow::SELECT_ALL: { + itBegin = telecommandMap.begin(); + itEnd = telecommandMap.end(); + break; + } + + case TypeOfTimeWindow::FROM_TIMETAG: { + uint32_t fromTimestamp = 0; + result = SerializeAdapter::deSerialize(&fromTimestamp, &data, &dataSize, DEF_END); + if (result != RETURN_OK) { + return result; + } + + itBegin = telecommandMap.begin(); + while (itBegin->first < fromTimestamp && itBegin != telecommandMap.end()) { + itBegin++; + } + + itEnd = telecommandMap.end(); + break; + } + + case TypeOfTimeWindow::TO_TIMETAG: { + uint32_t toTimestamp; + result = SerializeAdapter::deSerialize(&toTimestamp, &data, &dataSize, DEF_END); + if (result != RETURN_OK) { + return result; + } + itBegin = telecommandMap.begin(); + itEnd = telecommandMap.begin(); + while (itEnd->first <= toTimestamp && itEnd != telecommandMap.end()) { + itEnd++; + } + break; + } + + case TypeOfTimeWindow::FROM_TIMETAG_TO_TIMETAG: { + uint32_t fromTimestamp; + uint32_t toTimestamp; + + result = SerializeAdapter::deSerialize(&fromTimestamp, &data, &dataSize, + SerializeIF::Endianness::BIG); + if (result != RETURN_OK) { + return result; + } + result = SerializeAdapter::deSerialize(&toTimestamp, &data, &dataSize, + SerializeIF::Endianness::BIG); + if (result != RETURN_OK) { + return result; + } + itBegin = telecommandMap.begin(); + itEnd = telecommandMap.begin(); + + while (itBegin->first < fromTimestamp && itBegin != telecommandMap.end()) { + itBegin++; + } + while (itEnd->first <= toTimestamp && itEnd != telecommandMap.end()) { + itEnd++; + } + break; + } + + default: + return RETURN_FAILED; + } + + // additional security check, this should never be true + if (itBegin->first > itEnd->first) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 +#else + sif::printError("11::GetMapFilterFromData: itBegin > itEnd\n"); +#endif + return RETURN_FAILED; + } + + // the map range should now be set according to the sent filter. + return RETURN_OK; +} + +template +inline ReturnValue_t Service11TelecommandScheduling::handleInvalidData( + const char *ctx) { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "Service11TelecommandScheduling:: " << ctx << ": Invalid buffer" << std::endl; +#else + sif::printWarning("Service11TelecommandScheduling::%s: Invalid buffer\n", ctx); +#endif +#endif + return RETURN_FAILED; +} + +template +inline void Service11TelecommandScheduling::debugPrintMultimapContent() const { + for ([[maybe_unused]] const auto &dit : telecommandMap) { +#if FSFW_DISABLE_PRINTOUT == 0 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::debug << "Service11TelecommandScheduling::debugPrintMultimapContent: Multimap Content" + << std::endl; + sif::debug << "[" << dit.first << "]: Request ID: " << dit.second.requestId << " | " + << "Store Address: " << dit.second.storeAddr.raw << std::endl; +#else + sif::printDebug( + "Service11TelecommandScheduling::debugPrintMultimapContent: Multimap Content\n"); + for (auto dit = telecommandMap.begin(); dit != telecommandMap.end(); ++dit) { + sif::printDebug("[%d]: Request ID: %d | Store Address: %d\n", dit->first, + dit->second.requestId, dit->second.storeAddr); + } +#endif +#endif + } +} + +template +inline void Service11TelecommandScheduling::enableExpiredTcDeletion() { + deleteExpiredTcWhenDisabled = true; +} + +template +inline void Service11TelecommandScheduling::disableExpiredTcDeletion() { + deleteExpiredTcWhenDisabled = false; +} diff --git a/src/fsfw/pus/Service5EventReporting.cpp b/src/fsfw/pus/Service5EventReporting.cpp index 4517bc26..987217dc 100644 --- a/src/fsfw/pus/Service5EventReporting.cpp +++ b/src/fsfw/pus/Service5EventReporting.cpp @@ -86,8 +86,8 @@ ReturnValue_t Service5EventReporting::handleRequest(uint8_t subservice) { // In addition to the default PUSServiceBase initialization, this service needs // to be registered to the event manager to listen for events. ReturnValue_t Service5EventReporting::initialize() { - EventManagerIF* manager = ObjectManager::instance()->get(objects::EVENT_MANAGER); - if (manager == NULL) { + auto* manager = ObjectManager::instance()->get(objects::EVENT_MANAGER); + if (manager == nullptr) { return RETURN_FAILED; } // register Service 5 as listener for events diff --git a/src/fsfw/returnvalues/FwClassIds.h b/src/fsfw/returnvalues/FwClassIds.h index d07cedc9..f5f57276 100644 --- a/src/fsfw/returnvalues/FwClassIds.h +++ b/src/fsfw/returnvalues/FwClassIds.h @@ -72,6 +72,7 @@ enum : uint8_t { DLE_ENCODER, // DLEE PUS_SERVICE_3, // PUS3 PUS_SERVICE_9, // PUS9 + PUS_SERVICE_11, // PUS11 FILE_SYSTEM, // FILS LINUX_OSAL, // UXOS HAL_SPI, // HSPI diff --git a/src/fsfw/rmap/CMakeLists.txt b/src/fsfw/rmap/CMakeLists.txt index 78c99e42..44184860 100644 --- a/src/fsfw/rmap/CMakeLists.txt +++ b/src/fsfw/rmap/CMakeLists.txt @@ -1,7 +1,2 @@ -target_sources(${LIB_FSFW_NAME} - PRIVATE - RMAP.cpp - RMAPCookie.cpp - RmapDeviceCommunicationIF.cpp -) - +target_sources(${LIB_FSFW_NAME} PRIVATE RMAP.cpp RMAPCookie.cpp + RmapDeviceCommunicationIF.cpp) diff --git a/src/fsfw/serialize/CMakeLists.txt b/src/fsfw/serialize/CMakeLists.txt index fc2387e8..5ac92d7f 100644 --- a/src/fsfw/serialize/CMakeLists.txt +++ b/src/fsfw/serialize/CMakeLists.txt @@ -1,4 +1 @@ -target_sources(${LIB_FSFW_NAME} - PRIVATE - SerialBufferAdapter.cpp -) \ No newline at end of file +target_sources(${LIB_FSFW_NAME} PRIVATE SerialBufferAdapter.cpp) diff --git a/src/fsfw/serviceinterface/CMakeLists.txt b/src/fsfw/serviceinterface/CMakeLists.txt index 84c79177..df3f074e 100644 --- a/src/fsfw/serviceinterface/CMakeLists.txt +++ b/src/fsfw/serviceinterface/CMakeLists.txt @@ -1,5 +1,4 @@ -target_sources(${LIB_FSFW_NAME} PRIVATE - ServiceInterfaceStream.cpp - ServiceInterfaceBuffer.cpp - ServiceInterfacePrinter.cpp -) \ No newline at end of file +target_sources( + ${LIB_FSFW_NAME} + PRIVATE ServiceInterfaceStream.cpp ServiceInterfaceBuffer.cpp + ServiceInterfacePrinter.cpp) diff --git a/src/fsfw/storagemanager/CMakeLists.txt b/src/fsfw/storagemanager/CMakeLists.txt index b8138cae..50ce50ed 100644 --- a/src/fsfw/storagemanager/CMakeLists.txt +++ b/src/fsfw/storagemanager/CMakeLists.txt @@ -1,7 +1,3 @@ -target_sources(${LIB_FSFW_NAME} - PRIVATE - ConstStorageAccessor.cpp - StorageAccessor.cpp - LocalPool.cpp - PoolManager.cpp -) \ No newline at end of file +target_sources( + ${LIB_FSFW_NAME} PRIVATE ConstStorageAccessor.cpp StorageAccessor.cpp + LocalPool.cpp PoolManager.cpp) diff --git a/src/fsfw/subsystem/CMakeLists.txt b/src/fsfw/subsystem/CMakeLists.txt index 5c98ee70..164c90f7 100644 --- a/src/fsfw/subsystem/CMakeLists.txt +++ b/src/fsfw/subsystem/CMakeLists.txt @@ -1,7 +1,3 @@ -target_sources(${LIB_FSFW_NAME} - PRIVATE - Subsystem.cpp - SubsystemBase.cpp -) +target_sources(${LIB_FSFW_NAME} PRIVATE Subsystem.cpp SubsystemBase.cpp) -add_subdirectory(modes) \ No newline at end of file +add_subdirectory(modes) diff --git a/src/fsfw/subsystem/Subsystem.cpp b/src/fsfw/subsystem/Subsystem.cpp index ab8c1b16..27e6ae8e 100644 --- a/src/fsfw/subsystem/Subsystem.cpp +++ b/src/fsfw/subsystem/Subsystem.cpp @@ -307,6 +307,11 @@ void Subsystem::replyToCommand(ReturnValue_t status, uint32_t parameter) { } } +ReturnValue_t Subsystem::addSequence(SequenceEntry sequence) { + return addSequence(sequence.table, sequence.mode, sequence.fallbackMode, sequence.inStore, + sequence.preInit); +} + ReturnValue_t Subsystem::addSequence(ArrayList *sequence, Mode_t id, Mode_t fallbackSequence, bool inStore, bool preInit) { ReturnValue_t result; @@ -350,6 +355,10 @@ ReturnValue_t Subsystem::addSequence(ArrayList *sequence, Mode_t return result; } +ReturnValue_t Subsystem::addTable(TableEntry table) { + return addTable(table.table, table.mode, table.inStore, table.preInit); +} + ReturnValue_t Subsystem::addTable(ArrayList *table, Mode_t id, bool inStore, bool preInit) { ReturnValue_t result; @@ -458,6 +467,7 @@ ReturnValue_t Subsystem::initialize() { } mode = initialMode; + submode = initSubmode; return RETURN_OK; } @@ -595,7 +605,10 @@ ReturnValue_t Subsystem::checkObjectConnections() { return RETURN_OK; } -void Subsystem::setInitialMode(Mode_t mode) { initialMode = mode; } +void Subsystem::setInitialMode(Mode_t mode, Submode_t submode) { + this->initialMode = mode; + this->initSubmode = submode; +} void Subsystem::cantKeepMode() { ReturnValue_t result; diff --git a/src/fsfw/subsystem/Subsystem.h b/src/fsfw/subsystem/Subsystem.h index f1e7228d..855c8f7a 100644 --- a/src/fsfw/subsystem/Subsystem.h +++ b/src/fsfw/subsystem/Subsystem.h @@ -10,6 +10,28 @@ #include "fsfw/FSFW.h" #include "modes/ModeDefinitions.h" +struct TableSequenceBase { + public: + TableSequenceBase(Mode_t mode, ArrayList *table) : mode(mode), table(table){}; + Mode_t mode; + ArrayList *table; + bool inStore = false; + bool preInit = true; +}; + +struct TableEntry : public TableSequenceBase { + public: + TableEntry(Mode_t mode, ArrayList *table) : TableSequenceBase(mode, table){}; +}; + +struct SequenceEntry : public TableSequenceBase { + public: + SequenceEntry(Mode_t mode, ArrayList *table, Mode_t fallbackMode) + : TableSequenceBase(mode, table), fallbackMode(fallbackMode) {} + + Mode_t fallbackMode; +}; + /** * @brief TODO: documentation missing * @details @@ -44,13 +66,15 @@ class Subsystem : public SubsystemBase, public HasModeSequenceIF { uint32_t maxNumberOfTables); virtual ~Subsystem(); + ReturnValue_t addSequence(SequenceEntry sequence); ReturnValue_t addSequence(ArrayList *sequence, Mode_t id, Mode_t fallbackSequence, bool inStore = true, bool preInit = true); + ReturnValue_t addTable(TableEntry table); ReturnValue_t addTable(ArrayList *table, Mode_t id, bool inStore = true, bool preInit = true); - void setInitialMode(Mode_t mode); + void setInitialMode(Mode_t mode, Submode_t submode = SUBMODE_NONE); virtual ReturnValue_t initialize() override; @@ -89,6 +113,7 @@ class Subsystem : public SubsystemBase, public HasModeSequenceIF { Submode_t targetSubmode; Mode_t initialMode = 0; + Submode_t initSubmode = SUBMODE_NONE; HybridIterator currentSequenceIterator; diff --git a/src/fsfw/subsystem/modes/CMakeLists.txt b/src/fsfw/subsystem/modes/CMakeLists.txt index 6ac6a293..ba57de2c 100644 --- a/src/fsfw/subsystem/modes/CMakeLists.txt +++ b/src/fsfw/subsystem/modes/CMakeLists.txt @@ -1,5 +1 @@ -target_sources(${LIB_FSFW_NAME} - PRIVATE - ModeSequenceMessage.cpp - ModeStore.cpp -) +target_sources(${LIB_FSFW_NAME} PRIVATE ModeSequenceMessage.cpp ModeStore.cpp) diff --git a/src/fsfw/tasks/CMakeLists.txt b/src/fsfw/tasks/CMakeLists.txt index 1964bb4e..df69520a 100644 --- a/src/fsfw/tasks/CMakeLists.txt +++ b/src/fsfw/tasks/CMakeLists.txt @@ -1,5 +1,2 @@ -target_sources(${LIB_FSFW_NAME} - PRIVATE - FixedSequenceSlot.cpp - FixedSlotSequence.cpp -) \ No newline at end of file +target_sources(${LIB_FSFW_NAME} PRIVATE FixedSequenceSlot.cpp + FixedSlotSequence.cpp) diff --git a/src/fsfw/tcdistribution/CCSDSDistributor.cpp b/src/fsfw/tcdistribution/CCSDSDistributor.cpp index 3f4bbee3..628dd8d0 100644 --- a/src/fsfw/tcdistribution/CCSDSDistributor.cpp +++ b/src/fsfw/tcdistribution/CCSDSDistributor.cpp @@ -9,7 +9,7 @@ CCSDSDistributor::CCSDSDistributor(uint16_t setDefaultApid, object_id_t setObjectId) : TcDistributor(setObjectId), defaultApid(setDefaultApid) {} -CCSDSDistributor::~CCSDSDistributor() {} +CCSDSDistributor::~CCSDSDistributor() = default; TcDistributor::TcMqMapIter CCSDSDistributor::selectDestination() { #if CCSDS_DISTRIBUTOR_DEBUGGING == 1 @@ -38,6 +38,7 @@ TcDistributor::TcMqMapIter CCSDSDistributor::selectDestination() { " store failed!\n"); #endif #endif + return queueMap.end(); } SpacePacketBase currentPacket(packet); @@ -45,7 +46,7 @@ TcDistributor::TcMqMapIter CCSDSDistributor::selectDestination() { sif::info << "CCSDSDistributor::selectDestination has packet with APID " << std::hex << currentPacket.getAPID() << std::dec << std::endl; #endif - TcMqMapIter position = this->queueMap.find(currentPacket.getAPID()); + auto position = this->queueMap.find(currentPacket.getAPID()); if (position != this->queueMap.end()) { return position; } else { diff --git a/src/fsfw/tcdistribution/CMakeLists.txt b/src/fsfw/tcdistribution/CMakeLists.txt index 7118c38c..ab32c509 100644 --- a/src/fsfw/tcdistribution/CMakeLists.txt +++ b/src/fsfw/tcdistribution/CMakeLists.txt @@ -1,9 +1,4 @@ -target_sources(${LIB_FSFW_NAME} PRIVATE - CCSDSDistributor.cpp - PUSDistributor.cpp - TcDistributor.cpp - TcPacketCheckPUS.cpp - TcPacketCheckCFDP.cpp - CFDPDistributor.cpp -) - +target_sources( + ${LIB_FSFW_NAME} + PRIVATE CCSDSDistributor.cpp PUSDistributor.cpp TcDistributor.cpp + TcPacketCheckPUS.cpp TcPacketCheckCFDP.cpp CFDPDistributor.cpp) diff --git a/src/fsfw/tcdistribution/PUSDistributor.cpp b/src/fsfw/tcdistribution/PUSDistributor.cpp index aadecd69..dad002a1 100644 --- a/src/fsfw/tcdistribution/PUSDistributor.cpp +++ b/src/fsfw/tcdistribution/PUSDistributor.cpp @@ -15,7 +15,7 @@ PUSDistributor::PUSDistributor(uint16_t setApid, object_id_t setObjectId, tcStatus(RETURN_FAILED), packetSource(setPacketSource) {} -PUSDistributor::~PUSDistributor() {} +PUSDistributor::~PUSDistributor() = default; PUSDistributor::TcMqMapIter PUSDistributor::selectDestination() { #if FSFW_CPP_OSTREAM_ENABLED == 1 && PUS_DISTRIBUTOR_DEBUGGING == 1 @@ -23,7 +23,7 @@ PUSDistributor::TcMqMapIter PUSDistributor::selectDestination() { sif::debug << "PUSDistributor::handlePacket received: " << storeId.poolIndex << ", " << storeId.packetIndex << std::endl; #endif - TcMqMapIter queueMapIt = this->queueMap.end(); + auto queueMapIt = this->queueMap.end(); if (this->currentPacket == nullptr) { return queueMapIt; } @@ -48,10 +48,8 @@ PUSDistributor::TcMqMapIter PUSDistributor::selectDestination() { sif::warning << "PUSDistributor::handlePacket: Packet format invalid, " << keyword << " error" << std::endl; #else - sif::printWarning( - "PUSDistributor::handlePacket: Packet format invalid, " - "%s error\n", - keyword); + sif::printWarning("PUSDistributor::handlePacket: Packet format invalid, %s error\n", + keyword); #endif #endif } @@ -133,8 +131,7 @@ ReturnValue_t PUSDistributor::initialize() { return ObjectManagerIF::CHILD_INIT_FAILED; } - CCSDSDistributorIF* ccsdsDistributor = - ObjectManager::instance()->get(packetSource); + auto* ccsdsDistributor = ObjectManager::instance()->get(packetSource); if (ccsdsDistributor == nullptr) { #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "PUSDistributor::initialize: Packet source invalid" << std::endl; diff --git a/src/fsfw/thermal/CMakeLists.txt b/src/fsfw/thermal/CMakeLists.txt index ad532721..995ebc4d 100644 --- a/src/fsfw/thermal/CMakeLists.txt +++ b/src/fsfw/thermal/CMakeLists.txt @@ -1,10 +1,9 @@ -target_sources(${LIB_FSFW_NAME} - PRIVATE - AbstractTemperatureSensor.cpp - Heater.cpp - RedundantHeater.cpp - ThermalComponentCore.cpp - ThermalComponent.cpp - ThermalModule.cpp - ThermalMonitorReporter.cpp -) +target_sources( + ${LIB_FSFW_NAME} + PRIVATE AbstractTemperatureSensor.cpp + Heater.cpp + RedundantHeater.cpp + ThermalComponentCore.cpp + ThermalComponent.cpp + ThermalModule.cpp + ThermalMonitorReporter.cpp) diff --git a/src/fsfw/timemanager/CMakeLists.txt b/src/fsfw/timemanager/CMakeLists.txt index 00467772..c4f77395 100644 --- a/src/fsfw/timemanager/CMakeLists.txt +++ b/src/fsfw/timemanager/CMakeLists.txt @@ -1,8 +1,3 @@ -target_sources(${LIB_FSFW_NAME} PRIVATE - CCSDSTime.cpp - Countdown.cpp - Stopwatch.cpp - TimeMessage.cpp - TimeStamper.cpp - ClockCommon.cpp -) +target_sources( + ${LIB_FSFW_NAME} PRIVATE CCSDSTime.cpp Countdown.cpp Stopwatch.cpp + TimeMessage.cpp TimeStamper.cpp ClockCommon.cpp) diff --git a/src/fsfw/tmstorage/CMakeLists.txt b/src/fsfw/tmstorage/CMakeLists.txt index 7990d85a..80da7faf 100644 --- a/src/fsfw/tmstorage/CMakeLists.txt +++ b/src/fsfw/tmstorage/CMakeLists.txt @@ -1,4 +1 @@ -target_sources(${LIB_FSFW_NAME} - PRIVATE - TmStoreMessage.cpp -) +target_sources(${LIB_FSFW_NAME} PRIVATE TmStoreMessage.cpp) diff --git a/src/fsfw/tmtcpacket/CMakeLists.txt b/src/fsfw/tmtcpacket/CMakeLists.txt index e1deaba9..196ba752 100644 --- a/src/fsfw/tmtcpacket/CMakeLists.txt +++ b/src/fsfw/tmtcpacket/CMakeLists.txt @@ -1,8 +1,5 @@ -target_sources(${LIB_FSFW_NAME} PRIVATE - SpacePacket.cpp - SpacePacketBase.cpp -) +target_sources(${LIB_FSFW_NAME} PRIVATE SpacePacket.cpp SpacePacketBase.cpp) add_subdirectory(cfdp) add_subdirectory(packetmatcher) -add_subdirectory(pus) \ No newline at end of file +add_subdirectory(pus) diff --git a/src/fsfw/tmtcpacket/cfdp/CMakeLists.txt b/src/fsfw/tmtcpacket/cfdp/CMakeLists.txt index 0b7ab18a..7d20aab8 100644 --- a/src/fsfw/tmtcpacket/cfdp/CMakeLists.txt +++ b/src/fsfw/tmtcpacket/cfdp/CMakeLists.txt @@ -1,4 +1 @@ -target_sources(${LIB_FSFW_NAME} PRIVATE - CFDPPacket.cpp - CFDPPacketStored.cpp -) +target_sources(${LIB_FSFW_NAME} PRIVATE CFDPPacket.cpp CFDPPacketStored.cpp) diff --git a/src/fsfw/tmtcpacket/packetmatcher/CMakeLists.txt b/src/fsfw/tmtcpacket/packetmatcher/CMakeLists.txt index e9a8d03b..6ea94799 100644 --- a/src/fsfw/tmtcpacket/packetmatcher/CMakeLists.txt +++ b/src/fsfw/tmtcpacket/packetmatcher/CMakeLists.txt @@ -1,4 +1 @@ -target_sources(${LIB_FSFW_NAME} - PRIVATE - PacketMatchTree.cpp -) +target_sources(${LIB_FSFW_NAME} PRIVATE PacketMatchTree.cpp) diff --git a/src/fsfw/tmtcpacket/pus/tc/CMakeLists.txt b/src/fsfw/tmtcpacket/pus/tc/CMakeLists.txt index dc611263..09c63bfd 100644 --- a/src/fsfw/tmtcpacket/pus/tc/CMakeLists.txt +++ b/src/fsfw/tmtcpacket/pus/tc/CMakeLists.txt @@ -1,6 +1,3 @@ -target_sources(${LIB_FSFW_NAME} PRIVATE - TcPacketPusBase.cpp - TcPacketPus.cpp - TcPacketStoredBase.cpp - TcPacketStoredPus.cpp -) +target_sources( + ${LIB_FSFW_NAME} PRIVATE TcPacketPusBase.cpp TcPacketPus.cpp + TcPacketStoredBase.cpp TcPacketStoredPus.cpp) diff --git a/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredBase.cpp b/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredBase.cpp index 8cc38c5f..22918526 100644 --- a/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredBase.cpp +++ b/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredBase.cpp @@ -6,20 +6,20 @@ #include "fsfw/objectmanager/frameworkObjects.h" #include "fsfw/serviceinterface/ServiceInterface.h" -StorageManagerIF* TcPacketStoredBase::store = nullptr; +StorageManagerIF* TcPacketStoredBase::STORE = nullptr; TcPacketStoredBase::TcPacketStoredBase() { this->storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; - this->checkAndSetStore(); + TcPacketStoredBase::checkAndSetStore(); } -TcPacketStoredBase::~TcPacketStoredBase() {} +TcPacketStoredBase::~TcPacketStoredBase() = default; ReturnValue_t TcPacketStoredBase::getData(const uint8_t** dataPtr, size_t* dataSize) { - auto result = this->store->getData(storeAddress, dataPtr, dataSize); + auto result = TcPacketStoredBase::STORE->getData(storeAddress, dataPtr, dataSize); if (result != HasReturnvaluesIF::RETURN_OK) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "TcPacketStoredBase: Could not get data!" << std::endl; + sif::warning << "TcPacketStoredBase: Could not get data" << std::endl; #else sif::printWarning("TcPacketStoredBase: Could not get data!\n"); #endif @@ -28,11 +28,13 @@ ReturnValue_t TcPacketStoredBase::getData(const uint8_t** dataPtr, size_t* dataS } bool TcPacketStoredBase::checkAndSetStore() { - if (this->store == nullptr) { - this->store = ObjectManager::instance()->get(objects::TC_STORE); - if (this->store == nullptr) { + if (TcPacketStoredBase::STORE == nullptr) { + TcPacketStoredBase::STORE = ObjectManager::instance()->get(objects::TC_STORE); + if (TcPacketStoredBase::STORE == nullptr) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "TcPacketStoredBase::TcPacketStoredBase: TC Store not found!" << std::endl; + sif::error << "TcPacketStoredBase::TcPacketStoredBase: TC Store not found" << std::endl; +#else + sif::printError("TcPacketStoredBase::TcPacketStoredBase: TC Store not found\n"); #endif return false; } @@ -47,7 +49,7 @@ void TcPacketStoredBase::setStoreAddress(store_address_t setAddress, size_t tempSize; ReturnValue_t status = StorageManagerIF::RETURN_FAILED; if (this->checkAndSetStore()) { - status = this->store->getData(this->storeAddress, &tempData, &tempSize); + status = TcPacketStoredBase::STORE->getData(this->storeAddress, &tempData, &tempSize); } if (status == StorageManagerIF::RETURN_OK) { diff --git a/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredBase.h b/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredBase.h index 86f0d94e..ece0e482 100644 --- a/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredBase.h +++ b/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredBase.h @@ -65,7 +65,7 @@ class TcPacketStoredBase : public TcPacketStoredIF { * call tries to set it and throws an error message in case of failures. * The default store is objects::TC_STORE. */ - static StorageManagerIF* store; + static StorageManagerIF* STORE; /** * The address where the packet data of the object instance is stored. */ @@ -77,7 +77,7 @@ class TcPacketStoredBase : public TcPacketStoredIF { * @return @li @c true if the store is linked or could be created. * @li @c false otherwise. */ - bool checkAndSetStore(); + static bool checkAndSetStore(); }; -#endif /* TMTCPACKET_PUS_TcPacketStoredBase_H_ */ +#endif /* TMTCPACKET_PUS_TCPACKETSTORED_H_ */ diff --git a/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredIF.h b/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredIF.h index ac4019cd..7ac8c331 100644 --- a/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredIF.h +++ b/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredIF.h @@ -9,7 +9,8 @@ class TcPacketStoredIF { public: - virtual ~TcPacketStoredIF(){}; + virtual ~TcPacketStoredIF() = default; + ; /** * With this call, the stored packet can be set to another packet in a store. This is useful diff --git a/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredPus.cpp b/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredPus.cpp index 153ad863..643c2ecc 100644 --- a/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredPus.cpp +++ b/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredPus.cpp @@ -14,8 +14,8 @@ TcPacketStoredPus::TcPacketStoredPus(uint16_t apid, uint8_t service, uint8_t sub } uint8_t* pData = nullptr; ReturnValue_t returnValue = - this->store->getFreeElement(&this->storeAddress, (TC_PACKET_MIN_SIZE + size), &pData); - if (returnValue != this->store->RETURN_OK) { + this->STORE->getFreeElement(&this->storeAddress, (TC_PACKET_MIN_SIZE + size), &pData); + if (returnValue != this->STORE->RETURN_OK) { #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "TcPacketStoredBase: Could not get free element from store!" << std::endl; #endif @@ -44,19 +44,19 @@ TcPacketStoredPus::TcPacketStoredPus(const uint8_t* data, size_t size) : TcPacke return; } if (this->checkAndSetStore()) { - ReturnValue_t status = store->addData(&storeAddress, data, size); + ReturnValue_t status = STORE->addData(&storeAddress, data, size); if (status != HasReturnvaluesIF::RETURN_OK) { this->setData(nullptr, size); } const uint8_t* storePtr = nullptr; // Repoint base data pointer to the data in the store. - store->getData(storeAddress, &storePtr, &size); + STORE->getData(storeAddress, &storePtr, &size); this->setData(const_cast(storePtr), size); } } ReturnValue_t TcPacketStoredPus::deletePacket() { - ReturnValue_t result = this->store->deleteData(this->storeAddress); + ReturnValue_t result = this->STORE->deleteData(this->storeAddress); this->storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; // To circumvent size checks this->setData(nullptr, -1); @@ -68,7 +68,7 @@ TcPacketPusBase* TcPacketStoredPus::getPacketBase() { return this; } bool TcPacketStoredPus::isSizeCorrect() { const uint8_t* temp_data = nullptr; size_t temp_size; - ReturnValue_t status = this->store->getData(this->storeAddress, &temp_data, &temp_size); + ReturnValue_t status = this->STORE->getData(this->storeAddress, &temp_data, &temp_size); if (status == StorageManagerIF::RETURN_OK) { if (this->getFullSize() == temp_size) { return true; diff --git a/src/fsfw/tmtcpacket/pus/tm/CMakeLists.txt b/src/fsfw/tmtcpacket/pus/tm/CMakeLists.txt index ace87820..ded74ce2 100644 --- a/src/fsfw/tmtcpacket/pus/tm/CMakeLists.txt +++ b/src/fsfw/tmtcpacket/pus/tm/CMakeLists.txt @@ -1,9 +1,9 @@ -target_sources(${LIB_FSFW_NAME} PRIVATE - TmPacketStoredPusA.cpp - TmPacketStoredPusC.cpp - TmPacketPusA.cpp - TmPacketPusC.cpp - TmPacketStoredBase.cpp - TmPacketBase.cpp - TmPacketMinimal.cpp -) +target_sources( + ${LIB_FSFW_NAME} + PRIVATE TmPacketStoredPusA.cpp + TmPacketStoredPusC.cpp + TmPacketPusA.cpp + TmPacketPusC.cpp + TmPacketStoredBase.cpp + TmPacketBase.cpp + TmPacketMinimal.cpp) diff --git a/src/fsfw/tmtcservices/AcceptsTelecommandsIF.h b/src/fsfw/tmtcservices/AcceptsTelecommandsIF.h index 4186f4df..e18a4f3a 100644 --- a/src/fsfw/tmtcservices/AcceptsTelecommandsIF.h +++ b/src/fsfw/tmtcservices/AcceptsTelecommandsIF.h @@ -1,7 +1,7 @@ #ifndef FRAMEWORK_TMTCSERVICES_ACCEPTSTELECOMMANDSIF_H_ #define FRAMEWORK_TMTCSERVICES_ACCEPTSTELECOMMANDSIF_H_ -#include "../ipc/MessageQueueSenderIF.h" +#include "fsfw/ipc/MessageQueueSenderIF.h" /** * @brief This interface is implemented by classes that are sinks for @@ -20,7 +20,7 @@ class AcceptsTelecommandsIF { /** * @brief The virtual destructor as it is mandatory for C++ interfaces. */ - virtual ~AcceptsTelecommandsIF() {} + virtual ~AcceptsTelecommandsIF() = default; /** * @brief Getter for the service id. * @details Any receiving service (at least any PUS service) shall have a diff --git a/src/fsfw/tmtcservices/CMakeLists.txt b/src/fsfw/tmtcservices/CMakeLists.txt index 96cf99b5..d2a3f4ed 100644 --- a/src/fsfw/tmtcservices/CMakeLists.txt +++ b/src/fsfw/tmtcservices/CMakeLists.txt @@ -1,10 +1,9 @@ -target_sources(${LIB_FSFW_NAME} - PRIVATE - CommandingServiceBase.cpp - PusServiceBase.cpp - PusVerificationReport.cpp - TmTcBridge.cpp - TmTcMessage.cpp - VerificationReporter.cpp - SpacePacketParser.cpp -) \ No newline at end of file +target_sources( + ${LIB_FSFW_NAME} + PRIVATE CommandingServiceBase.cpp + PusServiceBase.cpp + PusVerificationReport.cpp + TmTcBridge.cpp + TmTcMessage.cpp + VerificationReporter.cpp + SpacePacketParser.cpp) diff --git a/src/fsfw/tmtcservices/CommandingServiceBase.h b/src/fsfw/tmtcservices/CommandingServiceBase.h index 867fc287..4dcad024 100644 --- a/src/fsfw/tmtcservices/CommandingServiceBase.h +++ b/src/fsfw/tmtcservices/CommandingServiceBase.h @@ -166,7 +166,7 @@ class CommandingServiceBase : public SystemObject, * @param objectId Target object ID * @return * - @c RETURN_OK to generate a verification start message - * - @c EXECUTION_COMPELTE Fire-and-forget command. Generate a completion + * - @c EXECUTION_COMPLETE Fire-and-forget command. Generate a completion * verification message. * - @c Anything else rejects the packets and generates a start failure * verification. diff --git a/src/fsfw/version.cpp b/src/fsfw/version.cpp index e4a62002..050187a9 100644 --- a/src/fsfw/version.cpp +++ b/src/fsfw/version.cpp @@ -13,11 +13,28 @@ #endif const fsfw::Version fsfw::FSFW_VERSION = {FSFW_VERSION_MAJOR, FSFW_VERSION_MINOR, - FSFW_VERSION_REVISION}; + FSFW_VERSION_REVISION, FSFW_VCS_INFO}; -fsfw::Version::Version(uint32_t major, uint32_t minor, uint32_t revision) - : major(major), minor(minor), revision(revision) {} +fsfw::Version::Version(int major, int minor, int revision, const char* addInfo) + : major(major), minor(minor), revision(revision), addInfo(addInfo) {} void fsfw::Version::getVersion(char* str, size_t maxLen) const { - snprintf(str, maxLen, "%d.%d.%d", major, minor, revision); + size_t len = snprintf(str, maxLen, "%d.%d.%d", major, minor, revision); + if (addInfo != nullptr) { + snprintf(str + len, maxLen - len, "-%s", addInfo); + } } + +namespace fsfw { + +#if FSFW_CPP_OSTREAM_ENABLED == 1 +std::ostream& operator<<(std::ostream& os, const Version& v) { + os << v.major << "." << v.minor << "." << v.revision; + if (v.addInfo != nullptr) { + os << "-" << v.addInfo; + } + return os; +} +#endif + +} // namespace fsfw diff --git a/src/fsfw/version.h b/src/fsfw/version.h index bb4d0399..a538c39a 100644 --- a/src/fsfw/version.h +++ b/src/fsfw/version.h @@ -12,10 +12,13 @@ namespace fsfw { class Version { public: - Version(uint32_t major, uint32_t minor, uint32_t revision); - uint32_t major = 0; - uint32_t minor = 0; - uint32_t revision = 0; + Version(int major, int minor, int revision, const char* addInfo = nullptr); + int major = -1; + int minor = -1; + int revision = -1; + + // Additional information, e.g. a git SHA hash + const char* addInfo = nullptr; friend bool operator==(const Version& v1, const Version& v2) { return (v1.major == v2.major and v1.minor == v2.minor and v1.revision == v2.revision); @@ -43,10 +46,7 @@ class Version { * @param v * @return */ - friend std::ostream& operator<<(std::ostream& os, const Version& v) { - os << v.major << "." << v.minor << "." << v.revision; - return os; - } + friend std::ostream& operator<<(std::ostream& os, const Version& v); #endif /** @@ -57,7 +57,7 @@ class Version { void getVersion(char* str, size_t maxLen) const; }; -extern const fsfw::Version FSFW_VERSION; +extern const Version FSFW_VERSION; } // namespace fsfw diff --git a/tests/src/fsfw_tests/unit/CMakeLists.txt b/tests/src/fsfw_tests/unit/CMakeLists.txt index eb57202a..f54e1fc9 100644 --- a/tests/src/fsfw_tests/unit/CMakeLists.txt +++ b/tests/src/fsfw_tests/unit/CMakeLists.txt @@ -11,7 +11,10 @@ target_sources(${FSFW_TEST_TGT} PRIVATE ) add_subdirectory(testcfg) +add_subdirectory(mocks) + add_subdirectory(action) +add_subdirectory(power) add_subdirectory(container) add_subdirectory(osal) add_subdirectory(serialize) diff --git a/tests/src/fsfw_tests/unit/mocks/CMakeLists.txt b/tests/src/fsfw_tests/unit/mocks/CMakeLists.txt new file mode 100644 index 00000000..1b86547c --- /dev/null +++ b/tests/src/fsfw_tests/unit/mocks/CMakeLists.txt @@ -0,0 +1,3 @@ +target_sources(${FSFW_TEST_TGT} PRIVATE + PowerSwitcherMock.cpp +) diff --git a/tests/src/fsfw_tests/unit/mocks/PowerSwitcherMock.cpp b/tests/src/fsfw_tests/unit/mocks/PowerSwitcherMock.cpp new file mode 100644 index 00000000..5c6935e4 --- /dev/null +++ b/tests/src/fsfw_tests/unit/mocks/PowerSwitcherMock.cpp @@ -0,0 +1,77 @@ +#include "PowerSwitcherMock.h" + +static uint32_t SWITCH_REQUEST_UPDATE_VALUE = 0; + +PowerSwitcherMock::PowerSwitcherMock() {} + +ReturnValue_t PowerSwitcherMock::sendSwitchCommand(power::Switch_t switchNr, ReturnValue_t onOff) { + if (switchMap.count(switchNr) == 0) { + switchMap.emplace(switchNr, SwitchInfo(switchNr, onOff)); + } else { + SwitchInfo& info = switchMap.at(switchNr); + info.currentState = onOff; + if (onOff == PowerSwitchIF::SWITCH_ON) { + info.timesCalledOn++; + } else { + info.timesCalledOff++; + } + } + return RETURN_OK; +} + +ReturnValue_t PowerSwitcherMock::sendFuseOnCommand(uint8_t fuseNr) { + if (fuseMap.count(fuseNr) == 0) { + fuseMap.emplace(fuseNr, FuseInfo(fuseNr)); + } else { + FuseInfo& info = fuseMap.at(fuseNr); + info.timesCalled++; + } + return RETURN_OK; +} + +ReturnValue_t PowerSwitcherMock::getSwitchState(power::Switch_t switchNr) const { + if (switchMap.count(switchNr) == 1) { + auto& info = switchMap.at(switchNr); + SWITCH_REQUEST_UPDATE_VALUE++; + return info.currentState; + } + return RETURN_FAILED; +} + +ReturnValue_t PowerSwitcherMock::getFuseState(uint8_t fuseNr) const { + if (fuseMap.count(fuseNr) == 1) { + return FUSE_ON; + } else { + return FUSE_OFF; + } + return RETURN_FAILED; +} + +uint32_t PowerSwitcherMock::getSwitchDelayMs(void) const { return 5000; } + +SwitchInfo::SwitchInfo() : switcher(0) {} + +SwitchInfo::SwitchInfo(power::Switch_t switcher, ReturnValue_t initState) + : switcher(switcher), currentState(initState) {} + +FuseInfo::FuseInfo(uint8_t fuse) : fuse(fuse) {} + +void PowerSwitcherMock::getSwitchInfo(power::Switch_t switcher, SwitchInfo& info) { + if (switchMap.count(switcher) == 1) { + info = switchMap.at(switcher); + } +} + +void PowerSwitcherMock::getFuseInfo(uint8_t fuse, FuseInfo& info) { + if (fuseMap.count(fuse) == 1) { + info = fuseMap.at(fuse); + } +} + +uint32_t PowerSwitcherMock::getAmountSwitchStatWasRequested() { + return SWITCH_REQUEST_UPDATE_VALUE; +} + +void PowerSwitcherMock::initSwitch(power::Switch_t switchNr) { + switchMap.emplace(switchNr, SwitchInfo(switchNr, PowerSwitchIF::SWITCH_OFF)); +} diff --git a/tests/src/fsfw_tests/unit/mocks/PowerSwitcherMock.h b/tests/src/fsfw_tests/unit/mocks/PowerSwitcherMock.h new file mode 100644 index 00000000..3a740e66 --- /dev/null +++ b/tests/src/fsfw_tests/unit/mocks/PowerSwitcherMock.h @@ -0,0 +1,52 @@ +#ifndef FSFW_TESTS_SRC_FSFW_TESTS_UNIT_MOCKS_POWERSWITCHERMOCK_H_ +#define FSFW_TESTS_SRC_FSFW_TESTS_UNIT_MOCKS_POWERSWITCHERMOCK_H_ + +#include + +#include +#include + +struct SwitchInfo { + public: + SwitchInfo(); + SwitchInfo(power::Switch_t switcher, ReturnValue_t initState); + + power::Switch_t switcher; + ReturnValue_t currentState = PowerSwitchIF::SWITCH_OFF; + uint32_t timesCalledOn = 0; + uint32_t timesCalledOff = 0; + uint32_t timesStatusRequested = 0; +}; + +struct FuseInfo { + public: + FuseInfo(uint8_t fuse); + uint8_t fuse; + uint32_t timesCalled = 0; +}; + +class PowerSwitcherMock : public PowerSwitchIF { + public: + PowerSwitcherMock(); + + ReturnValue_t sendSwitchCommand(power::Switch_t switchNr, ReturnValue_t onOff) override; + ReturnValue_t sendFuseOnCommand(uint8_t fuseNr) override; + ReturnValue_t getSwitchState(power::Switch_t switchNr) const override; + ReturnValue_t getFuseState(uint8_t fuseNr) const override; + uint32_t getSwitchDelayMs(void) const override; + + void getSwitchInfo(power::Switch_t switcher, SwitchInfo& info); + void getFuseInfo(uint8_t fuse, FuseInfo& info); + + uint32_t getAmountSwitchStatWasRequested(); + + void initSwitch(power::Switch_t switchNr); + + private: + using SwitchOnOffPair = std::pair; + using FuseOnOffPair = std::pair; + std::map switchMap; + std::map fuseMap; +}; + +#endif /* FSFW_TESTS_SRC_FSFW_TESTS_UNIT_MOCKS_POWERSWITCHERMOCK_H_ */ diff --git a/tests/src/fsfw_tests/unit/power/CMakeLists.txt b/tests/src/fsfw_tests/unit/power/CMakeLists.txt new file mode 100644 index 00000000..667e6f51 --- /dev/null +++ b/tests/src/fsfw_tests/unit/power/CMakeLists.txt @@ -0,0 +1,3 @@ +target_sources(${FSFW_TEST_TGT} PRIVATE + testPowerSwitcher.cpp +) diff --git a/tests/src/fsfw_tests/unit/power/testPowerSwitcher.cpp b/tests/src/fsfw_tests/unit/power/testPowerSwitcher.cpp new file mode 100644 index 00000000..941055ac --- /dev/null +++ b/tests/src/fsfw_tests/unit/power/testPowerSwitcher.cpp @@ -0,0 +1,71 @@ +#include +#include +#include + +#include + +#include "objects/systemObjectList.h" + +TEST_CASE("Power Switcher", "[power-switcher]") { + PowerSwitcherMock mock; + PowerSwitcher switcher(&mock, 1); + DummyPowerSwitcher dummySwitcher(objects::DUMMY_POWER_SWITCHER, 5, 5, false); + PowerSwitcher switcherUsingDummy(&dummySwitcher, 1); + SwitchInfo switchInfo; + mock.initSwitch(1); + + SECTION("Basic Tests") { + REQUIRE(switcher.getFirstSwitch() == 1); + REQUIRE(switcher.getSecondSwitch() == power::NO_SWITCH); + // Default start state + REQUIRE(switcher.getState() == PowerSwitcher::SWITCH_IS_OFF); + switcher.turnOn(true); + REQUIRE(mock.getAmountSwitchStatWasRequested() == 1); + REQUIRE(switcher.getState() == PowerSwitcher::WAIT_ON); + REQUIRE(switcher.checkSwitchState() == PowerSwitcher::IN_POWER_TRANSITION); + REQUIRE(switcher.active()); + switcher.doStateMachine(); + REQUIRE(switcher.getState() == PowerSwitcher::SWITCH_IS_ON); + mock.getSwitchInfo(1, switchInfo); + REQUIRE(switchInfo.timesCalledOn == 1); + REQUIRE(not switcher.active()); + REQUIRE(mock.getAmountSwitchStatWasRequested() == 2); + REQUIRE(switcher.checkSwitchState() == HasReturnvaluesIF::RETURN_OK); + REQUIRE(mock.getAmountSwitchStatWasRequested() == 3); + switcher.turnOff(false); + REQUIRE(mock.getAmountSwitchStatWasRequested() == 3); + REQUIRE(switcher.getState() == PowerSwitcher::WAIT_OFF); + REQUIRE(switcher.active()); + REQUIRE(switcher.getState() == PowerSwitcher::WAIT_OFF); + switcher.doStateMachine(); + mock.getSwitchInfo(1, switchInfo); + REQUIRE(switcher.getState() == PowerSwitcher::SWITCH_IS_OFF); + REQUIRE(switchInfo.timesCalledOn == 1); + REQUIRE(switchInfo.timesCalledOff == 1); + REQUIRE(not switcher.active()); + REQUIRE(mock.getAmountSwitchStatWasRequested() == 4); + } + + SECTION("Dummy Test") { + // Same tests, but we can't really check the dummy + REQUIRE(switcherUsingDummy.getFirstSwitch() == 1); + REQUIRE(switcherUsingDummy.getSecondSwitch() == power::NO_SWITCH); + REQUIRE(switcherUsingDummy.getState() == PowerSwitcher::SWITCH_IS_OFF); + switcherUsingDummy.turnOn(true); + REQUIRE(switcherUsingDummy.getState() == PowerSwitcher::WAIT_ON); + REQUIRE(switcherUsingDummy.active()); + switcherUsingDummy.doStateMachine(); + REQUIRE(switcherUsingDummy.getState() == PowerSwitcher::SWITCH_IS_ON); + REQUIRE(not switcherUsingDummy.active()); + + switcherUsingDummy.turnOff(false); + REQUIRE(switcherUsingDummy.getState() == PowerSwitcher::WAIT_OFF); + REQUIRE(switcherUsingDummy.active()); + REQUIRE(switcherUsingDummy.getState() == PowerSwitcher::WAIT_OFF); + switcherUsingDummy.doStateMachine(); + REQUIRE(switcherUsingDummy.getState() == PowerSwitcher::SWITCH_IS_OFF); + REQUIRE(not switcherUsingDummy.active()); + } + + SECTION("More Dummy Tests") {} +} diff --git a/tests/src/fsfw_tests/unit/testcfg/objects/systemObjectList.h b/tests/src/fsfw_tests/unit/testcfg/objects/systemObjectList.h index 29450309..6f40da3c 100644 --- a/tests/src/fsfw_tests/unit/testcfg/objects/systemObjectList.h +++ b/tests/src/fsfw_tests/unit/testcfg/objects/systemObjectList.h @@ -23,10 +23,12 @@ enum sourceObjects : uint32_t { SHARED_SET_ID = 26, - DEVICE_HANDLER_MOCK = 27, - COM_IF_MOCK = 28, - DEVICE_HANDLER_COMMANDER = 29, + DUMMY_POWER_SWITCHER = 28, + + DEVICE_HANDLER_MOCK = 29, + COM_IF_MOCK = 30, + DEVICE_HANDLER_COMMANDER = 40, }; } -#endif /* BSP_CONFIG_OBJECTS_SYSTEMOBJECTLIST_H_ */ +#endif /* BSP_CONFIG_OBJECTS_SYSTEMOBJECTLIST_H_ */ diff --git a/tests/src/fsfw_tests/unit/version.cpp b/tests/src/fsfw_tests/unit/version.cpp index 2967dfa5..662b1290 100644 --- a/tests/src/fsfw_tests/unit/version.cpp +++ b/tests/src/fsfw_tests/unit/version.cpp @@ -14,8 +14,8 @@ TEST_CASE("Version API Tests", "[TestVersionAPI]") { REQUIRE(fsfw::Version(255, 0, 0) >= fsfw::FSFW_VERSION); REQUIRE(fsfw::Version(0, 0, 0) < fsfw::FSFW_VERSION); REQUIRE(fsfw::Version(0, 0, 0) <= fsfw::FSFW_VERSION); - fsfw::Version v1 = fsfw::Version(1, 1, 1); - fsfw::Version v2 = fsfw::Version(1, 1, 1); + auto v1 = fsfw::Version(1, 1, 1); + auto v2 = fsfw::Version(1, 1, 1); REQUIRE(v1 == v2); REQUIRE(not(v1 < v2)); REQUIRE(not(v1 > v2));