diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000..ec53b72b --- /dev/null +++ b/.clang-format @@ -0,0 +1,7 @@ +--- +BasedOnStyle: Google +IndentWidth: 2 +--- +Language: Cpp +ColumnLimit: 100 +--- diff --git a/.gitignore b/.gitignore index fbd138e9..d6efb9cf 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ .project .settings .metadata + +/build* diff --git a/CHANGELOG b/CHANGELOG index add8e1a5..8f86c147 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,81 @@ -## Changes from ASTP 0.0.1 to 1.0.0 +# Changed from ASTP 1.1.0 to 1.2.0 + +## API Changes + +### FSFW Architecture + +- New src folder which contains all source files except the HAL, contributed code and test code +- External and internal API mostly stayed the same +- Folder names are now all smaller case: internalError was renamed to internalerror and + FreeRTOS was renamed to freertos +- Warning if optional headers are used but the modules was not added to the source files to compile + +### HAL + +- HAL added back into FSFW. It is tightly bound to the FSFW, and compiling it as a static library + made using it more complicated than necessary + +## Bugfixes + +### FreeRTOS QueueMapManager + +- Fixed a bug which causes the first generated Queue ID to be invalid + +## Enhancements + +### FSFW Architecture + +- See API changes chapter. This change will keep the internal API consistent in the future + +# Changes from ASTP 1.0.0 to 1.1.0 + +## API Changes + +### PUS + +- Added PUS C support +- SUBSYSTEM_IDs added for PUS Services +- Added new Parameter which must be defined in config: fsfwconfig::FSFW_MAX_TM_PACKET_SIZE + +### ObjectManager + + - ObjectManager is now a singelton + + +### Configuration + +- Additional configuration option fsfwconfig::FSFW_MAX_TM_PACKET_SIZE which + need to be specified in FSFWConfig.h + +### CMake + +- Changed Cmake FSFW_ADDITIONAL_INC_PATH to FSFW_ADDITIONAL_INC_PATHS + +## Bugfixes + +- timemanager/TimeStamperIF.h: Timestamp config was not used correctly, leading to different timestamp sizes than configured in fsfwconfig::FSFW_MISSION_TIMESTAMP_SIZE +- TCP server fixes + +## Enhancements + +### FreeRTOS Queue Handles + +- Fixed an internal issue how FreeRTOS MessageQueues were handled + +### Linux OSAL + +- Better printf error messages + +### CMake + +- Check for C++11 as mininimum required Version + +### Debug Output + +- Changed Warning color to magenta, which is well readable on both dark and light mode IDEs + + +# Changes from ASTP 0.0.1 to 1.0.0 ### Host OSAL diff --git a/CMakeLists.txt b/CMakeLists.txt index 8ba6a187..bb3d48b8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,124 +1,254 @@ cmake_minimum_required(VERSION 3.13) +set(FSFW_VERSION 2) +set(FSFW_SUBVERSION 0) +set(FSFW_REVISION 0) + +# Add the cmake folder so the FindSphinx module is found +set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) + 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) +endif() + option(FSFW_WARNING_SHADOW_LOCAL_GCC "Enable -Wshadow=local warning in GCC" ON) # Options to exclude parts of the FSFW from compilation. -option(FSFW_USE_RMAP "Compile with RMAP" ON) -option(FSFW_USE_DATALINKLAYER "Compile with Data Link Layer" ON) +option(FSFW_ADD_INTERNAL_TESTS "Add internal unit tests" ON) +option(FSFW_ADD_UNITTESTS "Add regular unittests. Requires Catch2" OFF) +option(FSFW_ADD_HAL "Add Hardware Abstraction Layer" ON) + +# Optional sources +option(FSFW_ADD_PUS "Compile with PUS sources" ON) +option(FSFW_ADD_MONITORING "Compile with monitoring components" ON) + +option(FSFW_ADD_RMAP "Compile with RMAP" OFF) +option(FSFW_ADD_DATALINKLAYER "Compile with Data Link Layer" OFF) +option(FSFW_ADD_COORDINATES "Compile with coordinate components" OFF) +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}) -set_property(CACHE OS_FSFW PROPERTY STRINGS host linux rtems freertos) +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 3) + # Not installed, so use FetchContent to download and provide Catch2 + if(NOT Catch2_FOUND) + include(FetchContent) -if(NOT OS_FSFW) - message(STATUS "No OS for FSFW via OS_FSFW set. Assuming host OS") + FetchContent_Declare( + Catch2 + GIT_REPOSITORY https://github.com/catchorg/Catch2.git + GIT_TAG v3.0.0-preview3 + ) + + FetchContent_MakeAvailable(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() +endif() + +set(FSFW_CORE_INC_PATH "inc") + +set_property(CACHE FSFW_OSAL PROPERTY STRINGS host linux rtems freertos) + +# 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() + +# 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) +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(OS_FSFW "linux" + set(FSFW_OSAL "linux" CACHE STRING "OS abstraction layer used in the FSFW" ) elseif(WIN32) - set(OS_FSFW "host" + set(FSFW_OSAL "host" CACHE STRING "OS abstraction layer used in the FSFW" ) endif() endif() -set(FSFW_OSAL_DEFINITION FSFW_HOST) +set(FSFW_OSAL_DEFINITION FSFW_OSAL_HOST) -if(${OS_FSFW} STREQUAL host) - set(OS_FSFW_NAME "Host") -elseif(${OS_FSFW} STREQUAL linux) - set(OS_FSFW_NAME "Linux") - set(FSFW_OSAL_DEFINITION FSFW_LINUX) -elseif(${OS_FSFW} STREQUAL freertos) - set(OS_FSFW_NAME "FreeRTOS") - set(FSFW_OSAL_DEFINITION FSFW_FREERTOS) - target_link_libraries(${LIB_FSFW_NAME} PRIVATE +if(FSFW_OSAL MATCHES host) + 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) +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} - ) -elseif(${OS_FSFW} STREQUAL rtems) - set(OS_FSFW_NAME "RTEMS") - set(FSFW_OSAL_DEFINITION FSFW_RTEMS) + ) +elseif(FSFW_OSAL STREQUAL rtems) + set(FSFW_OS_NAME "RTEMS") + set(FSFW_OSAL_RTEMS ON) else() - message(WARNING - "Invalid operating system for FSFW specified! Setting to host.." - ) - set(OS_FSFW_NAME "Host") - set(OS_FSFW "host") + message(WARNING + "Invalid operating system for FSFW specified! Setting to host.." + ) + set(FSFW_OS_NAME "Host") + set(OS_FSFW "host") endif() -target_compile_definitions(${LIB_FSFW_NAME} PRIVATE - ${FSFW_OSAL_DEFINITION} -) - -target_compile_definitions(${LIB_FSFW_NAME} INTERFACE - ${FSFW_OSAL_DEFINITION} -) - -message(STATUS "Compiling FSFW for the ${OS_FSFW_NAME} operating system.") - -add_subdirectory(action) -add_subdirectory(container) -add_subdirectory(controller) -add_subdirectory(coordinates) - -if(FSFW_USE_DATALINKLAYER) - add_subdirectory(datalinklayer) +if(FSFW_BUILD_UNITTESTS OR FSFW_BUILD_DOCS) + configure_file(src/fsfw/FSFW.h.in fsfw/FSFW.h) + configure_file(src/fsfw/FSFWVersion.h.in fsfw/FSFWVersion.h) +else() + configure_file(src/fsfw/FSFW.h.in FSFW.h) + configure_file(src/fsfw/FSFWVersion.h.in FSFWVersion.h) endif() -add_subdirectory(datapool) -add_subdirectory(datapoollocal) -add_subdirectory(housekeeping) -add_subdirectory(devicehandlers) -add_subdirectory(events) -add_subdirectory(fdir) -add_subdirectory(globalfunctions) -add_subdirectory(health) -add_subdirectory(internalError) -add_subdirectory(ipc) -add_subdirectory(memory) -add_subdirectory(modes) -add_subdirectory(monitoring) -add_subdirectory(objectmanager) -add_subdirectory(osal) -add_subdirectory(parameters) -add_subdirectory(power) -add_subdirectory(pus) +message(STATUS "Compiling FSFW for the ${FSFW_OS_NAME} operating system.") -if(FSFW_USE_RMAP) - add_subdirectory(rmap) +add_subdirectory(src) +add_subdirectory(tests) +if(FSFW_ADD_HAL) + add_subdirectory(hal) +endif() +add_subdirectory(contrib) +if(FSFW_BUILD_DOCS) + add_subdirectory(docs) endif() -add_subdirectory(serialize) -add_subdirectory(serviceinterface) -add_subdirectory(storagemanager) -add_subdirectory(subsystem) -add_subdirectory(tasks) -add_subdirectory(tcdistribution) -add_subdirectory(thermal) -add_subdirectory(timemanager) -add_subdirectory(tmstorage) -add_subdirectory(tmtcpacket) -add_subdirectory(tmtcservices) -add_subdirectory(unittest) +if(FSFW_BUILD_UNITTESTS) + if(FSFW_TESTS_GEN_COV) + if(CMAKE_COMPILER_IS_GNUCXX) + include(CodeCoverage) + + # 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}" + ) + + # Exclude directories here + if(WIN32) + set(GCOVR_ADDITIONAL_ARGS + "--exclude-throw-branches" + "--exclude-unreachable-branches" + ) + set(COVERAGE_EXCLUDES + "/c/msys64/mingw64/*" + ) + elseif(UNIX) + set(COVERAGE_EXCLUDES + "/usr/include/*" "/usr/bin/*" "Catch2/*" + "/usr/local/include/*" "*/fsfw_tests/*" + "*/catch2-src/*" + ) + 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 + ) + + 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() + 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. if(NOT FSFW_CONFIG_PATH) - message(WARNING "Flight Software Framework configuration path not set!") - message(WARNING "Setting default configuration!") - add_subdirectory(defaultcfg/fsfwconfig) + 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}) endif() # FSFW might be part of a possibly complicated folder structure, so we @@ -131,9 +261,9 @@ else() ) endif() -foreach(INCLUDE_PATH ${FSFW_ADDITIONAL_INC_PATH}) +foreach(INCLUDE_PATH ${FSFW_ADDITIONAL_INC_PATHS}) if(IS_ABSOLUTE ${INCLUDE_PATH}) - set(CURR_ABS_INC_PATH "${FREERTOS_PATH}") + set(CURR_ABS_INC_PATH "${INCLUDE_PATH}") else() get_filename_component(CURR_ABS_INC_PATH ${INCLUDE_PATH} REALPATH BASE_DIR ${CMAKE_SOURCE_DIR}) @@ -184,6 +314,7 @@ endif() target_include_directories(${LIB_FSFW_NAME} INTERFACE ${CMAKE_SOURCE_DIR} ${FSFW_CONFIG_PATH_ABSOLUTE} + ${FSFW_CORE_INC_PATH} ${FSFW_ADD_INC_PATHS_ABS} ) @@ -193,6 +324,7 @@ target_include_directories(${LIB_FSFW_NAME} INTERFACE target_include_directories(${LIB_FSFW_NAME} PRIVATE ${CMAKE_SOURCE_DIR} ${FSFW_CONFIG_PATH_ABSOLUTE} + ${FSFW_CORE_INC_PATH} ${FSFW_ADD_INC_PATHS_ABS} ) @@ -203,4 +335,17 @@ target_compile_options(${LIB_FSFW_NAME} PRIVATE target_link_libraries(${LIB_FSFW_NAME} PRIVATE ${FSFW_ADDITIONAL_LINK_LIBS} -) \ No newline at end of file +) + +string(CONCAT POST_BUILD_COMMENT + "######################################################################\n" + "Built FSFW v${FSFW_VERSION}.${FSFW_SUBVERSION}.${FSFW_REVISION}, " + "Target OSAL: ${FSFW_OS_NAME}\n" + "######################################################################\n" +) + +add_custom_command( + TARGET ${LIB_FSFW_NAME} + POST_BUILD + COMMENT ${POST_BUILD_COMMENT} +) diff --git a/FSFWVersion.h b/FSFWVersion.h deleted file mode 100644 index df2d49a5..00000000 --- a/FSFWVersion.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef FSFW_DEFAULTCFG_VERSION_H_ -#define FSFW_DEFAULTCFG_VERSION_H_ - -const char* const FSFW_VERSION_NAME = "ASTP"; - -#define FSFW_VERSION 1 -#define FSFW_SUBVERSION 0 -#define FSFW_REVISION 0 - - - -#endif /* FSFW_DEFAULTCFG_VERSION_H_ */ diff --git a/README.md b/README.md index fb3be429..73339ff6 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -![FSFW Logo](logo/FSFW_Logo_V3_bw.png) +![FSFW Logo](misc/logo/FSFW_Logo_V3_bw.png) # Flight Software Framework (FSFW) @@ -22,27 +22,107 @@ Currently, the FSFW provides the following OSALs: - FreeRTOS - RTEMS -The recommended hardware is a microprocessor with more than 1 MB of RAM and 1 MB of non-volatile Memory. For reference, current applications use a Cobham Gaisler UT699 (LEON3FT), a ISISPACE IOBC or a Zynq-7020 SoC. The `fsfw` was also successfully run on the STM32H743ZI-Nucleo board and on a Raspberry Pi and is currently running on the active satellite mission Flying Laptop. +The recommended hardware is a microprocessor with more than 1 MB of RAM and 1 MB of non-volatile +memory. For reference, current applications use a Cobham Gaisler UT699 (LEON3FT), a +ISISPACE IOBC or a Zynq-7020 SoC. The `fsfw` was also successfully run on the +STM32H743ZI-Nucleo board and on a Raspberry Pi and is currently running on the active +satellite mission Flying Laptop. ## Getting started -The [FSFW example](https://egit.irs.uni-stuttgart.de/fsfw/fsfw_example) provides a good starting point and a demo to see the FSFW capabilities and build it with the Make or the CMake build system. It is recommended to evaluate the FSFW by building and playing around with the demo application. +The [Hosted FSFW example](https://egit.irs.uni-stuttgart.de/fsfw/fsfw-example-hosted) provides a +good starting point and a demo to see the FSFW capabilities. +It is recommended to get started by building and playing around with the demo application. +There are also other examples provided for all OSALs using the popular embedded platforms +Raspberry Pi, Beagle Bone Black and STM32H7. -Generally, the FSFW is included in a project by compiling the FSFW sources and providing -a configuration folder and adding it to the include path. There are some functions like `printChar` which are different depending on the target architecture and need to be implemented by the mission developer. +Generally, the FSFW is included in a project by providing +a configuration folder, building the static library and linking against it. +There are some functions like `printChar` which are different depending on the target architecture +and need to be implemented by the mission developer. A template configuration folder was provided and can be copied into the project root to have -a starting point. The [configuration section](doc/README-config.md#top) provides more specific information about the possible options. +a starting point. The [configuration section](docs/README-config.md#top) provides more specific +information about the possible options. + +## Adding the library + +The following steps show how to add and use FSFW components. It is still recommended to +try out the example mentioned above to get started, but the following steps show how to +add and link against the FSFW library in general. + +1. Add this repository as a submodule + + ```sh + git submodule add https://egit.irs.uni-stuttgart.de/fsfw/fsfw.git fsfw + ``` + +2. Add the following directive inside the uppermost `CMakeLists.txt` file of your project + + ```cmake + add_subdirectory(fsfw) + ``` + +3. Make sure to provide a configuration folder and supply the path to that folder with + the `FSFW_CONFIG_PATH` CMake variable from the uppermost `CMakeLists.txt` file. + It is also necessary to provide the `printChar` function. You can find an example + implementation for a hosted build + [here](https://egit.irs.uni-stuttgart.de/fsfw/fsfw-example-hosted/src/branch/master/bsp_hosted/utility/printChar.c). + +4. Link against the FSFW library + + ```cmake + target_link_libraries( PRIVATE fsfw) + ``` + +5. It should now be possible use the FSFW as a static library from the user code. + +## Building the unittests + +The FSFW also has unittests which use the [Catch2 library](https://github.com/catchorg/Catch2). +These are built by setting the CMake option `FSFW_BUILD_UNITTESTS` to `ON` or `TRUE` +from your project `CMakeLists.txt` file or from the command line. + +The fsfw-tests binary will be built as part of the static library and dropped alongside it. +If the unittests are built, the library and the tests will be built with coverage information by +default. This can be disabled by setting the `FSFW_TESTS_COV_GEN` option to `OFF` or `FALSE`. + +You can use the following commands inside the `fsfw` folder to set up the build system + +```sh +mkdir build-Unittest && cd build-Unittest +cmake -DFSFW_BUILD_UNITTESTS=ON -DFSFW_OSAL=host .. +``` + +You can also use `-DFSFW_OSAL=linux` on Linux systems. + +Coverage data in HTML format can be generated using the `CodeCoverage` +[CMake module](https://github.com/bilke/cmake-modules/tree/master). +To build the unittests, run them and then generare the coverage data in this format, +the following command can be used inside the build directory after the build system was set up + +```sh +cmake --build . -- fsfw-tests_coverage -j +``` + +The `coverage.py` script located in the `script` folder can also be used to do this conveniently. + +## Formatting the sources + +The formatting is done by the `clang-format` tool. The configuration is contained within the +`.clang-format` file in the repository root. As long as `clang-format` is installed, you +can run the `apply-clang-format.sh` helper script to format all source files consistently. ## Index -[1. High-level overview](doc/README-highlevel.md#top)
-[2. Core components](doc/README-core.md#top)
-[3. OSAL overview](doc/README-osal.md#top)
-[4. PUS services](doc/README-pus.md#top)
-[5. Device Handler overview](doc/README-devicehandlers.md#top)
-[6. Controller overview](doc/README-controllers.md#top)
-[7. Local Data Pools](doc/README-localpools.md#top)
+[1. High-level overview](docs/README-highlevel.md#top)
+[2. Core components](docs/README-core.md#top)
+[3. Configuration](docs/README-config.md#top)
+[4. OSAL overview](docs/README-osal.md#top)
+[5. PUS services](docs/README-pus.md#top)
+[6. Device Handler overview](docs/README-devicehandlers.md#top)
+[7. Controller overview](docs/README-controllers.md#top)
+[8. Local Data Pools](docs/README-localpools.md#top)
diff --git a/automation/Dockerfile b/automation/Dockerfile new file mode 100644 index 00000000..93a4fe7d --- /dev/null +++ b/automation/Dockerfile @@ -0,0 +1,8 @@ +FROM ubuntu:focal + +RUN apt-get update +RUN apt-get --yes upgrade + +#tzdata is a dependency, won't install otherwise +ARG DEBIAN_FRONTEND=noninteractive +RUN apt-get --yes install gcc g++ cmake make lcov git valgrind nano diff --git a/automation/Jenkinsfile b/automation/Jenkinsfile new file mode 100644 index 00000000..d4a8e2ab --- /dev/null +++ b/automation/Jenkinsfile @@ -0,0 +1,72 @@ +pipeline { + agent any + environment { + BUILDDIR = 'build-unittests' + } + stages { + stage('Create Docker') { + agent { + dockerfile { + dir 'automation' + additionalBuildArgs '--no-cache' + reuseNode true + } + } + steps { + sh 'rm -rf $BUILDDIR' + } + } + stage('Configure') { + agent { + dockerfile { + dir 'automation' + reuseNode true + } + } + steps { + dir(BUILDDIR) { + sh 'cmake -DFSFW_OSAL=host -DFSFW_BUILD_UNITTESTS=ON ..' + } + } + } + stage('Build') { + agent { + dockerfile { + dir 'automation' + reuseNode true + } + } + steps { + dir(BUILDDIR) { + sh 'cmake --build . -j' + } + } + } + stage('Unittests') { + agent { + dockerfile { + dir 'automation' + reuseNode true + } + } + steps { + dir(BUILDDIR) { + sh 'cmake --build . -- fsfw-tests_coverage -j' + } + } + } + stage('Valgrind') { + agent { + dockerfile { + dir 'automation' + reuseNode true + } + } + steps { + dir(BUILDDIR) { + sh 'valgrind --leak-check=full --error-exitcode=1 ./fsfw-tests' + } + } + } + } +} diff --git a/cmake/FindSphinx.cmake b/cmake/FindSphinx.cmake new file mode 100644 index 00000000..4a5b0700 --- /dev/null +++ b/cmake/FindSphinx.cmake @@ -0,0 +1,13 @@ +# Look for an executable called sphinx-build +find_program(SPHINX_EXECUTABLE + NAMES sphinx-build + DOC "Path to sphinx-build executable") + +include(FindPackageHandleStandardArgs) + +# Handle standard arguments to find_package like REQUIRED and QUIET +find_package_handle_standard_args( + Sphinx + "Failed to find sphinx-build executable" + SPHINX_EXECUTABLE +) \ No newline at end of file diff --git a/contrib/CMakeLists.txt b/contrib/CMakeLists.txt new file mode 100644 index 00000000..e83da6af --- /dev/null +++ b/contrib/CMakeLists.txt @@ -0,0 +1,9 @@ +target_include_directories(${LIB_FSFW_NAME} PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} +) + +target_include_directories(${LIB_FSFW_NAME} INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR} +) + +add_subdirectory(fsfw_contrib) diff --git a/contrib/fsfw_contrib/CMakeLists.txt b/contrib/fsfw_contrib/CMakeLists.txt new file mode 100644 index 00000000..3a7e4182 --- /dev/null +++ b/contrib/fsfw_contrib/CMakeLists.txt @@ -0,0 +1,11 @@ +if(FSFW_ADD_SGP4_PROPAGATOR) + target_sources(${LIB_FSFW_NAME} PRIVATE + sgp4/sgp4unit.cpp + ) + target_include_directories(${LIB_FSFW_NAME} PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/sgp4 + ) + target_include_directories(${LIB_FSFW_NAME} INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR}/sgp4 + ) +endif() diff --git a/contrib/sgp4/LICENSE b/contrib/fsfw_contrib/sgp4/LICENSE similarity index 100% rename from contrib/sgp4/LICENSE rename to contrib/fsfw_contrib/sgp4/LICENSE diff --git a/contrib/sgp4/sgp4unit.cpp b/contrib/fsfw_contrib/sgp4/sgp4unit.cpp similarity index 100% rename from contrib/sgp4/sgp4unit.cpp rename to contrib/fsfw_contrib/sgp4/sgp4unit.cpp diff --git a/contrib/sgp4/sgp4unit.h b/contrib/fsfw_contrib/sgp4/sgp4unit.h similarity index 100% rename from contrib/sgp4/sgp4unit.h rename to contrib/fsfw_contrib/sgp4/sgp4unit.h diff --git a/datapoollocal/LocalDataPoolManager.cpp b/datapoollocal/LocalDataPoolManager.cpp deleted file mode 100644 index dbe68ff1..00000000 --- a/datapoollocal/LocalDataPoolManager.cpp +++ /dev/null @@ -1,942 +0,0 @@ -#include "HasLocalDataPoolIF.h" -#include "LocalDataPoolManager.h" -#include "LocalPoolObjectBase.h" -#include "LocalPoolDataSetBase.h" -#include "internal/LocalPoolDataSetAttorney.h" -#include "internal/HasLocalDpIFManagerAttorney.h" - -#include "../housekeeping/HousekeepingSetPacket.h" -#include "../housekeeping/HousekeepingSnapshot.h" -#include "../housekeeping/AcceptsHkPacketsIF.h" -#include "../timemanager/CCSDSTime.h" -#include "../ipc/MutexFactory.h" -#include "../ipc/MutexGuard.h" -#include "../ipc/QueueFactory.h" - -#include -#include - -object_id_t LocalDataPoolManager::defaultHkDestination = objects::PUS_SERVICE_3_HOUSEKEEPING; - -LocalDataPoolManager::LocalDataPoolManager(HasLocalDataPoolIF* owner, MessageQueueIF* queueToUse, - bool appendValidityBuffer): - appendValidityBuffer(appendValidityBuffer) { - if(owner == nullptr) { - printWarningOrError(sif::OutputTypes::OUT_WARNING, - "LocalDataPoolManager", HasReturnvaluesIF::RETURN_FAILED, - "Invalid supplied owner"); - return; - } - this->owner = owner; - mutex = MutexFactory::instance()->createMutex(); - if(mutex == nullptr) { - printWarningOrError(sif::OutputTypes::OUT_ERROR, - "LocalDataPoolManager", HasReturnvaluesIF::RETURN_FAILED, - "Could not create mutex"); - } - - hkQueue = queueToUse; -} - -LocalDataPoolManager::~LocalDataPoolManager() { - if(mutex != nullptr) { - MutexFactory::instance()->deleteMutex(mutex); - } -} - -ReturnValue_t LocalDataPoolManager::initialize(MessageQueueIF* queueToUse) { - if(queueToUse == nullptr) { - /* Error, all destinations invalid */ - printWarningOrError(sif::OutputTypes::OUT_ERROR, "initialize", - QUEUE_OR_DESTINATION_INVALID); - } - hkQueue = queueToUse; - - ipcStore = objectManager->get(objects::IPC_STORE); - if(ipcStore == nullptr) { - /* Error, all destinations invalid */ - printWarningOrError(sif::OutputTypes::OUT_ERROR, - "initialize", HasReturnvaluesIF::RETURN_FAILED, - "Could not set IPC store."); - return HasReturnvaluesIF::RETURN_FAILED; - } - - - if(defaultHkDestination != objects::NO_OBJECT) { - AcceptsHkPacketsIF* hkPacketReceiver = - objectManager->get(defaultHkDestination); - if(hkPacketReceiver != nullptr) { - hkDestinationId = hkPacketReceiver->getHkQueue(); - } - else { - printWarningOrError(sif::OutputTypes::OUT_ERROR, - "initialize", QUEUE_OR_DESTINATION_INVALID); - return QUEUE_OR_DESTINATION_INVALID; - } - } - - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t LocalDataPoolManager::initializeAfterTaskCreation( - uint8_t nonDiagInvlFactor) { - setNonDiagnosticIntervalFactor(nonDiagInvlFactor); - return initializeHousekeepingPoolEntriesOnce(); -} - -ReturnValue_t LocalDataPoolManager::initializeHousekeepingPoolEntriesOnce() { - if(not mapInitialized) { - ReturnValue_t result = owner->initializeLocalDataPool(localPoolMap, - *this); - if(result == HasReturnvaluesIF::RETURN_OK) { - mapInitialized = true; - } - return result; - } - - printWarningOrError(sif::OutputTypes::OUT_WARNING, - "initialize", HasReturnvaluesIF::RETURN_FAILED, - "The map should only be initialized once"); - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t LocalDataPoolManager::performHkOperation() { - ReturnValue_t status = HasReturnvaluesIF::RETURN_OK; - for(auto& receiver: hkReceivers) { - switch(receiver.reportingType) { - case(ReportingType::PERIODIC): { - if(receiver.dataType == DataType::LOCAL_POOL_VARIABLE) { - /* Periodic packets shall only be generated from datasets */ - continue; - } - performPeriodicHkGeneration(receiver); - break; - } - case(ReportingType::UPDATE_HK): { - handleHkUpdate(receiver, status); - break; - } - case(ReportingType::UPDATE_NOTIFICATION): { - handleNotificationUpdate(receiver, status); - break; - } - case(ReportingType::UPDATE_SNAPSHOT): { - handleNotificationSnapshot(receiver, status); - break; - } - default: - // This should never happen. - return HasReturnvaluesIF::RETURN_FAILED; - } - } - resetHkUpdateResetHelper(); - return status; -} - -ReturnValue_t LocalDataPoolManager::handleHkUpdate(HkReceiver& receiver, - ReturnValue_t& status) { - if(receiver.dataType == DataType::LOCAL_POOL_VARIABLE) { - /* Update packets shall only be generated from datasets. */ - return HasReturnvaluesIF::RETURN_FAILED; - } - LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, - receiver.dataId.sid); - if(dataSet == nullptr) { - return DATASET_NOT_FOUND; - } - if(dataSet->hasChanged()) { - /* Prepare and send update notification */ - ReturnValue_t result = generateHousekeepingPacket( - receiver.dataId.sid, dataSet, true); - if(result != HasReturnvaluesIF::RETURN_OK) { - status = result; - } - } - handleChangeResetLogic(receiver.dataType, receiver.dataId, - dataSet); - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t LocalDataPoolManager::handleNotificationUpdate(HkReceiver& receiver, - ReturnValue_t& status) { - MarkChangedIF* toReset = nullptr; - if(receiver.dataType == DataType::LOCAL_POOL_VARIABLE) { - LocalPoolObjectBase* poolObj = HasLocalDpIFManagerAttorney::getPoolObjectHandle(owner, - receiver.dataId.localPoolId); - if(poolObj == nullptr) { - printWarningOrError(sif::OutputTypes::OUT_WARNING, - "handleNotificationUpdate", POOLOBJECT_NOT_FOUND); - return POOLOBJECT_NOT_FOUND; - } - if(poolObj->hasChanged()) { - /* Prepare and send update notification. */ - CommandMessage notification; - HousekeepingMessage::setUpdateNotificationVariableCommand(¬ification, - gp_id_t(owner->getObjectId(), receiver.dataId.localPoolId)); - ReturnValue_t result = hkQueue->sendMessage(receiver.destinationQueue, ¬ification); - if(result != HasReturnvaluesIF::RETURN_OK) { - status = result; - } - toReset = poolObj; - } - - } - else { - LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, - receiver.dataId.sid); - if(dataSet == nullptr) { - printWarningOrError(sif::OutputTypes::OUT_WARNING, - "handleNotificationUpdate", DATASET_NOT_FOUND); - return DATASET_NOT_FOUND; - } - if(dataSet->hasChanged()) { - /* Prepare and send update notification */ - CommandMessage notification; - HousekeepingMessage::setUpdateNotificationSetCommand(¬ification, - receiver.dataId.sid); - ReturnValue_t result = hkQueue->sendMessage( - receiver.destinationQueue, ¬ification); - if(result != HasReturnvaluesIF::RETURN_OK) { - status = result; - } - toReset = dataSet; - } - } - if(toReset != nullptr) { - handleChangeResetLogic(receiver.dataType, receiver.dataId, toReset); - } - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t LocalDataPoolManager::handleNotificationSnapshot( - HkReceiver& receiver, ReturnValue_t& status) { - MarkChangedIF* toReset = nullptr; - /* Check whether data has changed and send messages in case it has */ - if(receiver.dataType == DataType::LOCAL_POOL_VARIABLE) { - LocalPoolObjectBase* poolObj = HasLocalDpIFManagerAttorney::getPoolObjectHandle(owner, - receiver.dataId.localPoolId); - if(poolObj == nullptr) { - printWarningOrError(sif::OutputTypes::OUT_WARNING, - "handleNotificationSnapshot", POOLOBJECT_NOT_FOUND); - return POOLOBJECT_NOT_FOUND; - } - - if (not poolObj->hasChanged()) { - return HasReturnvaluesIF::RETURN_OK; - } - - /* Prepare and send update snapshot */ - timeval now; - Clock::getClock_timeval(&now); - CCSDSTime::CDS_short cds; - CCSDSTime::convertToCcsds(&cds, &now); - HousekeepingSnapshot updatePacket(reinterpret_cast(&cds), sizeof(cds), - HasLocalDpIFManagerAttorney::getPoolObjectHandle( - owner,receiver.dataId.localPoolId)); - - store_address_t storeId; - ReturnValue_t result = addUpdateToStore(updatePacket, storeId); - if(result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - CommandMessage notification; - HousekeepingMessage::setUpdateSnapshotVariableCommand(¬ification, - gp_id_t(owner->getObjectId(), receiver.dataId.localPoolId), storeId); - result = hkQueue->sendMessage(receiver.destinationQueue, - ¬ification); - if (result != HasReturnvaluesIF::RETURN_OK) { - status = result; - } - toReset = poolObj; - } - else { - LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, - receiver.dataId.sid); - if(dataSet == nullptr) { - printWarningOrError(sif::OutputTypes::OUT_WARNING, - "handleNotificationSnapshot", DATASET_NOT_FOUND); - return DATASET_NOT_FOUND; - } - - if(not dataSet->hasChanged()) { - return HasReturnvaluesIF::RETURN_OK; - } - - /* Prepare and send update snapshot */ - timeval now; - Clock::getClock_timeval(&now); - CCSDSTime::CDS_short cds; - CCSDSTime::convertToCcsds(&cds, &now); - HousekeepingSnapshot updatePacket(reinterpret_cast(&cds), - sizeof(cds), HasLocalDpIFManagerAttorney::getDataSetHandle(owner, - receiver.dataId.sid)); - - store_address_t storeId; - ReturnValue_t result = addUpdateToStore(updatePacket, storeId); - if(result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - CommandMessage notification; - HousekeepingMessage::setUpdateSnapshotSetCommand( - ¬ification, receiver.dataId.sid, storeId); - result = hkQueue->sendMessage(receiver.destinationQueue, ¬ification); - if(result != HasReturnvaluesIF::RETURN_OK) { - status = result; - } - toReset = dataSet; - - } - if(toReset != nullptr) { - handleChangeResetLogic(receiver.dataType, - receiver.dataId, toReset); - } - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t LocalDataPoolManager::addUpdateToStore( - HousekeepingSnapshot& updatePacket, store_address_t& storeId) { - size_t updatePacketSize = updatePacket.getSerializedSize(); - uint8_t *storePtr = nullptr; - ReturnValue_t result = ipcStore->getFreeElement(&storeId, - updatePacket.getSerializedSize(), &storePtr); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - size_t serializedSize = 0; - result = updatePacket.serialize(&storePtr, &serializedSize, - updatePacketSize, SerializeIF::Endianness::MACHINE); - return result;; -} - -void LocalDataPoolManager::handleChangeResetLogic( - DataType type, DataId dataId, MarkChangedIF* toReset) { - if(hkUpdateResetList == nullptr) { - /* Config error */ - return; - } - HkUpdateResetList& listRef = *hkUpdateResetList; - for(auto& changeInfo: listRef) { - if(changeInfo.dataType != type) { - continue; - } - if((changeInfo.dataType == DataType::DATA_SET) and - (changeInfo.dataId.sid != dataId.sid)) { - continue; - } - if((changeInfo.dataType == DataType::LOCAL_POOL_VARIABLE) and - (changeInfo.dataId.localPoolId != dataId.localPoolId)) { - continue; - } - - /* Only one update recipient, we can reset changes status immediately */ - if(changeInfo.updateCounter <= 1) { - toReset->setChanged(false); - } - /* All recipients have been notified, reset the changed flag */ - else if(changeInfo.currentUpdateCounter <= 1) { - toReset->setChanged(false); - changeInfo.currentUpdateCounter = 0; - } - /* Not all recipiens have been notified yet, decrement */ - else { - changeInfo.currentUpdateCounter--; - } - return; - } -} - -void LocalDataPoolManager::resetHkUpdateResetHelper() { - if(hkUpdateResetList == nullptr) { - return; - } - - for(auto& changeInfo: *hkUpdateResetList) { - changeInfo.currentUpdateCounter = changeInfo.updateCounter; - } -} - -ReturnValue_t LocalDataPoolManager::subscribeForPeriodicPacket(sid_t sid, - bool enableReporting, float collectionInterval, bool isDiagnostics, - object_id_t packetDestination) { - AcceptsHkPacketsIF* hkReceiverObject = - objectManager->get(packetDestination); - if(hkReceiverObject == nullptr) { - printWarningOrError(sif::OutputTypes::OUT_WARNING, - "subscribeForPeriodicPacket", QUEUE_OR_DESTINATION_INVALID); - return QUEUE_OR_DESTINATION_INVALID; - } - - struct HkReceiver hkReceiver; - hkReceiver.dataId.sid = sid; - hkReceiver.reportingType = ReportingType::PERIODIC; - hkReceiver.dataType = DataType::DATA_SET; - hkReceiver.destinationQueue = hkReceiverObject->getHkQueue(); - - LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid); - if(dataSet != nullptr) { - LocalPoolDataSetAttorney::setReportingEnabled(*dataSet, enableReporting); - LocalPoolDataSetAttorney::setDiagnostic(*dataSet, isDiagnostics); - LocalPoolDataSetAttorney::initializePeriodicHelper(*dataSet, collectionInterval, - owner->getPeriodicOperationFrequency()); - } - - hkReceivers.push_back(hkReceiver); - return HasReturnvaluesIF::RETURN_OK; -} - - -ReturnValue_t LocalDataPoolManager::subscribeForUpdatePacket(sid_t sid, - bool isDiagnostics, bool reportingEnabled, - object_id_t packetDestination) { - AcceptsHkPacketsIF* hkReceiverObject = - objectManager->get(packetDestination); - if(hkReceiverObject == nullptr) { - printWarningOrError(sif::OutputTypes::OUT_WARNING, - "subscribeForPeriodicPacket", QUEUE_OR_DESTINATION_INVALID); - return QUEUE_OR_DESTINATION_INVALID; - } - - struct HkReceiver hkReceiver; - hkReceiver.dataId.sid = sid; - hkReceiver.reportingType = ReportingType::UPDATE_HK; - hkReceiver.dataType = DataType::DATA_SET; - hkReceiver.destinationQueue = hkReceiverObject->getHkQueue(); - - LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid); - if(dataSet != nullptr) { - LocalPoolDataSetAttorney::setReportingEnabled(*dataSet, true); - LocalPoolDataSetAttorney::setDiagnostic(*dataSet, isDiagnostics); - } - - hkReceivers.push_back(hkReceiver); - - handleHkUpdateResetListInsertion(hkReceiver.dataType, hkReceiver.dataId); - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t LocalDataPoolManager::subscribeForSetUpdateMessage( - const uint32_t setId, object_id_t destinationObject, - MessageQueueId_t targetQueueId, bool generateSnapshot) { - struct HkReceiver hkReceiver; - hkReceiver.dataType = DataType::DATA_SET; - hkReceiver.dataId.sid = sid_t(owner->getObjectId(), setId); - hkReceiver.destinationQueue = targetQueueId; - hkReceiver.objectId = destinationObject; - if(generateSnapshot) { - hkReceiver.reportingType = ReportingType::UPDATE_SNAPSHOT; - } - else { - hkReceiver.reportingType = ReportingType::UPDATE_NOTIFICATION; - } - - hkReceivers.push_back(hkReceiver); - - handleHkUpdateResetListInsertion(hkReceiver.dataType, hkReceiver.dataId); - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t LocalDataPoolManager::subscribeForVariableUpdateMessage( - const lp_id_t localPoolId, object_id_t destinationObject, - MessageQueueId_t targetQueueId, bool generateSnapshot) { - struct HkReceiver hkReceiver; - hkReceiver.dataType = DataType::LOCAL_POOL_VARIABLE; - hkReceiver.dataId.localPoolId = localPoolId; - hkReceiver.destinationQueue = targetQueueId; - hkReceiver.objectId = destinationObject; - if(generateSnapshot) { - hkReceiver.reportingType = ReportingType::UPDATE_SNAPSHOT; - } - else { - hkReceiver.reportingType = ReportingType::UPDATE_NOTIFICATION; - } - - hkReceivers.push_back(hkReceiver); - - handleHkUpdateResetListInsertion(hkReceiver.dataType, hkReceiver.dataId); - return HasReturnvaluesIF::RETURN_OK; -} - -void LocalDataPoolManager::handleHkUpdateResetListInsertion(DataType dataType, - DataId dataId) { - if(hkUpdateResetList == nullptr) { - hkUpdateResetList = new std::vector(); - } - - for(auto& updateResetStruct: *hkUpdateResetList) { - if(dataType == DataType::DATA_SET) { - if(updateResetStruct.dataId.sid == dataId.sid) { - updateResetStruct.updateCounter++; - updateResetStruct.currentUpdateCounter++; - return; - } - } - else { - if(updateResetStruct.dataId.localPoolId == dataId.localPoolId) { - updateResetStruct.updateCounter++; - updateResetStruct.currentUpdateCounter++; - return; - } - } - - } - HkUpdateResetHelper hkUpdateResetHelper; - hkUpdateResetHelper.currentUpdateCounter = 1; - hkUpdateResetHelper.updateCounter = 1; - hkUpdateResetHelper.dataType = dataType; - if(dataType == DataType::DATA_SET) { - hkUpdateResetHelper.dataId.sid = dataId.sid; - } - else { - hkUpdateResetHelper.dataId.localPoolId = dataId.localPoolId; - } - hkUpdateResetList->push_back(hkUpdateResetHelper); -} - -ReturnValue_t LocalDataPoolManager::handleHousekeepingMessage( - CommandMessage* message) { - Command_t command = message->getCommand(); - sid_t sid = HousekeepingMessage::getSid(message); - ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; - switch(command) { - // Houskeeping interface handling. - case(HousekeepingMessage::ENABLE_PERIODIC_DIAGNOSTICS_GENERATION): { - result = togglePeriodicGeneration(sid, true, true); - break; - } - - case(HousekeepingMessage::DISABLE_PERIODIC_DIAGNOSTICS_GENERATION): { - result = togglePeriodicGeneration(sid, false, true); - break; - } - - case(HousekeepingMessage::ENABLE_PERIODIC_HK_REPORT_GENERATION): { - result = togglePeriodicGeneration(sid, true, false); - break; - } - - case(HousekeepingMessage::DISABLE_PERIODIC_HK_REPORT_GENERATION): { - result = togglePeriodicGeneration(sid, false, false); - break; - } - - case(HousekeepingMessage::REPORT_DIAGNOSTICS_REPORT_STRUCTURES): { - result = generateSetStructurePacket(sid, true); - if(result == HasReturnvaluesIF::RETURN_OK) { - return result; - } - break; - } - - case(HousekeepingMessage::REPORT_HK_REPORT_STRUCTURES): { - result = generateSetStructurePacket(sid, false); - if(result == HasReturnvaluesIF::RETURN_OK) { - return result; - } - break; - } - case(HousekeepingMessage::MODIFY_DIAGNOSTICS_REPORT_COLLECTION_INTERVAL): - case(HousekeepingMessage::MODIFY_PARAMETER_REPORT_COLLECTION_INTERVAL): { - float newCollIntvl = 0; - HousekeepingMessage::getCollectionIntervalModificationCommand(message, - &newCollIntvl); - if(command == HousekeepingMessage:: - MODIFY_DIAGNOSTICS_REPORT_COLLECTION_INTERVAL) { - result = changeCollectionInterval(sid, newCollIntvl, true); - } - else { - result = changeCollectionInterval(sid, newCollIntvl, false); - } - break; - } - - case(HousekeepingMessage::GENERATE_ONE_PARAMETER_REPORT): - case(HousekeepingMessage::GENERATE_ONE_DIAGNOSTICS_REPORT): { - LocalPoolDataSetBase* dataSet =HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid); - if(command == HousekeepingMessage::GENERATE_ONE_PARAMETER_REPORT - and LocalPoolDataSetAttorney::isDiagnostics(*dataSet)) { - result = WRONG_HK_PACKET_TYPE; - break; - } - else if(command == HousekeepingMessage::GENERATE_ONE_DIAGNOSTICS_REPORT - and not LocalPoolDataSetAttorney::isDiagnostics(*dataSet)) { - result = WRONG_HK_PACKET_TYPE; - break; - } - return generateHousekeepingPacket(HousekeepingMessage::getSid(message), - dataSet, true); - } - - /* Notification handling */ - case(HousekeepingMessage::UPDATE_NOTIFICATION_SET): { - owner->handleChangedDataset(sid); - return HasReturnvaluesIF::RETURN_OK; - } - case(HousekeepingMessage::UPDATE_NOTIFICATION_VARIABLE): { - gp_id_t globPoolId = HousekeepingMessage::getUpdateNotificationVariableCommand(message); - owner->handleChangedPoolVariable(globPoolId); - return HasReturnvaluesIF::RETURN_OK; - } - case(HousekeepingMessage::UPDATE_SNAPSHOT_SET): { - store_address_t storeId; - HousekeepingMessage::getUpdateSnapshotSetCommand(message, &storeId); - bool clearMessage = true; - owner->handleChangedDataset(sid, storeId, &clearMessage); - if(clearMessage) { - message->clear(); - } - return HasReturnvaluesIF::RETURN_OK; - } - case(HousekeepingMessage::UPDATE_SNAPSHOT_VARIABLE): { - store_address_t storeId; - gp_id_t globPoolId = HousekeepingMessage::getUpdateSnapshotVariableCommand(message, - &storeId); - bool clearMessage = true; - owner->handleChangedPoolVariable(globPoolId, storeId, &clearMessage); - if(clearMessage) { - message->clear(); - } - return HasReturnvaluesIF::RETURN_OK; - } - - default: - return CommandMessageIF::UNKNOWN_COMMAND; - } - - CommandMessage reply; - if(result != HasReturnvaluesIF::RETURN_OK) { - HousekeepingMessage::setHkRequestFailureReply(&reply, sid, result); - } - else { - HousekeepingMessage::setHkRequestSuccessReply(&reply, sid); - } - hkQueue->sendMessage(hkDestinationId, &reply); - return result; -} - -ReturnValue_t LocalDataPoolManager::printPoolEntry( - lp_id_t localPoolId) { - auto poolIter = localPoolMap.find(localPoolId); - if (poolIter == localPoolMap.end()) { - printWarningOrError(sif::OutputTypes::OUT_WARNING, "printPoolEntry", - localpool::POOL_ENTRY_NOT_FOUND); - return localpool::POOL_ENTRY_NOT_FOUND; - } - poolIter->second->print(); - return HasReturnvaluesIF::RETURN_OK; -} - -MutexIF* LocalDataPoolManager::getMutexHandle() { - return mutex; -} - -HasLocalDataPoolIF* LocalDataPoolManager::getOwner() { - return owner; -} - -ReturnValue_t LocalDataPoolManager::generateHousekeepingPacket(sid_t sid, - LocalPoolDataSetBase* dataSet, bool forDownlink, - MessageQueueId_t destination) { - if(dataSet == nullptr) { - /* Configuration error. */ - printWarningOrError(sif::OutputTypes::OUT_WARNING, - "generateHousekeepingPacket", - DATASET_NOT_FOUND); - return DATASET_NOT_FOUND; - } - - store_address_t storeId; - HousekeepingPacketDownlink hkPacket(sid, dataSet); - size_t serializedSize = 0; - ReturnValue_t result = serializeHkPacketIntoStore(hkPacket, storeId, - forDownlink, &serializedSize); - if(result != HasReturnvaluesIF::RETURN_OK or serializedSize == 0) { - return result; - } - - /* Now we set a HK message and send it the HK packet destination. */ - CommandMessage hkMessage; - if(LocalPoolDataSetAttorney::isDiagnostics(*dataSet)) { - HousekeepingMessage::setHkDiagnosticsReply(&hkMessage, sid, storeId); - } - else { - HousekeepingMessage::setHkReportReply(&hkMessage, sid, storeId); - } - - if(hkQueue == nullptr) { - /* Error, no queue available to send packet with. */ - printWarningOrError(sif::OutputTypes::OUT_WARNING, - "generateHousekeepingPacket", - QUEUE_OR_DESTINATION_INVALID); - return QUEUE_OR_DESTINATION_INVALID; - } - if(destination == MessageQueueIF::NO_QUEUE) { - if(hkDestinationId == MessageQueueIF::NO_QUEUE) { - /* Error, all destinations invalid */ - printWarningOrError(sif::OutputTypes::OUT_WARNING, - "generateHousekeepingPacket", - QUEUE_OR_DESTINATION_INVALID); - } - destination = hkDestinationId; - } - - return hkQueue->sendMessage(destination, &hkMessage); -} - -ReturnValue_t LocalDataPoolManager::serializeHkPacketIntoStore( - HousekeepingPacketDownlink& hkPacket, - store_address_t& storeId, bool forDownlink, - size_t* serializedSize) { - uint8_t* dataPtr = nullptr; - const size_t maxSize = hkPacket.getSerializedSize(); - ReturnValue_t result = ipcStore->getFreeElement(&storeId, - maxSize, &dataPtr); - if(result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - if(forDownlink) { - return hkPacket.serialize(&dataPtr, serializedSize, maxSize, - SerializeIF::Endianness::BIG); - } - return hkPacket.serialize(&dataPtr, serializedSize, maxSize, - SerializeIF::Endianness::MACHINE); -} - -void LocalDataPoolManager::setNonDiagnosticIntervalFactor( - uint8_t nonDiagInvlFactor) { - this->nonDiagnosticIntervalFactor = nonDiagInvlFactor; -} - -void LocalDataPoolManager::performPeriodicHkGeneration(HkReceiver& receiver) { - sid_t sid = receiver.dataId.sid; - LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid); - if(dataSet == nullptr) { - printWarningOrError(sif::OutputTypes::OUT_WARNING, - "performPeriodicHkGeneration", - DATASET_NOT_FOUND); - return; - } - - if(not LocalPoolDataSetAttorney::getReportingEnabled(*dataSet)) { - return; - } - - PeriodicHousekeepingHelper* periodicHelper = - LocalPoolDataSetAttorney::getPeriodicHelper(*dataSet); - - if(periodicHelper == nullptr) { - /* Configuration error */ - return; - } - - if(not periodicHelper->checkOpNecessary()) { - return; - } - - ReturnValue_t result = generateHousekeepingPacket( - sid, dataSet, true); - if(result != HasReturnvaluesIF::RETURN_OK) { - /* Configuration error */ -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "LocalDataPoolManager::performHkOperation: HK generation failed." << - std::endl; -#else - sif::printWarning("LocalDataPoolManager::performHkOperation: HK generation failed.\n"); -#endif - } -} - - -ReturnValue_t LocalDataPoolManager::togglePeriodicGeneration(sid_t sid, - bool enable, bool isDiagnostics) { - LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid); - if(dataSet == nullptr) { - printWarningOrError(sif::OutputTypes::OUT_WARNING, "togglePeriodicGeneration", - DATASET_NOT_FOUND); - return DATASET_NOT_FOUND; - } - - if((LocalPoolDataSetAttorney::isDiagnostics(*dataSet) and not isDiagnostics) or - (not LocalPoolDataSetAttorney::isDiagnostics(*dataSet) and isDiagnostics)) { - return WRONG_HK_PACKET_TYPE; - } - - if((LocalPoolDataSetAttorney::getReportingEnabled(*dataSet) and enable) or - (not LocalPoolDataSetAttorney::getReportingEnabled(*dataSet) and not enable)) { - return REPORTING_STATUS_UNCHANGED; - } - - LocalPoolDataSetAttorney::setReportingEnabled(*dataSet, enable); - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t LocalDataPoolManager::changeCollectionInterval(sid_t sid, - float newCollectionInterval, bool isDiagnostics) { - LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid); - if(dataSet == nullptr) { - printWarningOrError(sif::OutputTypes::OUT_WARNING, "changeCollectionInterval", - DATASET_NOT_FOUND); - return DATASET_NOT_FOUND; - } - - bool targetIsDiagnostics = LocalPoolDataSetAttorney::isDiagnostics(*dataSet); - if((targetIsDiagnostics and not isDiagnostics) or - (not targetIsDiagnostics and isDiagnostics)) { - return WRONG_HK_PACKET_TYPE; - } - - PeriodicHousekeepingHelper* periodicHelper = - LocalPoolDataSetAttorney::getPeriodicHelper(*dataSet); - - if(periodicHelper == nullptr) { - /* Configuration error, set might not have a corresponding pool manager */ - return PERIODIC_HELPER_INVALID; - } - - periodicHelper->changeCollectionInterval(newCollectionInterval); - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t LocalDataPoolManager::generateSetStructurePacket(sid_t sid, - bool isDiagnostics) { - /* Get and check dataset first. */ - LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid); - if(dataSet == nullptr) { - printWarningOrError(sif::OutputTypes::OUT_WARNING, - "performPeriodicHkGeneration", DATASET_NOT_FOUND); - return DATASET_NOT_FOUND; - } - - - bool targetIsDiagnostics = LocalPoolDataSetAttorney::isDiagnostics(*dataSet); - if((targetIsDiagnostics and not isDiagnostics) or - (not targetIsDiagnostics and isDiagnostics)) { - return WRONG_HK_PACKET_TYPE; - } - - bool valid = dataSet->isValid(); - bool reportingEnabled = LocalPoolDataSetAttorney::getReportingEnabled(*dataSet); - float collectionInterval = LocalPoolDataSetAttorney::getPeriodicHelper(*dataSet)-> - getCollectionIntervalInSeconds(); - - // Generate set packet which can be serialized. - HousekeepingSetPacket setPacket(sid, - reportingEnabled, valid, collectionInterval, dataSet); - size_t expectedSize = setPacket.getSerializedSize(); - uint8_t* storePtr = nullptr; - store_address_t storeId; - ReturnValue_t result = ipcStore->getFreeElement(&storeId, - expectedSize,&storePtr); - if(result != HasReturnvaluesIF::RETURN_OK) { - printWarningOrError(sif::OutputTypes::OUT_ERROR, - "generateSetStructurePacket", HasReturnvaluesIF::RETURN_FAILED, - "Could not get free element from IPC store."); - return result; - } - - // Serialize set packet into store. - size_t size = 0; - result = setPacket.serialize(&storePtr, &size, expectedSize, - SerializeIF::Endianness::BIG); - if(expectedSize != size) { - printWarningOrError(sif::OutputTypes::OUT_WARNING, - "generateSetStructurePacket", HasReturnvaluesIF::RETURN_FAILED, - "Expected size is not equal to serialized size"); - } - - // Send structure reporting reply. - CommandMessage reply; - if(isDiagnostics) { - HousekeepingMessage::setDiagnosticsStuctureReportReply(&reply, - sid, storeId); - } - else { - HousekeepingMessage::setHkStuctureReportReply(&reply, - sid, storeId); - } - - hkQueue->reply(&reply); - return result; -} - -void LocalDataPoolManager::clearReceiversList() { - /* Clear the vector completely and releases allocated memory. */ - HkReceivers().swap(hkReceivers); - /* Also clear the reset helper if it exists */ - if(hkUpdateResetList != nullptr) { - HkUpdateResetList().swap(*hkUpdateResetList); - } -} - -MutexIF* LocalDataPoolManager::getLocalPoolMutex() { - return this->mutex; -} - -object_id_t LocalDataPoolManager::getCreatorObjectId() const { - return owner->getObjectId(); -} - -void LocalDataPoolManager::printWarningOrError(sif::OutputTypes outputType, - const char* functionName, ReturnValue_t error, const char* errorPrint) { -#if FSFW_VERBOSE_LEVEL >= 1 - if(errorPrint == nullptr) { - if(error == DATASET_NOT_FOUND) { - errorPrint = "Dataset not found"; - } - else if(error == POOLOBJECT_NOT_FOUND) { - errorPrint = "Pool Object not found"; - } - else if(error == HasReturnvaluesIF::RETURN_FAILED) { - if(outputType == sif::OutputTypes::OUT_WARNING) { - errorPrint = "Generic Warning"; - } - else { - errorPrint = "Generic error"; - } - } - else if(error == QUEUE_OR_DESTINATION_INVALID) { - errorPrint = "Queue or destination not set"; - } - else if(error == localpool::POOL_ENTRY_TYPE_CONFLICT) { - errorPrint = "Pool entry type conflict"; - } - else if(error == localpool::POOL_ENTRY_NOT_FOUND) { - errorPrint = "Pool entry not found"; - } - else { - errorPrint = "Unknown error"; - } - } - object_id_t objectId = 0xffffffff; - if(owner != nullptr) { - objectId = owner->getObjectId(); - } - - if(outputType == sif::OutputTypes::OUT_WARNING) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "LocalDataPoolManager::" << functionName << ": Object ID 0x" << - std::setw(8) << std::setfill('0') << std::hex << objectId << " | " << errorPrint << - std::dec << std::setfill(' ') << std::endl; -#else - sif::printWarning("LocalDataPoolManager::%s: Object ID 0x%08x | %s\n", - functionName, objectId, errorPrint); -#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ - } - else if(outputType == sif::OutputTypes::OUT_ERROR) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "LocalDataPoolManager::" << functionName << ": Object ID 0x" << - std::setw(8) << std::setfill('0') << std::hex << objectId << " | " << errorPrint << - std::dec << std::setfill(' ') << std::endl; -#else - sif::printError("LocalDataPoolManager::%s: Object ID 0x%08x | %s\n", - functionName, objectId, errorPrint); -#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ - } -#endif /* #if FSFW_VERBOSE_LEVEL >= 1 */ -} - -LocalDataPoolManager* LocalDataPoolManager::getPoolManagerHandle() { - return this; -} diff --git a/datapoollocal/datapoollocal.h b/datapoollocal/datapoollocal.h deleted file mode 100644 index c5c47078..00000000 --- a/datapoollocal/datapoollocal.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef FSFW_DATAPOOLLOCAL_DATAPOOLLOCAL_H_ -#define FSFW_DATAPOOLLOCAL_DATAPOOLLOCAL_H_ - -/* Collected related headers */ -#include "LocalPoolVariable.h" -#include "LocalPoolVector.h" -#include "StaticLocalDataSet.h" -#include "LocalDataSet.h" -#include "SharedLocalDataSet.h" - - -#endif /* FSFW_DATAPOOLLOCAL_DATAPOOLLOCAL_H_ */ diff --git a/defaultcfg/fsfwconfig/CMakeLists.txt b/defaultcfg/fsfwconfig/CMakeLists.txt deleted file mode 100644 index cbd4ecde..00000000 --- a/defaultcfg/fsfwconfig/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -target_sources(${LIB_FSFW_NAME} PRIVATE - ipc/missionMessageTypes.cpp - objects/FsfwFactory.cpp - pollingsequence/PollingSequenceFactory.cpp -) - -# Should be added to include path -target_include_directories(${TARGET_NAME} PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR} -) - -if(NOT FSFW_CONFIG_PATH) - set(FSFW_CONFIG_PATH ${CMAKE_CURRENT_SOURCE_DIR}) -endif() - diff --git a/defaultcfg/fsfwconfig/fsfwconfig.mk b/defaultcfg/fsfwconfig/fsfwconfig.mk deleted file mode 100644 index 51543eba..00000000 --- a/defaultcfg/fsfwconfig/fsfwconfig.mk +++ /dev/null @@ -1,15 +0,0 @@ -CXXSRC += $(wildcard $(CURRENTPATH)/ipc/*.cpp) -CXXSRC += $(wildcard $(CURRENTPATH)/objects/*.cpp) -CXXSRC += $(wildcard $(CURRENTPATH)/pollingsequence/*.cpp) -CXXSRC += $(wildcard $(CURRENTPATH)/events/*.cpp) -CXXSRC += $(wildcard $(CURRENTPATH)/tmtc/*.cpp) -CXXSRC += $(wildcard $(CURRENTPATH)/devices/*.cpp) - -INCLUDES += $(CURRENTPATH) -INCLUDES += $(CURRENTPATH)/objects -INCLUDES += $(CURRENTPATH)/returnvalues -INCLUDES += $(CURRENTPATH)/tmtc -INCLUDES += $(CURRENTPATH)/events -INCLUDES += $(CURRENTPATH)/devices -INCLUDES += $(CURRENTPATH)/pollingsequence -INCLUDES += $(CURRENTPATH)/ipc diff --git a/doc/README-config.md b/doc/README-config.md deleted file mode 100644 index 036a7d14..00000000 --- a/doc/README-config.md +++ /dev/null @@ -1,21 +0,0 @@ - -## Configuring the FSFW - -The FSFW can be configured via the `fsfwconfig` folder. A template folder has -been provided to have a starting point for this. The folder should be added -to the include path. - - -### Configuring the Event Manager - -The number of allowed subscriptions can be modified with the following -parameters: - -``` c++ -namespace fsfwconfig { -//! Configure the allocated pool sizes for the event manager. -static constexpr size_t FSFW_EVENTMGMR_MATCHTREE_NODES = 240; -static constexpr size_t FSFW_EVENTMGMT_EVENTIDMATCHERS = 120; -static constexpr size_t FSFW_EVENTMGMR_RANGEMATCHERS = 120; -} -``` \ No newline at end of file diff --git a/doc/README-highlevel.md b/doc/README-highlevel.md deleted file mode 100644 index fac89c53..00000000 --- a/doc/README-highlevel.md +++ /dev/null @@ -1,99 +0,0 @@ -# High-level overview - -## Structure - -The general structure is driven by the usage of interfaces provided by objects. -The FSFW uses C++11 as baseline. The intention behind this is that this C++ Standard should be widely available, even with older compilers. -The FSFW uses dynamic allocation during the initialization but provides static containers during runtime. -This simplifies the instantiation of objects and allows the usage of some standard containers. -Dynamic Allocation after initialization is discouraged and different solutions are provided in the FSFW to achieve that. -The fsfw uses run-time type information but exceptions are not allowed. - -### Failure Handling - -Functions should return a defined ReturnValue_t to signal to the caller that something has gone wrong. -Returnvalues must be unique. For this the function HasReturnvaluesIF::makeReturnCode or the Macro MAKE_RETURN can be used. -The CLASS_ID is a unique id for that type of object. See returnvalues/FwClassIds. - -### OSAL - -The FSFW provides operation system abstraction layers for Linux, FreeRTOS and RTEMS. -The OSAL provides periodic tasks, message queues, clocks and semaphores as well as mutexes. -The [OSAL README](doc/README-osal.md#top) provides more detailed information on provided components and how to use them. - -### Core Components - -The FSFW has following core components. More detailed informations can be found in the -[core component section](doc/README-core.md#top): - -1. Tasks: Abstraction for different (periodic) task types like periodic tasks or tasks with fixed timeslots -2. ObjectManager: This module stores all `SystemObjects` by mapping a provided unique object ID to the object handles. -3. Static Stores: Different stores are provided to store data of variable size (like telecommands or small telemetry) in a pool structure without - using dynamic memory allocation. These pools are allocated up front. -3. Clock: This module provided common time related functions -4. EventManager: This module allows routing of events generated by `SystemObjects` -5. HealthTable: A component which stores the health states of objects - -### Static IDs in the framework - -Some parts of the framework use a static routing address for communication. -An example setup of ids can be found in the example config in "defaultcft/fsfwconfig/objects/Factory::setStaticFrameworkObjectIds()". - -### Events - -Events are tied to objects. EventIds can be generated by calling the Macro MAKE_EVENT. This works analog to the returnvalues. -Every object that needs own EventIds has to get a unique SUBSYSTEM_ID. -Every SystemObject can call triggerEvent from the parent class. -Therefore, event messages contain the specific EventId and the objectId of the object that has triggered. - -### Internal Communication - -Components communicate mostly over Message through Queues. -Those queues are created by calling the singleton QueueFactory::instance()->create(). - -### External Communication - -The external communication with the mission control system is mostly up to the user implementation. -The FSFW provides PUS Services which can be used to but don't need to be used. -The services can be seen as a conversion from a TC to a message based communication and back. - -#### CCSDS Frames, CCSDS Space Packets and PUS - -If the communication is based on CCSDS Frames and Space Packets, several classes can be used to distributed the packets to the corresponding services. Those can be found in tcdistribution. -If Space Packets are used, a timestamper must be created. -An example can be found in the timemanager folder, this uses CCSDSTime::CDS_short. - -#### Device Handlers - -DeviceHandlers are another important component of the FSFW. -The idea is, to have a software counterpart of every physical device to provide a simple mode, health and commanding interface. -By separating the underlying Communication Interface with DeviceCommunicationIF, a device handler (DH) can be tested on different hardware. -The DH has mechanisms to monitor the communication with the physical device which allow for FDIR reaction. -Device Handlers can be created by overriding `DeviceHandlerBase`. -A standard FDIR component for the DH will be created automatically but can be overwritten by the user. -More information on DeviceHandlers can be found in the related [documentation section](doc/README-devicehandlers.md#top). - -#### Modes, Health - -The two interfaces HasModesIF and HasHealthIF provide access for commanding and monitoring of components. -On-board Mode Management is implement in hierarchy system. -DeviceHandlers and Controllers are the lowest part of the hierarchy. -The next layer are Assemblies. Those assemblies act as a component which handle redundancies of handlers. -Assemblies share a common core with the next level which are the Subsystems. - -Those Assemblies are intended to act as auto-generated components from a database which describes the subsystem modes. -The definitions contain transition and target tables which contain the DH, Assembly and Controller Modes to be commanded. -Transition tables contain as many steps as needed to reach the mode from any other mode, e.g. a switch into any higher AOCS mode might first turn on the sensors, than the actuators and the controller as last component. -The target table is used to describe the state that is checked continuously by the subsystem. -All of this allows System Modes to be generated as Subsystem object as well from the same database. -This System contains list of subsystem modes in the transition and target tables. -Therefore, it allows a modular system to create system modes and easy commanding of those, because only the highest components must be commanded. - -The health state represents if the component is able to perform its tasks. -This can be used to signal the system to avoid using this component instead of a redundant one. -The on-board FDIR uses the health state for isolation and recovery. - -## Unit Tests - -Unit Tests are provided in the unittest folder. Those use the catch2 framework but do not include catch2 itself. More information on how to run these tests can be found in the separate -[`fsfw_tests` reposoitory](https://egit.irs.uni-stuttgart.de/fsfw/fsfw_tests) diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 00000000..a485625d --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1 @@ +/_build diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt new file mode 100644 index 00000000..fa5790db --- /dev/null +++ b/docs/CMakeLists.txt @@ -0,0 +1,66 @@ +# This is based on this excellent posting provided by Sy: +# https://devblogs.microsoft.com/cppblog/clear-functional-c-documentation-with-sphinx-breathe-doxygen-cmake/ +find_package(Doxygen REQUIRED) +find_package(Sphinx REQUIRED) + +get_target_property(LIB_FSFW_PUBLIC_HEADER_DIRS ${LIB_FSFW_NAME} INTERFACE_INCLUDE_DIRECTORIES) +# TODO: Add HAL as well +file(GLOB_RECURSE LIB_FSFW_PUBLIC_HEADERS ${PROJECT_SOURCE_DIR}/src/*.h) +file(GLOB_RECURSE RST_DOC_FILES ${PROJECT_SOURCE_DIR}/docs/*.rst) + +set(DOXYGEN_INPUT_DIR ${PROJECT_SOURCE_DIR}/src) +set(DOXYGEN_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/doxygen) +set(DOXYGEN_INDEX_FILE ${DOXYGEN_OUTPUT_DIR}/xml/index.xml) +set(DOXYFILE_IN ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in) +set(DOXYFILE_OUT ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) + +# Replace variables inside @@ with the current values +configure_file(${DOXYFILE_IN} ${DOXYFILE_OUT} @ONLY) + +# Doxygen won't create this for us +file(MAKE_DIRECTORY ${DOXYGEN_OUTPUT_DIR}) + +# Only regenerate Doxygen when the Doxyfile or public headers change +add_custom_command( + OUTPUT ${DOXYGEN_INDEX_FILE} + DEPENDS ${LIB_FSFW_PUBLIC_HEADERS} + COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYFILE_OUT} + MAIN_DEPENDENCY ${DOXYFILE_OUT} ${DOXYFILE_IN} + COMMENT "Generating docs" + VERBATIM +) + +# Nice named target so we can run the job easily +add_custom_target(Doxygen ALL DEPENDS ${DOXYGEN_INDEX_FILE}) + +set(SPHINX_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}) +set(SPHINX_BUILD ${CMAKE_CURRENT_BINARY_DIR}/sphinx) +set(SPHINX_INDEX_FILE ${SPHINX_BUILD}/index.html) + +# Only regenerate Sphinx when: +# - Doxygen has rerun +# - Our doc files have been updated +# - The Sphinx config has been updated +add_custom_command( + OUTPUT ${SPHINX_INDEX_FILE} + COMMAND + ${SPHINX_EXECUTABLE} -b html + # Tell Breathe where to find the Doxygen output + -Dbreathe_projects.fsfw=${DOXYGEN_OUTPUT_DIR}/xml + ${SPHINX_SOURCE} ${SPHINX_BUILD} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS + # Other docs files you want to track should go here (or in some variable) + ${RST_DOC_FILES} + ${DOXYGEN_INDEX_FILE} + MAIN_DEPENDENCY ${SPHINX_SOURCE}/conf.py + COMMENT "Generating documentation with Sphinx" +) + +# Nice named target so we can run the job easily +add_custom_target(Sphinx ALL DEPENDS ${SPHINX_INDEX_FILE}) + +# Add an install target to install the docs +include(GNUInstallDirs) +install(DIRECTORY ${SPHINX_BUILD} +DESTINATION ${CMAKE_INSTALL_DOCDIR}) diff --git a/docs/Doxyfile.in b/docs/Doxyfile.in new file mode 100644 index 00000000..3d01d126 --- /dev/null +++ b/docs/Doxyfile.in @@ -0,0 +1,7 @@ +INPUT = "@DOXYGEN_INPUT_DIR@" + +RECURSIVE = YES + +OUTPUT_DIRECTORY = "@DOXYGEN_OUTPUT_DIR@" + +GENERATE_XML = YES diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 00000000..d4bb2cbb --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/README-config.md b/docs/README-config.md new file mode 100644 index 00000000..d71feb97 --- /dev/null +++ b/docs/README-config.md @@ -0,0 +1,40 @@ +Configuring the FSFW +====== + +The FSFW can be configured via the `fsfwconfig` folder. A template folder has +been provided to have a starting point for this. The folder should be added +to the include path. The primary configuration file is the `FSFWConfig.h` folder. Some +of the available options will be explained in more detail here. + +# Auto-Translation of Events + +The FSFW allows the automatic translation of events, which allows developers to track triggered +events directly via console output. Using this feature requires: + +1. `FSFW_OBJ_EVENT_TRANSLATION` set to 1 in the configuration file. +2. Special auto-generated translation files which translate event IDs and object IDs into + human readable strings. These files can be generated using the + [modgen Python scripts](https://git.ksat-stuttgart.de/source/modgen.git). +3. The generated translation files for the object IDs should be named `translatesObjects.cpp` + and `translateObjects.h` and should be copied to the `fsfwconfig/objects` folder +4. The generated translation files for the event IDs should be named `translateEvents.cpp` and + `translateEvents.h` and should be copied to the `fsfwconfig/events` folder + +An example implementations of these translation file generators can be found as part +of the [SOURCE project here](https://git.ksat-stuttgart.de/source/sourceobsw/-/tree/development/generators) +or the [FSFW example](https://egit.irs.uni-stuttgart.de/fsfw/fsfw_example_public/src/branch/master/generators) + +## Configuring the Event Manager + +The number of allowed subscriptions can be modified with the following +parameters: + +``` c++ +namespace fsfwconfig { +//! Configure the allocated pool sizes for the event manager. +static constexpr size_t FSFW_EVENTMGMR_MATCHTREE_NODES = 240; +static constexpr size_t FSFW_EVENTMGMT_EVENTIDMATCHERS = 120; +static constexpr size_t FSFW_EVENTMGMR_RANGEMATCHERS = 120; +} +``` + diff --git a/doc/README-controllers.md b/docs/README-controllers.md similarity index 100% rename from doc/README-controllers.md rename to docs/README-controllers.md diff --git a/doc/README-core.md b/docs/README-core.md similarity index 71% rename from doc/README-core.md rename to docs/README-core.md index 6431b831..e34890ae 100644 --- a/doc/README-core.md +++ b/docs/README-core.md @@ -19,8 +19,9 @@ A nullptr check of the returning Pointer must be done. This function is based on ```cpp template T* ObjectManagerIF::get( object_id_t id ) ``` -* A typical way to create all objects on startup is a handing a static produce function to the ObjectManager on creation. -By calling objectManager->initialize() the produce function will be called and all SystemObjects will be initialized afterwards. +* A typical way to create all objects on startup is a handing a static produce function to the + ObjectManager on creation. By calling objectManager->initialize() the produce function will be + called and all SystemObjects will be initialized afterwards. ### Event Manager @@ -36,14 +37,19 @@ By calling objectManager->initialize() the produce function will be called and a ### Stores -* The message based communication can only exchange a few bytes of information inside the message itself. Therefore, additional information can - be exchanged with Stores. With this, only the store address must be exchanged in the message. -* Internally, the FSFW uses an IPC Store to exchange data between processes. For incoming TCs a TC Store is used. For outgoing TM a TM store is used. +* The message based communication can only exchange a few bytes of information inside the message + itself. Therefore, additional information can be exchanged with Stores. With this, only the + store address must be exchanged in the message. +* Internally, the FSFW uses an IPC Store to exchange data between processes. For incoming TCs a TC + Store is used. For outgoing TM a TM store is used. * All of them should use the Thread Safe Class storagemanager/PoolManager ### Tasks There are two different types of tasks: - * The PeriodicTask just executes objects that are of type ExecutableObjectIF in the order of the insertion to the Tasks. - * FixedTimeslotTask executes a list of calls in the order of the given list. This is intended for DeviceHandlers, where polling should be in a defined order. An example can be found in defaultcfg/fsfwconfig/pollingSequence + * The PeriodicTask just executes objects that are of type ExecutableObjectIF in the order of the + insertion to the Tasks. + * FixedTimeslotTask executes a list of calls in the order of the given list. This is intended for + DeviceHandlers, where polling should be in a defined order. An example can be found in + `defaultcfg/fsfwconfig/pollingSequence` folder diff --git a/doc/README-devicehandlers.md b/docs/README-devicehandlers.md similarity index 100% rename from doc/README-devicehandlers.md rename to docs/README-devicehandlers.md diff --git a/docs/README-highlevel.md b/docs/README-highlevel.md new file mode 100644 index 00000000..262138a7 --- /dev/null +++ b/docs/README-highlevel.md @@ -0,0 +1,135 @@ +High-level overview +====== + +# Structure + +The general structure is driven by the usage of interfaces provided by objects. +The FSFW uses C++11 as baseline. The intention behind this is that this C++ Standard should be +widely available, even with older compilers. +The FSFW uses dynamic allocation during the initialization but provides static containers during runtime. +This simplifies the instantiation of objects and allows the usage of some standard containers. +Dynamic Allocation after initialization is discouraged and different solutions are provided in the +FSFW to achieve that. The fsfw uses run-time type information but exceptions are not allowed. + +# Failure Handling + +Functions should return a defined `ReturnValue_t` to signal to the caller that something has +gone wrong. Returnvalues must be unique. For this the function `HasReturnvaluesIF::makeReturnCode` +or the macro `MAKE_RETURN` can be used. The `CLASS_ID` is a unique id for that type of object. +See `returnvalues/FwClassIds` folder. The user can add custom `CLASS_ID`s via the +`fsfwconfig` folder. + +# OSAL + +The FSFW provides operation system abstraction layers for Linux, FreeRTOS and RTEMS. +The OSAL provides periodic tasks, message queues, clocks and semaphores as well as mutexes. +The [OSAL README](doc/README-osal.md#top) provides more detailed information on provided components +and how to use them. + +# Core Components + +The FSFW has following core components. More detailed informations can be found in the +[core component section](doc/README-core.md#top): + +1. Tasks: Abstraction for different (periodic) task types like periodic tasks or tasks + with fixed timeslots +2. ObjectManager: This module stores all `SystemObjects` by mapping a provided unique object ID + to the object handles. +3. Static Stores: Different stores are provided to store data of variable size (like telecommands + or small telemetry) in a pool structure without using dynamic memory allocation. + These pools are allocated up front. +3. Clock: This module provided common time related functions +4. EventManager: This module allows routing of events generated by `SystemObjects` +5. HealthTable: A component which stores the health states of objects + +# Static IDs in the framework + +Some parts of the framework use a static routing address for communication. +An example setup of ids can be found in the example config in `defaultcft/fsfwconfig/objects` + inside the function `Factory::setStaticFrameworkObjectIds()`. + +# Events + +Events are tied to objects. EventIds can be generated by calling the Macro MAKE_EVENT. +This works analog to the returnvalues. Every object that needs own EventIds has to get a +unique SUBSYSTEM_ID. Every SystemObject can call triggerEvent from the parent class. +Therefore, event messages contain the specific EventId and the objectId of the object that +has triggered. + +# Internal Communication + +Components communicate mostly via Messages through Queues. +Those queues are created by calling the singleton `QueueFactory::instance()->create()` which +will create `MessageQueue` instances for the used OSAL. + +# External Communication + +The external communication with the mission control system is mostly up to the user implementation. +The FSFW provides PUS Services which can be used to but don't need to be used. +The services can be seen as a conversion from a TC to a message based communication and back. + +## TMTC Communication + +The FSFW provides some components to facilitate TMTC handling via the PUS commands. +For example, a UDP or TCP PUS server socket can be opened on a specific port using the +files located in `osal/common`. The FSFW example uses this functionality to allow sending telecommands +and receiving telemetry using the [TMTC commander application](https://github.com/spacefisch/tmtccmd). +Simple commands like the PUS Service 17 ping service can be tested by simply running the +`tmtc_client_cli.py` or `tmtc_client_gui.py` utility in +the [example tmtc folder](https://egit.irs.uni-stuttgart.de/fsfw/fsfw_example_public/src/branch/master/tmtc) +while the `fsfw_example` application is running. + +More generally, any class responsible for handling incoming telecommands and sending telemetry +can implement the generic `TmTcBridge` class located in `tmtcservices`. Many applications +also use a dedicated polling task for reading telecommands which passes telecommands +to the `TmTcBridge` implementation. + +## CCSDS Frames, CCSDS Space Packets and PUS + +If the communication is based on CCSDS Frames and Space Packets, several classes can be used to +distributed the packets to the corresponding services. Those can be found in `tcdistribution`. +If Space Packets are used, a timestamper has to be provided by the user. +An example can be found in the `timemanager` folder, which uses `CCSDSTime::CDS_short`. + +# Device Handlers + +DeviceHandlers are another important component of the FSFW. +The idea is, to have a software counterpart of every physical device to provide a simple mode, +health and commanding interface. By separating the underlying Communication Interface with +`DeviceCommunicationIF`, a device handler (DH) can be tested on different hardware. +The DH has mechanisms to monitor the communication with the physical device which allow +for FDIR reaction. Device Handlers can be created by implementing `DeviceHandlerBase`. +A standard FDIR component for the DH will be created automatically but can +be overwritten by the user. More information on DeviceHandlers can be found in the +related [documentation section](doc/README-devicehandlers.md#top). + +# Modes and Health + +The two interfaces `HasModesIF` and `HasHealthIF` provide access for commanding and monitoring +of components. On-board Mode Management is implement in hierarchy system. +DeviceHandlers and Controllers are the lowest part of the hierarchy. +The next layer are Assemblies. Those assemblies act as a component which handle +redundancies of handlers. Assemblies share a common core with the next level which +are the Subsystems. + +Those Assemblies are intended to act as auto-generated components from a database which describes +the subsystem modes. The definitions contain transition and target tables which contain the DH, +Assembly and Controller Modes to be commanded. +Transition tables contain as many steps as needed to reach the mode from any other mode, e.g. a +switch into any higher AOCS mode might first turn on the sensors, than the actuators and the +controller as last component. +The target table is used to describe the state that is checked continuously by the subsystem. +All of this allows System Modes to be generated as Subsystem object as well from the same database. +This System contains list of subsystem modes in the transition and target tables. +Therefore, it allows a modular system to create system modes and easy commanding of those, because +only the highest components must be commanded. + +The health state represents if the component is able to perform its tasks. +This can be used to signal the system to avoid using this component instead of a redundant one. +The on-board FDIR uses the health state for isolation and recovery. + +# Unit Tests + +Unit Tests are provided in the unittest folder. Those use the catch2 framework but do not include +catch2 itself. More information on how to run these tests can be found in the separate +[`fsfw_tests` reposoitory](https://egit.irs.uni-stuttgart.de/fsfw/fsfw_tests) diff --git a/doc/README-localpools.md b/docs/README-localpools.md similarity index 98% rename from doc/README-localpools.md rename to docs/README-localpools.md index 96ae2d0a..2ee75189 100644 --- a/doc/README-localpools.md +++ b/docs/README-localpools.md @@ -31,7 +31,9 @@ cohesive pool variables. These sets simply iterator over the list of variables a `read` and `commit` functions of each variable. The following diagram shows the high-level architecture of the local data pools. -
+.. image:: ../misc/logo/FSFW_Logo_V3_bw.png + :alt: FSFW Logo + An example is shown for using the local data pools with a Gyroscope. For example, the following code shows an implementation to access data from a Gyroscope taken diff --git a/doc/README-osal.md b/docs/README-osal.md similarity index 100% rename from doc/README-osal.md rename to docs/README-osal.md diff --git a/doc/README-pus.md b/docs/README-pus.md similarity index 100% rename from doc/README-pus.md rename to docs/README-pus.md diff --git a/docs/api.rst b/docs/api.rst new file mode 100644 index 00000000..d2ee6c69 --- /dev/null +++ b/docs/api.rst @@ -0,0 +1,16 @@ +API +==== + +.. toctree:: + :maxdepth: 4 + + api/objectmanager + api/task + api/ipc + api/returnvalue + api/event + api/modes + api/health + api/action + api/devicehandler + api/controller diff --git a/docs/api/action.rst b/docs/api/action.rst new file mode 100644 index 00000000..31825b89 --- /dev/null +++ b/docs/api/action.rst @@ -0,0 +1,15 @@ +Action Module API +================= + +``ActionHelper`` +----------------- + +.. doxygenclass:: ActionHelper + :members: + +``HasActionsIF`` +----------------- + +.. doxygenclass:: HasActionsIF + :members: + :protected-members: diff --git a/docs/api/controller.rst b/docs/api/controller.rst new file mode 100644 index 00000000..27136be6 --- /dev/null +++ b/docs/api/controller.rst @@ -0,0 +1,16 @@ +Controller API +================= + +``ControllerBase`` +------------------------- + +.. doxygenclass:: ControllerBase + :members: + :protected-members: + +``ExtendedControllerBase`` +----------------------------- + +.. doxygenclass:: ExtendedControllerBase + :members: + :protected-members: diff --git a/docs/api/devicehandler.rst b/docs/api/devicehandler.rst new file mode 100644 index 00000000..f709b640 --- /dev/null +++ b/docs/api/devicehandler.rst @@ -0,0 +1,16 @@ +Device Handler Base API +========================= + +``DeviceHandlerBase`` +----------------------- + +.. doxygenclass:: DeviceHandlerBase + :members: + :protected-members: + +``DeviceHandlerIF`` +----------------------- + +.. doxygenclass:: DeviceHandlerIF + :members: + :protected-members: diff --git a/docs/api/event.rst b/docs/api/event.rst new file mode 100644 index 00000000..7553c963 --- /dev/null +++ b/docs/api/event.rst @@ -0,0 +1,6 @@ +.. _eventapi: + +Event API +============ + +.. doxygenfile:: Event.h diff --git a/docs/api/health.rst b/docs/api/health.rst new file mode 100644 index 00000000..b1d4c1b2 --- /dev/null +++ b/docs/api/health.rst @@ -0,0 +1,9 @@ +Health API +=========== + +``HasHealthIF`` +------------------ + +.. doxygenclass:: HasHealthIF + :members: + :protected-members: diff --git a/docs/api/ipc.rst b/docs/api/ipc.rst new file mode 100644 index 00000000..17a91f00 --- /dev/null +++ b/docs/api/ipc.rst @@ -0,0 +1,9 @@ +IPC Module API +================= + +``MessageQueueIF`` +------------------- + +.. doxygenclass:: MessageQueueIF + :members: + :protected-members: diff --git a/docs/api/modes.rst b/docs/api/modes.rst new file mode 100644 index 00000000..7b6b0dca --- /dev/null +++ b/docs/api/modes.rst @@ -0,0 +1,10 @@ +Modes API +========= + + +``HasModesIF`` +--------------- + +.. doxygenclass:: HasModesIF + :members: + :protected-members: diff --git a/docs/api/objectmanager.rst b/docs/api/objectmanager.rst new file mode 100644 index 00000000..e90deb57 --- /dev/null +++ b/docs/api/objectmanager.rst @@ -0,0 +1,30 @@ +Object Manager API +========================= + +``SystemObject`` +-------------------- + +.. doxygenclass:: SystemObject + :members: + :protected-members: + +``ObjectManager`` +----------------------- + +.. doxygenclass:: ObjectManager + :members: + :protected-members: + +``SystemObjectIF`` +-------------------- + +.. doxygenclass:: SystemObjectIF + :members: + :protected-members: + +``ObjectManagerIF`` +----------------------- + +.. doxygenclass:: ObjectManagerIF + :members: + :protected-members: diff --git a/docs/api/returnvalue.rst b/docs/api/returnvalue.rst new file mode 100644 index 00000000..b0d43916 --- /dev/null +++ b/docs/api/returnvalue.rst @@ -0,0 +1,10 @@ +.. _retvalapi: + +Returnvalue API +================== + +.. doxygenfile:: HasReturnvaluesIF.h + +.. _fwclassids: + +.. doxygenfile:: FwClassIds.h diff --git a/docs/api/task.rst b/docs/api/task.rst new file mode 100644 index 00000000..b218dac1 --- /dev/null +++ b/docs/api/task.rst @@ -0,0 +1,8 @@ +Task API +========= + +``ExecutableObjectIF`` +----------------------- + +.. doxygenclass:: ExecutableObjectIF + :members: diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 00000000..62b17192 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,56 @@ +# Configuration file for the Sphinx documentation builder. +# +# This file only contains a selection of the most common options. For a full +# list see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +# import os +# import sys +# sys.path.insert(0, os.path.abspath('.')) + + +# -- Project information ----------------------------------------------------- + +project = 'Flight Software Framework' +copyright = '2021, Institute of Space Systems (IRS)' +author = 'Institute of Space Systems (IRS)' + +# The full version, including alpha/beta/rc tags +release = '2.0.1' + + +# -- General configuration --------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ "breathe" ] + +breathe_default_project = "fsfw" + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'alabaster' + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = [] \ No newline at end of file diff --git a/docs/config.rst b/docs/config.rst new file mode 100644 index 00000000..ed317aed --- /dev/null +++ b/docs/config.rst @@ -0,0 +1,41 @@ +Configuring the FSFW +===================== + +The FSFW can be configured via the ``fsfwconfig`` folder. A template folder has been provided in +``misc/defaultcfg`` to have a starting point for this. The folder should be added +to the include path. The primary configuration file is the ``FSFWConfig.h`` folder. Some +of the available options will be explained in more detail here. + +Auto-Translation of Events +---------------------------- + +The FSFW allows the automatic translation of events, which allows developers to track triggered +events directly via console output. Using this feature requires: + +1. ``FSFW_OBJ_EVENT_TRANSLATION`` set to 1 in the configuration file. +2. Special auto-generated translation files which translate event IDs and object IDs into + human readable strings. These files can be generated using the + `fsfwgen Python scripts `_. +3. The generated translation files for the object IDs should be named ``translatesObjects.cpp`` + and ``translateObjects.h`` and should be copied to the ``fsfwconfig/objects`` folder +4. The generated translation files for the event IDs should be named ``translateEvents.cpp`` and + ``translateEvents.h`` and should be copied to the ``fsfwconfig/events`` folder + +An example implementations of these translation file generators can be found as part +of the `SOURCE project here `_ +or the `FSFW example `_ + +Configuring the Event Manager +---------------------------------- + +The number of allowed subscriptions can be modified with the following +parameters: + +.. code-block:: cpp + + namespace fsfwconfig { + //! Configure the allocated pool sizes for the event manager. + static constexpr size_t FSFW_EVENTMGMR_MATCHTREE_NODES = 240; + static constexpr size_t FSFW_EVENTMGMT_EVENTIDMATCHERS = 120; + static constexpr size_t FSFW_EVENTMGMR_RANGEMATCHERS = 120; + } diff --git a/docs/controllers.rst b/docs/controllers.rst new file mode 100644 index 00000000..28f57393 --- /dev/null +++ b/docs/controllers.rst @@ -0,0 +1,2 @@ +Controllers +============= diff --git a/docs/core.rst b/docs/core.rst new file mode 100644 index 00000000..ef6f6165 --- /dev/null +++ b/docs/core.rst @@ -0,0 +1,70 @@ +.. _core: + +Core Modules +============= + +The core modules provide the most important functionalities of the Flight Software Framework. + +Clock +------ + +- This is a class of static functions that can be used at anytime +- Leap Seconds must be set if any time conversions from UTC to other times is used + +Object Manager +--------------- + +- Must be created during program startup +- The component which handles all references. All :cpp:class:`SystemObject`\s register at this + component. +- All :cpp:class:`SystemObject`\s needs to have a unique Object ID. Those can be managed like + framework objects. +- A reference to an object can be retrieved by calling the ``get`` function of + :cpp:class:`ObjectManagerIF`. The target type must be specified as a template argument. + A ``nullptr`` check of the returning pointer must be done. This function is based on + run-time type information. + + .. code-block:: cpp + + template T* ObjectManagerIF::get(object_id_t id); + +- A typical way to create all objects on startup is a handing a static produce function to the + ObjectManager on creation. By calling ``ObjectManager::instance()->initialize(produceFunc)`` the + produce function will be called and all :cpp:class:`SystemObject`\s will be initialized + afterwards. + +Event Manager +--------------- + +- Component which allows routing of events +- Other objects can subscribe to specific events, ranges of events or all events of an object. +- Subscriptions can be done during runtime but should be done during initialization +- Amounts of allowed subscriptions can be configured in ``FSFWConfig.h`` + +Health Table +--------------- + +- A component which holds every health state +- Provides a thread safe way to access all health states without the need of message exchanges + +Stores +-------------- + +- The message based communication can only exchange a few bytes of information inside the message + itself. Therefore, additional information can be exchanged with Stores. With this, only the + store address must be exchanged in the message. +- Internally, the FSFW uses an IPC Store to exchange data between processes. For incoming TCs a TC + Store is used. For outgoing TM a TM store is used. +- All of them should use the Thread Safe Class storagemanager/PoolManager + +Tasks +--------- + +There are two different types of tasks: + +- The PeriodicTask just executes objects that are of type ExecutableObjectIF in the order of the + insertion to the Tasks. +- FixedTimeslotTask executes a list of calls in the order of the given list. This is intended for + DeviceHandlers, where polling should be in a defined order. An example can be found in + ``defaultcfg/fsfwconfig/pollingSequence`` folder + diff --git a/docs/devicehandlers.rst b/docs/devicehandlers.rst new file mode 100644 index 00000000..58c2df78 --- /dev/null +++ b/docs/devicehandlers.rst @@ -0,0 +1,3 @@ +Device Handlers +================== + diff --git a/doc/doxy/.gitignore b/docs/doxy/.gitignore similarity index 100% rename from doc/doxy/.gitignore rename to docs/doxy/.gitignore diff --git a/doc/doxy/OPUS.doxyfile b/docs/doxy/OPUS.doxyfile similarity index 100% rename from doc/doxy/OPUS.doxyfile rename to docs/doxy/OPUS.doxyfile diff --git a/docs/getting_started.rst b/docs/getting_started.rst new file mode 100644 index 00000000..069e98cd --- /dev/null +++ b/docs/getting_started.rst @@ -0,0 +1,115 @@ +Getting Started +================ + + +Getting started +---------------- + +The `Hosted FSFW example`_ provides a good starting point and a demo to see the FSFW capabilities. +It is recommended to get started by building and playing around with the demo application. +There are also other examples provided for all OSALs using the popular embedded platforms +Raspberry Pi, Beagle Bone Black and STM32H7. + +Generally, the FSFW is included in a project by providing +a configuration folder, building the static library and linking against it. +There are some functions like ``printChar`` which are different depending on the target architecture +and need to be implemented by the mission developer. + +A template configuration folder was provided and can be copied into the project root to have +a starting point. The [configuration section](docs/README-config.md#top) provides more specific +information about the possible options. + +Adding the library +------------------- + +The following steps show how to add and use FSFW components. It is still recommended to +try out the example mentioned above to get started, but the following steps show how to +add and link against the FSFW library in general. + +1. Add this repository as a submodule + + .. code-block:: console + + git submodule add https://egit.irs.uni-stuttgart.de/fsfw/fsfw.git fsfw + +2. Add the following directive inside the uppermost ``CMakeLists.txt`` file of your project + + .. code-block:: cmake + + add_subdirectory(fsfw) + +3. Make sure to provide a configuration folder and supply the path to that folder with + the `FSFW_CONFIG_PATH` CMake variable from the uppermost `CMakeLists.txt` file. + It is also necessary to provide the `printChar` function. You can find an example + implementation for a hosted build + `here `_. + +4. Link against the FSFW library + + .. code-block:: cmake + + target_link_libraries( PRIVATE fsfw) + + +5. It should now be possible use the FSFW as a static library from the user code. + +Building the unittests +------------------------- + +The FSFW also has unittests which use the `Catch2 library`_. +These are built by setting the CMake option ``FSFW_BUILD_UNITTESTS`` to ``ON`` or `TRUE` +from your project `CMakeLists.txt` file or from the command line. + +The fsfw-tests binary will be built as part of the static library and dropped alongside it. +If the unittests are built, the library and the tests will be built with coverage information by +default. This can be disabled by setting the `FSFW_TESTS_COV_GEN` option to `OFF` or `FALSE`. + +You can use the following commands inside the ``fsfw`` folder to set up the build system + +.. code-block:: console + + mkdir build-tests && cd build-tests + cmake -DFSFW_BUILD_UNITTESTS=ON -DFSFW_OSAL=host .. + + +You can also use ``-DFSFW_OSAL=linux`` on Linux systems. + +Coverage data in HTML format can be generated using the `Code coverage`_ CMake module. +To build the unittests, run them and then generare the coverage data in this format, +the following command can be used inside the build directory after the build system was set up + +.. code-block:: console + + cmake --build . -- fsfw-tests_coverage -j + + +The ``helper.py`` script located in the ``script`` folder can also be used to create, build +and open the unittests conveniently. Try ``helper.py -h`` for more information. + +Building the documentation +---------------------------- + +The FSFW documentation is built using the tools Sphinx, doxygen and breathe based on the +instructions provided in `this blogpost `_. You can set up a +documentation build system using the following commands + +.. code-block:: bash + + mkdir build-docs && cd build-docs + cmake -DFSFW_BUILD_DOCS=ON -DFSFW_OSAL=host .. + +Then you can generate the documentation using + +.. code-block:: bash + + cmake --build . -j + +You can find the generated documentation inside the ``docs/sphinx`` folder inside the build +folder. Simply open the ``index.html`` in the webbrowser of your choice. + +The ``helper.py`` script located in the ``script`` folder can also be used to create, build +and open the documentation conveniently. Try ``helper.py -h`` for more information. + +.. _`Hosted FSFW example`: https://egit.irs.uni-stuttgart.de/fsfw/fsfw-example-hosted +.. _`Catch2 library`: https://github.com/catchorg/Catch2 +.. _`Code coverage`: https://github.com/bilke/cmake-modules/tree/master diff --git a/docs/highlevel.rst b/docs/highlevel.rst new file mode 100644 index 00000000..08f44777 --- /dev/null +++ b/docs/highlevel.rst @@ -0,0 +1,149 @@ +.. _highlevel: + +High-level overview +=================== + +Structure +---------- + +The general structure is driven by the usage of interfaces provided by objects. +The FSFW uses C++11 as baseline. The intention behind this is that this C++ Standard should be +widely available, even with older compilers. +The FSFW uses dynamic allocation during the initialization but provides static containers during runtime. +This simplifies the instantiation of objects and allows the usage of some standard containers. +Dynamic Allocation after initialization is discouraged and different solutions are provided in the +FSFW to achieve that. The fsfw uses run-time type information but exceptions are not allowed. + +Failure Handling +----------------- + +Functions should return a defined :cpp:type:`ReturnValue_t` to signal to the caller that something has +gone wrong. Returnvalues must be unique. For this the function :cpp:func:`HasReturnvaluesIF::makeReturnCode` +or the :ref:`macro MAKE_RETURN_CODE ` can be used. The ``CLASS_ID`` is a unique ID for that type of object. +See the :ref:`FSFW Class IDs file `. The user can add custom ``CLASS_ID``\s via the +``fsfwconfig`` folder. + +OSAL +------------ + +The FSFW provides operation system abstraction layers for Linux, FreeRTOS and RTEMS. +The OSAL provides periodic tasks, message queues, clocks and semaphores as well as mutexes. +The :ref:`OSAL README ` provides more detailed information on provided components +and how to use them. + +Core Components +---------------- + +The FSFW has following core components. More detailed informations can be found in the +:ref:`core component section `: + +1. Tasks: Abstraction for different (periodic) task types like periodic tasks or tasks + with fixed timeslots +2. ObjectManager: This module stores all `SystemObjects` by mapping a provided unique object ID + to the object handles. +3. Static Stores: Different stores are provided to store data of variable size (like telecommands + or small telemetry) in a pool structure without using dynamic memory allocation. + These pools are allocated up front. +4. Clock: This module provided common time related functions +5. EventManager: This module allows routing of events generated by `SystemObjects` +6. HealthTable: A component which stores the health states of objects + +Static IDs in the framework +-------------------------------- + +Some parts of the framework use a static routing address for communication. +An example setup of IDs can be found in the example config in ``misc/defaultcfg/fsfwconfig/objects`` +inside the function ``Factory::setStaticFrameworkObjectIds``. + +Events +---------------- + +Events are tied to objects. EventIds can be generated by calling the +:ref:`macro MAKE_EVENT ` or the function :cpp:func:`event::makeEvent`. +This works analog to the returnvalues. Every object that needs own Event IDs has to get a +unique ``SUBSYSTEM_ID``. Every :cpp:class:`SystemObject` can call +:cpp:func:`SystemObject::triggerEvent` from the parent class. +Therefore, event messages contain the specific EventId and the objectId of the object that +has triggered. + +Internal Communication +------------------------- + +Components communicate mostly via Messages through Queues. +Those queues are created by calling the singleton ``QueueFactory::instance()->create`` which +will create `MessageQueue` instances for the used OSAL. + +External Communication +-------------------------- + +The external communication with the mission control system is mostly up to the user implementation. +The FSFW provides PUS Services which can be used to but don't need to be used. +The services can be seen as a conversion from a TC to a message based communication and back. + +TMTC Communication +~~~~~~~~~~~~~~~~~~~ + +The FSFW provides some components to facilitate TMTC handling via the PUS commands. +For example, a UDP or TCP PUS server socket can be opened on a specific port using the +files located in ``osal/common``. The FSFW example uses this functionality to allow sending +telecommands and receiving telemetry using the +`TMTC commander application `_. + +Simple commands like the PUS Service 17 ping service can be tested by simply running the +``tmtc_client_cli.py`` or ``tmtc_client_gui.py`` utility in +the `example tmtc folder `_ +while the `fsfw_example` application is running. + +More generally, any class responsible for handling incoming telecommands and sending telemetry +can implement the generic ``TmTcBridge`` class located in ``tmtcservices``. Many applications +also use a dedicated polling task for reading telecommands which passes telecommands +to the ``TmTcBridge`` implementation. + +CCSDS Frames, CCSDS Space Packets and PUS +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If the communication is based on CCSDS Frames and Space Packets, several classes can be used to +distributed the packets to the corresponding services. Those can be found in ``tcdistribution``. +If Space Packets are used, a timestamper has to be provided by the user. +An example can be found in the ``timemanager`` folder, which uses ``CCSDSTime::CDS_short``. + +Device Handlers +-------------------------- + +DeviceHandlers are another important component of the FSFW. The idea is, to have a software +counterpart of every physical device to provide a simple mode, health and commanding interface. +By separating the underlying Communication Interface with +``DeviceCommunicationIF``, a device handler (DH) can be tested on different hardware. +The DH has mechanisms to monitor the communication with the physical device which allow +for FDIR reaction. Device Handlers can be created by implementing ``DeviceHandlerBase``. +A standard FDIR component for the DH will be created automatically but can +be overwritten by the user. More information on DeviceHandlers can be found in the +related [documentation section](doc/README-devicehandlers.md#top). + +Modes and Health +-------------------- + +The two interfaces ``HasModesIF`` and ``HasHealthIF`` provide access for commanding and monitoring +of components. On-board mode management is implement in hierarchy system. + +- Device handlers and controllers are the lowest part of the hierarchy. +- The next layer are assemblies. Those assemblies act as a component which handle + redundancies of handlers. Assemblies share a common core with the top level subsystem components +- The top level subsystem components are used to group assemblies, controllers and device handlers. + For example, a spacecraft can have a atttitude control subsystem and a power subsystem. + +Those assemblies are intended to act as auto-generated components from a database which describes +the subsystem modes. The definitions contain transition and target tables which contain the DH, +Assembly and Controller Modes to be commanded. +Transition tables contain as many steps as needed to reach the mode from any other mode, e.g. a +switch into any higher AOCS mode might first turn on the sensors, than the actuators and the +controller as last component. +The target table is used to describe the state that is checked continuously by the subsystem. +All of this allows System Modes to be generated as Subsystem object as well from the same database. +This System contains list of subsystem modes in the transition and target tables. +Therefore, it allows a modular system to create system modes and easy commanding of those, because +only the highest components must be commanded. + +The health state represents if the component is able to perform its tasks. +This can be used to signal the system to avoid using this component instead of a redundant one. +The on-board FDIR uses the health state for isolation and recovery. diff --git a/doc/images/PoolArchitecture.png b/docs/images/PoolArchitecture.png similarity index 100% rename from doc/images/PoolArchitecture.png rename to docs/images/PoolArchitecture.png diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 00000000..b37c0904 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,69 @@ +.. Flight Software Framework documentation master file, created by + sphinx-quickstart on Tue Nov 30 10:56:03 2021. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Flight Software Framework (FSFW) documentation +================================================ + +.. image:: ../misc/logo/FSFW_Logo_V3_bw.png + :alt: FSFW Logo + +The Flight Software Framework is a C++ Object Oriented Framework for unmanned, +automated systems like Satellites. + +The initial version of the Flight Software Framework was developed during +the Flying Laptop Project by the University of Stuttgart in cooperation +with Airbus Defence and Space GmbH. + +Quick facts +--------------- + +The framework is designed for systems, which communicate with external devices, perform control +loops, receive telecommands and send telemetry, and need to maintain a high level of availability. +Therefore, a mode and health system provides control over the states of the software and the +controlled devices. In addition, a simple mechanism of event based fault detection, isolation and +recovery is implemented as well. + +The FSFW provides abstraction layers for operating systems to provide a uniform operating system +abstraction layer (OSAL). Some components of this OSAL are required internally by the FSFW but is +also very useful for developers to implement the same application logic on different operating +systems with a uniform interface. + +Currently, the FSFW provides the following OSALs: + +- Linux +- Host +- FreeRTOS +- RTEMS + +The recommended hardware is a microprocessor with more than 1 MB of RAM and 1 MB of non-volatile +memory. For reference, current applications use a Cobham Gaisler UT699 (LEON3FT), a +ISISPACE IOBC or a Zynq-7020 SoC. The ``fsfw`` was also successfully run on the +STM32H743ZI-Nucleo board and on a Raspberry Pi and is currently running on the active +satellite mission Flying Laptop. + +Index +------- + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + getting_started + highlevel + core + config + osal + pus + devicehandlers + controllers + localpools + api + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/docs/localpools.rst b/docs/localpools.rst new file mode 100644 index 00000000..d2afd0a0 --- /dev/null +++ b/docs/localpools.rst @@ -0,0 +1,181 @@ +Local Data Pools +========================================= + +The following text is targeted towards mission software developers which would like +to use the local data pools provided by the FSFW to store data like sensor values so they can be +used by other software objects like controllers as well. If a custom class should have a local +pool which can be used by other software objects as well, following steps have to be performed: + +1. Create a ``LocalDataPoolManager`` member object in the custom class +2. Implement the ``HasLocalDataPoolIF`` with specifies the interface between the local pool + manager and the class owning the local pool. + +The local data pool manager is also able to process housekeeping service requests in form +of messages, generate periodic housekeeping packet, generate notification and snapshots of changed +variables and datasets and process notifications and snapshots coming from other objects. +The two former tasks are related to the external interface using telemetry and telecommands (TMTC) +while the later two are related to data consumers like controllers only acting on data change +detected by the data creator instead of checking the data manually each cycle. Two important +framework classes ``DeviceHandlerBase`` and ``ExtendedControllerBase`` already perform the two steps +shown above so the steps required are altered slightly. + +Storing and Accessing pool data +------------------------------------- + +The pool manager is responsible for thread-safe access of the pool data, but the actual +access to the pool data from the point of view of a mission software developer happens via proxy +classes like pool variable classes. These classes store a copy +of the pool variable with the matching datatype and copy the actual data from the local pool +on a ``read`` call. Changed variables can then be written to the local pool with a ``commit`` call. +The ``read`` and ``commit`` calls are thread-safe and can be called concurrently from data creators +and data consumers. Generally, a user will create a dataset class which in turn groups all +cohesive pool variables. These sets simply iterator over the list of variables and call the +``read`` and ``commit`` functions of each variable. The following diagram shows the +high-level architecture of the local data pools. + +.. image:: ../docs/images/PoolArchitecture.png + :alt: Pool Architecture + +An example is shown for using the local data pools with a Gyroscope. +For example, the following code shows an implementation to access data from a Gyroscope taken +from the SOURCE CubeSat project: + +.. code-block:: cpp + + class GyroPrimaryDataset: public StaticLocalDataSet<3 * sizeof(float)> { + public: + /** + * Constructor for data users + * @param gyroId + */ + GyroPrimaryDataset(object_id_t gyroId): + StaticLocalDataSet(sid_t(gyroId, gyrodefs::GYRO_DATA_SET_ID)) { + setAllVariablesReadOnly(); + } + + lp_var_t angVelocityX = lp_var_t(sid.objectId, + gyrodefs::ANGULAR_VELOCITY_X, this); + lp_var_t angVelocityY = lp_var_t(sid.objectId, + gyrodefs::ANGULAR_VELOCITY_Y, this); + lp_var_t angVelocityZ = lp_var_t(sid.objectId, + gyrodefs::ANGULAR_VELOCITY_Z, this); + private: + + friend class GyroHandler; + /** + * Constructor for data creator + * @param hkOwner + */ + GyroPrimaryDataset(HasLocalDataPoolIF* hkOwner): + StaticLocalDataSet(hkOwner, gyrodefs::GYRO_DATA_SET_ID) {} + }; + +There is a public constructor for users which sets all variables to read-only and there is a +constructor for the GyroHandler data creator by marking it private and declaring the ``GyroHandler`` +as a friend class. Both the atittude controller and the ``GyroHandler`` can now +use the same class definition to access the pool variables with ``read`` and ``commit`` semantics +in a thread-safe way. Generally, each class requiring access will have the set class as a member +class. The data creator will also be generally a ``DeviceHandlerBase`` subclass and some additional +steps are necessary to expose the set for housekeeping purposes. + +Using the local data pools in a ``DeviceHandlerBase`` subclass +-------------------------------------------------------------- + +It is very common to store data generated by devices like a sensor into a pool which can +then be used by other objects. Therefore, the ``DeviceHandlerBase`` already has a +local pool. Using the aforementioned example, the ``GyroHandler`` will now have the set class +as a member: + +.. code-block:: cpp + + class GyroHandler: ... { + + public: + ... + private: + ... + GyroPrimaryDataset gyroData; + ... + }; + + +The constructor used for the creators expects the owner class as a parameter, so we initialize +the object in the `GyroHandler` constructor like this: + +.. code-block:: cpp + + GyroHandler::GyroHandler(object_id_t objectId, object_id_t comIF, + CookieIF *comCookie, uint8_t switchId): + DeviceHandlerBase(objectId, comIF, comCookie), switchId(switchId), + gyroData(this) {} + + +We need to assign the set to a reply ID used in the ``DeviceHandlerBase``. +The combination of the ``GyroHandler`` object ID and the reply ID will be the 64-bit structure ID +``sid_t`` and is used to globally identify the set, for example when requesting housekeeping data or +generating update messages. We need to assign our custom set class in some way so that the local +pool manager can access the custom data sets as well. +By default, the ``getDataSetHandle`` will take care of this tasks. The default implementation for a +``DeviceHandlerBase`` subclass will use the internal command map to retrieve +a handle to a dataset from a given reply ID. Therefore, +we assign the set in the ``fillCommandAndReplyMap`` function: + +.. code-block:: cpp + + void GyroHandler::fillCommandAndReplyMap() { + ... + this->insertInCommandAndReplyMap(gyrodefs::GYRO_DATA, 3, &gyroData); + ... + } + + +Now, we need to create the actual pool entries as well, using the ``initializeLocalDataPool`` +function. Here, we also immediately subscribe for periodic housekeeping packets +with an interval of 4 seconds. They are still disabled in this example and can be enabled +with a housekeeping service command. + +.. code-block:: cpp + + ReturnValue_t GyroHandler::initializeLocalDataPool(localpool::DataPool &localDataPoolMap, + LocalDataPoolManager &poolManager) { + localDataPoolMap.emplace(gyrodefs::ANGULAR_VELOCITY_X, + new PoolEntry({0.0})); + localDataPoolMap.emplace(gyrodefs::ANGULAR_VELOCITY_Y, + new PoolEntry({0.0})); + localDataPoolMap.emplace(gyrodefs::ANGULAR_VELOCITY_Z, + new PoolEntry({0.0})); + localDataPoolMap.emplace(gyrodefs::GENERAL_CONFIG_REG42, + new PoolEntry({0})); + localDataPoolMap.emplace(gyrodefs::RANGE_CONFIG_REG43, + new PoolEntry({0})); + + poolManager.subscribeForPeriodicPacket(gyroData.getSid(), false, 4.0, false); + return HasReturnvaluesIF::RETURN_OK; + } + +Now, if we receive some sensor data and converted them into the right format, +we can write it into the pool like this, using a guard class to ensure the set is commited back +in any case: + +.. code-block:: cpp + + PoolReadGuard readHelper(&gyroData); + if(readHelper.getReadResult() == HasReturnvaluesIF::RETURN_OK) { + if(not gyroData.isValid()) { + gyroData.setValidity(true, true); + } + + gyroData.angVelocityX = angularVelocityX; + gyroData.angVelocityY = angularVelocityY; + gyroData.angVelocityZ = angularVelocityZ; + } + + +The guard class will commit the changed data on destruction automatically. + +Using the local data pools in a ``ExtendedControllerBase`` subclass +---------------------------------------------------------------------- + +Coming soon + + diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 00000000..922152e9 --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=. +set BUILDDIR=_build + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/docs/osal.rst b/docs/osal.rst new file mode 100644 index 00000000..7ac66e47 --- /dev/null +++ b/docs/osal.rst @@ -0,0 +1,63 @@ +.. _osal: + +Operating System Abstraction Layer (OSAL) +============================================ + +Some specific information on the provided OSALs are provided. + +Linux +------- + +This OSAL can be used to compile for Linux host systems like Ubuntu 20.04 or for +embedded Linux targets like the Raspberry Pi. This OSAL generally requires threading support +and real-time functionalities. For most UNIX systems, this is done by adding ``-lrt`` and +``-lpthread`` to the linked libraries in the compilation process. The CMake build support provided +will do this automatically for the ``fsfw`` target. It should be noted that most UNIX systems need +to be configured specifically to allow the real-time functionalities required by the FSFW. + +Hosted OSAL +------------------- + +This is the newest OSAL. Support for Semaphores has not been implemented yet and will propably be +implemented as soon as C++20 with Semaphore support has matured. This OSAL can be used to run the +FSFW on any host system, but currently has only been tested on Windows 10 and Ubuntu 20.04. Unlike +the other OSALs, it uses dynamic memory allocation (e.g. for the message queue implementation). +Cross-platform serial port (USB) support might be added soon. + +FreeRTOS OSAL +------------------ + +FreeRTOS is not included and the developer needs to take care of compiling the FreeRTOS sources and +adding the ``FreeRTOSConfig.h`` file location to the include path. This OSAL has only been tested +extensively with the pre-emptive scheduler configuration so far but it should in principle also be +possible to use a cooperative scheduler. It is recommended to use the `heap_4` allocation scheme. +When using newlib (nano), it is also recommended to add ``#define configUSE_NEWLIB_REENTRANT`` to +the FreeRTOS configuration file to ensure thread-safety. + +When using this OSAL, developers also need to provide an implementation for the +``vRequestContextSwitchFromISR`` function. This has been done because the call to request a context +switch from an ISR is generally located in the ``portmacro.h`` header and is different depending on +the target architecture or device. + +RTEMS OSAL +--------------- + +The RTEMS OSAL was the first implemented OSAL which is also used on the active satellite Flying Laptop. + +TCP/IP socket abstraction +------------------------------ + +The Linux and Host OSAL provide abstraction layers for the socket API. Currently, only UDP sockets +have been imlemented. This is very useful to test TMTC handling either on the host computer +directly (targeting localhost with a TMTC application) or on embedded Linux devices, sending +TMTC packets via Ethernet. + +Example Applications +---------------------- + +There are example applications available for each OSAL + +- `Hosted OSAL `_ +- `Linux OSAL for MCUs `_ +- `FreeRTOS OSAL on the STM32H743ZIT `_ +- `RTEMS OSAL on the STM32H743ZIT `_ diff --git a/docs/pus.rst b/docs/pus.rst new file mode 100644 index 00000000..8dbb2104 --- /dev/null +++ b/docs/pus.rst @@ -0,0 +1,2 @@ +PUS Services +============== diff --git a/events/CMakeLists.txt b/events/CMakeLists.txt deleted file mode 100644 index 4e935167..00000000 --- a/events/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -target_sources(${LIB_FSFW_NAME} - PRIVATE - EventManager.cpp - EventMessage.cpp -) - -add_subdirectory(eventmatching) \ No newline at end of file diff --git a/events/EventManager.cpp b/events/EventManager.cpp deleted file mode 100644 index 5b2b31b5..00000000 --- a/events/EventManager.cpp +++ /dev/null @@ -1,177 +0,0 @@ -#include "EventManager.h" -#include "EventMessage.h" - -#include -#include "../serviceinterface/ServiceInterfaceStream.h" -#include "../ipc/QueueFactory.h" -#include "../ipc/MutexFactory.h" - -MessageQueueId_t EventManagerIF::eventmanagerQueue = MessageQueueIF::NO_QUEUE; - -// If one checks registerListener calls, there are around 40 (to max 50) -// objects registering for certain events. -// Each listener requires 1 or 2 EventIdMatcher and 1 or 2 ReportRangeMatcher. -// So a good guess is 75 to a max of 100 pools required for each, which fits well. -const LocalPool::LocalPoolConfig EventManager::poolConfig = { - {fsfwconfig::FSFW_EVENTMGMR_MATCHTREE_NODES, - sizeof(EventMatchTree::Node)}, - {fsfwconfig::FSFW_EVENTMGMT_EVENTIDMATCHERS, - sizeof(EventIdRangeMatcher)}, - {fsfwconfig::FSFW_EVENTMGMR_RANGEMATCHERS, - sizeof(ReporterRangeMatcher)} -}; - -EventManager::EventManager(object_id_t setObjectId) : - SystemObject(setObjectId), - factoryBackend(0, poolConfig, false, true) { - mutex = MutexFactory::instance()->createMutex(); - eventReportQueue = QueueFactory::instance()->createMessageQueue( - MAX_EVENTS_PER_CYCLE, EventMessage::EVENT_MESSAGE_SIZE); -} - -EventManager::~EventManager() { - QueueFactory::instance()->deleteMessageQueue(eventReportQueue); - MutexFactory::instance()->deleteMutex(mutex); -} - -MessageQueueId_t EventManager::getEventReportQueue() { - return eventReportQueue->getId(); -} - -ReturnValue_t EventManager::performOperation(uint8_t opCode) { - ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; - while (result == HasReturnvaluesIF::RETURN_OK) { - EventMessage message; - result = eventReportQueue->receiveMessage(&message); - if (result == HasReturnvaluesIF::RETURN_OK) { -#if FSFW_OBJ_EVENT_TRANSLATION == 1 - printEvent(&message); -#endif - notifyListeners(&message); - } - } - return HasReturnvaluesIF::RETURN_OK; -} - -void EventManager::notifyListeners(EventMessage* message) { - lockMutex(); - for (auto iter = listenerList.begin(); iter != listenerList.end(); ++iter) { - if (iter->second.match(message)) { - MessageQueueSenderIF::sendMessage(iter->first, message, - message->getSender()); - } - } - unlockMutex(); -} - -ReturnValue_t EventManager::registerListener(MessageQueueId_t listener, -bool forwardAllButSelected) { - auto result = listenerList.insert( - std::pair(listener, - EventMatchTree(&factoryBackend, forwardAllButSelected))); - if (!result.second) { - return HasReturnvaluesIF::RETURN_FAILED; - } - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t EventManager::subscribeToEvent(MessageQueueId_t listener, - EventId_t event) { - return subscribeToEventRange(listener, event); -} - -ReturnValue_t EventManager::subscribeToAllEventsFrom(MessageQueueId_t listener, - object_id_t object) { - return subscribeToEventRange(listener, 0, 0, true, object); -} - -ReturnValue_t EventManager::subscribeToEventRange(MessageQueueId_t listener, - EventId_t idFrom, EventId_t idTo, bool idInverted, - object_id_t reporterFrom, object_id_t reporterTo, - bool reporterInverted) { - auto iter = listenerList.find(listener); - if (iter == listenerList.end()) { - return LISTENER_NOT_FOUND; - } - lockMutex(); - ReturnValue_t result = iter->second.addMatch(idFrom, idTo, idInverted, - reporterFrom, reporterTo, reporterInverted); - unlockMutex(); - return result; -} - -ReturnValue_t EventManager::unsubscribeFromEventRange(MessageQueueId_t listener, - EventId_t idFrom, EventId_t idTo, bool idInverted, - object_id_t reporterFrom, object_id_t reporterTo, - bool reporterInverted) { - auto iter = listenerList.find(listener); - if (iter == listenerList.end()) { - return LISTENER_NOT_FOUND; - } - lockMutex(); - ReturnValue_t result = iter->second.removeMatch(idFrom, idTo, idInverted, - reporterFrom, reporterTo, reporterInverted); - unlockMutex(); - return result; -} - -#if FSFW_OBJ_EVENT_TRANSLATION == 1 - -void EventManager::printEvent(EventMessage* message) { - const char *string = 0; - switch (message->getSeverity()) { - case severity::INFO: -#if DEBUG_INFO_EVENT == 1 - string = translateObject(message->getReporter()); -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::info << "EVENT: "; - if (string != 0) { - sif::info << string; - } else { - sif::info << "0x" << std::hex << message->getReporter() << std::dec; - } - sif::info << " reported " << translateEvents(message->getEvent()) << " (" - << std::dec << message->getEventId() << std::hex << ") P1: 0x" - << message->getParameter1() << " P2: 0x" - << message->getParameter2() << std::dec << std::endl; -#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ -#endif /* DEBUG_INFO_EVENT == 1 */ - break; - default: - string = translateObject(message->getReporter()); -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::debug << "EventManager: "; - if (string != 0) { - sif::debug << string; - } - else { - sif::debug << "0x" << std::hex << message->getReporter() << std::dec; - } - sif::debug << " reported " << translateEvents(message->getEvent()) - << " (" << std::dec << message->getEventId() << ") " - << std::endl; - sif::debug << std::hex << "P1 Hex: 0x" << message->getParameter1() - << ", P1 Dec: " << std::dec << message->getParameter1() - << std::endl; - sif::debug << std::hex << "P2 Hex: 0x" << message->getParameter2() - << ", P2 Dec: " << std::dec << message->getParameter2() - << std::endl; -#endif - break; - } -} -#endif - -void EventManager::lockMutex() { - mutex->lockMutex(timeoutType, timeoutMs); -} - -void EventManager::unlockMutex() { - mutex->unlockMutex(); -} - -void EventManager::setMutexTimeout(MutexIF::TimeoutType timeoutType, - uint32_t timeoutMs) { - this->timeoutType = timeoutType; - this->timeoutMs = timeoutMs; -} diff --git a/events/fwSubsystemIdRanges.h b/events/fwSubsystemIdRanges.h deleted file mode 100644 index 1b0b238e..00000000 --- a/events/fwSubsystemIdRanges.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef FSFW_EVENTS_FWSUBSYSTEMIDRANGES_H_ -#define FSFW_EVENTS_FWSUBSYSTEMIDRANGES_H_ - -namespace SUBSYSTEM_ID { -enum { - MEMORY = 22, - OBSW = 26, - CDH = 28, - TCS_1 = 59, - PCDU_1 = 42, - PCDU_2 = 43, - HEATER = 50, - T_SENSORS = 52, - FDIR = 70, - FDIR_1 = 71, - FDIR_2 = 72, - HK = 73, - SYSTEM_MANAGER = 74, - SYSTEM_MANAGER_1 = 75, - SYSTEM_1 = 79, - PUS_SERVICE_1 = 80, - PUS_SERVICE_9 = 89, - PUS_SERVICE_17 = 97, - FW_SUBSYSTEM_ID_RANGE -}; -} - - - -#endif /* FSFW_EVENTS_FWSUBSYSTEMIDRANGES_H_ */ diff --git a/fsfw.mk b/fsfw.mk deleted file mode 100644 index 0d72fae1..00000000 --- a/fsfw.mk +++ /dev/null @@ -1,75 +0,0 @@ -# This submake file needs to be included by the primary Makefile. -# This file needs FRAMEWORK_PATH and OS_FSFW set correctly by another Makefile. -# Valid API settings: rtems, linux, freeRTOS, host - -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/action/*.cpp) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/container/*.cpp) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/contrib/sgp4/*.cpp) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/controller/*.cpp) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/coordinates/*.cpp) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/datalinklayer/*.cpp) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/datapool/*.cpp) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/datapoollocal/*.cpp) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/datapoollocal/internal/*.cpp) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/housekeeping/*.cpp) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/devicehandlers/*.cpp) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/events/*.cpp) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/events/eventmatching/*.cpp) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/fdir/*.cpp) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/globalfunctions/*.cpp) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/globalfunctions/matching/*.cpp) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/globalfunctions/math/*.cpp) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/health/*.cpp) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/internalError/*.cpp) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/ipc/*.cpp) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/memory/*.cpp) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/modes/*.cpp) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/monitoring/*.cpp) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/objectmanager/*.cpp) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/osal/*.cpp) - -# select the OS -ifeq ($(OS_FSFW),rtems) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/osal/rtems/*.cpp) - -else ifeq ($(OS_FSFW),linux) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/osal/linux/*.cpp) - -else ifeq ($(OS_FSFW),freeRTOS) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/osal/FreeRTOS/*.cpp) - -else ifeq ($(OS_FSFW),host) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/osal/host/*.cpp) -ifeq ($(OS),Windows_NT) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/osal/windows/*.cpp) -else -# For now, the linux UDP bridge sources needs to be included manually by upper makefile -# for host OS because we can't be sure the OS is linux. -# Following lines can be used to do this: -# CXXSRC += $(FRAMEWORK_PATH)/osal/linux/TcUnixUdpPollingTask.cpp -# CXXSRC += $(FRAMEWORK_PATH)/osal/linux/TmTcUnixUdpBridge.cpp -endif - -else -$(error invalid OS_FSFW specified, valid OS_FSFW are rtems, linux, freeRTOS, host) -endif - -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/parameters/*.cpp) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/power/*.cpp) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/returnvalues/*.cpp) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/rmap/*.cpp) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/serialize/*.cpp) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/serviceinterface/*.cpp) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/storagemanager/*.cpp) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/subsystem/*.cpp) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/subsystem/modes/*.cpp) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/tasks/*.cpp) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/tcdistribution/*.cpp) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/thermal/*.cpp) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/timemanager/*.cpp) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/tmstorage/*.cpp) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/tmtcpacket/*.cpp) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/tmtcpacket/packetmatcher/*.cpp) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/tmtcpacket/pus/*.cpp) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/tmtcservices/*.cpp) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/pus/*.cpp) diff --git a/globalfunctions/DleEncoder.cpp b/globalfunctions/DleEncoder.cpp deleted file mode 100644 index 8520389d..00000000 --- a/globalfunctions/DleEncoder.cpp +++ /dev/null @@ -1,124 +0,0 @@ -#include "../globalfunctions/DleEncoder.h" - -DleEncoder::DleEncoder() {} - -DleEncoder::~DleEncoder() {} - -ReturnValue_t DleEncoder::encode(const uint8_t* sourceStream, - size_t sourceLen, uint8_t* destStream, size_t maxDestLen, - size_t* encodedLen, bool addStxEtx) { - if (maxDestLen < 2) { - return STREAM_TOO_SHORT; - } - size_t encodedIndex = 0, sourceIndex = 0; - uint8_t nextByte; - if (addStxEtx) { - destStream[0] = STX_CHAR; - ++encodedIndex; - } - - while (encodedIndex < maxDestLen and sourceIndex < sourceLen) - { - nextByte = sourceStream[sourceIndex]; - // STX, ETX and CR characters in the stream need to be escaped with DLE - if (nextByte == STX_CHAR or nextByte == ETX_CHAR or nextByte == CARRIAGE_RETURN) { - if (encodedIndex + 1 >= maxDestLen) { - return STREAM_TOO_SHORT; - } - else { - destStream[encodedIndex] = DLE_CHAR; - ++encodedIndex; - /* Escaped byte will be actual byte + 0x40. This prevents - * STX, ETX, and carriage return characters from appearing - * in the encoded data stream at all, so when polling an - * encoded stream, the transmission can be stopped at ETX. - * 0x40 was chosen at random with special requirements: - * - Prevent going from one control char to another - * - Prevent overflow for common characters */ - destStream[encodedIndex] = nextByte + 0x40; - } - } - // DLE characters are simply escaped with DLE. - else if (nextByte == DLE_CHAR) { - if (encodedIndex + 1 >= maxDestLen) { - return STREAM_TOO_SHORT; - } - else { - destStream[encodedIndex] = DLE_CHAR; - ++encodedIndex; - destStream[encodedIndex] = DLE_CHAR; - } - } - else { - destStream[encodedIndex] = nextByte; - } - ++encodedIndex; - ++sourceIndex; - } - - if (sourceIndex == sourceLen and encodedIndex < maxDestLen) { - if (addStxEtx) { - destStream[encodedIndex] = ETX_CHAR; - ++encodedIndex; - } - *encodedLen = encodedIndex; - return RETURN_OK; - } - else { - return STREAM_TOO_SHORT; - } -} - -ReturnValue_t DleEncoder::decode(const uint8_t *sourceStream, - size_t sourceStreamLen, size_t *readLen, uint8_t *destStream, - size_t maxDestStreamlen, size_t *decodedLen) { - size_t encodedIndex = 0, decodedIndex = 0; - uint8_t nextByte; - if (*sourceStream != STX_CHAR) { - return DECODING_ERROR; - } - ++encodedIndex; - - while ((encodedIndex < sourceStreamLen) && (decodedIndex < maxDestStreamlen) - && (sourceStream[encodedIndex] != ETX_CHAR) - && (sourceStream[encodedIndex] != STX_CHAR)) { - if (sourceStream[encodedIndex] == DLE_CHAR) { - nextByte = sourceStream[encodedIndex + 1]; - // The next byte is a DLE character that was escaped by another - // DLE character, so we can write it to the destination stream. - if (nextByte == DLE_CHAR) { - destStream[decodedIndex] = nextByte; - } - else { - /* The next byte is a STX, DTX or 0x0D character which - * was escaped by a DLE character. The actual byte was - * also encoded by adding + 0x40 to prevent having control chars, - * in the stream at all, so we convert it back. */ - if (nextByte == 0x42 or nextByte == 0x43 or nextByte == 0x4D) { - destStream[decodedIndex] = nextByte - 0x40; - } - else { - return DECODING_ERROR; - } - } - ++encodedIndex; - } - else { - destStream[decodedIndex] = sourceStream[encodedIndex]; - } - - ++encodedIndex; - ++decodedIndex; - } - - if (sourceStream[encodedIndex] != ETX_CHAR) { - *readLen = ++encodedIndex; - return DECODING_ERROR; - } - else { - *readLen = ++encodedIndex; - *decodedLen = decodedIndex; - return RETURN_OK; - } -} - diff --git a/globalfunctions/DleEncoder.h b/globalfunctions/DleEncoder.h deleted file mode 100644 index 6d073f9a..00000000 --- a/globalfunctions/DleEncoder.h +++ /dev/null @@ -1,79 +0,0 @@ -#ifndef FRAMEWORK_GLOBALFUNCTIONS_DLEENCODER_H_ -#define FRAMEWORK_GLOBALFUNCTIONS_DLEENCODER_H_ - -#include "../returnvalues/HasReturnvaluesIF.h" -#include - -/** - * @brief This DLE Encoder (Data Link Encoder) can be used to encode and - * decode arbitrary data with ASCII control characters - * @details - * List of control codes: - * https://en.wikipedia.org/wiki/C0_and_C1_control_codes - * - * This encoder can be used to achieve a basic transport layer when using - * char based transmission systems. - * The passed source strean is converted into a encoded stream by adding - * a STX marker at the start of the stream and an ETX marker at the end of - * the stream. Any STX, ETX, DLE and CR occurrences in the source stream are - * escaped by a DLE character. The encoder also replaces escaped control chars - * by another char, so STX, ETX and CR should not appear anywhere in the actual - * encoded data stream. - * - * When using a strictly char based reception of packets encoded with DLE, - * STX can be used to notify a reader that actual data will start to arrive - * while ETX can be used to notify the reader that the data has ended. - */ -class DleEncoder: public HasReturnvaluesIF { -private: - DleEncoder(); - virtual ~DleEncoder(); - -public: - static constexpr uint8_t INTERFACE_ID = CLASS_ID::DLE_ENCODER; - static constexpr ReturnValue_t STREAM_TOO_SHORT = MAKE_RETURN_CODE(0x01); - static constexpr ReturnValue_t DECODING_ERROR = MAKE_RETURN_CODE(0x02); - - //! Start Of Text character. First character is encoded stream - static constexpr uint8_t STX_CHAR = 0x02; - //! End Of Text character. Last character in encoded stream - static constexpr uint8_t ETX_CHAR = 0x03; - //! Data Link Escape character. Used to escape STX, ETX and DLE occurrences - //! in the source stream. - static constexpr uint8_t DLE_CHAR = 0x10; - static constexpr uint8_t CARRIAGE_RETURN = 0x0D; - - /** - * Encodes the give data stream by preceding it with the STX marker - * and ending it with an ETX marker. STX, ETX and DLE characters inside - * the stream are escaped by DLE characters and also replaced by adding - * 0x40 (which is reverted in the decoding process). - * @param sourceStream - * @param sourceLen - * @param destStream - * @param maxDestLen - * @param encodedLen - * @param addStxEtx - * Adding STX and ETX can be omitted, if they are added manually. - * @return - */ - static ReturnValue_t encode(const uint8_t *sourceStream, size_t sourceLen, - uint8_t *destStream, size_t maxDestLen, size_t *encodedLen, - bool addStxEtx = true); - - /** - * Converts an encoded stream back. - * @param sourceStream - * @param sourceStreamLen - * @param readLen - * @param destStream - * @param maxDestStreamlen - * @param decodedLen - * @return - */ - static ReturnValue_t decode(const uint8_t *sourceStream, - size_t sourceStreamLen, size_t *readLen, uint8_t *destStream, - size_t maxDestStreamlen, size_t *decodedLen); -}; - -#endif /* FRAMEWORK_GLOBALFUNCTIONS_DLEENCODER_H_ */ diff --git a/globalfunctions/PeriodicOperationDivider.cpp b/globalfunctions/PeriodicOperationDivider.cpp deleted file mode 100644 index 28e98feb..00000000 --- a/globalfunctions/PeriodicOperationDivider.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "PeriodicOperationDivider.h" - - -PeriodicOperationDivider::PeriodicOperationDivider(uint32_t divider, - bool resetAutomatically): resetAutomatically(resetAutomatically), - counter(divider), divider(divider) { -} - -bool PeriodicOperationDivider::checkAndIncrement() { - bool opNecessary = check(); - if(opNecessary) { - if(resetAutomatically) { - counter = 0; - } - return opNecessary; - } - counter ++; - return opNecessary; -} - -bool PeriodicOperationDivider::check() { - if(counter >= divider) { - return true; - } - return false; -} - - - -void PeriodicOperationDivider::resetCounter() { - counter = 0; -} - -void PeriodicOperationDivider::setDivider(uint32_t newDivider) { - divider = newDivider; -} - -uint32_t PeriodicOperationDivider::getCounter() const { - return counter; -} - -uint32_t PeriodicOperationDivider::getDivider() const { - return divider; -} diff --git a/globalfunctions/PeriodicOperationDivider.h b/globalfunctions/PeriodicOperationDivider.h deleted file mode 100644 index 7f7fb469..00000000 --- a/globalfunctions/PeriodicOperationDivider.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef FSFW_GLOBALFUNCTIONS_PERIODICOPERATIONDIVIDER_H_ -#define FSFW_GLOBALFUNCTIONS_PERIODICOPERATIONDIVIDER_H_ - -#include - -/** - * @brief Lightweight helper class to facilitate periodic operation with - * decreased frequencies. - * @details - * This class is useful to perform operations which have to be performed - * with a reduced frequency, like debugging printouts in high periodic tasks - * or low priority operations. - */ -class PeriodicOperationDivider { -public: - /** - * Initialize with the desired divider and specify whether the internal - * counter will be reset automatically. - * @param divider - * @param resetAutomatically - */ - PeriodicOperationDivider(uint32_t divider, bool resetAutomatically = true); - - - /** - * Check whether operation is necessary. - * If an operation is necessary and the class has been - * configured to be reset automatically, the counter will be reset. - * - * @return - * -@c true if the counter is larger or equal to the divider - * -@c false otherwise - */ - bool checkAndIncrement(); - - /** - * Checks whether an operation is necessary. - * This function will not increment the counter! - * @return - * -@c true if the counter is larger or equal to the divider - * -@c false otherwise - */ - bool check(); - - /** - * Can be used to reset the counter to 0 manually. - */ - void resetCounter(); - uint32_t getCounter() const; - - /** - * Can be used to set a new divider value. - * @param newDivider - */ - void setDivider(uint32_t newDivider); - uint32_t getDivider() const; -private: - bool resetAutomatically = true; - uint32_t counter = 0; - uint32_t divider = 0; -}; - - - -#endif /* FSFW_GLOBALFUNCTIONS_PERIODICOPERATIONDIVIDER_H_ */ diff --git a/globalfunctions/bitutility.h b/globalfunctions/bitutility.h deleted file mode 100644 index 1fc1290d..00000000 --- a/globalfunctions/bitutility.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef FSFW_GLOBALFUNCTIONS_BITUTIL_H_ -#define FSFW_GLOBALFUNCTIONS_BITUTIL_H_ - -#include - -namespace bitutil { - -/* Helper functions for manipulating the individual bits of a byte. -Position refers to n-th bit of a byte, going from 0 (most significant bit) to -7 (least significant bit) */ -void bitSet(uint8_t* byte, uint8_t position); -void bitToggle(uint8_t* byte, uint8_t position); -void bitClear(uint8_t* byte, uint8_t position); -bool bitGet(const uint8_t* byte, uint8_t position); - -} - -#endif /* FSFW_GLOBALFUNCTIONS_BITUTIL_H_ */ diff --git a/hal/CMakeLists.txt b/hal/CMakeLists.txt new file mode 100644 index 00000000..7a9a0ffa --- /dev/null +++ b/hal/CMakeLists.txt @@ -0,0 +1,41 @@ +cmake_minimum_required(VERSION 3.13) + +# Can also be changed by upper CMakeLists.txt file +find_library(LIB_FSFW_NAME fsfw REQUIRED) + +option(FSFW_HAL_ADD_LINUX "Add the Linux HAL to the sources. Required gpiod library" OFF) +option(FSFW_HAL_ADD_RASPBERRY_PI "Add Raspberry Pi specific code to the sources" OFF) +option(FSFW_HAL_ADD_STM32H7 "Add the STM32H7 HAL to the sources" OFF) +option(FSFW_HAL_WARNING_SHADOW_LOCAL_GCC "Enable -Wshadow=local warning in GCC" ON) + +set(LINUX_HAL_PATH_NAME linux) +set(STM32H7_PATH_NAME stm32h7) + +add_subdirectory(src) + +foreach(INCLUDE_PATH ${FSFW_HAL_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(CMAKE_VERBOSE) + message(STATUS "FSFW include path: ${CURR_ABS_INC_PATH}") + endif() + + list(APPEND FSFW_HAL_ADD_INC_PATHS_ABS ${CURR_ABS_INC_PATH}) +endforeach() + +target_include_directories(${LIB_FSFW_NAME} PRIVATE + ${FSFW_HAL_ADD_INC_PATHS_ABS} +) + +target_compile_definitions(${LIB_FSFW_NAME} PRIVATE + ${FSFW_HAL_DEFINES} +) + +target_link_libraries(${LIB_FSFW_NAME} PRIVATE + ${FSFW_HAL_LINK_LIBS} +) diff --git a/hal/src/CMakeLists.txt b/hal/src/CMakeLists.txt new file mode 100644 index 00000000..76ee45c6 --- /dev/null +++ b/hal/src/CMakeLists.txt @@ -0,0 +1,9 @@ +target_include_directories(${LIB_FSFW_NAME} PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} +) + +target_include_directories(${LIB_FSFW_NAME} INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR} +) + +add_subdirectory(fsfw_hal) diff --git a/hal/src/fsfw_hal/CMakeLists.txt b/hal/src/fsfw_hal/CMakeLists.txt new file mode 100644 index 00000000..f5901e91 --- /dev/null +++ b/hal/src/fsfw_hal/CMakeLists.txt @@ -0,0 +1,10 @@ +add_subdirectory(devicehandlers) +add_subdirectory(common) + +if(FSFW_HAL_ADD_LINUX) + add_subdirectory(linux) +endif() + +if(FSFW_HAL_ADD_STM32H7) + add_subdirectory(stm32h7) +endif() diff --git a/hal/src/fsfw_hal/common/CMakeLists.txt b/hal/src/fsfw_hal/common/CMakeLists.txt new file mode 100644 index 00000000..f1cfec52 --- /dev/null +++ b/hal/src/fsfw_hal/common/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(gpio) diff --git a/hal/src/fsfw_hal/common/gpio/CMakeLists.txt b/hal/src/fsfw_hal/common/gpio/CMakeLists.txt new file mode 100644 index 00000000..098c05fa --- /dev/null +++ b/hal/src/fsfw_hal/common/gpio/CMakeLists.txt @@ -0,0 +1,3 @@ +target_sources(${LIB_FSFW_NAME} PRIVATE + GpioCookie.cpp +) \ No newline at end of file diff --git a/hal/src/fsfw_hal/common/gpio/GpioCookie.cpp b/hal/src/fsfw_hal/common/gpio/GpioCookie.cpp new file mode 100644 index 00000000..7c56ebcf --- /dev/null +++ b/hal/src/fsfw_hal/common/gpio/GpioCookie.cpp @@ -0,0 +1,50 @@ +#include "fsfw_hal/common/gpio/GpioCookie.h" +#include "fsfw/serviceinterface/ServiceInterface.h" + +GpioCookie::GpioCookie() { +} + +ReturnValue_t GpioCookie::addGpio(gpioId_t gpioId, GpioBase* gpioConfig) { + if (gpioConfig == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "GpioCookie::addGpio: gpioConfig is nullpointer" << std::endl; +#else + sif::printWarning("GpioCookie::addGpio: gpioConfig is nullpointer\n"); +#endif + return HasReturnvaluesIF::RETURN_FAILED; + } + auto gpioMapIter = gpioMap.find(gpioId); + if(gpioMapIter == gpioMap.end()) { + auto statusPair = gpioMap.emplace(gpioId, gpioConfig); + if (statusPair.second == false) { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "GpioCookie::addGpio: Failed to add GPIO " << gpioId << + " to GPIO map" << std::endl; +#else + sif::printWarning("GpioCookie::addGpio: Failed to add GPIO %d to GPIO map\n", gpioId); +#endif +#endif + return HasReturnvaluesIF::RETURN_FAILED; + } + return HasReturnvaluesIF::RETURN_OK; + } +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "GpioCookie::addGpio: GPIO already exists in GPIO map " << std::endl; +#else + sif::printWarning("GpioCookie::addGpio: GPIO already exists in GPIO map\n"); +#endif +#endif + return HasReturnvaluesIF::RETURN_FAILED; +} + +GpioMap GpioCookie::getGpioMap() const { + return gpioMap; +} + +GpioCookie::~GpioCookie() { + for(auto& config: gpioMap) { + delete(config.second); + } +} diff --git a/hal/src/fsfw_hal/common/gpio/GpioCookie.h b/hal/src/fsfw_hal/common/gpio/GpioCookie.h new file mode 100644 index 00000000..0473fe0f --- /dev/null +++ b/hal/src/fsfw_hal/common/gpio/GpioCookie.h @@ -0,0 +1,41 @@ +#ifndef COMMON_GPIO_GPIOCOOKIE_H_ +#define COMMON_GPIO_GPIOCOOKIE_H_ + +#include "GpioIF.h" +#include "gpioDefinitions.h" + +#include +#include + +/** + * @brief Cookie for the GpioIF. Allows the GpioIF to determine which + * GPIOs to initialize and whether they should be configured as in- or + * output. + * @details One GpioCookie can hold multiple GPIO configurations. To add a new + * GPIO configuration to a GpioCookie use the GpioCookie::addGpio + * function. + * + * @author J. Meier + */ +class GpioCookie: public CookieIF { +public: + + GpioCookie(); + + virtual ~GpioCookie(); + + ReturnValue_t addGpio(gpioId_t gpioId, GpioBase* gpioConfig); + + /** + * @brief Get map with registered GPIOs. + */ + GpioMap getGpioMap() const; + +private: + /** + * Returns a copy of the internal GPIO map. + */ + GpioMap gpioMap; +}; + +#endif /* COMMON_GPIO_GPIOCOOKIE_H_ */ diff --git a/hal/src/fsfw_hal/common/gpio/GpioIF.h b/hal/src/fsfw_hal/common/gpio/GpioIF.h new file mode 100644 index 00000000..af73f94c --- /dev/null +++ b/hal/src/fsfw_hal/common/gpio/GpioIF.h @@ -0,0 +1,54 @@ +#ifndef COMMON_GPIO_GPIOIF_H_ +#define COMMON_GPIO_GPIOIF_H_ + +#include "gpioDefinitions.h" +#include +#include + +class GpioCookie; + +/** + * @brief This class defines the interface for objects requiring the control + * over GPIOs. + * @author J. Meier + */ +class GpioIF : public HasReturnvaluesIF { +public: + + virtual ~GpioIF() {}; + + /** + * @brief Called by the GPIO using object. + * @param cookie Cookie specifying informations of the GPIOs required + * by a object. + */ + virtual ReturnValue_t addGpios(GpioCookie* cookie) = 0; + + /** + * @brief By implementing this function a child must provide the + * functionality to pull a certain GPIO to high logic level. + * + * @param gpioId A unique number which specifies the GPIO to drive. + * @return Returns RETURN_OK for success. This should never return RETURN_FAILED. + */ + virtual ReturnValue_t pullHigh(gpioId_t gpioId) = 0; + + /** + * @brief By implementing this function a child must provide the + * functionality to pull a certain GPIO to low logic level. + * + * @param gpioId A unique number which specifies the GPIO to drive. + */ + virtual ReturnValue_t pullLow(gpioId_t gpioId) = 0; + + /** + * @brief This function requires a child to implement the functionality to read the state of + * an ouput or input gpio. + * + * @param gpioId A unique number which specifies the GPIO to read. + * @param gpioState State of GPIO will be written to this pointer. + */ + virtual ReturnValue_t readGpio(gpioId_t gpioId, int* gpioState) = 0; +}; + +#endif /* COMMON_GPIO_GPIOIF_H_ */ diff --git a/hal/src/fsfw_hal/common/gpio/gpioDefinitions.h b/hal/src/fsfw_hal/common/gpio/gpioDefinitions.h new file mode 100644 index 00000000..c6f21195 --- /dev/null +++ b/hal/src/fsfw_hal/common/gpio/gpioDefinitions.h @@ -0,0 +1,170 @@ +#ifndef COMMON_GPIO_GPIODEFINITIONS_H_ +#define COMMON_GPIO_GPIODEFINITIONS_H_ + +#include +#include +#include + +using gpioId_t = uint16_t; + +namespace gpio { + +enum Levels: uint8_t { + LOW = 0, + HIGH = 1, + NONE = 99 +}; + +enum Direction: uint8_t { + IN = 0, + OUT = 1 +}; + +enum GpioOperation { + READ, + WRITE +}; + +enum class GpioTypes { + NONE, + GPIO_REGULAR_BY_CHIP, + GPIO_REGULAR_BY_LABEL, + GPIO_REGULAR_BY_LINE_NAME, + CALLBACK +}; + +static constexpr gpioId_t NO_GPIO = -1; + +using gpio_cb_t = void (*) (gpioId_t gpioId, gpio::GpioOperation gpioOp, gpio::Levels value, + void* args); + +} + +/** + * @brief Struct containing information about the GPIO to use. This is + * required by the libgpiod to access and drive a GPIO. + * @param chipname String of the chipname specifying the group which contains the GPIO to + * access. E.g. gpiochip0. To detect names of GPIO groups run gpiodetect on + * the linux command line. + * @param lineNum The offset of the GPIO within the GPIO group. + * @param consumer Name of the consumer. Simply a description of the GPIO configuration. + * @param direction Specifies whether the GPIO should be used as in- or output. + * @param initValue Defines the initial state of the GPIO when configured as output. + * Only required for output GPIOs. + * @param lineHandle The handle returned by gpiod_chip_get_line will be later written to this + * pointer. + */ +class GpioBase { +public: + + GpioBase() = default; + + GpioBase(gpio::GpioTypes gpioType, std::string consumer, gpio::Direction direction, + gpio::Levels initValue): + gpioType(gpioType), consumer(consumer),direction(direction), initValue(initValue) {} + + virtual~ GpioBase() {}; + + // Can be used to cast GpioBase to a concrete child implementation + gpio::GpioTypes gpioType = gpio::GpioTypes::NONE; + std::string consumer; + gpio::Direction direction = gpio::Direction::IN; + gpio::Levels initValue = gpio::Levels::NONE; +}; + +class GpiodRegularBase: public GpioBase { +public: + GpiodRegularBase(gpio::GpioTypes gpioType, std::string consumer, gpio::Direction direction, + gpio::Levels initValue, int lineNum): + GpioBase(gpioType, consumer, direction, initValue), lineNum(lineNum) { + } + + // line number will be configured at a later point for the open by line name configuration + GpiodRegularBase(gpio::GpioTypes gpioType, std::string consumer, gpio::Direction direction, + gpio::Levels initValue): GpioBase(gpioType, consumer, direction, initValue) { + } + + int lineNum = 0; + struct gpiod_line* lineHandle = nullptr; +}; + +class GpiodRegularByChip: public GpiodRegularBase { +public: + GpiodRegularByChip() : + GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_CHIP, + std::string(), gpio::Direction::IN, gpio::LOW, 0) { + } + + GpiodRegularByChip(std::string chipname_, int lineNum_, std::string consumer_, + gpio::Direction direction_, gpio::Levels initValue_) : + GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_CHIP, + consumer_, direction_, initValue_, lineNum_), + chipname(chipname_){ + } + + GpiodRegularByChip(std::string chipname_, int lineNum_, std::string consumer_) : + GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_CHIP, consumer_, + gpio::Direction::IN, gpio::LOW, lineNum_), + chipname(chipname_) { + } + + std::string chipname; +}; + +class GpiodRegularByLabel: public GpiodRegularBase { +public: + GpiodRegularByLabel(std::string label_, int lineNum_, std::string consumer_, + gpio::Direction direction_, gpio::Levels initValue_) : + GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_LABEL, consumer_, + direction_, initValue_, lineNum_), + label(label_) { + } + + GpiodRegularByLabel(std::string label_, int lineNum_, std::string consumer_) : + GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_LABEL, consumer_, + gpio::Direction::IN, gpio::LOW, lineNum_), + label(label_) { + } + + std::string label; +}; + +/** + * @brief Passing this GPIO configuration to the GPIO IF object will try to open the GPIO by its + * line name. This line name can be set in the device tree and must be unique. Otherwise + * the driver will open the first line with the given name. + */ +class GpiodRegularByLineName: public GpiodRegularBase { +public: + GpiodRegularByLineName(std::string lineName_, std::string consumer_, gpio::Direction direction_, + gpio::Levels initValue_) : + GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME, consumer_, direction_, + initValue_), lineName(lineName_) { + } + + GpiodRegularByLineName(std::string lineName_, std::string consumer_) : + GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME, consumer_, + gpio::Direction::IN, gpio::LOW), lineName(lineName_) { + } + + std::string lineName; +}; + +class GpioCallback: public GpioBase { +public: + GpioCallback(std::string consumer, gpio::Direction direction_, gpio::Levels initValue_, + gpio::gpio_cb_t callback, void* callbackArgs): + GpioBase(gpio::GpioTypes::CALLBACK, consumer, direction_, initValue_), + callback(callback), callbackArgs(callbackArgs) {} + + gpio::gpio_cb_t callback = nullptr; + void* callbackArgs = nullptr; +}; + + +using GpioMap = std::map; +using GpioUnorderedMap = std::unordered_map; +using GpioMapIter = GpioMap::iterator; +using GpioUnorderedMapIter = GpioUnorderedMap::iterator; + +#endif /* LINUX_GPIO_GPIODEFINITIONS_H_ */ diff --git a/hal/src/fsfw_hal/common/spi/spiCommon.h b/hal/src/fsfw_hal/common/spi/spiCommon.h new file mode 100644 index 00000000..9b3aef6a --- /dev/null +++ b/hal/src/fsfw_hal/common/spi/spiCommon.h @@ -0,0 +1,17 @@ +#ifndef FSFW_HAL_COMMON_SPI_SPICOMMON_H_ +#define FSFW_HAL_COMMON_SPI_SPICOMMON_H_ + +#include + +namespace spi { + +enum SpiModes: uint8_t { + MODE_0, + MODE_1, + MODE_2, + MODE_3 +}; + +} + +#endif /* FSFW_HAL_COMMON_SPI_SPICOMMON_H_ */ diff --git a/hal/src/fsfw_hal/devicehandlers/CMakeLists.txt b/hal/src/fsfw_hal/devicehandlers/CMakeLists.txt new file mode 100644 index 00000000..94e67c72 --- /dev/null +++ b/hal/src/fsfw_hal/devicehandlers/CMakeLists.txt @@ -0,0 +1,5 @@ +target_sources(${LIB_FSFW_NAME} PRIVATE + GyroL3GD20Handler.cpp + MgmRM3100Handler.cpp + MgmLIS3MDLHandler.cpp +) diff --git a/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.cpp b/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.cpp new file mode 100644 index 00000000..d27351d7 --- /dev/null +++ b/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.cpp @@ -0,0 +1,287 @@ +#include "GyroL3GD20Handler.h" + +#include "fsfw/datapool/PoolReadGuard.h" + +#include + +GyroHandlerL3GD20H::GyroHandlerL3GD20H(object_id_t objectId, object_id_t deviceCommunication, + CookieIF *comCookie, uint32_t transitionDelayMs): + DeviceHandlerBase(objectId, deviceCommunication, comCookie), + transitionDelayMs(transitionDelayMs), dataset(this) { +#if FSFW_HAL_L3GD20_GYRO_DEBUG == 1 + debugDivider = new PeriodicOperationDivider(3); +#endif +} + +GyroHandlerL3GD20H::~GyroHandlerL3GD20H() {} + +void GyroHandlerL3GD20H::doStartUp() { + if(internalState == InternalState::NONE) { + internalState = InternalState::CONFIGURE; + } + + if(internalState == InternalState::CONFIGURE) { + if(commandExecuted) { + internalState = InternalState::CHECK_REGS; + commandExecuted = false; + } + } + + if(internalState == InternalState::CHECK_REGS) { + if(commandExecuted) { + internalState = InternalState::NORMAL; + if(goNormalModeImmediately) { + setMode(MODE_NORMAL); + } + else { + setMode(_MODE_TO_ON); + } + commandExecuted = false; + } + } +} + +void GyroHandlerL3GD20H::doShutDown() { + setMode(_MODE_POWER_DOWN); +} + +ReturnValue_t GyroHandlerL3GD20H::buildTransitionDeviceCommand(DeviceCommandId_t *id) { + switch(internalState) { + case(InternalState::NONE): + case(InternalState::NORMAL): { + return NOTHING_TO_SEND; + } + case(InternalState::CONFIGURE): { + *id = L3GD20H::CONFIGURE_CTRL_REGS; + uint8_t command [5]; + command[0] = L3GD20H::CTRL_REG_1_VAL; + command[1] = L3GD20H::CTRL_REG_2_VAL; + command[2] = L3GD20H::CTRL_REG_3_VAL; + command[3] = L3GD20H::CTRL_REG_4_VAL; + command[4] = L3GD20H::CTRL_REG_5_VAL; + return buildCommandFromCommand(*id, command, 5); + } + case(InternalState::CHECK_REGS): { + *id = L3GD20H::READ_REGS; + return buildCommandFromCommand(*id, nullptr, 0); + } + default: +#if FSFW_CPP_OSTREAM_ENABLED == 1 + /* Might be a configuration error. */ + sif::warning << "GyroL3GD20Handler::buildTransitionDeviceCommand: " + "Unknown internal state!" << std::endl; +#else + sif::printDebug("GyroL3GD20Handler::buildTransitionDeviceCommand: " + "Unknown internal state!\n"); +#endif + return HasReturnvaluesIF::RETURN_OK; + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t GyroHandlerL3GD20H::buildNormalDeviceCommand(DeviceCommandId_t *id) { + *id = L3GD20H::READ_REGS; + return buildCommandFromCommand(*id, nullptr, 0); +} + +ReturnValue_t GyroHandlerL3GD20H::buildCommandFromCommand( + DeviceCommandId_t deviceCommand, const uint8_t *commandData, + size_t commandDataLen) { + switch(deviceCommand) { + case(L3GD20H::READ_REGS): { + commandBuffer[0] = L3GD20H::READ_START | L3GD20H::AUTO_INCREMENT_MASK | L3GD20H::READ_MASK; + std::memset(commandBuffer + 1, 0, L3GD20H::READ_LEN); + rawPacket = commandBuffer; + rawPacketLen = L3GD20H::READ_LEN + 1; + break; + } + case(L3GD20H::CONFIGURE_CTRL_REGS): { + commandBuffer[0] = L3GD20H::CTRL_REG_1 | L3GD20H::AUTO_INCREMENT_MASK; + if(commandData == nullptr or commandDataLen != 5) { + return DeviceHandlerIF::INVALID_COMMAND_PARAMETER; + } + + ctrlReg1Value = commandData[0]; + ctrlReg2Value = commandData[1]; + ctrlReg3Value = commandData[2]; + ctrlReg4Value = commandData[3]; + ctrlReg5Value = commandData[4]; + + bool fsH = ctrlReg4Value & L3GD20H::SET_FS_1; + bool fsL = ctrlReg4Value & L3GD20H::SET_FS_0; + + if(not fsH and not fsL) { + sensitivity = L3GD20H::SENSITIVITY_00; + } + else if(not fsH and fsL) { + sensitivity = L3GD20H::SENSITIVITY_01; + } + else { + sensitivity = L3GD20H::SENSITIVITY_11; + } + + commandBuffer[1] = ctrlReg1Value; + commandBuffer[2] = ctrlReg2Value; + commandBuffer[3] = ctrlReg3Value; + commandBuffer[4] = ctrlReg4Value; + commandBuffer[5] = ctrlReg5Value; + + rawPacket = commandBuffer; + rawPacketLen = 6; + break; + } + case(L3GD20H::READ_CTRL_REGS): { + commandBuffer[0] = L3GD20H::READ_START | L3GD20H::AUTO_INCREMENT_MASK | + L3GD20H::READ_MASK; + + std::memset(commandBuffer + 1, 0, 5); + rawPacket = commandBuffer; + rawPacketLen = 6; + break; + } + default: + return DeviceHandlerIF::COMMAND_NOT_IMPLEMENTED; + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t GyroHandlerL3GD20H::scanForReply(const uint8_t *start, size_t len, + DeviceCommandId_t *foundId, size_t *foundLen) { + // For SPI, the ID will always be the one of the last sent command + *foundId = this->getPendingCommand(); + *foundLen = this->rawPacketLen; + + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t GyroHandlerL3GD20H::interpretDeviceReply(DeviceCommandId_t id, + const uint8_t *packet) { + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + switch(id) { + case(L3GD20H::CONFIGURE_CTRL_REGS): { + commandExecuted = true; + break; + } + case(L3GD20H::READ_CTRL_REGS): { + if(packet[1] == ctrlReg1Value and packet[2] == ctrlReg2Value and + packet[3] == ctrlReg3Value and packet[4] == ctrlReg4Value and + packet[5] == ctrlReg5Value) { + commandExecuted = true; + } + else { + // Attempt reconfiguration + internalState = InternalState::CONFIGURE; + return DeviceHandlerIF::DEVICE_REPLY_INVALID; + } + break; + } + case(L3GD20H::READ_REGS): { + if(packet[1] != ctrlReg1Value and packet[2] != ctrlReg2Value and + packet[3] != ctrlReg3Value and packet[4] != ctrlReg4Value and + packet[5] != ctrlReg5Value) { + return DeviceHandlerIF::DEVICE_REPLY_INVALID; + } + else { + if(internalState == InternalState::CHECK_REGS) { + commandExecuted = true; + } + } + + statusReg = packet[L3GD20H::STATUS_IDX]; + + int16_t angVelocXRaw = packet[L3GD20H::OUT_X_H] << 8 | packet[L3GD20H::OUT_X_L]; + int16_t angVelocYRaw = packet[L3GD20H::OUT_Y_H] << 8 | packet[L3GD20H::OUT_Y_L]; + int16_t angVelocZRaw = packet[L3GD20H::OUT_Z_H] << 8 | packet[L3GD20H::OUT_Z_L]; + float angVelocX = angVelocXRaw * sensitivity; + float angVelocY = angVelocYRaw * sensitivity; + float angVelocZ = angVelocZRaw * sensitivity; + + int8_t temperaturOffset = (-1) * packet[L3GD20H::TEMPERATURE_IDX]; + float temperature = 25.0 + temperaturOffset; +#if FSFW_HAL_L3GD20_GYRO_DEBUG == 1 + if(debugDivider->checkAndIncrement()) { + /* Set terminal to utf-8 if there is an issue with micro printout. */ +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "GyroHandlerL3GD20H: Angular velocities (deg/s):" << std::endl; + sif::info << "X: " << angVelocX << std::endl; + sif::info << "Y: " << angVelocY << std::endl; + sif::info << "Z: " << angVelocZ << std::endl; +#else + sif::printInfo("GyroHandlerL3GD20H: Angular velocities (deg/s):\n"); + sif::printInfo("X: %f\n", angVelocX); + sif::printInfo("Y: %f\n", angVelocY); + sif::printInfo("Z: %f\n", angVelocZ); +#endif + } +#endif + + PoolReadGuard readSet(&dataset); + if(readSet.getReadResult() == HasReturnvaluesIF::RETURN_OK) { + if(std::abs(angVelocX) < this->absLimitX) { + dataset.angVelocX = angVelocX; + dataset.angVelocX.setValid(true); + } + else { + dataset.angVelocX.setValid(false); + } + + if(std::abs(angVelocY) < this->absLimitY) { + dataset.angVelocY = angVelocY; + dataset.angVelocY.setValid(true); + } + else { + dataset.angVelocY.setValid(false); + } + + if(std::abs(angVelocZ) < this->absLimitZ) { + dataset.angVelocZ = angVelocZ; + dataset.angVelocZ.setValid(true); + } + else { + dataset.angVelocZ.setValid(false); + } + + dataset.temperature = temperature; + dataset.temperature.setValid(true); + } + break; + } + default: + return DeviceHandlerIF::COMMAND_NOT_IMPLEMENTED; + } + return result; +} + + +uint32_t GyroHandlerL3GD20H::getTransitionDelayMs(Mode_t from, Mode_t to) { + return this->transitionDelayMs; +} + +void GyroHandlerL3GD20H::setToGoToNormalMode(bool enable) { + this->goNormalModeImmediately = true; +} + +ReturnValue_t GyroHandlerL3GD20H::initializeLocalDataPool( + localpool::DataPool &localDataPoolMap, LocalDataPoolManager &poolManager) { + localDataPoolMap.emplace(L3GD20H::ANG_VELOC_X, new PoolEntry({0.0})); + localDataPoolMap.emplace(L3GD20H::ANG_VELOC_Y, new PoolEntry({0.0})); + localDataPoolMap.emplace(L3GD20H::ANG_VELOC_Z, new PoolEntry({0.0})); + localDataPoolMap.emplace(L3GD20H::TEMPERATURE, new PoolEntry({0.0})); + return HasReturnvaluesIF::RETURN_OK; +} + +void GyroHandlerL3GD20H::fillCommandAndReplyMap() { + insertInCommandAndReplyMap(L3GD20H::READ_REGS, 1, &dataset); + insertInCommandAndReplyMap(L3GD20H::CONFIGURE_CTRL_REGS, 1); + insertInCommandAndReplyMap(L3GD20H::READ_CTRL_REGS, 1); +} + +void GyroHandlerL3GD20H::modeChanged() { + internalState = InternalState::NONE; +} + +void GyroHandlerL3GD20H::setAbsoluteLimits(float limitX, float limitY, float limitZ) { + this->absLimitX = limitX; + this->absLimitY = limitY; + this->absLimitZ = limitZ; +} diff --git a/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.h b/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.h new file mode 100644 index 00000000..e73d2fbb --- /dev/null +++ b/hal/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.h @@ -0,0 +1,99 @@ +#ifndef MISSION_DEVICES_GYROL3GD20HANDLER_H_ +#define MISSION_DEVICES_GYROL3GD20HANDLER_H_ + +#include "fsfw/FSFW.h" +#include "devicedefinitions/GyroL3GD20Definitions.h" + +#include +#include + +/** + * @brief Device Handler for the L3GD20H gyroscope sensor + * (https://www.st.com/en/mems-and-sensors/l3gd20h.html) + * @details + * Advanced documentation: + * https://egit.irs.uni-stuttgart.de/redmine/projects/eive-flight-manual/wiki/L3GD20H_Gyro + * + * Data is read big endian with the smallest possible range of 245 degrees per second. + */ +class GyroHandlerL3GD20H: public DeviceHandlerBase { +public: + GyroHandlerL3GD20H(object_id_t objectId, object_id_t deviceCommunication, + CookieIF* comCookie, uint32_t transitionDelayMs); + virtual ~GyroHandlerL3GD20H(); + + /** + * Set the absolute limit for the values on the axis in degrees per second. + * The dataset values will be marked as invalid if that limit is exceeded + * @param xLimit + * @param yLimit + * @param zLimit + */ + void setAbsoluteLimits(float limitX, float limitY, float limitZ); + + /** + * @brief Configure device handler to go to normal mode immediately + */ + void setToGoToNormalMode(bool enable); +protected: + + /* DeviceHandlerBase overrides */ + ReturnValue_t buildTransitionDeviceCommand( + DeviceCommandId_t *id) override; + void doStartUp() override; + void doShutDown() override; + ReturnValue_t buildNormalDeviceCommand( + DeviceCommandId_t *id) override; + ReturnValue_t buildCommandFromCommand( + DeviceCommandId_t deviceCommand, const uint8_t *commandData, + size_t commandDataLen) override; + ReturnValue_t scanForReply(const uint8_t *start, size_t len, + DeviceCommandId_t *foundId, size_t *foundLen) override; + virtual ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, + const uint8_t *packet) override; + + void fillCommandAndReplyMap() override; + void modeChanged() override; + virtual uint32_t getTransitionDelayMs(Mode_t from, Mode_t to) override; + ReturnValue_t initializeLocalDataPool(localpool::DataPool &localDataPoolMap, + LocalDataPoolManager &poolManager) override; + +private: + uint32_t transitionDelayMs = 0; + GyroPrimaryDataset dataset; + + float absLimitX = L3GD20H::RANGE_DPS_00; + float absLimitY = L3GD20H::RANGE_DPS_00; + float absLimitZ = L3GD20H::RANGE_DPS_00; + + enum class InternalState { + NONE, + CONFIGURE, + CHECK_REGS, + NORMAL + }; + InternalState internalState = InternalState::NONE; + bool commandExecuted = false; + + uint8_t statusReg = 0; + bool goNormalModeImmediately = false; + + uint8_t ctrlReg1Value = L3GD20H::CTRL_REG_1_VAL; + uint8_t ctrlReg2Value = L3GD20H::CTRL_REG_2_VAL; + uint8_t ctrlReg3Value = L3GD20H::CTRL_REG_3_VAL; + uint8_t ctrlReg4Value = L3GD20H::CTRL_REG_4_VAL; + uint8_t ctrlReg5Value = L3GD20H::CTRL_REG_5_VAL; + + uint8_t commandBuffer[L3GD20H::READ_LEN + 1]; + + // Set default value + float sensitivity = L3GD20H::SENSITIVITY_00; + +#if FSFW_HAL_L3GD20_GYRO_DEBUG == 1 + PeriodicOperationDivider* debugDivider = nullptr; +#endif +}; + + + +#endif /* MISSION_DEVICES_GYROL3GD20HANDLER_H_ */ diff --git a/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp b/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp new file mode 100644 index 00000000..1a61bfe2 --- /dev/null +++ b/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp @@ -0,0 +1,520 @@ +#include "MgmLIS3MDLHandler.h" + +#include "fsfw/datapool/PoolReadGuard.h" +#if FSFW_HAL_LIS3MDL_MGM_DEBUG == 1 +#include "fsfw/globalfunctions/PeriodicOperationDivider.h" +#endif + +#include + +MgmLIS3MDLHandler::MgmLIS3MDLHandler(object_id_t objectId, object_id_t deviceCommunication, + CookieIF* comCookie, uint32_t transitionDelay): + DeviceHandlerBase(objectId, deviceCommunication, comCookie), + dataset(this), transitionDelay(transitionDelay) { +#if FSFW_HAL_LIS3MDL_MGM_DEBUG == 1 + debugDivider = new PeriodicOperationDivider(3); +#endif + // Set to default values right away + registers[0] = MGMLIS3MDL::CTRL_REG1_DEFAULT; + registers[1] = MGMLIS3MDL::CTRL_REG2_DEFAULT; + registers[2] = MGMLIS3MDL::CTRL_REG3_DEFAULT; + registers[3] = MGMLIS3MDL::CTRL_REG4_DEFAULT; + registers[4] = MGMLIS3MDL::CTRL_REG5_DEFAULT; + +} + +MgmLIS3MDLHandler::~MgmLIS3MDLHandler() { +} + + +void MgmLIS3MDLHandler::doStartUp() { + switch (internalState) { + case(InternalState::STATE_NONE): { + internalState = InternalState::STATE_FIRST_CONTACT; + break; + } + case(InternalState::STATE_FIRST_CONTACT): { + /* Will be set by checking device ID (WHO AM I register) */ + if(commandExecuted) { + commandExecuted = false; + internalState = InternalState::STATE_SETUP; + } + break; + } + case(InternalState::STATE_SETUP): { + internalState = InternalState::STATE_CHECK_REGISTERS; + break; + } + case(InternalState::STATE_CHECK_REGISTERS): { + /* Set up cached registers which will be used to configure the MGM. */ + if(commandExecuted) { + commandExecuted = false; + if(goToNormalMode) { + setMode(MODE_NORMAL); + } + else { + setMode(_MODE_TO_ON); + } + } + break; + } + default: + break; + } + +} + +void MgmLIS3MDLHandler::doShutDown() { + setMode(_MODE_POWER_DOWN); +} + +ReturnValue_t MgmLIS3MDLHandler::buildTransitionDeviceCommand( + DeviceCommandId_t *id) { + switch (internalState) { + case(InternalState::STATE_NONE): + case(InternalState::STATE_NORMAL): { + return DeviceHandlerBase::NOTHING_TO_SEND; + } + case(InternalState::STATE_FIRST_CONTACT): { + *id = MGMLIS3MDL::IDENTIFY_DEVICE; + break; + } + case(InternalState::STATE_SETUP): { + *id = MGMLIS3MDL::SETUP_MGM; + break; + } + case(InternalState::STATE_CHECK_REGISTERS): { + *id = MGMLIS3MDL::READ_CONFIG_AND_DATA; + break; + } + default: { + /* might be a configuration error. */ +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "GyroHandler::buildTransitionDeviceCommand: Unknown internal state!" << + std::endl; +#else + sif::printWarning("GyroHandler::buildTransitionDeviceCommand: Unknown internal state!\n"); +#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ + return HasReturnvaluesIF::RETURN_OK; + } + + } + return buildCommandFromCommand(*id, NULL, 0); +} + +uint8_t MgmLIS3MDLHandler::readCommand(uint8_t command, bool continuousCom) { + command |= (1 << MGMLIS3MDL::RW_BIT); + if (continuousCom == true) { + command |= (1 << MGMLIS3MDL::MS_BIT); + } + return command; +} + +uint8_t MgmLIS3MDLHandler::writeCommand(uint8_t command, bool continuousCom) { + command &= ~(1 << MGMLIS3MDL::RW_BIT); + if (continuousCom == true) { + command |= (1 << MGMLIS3MDL::MS_BIT); + } + return command; +} + +void MgmLIS3MDLHandler::setupMgm() { + + registers[0] = MGMLIS3MDL::CTRL_REG1_DEFAULT; + registers[1] = MGMLIS3MDL::CTRL_REG2_DEFAULT; + registers[2] = MGMLIS3MDL::CTRL_REG3_DEFAULT; + registers[3] = MGMLIS3MDL::CTRL_REG4_DEFAULT; + registers[4] = MGMLIS3MDL::CTRL_REG5_DEFAULT; + + prepareCtrlRegisterWrite(); +} + +ReturnValue_t MgmLIS3MDLHandler::buildNormalDeviceCommand( + DeviceCommandId_t *id) { + // Data/config register will be read in an alternating manner. + if(communicationStep == CommunicationStep::DATA) { + *id = MGMLIS3MDL::READ_CONFIG_AND_DATA; + communicationStep = CommunicationStep::TEMPERATURE; + return buildCommandFromCommand(*id, NULL, 0); + } + else { + *id = MGMLIS3MDL::READ_TEMPERATURE; + communicationStep = CommunicationStep::DATA; + return buildCommandFromCommand(*id, NULL, 0); + } + +} + +ReturnValue_t MgmLIS3MDLHandler::buildCommandFromCommand( + DeviceCommandId_t deviceCommand, const uint8_t *commandData, + size_t commandDataLen) { + switch(deviceCommand) { + case(MGMLIS3MDL::READ_CONFIG_AND_DATA): { + std::memset(commandBuffer, 0, sizeof(commandBuffer)); + commandBuffer[0] = readCommand(MGMLIS3MDL::CTRL_REG1, true); + + rawPacket = commandBuffer; + rawPacketLen = MGMLIS3MDL::NR_OF_DATA_AND_CFG_REGISTERS + 1; + return RETURN_OK; + } + case(MGMLIS3MDL::READ_TEMPERATURE): { + std::memset(commandBuffer, 0, 3); + commandBuffer[0] = readCommand(MGMLIS3MDL::TEMP_LOWBYTE, true); + + rawPacket = commandBuffer; + rawPacketLen = 3; + return RETURN_OK; + } + case(MGMLIS3MDL::IDENTIFY_DEVICE): { + return identifyDevice(); + } + case(MGMLIS3MDL::TEMP_SENSOR_ENABLE): { + return enableTemperatureSensor(commandData, commandDataLen); + } + case(MGMLIS3MDL::SETUP_MGM): { + setupMgm(); + return HasReturnvaluesIF::RETURN_OK; + } + case(MGMLIS3MDL::ACCURACY_OP_MODE_SET): { + return setOperatingMode(commandData, commandDataLen); + } + default: + return DeviceHandlerIF::COMMAND_NOT_IMPLEMENTED; + } + return HasReturnvaluesIF::RETURN_FAILED; +} + +ReturnValue_t MgmLIS3MDLHandler::identifyDevice() { + uint32_t size = 2; + commandBuffer[0] = readCommand(MGMLIS3MDL::IDENTIFY_DEVICE_REG_ADDR); + commandBuffer[1] = 0x00; + + rawPacket = commandBuffer; + rawPacketLen = size; + + return RETURN_OK; +} + +ReturnValue_t MgmLIS3MDLHandler::scanForReply(const uint8_t *start, + size_t len, DeviceCommandId_t *foundId, size_t *foundLen) { + *foundLen = len; + if (len == MGMLIS3MDL::NR_OF_DATA_AND_CFG_REGISTERS + 1) { + *foundLen = len; + *foundId = MGMLIS3MDL::READ_CONFIG_AND_DATA; + // Check validity by checking config registers + if (start[1] != registers[0] or start[2] != registers[1] or + start[3] != registers[2] or start[4] != registers[3] or + start[5] != registers[4]) { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "MGMHandlerLIS3MDL::scanForReply: Invalid registers!" << std::endl; +#else + sif::printWarning("MGMHandlerLIS3MDL::scanForReply: Invalid registers!\n"); +#endif +#endif + return DeviceHandlerIF::INVALID_DATA; + } + if(mode == _MODE_START_UP) { + commandExecuted = true; + } + + } + else if(len == MGMLIS3MDL::TEMPERATURE_REPLY_LEN) { + *foundLen = len; + *foundId = MGMLIS3MDL::READ_TEMPERATURE; + } + else if (len == MGMLIS3MDL::SETUP_REPLY_LEN) { + *foundLen = len; + *foundId = MGMLIS3MDL::SETUP_MGM; + } + else if (len == SINGLE_COMMAND_ANSWER_LEN) { + *foundLen = len; + *foundId = getPendingCommand(); + if(*foundId == MGMLIS3MDL::IDENTIFY_DEVICE) { + if(start[1] != MGMLIS3MDL::DEVICE_ID) { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "MGMHandlerLIS3MDL::scanForReply: " + "Device identification failed!" << std::endl; +#else + sif::printWarning("MGMHandlerLIS3MDL::scanForReply: " + "Device identification failed!\n"); +#endif +#endif + return DeviceHandlerIF::INVALID_DATA; + } + + if(mode == _MODE_START_UP) { + commandExecuted = true; + } + } + } + else { + return DeviceHandlerIF::INVALID_DATA; + } + + /* Data with SPI Interface always has this answer */ + if (start[0] == 0b11111111) { + return RETURN_OK; + } + else { + return DeviceHandlerIF::INVALID_DATA; + } + +} +ReturnValue_t MgmLIS3MDLHandler::interpretDeviceReply(DeviceCommandId_t id, + const uint8_t *packet) { + + switch (id) { + case MGMLIS3MDL::IDENTIFY_DEVICE: { + break; + } + case MGMLIS3MDL::SETUP_MGM: { + break; + } + case MGMLIS3MDL::READ_CONFIG_AND_DATA: { + // TODO: Store configuration in new local datasets. + float sensitivityFactor = getSensitivityFactor(getSensitivity(registers[2])); + + int16_t mgmMeasurementRawX = packet[MGMLIS3MDL::X_HIGHBYTE_IDX] << 8 + | packet[MGMLIS3MDL::X_LOWBYTE_IDX] ; + int16_t mgmMeasurementRawY = packet[MGMLIS3MDL::Y_HIGHBYTE_IDX] << 8 + | packet[MGMLIS3MDL::Y_LOWBYTE_IDX] ; + int16_t mgmMeasurementRawZ = packet[MGMLIS3MDL::Z_HIGHBYTE_IDX] << 8 + | packet[MGMLIS3MDL::Z_LOWBYTE_IDX] ; + + /* Target value in microtesla */ + float mgmX = static_cast(mgmMeasurementRawX) * sensitivityFactor + * MGMLIS3MDL::GAUSS_TO_MICROTESLA_FACTOR; + float mgmY = static_cast(mgmMeasurementRawY) * sensitivityFactor + * MGMLIS3MDL::GAUSS_TO_MICROTESLA_FACTOR; + float mgmZ = static_cast(mgmMeasurementRawZ) * sensitivityFactor + * MGMLIS3MDL::GAUSS_TO_MICROTESLA_FACTOR; + +#if FSFW_HAL_LIS3MDL_MGM_DEBUG == 1 + if(debugDivider->checkAndIncrement()) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "MGMHandlerLIS3: Magnetic field strength in" + " microtesla:" << std::endl; + sif::info << "X: " << mgmX << " uT" << std::endl; + sif::info << "Y: " << mgmY << " uT" << std::endl; + sif::info << "Z: " << mgmZ << " uT" << std::endl; +#else + sif::printInfo("MGMHandlerLIS3: Magnetic field strength in microtesla:\n"); + sif::printInfo("X: %f uT\n", mgmX); + sif::printInfo("Y: %f uT\n", mgmY); + sif::printInfo("Z: %f uT\n", mgmZ); +#endif /* FSFW_CPP_OSTREAM_ENABLED == 0 */ + } +#endif /* OBSW_VERBOSE_LEVEL >= 1 */ + PoolReadGuard readHelper(&dataset); + if(readHelper.getReadResult() == HasReturnvaluesIF::RETURN_OK) { + if(std::abs(mgmX) < absLimitX) { + dataset.fieldStrengthX = mgmX; + dataset.fieldStrengthX.setValid(true); + } + else { + dataset.fieldStrengthX.setValid(false); + } + + if(std::abs(mgmY) < absLimitY) { + dataset.fieldStrengthY = mgmY; + dataset.fieldStrengthY.setValid(true); + } + else { + dataset.fieldStrengthY.setValid(false); + } + + if(std::abs(mgmZ) < absLimitZ) { + dataset.fieldStrengthZ = mgmZ; + dataset.fieldStrengthZ.setValid(true); + } + else { + dataset.fieldStrengthZ.setValid(false); + } + } + break; + } + + case MGMLIS3MDL::READ_TEMPERATURE: { + int16_t tempValueRaw = packet[2] << 8 | packet[1]; + float tempValue = 25.0 + ((static_cast(tempValueRaw)) / 8.0); + #if FSFW_HAL_LIS3MDL_MGM_DEBUG == 1 + if(debugDivider->check()) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "MGMHandlerLIS3: Temperature: " << tempValue << " C" << + std::endl; +#else + sif::printInfo("MGMHandlerLIS3: Temperature: %f C\n"); +#endif + } +#endif + ReturnValue_t result = dataset.read(); + if(result == HasReturnvaluesIF::RETURN_OK) { + dataset.temperature = tempValue; + dataset.commit(); + } + break; + } + + default: { + return DeviceHandlerIF::UNKNOWN_DEVICE_REPLY; + } + + } + return RETURN_OK; +} + +MGMLIS3MDL::Sensitivies MgmLIS3MDLHandler::getSensitivity(uint8_t ctrlRegister2) { + bool fs0Set = ctrlRegister2 & (1 << MGMLIS3MDL::FSO); // Checks if FS0 bit is set + bool fs1Set = ctrlRegister2 & (1 << MGMLIS3MDL::FS1); // Checks if FS1 bit is set + + if (fs0Set && fs1Set) + return MGMLIS3MDL::Sensitivies::GAUSS_16; + else if (!fs0Set && fs1Set) + return MGMLIS3MDL::Sensitivies::GAUSS_12; + else if (fs0Set && !fs1Set) + return MGMLIS3MDL::Sensitivies::GAUSS_8; + else + return MGMLIS3MDL::Sensitivies::GAUSS_4; +} + +float MgmLIS3MDLHandler::getSensitivityFactor(MGMLIS3MDL::Sensitivies sens) { + switch(sens) { + case(MGMLIS3MDL::GAUSS_4): { + return MGMLIS3MDL::FIELD_LSB_PER_GAUSS_4_SENS; + } + case(MGMLIS3MDL::GAUSS_8): { + return MGMLIS3MDL::FIELD_LSB_PER_GAUSS_8_SENS; + } + case(MGMLIS3MDL::GAUSS_12): { + return MGMLIS3MDL::FIELD_LSB_PER_GAUSS_12_SENS; + } + case(MGMLIS3MDL::GAUSS_16): { + return MGMLIS3MDL::FIELD_LSB_PER_GAUSS_16_SENS; + } + default: { + // Should never happen + return MGMLIS3MDL::FIELD_LSB_PER_GAUSS_4_SENS; + } + } +} + + +ReturnValue_t MgmLIS3MDLHandler::enableTemperatureSensor( + const uint8_t *commandData, size_t commandDataLen) { + triggerEvent(CHANGE_OF_SETUP_PARAMETER); + uint32_t size = 2; + commandBuffer[0] = writeCommand(MGMLIS3MDL::CTRL_REG1); + if (commandDataLen > 1) { + return INVALID_NUMBER_OR_LENGTH_OF_PARAMETERS; + } + switch (*commandData) { + case (MGMLIS3MDL::ON): { + commandBuffer[1] = registers[0] | (1 << 7); + break; + } + case (MGMLIS3MDL::OFF): { + commandBuffer[1] = registers[0] & ~(1 << 7); + break; + } + default: + return INVALID_COMMAND_PARAMETER; + } + registers[0] = commandBuffer[1]; + + rawPacket = commandBuffer; + rawPacketLen = size; + + return RETURN_OK; +} + +ReturnValue_t MgmLIS3MDLHandler::setOperatingMode(const uint8_t *commandData, + size_t commandDataLen) { + triggerEvent(CHANGE_OF_SETUP_PARAMETER); + if (commandDataLen != 1) { + return INVALID_NUMBER_OR_LENGTH_OF_PARAMETERS; + } + + switch (commandData[0]) { + case MGMLIS3MDL::LOW: + registers[0] = (registers[0] & (~(1 << MGMLIS3MDL::OM1))) & (~(1 << MGMLIS3MDL::OM0)); + registers[3] = (registers[3] & (~(1 << MGMLIS3MDL::OMZ1))) & (~(1 << MGMLIS3MDL::OMZ0)); + break; + case MGMLIS3MDL::MEDIUM: + registers[0] = (registers[0] & (~(1 << MGMLIS3MDL::OM1))) | (1 << MGMLIS3MDL::OM0); + registers[3] = (registers[3] & (~(1 << MGMLIS3MDL::OMZ1))) | (1 << MGMLIS3MDL::OMZ0); + break; + + case MGMLIS3MDL::HIGH: + registers[0] = (registers[0] | (1 << MGMLIS3MDL::OM1)) & (~(1 << MGMLIS3MDL::OM0)); + registers[3] = (registers[3] | (1 << MGMLIS3MDL::OMZ1)) & (~(1 << MGMLIS3MDL::OMZ0)); + break; + + case MGMLIS3MDL::ULTRA: + registers[0] = (registers[0] | (1 << MGMLIS3MDL::OM1)) | (1 << MGMLIS3MDL::OM0); + registers[3] = (registers[3] | (1 << MGMLIS3MDL::OMZ1)) | (1 << MGMLIS3MDL::OMZ0); + break; + default: + break; + } + + return prepareCtrlRegisterWrite(); +} + +void MgmLIS3MDLHandler::fillCommandAndReplyMap() { + insertInCommandAndReplyMap(MGMLIS3MDL::READ_CONFIG_AND_DATA, 1, &dataset); + insertInCommandAndReplyMap(MGMLIS3MDL::READ_TEMPERATURE, 1); + insertInCommandAndReplyMap(MGMLIS3MDL::SETUP_MGM, 1); + insertInCommandAndReplyMap(MGMLIS3MDL::IDENTIFY_DEVICE, 1); + insertInCommandAndReplyMap(MGMLIS3MDL::TEMP_SENSOR_ENABLE, 1); + insertInCommandAndReplyMap(MGMLIS3MDL::ACCURACY_OP_MODE_SET, 1); +} + +void MgmLIS3MDLHandler::setToGoToNormalMode(bool enable) { + this->goToNormalMode = enable; +} + +ReturnValue_t MgmLIS3MDLHandler::prepareCtrlRegisterWrite() { + commandBuffer[0] = writeCommand(MGMLIS3MDL::CTRL_REG1, true); + + for (size_t i = 0; i < MGMLIS3MDL::NR_OF_CTRL_REGISTERS; i++) { + commandBuffer[i + 1] = registers[i]; + } + rawPacket = commandBuffer; + rawPacketLen = MGMLIS3MDL::NR_OF_CTRL_REGISTERS + 1; + + // We dont have to check if this is working because we just did i + return RETURN_OK; +} + +void MgmLIS3MDLHandler::doTransition(Mode_t modeFrom, Submode_t subModeFrom) { + +} + +uint32_t MgmLIS3MDLHandler::getTransitionDelayMs(Mode_t from, Mode_t to) { + return transitionDelay; +} + +void MgmLIS3MDLHandler::modeChanged(void) { + internalState = InternalState::STATE_NONE; +} + +ReturnValue_t MgmLIS3MDLHandler::initializeLocalDataPool( + localpool::DataPool &localDataPoolMap, LocalDataPoolManager &poolManager) { + localDataPoolMap.emplace(MGMLIS3MDL::FIELD_STRENGTH_X, + new PoolEntry({0.0})); + localDataPoolMap.emplace(MGMLIS3MDL::FIELD_STRENGTH_Y, + new PoolEntry({0.0})); + localDataPoolMap.emplace(MGMLIS3MDL::FIELD_STRENGTH_Z, + new PoolEntry({0.0})); + localDataPoolMap.emplace(MGMLIS3MDL::TEMPERATURE_CELCIUS, + new PoolEntry({0.0})); + return HasReturnvaluesIF::RETURN_OK; +} + +void MgmLIS3MDLHandler::setAbsoluteLimits(float xLimit, float yLimit, float zLimit) { + this->absLimitX = xLimit; + this->absLimitY = yLimit; + this->absLimitZ = zLimit; +} diff --git a/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.h b/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.h new file mode 100644 index 00000000..6bf89a49 --- /dev/null +++ b/hal/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.h @@ -0,0 +1,186 @@ +#ifndef MISSION_DEVICES_MGMLIS3MDLHANDLER_H_ +#define MISSION_DEVICES_MGMLIS3MDLHANDLER_H_ + +#include "fsfw/FSFW.h" +#include "events/subsystemIdRanges.h" +#include "devicedefinitions/MgmLIS3HandlerDefs.h" + +#include "fsfw/devicehandlers/DeviceHandlerBase.h" + +class PeriodicOperationDivider; + +/** + * @brief Device handler object for the LIS3MDL 3-axis magnetometer + * by STMicroeletronics + * @details + * Datasheet can be found online by googling LIS3MDL. + * Flight manual: + * https://egit.irs.uni-stuttgart.de/redmine/projects/eive-flight-manual/wiki/LIS3MDL_MGM + * @author L. Loidold, R. Mueller + */ +class MgmLIS3MDLHandler: public DeviceHandlerBase { +public: + enum class CommunicationStep { + DATA, + TEMPERATURE + }; + + static const uint8_t INTERFACE_ID = CLASS_ID::MGM_LIS3MDL; + static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::MGM_LIS3MDL; + //Notifies a command to change the setup parameters + static const Event CHANGE_OF_SETUP_PARAMETER = MAKE_EVENT(0, severity::LOW); + + MgmLIS3MDLHandler(uint32_t objectId, object_id_t deviceCommunication, CookieIF* comCookie, + uint32_t transitionDelay); + virtual ~MgmLIS3MDLHandler(); + + /** + * Set the absolute limit for the values on the axis in microtesla. The dataset values will + * be marked as invalid if that limit is exceeded + * @param xLimit + * @param yLimit + * @param zLimit + */ + void setAbsoluteLimits(float xLimit, float yLimit, float zLimit); + void setToGoToNormalMode(bool enable); + +protected: + + /** DeviceHandlerBase overrides */ + void doShutDown() override; + void doStartUp() override; + void doTransition(Mode_t modeFrom, Submode_t subModeFrom) override; + virtual uint32_t getTransitionDelayMs(Mode_t from, Mode_t to) override; + ReturnValue_t buildCommandFromCommand( + DeviceCommandId_t deviceCommand, const uint8_t *commandData, + size_t commandDataLen) override; + ReturnValue_t buildTransitionDeviceCommand( + DeviceCommandId_t *id) override; + ReturnValue_t buildNormalDeviceCommand( + DeviceCommandId_t *id) override; + ReturnValue_t scanForReply(const uint8_t *start, size_t len, + DeviceCommandId_t *foundId, size_t *foundLen) override; + /** + * This implementation is tailored towards space applications and will flag values larger + * than 100 microtesla on X,Y and 150 microtesla on Z as invalid + * @param id + * @param packet + * @return + */ + virtual ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, + const uint8_t *packet) override; + void fillCommandAndReplyMap() override; + void modeChanged(void) override; + ReturnValue_t initializeLocalDataPool(localpool::DataPool &localDataPoolMap, + LocalDataPoolManager &poolManager) override; + +private: + MGMLIS3MDL::MgmPrimaryDataset dataset; + //Length a single command SPI answer + static const uint8_t SINGLE_COMMAND_ANSWER_LEN = 2; + + uint32_t transitionDelay; + // Single SPI command has 2 bytes, first for adress, second for content + size_t singleComandSize = 2; + // Has the size for all adresses of the lis3mdl + the continous write bit + uint8_t commandBuffer[MGMLIS3MDL::NR_OF_DATA_AND_CFG_REGISTERS + 1]; + + float absLimitX = 100; + float absLimitY = 100; + float absLimitZ = 150; + + /** + * We want to save the registers we set, so we dont have to read the + * registers when we want to change something. + * --> everytime we change set a register we have to save it + */ + uint8_t registers[MGMLIS3MDL::NR_OF_CTRL_REGISTERS]; + + uint8_t statusRegister = 0; + bool goToNormalMode = false; + + enum class InternalState { + STATE_NONE, + STATE_FIRST_CONTACT, + STATE_SETUP, + STATE_CHECK_REGISTERS, + STATE_NORMAL + }; + + InternalState internalState = InternalState::STATE_NONE; + CommunicationStep communicationStep = CommunicationStep::DATA; + bool commandExecuted = false; + + /*------------------------------------------------------------------------*/ + /* Device specific commands and variables */ + /*------------------------------------------------------------------------*/ + /** + * Sets the read bit for the command + * @param single command to set the read-bit at + * @param boolean to select a continuous read bit, default = false + */ + uint8_t readCommand(uint8_t command, bool continuousCom = false); + + /** + * Sets the write bit for the command + * @param single command to set the write-bit at + * @param boolean to select a continuous write bit, default = false + */ + uint8_t writeCommand(uint8_t command, bool continuousCom = false); + + /** + * This Method gets the full scale for the measurement range + * e.g.: +- 4 gauss. See p.25 datasheet. + * @return The ReturnValue does not contain the sign of the value + */ + MGMLIS3MDL::Sensitivies getSensitivity(uint8_t ctrlReg2); + + /** + * The 16 bit value needs to be multiplied with a sensitivity factor + * which depends on the sensitivity configuration + * + * @param sens Configured sensitivity of the LIS3 device + * @return Multiplication factor to get the sensor value from raw data. + */ + float getSensitivityFactor(MGMLIS3MDL::Sensitivies sens); + + /** + * This Command detects the device ID + */ + ReturnValue_t identifyDevice(); + + virtual void setupMgm(); + + /*------------------------------------------------------------------------*/ + /* Non normal commands */ + /*------------------------------------------------------------------------*/ + /** + * Enables/Disables the integrated Temperaturesensor + * @param commandData On or Off + * @param length of the commandData: has to be 1 + */ + virtual ReturnValue_t enableTemperatureSensor(const uint8_t *commandData, + size_t commandDataLen); + + /** + * Sets the accuracy of the measurement of the axis. The noise is changing. + * @param commandData LOW, MEDIUM, HIGH, ULTRA + * @param length of the command, has to be 1 + */ + virtual ReturnValue_t setOperatingMode(const uint8_t *commandData, + size_t commandDataLen); + + /** + * We always update all registers together, so this method updates + * the rawpacket and rawpacketLen, so we just manipulate the local + * saved register + * + */ + ReturnValue_t prepareCtrlRegisterWrite(); + +#if FSFW_HAL_LIS3MDL_MGM_DEBUG == 1 + PeriodicOperationDivider* debugDivider; +#endif +}; + +#endif /* MISSION_DEVICES_MGMLIS3MDLHANDLER_H_ */ diff --git a/hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.cpp b/hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.cpp new file mode 100644 index 00000000..db4ea607 --- /dev/null +++ b/hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.cpp @@ -0,0 +1,376 @@ +#include "MgmRM3100Handler.h" + +#include "fsfw/datapool/PoolReadGuard.h" +#include "fsfw/globalfunctions/bitutility.h" +#include "fsfw/devicehandlers/DeviceHandlerMessage.h" +#include "fsfw/objectmanager/SystemObjectIF.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" + + +MgmRM3100Handler::MgmRM3100Handler(object_id_t objectId, + object_id_t deviceCommunication, CookieIF* comCookie, uint32_t transitionDelay): + DeviceHandlerBase(objectId, deviceCommunication, comCookie), + primaryDataset(this), transitionDelay(transitionDelay) { +#if FSFW_HAL_RM3100_MGM_DEBUG == 1 + debugDivider = new PeriodicOperationDivider(3); +#endif +} + +MgmRM3100Handler::~MgmRM3100Handler() {} + +void MgmRM3100Handler::doStartUp() { + switch(internalState) { + case(InternalState::NONE): { + internalState = InternalState::CONFIGURE_CMM; + break; + } + case(InternalState::CONFIGURE_CMM): { + internalState = InternalState::READ_CMM; + break; + } + case(InternalState::READ_CMM): { + if(commandExecuted) { + internalState = InternalState::STATE_CONFIGURE_TMRC; + } + break; + } + case(InternalState::STATE_CONFIGURE_TMRC): { + if(commandExecuted) { + internalState = InternalState::STATE_READ_TMRC; + } + break; + } + case(InternalState::STATE_READ_TMRC): { + if(commandExecuted) { + internalState = InternalState::NORMAL; + if(goToNormalModeAtStartup) { + setMode(MODE_NORMAL); + } + else { + setMode(_MODE_TO_ON); + } + } + break; + } + default: { + break; + } + } +} + +void MgmRM3100Handler::doShutDown() { + setMode(_MODE_POWER_DOWN); +} + +ReturnValue_t MgmRM3100Handler::buildTransitionDeviceCommand( + DeviceCommandId_t *id) { + size_t commandLen = 0; + switch(internalState) { + case(InternalState::NONE): + case(InternalState::NORMAL): { + return NOTHING_TO_SEND; + } + case(InternalState::CONFIGURE_CMM): { + *id = RM3100::CONFIGURE_CMM; + break; + } + case(InternalState::READ_CMM): { + *id = RM3100::READ_CMM; + break; + } + case(InternalState::STATE_CONFIGURE_TMRC): { + commandBuffer[0] = RM3100::TMRC_DEFAULT_VALUE; + commandLen = 1; + *id = RM3100::CONFIGURE_TMRC; + break; + } + case(InternalState::STATE_READ_TMRC): { + *id = RM3100::READ_TMRC; + break; + } + default: +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + // Might be a configuration error + sif::warning << "MgmRM3100Handler::buildTransitionDeviceCommand: " + "Unknown internal state" << std::endl; +#else + sif::printWarning("MgmRM3100Handler::buildTransitionDeviceCommand: " + "Unknown internal state\n"); +#endif +#endif + return HasReturnvaluesIF::RETURN_OK; + } + + return buildCommandFromCommand(*id, commandBuffer, commandLen); +} + +ReturnValue_t MgmRM3100Handler::buildCommandFromCommand(DeviceCommandId_t deviceCommand, + const uint8_t *commandData, size_t commandDataLen) { + switch(deviceCommand) { + case(RM3100::CONFIGURE_CMM): { + commandBuffer[0] = RM3100::CMM_REGISTER; + commandBuffer[1] = RM3100::CMM_VALUE; + rawPacket = commandBuffer; + rawPacketLen = 2; + break; + } + case(RM3100::READ_CMM): { + commandBuffer[0] = RM3100::CMM_REGISTER | RM3100::READ_MASK; + commandBuffer[1] = 0; + rawPacket = commandBuffer; + rawPacketLen = 2; + break; + } + case(RM3100::CONFIGURE_TMRC): { + return handleTmrcConfigCommand(deviceCommand, commandData, commandDataLen); + } + case(RM3100::READ_TMRC): { + commandBuffer[0] = RM3100::TMRC_REGISTER | RM3100::READ_MASK; + commandBuffer[1] = 0; + rawPacket = commandBuffer; + rawPacketLen = 2; + break; + } + case(RM3100::CONFIGURE_CYCLE_COUNT): { + return handleCycleCountConfigCommand(deviceCommand, commandData, commandDataLen); + } + case(RM3100::READ_CYCLE_COUNT): { + commandBuffer[0] = RM3100::CYCLE_COUNT_START_REGISTER | RM3100::READ_MASK; + std::memset(commandBuffer + 1, 0, 6); + rawPacket = commandBuffer; + rawPacketLen = 7; + break; + } + case(RM3100::READ_DATA): { + commandBuffer[0] = RM3100::MEASUREMENT_REG_START | RM3100::READ_MASK; + std::memset(commandBuffer + 1, 0, 9); + rawPacketLen = 10; + break; + } + default: + return DeviceHandlerIF::COMMAND_NOT_IMPLEMENTED; + } + return RETURN_OK; +} + +ReturnValue_t MgmRM3100Handler::buildNormalDeviceCommand( + DeviceCommandId_t *id) { + *id = RM3100::READ_DATA; + return buildCommandFromCommand(*id, nullptr, 0); +} + +ReturnValue_t MgmRM3100Handler::scanForReply(const uint8_t *start, + size_t len, DeviceCommandId_t *foundId, + size_t *foundLen) { + + // For SPI, ID will always be the one of the last sent command + *foundId = this->getPendingCommand(); + *foundLen = len; + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t MgmRM3100Handler::interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) { + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + switch(id) { + case(RM3100::CONFIGURE_CMM): + case(RM3100::CONFIGURE_CYCLE_COUNT): + case(RM3100::CONFIGURE_TMRC): { + // We can only check whether write was successful with read operation + if(mode == _MODE_START_UP) { + commandExecuted = true; + } + break; + } + case(RM3100::READ_CMM): { + uint8_t cmmValue = packet[1]; + // We clear the seventh bit in any case + // because this one is zero sometimes for some reason + bitutil::clear(&cmmValue, 6); + if(cmmValue == cmmRegValue and internalState == InternalState::READ_CMM) { + commandExecuted = true; + } + else { + // Attempt reconfiguration + internalState = InternalState::CONFIGURE_CMM; + return DeviceHandlerIF::DEVICE_REPLY_INVALID; + } + break; + } + case(RM3100::READ_TMRC): { + if(packet[1] == tmrcRegValue) { + commandExecuted = true; + // Reading TMRC was commanded. Trigger event to inform ground + if(mode != _MODE_START_UP) { + triggerEvent(tmrcSet, tmrcRegValue, 0); + } + } + else { + // Attempt reconfiguration + internalState = InternalState::STATE_CONFIGURE_TMRC; + return DeviceHandlerIF::DEVICE_REPLY_INVALID; + } + break; + } + case(RM3100::READ_CYCLE_COUNT): { + uint16_t cycleCountX = packet[1] << 8 | packet[2]; + uint16_t cycleCountY = packet[3] << 8 | packet[4]; + uint16_t cycleCountZ = packet[5] << 8 | packet[6]; + if(cycleCountX != cycleCountRegValueX or cycleCountY != cycleCountRegValueY or + cycleCountZ != cycleCountRegValueZ) { + return DeviceHandlerIF::DEVICE_REPLY_INVALID; + } + // Reading TMRC was commanded. Trigger event to inform ground + if(mode != _MODE_START_UP) { + uint32_t eventParam1 = (cycleCountX << 16) | cycleCountY; + triggerEvent(cycleCountersSet, eventParam1, cycleCountZ); + } + break; + } + case(RM3100::READ_DATA): { + result = handleDataReadout(packet); + break; + } + default: + return DeviceHandlerIF::UNKNOWN_DEVICE_REPLY; + } + + return result; +} + +ReturnValue_t MgmRM3100Handler::handleCycleCountConfigCommand(DeviceCommandId_t deviceCommand, + const uint8_t *commandData, size_t commandDataLen) { + if(commandData == nullptr) { + return DeviceHandlerIF::INVALID_COMMAND_PARAMETER; + } + + // Set cycle count + if(commandDataLen == 2) { + handleCycleCommand(true, commandData, commandDataLen); + } + else if(commandDataLen == 6) { + handleCycleCommand(false, commandData, commandDataLen); + } + else { + return DeviceHandlerIF::INVALID_COMMAND_PARAMETER; + } + + commandBuffer[0] = RM3100::CYCLE_COUNT_VALUE; + std::memcpy(commandBuffer + 1, &cycleCountRegValueX, 2); + std::memcpy(commandBuffer + 3, &cycleCountRegValueY, 2); + std::memcpy(commandBuffer + 5, &cycleCountRegValueZ, 2); + rawPacketLen = 7; + rawPacket = commandBuffer; + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t MgmRM3100Handler::handleCycleCommand(bool oneCycleValue, + const uint8_t *commandData, size_t commandDataLen) { + RM3100::CycleCountCommand command(oneCycleValue); + ReturnValue_t result = command.deSerialize(&commandData, &commandDataLen, + SerializeIF::Endianness::BIG); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + // Data sheet p.30 "while noise limits the useful upper range to ~400 cycle counts." + if(command.cycleCountX > 450 ) { + return DeviceHandlerIF::INVALID_COMMAND_PARAMETER; + } + + if(not oneCycleValue and (command.cycleCountY > 450 or command.cycleCountZ > 450)) { + return DeviceHandlerIF::INVALID_COMMAND_PARAMETER; + } + + cycleCountRegValueX = command.cycleCountX; + cycleCountRegValueY = command.cycleCountY; + cycleCountRegValueZ = command.cycleCountZ; + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t MgmRM3100Handler::handleTmrcConfigCommand(DeviceCommandId_t deviceCommand, + const uint8_t *commandData, size_t commandDataLen) { + if(commandData == nullptr or commandDataLen != 1) { + return DeviceHandlerIF::INVALID_COMMAND_PARAMETER; + } + + commandBuffer[0] = RM3100::TMRC_REGISTER; + commandBuffer[1] = commandData[0]; + tmrcRegValue = commandData[0]; + rawPacketLen = 2; + rawPacket = commandBuffer; + return HasReturnvaluesIF::RETURN_OK; +} + +void MgmRM3100Handler::fillCommandAndReplyMap() { + insertInCommandAndReplyMap(RM3100::CONFIGURE_CMM, 3); + insertInCommandAndReplyMap(RM3100::READ_CMM, 3); + + insertInCommandAndReplyMap(RM3100::CONFIGURE_TMRC, 3); + insertInCommandAndReplyMap(RM3100::READ_TMRC, 3); + + insertInCommandAndReplyMap(RM3100::CONFIGURE_CYCLE_COUNT, 3); + insertInCommandAndReplyMap(RM3100::READ_CYCLE_COUNT, 3); + + insertInCommandAndReplyMap(RM3100::READ_DATA, 3, &primaryDataset); +} + +void MgmRM3100Handler::modeChanged(void) { + internalState = InternalState::NONE; +} + +ReturnValue_t MgmRM3100Handler::initializeLocalDataPool( + localpool::DataPool &localDataPoolMap, LocalDataPoolManager &poolManager) { + localDataPoolMap.emplace(RM3100::FIELD_STRENGTH_X, new PoolEntry({0.0})); + localDataPoolMap.emplace(RM3100::FIELD_STRENGTH_Y, new PoolEntry({0.0})); + localDataPoolMap.emplace(RM3100::FIELD_STRENGTH_Z, new PoolEntry({0.0})); + return HasReturnvaluesIF::RETURN_OK; +} + +uint32_t MgmRM3100Handler::getTransitionDelayMs(Mode_t from, Mode_t to) { + return this->transitionDelay; +} + +void MgmRM3100Handler::setToGoToNormalMode(bool enable) { + goToNormalModeAtStartup = enable; +} + +ReturnValue_t MgmRM3100Handler::handleDataReadout(const uint8_t *packet) { + // Analyze data here. The sensor generates 24 bit signed values so we need to do some bitshift + // trickery here to calculate the raw values first + int32_t fieldStrengthRawX = ((packet[1] << 24) | (packet[2] << 16) | (packet[3] << 8)) >> 8; + int32_t fieldStrengthRawY = ((packet[4] << 24) | (packet[5] << 16) | (packet[6] << 8)) >> 8; + int32_t fieldStrengthRawZ = ((packet[7] << 24) | (packet[8] << 16) | (packet[3] << 8)) >> 8; + + // Now scale to physical value in microtesla + float fieldStrengthX = fieldStrengthRawX * scaleFactorX; + float fieldStrengthY = fieldStrengthRawY * scaleFactorX; + float fieldStrengthZ = fieldStrengthRawZ * scaleFactorX; + +#if FSFW_HAL_RM3100_MGM_DEBUG == 1 + if(debugDivider->checkAndIncrement()) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "MgmRM3100Handler: Magnetic field strength in" + " microtesla:" << std::endl; + sif::info << "X: " << fieldStrengthX << " uT" << std::endl; + sif::info << "Y: " << fieldStrengthY << " uT" << std::endl; + sif::info << "Z: " << fieldStrengthZ << " uT" << std::endl; +#else + sif::printInfo("MgmRM3100Handler: Magnetic field strength in microtesla:\n"); + sif::printInfo("X: %f uT\n", fieldStrengthX); + sif::printInfo("Y: %f uT\n", fieldStrengthY); + sif::printInfo("Z: %f uT\n", fieldStrengthZ); +#endif + } +#endif + + // TODO: Sanity check on values? + PoolReadGuard readGuard(&primaryDataset); + if(readGuard.getReadResult() == HasReturnvaluesIF::RETURN_OK) { + primaryDataset.fieldStrengthX = fieldStrengthX; + primaryDataset.fieldStrengthY = fieldStrengthY; + primaryDataset.fieldStrengthZ = fieldStrengthZ; + primaryDataset.setValidity(true, true); + } + return RETURN_OK; +} diff --git a/hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.h b/hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.h new file mode 100644 index 00000000..6627cbb7 --- /dev/null +++ b/hal/src/fsfw_hal/devicehandlers/MgmRM3100Handler.h @@ -0,0 +1,110 @@ +#ifndef MISSION_DEVICES_MGMRM3100HANDLER_H_ +#define MISSION_DEVICES_MGMRM3100HANDLER_H_ + +#include "fsfw/FSFW.h" +#include "devicedefinitions/MgmRM3100HandlerDefs.h" +#include "fsfw/devicehandlers/DeviceHandlerBase.h" + +#if FSFW_HAL_RM3100_MGM_DEBUG == 1 +#include "fsfw/globalfunctions/PeriodicOperationDivider.h" +#endif + +/** + * @brief Device Handler for the RM3100 geomagnetic magnetometer sensor + * (https://www.pnicorp.com/rm3100/) + * @details + * Flight manual: + * https://egit.irs.uni-stuttgart.de/redmine/projects/eive-flight-manual/wiki/RM3100_MGM + */ +class MgmRM3100Handler: public DeviceHandlerBase { +public: + static const uint8_t INTERFACE_ID = CLASS_ID::MGM_RM3100; + + //! [EXPORT] : [COMMENT] P1: TMRC value which was set, P2: 0 + static constexpr Event tmrcSet = event::makeEvent(SUBSYSTEM_ID::MGM_RM3100, + 0x00, severity::INFO); + + //! [EXPORT] : [COMMENT] Cycle counter set. P1: First two bytes new Cycle Count X + //! P1: Second two bytes new Cycle Count Y + //! P2: New cycle count Z + static constexpr Event cycleCountersSet = event::makeEvent( + SUBSYSTEM_ID::MGM_RM3100, 0x01, severity::INFO); + + MgmRM3100Handler(object_id_t objectId, object_id_t deviceCommunication, + CookieIF* comCookie, uint32_t transitionDelay); + virtual ~MgmRM3100Handler(); + + /** + * Configure device handler to go to normal mode after startup immediately + * @param enable + */ + void setToGoToNormalMode(bool enable); + +protected: + + /* DeviceHandlerBase overrides */ + ReturnValue_t buildTransitionDeviceCommand( + DeviceCommandId_t *id) override; + void doStartUp() override; + void doShutDown() override; + ReturnValue_t buildNormalDeviceCommand(DeviceCommandId_t *id) override; + ReturnValue_t buildCommandFromCommand(DeviceCommandId_t deviceCommand, + const uint8_t *commandData, size_t commandDataLen) override; + ReturnValue_t scanForReply(const uint8_t *start, size_t len, + DeviceCommandId_t *foundId, size_t *foundLen) override; + ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) override; + + void fillCommandAndReplyMap() override; + void modeChanged(void) override; + virtual uint32_t getTransitionDelayMs(Mode_t from, Mode_t to) override; + ReturnValue_t initializeLocalDataPool(localpool::DataPool &localDataPoolMap, + LocalDataPoolManager &poolManager) override; + +private: + + enum class InternalState { + NONE, + CONFIGURE_CMM, + READ_CMM, + // The cycle count states are propably not going to be used because + // the default cycle count will be used. + STATE_CONFIGURE_CYCLE_COUNT, + STATE_READ_CYCLE_COUNT, + STATE_CONFIGURE_TMRC, + STATE_READ_TMRC, + NORMAL + }; + InternalState internalState = InternalState::NONE; + bool commandExecuted = false; + RM3100::Rm3100PrimaryDataset primaryDataset; + + uint8_t commandBuffer[10]; + uint8_t commandBufferLen = 0; + + uint8_t cmmRegValue = RM3100::CMM_VALUE; + uint8_t tmrcRegValue = RM3100::TMRC_DEFAULT_VALUE; + uint16_t cycleCountRegValueX = RM3100::CYCLE_COUNT_VALUE; + uint16_t cycleCountRegValueY = RM3100::CYCLE_COUNT_VALUE; + uint16_t cycleCountRegValueZ = RM3100::CYCLE_COUNT_VALUE; + float scaleFactorX = 1.0 / RM3100::DEFAULT_GAIN; + float scaleFactorY = 1.0 / RM3100::DEFAULT_GAIN; + float scaleFactorZ = 1.0 / RM3100::DEFAULT_GAIN; + + bool goToNormalModeAtStartup = false; + uint32_t transitionDelay; + + ReturnValue_t handleCycleCountConfigCommand(DeviceCommandId_t deviceCommand, + const uint8_t *commandData,size_t commandDataLen); + ReturnValue_t handleCycleCommand(bool oneCycleValue, + const uint8_t *commandData, size_t commandDataLen); + + ReturnValue_t handleTmrcConfigCommand(DeviceCommandId_t deviceCommand, + const uint8_t *commandData,size_t commandDataLen); + + ReturnValue_t handleDataReadout(const uint8_t* packet); +#if FSFW_HAL_RM3100_MGM_DEBUG == 1 + PeriodicOperationDivider* debugDivider; +#endif +}; + +#endif /* MISSION_DEVICEHANDLING_MGMRM3100HANDLER_H_ */ diff --git a/hal/src/fsfw_hal/devicehandlers/devicedefinitions/GyroL3GD20Definitions.h b/hal/src/fsfw_hal/devicehandlers/devicedefinitions/GyroL3GD20Definitions.h new file mode 100644 index 00000000..56a2468d --- /dev/null +++ b/hal/src/fsfw_hal/devicehandlers/devicedefinitions/GyroL3GD20Definitions.h @@ -0,0 +1,143 @@ +#ifndef MISSION_DEVICES_DEVICEDEFINITIONS_GYROL3GD20DEFINITIONS_H_ +#define MISSION_DEVICES_DEVICEDEFINITIONS_GYROL3GD20DEFINITIONS_H_ + +#include +#include +#include + +namespace L3GD20H { + +/* Actual size is 15 but we round up a bit */ +static constexpr size_t MAX_BUFFER_SIZE = 16; + +static constexpr uint8_t READ_MASK = 0b10000000; + +static constexpr uint8_t AUTO_INCREMENT_MASK = 0b01000000; + +static constexpr uint8_t WHO_AM_I_REG = 0b00001111; +static constexpr uint8_t WHO_AM_I_VAL = 0b11010111; + +/*------------------------------------------------------------------------*/ +/* Control registers */ +/*------------------------------------------------------------------------*/ +static constexpr uint8_t CTRL_REG_1 = 0b00100000; +static constexpr uint8_t CTRL_REG_2 = 0b00100001; +static constexpr uint8_t CTRL_REG_3 = 0b00100010; +static constexpr uint8_t CTRL_REG_4 = 0b00100011; +static constexpr uint8_t CTRL_REG_5 = 0b00100100; + +/* Register 1 */ +static constexpr uint8_t SET_DR_1 = 1 << 7; +static constexpr uint8_t SET_DR_0 = 1 << 6; +static constexpr uint8_t SET_BW_1 = 1 << 5; +static constexpr uint8_t SET_BW_0 = 1 << 4; +static constexpr uint8_t SET_POWER_NORMAL_MODE = 1 << 3; +static constexpr uint8_t SET_Z_ENABLE = 1 << 2; +static constexpr uint8_t SET_X_ENABLE = 1 << 1; +static constexpr uint8_t SET_Y_ENABLE = 1; + +static constexpr uint8_t CTRL_REG_1_VAL = SET_POWER_NORMAL_MODE | SET_Z_ENABLE | + SET_Y_ENABLE | SET_X_ENABLE; + +/* Register 2 */ +static constexpr uint8_t EXTERNAL_EDGE_ENB = 1 << 7; +static constexpr uint8_t LEVEL_SENSITIVE_TRIGGER = 1 << 6; +static constexpr uint8_t SET_HPM_1 = 1 << 5; +static constexpr uint8_t SET_HPM_0 = 1 << 4; +static constexpr uint8_t SET_HPCF_3 = 1 << 3; +static constexpr uint8_t SET_HPCF_2 = 1 << 2; +static constexpr uint8_t SET_HPCF_1 = 1 << 1; +static constexpr uint8_t SET_HPCF_0 = 1; + +static constexpr uint8_t CTRL_REG_2_VAL = 0b00000000; + +/* Register 3 */ +static constexpr uint8_t CTRL_REG_3_VAL = 0b00000000; + +/* Register 4 */ +static constexpr uint8_t SET_BNU = 1 << 7; +static constexpr uint8_t SET_BLE = 1 << 6; +static constexpr uint8_t SET_FS_1 = 1 << 5; +static constexpr uint8_t SET_FS_0 = 1 << 4; +static constexpr uint8_t SET_IMP_ENB = 1 << 3; +static constexpr uint8_t SET_SELF_TEST_ENB_1 = 1 << 2; +static constexpr uint8_t SET_SELF_TEST_ENB_0 = 1 << 1; +static constexpr uint8_t SET_SPI_IF_SELECT = 1; + +/* Enable big endian data format */ +static constexpr uint8_t CTRL_REG_4_VAL = SET_BLE; + +/* Register 5 */ +static constexpr uint8_t SET_REBOOT_MEM = 1 << 7; +static constexpr uint8_t SET_FIFO_ENB = 1 << 6; + +static constexpr uint8_t CTRL_REG_5_VAL = 0b00000000; + +/* Possible range values in degrees per second (DPS). */ +static constexpr uint16_t RANGE_DPS_00 = 245; +static constexpr float SENSITIVITY_00 = 8.75 * 0.001; +static constexpr uint16_t RANGE_DPS_01 = 500; +static constexpr float SENSITIVITY_01 = 17.5 * 0.001; +static constexpr uint16_t RANGE_DPS_11 = 2000; +static constexpr float SENSITIVITY_11 = 70.0 * 0.001; + +static constexpr uint8_t READ_START = CTRL_REG_1; +static constexpr size_t READ_LEN = 14; + +/* Indexing */ +static constexpr uint8_t REFERENCE_IDX = 6; +static constexpr uint8_t TEMPERATURE_IDX = 7; +static constexpr uint8_t STATUS_IDX = 8; +static constexpr uint8_t OUT_X_H = 9; +static constexpr uint8_t OUT_X_L = 10; +static constexpr uint8_t OUT_Y_H = 11; +static constexpr uint8_t OUT_Y_L = 12; +static constexpr uint8_t OUT_Z_H = 13; +static constexpr uint8_t OUT_Z_L = 14; + +/*------------------------------------------------------------------------*/ +/* Device Handler specific */ +/*------------------------------------------------------------------------*/ +static constexpr DeviceCommandId_t READ_REGS = 0; +static constexpr DeviceCommandId_t CONFIGURE_CTRL_REGS = 1; +static constexpr DeviceCommandId_t READ_CTRL_REGS = 2; + +static constexpr uint32_t GYRO_DATASET_ID = READ_REGS; + +enum GyroPoolIds: lp_id_t { + ANG_VELOC_X, + ANG_VELOC_Y, + ANG_VELOC_Z, + TEMPERATURE +}; + +} + +class GyroPrimaryDataset: public StaticLocalDataSet<5> { +public: + + /** Constructor for data users like controllers */ + GyroPrimaryDataset(object_id_t mgmId): + StaticLocalDataSet(sid_t(mgmId, L3GD20H::GYRO_DATASET_ID)) { + setAllVariablesReadOnly(); + } + + /* Angular velocities in degrees per second (DPS) */ + lp_var_t angVelocX = lp_var_t(sid.objectId, + L3GD20H::ANG_VELOC_X, this); + lp_var_t angVelocY = lp_var_t(sid.objectId, + L3GD20H::ANG_VELOC_Y, this); + lp_var_t angVelocZ = lp_var_t(sid.objectId, + L3GD20H::ANG_VELOC_Z, this); + lp_var_t temperature = lp_var_t(sid.objectId, + L3GD20H::TEMPERATURE, this); +private: + + friend class GyroHandlerL3GD20H; + /** Constructor for the data creator */ + GyroPrimaryDataset(HasLocalDataPoolIF* hkOwner): + StaticLocalDataSet(hkOwner, L3GD20H::GYRO_DATASET_ID) {} +}; + + +#endif /* MISSION_DEVICES_DEVICEDEFINITIONS_GYROL3GD20DEFINITIONS_H_ */ diff --git a/hal/src/fsfw_hal/devicehandlers/devicedefinitions/MgmLIS3HandlerDefs.h b/hal/src/fsfw_hal/devicehandlers/devicedefinitions/MgmLIS3HandlerDefs.h new file mode 100644 index 00000000..9d65aae2 --- /dev/null +++ b/hal/src/fsfw_hal/devicehandlers/devicedefinitions/MgmLIS3HandlerDefs.h @@ -0,0 +1,178 @@ +#ifndef MISSION_DEVICES_DEVICEDEFINITIONS_MGMLIS3HANDLERDEFS_H_ +#define MISSION_DEVICES_DEVICEDEFINITIONS_MGMLIS3HANDLERDEFS_H_ + +#include +#include +#include +#include + +namespace MGMLIS3MDL { + +enum Set { + ON, OFF +}; +enum OpMode { + LOW, MEDIUM, HIGH, ULTRA +}; + +enum Sensitivies: uint8_t { + GAUSS_4 = 4, + GAUSS_8 = 8, + GAUSS_12 = 12, + GAUSS_16 = 16 +}; + +/* Actually 15, we just round up a bit */ +static constexpr size_t MAX_BUFFER_SIZE = 16; + +/* Field data register scaling */ +static constexpr uint8_t GAUSS_TO_MICROTESLA_FACTOR = 100; +static constexpr float FIELD_LSB_PER_GAUSS_4_SENS = 1.0 / 6842.0; +static constexpr float FIELD_LSB_PER_GAUSS_8_SENS = 1.0 / 3421.0; +static constexpr float FIELD_LSB_PER_GAUSS_12_SENS = 1.0 / 2281.0; +static constexpr float FIELD_LSB_PER_GAUSS_16_SENS = 1.0 / 1711.0; + +static const DeviceCommandId_t READ_CONFIG_AND_DATA = 0x00; +static const DeviceCommandId_t SETUP_MGM = 0x01; +static const DeviceCommandId_t READ_TEMPERATURE = 0x02; +static const DeviceCommandId_t IDENTIFY_DEVICE = 0x03; +static const DeviceCommandId_t TEMP_SENSOR_ENABLE = 0x04; +static const DeviceCommandId_t ACCURACY_OP_MODE_SET = 0x05; + +/* Number of all control registers */ +static const uint8_t NR_OF_CTRL_REGISTERS = 5; +/* Number of registers in the MGM */ +static const uint8_t NR_OF_REGISTERS = 19; +/* Total number of adresses for all registers */ +static const uint8_t TOTAL_NR_OF_ADRESSES = 52; +static const uint8_t NR_OF_DATA_AND_CFG_REGISTERS = 14; +static const uint8_t TEMPERATURE_REPLY_LEN = 3; +static const uint8_t SETUP_REPLY_LEN = 6; + +/*------------------------------------------------------------------------*/ +/* Register adresses */ +/*------------------------------------------------------------------------*/ +/* Register adress returns identifier of device with default 0b00111101 */ +static const uint8_t IDENTIFY_DEVICE_REG_ADDR = 0b00001111; +static const uint8_t DEVICE_ID = 0b00111101; // Identifier for Device + +/* Register adress to access register 1 */ +static const uint8_t CTRL_REG1 = 0b00100000; +/* Register adress to access register 2 */ +static const uint8_t CTRL_REG2 = 0b00100001; +/* Register adress to access register 3 */ +static const uint8_t CTRL_REG3 = 0b00100010; +/* Register adress to access register 4 */ +static const uint8_t CTRL_REG4 = 0b00100011; +/* Register adress to access register 5 */ +static const uint8_t CTRL_REG5 = 0b00100100; + +/* Register adress to access status register */ +static const uint8_t STATUS_REG_IDX = 8; +static const uint8_t STATUS_REG = 0b00100111; + +/* Register adress to access low byte of x-axis */ +static const uint8_t X_LOWBYTE_IDX = 9; +static const uint8_t X_LOWBYTE = 0b00101000; +/* Register adress to access high byte of x-axis */ +static const uint8_t X_HIGHBYTE_IDX = 10; +static const uint8_t X_HIGHBYTE = 0b00101001; +/* Register adress to access low byte of y-axis */ +static const uint8_t Y_LOWBYTE_IDX = 11; +static const uint8_t Y_LOWBYTE = 0b00101010; +/* Register adress to access high byte of y-axis */ +static const uint8_t Y_HIGHBYTE_IDX = 12; +static const uint8_t Y_HIGHBYTE = 0b00101011; +/* Register adress to access low byte of z-axis */ +static const uint8_t Z_LOWBYTE_IDX = 13; +static const uint8_t Z_LOWBYTE = 0b00101100; +/* Register adress to access high byte of z-axis */ +static const uint8_t Z_HIGHBYTE_IDX = 14; +static const uint8_t Z_HIGHBYTE = 0b00101101; + +/* Register adress to access low byte of temperature sensor */ +static const uint8_t TEMP_LOWBYTE = 0b00101110; +/* Register adress to access high byte of temperature sensor */ +static const uint8_t TEMP_HIGHBYTE = 0b00101111; + +/*------------------------------------------------------------------------*/ +/* Initialize Setup Register set bits */ +/*------------------------------------------------------------------------*/ +/* General transfer bits */ +// Read=1 / Write=0 Bit +static const uint8_t RW_BIT = 7; +// Continous Read/Write Bit, increment adress +static const uint8_t MS_BIT = 6; + +/* CTRL_REG1 bits */ +static const uint8_t ST = 0; // Self test enable bit, enabled = 1 +// Enable rates higher than 80 Hz enabled = 1 +static const uint8_t FAST_ODR = 1; +static const uint8_t DO0 = 2; // Output data rate bit 2 +static const uint8_t DO1 = 3; // Output data rate bit 3 +static const uint8_t DO2 = 4; // Output data rate bit 4 +static const uint8_t OM0 = 5; // XY operating mode bit 5 +static const uint8_t OM1 = 6; // XY operating mode bit 6 +static const uint8_t TEMP_EN = 7; // Temperature sensor enable enabled = 1 +static const uint8_t CTRL_REG1_DEFAULT = (1 << TEMP_EN) | (1 << OM1) | + (1 << DO0) | (1 << DO1) | (1 << DO2); + +/* CTRL_REG2 bits */ +//reset configuration registers and user registers +static const uint8_t SOFT_RST = 2; +static const uint8_t REBOOT = 3; //reboot memory content +static const uint8_t FSO = 5; //full-scale selection bit 5 +static const uint8_t FS1 = 6; //full-scale selection bit 6 +static const uint8_t CTRL_REG2_DEFAULT = 0; + +/* CTRL_REG3 bits */ +static const uint8_t MD0 = 0; //Operating mode bit 0 +static const uint8_t MD1 = 1; //Operating mode bit 1 +//SPI serial interface mode selection enabled = 3-wire-mode +static const uint8_t SIM = 2; +static const uint8_t LP = 5; //low-power mode +static const uint8_t CTRL_REG3_DEFAULT = 0; + +/* CTRL_REG4 bits */ +//big/little endian data selection enabled = MSb at lower adress +static const uint8_t BLE = 1; +static const uint8_t OMZ0 = 2; //Z operating mode bit 2 +static const uint8_t OMZ1 = 3; //Z operating mode bit 3 +static const uint8_t CTRL_REG4_DEFAULT = (1 << OMZ1); + +/* CTRL_REG5 bits */ +static const uint8_t BDU = 6; //Block data update +static const uint8_t FAST_READ = 7; //Fast read enabled = 1 +static const uint8_t CTRL_REG5_DEFAULT = 0; + +static const uint32_t MGM_DATA_SET_ID = READ_CONFIG_AND_DATA; + +enum MgmPoolIds: lp_id_t { + FIELD_STRENGTH_X, + FIELD_STRENGTH_Y, + FIELD_STRENGTH_Z, + TEMPERATURE_CELCIUS +}; + +class MgmPrimaryDataset: public StaticLocalDataSet<4> { +public: + MgmPrimaryDataset(HasLocalDataPoolIF* hkOwner): + StaticLocalDataSet(hkOwner, MGM_DATA_SET_ID) {} + + MgmPrimaryDataset(object_id_t mgmId): + StaticLocalDataSet(sid_t(mgmId, MGM_DATA_SET_ID)) {} + + lp_var_t fieldStrengthX = lp_var_t(sid.objectId, + FIELD_STRENGTH_X, this); + lp_var_t fieldStrengthY = lp_var_t(sid.objectId, + FIELD_STRENGTH_Y, this); + lp_var_t fieldStrengthZ = lp_var_t(sid.objectId, + FIELD_STRENGTH_Z, this); + lp_var_t temperature = lp_var_t(sid.objectId, + TEMPERATURE_CELCIUS, this); +}; + +} + + +#endif /* MISSION_DEVICES_DEVICEDEFINITIONS_MGMLIS3HANDLERDEFS_H_ */ diff --git a/hal/src/fsfw_hal/devicehandlers/devicedefinitions/MgmRM3100HandlerDefs.h b/hal/src/fsfw_hal/devicehandlers/devicedefinitions/MgmRM3100HandlerDefs.h new file mode 100644 index 00000000..b6375692 --- /dev/null +++ b/hal/src/fsfw_hal/devicehandlers/devicedefinitions/MgmRM3100HandlerDefs.h @@ -0,0 +1,132 @@ +#ifndef MISSION_DEVICES_DEVICEDEFINITIONS_MGMHANDLERRM3100DEFINITIONS_H_ +#define MISSION_DEVICES_DEVICEDEFINITIONS_MGMHANDLERRM3100DEFINITIONS_H_ + +#include +#include +#include +#include +#include + +namespace RM3100 { + +/* Actually 10, we round up a little bit */ +static constexpr size_t MAX_BUFFER_SIZE = 12; + +static constexpr uint8_t READ_MASK = 0x80; + +/*----------------------------------------------------------------------------*/ +/* CMM Register */ +/*----------------------------------------------------------------------------*/ +static constexpr uint8_t SET_CMM_CMZ = 1 << 6; +static constexpr uint8_t SET_CMM_CMY = 1 << 5; +static constexpr uint8_t SET_CMM_CMX = 1 << 4; +static constexpr uint8_t SET_CMM_DRDM = 1 << 2; +static constexpr uint8_t SET_CMM_START = 1; +static constexpr uint8_t CMM_REGISTER = 0x01; + +static constexpr uint8_t CMM_VALUE = SET_CMM_CMZ | SET_CMM_CMY | SET_CMM_CMX | + SET_CMM_DRDM | SET_CMM_START; + +/*----------------------------------------------------------------------------*/ +/* Cycle count register */ +/*----------------------------------------------------------------------------*/ +// Default value (200) +static constexpr uint8_t CYCLE_COUNT_VALUE = 0xC8; + +static constexpr float DEFAULT_GAIN = static_cast(CYCLE_COUNT_VALUE) / + 100 * 38; +static constexpr uint8_t CYCLE_COUNT_START_REGISTER = 0x04; + +/*----------------------------------------------------------------------------*/ +/* TMRC register */ +/*----------------------------------------------------------------------------*/ +static constexpr uint8_t TMRC_150HZ_VALUE = 0x94; +static constexpr uint8_t TMRC_75HZ_VALUE = 0x95; +static constexpr uint8_t TMRC_DEFAULT_37HZ_VALUE = 0x96; + +static constexpr uint8_t TMRC_REGISTER = 0x0B; +static constexpr uint8_t TMRC_DEFAULT_VALUE = TMRC_DEFAULT_37HZ_VALUE; + +static constexpr uint8_t MEASUREMENT_REG_START = 0x24; +static constexpr uint8_t BIST_REGISTER = 0x33; +static constexpr uint8_t DATA_READY_VAL = 0b10000000; +static constexpr uint8_t STATUS_REGISTER = 0x34; +static constexpr uint8_t REVID_REGISTER = 0x36; + +// Range in Microtesla. 1 T equals 10000 Gauss (for comparison with LIS3 MGM) +static constexpr uint16_t RANGE = 800; + +static constexpr DeviceCommandId_t READ_DATA = 0; + +static constexpr DeviceCommandId_t CONFIGURE_CMM = 1; +static constexpr DeviceCommandId_t READ_CMM = 2; + +static constexpr DeviceCommandId_t CONFIGURE_TMRC = 3; +static constexpr DeviceCommandId_t READ_TMRC = 4; + +static constexpr DeviceCommandId_t CONFIGURE_CYCLE_COUNT = 5; +static constexpr DeviceCommandId_t READ_CYCLE_COUNT = 6; + +class CycleCountCommand: public SerialLinkedListAdapter { +public: + CycleCountCommand(bool oneCycleCount = true): oneCycleCount(oneCycleCount) { + setLinks(oneCycleCount); + } + + ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + Endianness streamEndianness) override { + ReturnValue_t result = SerialLinkedListAdapter::deSerialize(buffer, + size, streamEndianness); + if(oneCycleCount) { + cycleCountY = cycleCountX; + cycleCountZ = cycleCountX; + } + return result; + } + + SerializeElement cycleCountX; + SerializeElement cycleCountY; + SerializeElement cycleCountZ; + +private: + void setLinks(bool oneCycleCount) { + setStart(&cycleCountX); + if(not oneCycleCount) { + cycleCountX.setNext(&cycleCountY); + cycleCountY.setNext(&cycleCountZ); + } + } + + bool oneCycleCount; +}; + +static constexpr uint32_t MGM_DATASET_ID = READ_DATA; + +enum MgmPoolIds: lp_id_t { + FIELD_STRENGTH_X, + FIELD_STRENGTH_Y, + FIELD_STRENGTH_Z, +}; + +class Rm3100PrimaryDataset: public StaticLocalDataSet<3> { +public: + Rm3100PrimaryDataset(HasLocalDataPoolIF* hkOwner): + StaticLocalDataSet(hkOwner, MGM_DATASET_ID) {} + + Rm3100PrimaryDataset(object_id_t mgmId): + StaticLocalDataSet(sid_t(mgmId, MGM_DATASET_ID)) {} + + // Field strengths in micro Tesla. + lp_var_t fieldStrengthX = lp_var_t(sid.objectId, + FIELD_STRENGTH_X, this); + lp_var_t fieldStrengthY = lp_var_t(sid.objectId, + FIELD_STRENGTH_Y, this); + lp_var_t fieldStrengthZ = lp_var_t(sid.objectId, + FIELD_STRENGTH_Z, this); +}; + +} + + + +#endif /* MISSION_DEVICES_DEVICEDEFINITIONS_MGMHANDLERRM3100DEFINITIONS_H_ */ diff --git a/hal/src/fsfw_hal/host/CMakeLists.txt b/hal/src/fsfw_hal/host/CMakeLists.txt new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/hal/src/fsfw_hal/host/CMakeLists.txt @@ -0,0 +1 @@ + diff --git a/hal/src/fsfw_hal/linux/CMakeLists.txt b/hal/src/fsfw_hal/linux/CMakeLists.txt new file mode 100644 index 00000000..5944b0e5 --- /dev/null +++ b/hal/src/fsfw_hal/linux/CMakeLists.txt @@ -0,0 +1,13 @@ +if(FSFW_HAL_ADD_RASPBERRY_PI) + add_subdirectory(rpi) +endif() + +target_sources(${LIB_FSFW_NAME} PRIVATE + UnixFileGuard.cpp + utility.cpp +) + +add_subdirectory(gpio) +add_subdirectory(spi) +add_subdirectory(i2c) +add_subdirectory(uart) \ No newline at end of file diff --git a/hal/src/fsfw_hal/linux/UnixFileGuard.cpp b/hal/src/fsfw_hal/linux/UnixFileGuard.cpp new file mode 100644 index 00000000..5019343e --- /dev/null +++ b/hal/src/fsfw_hal/linux/UnixFileGuard.cpp @@ -0,0 +1,37 @@ +#include "fsfw/FSFW.h" +#include "fsfw/serviceinterface.h" +#include "fsfw_hal/linux/UnixFileGuard.h" + +#include +#include + +UnixFileGuard::UnixFileGuard(std::string device, int* fileDescriptor, int flags, + std::string diagnosticPrefix): + fileDescriptor(fileDescriptor) { + if(fileDescriptor == nullptr) { + return; + } + *fileDescriptor = open(device.c_str(), flags); + if (*fileDescriptor < 0) { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << diagnosticPrefix << ": Opening device failed with error code " << + errno << ": " << strerror(errno) << std::endl; +#else + sif::printWarning("%s: Opening device failed with error code %d: %s\n", + diagnosticPrefix, errno, strerror(errno)); +#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ +#endif /* FSFW_VERBOSE_LEVEL >= 1 */ + openStatus = OPEN_FILE_FAILED; + } +} + +UnixFileGuard::~UnixFileGuard() { + if(fileDescriptor != nullptr) { + close(*fileDescriptor); + } +} + +ReturnValue_t UnixFileGuard::getOpenResult() const { + return openStatus; +} diff --git a/hal/src/fsfw_hal/linux/UnixFileGuard.h b/hal/src/fsfw_hal/linux/UnixFileGuard.h new file mode 100644 index 00000000..fb595704 --- /dev/null +++ b/hal/src/fsfw_hal/linux/UnixFileGuard.h @@ -0,0 +1,33 @@ +#ifndef LINUX_UTILITY_UNIXFILEGUARD_H_ +#define LINUX_UTILITY_UNIXFILEGUARD_H_ + +#include + +#include + +#include +#include + + +class UnixFileGuard { +public: + static constexpr int READ_WRITE_FLAG = O_RDWR; + static constexpr int READ_ONLY_FLAG = O_RDONLY; + static constexpr int NON_BLOCKING_IO_FLAG = O_NONBLOCK; + + static constexpr ReturnValue_t OPEN_FILE_FAILED = 1; + + UnixFileGuard(std::string device, int* fileDescriptor, int flags, + std::string diagnosticPrefix = ""); + + virtual~ UnixFileGuard(); + + ReturnValue_t getOpenResult() const; +private: + int* fileDescriptor = nullptr; + ReturnValue_t openStatus = HasReturnvaluesIF::RETURN_OK; +}; + + + +#endif /* LINUX_UTILITY_UNIXFILEGUARD_H_ */ diff --git a/hal/src/fsfw_hal/linux/gpio/CMakeLists.txt b/hal/src/fsfw_hal/linux/gpio/CMakeLists.txt new file mode 100644 index 00000000..7083f70d --- /dev/null +++ b/hal/src/fsfw_hal/linux/gpio/CMakeLists.txt @@ -0,0 +1,12 @@ +target_sources(${LIB_FSFW_NAME} PRIVATE + LinuxLibgpioIF.cpp +) + +# This abstraction layer requires the gpiod library. You can install this library +# with "sudo apt-get install -y libgpiod-dev". If you are cross-compiling, you need +# to install the package before syncing the sysroot to your host computer. +find_library(LIB_GPIO gpiod REQUIRED) + +target_link_libraries(${LIB_FSFW_NAME} PRIVATE + ${LIB_GPIO} +) \ No newline at end of file diff --git a/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp b/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp new file mode 100644 index 00000000..020ba964 --- /dev/null +++ b/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp @@ -0,0 +1,442 @@ +#include "LinuxLibgpioIF.h" + +#include "fsfw_hal/common/gpio/gpioDefinitions.h" +#include "fsfw_hal/common/gpio/GpioCookie.h" + +#include "fsfw/serviceinterface/ServiceInterface.h" + +#include +#include +#include + +LinuxLibgpioIF::LinuxLibgpioIF(object_id_t objectId) : SystemObject(objectId) { +} + +LinuxLibgpioIF::~LinuxLibgpioIF() { + for(auto& config: gpioMap) { + delete(config.second); + } +} + +ReturnValue_t LinuxLibgpioIF::addGpios(GpioCookie* gpioCookie) { + ReturnValue_t result; + if(gpioCookie == nullptr) { + sif::error << "LinuxLibgpioIF::addGpios: Invalid cookie" << std::endl; + return RETURN_FAILED; + } + + GpioMap mapToAdd = gpioCookie->getGpioMap(); + + /* Check whether this ID already exists in the map and remove duplicates */ + result = checkForConflicts(mapToAdd); + if (result != RETURN_OK){ + return result; + } + + result = configureGpios(mapToAdd); + if (result != RETURN_OK) { + return RETURN_FAILED; + } + + /* Register new GPIOs in gpioMap */ + gpioMap.insert(mapToAdd.begin(), mapToAdd.end()); + + return RETURN_OK; +} + +ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) { + for(auto& gpioConfig: mapToAdd) { + auto& gpioType = gpioConfig.second->gpioType; + switch(gpioType) { + case(gpio::GpioTypes::NONE): { + return GPIO_INVALID_INSTANCE; + } + case(gpio::GpioTypes::GPIO_REGULAR_BY_CHIP): { + auto regularGpio = dynamic_cast(gpioConfig.second); + if(regularGpio == nullptr) { + return GPIO_INVALID_INSTANCE; + } + configureGpioByChip(gpioConfig.first, *regularGpio); + break; + } + case(gpio::GpioTypes::GPIO_REGULAR_BY_LABEL):{ + auto regularGpio = dynamic_cast(gpioConfig.second); + if(regularGpio == nullptr) { + return GPIO_INVALID_INSTANCE; + } + configureGpioByLabel(gpioConfig.first, *regularGpio); + break; + } + case(gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME):{ + auto regularGpio = dynamic_cast(gpioConfig.second); + if(regularGpio == nullptr) { + return GPIO_INVALID_INSTANCE; + } + configureGpioByLineName(gpioConfig.first, *regularGpio); + break; + } + case(gpio::GpioTypes::CALLBACK): { + auto gpioCallback = dynamic_cast(gpioConfig.second); + if(gpioCallback->callback == nullptr) { + return GPIO_INVALID_INSTANCE; + } + gpioCallback->callback(gpioConfig.first, gpio::GpioOperation::WRITE, + gpioCallback->initValue, gpioCallback->callbackArgs); + } + } + } + return RETURN_OK; +} + +ReturnValue_t LinuxLibgpioIF::configureGpioByLabel(gpioId_t gpioId, + GpiodRegularByLabel &gpioByLabel) { + std::string& label = gpioByLabel.label; + struct gpiod_chip* chip = gpiod_chip_open_by_label(label.c_str()); + if (chip == nullptr) { + sif::warning << "LinuxLibgpioIF::configureGpioByLabel: Failed to open gpio from gpio " + << "group with label " << label << ". Gpio ID: " << gpioId << std::endl; + return RETURN_FAILED; + + } + std::string failOutput = "label: " + label; + return configureRegularGpio(gpioId, chip, gpioByLabel, failOutput); +} + +ReturnValue_t LinuxLibgpioIF::configureGpioByChip(gpioId_t gpioId, + GpiodRegularByChip &gpioByChip) { + std::string& chipname = gpioByChip.chipname; + struct gpiod_chip* chip = gpiod_chip_open_by_name(chipname.c_str()); + if (chip == nullptr) { + sif::warning << "LinuxLibgpioIF::configureGpioByChip: Failed to open chip " + << chipname << ". Gpio ID: " << gpioId << std::endl; + return RETURN_FAILED; + } + std::string failOutput = "chipname: " + chipname; + return configureRegularGpio(gpioId, chip, gpioByChip, failOutput); +} + +ReturnValue_t LinuxLibgpioIF::configureGpioByLineName(gpioId_t gpioId, + GpiodRegularByLineName &gpioByLineName) { + std::string& lineName = gpioByLineName.lineName; + char chipname[MAX_CHIPNAME_LENGTH]; + unsigned int lineOffset; + + int result = gpiod_ctxless_find_line(lineName.c_str(), chipname, MAX_CHIPNAME_LENGTH, + &lineOffset); + if (result != LINE_FOUND) { + parseFindeLineResult(result, lineName); + return RETURN_FAILED; + } + + gpioByLineName.lineNum = static_cast(lineOffset); + + struct gpiod_chip* chip = gpiod_chip_open_by_name(chipname); + if (chip == nullptr) { + sif::warning << "LinuxLibgpioIF::configureGpioByLineName: Failed to open chip " + << chipname << ". second->gpioType; + if (gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_CHIP + or gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_LABEL + or gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME) { + auto regularGpio = dynamic_cast(gpioMapIter->second); + if(regularGpio == nullptr) { + return GPIO_TYPE_FAILURE; + } + return driveGpio(gpioId, *regularGpio, gpio::HIGH); + } + else { + auto gpioCallback = dynamic_cast(gpioMapIter->second); + if(gpioCallback->callback == nullptr) { + return GPIO_INVALID_INSTANCE; + } + gpioCallback->callback(gpioMapIter->first, gpio::GpioOperation::WRITE, + gpio::Levels::HIGH, gpioCallback->callbackArgs); + return RETURN_OK; + } + return GPIO_TYPE_FAILURE; +} + +ReturnValue_t LinuxLibgpioIF::pullLow(gpioId_t gpioId) { + gpioMapIter = gpioMap.find(gpioId); + if (gpioMapIter == gpioMap.end()) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "LinuxLibgpioIF::pullLow: Unknown GPIO ID " << gpioId << std::endl; +#else + sif::printWarning("LinuxLibgpioIF::pullLow: Unknown GPIO ID %d\n", gpioId); +#endif + return UNKNOWN_GPIO_ID; + } + + auto& gpioType = gpioMapIter->second->gpioType; + if (gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_CHIP + or gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_LABEL + or gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME) { + auto regularGpio = dynamic_cast(gpioMapIter->second); + if(regularGpio == nullptr) { + return GPIO_TYPE_FAILURE; + } + return driveGpio(gpioId, *regularGpio, gpio::LOW); + } + else { + auto gpioCallback = dynamic_cast(gpioMapIter->second); + if(gpioCallback->callback == nullptr) { + return GPIO_INVALID_INSTANCE; + } + gpioCallback->callback(gpioMapIter->first, gpio::GpioOperation::WRITE, + gpio::Levels::LOW, gpioCallback->callbackArgs); + return RETURN_OK; + } + return GPIO_TYPE_FAILURE; +} + +ReturnValue_t LinuxLibgpioIF::driveGpio(gpioId_t gpioId, + GpiodRegularBase& regularGpio, gpio::Levels logicLevel) { + int result = gpiod_line_set_value(regularGpio.lineHandle, logicLevel); + if (result < 0) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "LinuxLibgpioIF::driveGpio: Failed to pull GPIO with ID " << gpioId << + " to logic level " << logicLevel << std::endl; +#else + sif::printWarning("LinuxLibgpioIF::driveGpio: Failed to pull GPIO with ID %d to " + "logic level %d\n", gpioId, logicLevel); +#endif + return DRIVE_GPIO_FAILURE; + } + + return RETURN_OK; +} + +ReturnValue_t LinuxLibgpioIF::readGpio(gpioId_t gpioId, int* gpioState) { + gpioMapIter = gpioMap.find(gpioId); + if (gpioMapIter == gpioMap.end()){ +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "LinuxLibgpioIF::readGpio: Unknown GPIOD ID " << gpioId << std::endl; +#else + sif::printWarning("LinuxLibgpioIF::readGpio: Unknown GPIOD ID %d\n", gpioId); +#endif + return UNKNOWN_GPIO_ID; + } + + auto gpioType = gpioMapIter->second->gpioType; + if (gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_CHIP + or gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_LABEL + or gpioType == gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME) { + auto regularGpio = dynamic_cast(gpioMapIter->second); + if(regularGpio == nullptr) { + return GPIO_TYPE_FAILURE; + } + *gpioState = gpiod_line_get_value(regularGpio->lineHandle); + } + else { + auto gpioCallback = dynamic_cast(gpioMapIter->second); + if(gpioCallback->callback == nullptr) { + return GPIO_INVALID_INSTANCE; + } + gpioCallback->callback(gpioMapIter->first, gpio::GpioOperation::READ, + gpio::Levels::NONE, gpioCallback->callbackArgs); + return RETURN_OK; + } + return RETURN_OK; +} + +ReturnValue_t LinuxLibgpioIF::checkForConflicts(GpioMap& mapToAdd){ + ReturnValue_t status = HasReturnvaluesIF::RETURN_OK; + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + for(auto& gpioConfig: mapToAdd) { + switch(gpioConfig.second->gpioType) { + case(gpio::GpioTypes::GPIO_REGULAR_BY_CHIP): + case(gpio::GpioTypes::GPIO_REGULAR_BY_LABEL): + case(gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME): { + auto regularGpio = dynamic_cast(gpioConfig.second); + if(regularGpio == nullptr) { + return GPIO_TYPE_FAILURE; + } + // Check for conflicts and remove duplicates if necessary + result = checkForConflictsById(gpioConfig.first, gpioConfig.second->gpioType, mapToAdd); + if(result != HasReturnvaluesIF::RETURN_OK) { + status = result; + } + break; + } + case(gpio::GpioTypes::CALLBACK): { + auto callbackGpio = dynamic_cast(gpioConfig.second); + if(callbackGpio == nullptr) { + return GPIO_TYPE_FAILURE; + } + // Check for conflicts and remove duplicates if necessary + result = checkForConflictsById(gpioConfig.first, + gpioConfig.second->gpioType, mapToAdd); + if(result != HasReturnvaluesIF::RETURN_OK) { + status = result; + } + break; + } + default: { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "Invalid GPIO type detected for GPIO ID " << gpioConfig.first + << std::endl; +#else + sif::printWarning("Invalid GPIO type detected for GPIO ID %d\n", gpioConfig.first); +#endif + status = GPIO_TYPE_FAILURE; + } + } + } + return status; +} + +ReturnValue_t LinuxLibgpioIF::checkForConflictsById(gpioId_t gpioIdToCheck, + gpio::GpioTypes expectedType, GpioMap& mapToAdd) { + // Cross check with private map + gpioMapIter = gpioMap.find(gpioIdToCheck); + if(gpioMapIter != gpioMap.end()) { + auto& gpioType = gpioMapIter->second->gpioType; + bool eraseDuplicateDifferentType = false; + switch(expectedType) { + case(gpio::GpioTypes::NONE): { + break; + } + case(gpio::GpioTypes::GPIO_REGULAR_BY_CHIP): + case(gpio::GpioTypes::GPIO_REGULAR_BY_LABEL): + case(gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME): { + if(gpioType == gpio::GpioTypes::NONE or gpioType == gpio::GpioTypes::CALLBACK) { + eraseDuplicateDifferentType = true; + } + break; + } + case(gpio::GpioTypes::CALLBACK): { + if(gpioType != gpio::GpioTypes::CALLBACK) { + eraseDuplicateDifferentType = true; + } + } + } + if(eraseDuplicateDifferentType) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "LinuxLibgpioIF::checkForConflicts: ID already exists for " + "different GPIO type " << gpioIdToCheck << + ". Removing duplicate from map to add" << std::endl; +#else + sif::printWarning("LinuxLibgpioIF::checkForConflicts: ID already exists for " + "different GPIO type %d. Removing duplicate from map to add\n", gpioIdToCheck); +#endif + mapToAdd.erase(gpioIdToCheck); + return GPIO_DUPLICATE_DETECTED; + } + + // Remove element from map to add because a entry for this GPIO already exists +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "LinuxLibgpioIF::checkForConflictsRegularGpio: Duplicate GPIO " + "definition with ID " << gpioIdToCheck << " detected. " << + "Duplicate will be removed from map to add" << std::endl; +#else + sif::printWarning("LinuxLibgpioIF::checkForConflictsRegularGpio: Duplicate GPIO definition " + "with ID %d detected. Duplicate will be removed from map to add\n", gpioIdToCheck); +#endif + mapToAdd.erase(gpioIdToCheck); + return GPIO_DUPLICATE_DETECTED; + } + return HasReturnvaluesIF::RETURN_OK; +} + +void LinuxLibgpioIF::parseFindeLineResult(int result, std::string& lineName) { + switch (result) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + case LINE_NOT_EXISTS: + case LINE_ERROR: { + sif::warning << "LinuxLibgpioIF::parseFindeLineResult: Line with name " << lineName << + " does not exist" << std::endl; + break; + } + default: { + sif::warning << "LinuxLibgpioIF::parseFindeLineResult: Unknown return code for line " + "with name " << lineName << std::endl; + break; + } +#else + case LINE_NOT_EXISTS: + case LINE_ERROR: { + sif::printWarning("LinuxLibgpioIF::parseFindeLineResult: Line with name %s " + "does not exist\n", lineName); + break; + } + default: { + sif::printWarning("LinuxLibgpioIF::parseFindeLineResult: Unknown return code for line " + "with name %s\n", lineName); + break; + } +#endif + } + +} diff --git a/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.h b/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.h new file mode 100644 index 00000000..cc32bd70 --- /dev/null +++ b/hal/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.h @@ -0,0 +1,91 @@ +#ifndef LINUX_GPIO_LINUXLIBGPIOIF_H_ +#define LINUX_GPIO_LINUXLIBGPIOIF_H_ + +#include "fsfw/returnvalues/FwClassIds.h" +#include "fsfw_hal/common/gpio/GpioIF.h" +#include "fsfw/objectmanager/SystemObject.h" + +class GpioCookie; +class GpiodRegularIF; + +/** + * @brief This class implements the GpioIF for a linux based system. + * @details + * This implementation is based on the libgpiod lib which requires Linux 4.8 or higher. + * @note + * The Petalinux SDK from Xilinx supports libgpiod since Petalinux 2019.1. + */ +class LinuxLibgpioIF : public GpioIF, public SystemObject { +public: + + static const uint8_t gpioRetvalId = CLASS_ID::HAL_GPIO; + + static constexpr ReturnValue_t UNKNOWN_GPIO_ID = + HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 1); + static constexpr ReturnValue_t DRIVE_GPIO_FAILURE = + HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 2); + static constexpr ReturnValue_t GPIO_TYPE_FAILURE = + HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 3); + static constexpr ReturnValue_t GPIO_INVALID_INSTANCE = + HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 4); + static constexpr ReturnValue_t GPIO_DUPLICATE_DETECTED = + HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 5); + + LinuxLibgpioIF(object_id_t objectId); + virtual ~LinuxLibgpioIF(); + + ReturnValue_t addGpios(GpioCookie* gpioCookie) override; + ReturnValue_t pullHigh(gpioId_t gpioId) override; + ReturnValue_t pullLow(gpioId_t gpioId) override; + ReturnValue_t readGpio(gpioId_t gpioId, int* gpioState) override; + +private: + + static const size_t MAX_CHIPNAME_LENGTH = 11; + static const int LINE_NOT_EXISTS = 0; + static const int LINE_ERROR = -1; + static const int LINE_FOUND = 1; + + // Holds the information and configuration of all used GPIOs + GpioUnorderedMap gpioMap; + GpioUnorderedMapIter gpioMapIter; + + /** + * @brief This functions drives line of a GPIO specified by the GPIO ID. + * + * @param gpioId The GPIO ID of the GPIO to drive. + * @param logiclevel The logic level to set. O or 1. + */ + ReturnValue_t driveGpio(gpioId_t gpioId, GpiodRegularBase& regularGpio, + gpio::Levels logicLevel); + + ReturnValue_t configureGpioByLabel(gpioId_t gpioId, GpiodRegularByLabel& gpioByLabel); + ReturnValue_t configureGpioByChip(gpioId_t gpioId, GpiodRegularByChip& gpioByChip); + ReturnValue_t configureGpioByLineName(gpioId_t gpioId, + GpiodRegularByLineName &gpioByLineName); + ReturnValue_t configureRegularGpio(gpioId_t gpioId, struct gpiod_chip* chip, + GpiodRegularBase& regularGpio, std::string failOutput); + + /** + * @brief This function checks if GPIOs are already registered and whether + * there exists a conflict in the GPIO configuration. E.g. the + * direction. + * + * @param mapToAdd The GPIOs which shall be added to the gpioMap. + * + * @return RETURN_OK if successful, otherwise RETURN_FAILED + */ + ReturnValue_t checkForConflicts(GpioMap& mapToAdd); + + ReturnValue_t checkForConflictsById(gpioId_t gpiodId, gpio::GpioTypes type, + GpioMap& mapToAdd); + + /** + * @brief Performs the initial configuration of all GPIOs specified in the GpioMap mapToAdd. + */ + ReturnValue_t configureGpios(GpioMap& mapToAdd); + + void parseFindeLineResult(int result, std::string& lineName); +}; + +#endif /* LINUX_GPIO_LINUXLIBGPIOIF_H_ */ diff --git a/hal/src/fsfw_hal/linux/i2c/CMakeLists.txt b/hal/src/fsfw_hal/linux/i2c/CMakeLists.txt new file mode 100644 index 00000000..3eb0882c --- /dev/null +++ b/hal/src/fsfw_hal/linux/i2c/CMakeLists.txt @@ -0,0 +1,8 @@ +target_sources(${LIB_FSFW_NAME} PUBLIC + I2cComIF.cpp + I2cCookie.cpp +) + + + + diff --git a/hal/src/fsfw_hal/linux/i2c/I2cComIF.cpp b/hal/src/fsfw_hal/linux/i2c/I2cComIF.cpp new file mode 100644 index 00000000..98d9a510 --- /dev/null +++ b/hal/src/fsfw_hal/linux/i2c/I2cComIF.cpp @@ -0,0 +1,205 @@ +#include "fsfw_hal/linux/i2c/I2cComIF.h" +#include "fsfw_hal/linux/utility.h" +#include "fsfw_hal/linux/UnixFileGuard.h" + +#include "fsfw/serviceinterface/ServiceInterface.h" + +#include +#include +#include +#include +#include + +#include + + +I2cComIF::I2cComIF(object_id_t objectId): SystemObject(objectId){ +} + +I2cComIF::~I2cComIF() {} + +ReturnValue_t I2cComIF::initializeInterface(CookieIF* cookie) { + + address_t i2cAddress; + std::string deviceFile; + + if(cookie == nullptr) { + sif::error << "I2cComIF::initializeInterface: Invalid cookie!" << std::endl; + return NULLPOINTER; + } + I2cCookie* i2cCookie = dynamic_cast(cookie); + if(i2cCookie == nullptr) { + sif::error << "I2cComIF::initializeInterface: Invalid I2C cookie!" << std::endl; + return NULLPOINTER; + } + + i2cAddress = i2cCookie->getAddress(); + + i2cDeviceMapIter = i2cDeviceMap.find(i2cAddress); + if(i2cDeviceMapIter == i2cDeviceMap.end()) { + size_t maxReplyLen = i2cCookie->getMaxReplyLen(); + I2cInstance i2cInstance = {std::vector(maxReplyLen), 0}; + auto statusPair = i2cDeviceMap.emplace(i2cAddress, i2cInstance); + if (not statusPair.second) { + sif::error << "I2cComIF::initializeInterface: Failed to insert device with address " << + i2cAddress << "to I2C device " << "map" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + return HasReturnvaluesIF::RETURN_OK; + } + + sif::error << "I2cComIF::initializeInterface: Device with address " << i2cAddress << + "already in use" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; +} + +ReturnValue_t I2cComIF::sendMessage(CookieIF *cookie, + const uint8_t *sendData, size_t sendLen) { + + ReturnValue_t result; + int fd; + std::string deviceFile; + + if(sendData == nullptr) { + sif::error << "I2cComIF::sendMessage: Send Data is nullptr" + << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + + if(sendLen == 0) { + return HasReturnvaluesIF::RETURN_OK; + } + + I2cCookie* i2cCookie = dynamic_cast(cookie); + if(i2cCookie == nullptr) { + sif::error << "I2cComIF::sendMessage: Invalid I2C Cookie!" << std::endl; + return NULLPOINTER; + } + + address_t i2cAddress = i2cCookie->getAddress(); + i2cDeviceMapIter = i2cDeviceMap.find(i2cAddress); + if (i2cDeviceMapIter == i2cDeviceMap.end()) { + sif::error << "I2cComIF::sendMessage: i2cAddress of Cookie not " + << "registered in i2cDeviceMap" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + + deviceFile = i2cCookie->getDeviceFile(); + UnixFileGuard fileHelper(deviceFile, &fd, O_RDWR, "I2cComIF::sendMessage"); + if(fileHelper.getOpenResult() != HasReturnvaluesIF::RETURN_OK) { + return fileHelper.getOpenResult(); + } + result = openDevice(deviceFile, i2cAddress, &fd); + if (result != HasReturnvaluesIF::RETURN_OK){ + return result; + } + + if (write(fd, sendData, sendLen) != (int)sendLen) { + sif::error << "I2cComIF::sendMessage: Failed to send data to I2C " + "device with error code " << errno << ". Error description: " + << strerror(errno) << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t I2cComIF::getSendSuccess(CookieIF *cookie) { + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t I2cComIF::requestReceiveMessage(CookieIF *cookie, + size_t requestLen) { + ReturnValue_t result; + int fd; + std::string deviceFile; + + if (requestLen == 0) { + return HasReturnvaluesIF::RETURN_OK; + } + + I2cCookie* i2cCookie = dynamic_cast(cookie); + if(i2cCookie == nullptr) { + sif::error << "I2cComIF::requestReceiveMessage: Invalid I2C Cookie!" << std::endl; + i2cDeviceMapIter->second.replyLen = 0; + return NULLPOINTER; + } + + address_t i2cAddress = i2cCookie->getAddress(); + i2cDeviceMapIter = i2cDeviceMap.find(i2cAddress); + if (i2cDeviceMapIter == i2cDeviceMap.end()) { + sif::error << "I2cComIF::requestReceiveMessage: i2cAddress of Cookie not " + << "registered in i2cDeviceMap" << std::endl; + i2cDeviceMapIter->second.replyLen = 0; + return HasReturnvaluesIF::RETURN_FAILED; + } + + deviceFile = i2cCookie->getDeviceFile(); + UnixFileGuard fileHelper(deviceFile, &fd, O_RDWR, "I2cComIF::requestReceiveMessage"); + if(fileHelper.getOpenResult() != HasReturnvaluesIF::RETURN_OK) { + return fileHelper.getOpenResult(); + } + result = openDevice(deviceFile, i2cAddress, &fd); + if (result != HasReturnvaluesIF::RETURN_OK){ + i2cDeviceMapIter->second.replyLen = 0; + return result; + } + + uint8_t* replyBuffer = i2cDeviceMapIter->second.replyBuffer.data(); + + int readLen = read(fd, replyBuffer, requestLen); + if (readLen != static_cast(requestLen)) { +#if FSFW_VERBOSE_LEVEL >= 1 and FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "I2cComIF::requestReceiveMessage: Reading from I2C " + << "device failed with error code " << errno <<". Description" + << " of error: " << strerror(errno) << std::endl; + sif::error << "I2cComIF::requestReceiveMessage: Read only " << readLen << " from " + << requestLen << " bytes" << std::endl; +#endif + i2cDeviceMapIter->second.replyLen = 0; + sif::debug << "I2cComIF::requestReceiveMessage: Read " << readLen << " of " << requestLen << " bytes" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + + i2cDeviceMapIter->second.replyLen = requestLen; + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t I2cComIF::readReceivedMessage(CookieIF *cookie, + uint8_t **buffer, size_t* size) { + I2cCookie* i2cCookie = dynamic_cast(cookie); + if(i2cCookie == nullptr) { + sif::error << "I2cComIF::readReceivedMessage: Invalid I2C Cookie!" << std::endl; + return NULLPOINTER; + } + + address_t i2cAddress = i2cCookie->getAddress(); + i2cDeviceMapIter = i2cDeviceMap.find(i2cAddress); + if (i2cDeviceMapIter == i2cDeviceMap.end()) { + sif::error << "I2cComIF::readReceivedMessage: i2cAddress of Cookie not " + << "found in i2cDeviceMap" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + *buffer = i2cDeviceMapIter->second.replyBuffer.data(); + *size = i2cDeviceMapIter->second.replyLen; + + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t I2cComIF::openDevice(std::string deviceFile, + address_t i2cAddress, int* fileDescriptor) { + + if (ioctl(*fileDescriptor, I2C_SLAVE, i2cAddress) < 0) { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "I2cComIF: Specifying target device failed with error code " << errno << "." + << std::endl; + sif::warning << "Error description " << strerror(errno) << std::endl; +#else + sif::printWarning("I2cComIF: Specifying target device failed with error code %d.\n"); + sif::printWarning("Error description: %s\n", strerror(errno)); +#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ +#endif /* FSFW_VERBOSE_LEVEL >= 1 */ + return HasReturnvaluesIF::RETURN_FAILED; + } + return HasReturnvaluesIF::RETURN_OK; +} diff --git a/hal/src/fsfw_hal/linux/i2c/I2cComIF.h b/hal/src/fsfw_hal/linux/i2c/I2cComIF.h new file mode 100644 index 00000000..0856c9bd --- /dev/null +++ b/hal/src/fsfw_hal/linux/i2c/I2cComIF.h @@ -0,0 +1,61 @@ +#ifndef LINUX_I2C_I2COMIF_H_ +#define LINUX_I2C_I2COMIF_H_ + +#include "I2cCookie.h" +#include +#include + +#include +#include + +/** + * @brief This is the communication interface for I2C devices connected + * to a system running a Linux OS. + * + * @note The Xilinx Linux kernel might not support to read more than 255 bytes at once. + * + * @author J. Meier + */ +class I2cComIF: public DeviceCommunicationIF, public SystemObject { +public: + I2cComIF(object_id_t objectId); + + virtual ~I2cComIF(); + + ReturnValue_t initializeInterface(CookieIF * cookie) override; + ReturnValue_t sendMessage(CookieIF *cookie,const uint8_t *sendData, + size_t sendLen) override; + ReturnValue_t getSendSuccess(CookieIF *cookie) override; + ReturnValue_t requestReceiveMessage(CookieIF *cookie, + size_t requestLen) override; + ReturnValue_t readReceivedMessage(CookieIF *cookie, uint8_t **buffer, + size_t *size) override; + +private: + + struct I2cInstance { + std::vector replyBuffer; + size_t replyLen; + }; + + using I2cDeviceMap = std::unordered_map; + using I2cDeviceMapIter = I2cDeviceMap::iterator; + + /* In this map all i2c devices will be registered with their address and + * the appropriate file descriptor will be stored */ + I2cDeviceMap i2cDeviceMap; + I2cDeviceMapIter i2cDeviceMapIter; + + /** + * @brief This function opens an I2C device and binds the opened file + * to a specific I2C address. + * @param deviceFile The name of the device file. E.g. i2c-0 + * @param i2cAddress The address of the i2c slave device. + * @param fileDescriptor Pointer to device descriptor. + * @return RETURN_OK if successful, otherwise RETURN_FAILED. + */ + ReturnValue_t openDevice(std::string deviceFile, + address_t i2cAddress, int* fileDescriptor); +}; + +#endif /* LINUX_I2C_I2COMIF_H_ */ diff --git a/hal/src/fsfw_hal/linux/i2c/I2cCookie.cpp b/hal/src/fsfw_hal/linux/i2c/I2cCookie.cpp new file mode 100644 index 00000000..aebffedb --- /dev/null +++ b/hal/src/fsfw_hal/linux/i2c/I2cCookie.cpp @@ -0,0 +1,20 @@ +#include "fsfw_hal/linux/i2c/I2cCookie.h" + +I2cCookie::I2cCookie(address_t i2cAddress_, size_t maxReplyLen_, + std::string deviceFile_) : + i2cAddress(i2cAddress_), maxReplyLen(maxReplyLen_), deviceFile(deviceFile_) { +} + +address_t I2cCookie::getAddress() const { + return i2cAddress; +} + +size_t I2cCookie::getMaxReplyLen() const { + return maxReplyLen; +} + +std::string I2cCookie::getDeviceFile() const { + return deviceFile; +} + +I2cCookie::~I2cCookie() {} diff --git a/hal/src/fsfw_hal/linux/i2c/I2cCookie.h b/hal/src/fsfw_hal/linux/i2c/I2cCookie.h new file mode 100644 index 00000000..888a2b12 --- /dev/null +++ b/hal/src/fsfw_hal/linux/i2c/I2cCookie.h @@ -0,0 +1,38 @@ +#ifndef LINUX_I2C_I2CCOOKIE_H_ +#define LINUX_I2C_I2CCOOKIE_H_ + +#include +#include + +/** + * @brief Cookie for the i2cDeviceComIF. + * + * @author J. Meier + */ +class I2cCookie: public CookieIF { +public: + + /** + * @brief Constructor for the I2C cookie. + * @param i2cAddress_ The i2c address of the target device. + * @param maxReplyLen_ The maximum expected length of a reply from the + * target device. + * @param devicFile_ The device file specifying the i2c interface to use. E.g. "/dev/i2c-0". + */ + I2cCookie(address_t i2cAddress_, size_t maxReplyLen_, + std::string deviceFile_); + + virtual ~I2cCookie(); + + address_t getAddress() const; + size_t getMaxReplyLen() const; + std::string getDeviceFile() const; + +private: + + address_t i2cAddress = 0; + size_t maxReplyLen = 0; + std::string deviceFile; +}; + +#endif /* LINUX_I2C_I2CCOOKIE_H_ */ diff --git a/hal/src/fsfw_hal/linux/rpi/CMakeLists.txt b/hal/src/fsfw_hal/linux/rpi/CMakeLists.txt new file mode 100644 index 00000000..47be218c --- /dev/null +++ b/hal/src/fsfw_hal/linux/rpi/CMakeLists.txt @@ -0,0 +1,3 @@ +target_sources(${LIB_FSFW_NAME} PRIVATE + GpioRPi.cpp +) \ No newline at end of file diff --git a/hal/src/fsfw_hal/linux/rpi/GpioRPi.cpp b/hal/src/fsfw_hal/linux/rpi/GpioRPi.cpp new file mode 100644 index 00000000..e1c274c0 --- /dev/null +++ b/hal/src/fsfw_hal/linux/rpi/GpioRPi.cpp @@ -0,0 +1,38 @@ +#include "fsfw/FSFW.h" + +#include "fsfw_hal/linux/rpi/GpioRPi.h" +#include "fsfw_hal/common/gpio/GpioCookie.h" + +#include + + +ReturnValue_t gpio::createRpiGpioConfig(GpioCookie* cookie, gpioId_t gpioId, int bcmPin, + std::string consumer, gpio::Direction direction, int initValue) { + if(cookie == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + + auto config = new GpiodRegularByChip(); + /* Default chipname for Raspberry Pi. There is still gpiochip1 for expansion, but most users + will not need this */ + config->chipname = "gpiochip0"; + + config->consumer = consumer; + config->direction = direction; + config->initValue = initValue; + + /* Sanity check for the BCM pins before assigning it */ + if(bcmPin > 27) { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "createRpiGpioConfig: BCM pin " << bcmPin << " invalid!" << std::endl; +#else + sif::printError("createRpiGpioConfig: BCM pin %d invalid!\n", bcmPin); +#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ +#endif /* FSFW_VERBOSE_LEVEL >= 1 */ + return HasReturnvaluesIF::RETURN_FAILED; + } + config->lineNum = bcmPin; + cookie->addGpio(gpioId, config); + return HasReturnvaluesIF::RETURN_OK; +} diff --git a/hal/src/fsfw_hal/linux/rpi/GpioRPi.h b/hal/src/fsfw_hal/linux/rpi/GpioRPi.h new file mode 100644 index 00000000..54917e6d --- /dev/null +++ b/hal/src/fsfw_hal/linux/rpi/GpioRPi.h @@ -0,0 +1,26 @@ +#ifndef BSP_RPI_GPIO_GPIORPI_H_ +#define BSP_RPI_GPIO_GPIORPI_H_ + +#include +#include "../../common/gpio/gpioDefinitions.h" + +class GpioCookie; + +namespace gpio { + +/** + * Create a GpioConfig_t. This function does a sanity check on the BCM pin number and fails if the + * BCM pin is invalid. + * @param cookie Adds the configuration to this cookie directly + * @param gpioId ID which identifies the GPIO configuration + * @param bcmPin Raspberry Pi BCM pin + * @param consumer Information string + * @param direction GPIO direction + * @param initValue Intial value for output pins, 0 for low, 1 for high + * @return + */ +ReturnValue_t createRpiGpioConfig(GpioCookie* cookie, gpioId_t gpioId, int bcmPin, + std::string consumer, gpio::Direction direction, int initValue); +} + +#endif /* BSP_RPI_GPIO_GPIORPI_H_ */ diff --git a/hal/src/fsfw_hal/linux/spi/CMakeLists.txt b/hal/src/fsfw_hal/linux/spi/CMakeLists.txt new file mode 100644 index 00000000..404e1f47 --- /dev/null +++ b/hal/src/fsfw_hal/linux/spi/CMakeLists.txt @@ -0,0 +1,8 @@ +target_sources(${LIB_FSFW_NAME} PUBLIC + SpiComIF.cpp + SpiCookie.cpp +) + + + + diff --git a/hal/src/fsfw_hal/linux/spi/SpiComIF.cpp b/hal/src/fsfw_hal/linux/spi/SpiComIF.cpp new file mode 100644 index 00000000..9c4e66ae --- /dev/null +++ b/hal/src/fsfw_hal/linux/spi/SpiComIF.cpp @@ -0,0 +1,408 @@ +#include "fsfw/FSFW.h" +#include "fsfw_hal/linux/spi/SpiComIF.h" +#include "fsfw_hal/linux/spi/SpiCookie.h" +#include "fsfw_hal/linux/utility.h" +#include "fsfw_hal/linux/UnixFileGuard.h" + +#include +#include + +#include +#include +#include +#include + +#include +#include + +SpiComIF::SpiComIF(object_id_t objectId, GpioIF* gpioComIF): + SystemObject(objectId), gpioComIF(gpioComIF) { + if(gpioComIF == nullptr) { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "SpiComIF::SpiComIF: GPIO communication interface invalid!" << std::endl; +#else + sif::printError("SpiComIF::SpiComIF: GPIO communication interface invalid!\n"); +#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ +#endif /* FSFW_VERBOSE_LEVEL >= 1 */ + } + + spiMutex = MutexFactory::instance()->createMutex(); +} + +ReturnValue_t SpiComIF::initializeInterface(CookieIF *cookie) { + int retval = 0; + SpiCookie* spiCookie = dynamic_cast(cookie); + if(spiCookie == nullptr) { + return NULLPOINTER; + } + + address_t spiAddress = spiCookie->getSpiAddress(); + + auto iter = spiDeviceMap.find(spiAddress); + if(iter == spiDeviceMap.end()) { + size_t bufferSize = spiCookie->getMaxBufferSize(); + SpiInstance spiInstance(bufferSize); + auto statusPair = spiDeviceMap.emplace(spiAddress, spiInstance); + if (not statusPair.second) { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "SpiComIF::initializeInterface: Failed to insert device with address " << + spiAddress << "to SPI device map" << std::endl; +#else + sif::printError("SpiComIF::initializeInterface: Failed to insert device with address " + "%lu to SPI device map\n", static_cast(spiAddress)); +#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ +#endif /* FSFW_VERBOSE_LEVEL >= 1 */ + return HasReturnvaluesIF::RETURN_FAILED; + } + /* Now we emplaced the read buffer in the map, we still need to assign that location + to the SPI driver transfer struct */ + spiCookie->assignReadBuffer(statusPair.first->second.replyBuffer.data()); + } + else { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "SpiComIF::initializeInterface: SPI address already exists!" << std::endl; +#else + sif::printError("SpiComIF::initializeInterface: SPI address already exists!\n"); +#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ +#endif /* FSFW_VERBOSE_LEVEL >= 1 */ + return HasReturnvaluesIF::RETURN_FAILED; + } + + /* Pull CS high in any case to be sure that device is inactive */ + gpioId_t gpioId = spiCookie->getChipSelectPin(); + if(gpioId != gpio::NO_GPIO) { + gpioComIF->pullHigh(gpioId); + } + + uint32_t spiSpeed = 0; + spi::SpiModes spiMode = spi::SpiModes::MODE_0; + + SpiCookie::UncommonParameters params; + spiCookie->getSpiParameters(spiMode, spiSpeed, ¶ms); + + int fileDescriptor = 0; + UnixFileGuard fileHelper(spiCookie->getSpiDevice(), &fileDescriptor, O_RDWR, + "SpiComIF::initializeInterface"); + if(fileHelper.getOpenResult() != HasReturnvaluesIF::RETURN_OK) { + return fileHelper.getOpenResult(); + } + + /* These flags are rather uncommon */ + if(params.threeWireSpi or params.noCs or params.csHigh) { + uint32_t currentMode = 0; + retval = ioctl(fileDescriptor, SPI_IOC_RD_MODE32, ¤tMode); + if(retval != 0) { + utility::handleIoctlError("SpiComIF::initialiezInterface: Could not read full mode!"); + } + + if(params.threeWireSpi) { + currentMode |= SPI_3WIRE; + } + if(params.noCs) { + /* Some drivers like the Raspberry Pi ignore this flag in any case */ + currentMode |= SPI_NO_CS; + } + if(params.csHigh) { + currentMode |= SPI_CS_HIGH; + } + /* Write adapted mode */ + retval = ioctl(fileDescriptor, SPI_IOC_WR_MODE32, ¤tMode); + if(retval != 0) { + utility::handleIoctlError("SpiComIF::initialiezInterface: Could not write full mode!"); + } + } + if(params.lsbFirst) { + retval = ioctl(fileDescriptor, SPI_IOC_WR_LSB_FIRST, ¶ms.lsbFirst); + if(retval != 0) { + utility::handleIoctlError("SpiComIF::initializeInterface: Setting LSB first failed"); + } + } + if(params.bitsPerWord != 8) { + retval = ioctl(fileDescriptor, SPI_IOC_WR_BITS_PER_WORD, ¶ms.bitsPerWord); + if(retval != 0) { + utility::handleIoctlError("SpiComIF::initializeInterface: " + "Could not write bits per word!"); + } + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t SpiComIF::sendMessage(CookieIF *cookie, const uint8_t *sendData, size_t sendLen) { + SpiCookie* spiCookie = dynamic_cast(cookie); + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + + if(spiCookie == nullptr) { + return NULLPOINTER; + } + + if(sendLen > spiCookie->getMaxBufferSize()) { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "SpiComIF::sendMessage: Too much data sent, send length " << sendLen << + "larger than maximum buffer length " << spiCookie->getMaxBufferSize() << std::endl; +#else + sif::printWarning("SpiComIF::sendMessage: Too much data sent, send length %lu larger " + "than maximum buffer length %lu!\n", static_cast(sendLen), + static_cast(spiCookie->getMaxBufferSize())); +#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ +#endif /* FSFW_VERBOSE_LEVEL >= 1 */ + return DeviceCommunicationIF::TOO_MUCH_DATA; + } + + if(spiCookie->getComIfMode() == spi::SpiComIfModes::REGULAR) { + result = performRegularSendOperation(spiCookie, sendData, sendLen); + } + else if(spiCookie->getComIfMode() == spi::SpiComIfModes::CALLBACK) { + spi::send_callback_function_t sendFunc = nullptr; + void* funcArgs = nullptr; + spiCookie->getCallback(&sendFunc, &funcArgs); + if(sendFunc != nullptr) { + result = sendFunc(this, spiCookie, sendData, sendLen, funcArgs); + } + } + return result; +} + +ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie *spiCookie, const uint8_t *sendData, + size_t sendLen) { + address_t spiAddress = spiCookie->getSpiAddress(); + auto iter = spiDeviceMap.find(spiAddress); + if(iter != spiDeviceMap.end()) { + spiCookie->assignReadBuffer(iter->second.replyBuffer.data()); + } + + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + int retval = 0; + /* Prepare transfer */ + int fileDescriptor = 0; + std::string device = spiCookie->getSpiDevice(); + UnixFileGuard fileHelper(device, &fileDescriptor, O_RDWR, "SpiComIF::sendMessage"); + if(fileHelper.getOpenResult() != HasReturnvaluesIF::RETURN_OK) { + return OPENING_FILE_FAILED; + } + spi::SpiModes spiMode = spi::SpiModes::MODE_0; + uint32_t spiSpeed = 0; + spiCookie->getSpiParameters(spiMode, spiSpeed, nullptr); + setSpiSpeedAndMode(fileDescriptor, spiMode, spiSpeed); + spiCookie->assignWriteBuffer(sendData); + spiCookie->setTransferSize(sendLen); + + bool fullDuplex = spiCookie->isFullDuplex(); + gpioId_t gpioId = spiCookie->getChipSelectPin(); + + /* Pull SPI CS low. For now, no support for active high given */ + if(gpioId != gpio::NO_GPIO) { + result = spiMutex->lockMutex(timeoutType, timeoutMs); + if (result != RETURN_OK) { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "SpiComIF::sendMessage: Failed to lock mutex" << std::endl; +#else + sif::printError("SpiComIF::sendMessage: Failed to lock mutex\n"); +#endif +#endif + return result; + } + ReturnValue_t result = gpioComIF->pullLow(gpioId); + if(result != HasReturnvaluesIF::RETURN_OK) { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "SpiComIF::sendMessage: Pulling low CS pin failed" << std::endl; +#else + sif::printWarning("SpiComIF::sendMessage: Pulling low CS pin failed"); +#endif +#endif + return result; + } + } + + /* Execute transfer */ + if(fullDuplex) { + /* Initiate a full duplex SPI transfer. */ + retval = ioctl(fileDescriptor, SPI_IOC_MESSAGE(1), spiCookie->getTransferStructHandle()); + if(retval < 0) { + utility::handleIoctlError("SpiComIF::sendMessage: ioctl error."); + result = FULL_DUPLEX_TRANSFER_FAILED; + } +#if FSFW_HAL_SPI_WIRETAPPING == 1 + performSpiWiretapping(spiCookie); +#endif /* FSFW_LINUX_SPI_WIRETAPPING == 1 */ + } + else { + /* We write with a blocking half-duplex transfer here */ + if (write(fileDescriptor, sendData, sendLen) != static_cast(sendLen)) { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "SpiComIF::sendMessage: Half-Duplex write operation failed!" << + std::endl; +#else + sif::printWarning("SpiComIF::sendMessage: Half-Duplex write operation failed!\n"); +#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ +#endif /* FSFW_VERBOSE_LEVEL >= 1 */ + result = HALF_DUPLEX_TRANSFER_FAILED; + } + } + + if(gpioId != gpio::NO_GPIO) { + gpioComIF->pullHigh(gpioId); + result = spiMutex->unlockMutex(); + if (result != RETURN_OK) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "SpiComIF::sendMessage: Failed to unlock mutex" << std::endl; +#endif + return result; + } + } + return result; +} + +ReturnValue_t SpiComIF::getSendSuccess(CookieIF *cookie) { + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t SpiComIF::requestReceiveMessage(CookieIF *cookie, size_t requestLen) { + SpiCookie* spiCookie = dynamic_cast(cookie); + if(spiCookie == nullptr) { + return NULLPOINTER; + } + + if(spiCookie->isFullDuplex()) { + return HasReturnvaluesIF::RETURN_OK; + } + + return performHalfDuplexReception(spiCookie); +} + + +ReturnValue_t SpiComIF::performHalfDuplexReception(SpiCookie* spiCookie) { + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + std::string device = spiCookie->getSpiDevice(); + int fileDescriptor = 0; + UnixFileGuard fileHelper(device, &fileDescriptor, O_RDWR, + "SpiComIF::requestReceiveMessage"); + if(fileHelper.getOpenResult() != HasReturnvaluesIF::RETURN_OK) { + return OPENING_FILE_FAILED; + } + + uint8_t* rxBuf = nullptr; + size_t readSize = spiCookie->getCurrentTransferSize(); + result = getReadBuffer(spiCookie->getSpiAddress(), &rxBuf); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + gpioId_t gpioId = spiCookie->getChipSelectPin(); + if(gpioId != gpio::NO_GPIO) { + result = spiMutex->lockMutex(timeoutType, timeoutMs); + if (result != RETURN_OK) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "SpiComIF::getSendSuccess: Failed to lock mutex" << std::endl; +#endif + return result; + } + gpioComIF->pullLow(gpioId); + } + + if(read(fileDescriptor, rxBuf, readSize) != static_cast(readSize)) { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "SpiComIF::sendMessage: Half-Duplex read operation failed!" << std::endl; +#else + sif::printWarning("SpiComIF::sendMessage: Half-Duplex read operation failed!\n"); +#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ +#endif /* FSFW_VERBOSE_LEVEL >= 1 */ + result = HALF_DUPLEX_TRANSFER_FAILED; + } + + if(gpioId != gpio::NO_GPIO) { + gpioComIF->pullHigh(gpioId); + result = spiMutex->unlockMutex(); + if (result != RETURN_OK) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "SpiComIF::getSendSuccess: Failed to unlock mutex" << std::endl; +#endif + return result; + } + } + + return result; +} + +ReturnValue_t SpiComIF::readReceivedMessage(CookieIF *cookie, uint8_t **buffer, size_t *size) { + SpiCookie* spiCookie = dynamic_cast(cookie); + if(spiCookie == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + uint8_t* rxBuf = nullptr; + ReturnValue_t result = getReadBuffer(spiCookie->getSpiAddress(), &rxBuf); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + *buffer = rxBuf; + *size = spiCookie->getCurrentTransferSize(); + spiCookie->setTransferSize(0); + return HasReturnvaluesIF::RETURN_OK; +} + +MutexIF* SpiComIF::getMutex(MutexIF::TimeoutType* timeoutType, uint32_t* timeoutMs) { + if(timeoutType != nullptr) { + *timeoutType = this->timeoutType; + } + if(timeoutMs != nullptr) { + *timeoutMs = this->timeoutMs; + } + return spiMutex; +} + +void SpiComIF::performSpiWiretapping(SpiCookie* spiCookie) { + if(spiCookie == nullptr) { + return; + } + size_t dataLen = spiCookie->getTransferStructHandle()->len; + uint8_t* dataPtr = reinterpret_cast(spiCookie->getTransferStructHandle()->tx_buf); +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "Sent SPI data: " << std::endl; + arrayprinter::print(dataPtr, dataLen, OutputType::HEX, false); + sif::info << "Received SPI data: " << std::endl; +#else + sif::printInfo("Sent SPI data: \n"); + arrayprinter::print(dataPtr, dataLen, OutputType::HEX, false); + sif::printInfo("Received SPI data: \n"); +#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ + dataPtr = reinterpret_cast(spiCookie->getTransferStructHandle()->rx_buf); + arrayprinter::print(dataPtr, dataLen, OutputType::HEX, false); +} + +ReturnValue_t SpiComIF::getReadBuffer(address_t spiAddress, uint8_t** buffer) { + if(buffer == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + + auto iter = spiDeviceMap.find(spiAddress); + if(iter == spiDeviceMap.end()) { + return HasReturnvaluesIF::RETURN_FAILED; + } + + *buffer = iter->second.replyBuffer.data(); + return HasReturnvaluesIF::RETURN_OK; +} + +GpioIF* SpiComIF::getGpioInterface() { + return gpioComIF; +} + +void SpiComIF::setSpiSpeedAndMode(int spiFd, spi::SpiModes mode, uint32_t speed) { + int retval = ioctl(spiFd, SPI_IOC_WR_MODE, reinterpret_cast(&mode)); + if(retval != 0) { + utility::handleIoctlError("SpiComIF::setSpiSpeedAndMode: Setting SPI mode failed"); + } + + retval = ioctl(spiFd, SPI_IOC_WR_MAX_SPEED_HZ, &speed); + if(retval != 0) { + utility::handleIoctlError("SpiComIF::setSpiSpeedAndMode: Setting SPI speed failed"); + } +} diff --git a/hal/src/fsfw_hal/linux/spi/SpiComIF.h b/hal/src/fsfw_hal/linux/spi/SpiComIF.h new file mode 100644 index 00000000..bcca7462 --- /dev/null +++ b/hal/src/fsfw_hal/linux/spi/SpiComIF.h @@ -0,0 +1,91 @@ +#ifndef LINUX_SPI_SPICOMIF_H_ +#define LINUX_SPI_SPICOMIF_H_ + +#include "fsfw/FSFW.h" +#include "spiDefinitions.h" +#include "returnvalues/classIds.h" +#include "fsfw_hal/common/gpio/GpioIF.h" + +#include "fsfw/devicehandlers/DeviceCommunicationIF.h" +#include "fsfw/objectmanager/SystemObject.h" + +#include +#include + +class SpiCookie; + +/** + * @brief Encapsulates access to linux SPI driver for FSFW objects + * @details + * Right now, only full-duplex SPI is supported. Most device specific transfer properties + * are contained in the SPI cookie. + * @author R. Mueller + */ +class SpiComIF: public DeviceCommunicationIF, public SystemObject { +public: + static constexpr uint8_t spiRetvalId = CLASS_ID::HAL_SPI; + static constexpr ReturnValue_t OPENING_FILE_FAILED = + HasReturnvaluesIF::makeReturnCode(spiRetvalId, 0); + /* Full duplex (ioctl) transfer failure */ + static constexpr ReturnValue_t FULL_DUPLEX_TRANSFER_FAILED = + HasReturnvaluesIF::makeReturnCode(spiRetvalId, 1); + /* Half duplex (read/write) transfer failure */ + static constexpr ReturnValue_t HALF_DUPLEX_TRANSFER_FAILED = + HasReturnvaluesIF::makeReturnCode(spiRetvalId, 2); + + SpiComIF(object_id_t objectId, GpioIF* gpioComIF); + + ReturnValue_t initializeInterface(CookieIF * cookie) override; + ReturnValue_t sendMessage(CookieIF *cookie,const uint8_t *sendData, + size_t sendLen) override; + ReturnValue_t getSendSuccess(CookieIF *cookie) override; + ReturnValue_t requestReceiveMessage(CookieIF *cookie, + size_t requestLen) override; + ReturnValue_t readReceivedMessage(CookieIF *cookie, uint8_t **buffer, + size_t *size) override; + + /** + * @brief This function returns the mutex which can be used to protect the spi bus when + * the chip select must be driven from outside of the com if. + */ + MutexIF* getMutex(MutexIF::TimeoutType* timeoutType = nullptr, uint32_t* timeoutMs = nullptr); + + /** + * Perform a regular send operation using Linux iotcl. This is public so it can be used + * in functions like a user callback if special handling is only necessary for certain commands. + * @param spiCookie + * @param sendData + * @param sendLen + * @return + */ + ReturnValue_t performRegularSendOperation(SpiCookie* spiCookie, const uint8_t *sendData, + size_t sendLen); + + GpioIF* getGpioInterface(); + void setSpiSpeedAndMode(int spiFd, spi::SpiModes mode, uint32_t speed); + void performSpiWiretapping(SpiCookie* spiCookie); + + ReturnValue_t getReadBuffer(address_t spiAddress, uint8_t** buffer); + +private: + + struct SpiInstance { + SpiInstance(size_t maxRecvSize): replyBuffer(std::vector(maxRecvSize)) {} + std::vector replyBuffer; + }; + + GpioIF* gpioComIF = nullptr; + + MutexIF* spiMutex = nullptr; + MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING; + uint32_t timeoutMs = 20; + + using SpiDeviceMap = std::unordered_map; + using SpiDeviceMapIter = SpiDeviceMap::iterator; + + SpiDeviceMap spiDeviceMap; + + ReturnValue_t performHalfDuplexReception(SpiCookie* spiCookie); +}; + +#endif /* LINUX_SPI_SPICOMIF_H_ */ diff --git a/hal/src/fsfw_hal/linux/spi/SpiCookie.cpp b/hal/src/fsfw_hal/linux/spi/SpiCookie.cpp new file mode 100644 index 00000000..f07954e9 --- /dev/null +++ b/hal/src/fsfw_hal/linux/spi/SpiCookie.cpp @@ -0,0 +1,144 @@ +#include "fsfw_hal/linux/spi/SpiCookie.h" + +SpiCookie::SpiCookie(address_t spiAddress, gpioId_t chipSelect, std::string spiDev, + const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed): + SpiCookie(spi::SpiComIfModes::REGULAR, spiAddress, chipSelect, spiDev, maxSize, spiMode, + spiSpeed, nullptr, nullptr) { + +} + +SpiCookie::SpiCookie(address_t spiAddress, std::string spiDev, const size_t maxSize, + spi::SpiModes spiMode, uint32_t spiSpeed): + SpiCookie(spiAddress, gpio::NO_GPIO, spiDev, maxSize, spiMode, spiSpeed) { +} + +SpiCookie::SpiCookie(address_t spiAddress, gpioId_t chipSelect, std::string spiDev, + const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed, + spi::send_callback_function_t callback, void *args): + SpiCookie(spi::SpiComIfModes::CALLBACK, spiAddress, chipSelect, spiDev, maxSize, + spiMode, spiSpeed, callback, args) { +} + +SpiCookie::SpiCookie(spi::SpiComIfModes comIfMode, address_t spiAddress, gpioId_t chipSelect, + std::string spiDev, const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed, + spi::send_callback_function_t callback, void* args): + spiAddress(spiAddress), chipSelectPin(chipSelect), spiDevice(spiDev), + comIfMode(comIfMode), maxSize(maxSize), spiMode(spiMode), spiSpeed(spiSpeed), + sendCallback(callback), callbackArgs(args) { +} + +spi::SpiComIfModes SpiCookie::getComIfMode() const { + return this->comIfMode; +} + +void SpiCookie::getSpiParameters(spi::SpiModes& spiMode, uint32_t& spiSpeed, + UncommonParameters* parameters) const { + spiMode = this->spiMode; + spiSpeed = this->spiSpeed; + + if(parameters != nullptr) { + parameters->threeWireSpi = uncommonParameters.threeWireSpi; + parameters->lsbFirst = uncommonParameters.lsbFirst; + parameters->noCs = uncommonParameters.noCs; + parameters->bitsPerWord = uncommonParameters.bitsPerWord; + parameters->csHigh = uncommonParameters.csHigh; + } +} + +gpioId_t SpiCookie::getChipSelectPin() const { + return chipSelectPin; +} + +size_t SpiCookie::getMaxBufferSize() const { + return maxSize; +} + +address_t SpiCookie::getSpiAddress() const { + return spiAddress; +} + +std::string SpiCookie::getSpiDevice() const { + return spiDevice; +} + +void SpiCookie::setThreeWireSpi(bool enable) { + uncommonParameters.threeWireSpi = enable; +} + +void SpiCookie::setLsbFirst(bool enable) { + uncommonParameters.lsbFirst = enable; +} + +void SpiCookie::setNoCs(bool enable) { + uncommonParameters.noCs = enable; +} + +void SpiCookie::setBitsPerWord(uint8_t bitsPerWord) { + uncommonParameters.bitsPerWord = bitsPerWord; +} + +void SpiCookie::setCsHigh(bool enable) { + uncommonParameters.csHigh = enable; +} + +void SpiCookie::activateCsDeselect(bool deselectCs, uint16_t delayUsecs) { + spiTransferStruct.cs_change = deselectCs; + spiTransferStruct.delay_usecs = delayUsecs; +} + +void SpiCookie::assignReadBuffer(uint8_t* rx) { + if(rx != nullptr) { + spiTransferStruct.rx_buf = reinterpret_cast<__u64>(rx); + } +} + +void SpiCookie::assignWriteBuffer(const uint8_t* tx) { + if(tx != nullptr) { + spiTransferStruct.tx_buf = reinterpret_cast<__u64>(tx); + } +} + +void SpiCookie::setCallbackMode(spi::send_callback_function_t callback, + void *args) { + this->comIfMode = spi::SpiComIfModes::CALLBACK; + this->sendCallback = callback; + this->callbackArgs = args; +} + +void SpiCookie::setCallbackArgs(void *args) { + this->callbackArgs = args; +} + +spi_ioc_transfer* SpiCookie::getTransferStructHandle() { + return &spiTransferStruct; +} + +void SpiCookie::setFullOrHalfDuplex(bool halfDuplex) { + this->halfDuplex = halfDuplex; +} + +bool SpiCookie::isFullDuplex() const { + return not this->halfDuplex; +} + +void SpiCookie::setTransferSize(size_t transferSize) { + spiTransferStruct.len = transferSize; +} + +size_t SpiCookie::getCurrentTransferSize() const { + return spiTransferStruct.len; +} + +void SpiCookie::setSpiSpeed(uint32_t newSpeed) { + this->spiSpeed = newSpeed; +} + +void SpiCookie::setSpiMode(spi::SpiModes newMode) { + this->spiMode = newMode; +} + +void SpiCookie::getCallback(spi::send_callback_function_t *callback, + void **args) { + *callback = this->sendCallback; + *args = this->callbackArgs; +} diff --git a/hal/src/fsfw_hal/linux/spi/SpiCookie.h b/hal/src/fsfw_hal/linux/spi/SpiCookie.h new file mode 100644 index 00000000..844fd421 --- /dev/null +++ b/hal/src/fsfw_hal/linux/spi/SpiCookie.h @@ -0,0 +1,183 @@ +#ifndef LINUX_SPI_SPICOOKIE_H_ +#define LINUX_SPI_SPICOOKIE_H_ + +#include "spiDefinitions.h" +#include "../../common/gpio/gpioDefinitions.h" + +#include + +#include + +/** + * @brief This cookie class is passed to the SPI communication interface + * @details + * This cookie contains device specific properties like speed and SPI mode or the SPI transfer + * struct required by the Linux SPI driver. It also contains a handle to a GPIO interface + * to perform slave select switching when necessary. + * + * The user can specify gpio::NO_GPIO as the GPIO ID or use a custom send callback to meet + * special requirements like expander slave select switching (e.g. GPIO or I2C expander) + * or special timing related requirements. + */ +class SpiCookie: public CookieIF { +public: + /** + * Each SPI device will have a corresponding cookie. The cookie is used by the communication + * interface and contains device specific information like the largest expected size to be + * sent and received and the GPIO pin used to toggle the SPI slave select pin. + * @param spiAddress + * @param chipSelect Chip select. gpio::NO_GPIO can be used for hardware slave selects. + * @param spiDev + * @param maxSize + */ + SpiCookie(address_t spiAddress, gpioId_t chipSelect, std::string spiDev, + const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed); + + /** + * Like constructor above, but without a dedicated GPIO CS. Can be used for hardware + * slave select or if CS logic is performed with decoders. + */ + SpiCookie(address_t spiAddress, std::string spiDev, const size_t maxReplySize, + spi::SpiModes spiMode, uint32_t spiSpeed); + + /** + * Use the callback mode of the SPI communication interface. The user can pass the callback + * function here or by using the setter function #setCallbackMode + */ + SpiCookie(address_t spiAddress, gpioId_t chipSelect, std::string spiDev, const size_t maxSize, + spi::SpiModes spiMode, uint32_t spiSpeed, spi::send_callback_function_t callback, + void *args); + + /** + * Get the callback function + * @param callback + * @param args + */ + void getCallback(spi::send_callback_function_t* callback, void** args); + + address_t getSpiAddress() const; + std::string getSpiDevice() const; + gpioId_t getChipSelectPin() const; + size_t getMaxBufferSize() const; + + spi::SpiComIfModes getComIfMode() const; + + /** Enables changing SPI speed at run-time */ + void setSpiSpeed(uint32_t newSpeed); + /** Enables changing the SPI mode at run-time */ + void setSpiMode(spi::SpiModes newMode); + + /** + * Set the SPI to callback mode and assigns the user supplied callback and an argument + * passed to the callback. + * @param callback + * @param args + */ + void setCallbackMode(spi::send_callback_function_t callback, void* args); + + /** + * Can be used to set the callback arguments and a later point than initialization. + * @param args + */ + void setCallbackArgs(void* args); + + /** + * True if SPI transfers should be performed in full duplex mode + * @return + */ + bool isFullDuplex() const; + + /** + * Set transfer type to full duplex or half duplex. Full duplex is the default setting, + * ressembling common SPI hardware implementation with shift registers, where read and writes + * happen simultaneosly. + * @param fullDuplex + */ + void setFullOrHalfDuplex(bool halfDuplex); + + /** + * This needs to be called to specify where the SPI driver writes to or reads from. + * @param readLocation + * @param writeLocation + */ + void assignReadBuffer(uint8_t* rx); + void assignWriteBuffer(const uint8_t* tx); + /** + * Set size for the next transfer. Set to 0 for no transfer + * @param transferSize + */ + void setTransferSize(size_t transferSize); + size_t getCurrentTransferSize() const; + + struct UncommonParameters { + uint8_t bitsPerWord = 8; + bool noCs = false; + bool csHigh = false; + bool threeWireSpi = false; + /* MSB first is more common */ + bool lsbFirst = false; + }; + + /** + * Can be used to explicitely disable hardware chip select. + * Some drivers like the Raspberry Pi Linux driver will not use hardware chip select by default + * (see https://www.raspberrypi.org/documentation/hardware/raspberrypi/spi/README.md) + * @param enable + */ + void setNoCs(bool enable); + void setThreeWireSpi(bool enable); + void setLsbFirst(bool enable); + void setCsHigh(bool enable); + void setBitsPerWord(uint8_t bitsPerWord); + + void getSpiParameters(spi::SpiModes& spiMode, uint32_t& spiSpeed, + UncommonParameters* parameters = nullptr) const; + + /** + * See spidev.h cs_change and delay_usecs + * @param deselectCs + * @param delayUsecs + */ + void activateCsDeselect(bool deselectCs, uint16_t delayUsecs); + + spi_ioc_transfer* getTransferStructHandle(); +private: + + /** + * Internal constructor which initializes every field + * @param spiAddress + * @param chipSelect + * @param spiDev + * @param maxSize + * @param spiMode + * @param spiSpeed + * @param callback + * @param args + */ + SpiCookie(spi::SpiComIfModes comIfMode, address_t spiAddress, gpioId_t chipSelect, + std::string spiDev, const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed, + spi::send_callback_function_t callback, void* args); + + address_t spiAddress; + gpioId_t chipSelectPin; + std::string spiDevice; + + spi::SpiComIfModes comIfMode; + + // Required for regular mode + const size_t maxSize; + spi::SpiModes spiMode; + uint32_t spiSpeed; + bool halfDuplex = false; + + // Required for callback mode + spi::send_callback_function_t sendCallback = nullptr; + void* callbackArgs = nullptr; + + struct spi_ioc_transfer spiTransferStruct = {}; + UncommonParameters uncommonParameters; +}; + + + +#endif /* LINUX_SPI_SPICOOKIE_H_ */ diff --git a/hal/src/fsfw_hal/linux/spi/spiDefinitions.h b/hal/src/fsfw_hal/linux/spi/spiDefinitions.h new file mode 100644 index 00000000..14af4fd5 --- /dev/null +++ b/hal/src/fsfw_hal/linux/spi/spiDefinitions.h @@ -0,0 +1,28 @@ +#ifndef LINUX_SPI_SPIDEFINITONS_H_ +#define LINUX_SPI_SPIDEFINITONS_H_ + +#include "../../common/gpio/gpioDefinitions.h" +#include "../../common/spi/spiCommon.h" + +#include "fsfw/returnvalues/HasReturnvaluesIF.h" +#include + +#include + +class SpiCookie; +class SpiComIF; + +namespace spi { + +enum SpiComIfModes { + REGULAR, + CALLBACK +}; + + +using send_callback_function_t = ReturnValue_t (*) (SpiComIF* comIf, SpiCookie *cookie, + const uint8_t *sendData, size_t sendLen, void* args); + +} + +#endif /* LINUX_SPI_SPIDEFINITONS_H_ */ diff --git a/hal/src/fsfw_hal/linux/uart/CMakeLists.txt b/hal/src/fsfw_hal/linux/uart/CMakeLists.txt new file mode 100644 index 00000000..21ed0278 --- /dev/null +++ b/hal/src/fsfw_hal/linux/uart/CMakeLists.txt @@ -0,0 +1,4 @@ +target_sources(${LIB_FSFW_NAME} PUBLIC + UartComIF.cpp + UartCookie.cpp +) diff --git a/hal/src/fsfw_hal/linux/uart/UartComIF.cpp b/hal/src/fsfw_hal/linux/uart/UartComIF.cpp new file mode 100644 index 00000000..f5754c6e --- /dev/null +++ b/hal/src/fsfw_hal/linux/uart/UartComIF.cpp @@ -0,0 +1,529 @@ +#include "UartComIF.h" +#include "OBSWConfig.h" + +#include "fsfw_hal/linux/utility.h" +#include "fsfw/serviceinterface/ServiceInterface.h" + +#include +#include +#include +#include +#include + +UartComIF::UartComIF(object_id_t objectId): SystemObject(objectId){ +} + +UartComIF::~UartComIF() {} + +ReturnValue_t UartComIF::initializeInterface(CookieIF* cookie) { + + std::string deviceFile; + UartDeviceMapIter uartDeviceMapIter; + + if(cookie == nullptr) { + return NULLPOINTER; + } + + UartCookie* uartCookie = dynamic_cast(cookie); + if (uartCookie == nullptr) { + sif::error << "UartComIF::initializeInterface: Invalid UART Cookie!" << std::endl; + return NULLPOINTER; + } + + deviceFile = uartCookie->getDeviceFile(); + + uartDeviceMapIter = uartDeviceMap.find(deviceFile); + if(uartDeviceMapIter == uartDeviceMap.end()) { + int fileDescriptor = configureUartPort(uartCookie); + if (fileDescriptor < 0) { + return RETURN_FAILED; + } + size_t maxReplyLen = uartCookie->getMaxReplyLen(); + UartElements uartElements = {fileDescriptor, std::vector(maxReplyLen), 0}; + auto status = uartDeviceMap.emplace(deviceFile, uartElements); + if (status.second == false) { + sif::warning << "UartComIF::initializeInterface: Failed to insert device " << + deviceFile << "to UART device map" << std::endl; + return RETURN_FAILED; + } + } + else { + sif::warning << "UartComIF::initializeInterface: UART device " << deviceFile << + " already in use" << std::endl; + return RETURN_FAILED; + } + + return RETURN_OK; +} + +int UartComIF::configureUartPort(UartCookie* uartCookie) { + + struct termios options = {}; + + std::string deviceFile = uartCookie->getDeviceFile(); + int flags = O_RDWR; + if(uartCookie->getUartMode() == UartModes::CANONICAL) { + // In non-canonical mode, don't specify O_NONBLOCK because these properties will be + // controlled by the VTIME and VMIN parameters and O_NONBLOCK would override this + flags |= O_NONBLOCK; + } + int fd = open(deviceFile.c_str(), flags); + + if (fd < 0) { + sif::warning << "UartComIF::configureUartPort: Failed to open uart " << deviceFile << + "with error code " << errno << strerror(errno) << std::endl; + return fd; + } + + /* Read in existing settings */ + if(tcgetattr(fd, &options) != 0) { + sif::warning << "UartComIF::configureUartPort: Error " << errno << "from tcgetattr: " + << strerror(errno) << std::endl; + return fd; + } + + setParityOptions(&options, uartCookie); + setStopBitOptions(&options, uartCookie); + setDatasizeOptions(&options, uartCookie); + setFixedOptions(&options); + setUartMode(&options, *uartCookie); + if(uartCookie->getInputShouldBeFlushed()) { + tcflush(fd, TCIFLUSH); + } + + /* Sets uart to non-blocking mode. Read returns immediately when there are no data available */ + options.c_cc[VTIME] = 0; + options.c_cc[VMIN] = 0; + + configureBaudrate(&options, uartCookie); + + /* Save option settings */ + if (tcsetattr(fd, TCSANOW, &options) != 0) { + sif::warning << "UartComIF::configureUartPort: Failed to set options with error " << + errno << ": " << strerror(errno); + return fd; + } + return fd; +} + +void UartComIF::setParityOptions(struct termios* options, UartCookie* uartCookie) { + /* Clear parity bit */ + options->c_cflag &= ~PARENB; + switch (uartCookie->getParity()) { + case Parity::EVEN: + options->c_cflag |= PARENB; + options->c_cflag &= ~PARODD; + break; + case Parity::ODD: + options->c_cflag |= PARENB; + options->c_cflag |= PARODD; + break; + default: + break; + } +} + +void UartComIF::setStopBitOptions(struct termios* options, UartCookie* uartCookie) { + /* Clear stop field. Sets stop bit to one bit */ + options->c_cflag &= ~CSTOPB; + switch (uartCookie->getStopBits()) { + case StopBits::TWO_STOP_BITS: + options->c_cflag |= CSTOPB; + break; + default: + break; + } +} + +void UartComIF::setDatasizeOptions(struct termios* options, UartCookie* uartCookie) { + /* Clear size bits */ + options->c_cflag &= ~CSIZE; + switch (uartCookie->getBitsPerWord()) { + case 5: + options->c_cflag |= CS5; + break; + case 6: + options->c_cflag |= CS6; + break; + case 7: + options->c_cflag |= CS7; + break; + case 8: + options->c_cflag |= CS8; + break; + default: + sif::warning << "UartComIF::setDatasizeOptions: Invalid size specified" << std::endl; + break; + } +} + +void UartComIF::setFixedOptions(struct termios* options) { + /* Disable RTS/CTS hardware flow control */ + options->c_cflag &= ~CRTSCTS; + /* Turn on READ & ignore ctrl lines (CLOCAL = 1) */ + options->c_cflag |= CREAD | CLOCAL; + /* Disable echo */ + options->c_lflag &= ~ECHO; + /* Disable erasure */ + options->c_lflag &= ~ECHOE; + /* Disable new-line echo */ + options->c_lflag &= ~ECHONL; + /* Disable interpretation of INTR, QUIT and SUSP */ + options->c_lflag &= ~ISIG; + /* Turn off s/w flow ctrl */ + options->c_iflag &= ~(IXON | IXOFF | IXANY); + /* Disable any special handling of received bytes */ + options->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL); + /* Prevent special interpretation of output bytes (e.g. newline chars) */ + options->c_oflag &= ~OPOST; + /* Prevent conversion of newline to carriage return/line feed */ + options->c_oflag &= ~ONLCR; +} + +void UartComIF::configureBaudrate(struct termios* options, UartCookie* uartCookie) { + switch (uartCookie->getBaudrate()) { + case 50: + cfsetispeed(options, B50); + cfsetospeed(options, B50); + break; + case 75: + cfsetispeed(options, B75); + cfsetospeed(options, B75); + break; + case 110: + cfsetispeed(options, B110); + cfsetospeed(options, B110); + break; + case 134: + cfsetispeed(options, B134); + cfsetospeed(options, B134); + break; + case 150: + cfsetispeed(options, B150); + cfsetospeed(options, B150); + break; + case 200: + cfsetispeed(options, B200); + cfsetospeed(options, B200); + break; + case 300: + cfsetispeed(options, B300); + cfsetospeed(options, B300); + break; + case 600: + cfsetispeed(options, B600); + cfsetospeed(options, B600); + break; + case 1200: + cfsetispeed(options, B1200); + cfsetospeed(options, B1200); + break; + case 1800: + cfsetispeed(options, B1800); + cfsetospeed(options, B1800); + break; + case 2400: + cfsetispeed(options, B2400); + cfsetospeed(options, B2400); + break; + case 4800: + cfsetispeed(options, B4800); + cfsetospeed(options, B4800); + break; + case 9600: + cfsetispeed(options, B9600); + cfsetospeed(options, B9600); + break; + case 19200: + cfsetispeed(options, B19200); + cfsetospeed(options, B19200); + break; + case 38400: + cfsetispeed(options, B38400); + cfsetospeed(options, B38400); + break; + case 57600: + cfsetispeed(options, B57600); + cfsetospeed(options, B57600); + break; + case 115200: + cfsetispeed(options, B115200); + cfsetospeed(options, B115200); + break; + case 230400: + cfsetispeed(options, B230400); + cfsetospeed(options, B230400); + break; + case 460800: + cfsetispeed(options, B460800); + cfsetospeed(options, B460800); + break; + default: + sif::warning << "UartComIF::configureBaudrate: Baudrate not supported" << std::endl; + break; + } +} + +ReturnValue_t UartComIF::sendMessage(CookieIF *cookie, + const uint8_t *sendData, size_t sendLen) { + int fd = 0; + std::string deviceFile; + UartDeviceMapIter uartDeviceMapIter; + + if(sendLen == 0) { + return RETURN_OK; + } + + if(sendData == nullptr) { + sif::warning << "UartComIF::sendMessage: Send data is nullptr" << std::endl; + return RETURN_FAILED; + } + + UartCookie* uartCookie = dynamic_cast(cookie); + if(uartCookie == nullptr) { + sif::warning << "UartComIF::sendMessasge: Invalid UART Cookie!" << std::endl; + return NULLPOINTER; + } + + deviceFile = uartCookie->getDeviceFile(); + uartDeviceMapIter = uartDeviceMap.find(deviceFile); + if (uartDeviceMapIter == uartDeviceMap.end()) { + sif::debug << "UartComIF::sendMessage: Device file " << deviceFile << + "not in UART map" << std::endl; + return RETURN_FAILED; + } + + fd = uartDeviceMapIter->second.fileDescriptor; + + if (write(fd, sendData, sendLen) != (int)sendLen) { + sif::error << "UartComIF::sendMessage: Failed to send data with error code " << + errno << ": Error description: " << strerror(errno) << std::endl; + return RETURN_FAILED; + } + + return RETURN_OK; +} + +ReturnValue_t UartComIF::getSendSuccess(CookieIF *cookie) { + return RETURN_OK; +} + +ReturnValue_t UartComIF::requestReceiveMessage(CookieIF *cookie, size_t requestLen) { + std::string deviceFile; + UartDeviceMapIter uartDeviceMapIter; + + UartCookie* uartCookie = dynamic_cast(cookie); + if(uartCookie == nullptr) { + sif::debug << "UartComIF::requestReceiveMessage: Invalid Uart Cookie!" << std::endl; + return NULLPOINTER; + } + + UartModes uartMode = uartCookie->getUartMode(); + deviceFile = uartCookie->getDeviceFile(); + uartDeviceMapIter = uartDeviceMap.find(deviceFile); + + if(uartMode == UartModes::NON_CANONICAL and requestLen == 0) { + return RETURN_OK; + } + + if (uartDeviceMapIter == uartDeviceMap.end()) { + sif::debug << "UartComIF::requestReceiveMessage: Device file " << deviceFile + << " not in uart map" << std::endl; + return RETURN_FAILED; + } + + if (uartMode == UartModes::CANONICAL) { + return handleCanonicalRead(*uartCookie, uartDeviceMapIter, requestLen); + } + else if (uartMode == UartModes::NON_CANONICAL) { + return handleNoncanonicalRead(*uartCookie, uartDeviceMapIter, requestLen); + } + else { + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +ReturnValue_t UartComIF::handleCanonicalRead(UartCookie& uartCookie, UartDeviceMapIter& iter, + size_t requestLen) { + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + uint8_t maxReadCycles = uartCookie.getReadCycles(); + uint8_t currentReadCycles = 0; + int bytesRead = 0; + size_t currentBytesRead = 0; + size_t maxReplySize = uartCookie.getMaxReplyLen(); + int fd = iter->second.fileDescriptor; + auto bufferPtr = iter->second.replyBuffer.data(); + iter->second.replyLen = 0; + do { + size_t allowedReadSize = 0; + if(currentBytesRead >= maxReplySize) { + // Overflow risk. Emit warning, trigger event and break. If this happens, + // the reception buffer is not large enough or data is not polled often enough. +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "UartComIF::requestReceiveMessage: Next read would cause overflow!" + << std::endl; +#else + sif::printWarning("UartComIF::requestReceiveMessage: " + "Next read would cause overflow!"); +#endif +#endif + result = UART_RX_BUFFER_TOO_SMALL; + break; + } + else { + allowedReadSize = maxReplySize - currentBytesRead; + } + + bytesRead = read(fd, bufferPtr, allowedReadSize); + if (bytesRead < 0) { + // EAGAIN: No data available in non-blocking mode + if(errno != EAGAIN) { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "UartComIF::handleCanonicalRead: read failed with code" << + errno << ": " << strerror(errno) << std::endl; +#else + sif::printWarning("UartComIF::handleCanonicalRead: read failed with code %d: %s\n", + errno, strerror(errno)); +#endif +#endif + return RETURN_FAILED; + } + + } + else if(bytesRead > 0) { + iter->second.replyLen += bytesRead; + bufferPtr += bytesRead; + currentBytesRead += bytesRead; + } + currentReadCycles++; + } while(bytesRead > 0 and currentReadCycles < maxReadCycles); + return result; +} + +ReturnValue_t UartComIF::handleNoncanonicalRead(UartCookie &uartCookie, UartDeviceMapIter &iter, + size_t requestLen) { + int fd = iter->second.fileDescriptor; + auto bufferPtr = iter->second.replyBuffer.data(); + // Size check to prevent buffer overflow + if(requestLen > uartCookie.getMaxReplyLen()) { +#if OBSW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "UartComIF::requestReceiveMessage: Next read would cause overflow!" + << std::endl; +#else + sif::printWarning("UartComIF::requestReceiveMessage: " + "Next read would cause overflow!"); +#endif +#endif + return UART_RX_BUFFER_TOO_SMALL; + } + int bytesRead = read(fd, bufferPtr, requestLen); + if (bytesRead < 0) { + return RETURN_FAILED; + } + else if (bytesRead != static_cast(requestLen)) { + if(uartCookie.isReplySizeFixed()) { + sif::warning << "UartComIF::requestReceiveMessage: Only read " << bytesRead << + " of " << requestLen << " bytes" << std::endl; + return RETURN_FAILED; + } + } + iter->second.replyLen = bytesRead; + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t UartComIF::readReceivedMessage(CookieIF *cookie, + uint8_t **buffer, size_t* size) { + + std::string deviceFile; + UartDeviceMapIter uartDeviceMapIter; + + UartCookie* uartCookie = dynamic_cast(cookie); + if(uartCookie == nullptr) { + sif::debug << "UartComIF::readReceivedMessage: Invalid uart cookie!" << std::endl; + return NULLPOINTER; + } + + deviceFile = uartCookie->getDeviceFile(); + uartDeviceMapIter = uartDeviceMap.find(deviceFile); + if (uartDeviceMapIter == uartDeviceMap.end()) { + sif::debug << "UartComIF::readReceivedMessage: Device file " << deviceFile << + " not in uart map" << std::endl; + return RETURN_FAILED; + } + + *buffer = uartDeviceMapIter->second.replyBuffer.data(); + *size = uartDeviceMapIter->second.replyLen; + + /* Length is reset to 0 to prevent reading the same data twice */ + uartDeviceMapIter->second.replyLen = 0; + + return RETURN_OK; +} + +ReturnValue_t UartComIF::flushUartRxBuffer(CookieIF *cookie) { + std::string deviceFile; + UartDeviceMapIter uartDeviceMapIter; + UartCookie* uartCookie = dynamic_cast(cookie); + if(uartCookie == nullptr) { + sif::warning << "UartComIF::flushUartRxBuffer: Invalid uart cookie!" << std::endl; + return NULLPOINTER; + } + deviceFile = uartCookie->getDeviceFile(); + uartDeviceMapIter = uartDeviceMap.find(deviceFile); + if(uartDeviceMapIter != uartDeviceMap.end()) { + int fd = uartDeviceMapIter->second.fileDescriptor; + tcflush(fd, TCIFLUSH); + return RETURN_OK; + } + return RETURN_FAILED; +} + +ReturnValue_t UartComIF::flushUartTxBuffer(CookieIF *cookie) { + std::string deviceFile; + UartDeviceMapIter uartDeviceMapIter; + UartCookie* uartCookie = dynamic_cast(cookie); + if(uartCookie == nullptr) { + sif::warning << "UartComIF::flushUartTxBuffer: Invalid uart cookie!" << std::endl; + return NULLPOINTER; + } + deviceFile = uartCookie->getDeviceFile(); + uartDeviceMapIter = uartDeviceMap.find(deviceFile); + if(uartDeviceMapIter != uartDeviceMap.end()) { + int fd = uartDeviceMapIter->second.fileDescriptor; + tcflush(fd, TCOFLUSH); + return RETURN_OK; + } + return RETURN_FAILED; +} + +ReturnValue_t UartComIF::flushUartTxAndRxBuf(CookieIF *cookie) { + std::string deviceFile; + UartDeviceMapIter uartDeviceMapIter; + UartCookie* uartCookie = dynamic_cast(cookie); + if(uartCookie == nullptr) { + sif::warning << "UartComIF::flushUartTxAndRxBuf: Invalid uart cookie!" << std::endl; + return NULLPOINTER; + } + deviceFile = uartCookie->getDeviceFile(); + uartDeviceMapIter = uartDeviceMap.find(deviceFile); + if(uartDeviceMapIter != uartDeviceMap.end()) { + int fd = uartDeviceMapIter->second.fileDescriptor; + tcflush(fd, TCIOFLUSH); + return RETURN_OK; + } + return RETURN_FAILED; +} + +void UartComIF::setUartMode(struct termios *options, UartCookie &uartCookie) { + UartModes uartMode = uartCookie.getUartMode(); + if(uartMode == UartModes::NON_CANONICAL) { + /* Disable canonical mode */ + options->c_lflag &= ~ICANON; + } + else if(uartMode == UartModes::CANONICAL) { + options->c_lflag |= ICANON; + } +} diff --git a/hal/src/fsfw_hal/linux/uart/UartComIF.h b/hal/src/fsfw_hal/linux/uart/UartComIF.h new file mode 100644 index 00000000..68d2b9f5 --- /dev/null +++ b/hal/src/fsfw_hal/linux/uart/UartComIF.h @@ -0,0 +1,125 @@ +#ifndef BSP_Q7S_COMIF_UARTCOMIF_H_ +#define BSP_Q7S_COMIF_UARTCOMIF_H_ + +#include "UartCookie.h" +#include +#include + +#include +#include + +/** + * @brief This is the communication interface to access serial ports on linux based operating + * systems. + * + * @details The implementation follows the instructions from https://blog.mbedded.ninja/programming/ + * operating-systems/linux/linux-serial-ports-using-c-cpp/#disabling-canonical-mode + * + * @author J. Meier + */ +class UartComIF: public DeviceCommunicationIF, public SystemObject { +public: + static constexpr uint8_t uartRetvalId = CLASS_ID::HAL_UART; + + static constexpr ReturnValue_t UART_READ_FAILURE = + HasReturnvaluesIF::makeReturnCode(uartRetvalId, 1); + static constexpr ReturnValue_t UART_READ_SIZE_MISSMATCH = + HasReturnvaluesIF::makeReturnCode(uartRetvalId, 2); + static constexpr ReturnValue_t UART_RX_BUFFER_TOO_SMALL = + HasReturnvaluesIF::makeReturnCode(uartRetvalId, 3); + + UartComIF(object_id_t objectId); + + virtual ~UartComIF(); + + ReturnValue_t initializeInterface(CookieIF * cookie) override; + ReturnValue_t sendMessage(CookieIF *cookie,const uint8_t *sendData, + size_t sendLen) override; + ReturnValue_t getSendSuccess(CookieIF *cookie) override; + ReturnValue_t requestReceiveMessage(CookieIF *cookie, + size_t requestLen) override; + ReturnValue_t readReceivedMessage(CookieIF *cookie, uint8_t **buffer, + size_t *size) override; + + /** + * @brief This function discards all data received but not read in the UART buffer. + */ + ReturnValue_t flushUartRxBuffer(CookieIF *cookie); + + /** + * @brief This function discards all data in the transmit buffer of the UART driver. + */ + ReturnValue_t flushUartTxBuffer(CookieIF *cookie); + + /** + * @brief This function discards both data in the transmit and receive buffer of the UART. + */ + ReturnValue_t flushUartTxAndRxBuf(CookieIF *cookie); + +private: + + using UartDeviceFile_t = std::string; + + struct UartElements { + int fileDescriptor; + std::vector replyBuffer; + /** Number of bytes read will be written to this variable */ + size_t replyLen; + }; + + using UartDeviceMap = std::unordered_map; + using UartDeviceMapIter = UartDeviceMap::iterator; + + /** + * The uart devie map stores informations of initialized uart ports. + */ + UartDeviceMap uartDeviceMap; + + /** + * @brief This function opens and configures a uart device by using the information stored + * in the uart cookie. + * @param uartCookie Pointer to uart cookie with information about the uart. Contains the + * uart device file, baudrate, parity, stopbits etc. + * @return The file descriptor of the configured uart. + */ + int configureUartPort(UartCookie* uartCookie); + + /** + * @brief This function adds the parity settings to the termios options struct. + * + * @param options Pointer to termios options struct which will be modified to enable or disable + * parity checking. + * @param uartCookie Pointer to uart cookie containing the information about the desired + * parity settings. + * + */ + void setParityOptions(struct termios* options, UartCookie* uartCookie); + + void setStopBitOptions(struct termios* options, UartCookie* uartCookie); + + /** + * @brief This function sets options which are not configurable by the uartCookie. + */ + void setFixedOptions(struct termios* options); + + /** + * @brief With this function the datasize settings are added to the termios options struct. + */ + void setDatasizeOptions(struct termios* options, UartCookie* uartCookie); + + /** + * @brief This functions adds the baudrate specified in the uartCookie to the termios options + * struct. + */ + void configureBaudrate(struct termios* options, UartCookie* uartCookie); + + void setUartMode(struct termios* options, UartCookie& uartCookie); + + ReturnValue_t handleCanonicalRead(UartCookie& uartCookie, UartDeviceMapIter& iter, + size_t requestLen); + ReturnValue_t handleNoncanonicalRead(UartCookie& uartCookie, UartDeviceMapIter& iter, + size_t requestLen); + +}; + +#endif /* BSP_Q7S_COMIF_UARTCOMIF_H_ */ diff --git a/hal/src/fsfw_hal/linux/uart/UartCookie.cpp b/hal/src/fsfw_hal/linux/uart/UartCookie.cpp new file mode 100644 index 00000000..1c52e9cd --- /dev/null +++ b/hal/src/fsfw_hal/linux/uart/UartCookie.cpp @@ -0,0 +1,97 @@ +#include "fsfw_hal/linux/uart/UartCookie.h" + +#include + +UartCookie::UartCookie(object_id_t handlerId, std::string deviceFile, UartModes uartMode, + uint32_t baudrate, size_t maxReplyLen): + handlerId(handlerId), deviceFile(deviceFile), uartMode(uartMode), + baudrate(baudrate), maxReplyLen(maxReplyLen) { +} + +UartCookie::~UartCookie() {} + +uint32_t UartCookie::getBaudrate() const { + return baudrate; +} + +size_t UartCookie::getMaxReplyLen() const { + return maxReplyLen; +} + +std::string UartCookie::getDeviceFile() const { + return deviceFile; +} + +void UartCookie::setParityOdd() { + parity = Parity::ODD; +} + +void UartCookie::setParityEven() { + parity = Parity::EVEN; +} + +Parity UartCookie::getParity() const { + return parity; +} + +void UartCookie::setBitsPerWord(uint8_t bitsPerWord_) { + switch(bitsPerWord_) { + case 5: + case 6: + case 7: + case 8: + break; + default: + sif::debug << "UartCookie::setBitsPerWord: Invalid bits per word specified" << std::endl; + return; + } + bitsPerWord = bitsPerWord_; +} + +uint8_t UartCookie::getBitsPerWord() const { + return bitsPerWord; +} + +StopBits UartCookie::getStopBits() const { + return stopBits; +} + +void UartCookie::setTwoStopBits() { + stopBits = StopBits::TWO_STOP_BITS; +} + +void UartCookie::setOneStopBit() { + stopBits = StopBits::ONE_STOP_BIT; +} + +UartModes UartCookie::getUartMode() const { + return uartMode; +} + +void UartCookie::setReadCycles(uint8_t readCycles) { + this->readCycles = readCycles; +} + +void UartCookie::setToFlushInput(bool enable) { + this->flushInput = enable; +} + +uint8_t UartCookie::getReadCycles() const { + return readCycles; +} + +bool UartCookie::getInputShouldBeFlushed() { + return this->flushInput; +} + +object_id_t UartCookie::getHandlerId() const { + return this->handlerId; +} + +void UartCookie::setNoFixedSizeReply() { + replySizeFixed = false; +} + +bool UartCookie::isReplySizeFixed() { + return replySizeFixed; +} diff --git a/hal/src/fsfw_hal/linux/uart/UartCookie.h b/hal/src/fsfw_hal/linux/uart/UartCookie.h new file mode 100644 index 00000000..faf95d50 --- /dev/null +++ b/hal/src/fsfw_hal/linux/uart/UartCookie.h @@ -0,0 +1,121 @@ +#ifndef SAM9G20_COMIF_COOKIES_UART_COOKIE_H_ +#define SAM9G20_COMIF_COOKIES_UART_COOKIE_H_ + +#include +#include + +#include + +enum class Parity { + NONE, + EVEN, + ODD +}; + +enum class StopBits { + ONE_STOP_BIT, + TWO_STOP_BITS +}; + +enum class UartModes { + CANONICAL, + NON_CANONICAL +}; + +/** + * @brief Cookie for the UartComIF. There are many options available to configure the UART driver. + * The constructor only requests for common options like the baudrate. Other options can + * be set by member functions. + * + * @author J. Meier + */ +class UartCookie: public CookieIF { +public: + + /** + * @brief Constructor for the uart cookie. + * @param deviceFile The device file specifying the uart to use, e.g. "/dev/ttyPS1" + * @param uartMode Specify the UART mode. The canonical mode should be used if the + * messages are separated by a delimited character like '\n'. See the + * termios documentation for more information + * @param baudrate The baudrate to use for input and output. Possible Baudrates are: 50, + * 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, B19200, + * 38400, 57600, 115200, 230400, 460800 + * @param maxReplyLen The maximum size an object using this cookie expects + * @details + * Default configuration: No parity + * 8 databits (number of bits transfered with one uart frame) + * One stop bit + */ + UartCookie(object_id_t handlerId, std::string deviceFile, UartModes uartMode, + uint32_t baudrate, size_t maxReplyLen); + + virtual ~UartCookie(); + + uint32_t getBaudrate() const; + size_t getMaxReplyLen() const; + std::string getDeviceFile() const; + Parity getParity() const; + uint8_t getBitsPerWord() const; + StopBits getStopBits() const; + UartModes getUartMode() const; + object_id_t getHandlerId() const; + + /** + * The UART ComIF will only perform a specified number of read cycles for the canonical mode. + * The user can specify how many of those read cycles are performed for one device handler + * communication cycle. An example use-case would be to read all available GPS NMEA strings + * at once. + * @param readCycles + */ + void setReadCycles(uint8_t readCycles); + uint8_t getReadCycles() const; + + /** + * Allows to flush the data which was received but has not been read yet. This is useful + * to discard obsolete data at software startup. + */ + void setToFlushInput(bool enable); + bool getInputShouldBeFlushed(); + + /** + * Functions two enable parity checking. + */ + void setParityOdd(); + void setParityEven(); + + /** + * Function two set number of bits per UART frame. + */ + void setBitsPerWord(uint8_t bitsPerWord_); + + /** + * Function to specify the number of stopbits. + */ + void setTwoStopBits(); + void setOneStopBit(); + + /** + * Calling this function prevents the UartComIF to return failed if not all requested bytes + * could be read. This is required by a device handler when the size of a reply is not known. + */ + void setNoFixedSizeReply(); + + bool isReplySizeFixed(); + +private: + + const object_id_t handlerId; + std::string deviceFile; + const UartModes uartMode; + bool flushInput = false; + uint32_t baudrate; + size_t maxReplyLen = 0; + Parity parity = Parity::NONE; + uint8_t bitsPerWord = 8; + uint8_t readCycles = 1; + StopBits stopBits = StopBits::ONE_STOP_BIT; + bool replySizeFixed = true; +}; + +#endif diff --git a/hal/src/fsfw_hal/linux/utility.cpp b/hal/src/fsfw_hal/linux/utility.cpp new file mode 100644 index 00000000..99489e3f --- /dev/null +++ b/hal/src/fsfw_hal/linux/utility.cpp @@ -0,0 +1,26 @@ +#include "fsfw/FSFW.h" +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw_hal/linux/utility.h" + +#include +#include + +void utility::handleIoctlError(const char* const customPrintout) { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + if(customPrintout != nullptr) { + sif::warning << customPrintout << std::endl; + } + sif::warning << "handleIoctlError: Error code " << errno << ", "<< strerror(errno) << + std::endl; +#else + if(customPrintout != nullptr) { + sif::printWarning("%s\n", customPrintout); + } + sif::printWarning("handleIoctlError: Error code %d, %s\n", errno, strerror(errno)); +#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ +#endif /* FSFW_VERBOSE_LEVEL >= 1 */ + +} + + diff --git a/hal/src/fsfw_hal/linux/utility.h b/hal/src/fsfw_hal/linux/utility.h new file mode 100644 index 00000000..0353b1d0 --- /dev/null +++ b/hal/src/fsfw_hal/linux/utility.h @@ -0,0 +1,10 @@ +#ifndef LINUX_UTILITY_UTILITY_H_ +#define LINUX_UTILITY_UTILITY_H_ + +namespace utility { + +void handleIoctlError(const char* const customPrintout); + +} + +#endif /* LINUX_UTILITY_UTILITY_H_ */ diff --git a/hal/src/fsfw_hal/stm32h7/CMakeLists.txt b/hal/src/fsfw_hal/stm32h7/CMakeLists.txt new file mode 100644 index 00000000..bae3b1ac --- /dev/null +++ b/hal/src/fsfw_hal/stm32h7/CMakeLists.txt @@ -0,0 +1,7 @@ +add_subdirectory(spi) +add_subdirectory(gpio) +add_subdirectory(devicetest) + +target_sources(${LIB_FSFW_NAME} PRIVATE + dma.cpp +) diff --git a/hal/src/fsfw_hal/stm32h7/definitions.h b/hal/src/fsfw_hal/stm32h7/definitions.h new file mode 100644 index 00000000..af63a541 --- /dev/null +++ b/hal/src/fsfw_hal/stm32h7/definitions.h @@ -0,0 +1,25 @@ +#ifndef FSFW_HAL_STM32H7_DEFINITIONS_H_ +#define FSFW_HAL_STM32H7_DEFINITIONS_H_ + +#include +#include "stm32h7xx.h" + +namespace stm32h7 { + +/** + * Typedef for STM32 GPIO pair where the first entry is the port used (e.g. GPIOA) + * and the second entry is the pin number + */ +struct GpioCfg { + GpioCfg(): port(nullptr), pin(0), altFnc(0) {}; + + GpioCfg(GPIO_TypeDef* port, uint16_t pin, uint8_t altFnc = 0): + port(port), pin(pin), altFnc(altFnc) {}; + GPIO_TypeDef* port; + uint16_t pin; + uint8_t altFnc; +}; + +} + +#endif /* #ifndef FSFW_HAL_STM32H7_DEFINITIONS_H_ */ diff --git a/hal/src/fsfw_hal/stm32h7/devicetest/CMakeLists.txt b/hal/src/fsfw_hal/stm32h7/devicetest/CMakeLists.txt new file mode 100644 index 00000000..7bd4c3a9 --- /dev/null +++ b/hal/src/fsfw_hal/stm32h7/devicetest/CMakeLists.txt @@ -0,0 +1,3 @@ +target_sources(${LIB_FSFW_NAME} PRIVATE + GyroL3GD20H.cpp +) \ No newline at end of file diff --git a/hal/src/fsfw_hal/stm32h7/devicetest/GyroL3GD20H.cpp b/hal/src/fsfw_hal/stm32h7/devicetest/GyroL3GD20H.cpp new file mode 100644 index 00000000..d1fdd1e5 --- /dev/null +++ b/hal/src/fsfw_hal/stm32h7/devicetest/GyroL3GD20H.cpp @@ -0,0 +1,558 @@ +#include "fsfw_hal/stm32h7/devicetest/GyroL3GD20H.h" + +#include "fsfw_hal/stm32h7/spi/mspInit.h" +#include "fsfw_hal/stm32h7/spi/spiDefinitions.h" +#include "fsfw_hal/stm32h7/spi/spiCore.h" +#include "fsfw_hal/stm32h7/spi/spiInterrupts.h" +#include "fsfw_hal/stm32h7/spi/stm32h743zi.h" + +#include "fsfw/tasks/TaskFactory.h" +#include "fsfw/serviceinterface/ServiceInterface.h" + +#include "stm32h7xx_hal_spi.h" +#include "stm32h7xx_hal_rcc.h" + +#include + +alignas(32) std::array GyroL3GD20H::rxBuffer; +alignas(32) std::array +GyroL3GD20H::txBuffer __attribute__((section(".dma_buffer"))); + +TransferStates transferState = TransferStates::IDLE; +spi::TransferModes GyroL3GD20H::transferMode = spi::TransferModes::POLLING; + + +GyroL3GD20H::GyroL3GD20H(SPI_HandleTypeDef *spiHandle, spi::TransferModes transferMode_): + spiHandle(spiHandle) { + txDmaHandle = new DMA_HandleTypeDef(); + rxDmaHandle = new DMA_HandleTypeDef(); + spi::setSpiHandle(spiHandle); + spi::assignSpiUserArgs(spi::SpiBus::SPI_1, spiHandle); + transferMode = transferMode_; + if(transferMode == spi::TransferModes::DMA) { + mspCfg = new spi::MspDmaConfigStruct(); + auto typedCfg = dynamic_cast(mspCfg); + spi::setDmaHandles(txDmaHandle, rxDmaHandle); + stm32h7::h743zi::standardDmaCfg(*typedCfg, IrqPriorities::HIGHEST_FREERTOS, + IrqPriorities::HIGHEST_FREERTOS, IrqPriorities::HIGHEST_FREERTOS); + spi::setSpiDmaMspFunctions(typedCfg); + } + else if(transferMode == spi::TransferModes::INTERRUPT) { + mspCfg = new spi::MspIrqConfigStruct(); + auto typedCfg = dynamic_cast(mspCfg); + stm32h7::h743zi::standardInterruptCfg(*typedCfg, IrqPriorities::HIGHEST_FREERTOS); + spi::setSpiIrqMspFunctions(typedCfg); + } + else if(transferMode == spi::TransferModes::POLLING) { + mspCfg = new spi::MspPollingConfigStruct(); + auto typedCfg = dynamic_cast(mspCfg); + stm32h7::h743zi::standardPollingCfg(*typedCfg); + spi::setSpiPollingMspFunctions(typedCfg); + } + + spi::assignTransferRxTxCompleteCallback(&spiTransferCompleteCallback, nullptr); + spi::assignTransferErrorCallback(&spiTransferErrorCallback, nullptr); + + GPIO_InitTypeDef chipSelect = {}; + __HAL_RCC_GPIOD_CLK_ENABLE(); + chipSelect.Pin = GPIO_PIN_14; + chipSelect.Mode = GPIO_MODE_OUTPUT_PP; + HAL_GPIO_Init(GPIOD, &chipSelect); + HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_SET); +} + +GyroL3GD20H::~GyroL3GD20H() { + delete txDmaHandle; + delete rxDmaHandle; + if(mspCfg != nullptr) { + delete mspCfg; + } +} + +ReturnValue_t GyroL3GD20H::initialize() { + // Configure the SPI peripheral + spiHandle->Instance = SPI1; + spiHandle->Init.BaudRatePrescaler = spi::getPrescaler(HAL_RCC_GetHCLKFreq(), 3900000); + spiHandle->Init.Direction = SPI_DIRECTION_2LINES; + spi::assignSpiMode(spi::SpiModes::MODE_3, *spiHandle); + spiHandle->Init.DataSize = SPI_DATASIZE_8BIT; + spiHandle->Init.FirstBit = SPI_FIRSTBIT_MSB; + spiHandle->Init.TIMode = SPI_TIMODE_DISABLE; + spiHandle->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; + spiHandle->Init.CRCPolynomial = 7; + spiHandle->Init.CRCLength = SPI_CRC_LENGTH_8BIT; + spiHandle->Init.NSS = SPI_NSS_SOFT; + spiHandle->Init.NSSPMode = SPI_NSS_PULSE_DISABLE; + // Recommended setting to avoid glitches + spiHandle->Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE; + spiHandle->Init.Mode = SPI_MODE_MASTER; + if(HAL_SPI_Init(spiHandle) != HAL_OK) { + sif::printWarning("Error initializing SPI\n"); + return HasReturnvaluesIF::RETURN_FAILED; + } + + delete mspCfg; + transferState = TransferStates::WAIT; + + sif::printInfo("GyroL3GD20H::performOperation: Reading WHO AM I register\n"); + + txBuffer[0] = WHO_AM_I_REG | STM_READ_MASK; + txBuffer[1] = 0; + + switch(transferMode) { + case(spi::TransferModes::DMA): { + return handleDmaTransferInit(); + } + case(spi::TransferModes::INTERRUPT): { + return handleInterruptTransferInit(); + } + case(spi::TransferModes::POLLING): { + return handlePollingTransferInit(); + } + default: { + return HasReturnvaluesIF::RETURN_FAILED; + } + } + + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t GyroL3GD20H::performOperation() { + switch(transferMode) { + case(spi::TransferModes::DMA): { + return handleDmaSensorRead(); + } + case(spi::TransferModes::POLLING): { + return handlePollingSensorRead(); + } + case(spi::TransferModes::INTERRUPT): { + return handleInterruptSensorRead(); + } + default: { + return HasReturnvaluesIF::RETURN_FAILED; + } + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t GyroL3GD20H::handleDmaTransferInit() { + /* Clean D-cache */ + /* Make sure the address is 32-byte aligned and add 32-bytes to length, + in case it overlaps cacheline */ + // See https://community.st.com/s/article/FAQ-DMA-is-not-working-on-STM32H7-devices + HAL_StatusTypeDef result = performDmaTransfer(2); + if(result != HAL_OK) { + // Transfer error in transmission process + sif::printWarning("GyroL3GD20H::initialize: Error transmitting SPI with DMA\n"); + } + + // Wait for the transfer to complete + while (transferState == TransferStates::WAIT) { + TaskFactory::delayTask(1); + } + + switch(transferState) { + case(TransferStates::SUCCESS): { + uint8_t whoAmIVal = rxBuffer[1]; + if(whoAmIVal != EXPECTED_WHO_AM_I_VAL) { + sif::printDebug("GyroL3GD20H::initialize: " + "Read WHO AM I value %d not equal to expected value!\n", whoAmIVal); + } + transferState = TransferStates::IDLE; + break; + } + case(TransferStates::FAILURE): { + sif::printWarning("Transfer failure\n"); + transferState = TransferStates::FAILURE; + return HasReturnvaluesIF::RETURN_FAILED; + } + default: { + return HasReturnvaluesIF::RETURN_FAILED; + } + } + + sif::printInfo("GyroL3GD20H::initialize: Configuring device\n"); + // Configure the 5 configuration registers + uint8_t configRegs[5]; + prepareConfigRegs(configRegs); + + result = performDmaTransfer(6); + if(result != HAL_OK) { + // Transfer error in transmission process + sif::printWarning("Error transmitting SPI with DMA\n"); + } + + // Wait for the transfer to complete + while (transferState == TransferStates::WAIT) { + TaskFactory::delayTask(1); + } + + switch(transferState) { + case(TransferStates::SUCCESS): { + sif::printInfo("GyroL3GD20H::initialize: Configuration transfer success\n"); + transferState = TransferStates::IDLE; + break; + } + case(TransferStates::FAILURE): { + sif::printWarning("GyroL3GD20H::initialize: Configuration transfer failure\n"); + transferState = TransferStates::FAILURE; + return HasReturnvaluesIF::RETURN_FAILED; + } + default: { + return HasReturnvaluesIF::RETURN_FAILED; + } + } + + + txBuffer[0] = CTRL_REG_1 | STM_AUTO_INCREMENT_MASK | STM_READ_MASK; + std::memset(txBuffer.data() + 1, 0 , 5); + result = performDmaTransfer(6); + if(result != HAL_OK) { + // Transfer error in transmission process + sif::printWarning("Error transmitting SPI with DMA\n"); + } + // Wait for the transfer to complete + while (transferState == TransferStates::WAIT) { + TaskFactory::delayTask(1); + } + + switch(transferState) { + case(TransferStates::SUCCESS): { + if(rxBuffer[1] != configRegs[0] or rxBuffer[2] != configRegs[1] or + rxBuffer[3] != configRegs[2] or rxBuffer[4] != configRegs[3] or + rxBuffer[5] != configRegs[4]) { + sif::printWarning("GyroL3GD20H::initialize: Configuration failure\n"); + } + else { + sif::printInfo("GyroL3GD20H::initialize: Configuration success\n"); + } + transferState = TransferStates::IDLE; + break; + } + case(TransferStates::FAILURE): { + sif::printWarning("GyroL3GD20H::initialize: Configuration transfer failure\n"); + transferState = TransferStates::FAILURE; + return HasReturnvaluesIF::RETURN_FAILED; + } + default: { + return HasReturnvaluesIF::RETURN_FAILED; + } + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t GyroL3GD20H::handleDmaSensorRead() { + txBuffer[0] = CTRL_REG_1 | STM_AUTO_INCREMENT_MASK | STM_READ_MASK; + std::memset(txBuffer.data() + 1, 0 , 14); + + HAL_StatusTypeDef result = performDmaTransfer(15); + if(result != HAL_OK) { + // Transfer error in transmission process + sif::printDebug("GyroL3GD20H::handleDmaSensorRead: Error transmitting SPI with DMA\n"); + } + // Wait for the transfer to complete + while (transferState == TransferStates::WAIT) { + TaskFactory::delayTask(1); + } + + switch(transferState) { + case(TransferStates::SUCCESS): { + handleSensorReadout(); + break; + } + case(TransferStates::FAILURE): { + sif::printWarning("GyroL3GD20H::handleDmaSensorRead: Sensor read failure\n"); + transferState = TransferStates::FAILURE; + return HasReturnvaluesIF::RETURN_FAILED; + } + default: { + return HasReturnvaluesIF::RETURN_FAILED; + } + } + return HasReturnvaluesIF::RETURN_OK; +} + +HAL_StatusTypeDef GyroL3GD20H::performDmaTransfer(size_t sendSize) { + transferState = TransferStates::WAIT; +#if STM_USE_PERIPHERAL_TX_BUFFER_MPU_PROTECTION == 0 + SCB_CleanDCache_by_Addr((uint32_t*)(((uint32_t)txBuffer.data()) & ~(uint32_t)0x1F), + txBuffer.size()+32); +#endif + + // Start SPI transfer via DMA + HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_RESET); + return HAL_SPI_TransmitReceive_DMA(spiHandle, txBuffer.data(), rxBuffer.data(), sendSize); +} + +ReturnValue_t GyroL3GD20H::handlePollingTransferInit() { + HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_RESET); + auto result = HAL_SPI_TransmitReceive(spiHandle, txBuffer.data(), rxBuffer.data(), 2, 1000); + HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_SET); + switch(result) { + case(HAL_OK): { + sif::printInfo("GyroL3GD20H::initialize: Polling transfer success\n"); + uint8_t whoAmIVal = rxBuffer[1]; + if(whoAmIVal != EXPECTED_WHO_AM_I_VAL) { + sif::printDebug("GyroL3GD20H::performOperation: " + "Read WHO AM I value %d not equal to expected value!\n", whoAmIVal); + } + break; + } + case(HAL_TIMEOUT): { + sif::printDebug("GyroL3GD20H::initialize: Polling transfer timeout\n"); + return HasReturnvaluesIF::RETURN_FAILED; + } + case(HAL_ERROR): { + sif::printDebug("GyroL3GD20H::initialize: Polling transfer failure\n"); + return HasReturnvaluesIF::RETURN_FAILED; + } + default: { + return HasReturnvaluesIF::RETURN_FAILED; + } + } + + sif::printInfo("GyroL3GD20H::initialize: Configuring device\n"); + // Configure the 5 configuration registers + uint8_t configRegs[5]; + prepareConfigRegs(configRegs); + + HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_RESET); + result = HAL_SPI_TransmitReceive(spiHandle, txBuffer.data(), rxBuffer.data(), 6, 1000); + HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_SET); + switch(result) { + case(HAL_OK): { + break; + } + case(HAL_TIMEOUT): { + sif::printDebug("GyroL3GD20H::initialize: Polling transfer timeout\n"); + return HasReturnvaluesIF::RETURN_FAILED; + } + case(HAL_ERROR): { + sif::printDebug("GyroL3GD20H::initialize: Polling transfer failure\n"); + return HasReturnvaluesIF::RETURN_FAILED; + } + default: { + return HasReturnvaluesIF::RETURN_FAILED; + } + } + + txBuffer[0] = CTRL_REG_1 | STM_AUTO_INCREMENT_MASK | STM_READ_MASK; + std::memset(txBuffer.data() + 1, 0 , 5); + + HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_RESET); + result = HAL_SPI_TransmitReceive(spiHandle, txBuffer.data(), rxBuffer.data(), 6, 1000); + HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_SET); + switch(result) { + case(HAL_OK): { + if(rxBuffer[1] != configRegs[0] or rxBuffer[2] != configRegs[1] or + rxBuffer[3] != configRegs[2] or rxBuffer[4] != configRegs[3] or + rxBuffer[5] != configRegs[4]) { + sif::printWarning("GyroL3GD20H::initialize: Configuration failure\n"); + } + else { + sif::printInfo("GyroL3GD20H::initialize: Configuration success\n"); + } + break; + } + case(HAL_TIMEOUT): { + sif::printDebug("GyroL3GD20H::initialize: Polling transfer timeout\n"); + return HasReturnvaluesIF::RETURN_FAILED; + } + case(HAL_ERROR): { + sif::printDebug("GyroL3GD20H::initialize: Polling transfer failure\n"); + return HasReturnvaluesIF::RETURN_FAILED; + } + default: { + return HasReturnvaluesIF::RETURN_FAILED; + } + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t GyroL3GD20H::handlePollingSensorRead() { + txBuffer[0] = CTRL_REG_1 | STM_AUTO_INCREMENT_MASK | STM_READ_MASK; + std::memset(txBuffer.data() + 1, 0 , 14); + HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_RESET); + auto result = HAL_SPI_TransmitReceive(spiHandle, txBuffer.data(), rxBuffer.data(), 15, 1000); + HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_SET); + + switch(result) { + case(HAL_OK): { + handleSensorReadout(); + break; + } + case(HAL_TIMEOUT): { + sif::printDebug("GyroL3GD20H::initialize: Polling transfer timeout\n"); + return HasReturnvaluesIF::RETURN_FAILED; + } + case(HAL_ERROR): { + sif::printDebug("GyroL3GD20H::initialize: Polling transfer failure\n"); + return HasReturnvaluesIF::RETURN_FAILED; + } + default: { + return HasReturnvaluesIF::RETURN_FAILED; + } + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t GyroL3GD20H::handleInterruptTransferInit() { + HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_RESET); + switch(HAL_SPI_TransmitReceive_IT(spiHandle, txBuffer.data(), rxBuffer.data(), 2)) { + case(HAL_OK): { + sif::printInfo("GyroL3GD20H::initialize: Interrupt transfer success\n"); + // Wait for the transfer to complete + while (transferState == TransferStates::WAIT) { + TaskFactory::delayTask(1); + } + + uint8_t whoAmIVal = rxBuffer[1]; + if(whoAmIVal != EXPECTED_WHO_AM_I_VAL) { + sif::printDebug("GyroL3GD20H::initialize: " + "Read WHO AM I value %d not equal to expected value!\n", whoAmIVal); + } + break; + } + case(HAL_BUSY): + case(HAL_ERROR): + case(HAL_TIMEOUT): { + sif::printDebug("GyroL3GD20H::initialize: Initialization failure using interrupts\n"); + return HasReturnvaluesIF::RETURN_FAILED; + } + } + + sif::printInfo("GyroL3GD20H::initialize: Configuring device\n"); + transferState = TransferStates::WAIT; + // Configure the 5 configuration registers + uint8_t configRegs[5]; + prepareConfigRegs(configRegs); + HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_RESET); + switch(HAL_SPI_TransmitReceive_IT(spiHandle, txBuffer.data(), rxBuffer.data(), 6)) { + case(HAL_OK): { + // Wait for the transfer to complete + while (transferState == TransferStates::WAIT) { + TaskFactory::delayTask(1); + } + break; + } + case(HAL_BUSY): + case(HAL_ERROR): + case(HAL_TIMEOUT): { + sif::printDebug("GyroL3GD20H::initialize: Initialization failure using interrupts\n"); + return HasReturnvaluesIF::RETURN_FAILED; + } + } + + txBuffer[0] = CTRL_REG_1 | STM_AUTO_INCREMENT_MASK | STM_READ_MASK; + std::memset(txBuffer.data() + 1, 0 , 5); + transferState = TransferStates::WAIT; + HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_RESET); + switch(HAL_SPI_TransmitReceive_IT(spiHandle, txBuffer.data(), rxBuffer.data(), 6)) { + case(HAL_OK): { + // Wait for the transfer to complete + while (transferState == TransferStates::WAIT) { + TaskFactory::delayTask(1); + } + if(rxBuffer[1] != configRegs[0] or rxBuffer[2] != configRegs[1] or + rxBuffer[3] != configRegs[2] or rxBuffer[4] != configRegs[3] or + rxBuffer[5] != configRegs[4]) { + sif::printWarning("GyroL3GD20H::initialize: Configuration failure\n"); + } + else { + sif::printInfo("GyroL3GD20H::initialize: Configuration success\n"); + } + break; + } + case(HAL_BUSY): + case(HAL_ERROR): + case(HAL_TIMEOUT): { + sif::printDebug("GyroL3GD20H::initialize: Initialization failure using interrupts\n"); + return HasReturnvaluesIF::RETURN_FAILED; + } + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t GyroL3GD20H::handleInterruptSensorRead() { + transferState = TransferStates::WAIT; + txBuffer[0] = CTRL_REG_1 | STM_AUTO_INCREMENT_MASK | STM_READ_MASK; + std::memset(txBuffer.data() + 1, 0 , 14); + HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_RESET); + switch(HAL_SPI_TransmitReceive_IT(spiHandle, txBuffer.data(), rxBuffer.data(), 15)) { + case(HAL_OK): { + // Wait for the transfer to complete + while (transferState == TransferStates::WAIT) { + TaskFactory::delayTask(1); + } + handleSensorReadout(); + break; + } + case(HAL_BUSY): + case(HAL_ERROR): + case(HAL_TIMEOUT): { + sif::printDebug("GyroL3GD20H::initialize: Sensor read failure using interrupts\n"); + return HasReturnvaluesIF::RETURN_FAILED; + } + } + return HasReturnvaluesIF::RETURN_OK; +} + +void GyroL3GD20H::prepareConfigRegs(uint8_t* configRegs) { + // Enable sensor + configRegs[0] = 0b00001111; + configRegs[1] = 0b00000000; + configRegs[2] = 0b00000000; + // Big endian select + configRegs[3] = 0b01000000; + configRegs[4] = 0b00000000; + + txBuffer[0] = CTRL_REG_1 | STM_AUTO_INCREMENT_MASK; + std::memcpy(txBuffer.data() + 1, configRegs, 5); +} + +uint8_t GyroL3GD20H::readRegPolling(uint8_t reg) { + uint8_t rxBuf[2] = {}; + uint8_t txBuf[2] = {}; + txBuf[0] = reg | STM_READ_MASK; + HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_RESET); + auto result = HAL_SPI_TransmitReceive(spiHandle, txBuf, rxBuf, 2, 1000); + if(result) {}; + HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_SET); + return rxBuf[1]; +} + +void GyroL3GD20H::handleSensorReadout() { + uint8_t statusReg = rxBuffer[8]; + int16_t gyroXRaw = rxBuffer[9] << 8 | rxBuffer[10]; + float gyroX = static_cast(gyroXRaw) * 0.00875; + int16_t gyroYRaw = rxBuffer[11] << 8 | rxBuffer[12]; + float gyroY = static_cast(gyroYRaw) * 0.00875; + int16_t gyroZRaw = rxBuffer[13] << 8 | rxBuffer[14]; + float gyroZ = static_cast(gyroZRaw) * 0.00875; + sif::printInfo("Status register: 0b" BYTE_TO_BINARY_PATTERN "\n", BYTE_TO_BINARY(statusReg)); + sif::printInfo("Gyro X: %f\n", gyroX); + sif::printInfo("Gyro Y: %f\n", gyroY); + sif::printInfo("Gyro Z: %f\n", gyroZ); +} + + +void GyroL3GD20H::spiTransferCompleteCallback(SPI_HandleTypeDef *hspi, void* args) { + transferState = TransferStates::SUCCESS; + HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_SET); + if(GyroL3GD20H::transferMode == spi::TransferModes::DMA) { + // Invalidate cache prior to access by CPU + SCB_InvalidateDCache_by_Addr ((uint32_t *)GyroL3GD20H::rxBuffer.data(), + GyroL3GD20H::recvBufferSize); + } +} + +/** + * @brief SPI error callbacks. + * @param hspi: SPI handle + * @note This example shows a simple way to report transfer error, and you can + * add your own implementation. + * @retval None + */ +void GyroL3GD20H::spiTransferErrorCallback(SPI_HandleTypeDef *hspi, void* args) { + transferState = TransferStates::FAILURE; +} diff --git a/hal/src/fsfw_hal/stm32h7/devicetest/GyroL3GD20H.h b/hal/src/fsfw_hal/stm32h7/devicetest/GyroL3GD20H.h new file mode 100644 index 00000000..b65654de --- /dev/null +++ b/hal/src/fsfw_hal/stm32h7/devicetest/GyroL3GD20H.h @@ -0,0 +1,70 @@ +#ifndef FSFW_HAL_STM32H7_DEVICETEST_GYRO_L3GD20H_H_ +#define FSFW_HAL_STM32H7_DEVICETEST_GYRO_L3GD20H_H_ + +#include "stm32h7xx_hal.h" +#include "stm32h7xx_hal_spi.h" +#include "../spi/mspInit.h" +#include "../spi/spiDefinitions.h" + +#include "fsfw/returnvalues/HasReturnvaluesIF.h" + +#include +#include + +enum class TransferStates { + IDLE, + WAIT, + SUCCESS, + FAILURE +}; + +class GyroL3GD20H { +public: + GyroL3GD20H(SPI_HandleTypeDef* spiHandle, spi::TransferModes transferMode); + ~GyroL3GD20H(); + + ReturnValue_t initialize(); + ReturnValue_t performOperation(); + +private: + + const uint8_t WHO_AM_I_REG = 0b00001111; + const uint8_t STM_READ_MASK = 0b10000000; + const uint8_t STM_AUTO_INCREMENT_MASK = 0b01000000; + const uint8_t EXPECTED_WHO_AM_I_VAL = 0b11010111; + const uint8_t CTRL_REG_1 = 0b00100000; + const uint32_t L3G_RANGE = 245; + + SPI_HandleTypeDef* spiHandle; + + static spi::TransferModes transferMode; + static constexpr size_t recvBufferSize = 32 * 10; + static std::array rxBuffer; + static constexpr size_t txBufferSize = 32; + static std::array txBuffer; + + ReturnValue_t handleDmaTransferInit(); + ReturnValue_t handlePollingTransferInit(); + ReturnValue_t handleInterruptTransferInit(); + + ReturnValue_t handleDmaSensorRead(); + HAL_StatusTypeDef performDmaTransfer(size_t sendSize); + ReturnValue_t handlePollingSensorRead(); + ReturnValue_t handleInterruptSensorRead(); + + uint8_t readRegPolling(uint8_t reg); + + static void spiTransferCompleteCallback(SPI_HandleTypeDef *hspi, void* args); + static void spiTransferErrorCallback(SPI_HandleTypeDef *hspi, void* args); + + + void prepareConfigRegs(uint8_t* configRegs); + void handleSensorReadout(); + + + DMA_HandleTypeDef* txDmaHandle = {}; + DMA_HandleTypeDef* rxDmaHandle = {}; + spi::MspCfgBase* mspCfg = {}; +}; + +#endif /* FSFW_HAL_STM32H7_DEVICETEST_GYRO_L3GD20H_H_ */ diff --git a/hal/src/fsfw_hal/stm32h7/dma.cpp b/hal/src/fsfw_hal/stm32h7/dma.cpp new file mode 100644 index 00000000..bedf4aa4 --- /dev/null +++ b/hal/src/fsfw_hal/stm32h7/dma.cpp @@ -0,0 +1,84 @@ +#include + +#include +#include + +user_handler_t DMA_1_USER_HANDLERS[8]; +user_args_t DMA_1_USER_ARGS[8]; + +user_handler_t DMA_2_USER_HANDLERS[8]; +user_args_t DMA_2_USER_ARGS[8]; + +void dma::assignDmaUserHandler(DMAIndexes dma_idx, DMAStreams stream_idx, + user_handler_t user_handler, user_args_t user_args) { + if(dma_idx == DMA_1) { + DMA_1_USER_HANDLERS[stream_idx] = user_handler; + DMA_1_USER_ARGS[stream_idx] = user_args; + } + else if(dma_idx == DMA_2) { + DMA_2_USER_HANDLERS[stream_idx] = user_handler; + DMA_2_USER_ARGS[stream_idx] = user_args; + } +} + +// The interrupt handlers in the format required for the IRQ vector table + +/* Do not change these function names! They need to be exactly equal to the name of the functions +defined in the startup_stm32h743xx.s files! */ + +#define GENERIC_DMA_IRQ_HANDLER(DMA_IDX, STREAM_IDX) \ + if(DMA_##DMA_IDX##_USER_HANDLERS[STREAM_IDX] != NULL) { \ + DMA_##DMA_IDX##_USER_HANDLERS[STREAM_IDX](DMA_##DMA_IDX##_USER_ARGS[STREAM_IDX]); \ + return; \ + } \ + Default_Handler() \ + +extern"C" void DMA1_Stream0_IRQHandler() { + GENERIC_DMA_IRQ_HANDLER(1, 0); +} +extern"C" void DMA1_Stream1_IRQHandler() { + GENERIC_DMA_IRQ_HANDLER(1, 1); +} +extern"C" void DMA1_Stream2_IRQHandler() { + GENERIC_DMA_IRQ_HANDLER(1, 2); +} +extern"C" void DMA1_Stream3_IRQHandler() { + GENERIC_DMA_IRQ_HANDLER(1, 3); +} +extern"C" void DMA1_Stream4_IRQHandler() { + GENERIC_DMA_IRQ_HANDLER(1, 4); +} +extern"C" void DMA1_Stream5_IRQHandler() { + GENERIC_DMA_IRQ_HANDLER(1, 5); +} +extern"C" void DMA1_Stream6_IRQHandler() { + GENERIC_DMA_IRQ_HANDLER(1, 6); +} +extern"C" void DMA1_Stream7_IRQHandler() { + GENERIC_DMA_IRQ_HANDLER(1, 7); +} + +extern"C" void DMA2_Stream0_IRQHandler() { + GENERIC_DMA_IRQ_HANDLER(2, 0); +} +extern"C" void DMA2_Stream1_IRQHandler() { + GENERIC_DMA_IRQ_HANDLER(2, 1); +} +extern"C" void DMA2_Stream2_IRQHandler() { + GENERIC_DMA_IRQ_HANDLER(2, 2); +} +extern"C" void DMA2_Stream3_IRQHandler() { + GENERIC_DMA_IRQ_HANDLER(2, 3); +} +extern"C" void DMA2_Stream4_IRQHandler() { + GENERIC_DMA_IRQ_HANDLER(2, 4); +} +extern"C" void DMA2_Stream5_IRQHandler() { + GENERIC_DMA_IRQ_HANDLER(2, 5); +} +extern"C" void DMA2_Stream6_IRQHandler() { + GENERIC_DMA_IRQ_HANDLER(2, 6); +} +extern"C" void DMA2_Stream7_IRQHandler() { + GENERIC_DMA_IRQ_HANDLER(2, 7); +} diff --git a/hal/src/fsfw_hal/stm32h7/dma.h b/hal/src/fsfw_hal/stm32h7/dma.h new file mode 100644 index 00000000..779a64cb --- /dev/null +++ b/hal/src/fsfw_hal/stm32h7/dma.h @@ -0,0 +1,49 @@ +#ifndef FSFW_HAL_STM32H7_DMA_H_ +#define FSFW_HAL_STM32H7_DMA_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "interrupts.h" +#include + +namespace dma { + +enum DMAType { + TX = 0, + RX = 1 +}; + +enum DMAIndexes: uint8_t { + DMA_1 = 1, + DMA_2 = 2 +}; + +enum DMAStreams { + STREAM_0 = 0, + STREAM_1 = 1, + STREAM_2 = 2, + STREAM_3 = 3, + STREAM_4 = 4, + STREAM_5 = 5, + STREAM_6 = 6, + STREAM_7 = 7, +} ; + +/** + * Assign user interrupt handlers for DMA streams, allowing to pass an + * arbitrary argument as well. Generally, this argument will be the related DMA handle. + * @param user_handler + * @param user_args + */ +void assignDmaUserHandler(DMAIndexes dma_idx, DMAStreams stream_idx, + user_handler_t user_handler, user_args_t user_args); + +} + +#ifdef __cplusplus +} +#endif + +#endif /* FSFW_HAL_STM32H7_DMA_H_ */ diff --git a/hal/src/fsfw_hal/stm32h7/gpio/CMakeLists.txt b/hal/src/fsfw_hal/stm32h7/gpio/CMakeLists.txt new file mode 100644 index 00000000..35245b25 --- /dev/null +++ b/hal/src/fsfw_hal/stm32h7/gpio/CMakeLists.txt @@ -0,0 +1,3 @@ +target_sources(${LIB_FSFW_NAME} PRIVATE + gpio.cpp +) diff --git a/hal/src/fsfw_hal/stm32h7/gpio/gpio.cpp b/hal/src/fsfw_hal/stm32h7/gpio/gpio.cpp new file mode 100644 index 00000000..5a890d7f --- /dev/null +++ b/hal/src/fsfw_hal/stm32h7/gpio/gpio.cpp @@ -0,0 +1,71 @@ +#include "fsfw_hal/stm32h7/gpio/gpio.h" + +#include "stm32h7xx_hal_rcc.h" + +void gpio::initializeGpioClock(GPIO_TypeDef* gpioPort) { +#ifdef GPIOA + if(gpioPort == GPIOA) { + __HAL_RCC_GPIOA_CLK_ENABLE(); + } +#endif + +#ifdef GPIOB + if(gpioPort == GPIOB) { + __HAL_RCC_GPIOB_CLK_ENABLE(); + } +#endif + +#ifdef GPIOC + if(gpioPort == GPIOC) { + __HAL_RCC_GPIOC_CLK_ENABLE(); + } +#endif + +#ifdef GPIOD + if(gpioPort == GPIOD) { + __HAL_RCC_GPIOD_CLK_ENABLE(); + } +#endif + +#ifdef GPIOE + if(gpioPort == GPIOE) { + __HAL_RCC_GPIOE_CLK_ENABLE(); + } +#endif + +#ifdef GPIOF + if(gpioPort == GPIOF) { + __HAL_RCC_GPIOF_CLK_ENABLE(); + } +#endif + +#ifdef GPIOG + if(gpioPort == GPIOG) { + __HAL_RCC_GPIOG_CLK_ENABLE(); + } +#endif + +#ifdef GPIOH + if(gpioPort == GPIOH) { + __HAL_RCC_GPIOH_CLK_ENABLE(); + } +#endif + +#ifdef GPIOI + if(gpioPort == GPIOI) { + __HAL_RCC_GPIOI_CLK_ENABLE(); + } +#endif + +#ifdef GPIOJ + if(gpioPort == GPIOJ) { + __HAL_RCC_GPIOJ_CLK_ENABLE(); + } +#endif + +#ifdef GPIOK + if(gpioPort == GPIOK) { + __HAL_RCC_GPIOK_CLK_ENABLE(); + } +#endif +} diff --git a/hal/src/fsfw_hal/stm32h7/gpio/gpio.h b/hal/src/fsfw_hal/stm32h7/gpio/gpio.h new file mode 100644 index 00000000..38fcd708 --- /dev/null +++ b/hal/src/fsfw_hal/stm32h7/gpio/gpio.h @@ -0,0 +1,12 @@ +#ifndef FSFW_HAL_STM32H7_GPIO_GPIO_H_ +#define FSFW_HAL_STM32H7_GPIO_GPIO_H_ + +#include "stm32h7xx.h" + +namespace gpio { + +void initializeGpioClock(GPIO_TypeDef* gpioPort); + +} + +#endif /* FSFW_HAL_STM32H7_GPIO_GPIO_H_ */ diff --git a/hal/src/fsfw_hal/stm32h7/i2c/CMakeLists.txt b/hal/src/fsfw_hal/stm32h7/i2c/CMakeLists.txt new file mode 100644 index 00000000..5ecb0990 --- /dev/null +++ b/hal/src/fsfw_hal/stm32h7/i2c/CMakeLists.txt @@ -0,0 +1,2 @@ +target_sources(${LIB_FSFW_NAME} PRIVATE +) diff --git a/hal/src/fsfw_hal/stm32h7/interrupts.h b/hal/src/fsfw_hal/stm32h7/interrupts.h new file mode 100644 index 00000000..aef60bf7 --- /dev/null +++ b/hal/src/fsfw_hal/stm32h7/interrupts.h @@ -0,0 +1,28 @@ +#ifndef FSFW_HAL_STM32H7_INTERRUPTS_H_ +#define FSFW_HAL_STM32H7_INTERRUPTS_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Default handler which is defined in startup file as assembly code. + */ +extern void Default_Handler(); + +typedef void (*user_handler_t) (void*); +typedef void* user_args_t; + +enum IrqPriorities: uint8_t { + HIGHEST = 0, + HIGHEST_FREERTOS = 6, + LOWEST = 15 +}; + +#ifdef __cplusplus +} +#endif + +#endif /* FSFW_HAL_STM32H7_INTERRUPTS_H_ */ diff --git a/hal/src/fsfw_hal/stm32h7/spi/CMakeLists.txt b/hal/src/fsfw_hal/stm32h7/spi/CMakeLists.txt new file mode 100644 index 00000000..aa5541bc --- /dev/null +++ b/hal/src/fsfw_hal/stm32h7/spi/CMakeLists.txt @@ -0,0 +1,9 @@ +target_sources(${LIB_FSFW_NAME} PRIVATE + spiCore.cpp + spiDefinitions.cpp + spiInterrupts.cpp + mspInit.cpp + SpiCookie.cpp + SpiComIF.cpp + stm32h743zi.cpp +) diff --git a/hal/src/fsfw_hal/stm32h7/spi/SpiComIF.cpp b/hal/src/fsfw_hal/stm32h7/spi/SpiComIF.cpp new file mode 100644 index 00000000..4c4f7744 --- /dev/null +++ b/hal/src/fsfw_hal/stm32h7/spi/SpiComIF.cpp @@ -0,0 +1,480 @@ +#include "fsfw_hal/stm32h7/spi/SpiComIF.h" +#include "fsfw_hal/stm32h7/spi/SpiCookie.h" + +#include "fsfw/tasks/SemaphoreFactory.h" +#include "fsfw_hal/stm32h7/spi/spiCore.h" +#include "fsfw_hal/stm32h7/spi/spiInterrupts.h" +#include "fsfw_hal/stm32h7/spi/mspInit.h" +#include "fsfw_hal/stm32h7/gpio/gpio.h" + +// FreeRTOS required special Semaphore handling from an ISR. Therefore, we use the concrete +// instance here, because RTEMS and FreeRTOS are the only relevant OSALs currently +// and it is not trivial to add a releaseFromISR to the SemaphoreIF +#if defined FSFW_OSAL_RTEMS +#include "fsfw/osal/rtems/BinarySemaphore.h" +#elif defined FSFW_OSAL_FREERTOS +#include "fsfw/osal/freertos/TaskManagement.h" +#include "fsfw/osal/freertos/BinarySemaphore.h" +#endif + +#include "stm32h7xx_hal_gpio.h" + +SpiComIF::SpiComIF(object_id_t objectId): SystemObject(objectId) { + void* irqArgsVoided = reinterpret_cast(&irqArgs); + spi::assignTransferRxTxCompleteCallback(&spiTransferCompleteCallback, irqArgsVoided); + spi::assignTransferRxCompleteCallback(&spiTransferRxCompleteCallback, irqArgsVoided); + spi::assignTransferTxCompleteCallback(&spiTransferTxCompleteCallback, irqArgsVoided); + spi::assignTransferErrorCallback(&spiTransferErrorCallback, irqArgsVoided); +} + +void SpiComIF::configureCacheMaintenanceOnTxBuffer(bool enable) { + this->cacheMaintenanceOnTxBuffer = enable; +} + +void SpiComIF::addDmaHandles(DMA_HandleTypeDef *txHandle, DMA_HandleTypeDef *rxHandle) { + spi::setDmaHandles(txHandle, rxHandle); +} + +ReturnValue_t SpiComIF::initialize() { + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t SpiComIF::initializeInterface(CookieIF *cookie) { + SpiCookie* spiCookie = dynamic_cast(cookie); + if(spiCookie == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error < "SpiComIF::initializeInterface: Invalid cookie" << std::endl; +#else + sif::printError("SpiComIF::initializeInterface: Invalid cookie\n"); +#endif + return NULLPOINTER; + } + auto transferMode = spiCookie->getTransferMode(); + + if(transferMode == spi::TransferModes::DMA) { + DMA_HandleTypeDef *txHandle = nullptr; + DMA_HandleTypeDef *rxHandle = nullptr; + spi::getDmaHandles(&txHandle, &rxHandle); + if(txHandle == nullptr or rxHandle == nullptr) { + sif::printError("SpiComIF::initialize: DMA handles not set!\n"); + return HasReturnvaluesIF::RETURN_FAILED; + } + } + // This semaphore ensures thread-safety for a given bus + spiSemaphore = dynamic_cast( + SemaphoreFactory::instance()->createBinarySemaphore()); + address_t spiAddress = spiCookie->getDeviceAddress(); + + auto iter = spiDeviceMap.find(spiAddress); + if(iter == spiDeviceMap.end()) { + size_t bufferSize = spiCookie->getMaxRecvSize(); + auto statusPair = spiDeviceMap.emplace(spiAddress, SpiInstance(bufferSize)); + if (not statusPair.second) { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "SpiComIF::initializeInterface: Failed to insert device with address " << + spiAddress << "to SPI device map" << std::endl; +#else + sif::printError("SpiComIF::initializeInterface: Failed to insert device with address " + "%lu to SPI device map\n", static_cast(spiAddress)); +#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ +#endif /* FSFW_VERBOSE_LEVEL >= 1 */ + return HasReturnvaluesIF::RETURN_FAILED; + } + } + auto gpioPin = spiCookie->getChipSelectGpioPin(); + auto gpioPort = spiCookie->getChipSelectGpioPort(); + + SPI_HandleTypeDef& spiHandle = spiCookie->getSpiHandle(); + + auto spiIdx = spiCookie->getSpiIdx(); + if(spiIdx == spi::SpiBus::SPI_1) { +#ifdef SPI1 + spiHandle.Instance = SPI1; +#endif + } + else if(spiIdx == spi::SpiBus::SPI_2) { +#ifdef SPI2 + spiHandle.Instance = SPI2; +#endif + } + else { + printCfgError("SPI Bus Index"); + return HasReturnvaluesIF::RETURN_FAILED; + } + + auto mspCfg = spiCookie->getMspCfg(); + + if(transferMode == spi::TransferModes::POLLING) { + auto typedCfg = dynamic_cast(mspCfg); + if(typedCfg == nullptr) { + printCfgError("Polling MSP"); + return HasReturnvaluesIF::RETURN_FAILED; + } + spi::setSpiPollingMspFunctions(typedCfg); + } + else if(transferMode == spi::TransferModes::INTERRUPT) { + auto typedCfg = dynamic_cast(mspCfg); + if(typedCfg == nullptr) { + printCfgError("IRQ MSP"); + return HasReturnvaluesIF::RETURN_FAILED; + } + spi::setSpiIrqMspFunctions(typedCfg); + } + else if(transferMode == spi::TransferModes::DMA) { + auto typedCfg = dynamic_cast(mspCfg); + if(typedCfg == nullptr) { + printCfgError("DMA MSP"); + return HasReturnvaluesIF::RETURN_FAILED; + } + // Check DMA handles + DMA_HandleTypeDef* txHandle = nullptr; + DMA_HandleTypeDef* rxHandle = nullptr; + spi::getDmaHandles(&txHandle, &rxHandle); + if(txHandle == nullptr or rxHandle == nullptr) { + printCfgError("DMA Handle"); + return HasReturnvaluesIF::RETURN_FAILED; + } + spi::setSpiDmaMspFunctions(typedCfg); + } + + if(gpioPort != nullptr) { + gpio::initializeGpioClock(gpioPort); + GPIO_InitTypeDef chipSelect = {}; + chipSelect.Pin = gpioPin; + chipSelect.Mode = GPIO_MODE_OUTPUT_PP; + HAL_GPIO_Init(gpioPort, &chipSelect); + HAL_GPIO_WritePin(gpioPort, gpioPin, GPIO_PIN_SET); + } + + if(HAL_SPI_Init(&spiHandle) != HAL_OK) { + sif::printWarning("SpiComIF::initialize: Error initializing SPI\n"); + return HasReturnvaluesIF::RETURN_FAILED; + } + // The MSP configuration struct is not required anymore + spiCookie->deleteMspCfg(); + + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t SpiComIF::sendMessage(CookieIF *cookie, const uint8_t *sendData, size_t sendLen) { + SpiCookie* spiCookie = dynamic_cast(cookie); + if(spiCookie == nullptr) { + return NULLPOINTER; + } + + SPI_HandleTypeDef& spiHandle = spiCookie->getSpiHandle(); + + auto iter = spiDeviceMap.find(spiCookie->getDeviceAddress()); + if(iter == spiDeviceMap.end()) { + return HasReturnvaluesIF::RETURN_FAILED; + } + iter->second.currentTransferLen = sendLen; + + auto transferMode = spiCookie->getTransferMode(); + switch(spiCookie->getTransferState()) { + case(spi::TransferStates::IDLE): { + break; + } + case(spi::TransferStates::WAIT): + case(spi::TransferStates::FAILURE): + case(spi::TransferStates::SUCCESS): + default: { + return HasReturnvaluesIF::RETURN_FAILED; + } + } + + switch(transferMode) { + case(spi::TransferModes::POLLING): { + return handlePollingSendOperation(iter->second.replyBuffer.data(), spiHandle, *spiCookie, + sendData, sendLen); + } + case(spi::TransferModes::INTERRUPT): { + return handleInterruptSendOperation(iter->second.replyBuffer.data(), spiHandle, *spiCookie, + sendData, sendLen); + } + case(spi::TransferModes::DMA): { + return handleDmaSendOperation(iter->second.replyBuffer.data(), spiHandle, *spiCookie, + sendData, sendLen); + } + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t SpiComIF::getSendSuccess(CookieIF *cookie) { + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t SpiComIF::requestReceiveMessage(CookieIF *cookie, size_t requestLen) { + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t SpiComIF::readReceivedMessage(CookieIF *cookie, uint8_t **buffer, size_t *size) { + SpiCookie* spiCookie = dynamic_cast(cookie); + if(spiCookie == nullptr) { + return NULLPOINTER; + } + switch(spiCookie->getTransferState()) { + case(spi::TransferStates::SUCCESS): { + auto iter = spiDeviceMap.find(spiCookie->getDeviceAddress()); + if(iter == spiDeviceMap.end()) { + return HasReturnvaluesIF::RETURN_FAILED; + } + *buffer = iter->second.replyBuffer.data(); + *size = iter->second.currentTransferLen; + spiCookie->setTransferState(spi::TransferStates::IDLE); + break; + } + case(spi::TransferStates::FAILURE): { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "SpiComIF::readReceivedMessage: Transfer failure" << std::endl; +#else + sif::printWarning("SpiComIF::readReceivedMessage: Transfer failure\n"); +#endif +#endif + spiCookie->setTransferState(spi::TransferStates::IDLE); + return HasReturnvaluesIF::RETURN_FAILED; + } + case(spi::TransferStates::WAIT): + case(spi::TransferStates::IDLE): { + break; + } + default: { + return HasReturnvaluesIF::RETURN_FAILED; + } + } + + return HasReturnvaluesIF::RETURN_OK; +} + +void SpiComIF::setDefaultPollingTimeout(dur_millis_t timeout) { + this->defaultPollingTimeout = timeout; +} + +ReturnValue_t SpiComIF::handlePollingSendOperation(uint8_t* recvPtr, SPI_HandleTypeDef& spiHandle, + SpiCookie& spiCookie, const uint8_t *sendData, size_t sendLen) { + auto gpioPort = spiCookie.getChipSelectGpioPort(); + auto gpioPin = spiCookie.getChipSelectGpioPin(); + auto returnval = spiSemaphore->acquire(timeoutType, timeoutMs); + if(returnval != HasReturnvaluesIF::RETURN_OK) { + return returnval; + } + spiCookie.setTransferState(spi::TransferStates::WAIT); + if(gpioPort != nullptr) { + HAL_GPIO_WritePin(gpioPort, gpioPin, GPIO_PIN_RESET); + } + + auto result = HAL_SPI_TransmitReceive(&spiHandle, const_cast(sendData), + recvPtr, sendLen, defaultPollingTimeout); + if(gpioPort != nullptr) { + HAL_GPIO_WritePin(gpioPort, gpioPin, GPIO_PIN_SET); + } + spiSemaphore->release(); + switch(result) { + case(HAL_OK): { + spiCookie.setTransferState(spi::TransferStates::SUCCESS); + break; + } + case(HAL_TIMEOUT): { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "SpiComIF::sendMessage: Polling Mode | Timeout for SPI device" << + spiCookie->getDeviceAddress() << std::endl; +#else + sif::printWarning("SpiComIF::sendMessage: Polling Mode | Timeout for SPI device %d\n", + spiCookie.getDeviceAddress()); +#endif +#endif + spiCookie.setTransferState(spi::TransferStates::FAILURE); + return spi::HAL_TIMEOUT_RETVAL; + } + case(HAL_ERROR): + default: { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "SpiComIF::sendMessage: Polling Mode | HAL error for SPI device" << + spiCookie->getDeviceAddress() << std::endl; +#else + sif::printWarning("SpiComIF::sendMessage: Polling Mode | HAL error for SPI device %d\n", + spiCookie.getDeviceAddress()); +#endif +#endif + spiCookie.setTransferState(spi::TransferStates::FAILURE); + return spi::HAL_ERROR_RETVAL; + } + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t SpiComIF::handleInterruptSendOperation(uint8_t* recvPtr, SPI_HandleTypeDef& spiHandle, + SpiCookie& spiCookie, const uint8_t * sendData, size_t sendLen) { + return handleIrqSendOperation(recvPtr, spiHandle, spiCookie, sendData, sendLen); +} + +ReturnValue_t SpiComIF::handleDmaSendOperation(uint8_t* recvPtr, SPI_HandleTypeDef& spiHandle, + SpiCookie& spiCookie, const uint8_t * sendData, size_t sendLen) { + return handleIrqSendOperation(recvPtr, spiHandle, spiCookie, sendData, sendLen); +} + +ReturnValue_t SpiComIF::handleIrqSendOperation(uint8_t *recvPtr, SPI_HandleTypeDef& spiHandle, + SpiCookie& spiCookie, const uint8_t *sendData, size_t sendLen) { + ReturnValue_t result = genericIrqSendSetup(recvPtr, spiHandle, spiCookie, sendData, sendLen); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + // yet another HAL driver which is not const-correct.. + HAL_StatusTypeDef status = HAL_OK; + auto transferMode = spiCookie.getTransferMode(); + if(transferMode == spi::TransferModes::DMA) { + if(cacheMaintenanceOnTxBuffer) { + /* Clean D-cache. Make sure the address is 32-byte aligned and add 32-bytes to length, + in case it overlaps cacheline */ + SCB_CleanDCache_by_Addr((uint32_t*)(((uint32_t) sendData ) & ~(uint32_t)0x1F), + sendLen + 32); + } + status = HAL_SPI_TransmitReceive_DMA(&spiHandle, const_cast(sendData), + currentRecvPtr, sendLen); + } + else { + status = HAL_SPI_TransmitReceive_IT(&spiHandle, const_cast(sendData), + currentRecvPtr, sendLen); + } + switch(status) { + case(HAL_OK): { + break; + } + default: { + return halErrorHandler(status, transferMode); + } + } + return result; +} + +ReturnValue_t SpiComIF::halErrorHandler(HAL_StatusTypeDef status, spi::TransferModes transferMode) { + char modeString[10]; + if(transferMode == spi::TransferModes::DMA) { + std::snprintf(modeString, sizeof(modeString), "Dma"); + } + else { + std::snprintf(modeString, sizeof(modeString), "Interrupt"); + } + sif::printWarning("SpiComIF::handle%sSendOperation: HAL error %d occured\n", modeString, + status); + switch(status) { + case(HAL_BUSY): { + return spi::HAL_BUSY_RETVAL; + } + case(HAL_ERROR): { + return spi::HAL_ERROR_RETVAL; + } + case(HAL_TIMEOUT): { + return spi::HAL_TIMEOUT_RETVAL; + } + default: { + return HasReturnvaluesIF::RETURN_FAILED; + } + } +} + + +ReturnValue_t SpiComIF::genericIrqSendSetup(uint8_t *recvPtr, SPI_HandleTypeDef& spiHandle, + SpiCookie& spiCookie, const uint8_t *sendData, size_t sendLen) { + currentRecvPtr = recvPtr; + currentRecvBuffSize = sendLen; + + // Take the semaphore which will be released by a callback when the transfer is complete + ReturnValue_t result = spiSemaphore->acquire(SemaphoreIF::TimeoutType::WAITING, timeoutMs); + if(result != HasReturnvaluesIF::RETURN_OK) { + // Configuration error + sif::printWarning("SpiComIF::handleInterruptSendOperation: Semaphore " + "could not be acquired after %d ms\n", timeoutMs); + return result; + } + // Cache the current SPI handle in any case + spi::setSpiHandle(&spiHandle); + // Assign the IRQ arguments for the user callbacks + irqArgs.comIF = this; + irqArgs.spiCookie = &spiCookie; + // The SPI handle is passed to the default SPI callback as a void argument. This callback + // is different from the user callbacks specified above! + spi::assignSpiUserArgs(spiCookie.getSpiIdx(), reinterpret_cast(&spiHandle)); + if(spiCookie.getChipSelectGpioPort() != nullptr) { + HAL_GPIO_WritePin(spiCookie.getChipSelectGpioPort(), spiCookie.getChipSelectGpioPin(), + GPIO_PIN_RESET); + } + return HasReturnvaluesIF::RETURN_OK; +} + +void SpiComIF::spiTransferTxCompleteCallback(SPI_HandleTypeDef *hspi, void *args) { + genericIrqHandler(args, spi::TransferStates::SUCCESS); +} + +void SpiComIF::spiTransferRxCompleteCallback(SPI_HandleTypeDef *hspi, void *args) { + genericIrqHandler(args, spi::TransferStates::SUCCESS); +} + +void SpiComIF::spiTransferCompleteCallback(SPI_HandleTypeDef *hspi, void *args) { + genericIrqHandler(args, spi::TransferStates::SUCCESS); +} + +void SpiComIF::spiTransferErrorCallback(SPI_HandleTypeDef *hspi, void *args) { + genericIrqHandler(args, spi::TransferStates::FAILURE); +} + +void SpiComIF::genericIrqHandler(void *irqArgsVoid, spi::TransferStates targetState) { + IrqArgs* irqArgs = reinterpret_cast(irqArgsVoid); + if(irqArgs == nullptr) { + return; + } + SpiCookie* spiCookie = irqArgs->spiCookie; + SpiComIF* comIF = irqArgs->comIF; + if(spiCookie == nullptr or comIF == nullptr) { + return; + } + + spiCookie->setTransferState(targetState); + + if(spiCookie->getChipSelectGpioPort() != nullptr) { + // Pull CS pin high again + HAL_GPIO_WritePin(spiCookie->getChipSelectGpioPort(), spiCookie->getChipSelectGpioPin(), + GPIO_PIN_SET); + } + + +#if defined FSFW_OSAL_FREERTOS + // Release the task semaphore + BaseType_t taskWoken = pdFALSE; + ReturnValue_t result = BinarySemaphore::releaseFromISR(comIF->spiSemaphore->getSemaphore(), + &taskWoken); +#elif defined FSFW_OSAL_RTEMS + ReturnValue_t result = comIF->spiSemaphore->release(); +#endif + if(result != HasReturnvaluesIF::RETURN_OK) { + // Configuration error + printf("SpiComIF::genericIrqHandler: Failure releasing Semaphore!\n"); + } + + // Perform cache maintenance operation for DMA transfers + if(spiCookie->getTransferMode() == spi::TransferModes::DMA) { + // Invalidate cache prior to access by CPU + SCB_InvalidateDCache_by_Addr ((uint32_t *) comIF->currentRecvPtr, + comIF->currentRecvBuffSize); + } +#if defined FSFW_OSAL_FREERTOS + /* Request a context switch if the SPI ComIF task was woken up and has a higher priority + than the currently running task */ + if(taskWoken == pdTRUE) { + TaskManagement::requestContextSwitch(CallContext::ISR); + } +#endif +} + +void SpiComIF::printCfgError(const char *const type) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "SpiComIF::initializeInterface: Invalid " << type << " configuration" + << std::endl; +#else + sif::printWarning("SpiComIF::initializeInterface: Invalid %s configuration\n", type); +#endif +} diff --git a/hal/src/fsfw_hal/stm32h7/spi/SpiComIF.h b/hal/src/fsfw_hal/stm32h7/spi/SpiComIF.h new file mode 100644 index 00000000..cb6c4cf8 --- /dev/null +++ b/hal/src/fsfw_hal/stm32h7/spi/SpiComIF.h @@ -0,0 +1,129 @@ +#ifndef FSFW_HAL_STM32H7_SPI_SPICOMIF_H_ +#define FSFW_HAL_STM32H7_SPI_SPICOMIF_H_ + +#include "fsfw/tasks/SemaphoreIF.h" +#include "fsfw/devicehandlers/DeviceCommunicationIF.h" +#include "fsfw/objectmanager/SystemObject.h" + +#include "fsfw_hal/stm32h7/spi/spiDefinitions.h" +#include "stm32h7xx_hal_spi.h" +#include "stm32h743xx.h" + +#include +#include + +class SpiCookie; +class BinarySemaphore; + +/** + * @brief This communication interface allows using generic device handlers with using + * the STM32H7 SPI peripherals + * @details + * This communication interface supports all three major communcation modes: + * - Polling: Simple, but not recommended to real use-cases, blocks the CPU + * - Interrupt: Good for small data only arriving occasionally + * - DMA: Good for large data which also occur regularly. Please note that the number + * of DMA channels in limited + * The device specific information is usually kept in the SpiCookie class. The current + * implementation limits the transfer mode for a given SPI bus. + * @author R. Mueller + */ +class SpiComIF: + public SystemObject, + public DeviceCommunicationIF { +public: + /** + * Create a SPI communication interface for the given SPI peripheral (spiInstance) + * @param objectId + * @param spiInstance + * @param spiHandle + * @param transferMode + */ + SpiComIF(object_id_t objectId); + + /** + * Allows the user to disable cache maintenance on the TX buffer. This can be done if the + * TX buffers are places and MPU protected properly like specified in this link: + * https://community.st.com/s/article/FAQ-DMA-is-not-working-on-STM32H7-devices + * The cache maintenace is enabled by default. + * @param enable + */ + void configureCacheMaintenanceOnTxBuffer(bool enable); + + void setDefaultPollingTimeout(dur_millis_t timeout); + + /** + * Add the DMA handles. These need to be set in the DMA transfer mode is used. + * @param txHandle + * @param rxHandle + */ + void addDmaHandles(DMA_HandleTypeDef* txHandle, DMA_HandleTypeDef* rxHandle); + + ReturnValue_t initialize() override; + + // DeviceCommunicationIF overrides + virtual ReturnValue_t initializeInterface(CookieIF * cookie) override; + virtual ReturnValue_t sendMessage(CookieIF *cookie, + const uint8_t * sendData, size_t sendLen) override; + virtual ReturnValue_t getSendSuccess(CookieIF *cookie) override; + virtual ReturnValue_t requestReceiveMessage(CookieIF *cookie, + size_t requestLen) override; + virtual ReturnValue_t readReceivedMessage(CookieIF *cookie, + uint8_t **buffer, size_t *size) override; + +protected: + + struct SpiInstance { + SpiInstance(size_t maxRecvSize): replyBuffer(std::vector(maxRecvSize)) {} + std::vector replyBuffer; + size_t currentTransferLen = 0; + }; + + struct IrqArgs { + SpiComIF* comIF = nullptr; + SpiCookie* spiCookie = nullptr; + }; + + IrqArgs irqArgs; + + uint32_t defaultPollingTimeout = 50; + + SemaphoreIF::TimeoutType timeoutType = SemaphoreIF::TimeoutType::WAITING; + dur_millis_t timeoutMs = 20; + + BinarySemaphore* spiSemaphore = nullptr; + bool cacheMaintenanceOnTxBuffer = true; + + using SpiDeviceMap = std::map; + using SpiDeviceMapIter = SpiDeviceMap::iterator; + + uint8_t* currentRecvPtr = nullptr; + size_t currentRecvBuffSize = 0; + + SpiDeviceMap spiDeviceMap; + + ReturnValue_t handlePollingSendOperation(uint8_t* recvPtr, SPI_HandleTypeDef& spiHandle, + SpiCookie& spiCookie, const uint8_t * sendData, size_t sendLen); + ReturnValue_t handleInterruptSendOperation(uint8_t* recvPtr, SPI_HandleTypeDef& spiHandle, + SpiCookie& spiCookie, const uint8_t * sendData, size_t sendLen); + ReturnValue_t handleDmaSendOperation(uint8_t* recvPtr, SPI_HandleTypeDef& spiHandle, + SpiCookie& spiCookie, const uint8_t * sendData, size_t sendLen); + ReturnValue_t handleIrqSendOperation(uint8_t* recvPtr, SPI_HandleTypeDef& spiHandle, + SpiCookie& spiCookie, const uint8_t * sendData, size_t sendLen); + ReturnValue_t genericIrqSendSetup(uint8_t* recvPtr, SPI_HandleTypeDef& spiHandle, + SpiCookie& spiCookie, const uint8_t * sendData, size_t sendLen); + ReturnValue_t halErrorHandler(HAL_StatusTypeDef status, spi::TransferModes transferMode); + + static void spiTransferTxCompleteCallback(SPI_HandleTypeDef *hspi, void* args); + static void spiTransferRxCompleteCallback(SPI_HandleTypeDef *hspi, void* args); + static void spiTransferCompleteCallback(SPI_HandleTypeDef *hspi, void* args); + static void spiTransferErrorCallback(SPI_HandleTypeDef *hspi, void* args); + + static void genericIrqHandler(void* irqArgs, spi::TransferStates targetState); + + void printCfgError(const char* const type); +}; + + + +#endif /* FSFW_HAL_STM32H7_SPI_SPICOMIF_H_ */ diff --git a/hal/src/fsfw_hal/stm32h7/spi/SpiCookie.cpp b/hal/src/fsfw_hal/stm32h7/spi/SpiCookie.cpp new file mode 100644 index 00000000..200d4651 --- /dev/null +++ b/hal/src/fsfw_hal/stm32h7/spi/SpiCookie.cpp @@ -0,0 +1,78 @@ +#include "fsfw_hal/stm32h7/spi/SpiCookie.h" + + +SpiCookie::SpiCookie(address_t deviceAddress, spi::SpiBus spiIdx, spi::TransferModes transferMode, + spi::MspCfgBase* mspCfg, uint32_t spiSpeed, spi::SpiModes spiMode, + size_t maxRecvSize, stm32h7::GpioCfg csGpio): + deviceAddress(deviceAddress), spiIdx(spiIdx), spiSpeed(spiSpeed), spiMode(spiMode), + transferMode(transferMode), csGpio(csGpio), + mspCfg(mspCfg), maxRecvSize(maxRecvSize) { + spiHandle.Init.DataSize = SPI_DATASIZE_8BIT; + spiHandle.Init.FirstBit = SPI_FIRSTBIT_MSB; + spiHandle.Init.TIMode = SPI_TIMODE_DISABLE; + spiHandle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; + spiHandle.Init.CRCPolynomial = 7; + spiHandle.Init.CRCLength = SPI_CRC_LENGTH_8BIT; + spiHandle.Init.NSS = SPI_NSS_SOFT; + spiHandle.Init.NSSPMode = SPI_NSS_PULSE_DISABLE; + spiHandle.Init.Direction = SPI_DIRECTION_2LINES; + // Recommended setting to avoid glitches + spiHandle.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE; + spiHandle.Init.Mode = SPI_MODE_MASTER; + spi::assignSpiMode(spiMode, spiHandle); + spiHandle.Init.BaudRatePrescaler = spi::getPrescaler(HAL_RCC_GetHCLKFreq(), spiSpeed); +} + +uint16_t SpiCookie::getChipSelectGpioPin() const { + return csGpio.pin; +} + +GPIO_TypeDef* SpiCookie::getChipSelectGpioPort() { + return csGpio.port; +} + +address_t SpiCookie::getDeviceAddress() const { + return deviceAddress; +} + +spi::SpiBus SpiCookie::getSpiIdx() const { + return spiIdx; +} + +spi::SpiModes SpiCookie::getSpiMode() const { + return spiMode; +} + +uint32_t SpiCookie::getSpiSpeed() const { + return spiSpeed; +} + +size_t SpiCookie::getMaxRecvSize() const { + return maxRecvSize; +} + +SPI_HandleTypeDef& SpiCookie::getSpiHandle() { + return spiHandle; +} + +spi::MspCfgBase* SpiCookie::getMspCfg() { + return mspCfg; +} + +void SpiCookie::deleteMspCfg() { + if(mspCfg != nullptr) { + delete mspCfg; + } +} + +spi::TransferModes SpiCookie::getTransferMode() const { + return transferMode; +} + +void SpiCookie::setTransferState(spi::TransferStates transferState) { + this->transferState = transferState; +} + +spi::TransferStates SpiCookie::getTransferState() const { + return this->transferState; +} diff --git a/hal/src/fsfw_hal/stm32h7/spi/SpiCookie.h b/hal/src/fsfw_hal/stm32h7/spi/SpiCookie.h new file mode 100644 index 00000000..56c6e800 --- /dev/null +++ b/hal/src/fsfw_hal/stm32h7/spi/SpiCookie.h @@ -0,0 +1,80 @@ +#ifndef FSFW_HAL_STM32H7_SPI_SPICOOKIE_H_ +#define FSFW_HAL_STM32H7_SPI_SPICOOKIE_H_ + +#include "spiDefinitions.h" +#include "mspInit.h" +#include "../definitions.h" + +#include "fsfw/devicehandlers/CookieIF.h" + +#include "stm32h743xx.h" + +#include + +/** + * @brief SPI cookie implementation for the STM32H7 device family + * @details + * This cookie contains and caches device specific information to be used by the + * SPI communication interface + * @author R. Mueller + */ +class SpiCookie: public CookieIF { + friend class SpiComIF; +public: + + /** + * Allows construction of a SPI cookie for a connected SPI device + * @param deviceAddress + * @param spiIdx SPI bus, e.g. SPI1 or SPI2 + * @param transferMode + * @param mspCfg This is the MSP configuration. The user is expected to supply + * a valid MSP configuration. See mspInit.h for functions + * to create one. + * @param spiSpeed + * @param spiMode + * @param chipSelectGpioPin GPIO port. Don't use a number here, use the 16 bit type + * definitions supplied in the MCU header file! (e.g. GPIO_PIN_X) + * @param chipSelectGpioPort GPIO port (e.g. GPIOA) + * @param maxRecvSize Maximum expected receive size. Chose as small as possible. + * @param csGpio Optional CS GPIO definition. + */ + SpiCookie(address_t deviceAddress, spi::SpiBus spiIdx, spi::TransferModes transferMode, + spi::MspCfgBase* mspCfg, uint32_t spiSpeed, spi::SpiModes spiMode, + size_t maxRecvSize, stm32h7::GpioCfg csGpio = stm32h7::GpioCfg(nullptr, 0, 0)); + + uint16_t getChipSelectGpioPin() const; + GPIO_TypeDef* getChipSelectGpioPort(); + address_t getDeviceAddress() const; + spi::SpiBus getSpiIdx() const; + spi::SpiModes getSpiMode() const; + spi::TransferModes getTransferMode() const; + uint32_t getSpiSpeed() const; + size_t getMaxRecvSize() const; + SPI_HandleTypeDef& getSpiHandle(); + +private: + address_t deviceAddress; + SPI_HandleTypeDef spiHandle = {}; + spi::SpiBus spiIdx; + uint32_t spiSpeed; + spi::SpiModes spiMode; + spi::TransferModes transferMode; + volatile spi::TransferStates transferState = spi::TransferStates::IDLE; + stm32h7::GpioCfg csGpio; + + // The MSP configuration is cached here. Be careful when using this, it is automatically + // deleted by the SPI communication interface if it is not required anymore! + spi::MspCfgBase* mspCfg = nullptr; + const size_t maxRecvSize; + + // Only the SpiComIF is allowed to use this to prevent dangling pointers issues + spi::MspCfgBase* getMspCfg(); + void deleteMspCfg(); + + void setTransferState(spi::TransferStates transferState); + spi::TransferStates getTransferState() const; +}; + + + +#endif /* FSFW_HAL_STM32H7_SPI_SPICOOKIE_H_ */ diff --git a/hal/src/fsfw_hal/stm32h7/spi/mspInit.cpp b/hal/src/fsfw_hal/stm32h7/spi/mspInit.cpp new file mode 100644 index 00000000..b7ff2f70 --- /dev/null +++ b/hal/src/fsfw_hal/stm32h7/spi/mspInit.cpp @@ -0,0 +1,253 @@ +#include "fsfw_hal/stm32h7/dma.h" +#include "fsfw_hal/stm32h7/spi/mspInit.h" +#include "fsfw_hal/stm32h7/spi/spiCore.h" +#include "fsfw_hal/stm32h7/spi/spiInterrupts.h" + +#include "stm32h743xx.h" +#include "stm32h7xx_hal_spi.h" +#include "stm32h7xx_hal_dma.h" +#include "stm32h7xx_hal_def.h" + +#include + +spi::msp_func_t mspInitFunc = nullptr; +spi::MspCfgBase* mspInitArgs = nullptr; + +spi::msp_func_t mspDeinitFunc = nullptr; +spi::MspCfgBase* mspDeinitArgs = nullptr; + +/** + * @brief SPI MSP Initialization + * This function configures the hardware resources used in this example: + * - Peripheral's clock enable + * - Peripheral's GPIO Configuration + * - DMA configuration for transmission request by peripheral + * - NVIC configuration for DMA interrupt request enable + * @param hspi: SPI handle pointer + * @retval None + */ +void spi::halMspInitDma(SPI_HandleTypeDef* hspi, MspCfgBase* cfgBase) { + auto cfg = dynamic_cast(cfgBase); + if(hspi == nullptr or cfg == nullptr) { + return; + } + setSpiHandle(hspi); + + DMA_HandleTypeDef* hdma_tx = nullptr; + DMA_HandleTypeDef* hdma_rx = nullptr; + spi::getDmaHandles(&hdma_tx, &hdma_rx); + if(hdma_tx == nullptr or hdma_rx == nullptr) { + printf("HAL_SPI_MspInit: Invalid DMA handles. Make sure to call setDmaHandles!\n"); + return; + } + + spi::halMspInitInterrupt(hspi, cfg); + + // DMA setup + if(cfg->dmaClkEnableWrapper == nullptr) { + mspErrorHandler("spi::halMspInitDma", "DMA Clock init invalid"); + } + cfg->dmaClkEnableWrapper(); + + // Configure the DMA + /* Configure the DMA handler for Transmission process */ + if(hdma_tx->Instance == nullptr) { + // Assume it was not configured properly + mspErrorHandler("spi::halMspInitDma", "DMA TX handle invalid"); + } + + HAL_DMA_Init(hdma_tx); + /* Associate the initialized DMA handle to the the SPI handle */ + __HAL_LINKDMA(hspi, hdmatx, *hdma_tx); + + HAL_DMA_Init(hdma_rx); + /* Associate the initialized DMA handle to the the SPI handle */ + __HAL_LINKDMA(hspi, hdmarx, *hdma_rx); + + /*##-4- Configure the NVIC for DMA #########################################*/ + /* NVIC configuration for DMA transfer complete interrupt (SPI1_RX) */ + // Assign the interrupt handler + dma::assignDmaUserHandler(cfg->rxDmaIndex, cfg->rxDmaStream, &spi::dmaRxIrqHandler, hdma_rx); + HAL_NVIC_SetPriority(cfg->rxDmaIrqNumber, cfg->rxPreEmptPriority, cfg->rxSubpriority); + HAL_NVIC_EnableIRQ(cfg->rxDmaIrqNumber); + + /* NVIC configuration for DMA transfer complete interrupt (SPI1_TX) */ + // Assign the interrupt handler + dma::assignDmaUserHandler(cfg->txDmaIndex, cfg->txDmaStream, + &spi::dmaTxIrqHandler, hdma_tx); + HAL_NVIC_SetPriority(cfg->txDmaIrqNumber, cfg->txPreEmptPriority, cfg->txSubpriority); + HAL_NVIC_EnableIRQ(cfg->txDmaIrqNumber); +} + +/** + * @brief SPI MSP De-Initialization + * This function frees the hardware resources used in this example: + * - Disable the Peripheral's clock + * - Revert GPIO, DMA and NVIC configuration to their default state + * @param hspi: SPI handle pointer + * @retval None + */ +void spi::halMspDeinitDma(SPI_HandleTypeDef* hspi, MspCfgBase* cfgBase) { + auto cfg = dynamic_cast(cfgBase); + if(hspi == nullptr or cfg == nullptr) { + return; + } + spi::halMspDeinitInterrupt(hspi, cfgBase); + DMA_HandleTypeDef* hdma_tx = NULL; + DMA_HandleTypeDef* hdma_rx = NULL; + spi::getDmaHandles(&hdma_tx, &hdma_rx); + if(hdma_tx == NULL || hdma_rx == NULL) { + printf("HAL_SPI_MspInit: Invalid DMA handles. Make sure to call setDmaHandles!\n"); + } + else { + // Disable the DMA + /* De-Initialize the DMA associated to transmission process */ + HAL_DMA_DeInit(hdma_tx); + /* De-Initialize the DMA associated to reception process */ + HAL_DMA_DeInit(hdma_rx); + } + + // Disable the NVIC for DMA + HAL_NVIC_DisableIRQ(cfg->txDmaIrqNumber); + HAL_NVIC_DisableIRQ(cfg->rxDmaIrqNumber); + +} + +void spi::halMspInitPolling(SPI_HandleTypeDef* hspi, MspCfgBase* cfgBase) { + auto cfg = dynamic_cast(cfgBase); + GPIO_InitTypeDef GPIO_InitStruct = {}; + /*##-1- Enable peripherals and GPIO Clocks #################################*/ + /* Enable GPIO TX/RX clock */ + cfg->setupCb(); + + /*##-2- Configure peripheral GPIO ##########################################*/ + /* SPI SCK GPIO pin configuration */ + GPIO_InitStruct.Pin = cfg->sck.pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_PULLDOWN; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; + GPIO_InitStruct.Alternate = cfg->sck.altFnc; + HAL_GPIO_Init(cfg->sck.port, &GPIO_InitStruct); + + /* SPI MISO GPIO pin configuration */ + GPIO_InitStruct.Pin = cfg->miso.pin; + GPIO_InitStruct.Alternate = cfg->miso.altFnc; + HAL_GPIO_Init(cfg->miso.port, &GPIO_InitStruct); + + /* SPI MOSI GPIO pin configuration */ + GPIO_InitStruct.Pin = cfg->mosi.pin; + GPIO_InitStruct.Alternate = cfg->mosi.altFnc; + HAL_GPIO_Init(cfg->mosi.port, &GPIO_InitStruct); +} + +void spi::halMspDeinitPolling(SPI_HandleTypeDef* hspi, MspCfgBase* cfgBase) { + auto cfg = reinterpret_cast(cfgBase); + // Reset peripherals + cfg->cleanupCb(); + + // Disable peripherals and GPIO Clocks + /* Configure SPI SCK as alternate function */ + HAL_GPIO_DeInit(cfg->sck.port, cfg->sck.pin); + /* Configure SPI MISO as alternate function */ + HAL_GPIO_DeInit(cfg->miso.port, cfg->miso.pin); + /* Configure SPI MOSI as alternate function */ + HAL_GPIO_DeInit(cfg->mosi.port, cfg->mosi.pin); +} + +void spi::halMspInitInterrupt(SPI_HandleTypeDef* hspi, MspCfgBase* cfgBase) { + auto cfg = dynamic_cast(cfgBase); + if(cfg == nullptr or hspi == nullptr) { + return; + } + + spi::halMspInitPolling(hspi, cfg); + // Configure the NVIC for SPI + spi::assignSpiUserHandler(cfg->spiBus, cfg->spiIrqHandler, cfg->spiUserArgs); + HAL_NVIC_SetPriority(cfg->spiIrqNumber, cfg->preEmptPriority, cfg->subpriority); + HAL_NVIC_EnableIRQ(cfg->spiIrqNumber); +} + +void spi::halMspDeinitInterrupt(SPI_HandleTypeDef* hspi, MspCfgBase* cfgBase) { + auto cfg = dynamic_cast(cfgBase); + spi::halMspDeinitPolling(hspi, cfg); + // Disable the NVIC for SPI + HAL_NVIC_DisableIRQ(cfg->spiIrqNumber); +} + +void spi::getMspInitFunction(msp_func_t* init_func, MspCfgBase** args) { + if(init_func != NULL && args != NULL) { + *init_func = mspInitFunc; + *args = mspInitArgs; + } +} + +void spi::getMspDeinitFunction(msp_func_t* deinit_func, MspCfgBase** args) { + if(deinit_func != NULL && args != NULL) { + *deinit_func = mspDeinitFunc; + *args = mspDeinitArgs; + } +} + +void spi::setSpiDmaMspFunctions(MspDmaConfigStruct* cfg, + msp_func_t initFunc, msp_func_t deinitFunc) { + mspInitFunc = initFunc; + mspDeinitFunc = deinitFunc; + mspInitArgs = cfg; + mspDeinitArgs = cfg; +} + +void spi::setSpiIrqMspFunctions(MspIrqConfigStruct *cfg, msp_func_t initFunc, + msp_func_t deinitFunc) { + mspInitFunc = initFunc; + mspDeinitFunc = deinitFunc; + mspInitArgs = cfg; + mspDeinitArgs = cfg; +} + +void spi::setSpiPollingMspFunctions(MspPollingConfigStruct *cfg, msp_func_t initFunc, + msp_func_t deinitFunc) { + mspInitFunc = initFunc; + mspDeinitFunc = deinitFunc; + mspInitArgs = cfg; + mspDeinitArgs = cfg; +} + +/** + * @brief SPI MSP Initialization + * This function configures the hardware resources used in this example: + * - Peripheral's clock enable + * - Peripheral's GPIO Configuration + * - DMA configuration for transmission request by peripheral + * - NVIC configuration for DMA interrupt request enable + * @param hspi: SPI handle pointer + * @retval None + */ +extern "C" void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi) { + if(mspInitFunc != NULL) { + mspInitFunc(hspi, mspInitArgs); + } + else { + printf("HAL_SPI_MspInit: Please call set_msp_functions to assign SPI MSP functions\n"); + } +} + +/** + * @brief SPI MSP De-Initialization + * This function frees the hardware resources used in this example: + * - Disable the Peripheral's clock + * - Revert GPIO, DMA and NVIC configuration to their default state + * @param hspi: SPI handle pointer + * @retval None + */ +extern "C" void HAL_SPI_MspDeInit(SPI_HandleTypeDef *hspi) { + if(mspDeinitFunc != NULL) { + mspDeinitFunc(hspi, mspDeinitArgs); + } + else { + printf("HAL_SPI_MspDeInit: Please call set_msp_functions to assign SPI MSP functions\n"); + } +} + +void spi::mspErrorHandler(const char* const function, const char *const message) { + printf("%s failure: %s\n", function, message); +} diff --git a/hal/src/fsfw_hal/stm32h7/spi/mspInit.h b/hal/src/fsfw_hal/stm32h7/spi/mspInit.h new file mode 100644 index 00000000..0fb553f7 --- /dev/null +++ b/hal/src/fsfw_hal/stm32h7/spi/mspInit.h @@ -0,0 +1,132 @@ +#ifndef FSFW_HAL_STM32H7_SPI_MSPINIT_H_ +#define FSFW_HAL_STM32H7_SPI_MSPINIT_H_ + +#include "spiDefinitions.h" +#include "../definitions.h" +#include "../dma.h" + +#include "stm32h7xx_hal_spi.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +using mspCb = void (*) (void); + +/** + * @brief This file provides MSP implementation for DMA, IRQ and Polling mode for the + * SPI peripheral. This configuration is required for the SPI communication to work. + */ +namespace spi { + +struct MspCfgBase { + MspCfgBase(); + MspCfgBase(stm32h7::GpioCfg sck, stm32h7::GpioCfg mosi, stm32h7::GpioCfg miso, + mspCb cleanupCb = nullptr, mspCb setupCb = nullptr): + sck(sck), mosi(mosi), miso(miso), cleanupCb(cleanupCb), + setupCb(setupCb) {} + + virtual ~MspCfgBase() = default; + + stm32h7::GpioCfg sck; + stm32h7::GpioCfg mosi; + stm32h7::GpioCfg miso; + + mspCb cleanupCb = nullptr; + mspCb setupCb = nullptr; +}; + +struct MspPollingConfigStruct: public MspCfgBase { + MspPollingConfigStruct(): MspCfgBase() {}; + MspPollingConfigStruct(stm32h7::GpioCfg sck, stm32h7::GpioCfg mosi, stm32h7::GpioCfg miso, + mspCb cleanupCb = nullptr, mspCb setupCb = nullptr): + MspCfgBase(sck, mosi, miso, cleanupCb, setupCb) {} +}; + +/* A valid instance of this struct must be passed to the MSP initialization function as a void* +argument */ +struct MspIrqConfigStruct: public MspPollingConfigStruct { + MspIrqConfigStruct(): MspPollingConfigStruct() {}; + MspIrqConfigStruct(stm32h7::GpioCfg sck, stm32h7::GpioCfg mosi, stm32h7::GpioCfg miso, + mspCb cleanupCb = nullptr, mspCb setupCb = nullptr): + MspPollingConfigStruct(sck, mosi, miso, cleanupCb, setupCb) {} + + SpiBus spiBus = SpiBus::SPI_1; + user_handler_t spiIrqHandler = nullptr; + user_args_t spiUserArgs = nullptr; + IRQn_Type spiIrqNumber = SPI1_IRQn; + // Priorities for NVIC + // Pre-Empt priority ranging from 0 to 15. If FreeRTOS calls are used, only 5-15 are allowed + IrqPriorities preEmptPriority = IrqPriorities::LOWEST; + IrqPriorities subpriority = IrqPriorities::LOWEST; +}; + +/* A valid instance of this struct must be passed to the MSP initialization function as a void* +argument */ +struct MspDmaConfigStruct: public MspIrqConfigStruct { + MspDmaConfigStruct(): MspIrqConfigStruct() {}; + MspDmaConfigStruct(stm32h7::GpioCfg sck, stm32h7::GpioCfg mosi, stm32h7::GpioCfg miso, + mspCb cleanupCb = nullptr, mspCb setupCb = nullptr): + MspIrqConfigStruct(sck, mosi, miso, cleanupCb, setupCb) {} + void (* dmaClkEnableWrapper) (void) = nullptr; + + dma::DMAIndexes txDmaIndex = dma::DMAIndexes::DMA_1; + dma::DMAIndexes rxDmaIndex = dma::DMAIndexes::DMA_1; + dma::DMAStreams txDmaStream = dma::DMAStreams::STREAM_0; + dma::DMAStreams rxDmaStream = dma::DMAStreams::STREAM_0; + IRQn_Type txDmaIrqNumber = DMA1_Stream0_IRQn; + IRQn_Type rxDmaIrqNumber = DMA1_Stream1_IRQn; + // Priorities for NVIC + IrqPriorities txPreEmptPriority = IrqPriorities::LOWEST; + IrqPriorities rxPreEmptPriority = IrqPriorities::LOWEST; + IrqPriorities txSubpriority = IrqPriorities::LOWEST; + IrqPriorities rxSubpriority = IrqPriorities::LOWEST; +}; + +using msp_func_t = void (*) (SPI_HandleTypeDef* hspi, MspCfgBase* cfg); + + +void getMspInitFunction(msp_func_t* init_func, MspCfgBase **args); +void getMspDeinitFunction(msp_func_t* deinit_func, MspCfgBase **args); + +void halMspInitDma(SPI_HandleTypeDef* hspi, MspCfgBase* cfg); +void halMspDeinitDma(SPI_HandleTypeDef* hspi, MspCfgBase* cfg); + +void halMspInitInterrupt(SPI_HandleTypeDef* hspi, MspCfgBase* cfg); +void halMspDeinitInterrupt(SPI_HandleTypeDef* hspi, MspCfgBase* cfg); + +void halMspInitPolling(SPI_HandleTypeDef* hspi, MspCfgBase* cfg); +void halMspDeinitPolling(SPI_HandleTypeDef* hspi, MspCfgBase* cfg); + +/** + * Assign MSP init functions. Important for SPI configuration + * @param init_func + * @param init_args + * @param deinit_func + * @param deinit_args + */ +void setSpiDmaMspFunctions(MspDmaConfigStruct* cfg, + msp_func_t initFunc = &spi::halMspInitDma, + msp_func_t deinitFunc= &spi::halMspDeinitDma +); +void setSpiIrqMspFunctions(MspIrqConfigStruct* cfg, + msp_func_t initFunc = &spi::halMspInitInterrupt, + msp_func_t deinitFunc= &spi::halMspDeinitInterrupt +); +void setSpiPollingMspFunctions(MspPollingConfigStruct* cfg, + msp_func_t initFunc = &spi::halMspInitPolling, + msp_func_t deinitFunc= &spi::halMspDeinitPolling +); + +void mspErrorHandler(const char* const function, const char *const message); + +} + + +#ifdef __cplusplus +} +#endif + +#endif /* FSFW_HAL_STM32H7_SPI_MSPINIT_H_ */ diff --git a/hal/src/fsfw_hal/stm32h7/spi/spiCore.cpp b/hal/src/fsfw_hal/stm32h7/spi/spiCore.cpp new file mode 100644 index 00000000..e569c9f4 --- /dev/null +++ b/hal/src/fsfw_hal/stm32h7/spi/spiCore.cpp @@ -0,0 +1,341 @@ +#include "fsfw_hal/stm32h7/spi/spiCore.h" +#include "fsfw_hal/stm32h7/spi/spiDefinitions.h" + +#include + +SPI_HandleTypeDef* spiHandle = nullptr; +DMA_HandleTypeDef* hdmaTx = nullptr; +DMA_HandleTypeDef* hdmaRx = nullptr; + +spi_transfer_cb_t rxTxCb = nullptr; +void* rxTxArgs = nullptr; +spi_transfer_cb_t txCb = nullptr; +void* txArgs = nullptr; +spi_transfer_cb_t rxCb = nullptr; +void* rxArgs = nullptr; +spi_transfer_cb_t errorCb = nullptr; +void* errorArgs = nullptr; + +void mapIndexAndStream(DMA_HandleTypeDef* handle, dma::DMAType dmaType, dma::DMAIndexes dmaIdx, + dma::DMAStreams dmaStream, IRQn_Type* dmaIrqNumber); +void mapSpiBus(DMA_HandleTypeDef *handle, dma::DMAType dmaType, spi::SpiBus spiBus); + +void spi::configureDmaHandle(DMA_HandleTypeDef *handle, spi::SpiBus spiBus, dma::DMAType dmaType, + dma::DMAIndexes dmaIdx, dma::DMAStreams dmaStream, IRQn_Type* dmaIrqNumber, + uint32_t dmaMode, uint32_t dmaPriority) { + using namespace dma; + mapIndexAndStream(handle, dmaType, dmaIdx, dmaStream, dmaIrqNumber); + mapSpiBus(handle, dmaType, spiBus); + + if(dmaType == DMAType::TX) { + handle->Init.Direction = DMA_MEMORY_TO_PERIPH; + } + else { + handle->Init.Direction = DMA_PERIPH_TO_MEMORY; + } + + handle->Init.Priority = dmaPriority; + handle->Init.Mode = dmaMode; + + // Standard settings for the rest for now + handle->Init.FIFOMode = DMA_FIFOMODE_DISABLE; + handle->Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + handle->Init.MemBurst = DMA_MBURST_INC4; + handle->Init.PeriphBurst = DMA_PBURST_INC4; + handle->Init.PeriphInc = DMA_PINC_DISABLE; + handle->Init.MemInc = DMA_MINC_ENABLE; + handle->Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; + handle->Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; +} + +void spi::setDmaHandles(DMA_HandleTypeDef* txHandle, DMA_HandleTypeDef* rxHandle) { + hdmaTx = txHandle; + hdmaRx = rxHandle; +} + +void spi::getDmaHandles(DMA_HandleTypeDef** txHandle, DMA_HandleTypeDef** rxHandle) { + *txHandle = hdmaTx; + *rxHandle = hdmaRx; +} + +void spi::setSpiHandle(SPI_HandleTypeDef *spiHandle_) { + if(spiHandle_ == NULL) { + return; + } + spiHandle = spiHandle_; +} + +void spi::assignTransferRxTxCompleteCallback(spi_transfer_cb_t callback, void *userArgs) { + rxTxCb = callback; + rxTxArgs = userArgs; +} + +void spi::assignTransferRxCompleteCallback(spi_transfer_cb_t callback, void *userArgs) { + rxCb = callback; + rxArgs = userArgs; +} + +void spi::assignTransferTxCompleteCallback(spi_transfer_cb_t callback, void *userArgs) { + txCb = callback; + txArgs = userArgs; +} + +void spi::assignTransferErrorCallback(spi_transfer_cb_t callback, void *userArgs) { + errorCb = callback; + errorArgs = userArgs; +} + +SPI_HandleTypeDef* spi::getSpiHandle() { + return spiHandle; +} + + + +/** + * @brief TxRx Transfer completed callback. + * @param hspi: SPI handle + */ +extern "C" void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi) { + if(rxTxCb != NULL) { + rxTxCb(hspi, rxTxArgs); + } + else { + printf("HAL_SPI_TxRxCpltCallback: No user callback specified\n"); + } +} + +/** + * @brief TxRx Transfer completed callback. + * @param hspi: SPI handle + */ +extern "C" void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi) { + if(txCb != NULL) { + txCb(hspi, txArgs); + } + else { + printf("HAL_SPI_TxCpltCallback: No user callback specified\n"); + } +} + +/** + * @brief TxRx Transfer completed callback. + * @param hspi: SPI handle + */ +extern "C" void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi) { + if(rxCb != nullptr) { + rxCb(hspi, rxArgs); + } + else { + printf("HAL_SPI_RxCpltCallback: No user callback specified\n"); + } +} + +/** + * @brief SPI error callbacks. + * @param hspi: SPI handle + * @note This example shows a simple way to report transfer error, and you can + * add your own implementation. + * @retval None + */ +extern "C" void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi) { + if(errorCb != nullptr) { + errorCb(hspi, rxArgs); + } + else { + printf("HAL_SPI_ErrorCallback: No user callback specified\n"); + } +} + +void mapIndexAndStream(DMA_HandleTypeDef* handle, dma::DMAType dmaType, dma::DMAIndexes dmaIdx, + dma::DMAStreams dmaStream, IRQn_Type* dmaIrqNumber) { + using namespace dma; + if(dmaIdx == DMAIndexes::DMA_1) { +#ifdef DMA1 + switch(dmaStream) { + case(DMAStreams::STREAM_0): { +#ifdef DMA1_Stream0 + handle->Instance = DMA1_Stream0; + if(dmaIrqNumber != nullptr) { + *dmaIrqNumber = DMA1_Stream0_IRQn; + } +#endif + break; + } + case(DMAStreams::STREAM_1): { +#ifdef DMA1_Stream1 + handle->Instance = DMA1_Stream1; + if(dmaIrqNumber != nullptr) { + *dmaIrqNumber = DMA1_Stream1_IRQn; + } +#endif + break; + } + case(DMAStreams::STREAM_2): { +#ifdef DMA1_Stream2 + handle->Instance = DMA1_Stream2; + if(dmaIrqNumber != nullptr) { + *dmaIrqNumber = DMA1_Stream2_IRQn; + } +#endif + break; + } + case(DMAStreams::STREAM_3): { +#ifdef DMA1_Stream3 + handle->Instance = DMA1_Stream3; + if(dmaIrqNumber != nullptr) { + *dmaIrqNumber = DMA1_Stream3_IRQn; + } +#endif + break; + } + case(DMAStreams::STREAM_4): { +#ifdef DMA1_Stream4 + handle->Instance = DMA1_Stream4; + if(dmaIrqNumber != nullptr) { + *dmaIrqNumber = DMA1_Stream4_IRQn; + } +#endif + break; + } + case(DMAStreams::STREAM_5): { +#ifdef DMA1_Stream5 + handle->Instance = DMA1_Stream5; + if(dmaIrqNumber != nullptr) { + *dmaIrqNumber = DMA1_Stream5_IRQn; + } +#endif + break; + } + case(DMAStreams::STREAM_6): { +#ifdef DMA1_Stream6 + handle->Instance = DMA1_Stream6; + if(dmaIrqNumber != nullptr) { + *dmaIrqNumber = DMA1_Stream6_IRQn; + } +#endif + break; + } + case(DMAStreams::STREAM_7): { +#ifdef DMA1_Stream7 + handle->Instance = DMA1_Stream7; + if(dmaIrqNumber != nullptr) { + *dmaIrqNumber = DMA1_Stream7_IRQn; + } +#endif + break; + } + } + if(dmaType == DMAType::TX) { + handle->Init.Request = DMA_REQUEST_SPI1_TX; + } + else { + handle->Init.Request = DMA_REQUEST_SPI1_RX; + } +#endif /* DMA1 */ + } + if(dmaIdx == DMAIndexes::DMA_2) { +#ifdef DMA2 + switch(dmaStream) { + case(DMAStreams::STREAM_0): { +#ifdef DMA2_Stream0 + handle->Instance = DMA2_Stream0; + if(dmaIrqNumber != nullptr) { + *dmaIrqNumber = DMA2_Stream0_IRQn; + } +#endif + break; + } + case(DMAStreams::STREAM_1): { +#ifdef DMA2_Stream1 + handle->Instance = DMA2_Stream1; + if(dmaIrqNumber != nullptr) { + *dmaIrqNumber = DMA2_Stream1_IRQn; + } +#endif + break; + } + case(DMAStreams::STREAM_2): { +#ifdef DMA2_Stream2 + handle->Instance = DMA2_Stream2; + if(dmaIrqNumber != nullptr) { + *dmaIrqNumber = DMA2_Stream2_IRQn; + } +#endif + break; + } + case(DMAStreams::STREAM_3): { +#ifdef DMA2_Stream3 + handle->Instance = DMA2_Stream3; + if(dmaIrqNumber != nullptr) { + *dmaIrqNumber = DMA2_Stream3_IRQn; + } +#endif + break; + } + case(DMAStreams::STREAM_4): { +#ifdef DMA2_Stream4 + handle->Instance = DMA2_Stream4; + if(dmaIrqNumber != nullptr) { + *dmaIrqNumber = DMA2_Stream4_IRQn; + } +#endif + break; + } + case(DMAStreams::STREAM_5): { +#ifdef DMA2_Stream5 + handle->Instance = DMA2_Stream5; + if(dmaIrqNumber != nullptr) { + *dmaIrqNumber = DMA2_Stream5_IRQn; + } +#endif + break; + } + case(DMAStreams::STREAM_6): { +#ifdef DMA2_Stream6 + handle->Instance = DMA2_Stream6; + if(dmaIrqNumber != nullptr) { + *dmaIrqNumber = DMA2_Stream6_IRQn; + } +#endif + break; + } + case(DMAStreams::STREAM_7): { +#ifdef DMA2_Stream7 + handle->Instance = DMA2_Stream7; + if(dmaIrqNumber != nullptr) { + *dmaIrqNumber = DMA2_Stream7_IRQn; + } +#endif + break; + } + } +#endif /* DMA2 */ + } +} + +void mapSpiBus(DMA_HandleTypeDef *handle, dma::DMAType dmaType, spi::SpiBus spiBus) { + if(dmaType == dma::DMAType::TX) { + if(spiBus == spi::SpiBus::SPI_1) { +#ifdef DMA_REQUEST_SPI1_TX + handle->Init.Request = DMA_REQUEST_SPI1_TX; +#endif + } + else if(spiBus == spi::SpiBus::SPI_2) { +#ifdef DMA_REQUEST_SPI2_TX + handle->Init.Request = DMA_REQUEST_SPI2_TX; +#endif + } + } + else { + if(spiBus == spi::SpiBus::SPI_1) { +#ifdef DMA_REQUEST_SPI1_RX + handle->Init.Request = DMA_REQUEST_SPI1_RX; +#endif + } + else if(spiBus == spi::SpiBus::SPI_2) { +#ifdef DMA_REQUEST_SPI2_RX + handle->Init.Request = DMA_REQUEST_SPI2_RX; +#endif + } + } +} diff --git a/hal/src/fsfw_hal/stm32h7/spi/spiCore.h b/hal/src/fsfw_hal/stm32h7/spi/spiCore.h new file mode 100644 index 00000000..1ad5c693 --- /dev/null +++ b/hal/src/fsfw_hal/stm32h7/spi/spiCore.h @@ -0,0 +1,54 @@ +#ifndef FSFW_HAL_STM32H7_SPI_SPICORE_H_ +#define FSFW_HAL_STM32H7_SPI_SPICORE_H_ + +#include "fsfw_hal/stm32h7/dma.h" +#include "fsfw_hal/stm32h7/spi/spiDefinitions.h" + +#include "stm32h7xx_hal.h" +#include "stm32h7xx_hal_dma.h" + +#ifdef __cplusplus +extern "C" { +#endif + +using spi_transfer_cb_t = void (*) (SPI_HandleTypeDef *hspi, void* userArgs); + +namespace spi { + +void configureDmaHandle(DMA_HandleTypeDef* handle, spi::SpiBus spiBus, + dma::DMAType dmaType, dma::DMAIndexes dmaIdx, + dma::DMAStreams dmaStream, IRQn_Type* dmaIrqNumber, uint32_t dmaMode = DMA_NORMAL, + uint32_t dmaPriority = DMA_PRIORITY_LOW); + +/** + * Assign DMA handles. Required to use DMA for SPI transfers. + * @param txHandle + * @param rxHandle + */ +void setDmaHandles(DMA_HandleTypeDef* txHandle, DMA_HandleTypeDef* rxHandle); +void getDmaHandles(DMA_HandleTypeDef** txHandle, DMA_HandleTypeDef** rxHandle); + +/** + * Assign SPI handle. Needs to be done before using the SPI + * @param spiHandle + */ +void setSpiHandle(SPI_HandleTypeDef *spiHandle); + +void assignTransferRxTxCompleteCallback(spi_transfer_cb_t callback, void* userArgs); +void assignTransferRxCompleteCallback(spi_transfer_cb_t callback, void* userArgs); +void assignTransferTxCompleteCallback(spi_transfer_cb_t callback, void* userArgs); +void assignTransferErrorCallback(spi_transfer_cb_t callback, void* userArgs); + +/** + * Get the assigned SPI handle. + * @return + */ +SPI_HandleTypeDef* getSpiHandle(); + +} + +#ifdef __cplusplus +} +#endif + +#endif /* FSFW_HAL_STM32H7_SPI_SPICORE_H_ */ diff --git a/hal/src/fsfw_hal/stm32h7/spi/spiDefinitions.cpp b/hal/src/fsfw_hal/stm32h7/spi/spiDefinitions.cpp new file mode 100644 index 00000000..11655f5e --- /dev/null +++ b/hal/src/fsfw_hal/stm32h7/spi/spiDefinitions.cpp @@ -0,0 +1,52 @@ +#include "fsfw_hal/stm32h7/spi/spiDefinitions.h" + +void spi::assignSpiMode(SpiModes spiMode, SPI_HandleTypeDef& spiHandle) { + switch(spiMode) { + case(SpiModes::MODE_0): { + spiHandle.Init.CLKPolarity = SPI_POLARITY_LOW; + spiHandle.Init.CLKPhase = SPI_PHASE_1EDGE; + break; + } + case(SpiModes::MODE_1): { + spiHandle.Init.CLKPolarity = SPI_POLARITY_LOW; + spiHandle.Init.CLKPhase = SPI_PHASE_2EDGE; + break; + } + case(SpiModes::MODE_2): { + spiHandle.Init.CLKPolarity = SPI_POLARITY_HIGH; + spiHandle.Init.CLKPhase = SPI_PHASE_1EDGE; + break; + } + case(SpiModes::MODE_3): { + spiHandle.Init.CLKPolarity = SPI_POLARITY_HIGH; + spiHandle.Init.CLKPhase = SPI_PHASE_2EDGE; + break; + } + } +} + +uint32_t spi::getPrescaler(uint32_t clock_src_freq, uint32_t baudrate_mbps) { + uint32_t divisor = 0; + uint32_t spi_clk = clock_src_freq; + uint32_t presc = 0; + static const uint32_t baudrate[] = { + SPI_BAUDRATEPRESCALER_2, + SPI_BAUDRATEPRESCALER_4, + SPI_BAUDRATEPRESCALER_8, + SPI_BAUDRATEPRESCALER_16, + SPI_BAUDRATEPRESCALER_32, + SPI_BAUDRATEPRESCALER_64, + SPI_BAUDRATEPRESCALER_128, + SPI_BAUDRATEPRESCALER_256, + }; + + while( spi_clk > baudrate_mbps) { + presc = baudrate[divisor]; + if (++divisor > 7) + break; + + spi_clk = ( spi_clk >> 1); + } + + return presc; +} diff --git a/hal/src/fsfw_hal/stm32h7/spi/spiDefinitions.h b/hal/src/fsfw_hal/stm32h7/spi/spiDefinitions.h new file mode 100644 index 00000000..772bf32d --- /dev/null +++ b/hal/src/fsfw_hal/stm32h7/spi/spiDefinitions.h @@ -0,0 +1,50 @@ +#ifndef FSFW_HAL_STM32H7_SPI_SPIDEFINITIONS_H_ +#define FSFW_HAL_STM32H7_SPI_SPIDEFINITIONS_H_ + +#include "../../common/spi/spiCommon.h" + +#include "fsfw/returnvalues/FwClassIds.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" + +#include "stm32h7xx_hal.h" +#include "stm32h7xx_hal_spi.h" + +namespace spi { + +static constexpr uint8_t HAL_SPI_ID = CLASS_ID::HAL_SPI; +static constexpr ReturnValue_t HAL_TIMEOUT_RETVAL = HasReturnvaluesIF::makeReturnCode(HAL_SPI_ID, 0); +static constexpr ReturnValue_t HAL_BUSY_RETVAL = HasReturnvaluesIF::makeReturnCode(HAL_SPI_ID, 1); +static constexpr ReturnValue_t HAL_ERROR_RETVAL = HasReturnvaluesIF::makeReturnCode(HAL_SPI_ID, 2); + +enum class TransferStates { + IDLE, + WAIT, + SUCCESS, + FAILURE +}; + +enum SpiBus { + SPI_1, + SPI_2 +}; + +enum TransferModes { + POLLING, + INTERRUPT, + DMA +}; + +void assignSpiMode(SpiModes spiMode, SPI_HandleTypeDef& spiHandle); + +/** + * @brief Set SPI frequency to calculate correspondent baud-rate prescaler. + * @param clock_src_freq Frequency of clock source + * @param baudrate_mbps Baudrate to set to set + * @retval Baudrate prescaler + */ +uint32_t getPrescaler(uint32_t clock_src_freq, uint32_t baudrate_mbps); + +} + + +#endif /* FSFW_HAL_STM32H7_SPI_SPIDEFINITIONS_H_ */ diff --git a/hal/src/fsfw_hal/stm32h7/spi/spiInterrupts.cpp b/hal/src/fsfw_hal/stm32h7/spi/spiInterrupts.cpp new file mode 100644 index 00000000..5d84208d --- /dev/null +++ b/hal/src/fsfw_hal/stm32h7/spi/spiInterrupts.cpp @@ -0,0 +1,106 @@ +#include "fsfw_hal/stm32h7/spi/spiInterrupts.h" +#include "fsfw_hal/stm32h7/spi/spiCore.h" + +#include "stm32h7xx_hal.h" +#include "stm32h7xx_hal_dma.h" +#include "stm32h7xx_hal_spi.h" + +#include + +user_handler_t spi1UserHandler = &spi::spiIrqHandler; +user_args_t spi1UserArgs = nullptr; + +user_handler_t spi2UserHandler = &spi::spiIrqHandler; +user_args_t spi2UserArgs = nullptr; + +/** + * @brief This function handles DMA Rx interrupt request. + * @param None + * @retval None + */ +void spi::dmaRxIrqHandler(void* dmaHandle) { + if(dmaHandle == nullptr) { + return; + } + HAL_DMA_IRQHandler((DMA_HandleTypeDef *) dmaHandle); +} + +/** + * @brief This function handles DMA Rx interrupt request. + * @param None + * @retval None + */ +void spi::dmaTxIrqHandler(void* dmaHandle) { + if(dmaHandle == nullptr) { + return; + } + HAL_DMA_IRQHandler((DMA_HandleTypeDef *) dmaHandle); +} + +/** + * @brief This function handles SPIx interrupt request. + * @param None + * @retval None + */ +void spi::spiIrqHandler(void* spiHandle) { + if(spiHandle == nullptr) { + return; + } + //auto currentSpiHandle = spi::getSpiHandle(); + HAL_SPI_IRQHandler((SPI_HandleTypeDef *) spiHandle); +} + +void spi::assignSpiUserHandler(spi::SpiBus spiIdx, user_handler_t userHandler, + user_args_t userArgs) { + if(spiIdx == spi::SpiBus::SPI_1) { + spi1UserHandler = userHandler; + spi1UserArgs = userArgs; + } + else { + spi2UserHandler = userHandler; + spi2UserArgs = userArgs; + } +} + +void spi::getSpiUserHandler(spi::SpiBus spiBus, user_handler_t *userHandler, + user_args_t *userArgs) { + if(userHandler == nullptr or userArgs == nullptr) { + return; + } + if(spiBus == spi::SpiBus::SPI_1) { + *userArgs = spi1UserArgs; + *userHandler = spi1UserHandler; + } + else { + *userArgs = spi2UserArgs; + *userHandler = spi2UserHandler; + } +} + +void spi::assignSpiUserArgs(spi::SpiBus spiBus, user_args_t userArgs) { + if(spiBus == spi::SpiBus::SPI_1) { + spi1UserArgs = userArgs; + } + else { + spi2UserArgs = userArgs; + } +} + +/* Do not change these function names! They need to be exactly equal to the name of the functions +defined in the startup_stm32h743xx.s files! */ + +extern "C" void SPI1_IRQHandler() { + if(spi1UserHandler != NULL) { + spi1UserHandler(spi1UserArgs); + return; + } + Default_Handler(); +} + +extern "C" void SPI2_IRQHandler() { + if(spi2UserHandler != nullptr) { + spi2UserHandler(spi2UserArgs); + return; + } + Default_Handler(); +} diff --git a/hal/src/fsfw_hal/stm32h7/spi/spiInterrupts.h b/hal/src/fsfw_hal/stm32h7/spi/spiInterrupts.h new file mode 100644 index 00000000..0b53f48b --- /dev/null +++ b/hal/src/fsfw_hal/stm32h7/spi/spiInterrupts.h @@ -0,0 +1,41 @@ +#ifndef FSFW_HAL_STM32H7_SPI_INTERRUPTS_H_ +#define FSFW_HAL_STM32H7_SPI_INTERRUPTS_H_ + +#include "../interrupts.h" +#include "spiDefinitions.h" + +#ifdef __cplusplus +extern "C" { +#endif + +namespace spi { + +void assignSpiUserArgs(spi::SpiBus spiBus, user_args_t userArgs); + +/** + * Assign a user interrupt handler for SPI bus 1, allowing to pass an arbitrary argument as well. + * Generally, this argument will be the related SPI handle. + * @param user_handler + * @param user_args + */ +void assignSpiUserHandler(spi::SpiBus spiBus, user_handler_t user_handler, + user_args_t user_args); +void getSpiUserHandler(spi::SpiBus spiBus, user_handler_t* user_handler, + user_args_t* user_args); + +/** + * Generic interrupt handlers supplied for convenience. Do not call these directly! Set them + * instead with assign_dma_user_handler and assign_spi_user_handler functions. + * @param dma_handle + */ +void dmaRxIrqHandler(void* dma_handle); +void dmaTxIrqHandler(void* dma_handle); +void spiIrqHandler(void* spi_handle); + +} + +#ifdef __cplusplus +} +#endif + +#endif /* FSFW_HAL_STM32H7_SPI_INTERRUPTS_H_ */ diff --git a/hal/src/fsfw_hal/stm32h7/spi/stm32h743zi.cpp b/hal/src/fsfw_hal/stm32h7/spi/stm32h743zi.cpp new file mode 100644 index 00000000..1bafccd5 --- /dev/null +++ b/hal/src/fsfw_hal/stm32h7/spi/stm32h743zi.cpp @@ -0,0 +1,82 @@ +#include "fsfw_hal/stm32h7/spi/stm32h743zi.h" +#include "fsfw_hal/stm32h7/spi/spiCore.h" +#include "fsfw_hal/stm32h7/spi/spiInterrupts.h" + +#include "stm32h7xx_hal.h" +#include "stm32h7xx_hal_rcc.h" + +#include + +void spiSetupWrapper() { + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_SPI1_CLK_ENABLE(); +} + +void spiCleanUpWrapper() { + __HAL_RCC_SPI1_FORCE_RESET(); + __HAL_RCC_SPI1_RELEASE_RESET(); +} + +void spiDmaClockEnableWrapper() { + __HAL_RCC_DMA2_CLK_ENABLE(); +} + +void stm32h7::h743zi::standardPollingCfg(spi::MspPollingConfigStruct& cfg) { + cfg.setupCb = &spiSetupWrapper; + cfg.cleanupCb = &spiCleanUpWrapper; + cfg.sck.port = GPIOA; + cfg.sck.pin = GPIO_PIN_5; + cfg.miso.port = GPIOA; + cfg.miso.pin = GPIO_PIN_6; + cfg.mosi.port = GPIOA; + cfg.mosi.pin = GPIO_PIN_7; + cfg.sck.altFnc = GPIO_AF5_SPI1; + cfg.mosi.altFnc = GPIO_AF5_SPI1; + cfg.miso.altFnc = GPIO_AF5_SPI1; +} + +void stm32h7::h743zi::standardInterruptCfg(spi::MspIrqConfigStruct& cfg, IrqPriorities spiIrqPrio, + IrqPriorities spiSubprio) { + // High, but works on FreeRTOS as well (priorities range from 0 to 15) + cfg.preEmptPriority = spiIrqPrio; + cfg.subpriority = spiSubprio; + cfg.spiIrqNumber = SPI1_IRQn; + cfg.spiBus = spi::SpiBus::SPI_1; + user_handler_t spiUserHandler = nullptr; + user_args_t spiUserArgs = nullptr; + getSpiUserHandler(spi::SpiBus::SPI_1, &spiUserHandler, &spiUserArgs); + if(spiUserHandler == nullptr) { + printf("spi::h743zi::standardInterruptCfg: Invalid SPI user handlers\n"); + return; + } + cfg.spiUserArgs = spiUserArgs; + cfg.spiIrqHandler = spiUserHandler; + standardPollingCfg(cfg); +} + +void stm32h7::h743zi::standardDmaCfg(spi::MspDmaConfigStruct& cfg, IrqPriorities spiIrqPrio, + IrqPriorities txIrqPrio, IrqPriorities rxIrqPrio, IrqPriorities spiSubprio, + IrqPriorities txSubprio, IrqPriorities rxSubprio) { + cfg.dmaClkEnableWrapper = &spiDmaClockEnableWrapper; + cfg.rxDmaIndex = dma::DMAIndexes::DMA_2; + cfg.txDmaIndex = dma::DMAIndexes::DMA_2; + cfg.txDmaStream = dma::DMAStreams::STREAM_3; + cfg.rxDmaStream = dma::DMAStreams::STREAM_2; + DMA_HandleTypeDef* txHandle; + DMA_HandleTypeDef* rxHandle; + spi::getDmaHandles(&txHandle, &rxHandle); + if(txHandle == nullptr or rxHandle == nullptr) { + printf("spi::h743zi::standardDmaCfg: Invalid DMA handles\n"); + return; + } + spi::configureDmaHandle(txHandle, spi::SpiBus::SPI_1, dma::DMAType::TX, cfg.txDmaIndex, + cfg.txDmaStream, &cfg.txDmaIrqNumber); + spi::configureDmaHandle(rxHandle, spi::SpiBus::SPI_1, dma::DMAType::RX, cfg.rxDmaIndex, + cfg.rxDmaStream, &cfg.rxDmaIrqNumber, DMA_NORMAL, DMA_PRIORITY_HIGH); + cfg.txPreEmptPriority = txIrqPrio; + cfg.rxPreEmptPriority = txSubprio; + cfg.txSubpriority = rxIrqPrio; + cfg.rxSubpriority = rxSubprio; + standardInterruptCfg(cfg, spiIrqPrio, spiSubprio); +} diff --git a/hal/src/fsfw_hal/stm32h7/spi/stm32h743zi.h b/hal/src/fsfw_hal/stm32h7/spi/stm32h743zi.h new file mode 100644 index 00000000..daa95554 --- /dev/null +++ b/hal/src/fsfw_hal/stm32h7/spi/stm32h743zi.h @@ -0,0 +1,22 @@ +#ifndef FSFW_HAL_STM32H7_SPI_STM32H743ZISPI_H_ +#define FSFW_HAL_STM32H7_SPI_STM32H743ZISPI_H_ + +#include "mspInit.h" + +namespace stm32h7 { + +namespace h743zi { + +void standardPollingCfg(spi::MspPollingConfigStruct& cfg); +void standardInterruptCfg(spi::MspIrqConfigStruct& cfg, IrqPriorities spiIrqPrio, + IrqPriorities spiSubprio = HIGHEST); +void standardDmaCfg(spi::MspDmaConfigStruct& cfg, IrqPriorities spiIrqPrio, + IrqPriorities txIrqPrio, IrqPriorities rxIrqPrio, + IrqPriorities spiSubprio = HIGHEST, IrqPriorities txSubPrio = HIGHEST, + IrqPriorities rxSubprio = HIGHEST); + + +} +} + +#endif /* FSFW_HAL_STM32H7_SPI_STM32H743ZISPI_H_ */ diff --git a/hal/src/fsfw_hal/stm32h7/uart/CMakeLists.txt b/hal/src/fsfw_hal/stm32h7/uart/CMakeLists.txt new file mode 100644 index 00000000..5ecb0990 --- /dev/null +++ b/hal/src/fsfw_hal/stm32h7/uart/CMakeLists.txt @@ -0,0 +1,2 @@ +target_sources(${LIB_FSFW_NAME} PRIVATE +) diff --git a/memory/CMakeLists.txt b/memory/CMakeLists.txt deleted file mode 100644 index 9edb9031..00000000 --- a/memory/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -target_sources(${LIB_FSFW_NAME} - PRIVATE - MemoryHelper.cpp - MemoryMessage.cpp -) \ No newline at end of file diff --git a/defaultcfg/README.md b/misc/defaultcfg/README.md similarity index 100% rename from defaultcfg/README.md rename to misc/defaultcfg/README.md diff --git a/misc/defaultcfg/fsfwconfig/CMakeLists.txt b/misc/defaultcfg/fsfwconfig/CMakeLists.txt new file mode 100644 index 00000000..3b2064ba --- /dev/null +++ b/misc/defaultcfg/fsfwconfig/CMakeLists.txt @@ -0,0 +1,49 @@ +if(DEFINED TARGET_NAME) + target_include_directories(${TARGET_NAME} PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ) + + target_sources(${TARGET_NAME} PRIVATE + ipc/missionMessageTypes.cpp + pollingsequence/PollingSequenceFactory.cpp + objects/FsfwFactory.cpp + ) + + # If a special translation file for object IDs exists, compile it. + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/objects/translateObjects.cpp") + target_sources(${TARGET_NAME} PRIVATE + objects/translateObjects.cpp + ) + endif() + + # If a special translation file for events exists, compile it. + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/objects/translateObjects.cpp") + target_sources(${TARGET_NAME} PRIVATE + events/translateEvents.cpp + ) + endif() +else() + target_include_directories(${LIB_FSFW_NAME} PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ) + + target_sources(${LIB_FSFW_NAME} PRIVATE + ipc/missionMessageTypes.cpp + pollingsequence/PollingSequenceFactory.cpp + objects/FsfwFactory.cpp + ) + + # If a special translation file for object IDs exists, compile it. + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/objects/translateObjects.cpp") + target_sources(${LIB_FSFW_NAME} PRIVATE + objects/translateObjects.cpp + ) + endif() + + # If a special translation file for events exists, compile it. + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/objects/translateObjects.cpp") + target_sources(${LIB_FSFW_NAME} PRIVATE + events/translateEvents.cpp + ) + endif() +endif() diff --git a/defaultcfg/fsfwconfig/FSFWConfig.h b/misc/defaultcfg/fsfwconfig/FSFWConfig.h similarity index 76% rename from defaultcfg/fsfwconfig/FSFWConfig.h rename to misc/defaultcfg/fsfwconfig/FSFWConfig.h index fe18a2f4..adf9912f 100644 --- a/defaultcfg/fsfwconfig/FSFWConfig.h +++ b/misc/defaultcfg/fsfwconfig/FSFWConfig.h @@ -7,27 +7,30 @@ //! Used to determine whether C++ ostreams are used which can increase //! the binary size significantly. If this is disabled, //! the C stdio functions can be used alternatively -#define FSFW_CPP_OSTREAM_ENABLED 1 +#define FSFW_CPP_OSTREAM_ENABLED 1 //! More FSFW related printouts depending on level. Useful for development. -#define FSFW_VERBOSE_LEVEL 1 +#define FSFW_VERBOSE_LEVEL 1 //! Can be used to completely disable printouts, even the C stdio ones. #if FSFW_CPP_OSTREAM_ENABLED == 0 && FSFW_VERBOSE_LEVEL == 0 - #define FSFW_DISABLE_PRINTOUT 0 + #define FSFW_DISABLE_PRINTOUT 0 #endif +#define FSFW_USE_PUS_C_TELEMETRY 1 +#define FSFW_USE_PUS_C_TELECOMMANDS 1 + //! Can be used to disable the ANSI color sequences for C stdio. -#define FSFW_COLORED_OUTPUT 1 +#define FSFW_COLORED_OUTPUT 1 //! If FSFW_OBJ_EVENT_TRANSLATION is set to one, //! additional output which requires the translation files translateObjects //! and translateEvents (and their compiled source files) -#define FSFW_OBJ_EVENT_TRANSLATION 0 +#define FSFW_OBJ_EVENT_TRANSLATION 0 #if FSFW_OBJ_EVENT_TRANSLATION == 1 //! Specify whether info events are printed too. -#define FSFW_DEBUG_INFO 1 +#define FSFW_DEBUG_INFO 1 #include "objects/translateObjects.h" #include "events/translateEvents.h" #else @@ -35,22 +38,22 @@ //! When using the newlib nano library, C99 support for stdio facilities //! will not be provided. This define should be set to 1 if this is the case. -#define FSFW_NO_C99_IO 1 +#define FSFW_NO_C99_IO 1 //! Specify whether a special mode store is used for Subsystem components. -#define FSFW_USE_MODESTORE 0 +#define FSFW_USE_MODESTORE 0 //! Defines if the real time scheduler for linux should be used. //! If set to 0, this will also disable priority settings for linux //! as most systems will not allow to set nice values without privileges //! For embedded linux system set this to 1. //! If set to 1 the binary needs "cap_sys_nice=eip" privileges to run -#define FSFW_USE_REALTIME_FOR_LINUX 1 +#define FSFW_USE_REALTIME_FOR_LINUX 1 namespace fsfwconfig { -//! Default timestamp size. The default timestamp will be an eight byte CDC -//! short timestamp. -static constexpr uint8_t FSFW_MISSION_TIMESTAMP_SIZE = 8; + +//! Default timestamp size. The default timestamp will be an seven byte CDC short timestamp. +static constexpr uint8_t FSFW_MISSION_TIMESTAMP_SIZE = 7; //! Configure the allocated pool sizes for the event manager. static constexpr size_t FSFW_EVENTMGMR_MATCHTREE_NODES = 240; @@ -65,6 +68,8 @@ static constexpr uint8_t FSFW_CSB_FIFO_DEPTH = 6; static constexpr size_t FSFW_PRINT_BUFFER_SIZE = 124; +static constexpr size_t FSFW_MAX_TM_PACKET_SIZE = 2048; + } #endif /* CONFIG_FSFWCONFIG_H_ */ diff --git a/defaultcfg/fsfwconfig/OBSWConfig.h b/misc/defaultcfg/fsfwconfig/OBSWConfig.h similarity index 100% rename from defaultcfg/fsfwconfig/OBSWConfig.h rename to misc/defaultcfg/fsfwconfig/OBSWConfig.h diff --git a/defaultcfg/fsfwconfig/OBSWVersion.h b/misc/defaultcfg/fsfwconfig/OBSWVersion.h similarity index 100% rename from defaultcfg/fsfwconfig/OBSWVersion.h rename to misc/defaultcfg/fsfwconfig/OBSWVersion.h diff --git a/defaultcfg/fsfwconfig/devices/logicalAddresses.h b/misc/defaultcfg/fsfwconfig/devices/logicalAddresses.h similarity index 100% rename from defaultcfg/fsfwconfig/devices/logicalAddresses.h rename to misc/defaultcfg/fsfwconfig/devices/logicalAddresses.h diff --git a/defaultcfg/fsfwconfig/devices/powerSwitcherList.h b/misc/defaultcfg/fsfwconfig/devices/powerSwitcherList.h similarity index 100% rename from defaultcfg/fsfwconfig/devices/powerSwitcherList.h rename to misc/defaultcfg/fsfwconfig/devices/powerSwitcherList.h diff --git a/defaultcfg/fsfwconfig/events/subsystemIdRanges.h b/misc/defaultcfg/fsfwconfig/events/subsystemIdRanges.h similarity index 100% rename from defaultcfg/fsfwconfig/events/subsystemIdRanges.h rename to misc/defaultcfg/fsfwconfig/events/subsystemIdRanges.h diff --git a/defaultcfg/fsfwconfig/ipc/missionMessageTypes.cpp b/misc/defaultcfg/fsfwconfig/ipc/missionMessageTypes.cpp similarity index 100% rename from defaultcfg/fsfwconfig/ipc/missionMessageTypes.cpp rename to misc/defaultcfg/fsfwconfig/ipc/missionMessageTypes.cpp diff --git a/defaultcfg/fsfwconfig/ipc/missionMessageTypes.h b/misc/defaultcfg/fsfwconfig/ipc/missionMessageTypes.h similarity index 100% rename from defaultcfg/fsfwconfig/ipc/missionMessageTypes.h rename to misc/defaultcfg/fsfwconfig/ipc/missionMessageTypes.h diff --git a/defaultcfg/fsfwconfig/objects/FsfwFactory.cpp b/misc/defaultcfg/fsfwconfig/objects/FsfwFactory.cpp similarity index 91% rename from defaultcfg/fsfwconfig/objects/FsfwFactory.cpp rename to misc/defaultcfg/fsfwconfig/objects/FsfwFactory.cpp index 428adf1d..5aef4980 100644 --- a/defaultcfg/fsfwconfig/objects/FsfwFactory.cpp +++ b/misc/defaultcfg/fsfwconfig/objects/FsfwFactory.cpp @@ -4,10 +4,10 @@ #include #include #include -#include +#include #include #include -#include +#include #include @@ -48,6 +48,6 @@ void Factory::setStaticFrameworkObjectIds() { DeviceHandlerFailureIsolation::powerConfirmationId = objects::NO_OBJECT; - TmPacketStored::timeStamperId = objects::NO_OBJECT; + TmPacketBase::timeStamperId = objects::NO_OBJECT; } diff --git a/defaultcfg/fsfwconfig/objects/FsfwFactory.h b/misc/defaultcfg/fsfwconfig/objects/FsfwFactory.h similarity index 100% rename from defaultcfg/fsfwconfig/objects/FsfwFactory.h rename to misc/defaultcfg/fsfwconfig/objects/FsfwFactory.h diff --git a/defaultcfg/fsfwconfig/objects/systemObjectList.h b/misc/defaultcfg/fsfwconfig/objects/systemObjectList.h similarity index 100% rename from defaultcfg/fsfwconfig/objects/systemObjectList.h rename to misc/defaultcfg/fsfwconfig/objects/systemObjectList.h diff --git a/defaultcfg/fsfwconfig/pollingsequence/PollingSequenceFactory.cpp b/misc/defaultcfg/fsfwconfig/pollingsequence/PollingSequenceFactory.cpp similarity index 100% rename from defaultcfg/fsfwconfig/pollingsequence/PollingSequenceFactory.cpp rename to misc/defaultcfg/fsfwconfig/pollingsequence/PollingSequenceFactory.cpp diff --git a/defaultcfg/fsfwconfig/pollingsequence/PollingSequenceFactory.h b/misc/defaultcfg/fsfwconfig/pollingsequence/PollingSequenceFactory.h similarity index 100% rename from defaultcfg/fsfwconfig/pollingsequence/PollingSequenceFactory.h rename to misc/defaultcfg/fsfwconfig/pollingsequence/PollingSequenceFactory.h diff --git a/defaultcfg/fsfwconfig/returnvalues/classIds.h b/misc/defaultcfg/fsfwconfig/returnvalues/classIds.h similarity index 100% rename from defaultcfg/fsfwconfig/returnvalues/classIds.h rename to misc/defaultcfg/fsfwconfig/returnvalues/classIds.h diff --git a/defaultcfg/fsfwconfig/tmtc/apid.h b/misc/defaultcfg/fsfwconfig/tmtc/apid.h similarity index 100% rename from defaultcfg/fsfwconfig/tmtc/apid.h rename to misc/defaultcfg/fsfwconfig/tmtc/apid.h diff --git a/defaultcfg/fsfwconfig/tmtc/pusIds.h b/misc/defaultcfg/fsfwconfig/tmtc/pusIds.h similarity index 100% rename from defaultcfg/fsfwconfig/tmtc/pusIds.h rename to misc/defaultcfg/fsfwconfig/tmtc/pusIds.h diff --git a/logo/FSFW_Logo_V3.png b/misc/logo/FSFW_Logo_V3.png similarity index 100% rename from logo/FSFW_Logo_V3.png rename to misc/logo/FSFW_Logo_V3.png diff --git a/logo/FSFW_Logo_V3.svg b/misc/logo/FSFW_Logo_V3.svg similarity index 100% rename from logo/FSFW_Logo_V3.svg rename to misc/logo/FSFW_Logo_V3.svg diff --git a/logo/FSFW_Logo_V3_bw.png b/misc/logo/FSFW_Logo_V3_bw.png similarity index 100% rename from logo/FSFW_Logo_V3_bw.png rename to misc/logo/FSFW_Logo_V3_bw.png diff --git a/objectmanager/ObjectManager.h b/objectmanager/ObjectManager.h deleted file mode 100644 index 69a74f73..00000000 --- a/objectmanager/ObjectManager.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef FSFW_OBJECTMANAGER_OBJECTMANAGER_H_ -#define FSFW_OBJECTMANAGER_OBJECTMANAGER_H_ - -#include "ObjectManagerIF.h" -#include "SystemObjectIF.h" -#include - -/** - * @brief This class implements a global object manager. - * @details This manager handles a list of available objects with system-wide - * relevance, such as device handlers, and TM/TC services. Objects can - * be inserted, removed and retrieved from the list. In addition, the - * class holds a so-called factory, that creates and inserts new - * objects if they are not already in the list. This feature automates - * most of the system initialization. - * As the system is static after initialization, no new objects are - * created or inserted into the list after startup. - * @ingroup system_objects - * @author Bastian Baetz - */ -class ObjectManager : public ObjectManagerIF { -private: - //comparison? - /** - * @brief This is the map of all initialized objects in the manager. - * @details Objects in the List must inherit the SystemObjectIF. - */ - std::map objectList; -protected: - SystemObjectIF* getSystemObject( object_id_t id ); - /** - * @brief This attribute is initialized with the factory function - * that creates new objects. - * @details The function is called if an object was requested with - * getSystemObject, but not found in objectList. - * @param The id of the object to be created. - * @return Returns a pointer to the newly created object or NULL. - */ - void (*produceObjects)(); -public: - /** - * @brief Apart from setting the producer function, nothing special - * happens in the constructor. - * @param setProducer A pointer to a factory function. - */ - ObjectManager( void (*produce)() ); - ObjectManager(); - /** - * @brief In the class's destructor, all objects in the list are deleted. - */ - // SHOULDDO: If, for some reason, deleting an ObjectManager instance is - // required, check if this works. - virtual ~ObjectManager( void ); - ReturnValue_t insert( object_id_t id, SystemObjectIF* object ); - ReturnValue_t remove( object_id_t id ); - void initialize(); - void printList(); -}; - - - -#endif /* FSFW_OBJECTMANAGER_OBJECTMANAGER_H_ */ diff --git a/osal/FreeRTOS/MessageQueue.cpp b/osal/FreeRTOS/MessageQueue.cpp deleted file mode 100644 index 3a0f654e..00000000 --- a/osal/FreeRTOS/MessageQueue.cpp +++ /dev/null @@ -1,164 +0,0 @@ -#include "MessageQueue.h" -#include "../../objectmanager/ObjectManagerIF.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" - -// TODO I guess we should have a way of checking if we are in an ISR and then -// use the "fromISR" versions of all calls -// As a first step towards this, introduces system context variable which needs -// to be switched manually -// Haven't found function to find system context. -MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize): - maxMessageSize(maxMessageSize) { - handle = xQueueCreate(messageDepth, maxMessageSize); -#if FSFW_CPP_OSTREAM_ENABLED == 1 - if (handle == nullptr) { - sif::error << "MessageQueue::MessageQueue:" - << " Creation failed." << std::endl; - sif::error << "Specified Message Depth: " << messageDepth - << std::endl; - sif::error << "Specified Maximum Message Size: " - << maxMessageSize << std::endl; - - } -#endif -} - -MessageQueue::~MessageQueue() { - if (handle != nullptr) { - vQueueDelete(handle); - } -} - -void MessageQueue::switchSystemContext(CallContext callContext) { - this->callContext = callContext; -} - -ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo, - MessageQueueMessageIF* message, bool ignoreFault) { - return sendMessageFrom(sendTo, message, this->getId(), ignoreFault); -} - -ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessageIF* message) { - return sendToDefaultFrom(message, this->getId()); -} - -ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessageIF* message, - MessageQueueId_t sentFrom, bool ignoreFault) { - return sendMessageFrom(defaultDestination,message,sentFrom,ignoreFault); -} - -ReturnValue_t MessageQueue::reply(MessageQueueMessageIF* message) { - if (this->lastPartner != MessageQueueIF::NO_QUEUE) { - return sendMessageFrom(this->lastPartner, message, this->getId()); - } else { - return NO_REPLY_PARTNER; - } -} - -ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, - MessageQueueMessageIF* message, MessageQueueId_t sentFrom, - bool ignoreFault) { - return sendMessageFromMessageQueue(sendTo, message, sentFrom, ignoreFault, - callContext); -} - - -ReturnValue_t MessageQueue::handleSendResult(BaseType_t result, bool ignoreFault) { - if (result != pdPASS) { - if (not ignoreFault) { - InternalErrorReporterIF* internalErrorReporter = objectManager-> - get( - objects::INTERNAL_ERROR_REPORTER); - if (internalErrorReporter != nullptr) { - internalErrorReporter->queueMessageNotSent(); - } - } - return MessageQueueIF::FULL; - } - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message, - MessageQueueId_t* receivedFrom) { - ReturnValue_t status = this->receiveMessage(message); - if(status == HasReturnvaluesIF::RETURN_OK) { - *receivedFrom = this->lastPartner; - } - return status; -} - -ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) { - BaseType_t result = xQueueReceive(handle,reinterpret_cast( - message->getBuffer()), 0); - if (result == pdPASS){ - this->lastPartner = message->getSender(); - return HasReturnvaluesIF::RETURN_OK; - } else { - return MessageQueueIF::EMPTY; - } -} - -MessageQueueId_t MessageQueue::getLastPartner() const { - return lastPartner; -} - -ReturnValue_t MessageQueue::flush(uint32_t* count) { - //TODO FreeRTOS does not support flushing partially - //Is always successful - xQueueReset(handle); - return HasReturnvaluesIF::RETURN_OK; -} - -MessageQueueId_t MessageQueue::getId() const { - return reinterpret_cast(handle); -} - -void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) { - defaultDestinationSet = true; - this->defaultDestination = defaultDestination; -} - -MessageQueueId_t MessageQueue::getDefaultDestination() const { - return defaultDestination; -} - -bool MessageQueue::isDefaultDestinationSet() const { - return defaultDestinationSet; -} - - -// static core function to send messages. -ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, - MessageQueueMessageIF* message, MessageQueueId_t sentFrom, - bool ignoreFault, CallContext callContext) { - BaseType_t result = pdFALSE; - QueueHandle_t destination = nullptr; - - if(sendTo == MessageQueueIF::NO_QUEUE or sendTo == 0x00) { - return MessageQueueIF::DESTINATION_INVALID; - } - else { - destination = reinterpret_cast(sendTo); - } - - message->setSender(sentFrom); - - - if(callContext == CallContext::TASK) { - result = xQueueSendToBack(destination, - static_cast(message->getBuffer()), 0); - } - else { - /* If the call context is from an interrupt, - * request a context switch if a higher priority task - * was blocked by the interrupt. */ - BaseType_t xHigherPriorityTaskWoken = pdFALSE; - result = xQueueSendFromISR(reinterpret_cast(sendTo), - static_cast(message->getBuffer()), - &xHigherPriorityTaskWoken); - if(xHigherPriorityTaskWoken == pdTRUE) { - TaskManagement::requestContextSwitch(callContext); - } - } - return handleSendResult(result, ignoreFault); -} diff --git a/osal/FreeRTOS/MessageQueue.h b/osal/FreeRTOS/MessageQueue.h deleted file mode 100644 index 8fa86283..00000000 --- a/osal/FreeRTOS/MessageQueue.h +++ /dev/null @@ -1,151 +0,0 @@ -#ifndef FSFW_OSAL_FREERTOS_MESSAGEQUEUE_H_ -#define FSFW_OSAL_FREERTOS_MESSAGEQUEUE_H_ - -#include "TaskManagement.h" - -#include "../../internalError/InternalErrorReporterIF.h" -#include "../../ipc/MessageQueueIF.h" -#include "../../ipc/MessageQueueMessageIF.h" - -#include -#include -#include - -// TODO: this class assumes that MessageQueueId_t is the same size as void* -// (the FreeRTOS handle type), compiler will catch this but it might be nice -// to have something checking or even an always working solution -// https://scaryreasoner.wordpress.com/2009/02/28/checking-sizeof-at-compile-time/ - -/** - * @brief This class manages sending and receiving of - * message queue messages. - * @details - * Message queues are used to pass asynchronous messages between processes. - * They work like post boxes, where all incoming messages are stored in FIFO - * order. This class creates a new receiving queue and provides methods to fetch - * received messages. Being a child of MessageQueueSender, this class also - * provides methods to send a message to a user-defined or a default destination. - * In addition it also provides a reply method to answer to the queue it - * received its last message from. - * - * The MessageQueue should be used as "post box" for a single owning object. - * So all message queue communication is "n-to-one". - * For creating the queue, as well as sending and receiving messages, the class - * makes use of the operating system calls provided. - * - * Please keep in mind that FreeRTOS offers different calls for message queue - * operations if called from an ISR. - * For now, the system context needs to be switched manually. - * @ingroup osal - * @ingroup message_queue - */ -class MessageQueue : public MessageQueueIF { - friend class MessageQueueSenderIF; -public: - /** - * @brief The constructor initializes and configures the message queue. - * @details - * By making use of the according operating system call, a message queue - * is created and initialized. The message depth - the maximum number of - * messages to be buffered - may be set with the help of a parameter, - * whereas the message size is automatically set to the maximum message - * queue message size. The operating system sets the message queue id, or - * in case of failure, it is set to zero. - * @param message_depth - * The number of messages to be buffered before passing an error to the - * sender. Default is three. - * @param max_message_size - * With this parameter, the maximum message size can be adjusted. - * This should be left default. - */ - MessageQueue( size_t messageDepth = 3, - size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE ); - - /** Copying message queues forbidden */ - MessageQueue(const MessageQueue&) = delete; - MessageQueue& operator=(const MessageQueue&) = delete; - - /** - * @brief The destructor deletes the formerly created message queue. - * @details This is accomplished by using the delete call provided - * by the operating system. - */ - virtual ~MessageQueue(); - - /** - * This function is used to switch the call context. This has to be called - * if a message is sent or received from an ISR! - * @param callContext - */ - void switchSystemContext(CallContext callContext); - - /** MessageQueueIF implementation */ - ReturnValue_t sendMessage(MessageQueueId_t sendTo, - MessageQueueMessageIF* message, bool ignoreFault = false) override; - - ReturnValue_t sendToDefault(MessageQueueMessageIF* message) override; - - ReturnValue_t reply(MessageQueueMessageIF* message) override; - virtual ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, - MessageQueueMessageIF* message, - MessageQueueId_t sentFrom = NO_QUEUE, - bool ignoreFault = false) override; - - virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessageIF* message, - MessageQueueId_t sentFrom = NO_QUEUE, - bool ignoreFault = false) override; - - ReturnValue_t receiveMessage(MessageQueueMessageIF* message, - MessageQueueId_t *receivedFrom) override; - - ReturnValue_t receiveMessage(MessageQueueMessageIF* message) override; - - ReturnValue_t flush(uint32_t* count) override; - - MessageQueueId_t getLastPartner() const override; - - MessageQueueId_t getId() const override; - - void setDefaultDestination(MessageQueueId_t defaultDestination) override; - - MessageQueueId_t getDefaultDestination() const override; - - bool isDefaultDestinationSet() const override; - -protected: - /** - * @brief Implementation to be called from any send Call within - * MessageQueue and MessageQueueSenderIF. - * @details - * This method takes the message provided, adds the sentFrom information and - * passes it on to the destination provided with an operating system call. - * The OS's return value is returned. - * @param sendTo - * This parameter specifies the message queue id to send the message to. - * @param message - * This is a pointer to a previously created message, which is sent. - * @param sentFrom - * The sentFrom information can be set to inject the sender's queue id into - * the message. This variable is set to zero by default. - * @param ignoreFault - * If set to true, the internal software fault counter is not incremented - * if queue is full. - * @param context Specify whether call is made from task or from an ISR. - */ - static ReturnValue_t sendMessageFromMessageQueue(MessageQueueId_t sendTo, - MessageQueueMessageIF* message, MessageQueueId_t sentFrom = NO_QUEUE, - bool ignoreFault=false, CallContext callContext = CallContext::TASK); - - static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault); - -private: - bool defaultDestinationSet = false; - QueueHandle_t handle; - MessageQueueId_t defaultDestination = MessageQueueIF::NO_QUEUE; - MessageQueueId_t lastPartner = MessageQueueIF::NO_QUEUE; - const size_t maxMessageSize; - //! Stores the current system context - CallContext callContext = CallContext::TASK; -}; - -#endif /* FSFW_OSAL_FREERTOS_MESSAGEQUEUE_H_ */ diff --git a/osal/InternalErrorCodes.h b/osal/InternalErrorCodes.h deleted file mode 100644 index 1da116fa..00000000 --- a/osal/InternalErrorCodes.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef INTERNALERRORCODES_H_ -#define INTERNALERRORCODES_H_ - -#include "../returnvalues/HasReturnvaluesIF.h" - -class InternalErrorCodes { -public: - static const uint8_t INTERFACE_ID = CLASS_ID::INTERNAL_ERROR_CODES; - -static const ReturnValue_t NO_CONFIGURATION_TABLE = MAKE_RETURN_CODE(0x01 ); -static const ReturnValue_t NO_CPU_TABLE = MAKE_RETURN_CODE(0x02 ); -static const ReturnValue_t INVALID_WORKSPACE_ADDRESS = MAKE_RETURN_CODE(0x03 ); -static const ReturnValue_t TOO_LITTLE_WORKSPACE = MAKE_RETURN_CODE(0x04 ); -static const ReturnValue_t WORKSPACE_ALLOCATION = MAKE_RETURN_CODE(0x05 ); -static const ReturnValue_t INTERRUPT_STACK_TOO_SMALL = MAKE_RETURN_CODE(0x06 ); -static const ReturnValue_t THREAD_EXITTED = MAKE_RETURN_CODE(0x07 ); -static const ReturnValue_t INCONSISTENT_MP_INFORMATION = MAKE_RETURN_CODE(0x08 ); -static const ReturnValue_t INVALID_NODE = MAKE_RETURN_CODE(0x09 ); -static const ReturnValue_t NO_MPCI = MAKE_RETURN_CODE(0x0a ); -static const ReturnValue_t BAD_PACKET = MAKE_RETURN_CODE(0x0b ); -static const ReturnValue_t OUT_OF_PACKETS = MAKE_RETURN_CODE(0x0c ); -static const ReturnValue_t OUT_OF_GLOBAL_OBJECTS = MAKE_RETURN_CODE(0x0d ); -static const ReturnValue_t OUT_OF_PROXIES = MAKE_RETURN_CODE(0x0e ); -static const ReturnValue_t INVALID_GLOBAL_ID = MAKE_RETURN_CODE(0x0f ); -static const ReturnValue_t BAD_STACK_HOOK = MAKE_RETURN_CODE(0x10 ); -static const ReturnValue_t BAD_ATTRIBUTES = MAKE_RETURN_CODE(0x11 ); -static const ReturnValue_t IMPLEMENTATION_KEY_CREATE_INCONSISTENCY = MAKE_RETURN_CODE(0x12 ); -static const ReturnValue_t IMPLEMENTATION_BLOCKING_OPERATION_CANCEL = MAKE_RETURN_CODE(0x13 ); -static const ReturnValue_t MUTEX_OBTAIN_FROM_BAD_STATE = MAKE_RETURN_CODE(0x14 ); -static const ReturnValue_t UNLIMITED_AND_MAXIMUM_IS_0 = MAKE_RETURN_CODE(0x15 ); - - virtual ~InternalErrorCodes(); - - static ReturnValue_t translate(uint8_t code); -private: - InternalErrorCodes(); -}; - -#endif /* INTERNALERRORCODES_H_ */ diff --git a/osal/common/TcpTmTcServer.cpp b/osal/common/TcpTmTcServer.cpp deleted file mode 100644 index 08a62ffb..00000000 --- a/osal/common/TcpTmTcServer.cpp +++ /dev/null @@ -1,132 +0,0 @@ -#include "TcpTmTcServer.h" -#include "tcpipHelpers.h" -#include "../../serviceinterface/ServiceInterface.h" - -#ifdef _WIN32 -#include -#include - -#elif defined(__unix__) - -#include - -#endif - -const std::string TcpTmTcServer::DEFAULT_TCP_SERVER_PORT = "7301"; -const std::string TcpTmTcServer::DEFAULT_TCP_CLIENT_PORT = "7302"; - -TcpTmTcServer::TcpTmTcServer(object_id_t objectId, object_id_t tmtcUnixUdpBridge, - std::string customTcpServerPort): - SystemObject(objectId), tcpPort(customTcpServerPort) { - if(tcpPort == "") { - tcpPort = DEFAULT_TCP_SERVER_PORT; - } -} - -ReturnValue_t TcpTmTcServer::initialize() { - using namespace tcpip; - - ReturnValue_t result = TcpIpBase::initialize(); - if(result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - int retval = 0; - struct addrinfo *addrResult = nullptr; - struct addrinfo hints = {}; - - hints.ai_family = AF_INET; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - hints.ai_flags = AI_PASSIVE; - - retval = getaddrinfo(nullptr, tcpPort.c_str(), &hints, &addrResult); - if (retval != 0) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "TcWinTcpServer::TcpTmTcServer: Retrieving address info failed!" << - std::endl; -#endif - handleError(Protocol::TCP, ErrorSources::GETADDRINFO_CALL); - return HasReturnvaluesIF::RETURN_FAILED; - } - - /* Open TCP (stream) socket */ - listenerTcpSocket = socket(addrResult->ai_family, addrResult->ai_socktype, - addrResult->ai_protocol); - if(listenerTcpSocket == INVALID_SOCKET) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "TcWinTcpServer::TcWinTcpServer: Socket creation failed!" << std::endl; -#endif - freeaddrinfo(addrResult); - handleError(Protocol::TCP, ErrorSources::SOCKET_CALL); - return HasReturnvaluesIF::RETURN_FAILED; - } - - retval = bind(listenerTcpSocket, addrResult->ai_addr, static_cast(addrResult->ai_addrlen)); - if(retval == SOCKET_ERROR) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "TcWinTcpServer::TcpTmTcServer: Binding socket failed!" << - std::endl; -#endif - freeaddrinfo(addrResult); - handleError(Protocol::TCP, ErrorSources::BIND_CALL); - return HasReturnvaluesIF::RETURN_FAILED; - } - - freeaddrinfo(addrResult); - return HasReturnvaluesIF::RETURN_OK; -} - - -TcpTmTcServer::~TcpTmTcServer() { - closeSocket(listenerTcpSocket); -} - -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 clientSocket = 0; - sockaddr clientSockAddr = {}; - socklen_t connectorSockAddrLen = 0; - int retval = 0; - - /* Listen for connection requests permanently for lifetime of program */ - while(true) { - retval = listen(listenerTcpSocket, currentBacklog); - if(retval == SOCKET_ERROR) { - handleError(Protocol::TCP, ErrorSources::LISTEN_CALL, 500); - continue; - } - - clientSocket = accept(listenerTcpSocket, &clientSockAddr, &connectorSockAddrLen); - - if(clientSocket == INVALID_SOCKET) { - handleError(Protocol::TCP, ErrorSources::ACCEPT_CALL, 500); - closeSocket(clientSocket); - continue; - }; - - retval = recv(clientSocket, reinterpret_cast(receptionBuffer.data()), - receptionBuffer.size(), 0); - if(retval > 0) { -#if FSFW_TCP_RCV_WIRETAPPING_ENABLED == 1 - sif::info << "TcpTmTcServer::performOperation: Received " << retval << " bytes." - std::endl; -#endif - handleError(Protocol::TCP, ErrorSources::RECV_CALL, 500); - } - else if(retval == 0) { - - } - else { - - } - - /* Done, shut down connection */ - retval = shutdown(clientSocket, SHUT_SEND); - closeSocket(clientSocket); - } - return HasReturnvaluesIF::RETURN_OK; -} - - diff --git a/osal/common/TcpTmTcServer.h b/osal/common/TcpTmTcServer.h deleted file mode 100644 index 4dcc77a2..00000000 --- a/osal/common/TcpTmTcServer.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef FSFW_OSAL_WINDOWS_TCWINTCPSERVER_H_ -#define FSFW_OSAL_WINDOWS_TCWINTCPSERVER_H_ - -#include "TcpIpBase.h" -#include "../../objectmanager/SystemObject.h" -#include "../../tasks/ExecutableObjectIF.h" - -#ifdef __unix__ -#include -#endif - -#include -#include - -//! Debugging preprocessor define. -#define FSFW_TCP_RCV_WIRETAPPING_ENABLED 0 - -/** - * @brief Windows TCP server used to receive telecommands on a Windows Host - * @details - * Based on: https://docs.microsoft.com/en-us/windows/win32/winsock/complete-server-code - */ -class TcpTmTcServer: - public SystemObject, - public TcpIpBase, - public ExecutableObjectIF { -public: - /* The ports chosen here should not be used by any other process. */ - static const std::string DEFAULT_TCP_SERVER_PORT; - static const std::string DEFAULT_TCP_CLIENT_PORT; - - TcpTmTcServer(object_id_t objectId, object_id_t tmtcUnixUdpBridge, - std::string customTcpServerPort = ""); - virtual~ TcpTmTcServer(); - - ReturnValue_t initialize() override; - ReturnValue_t performOperation(uint8_t opCode) override; - -private: - - std::string tcpPort; - socket_t listenerTcpSocket = 0; - struct sockaddr tcpAddress; - int tcpAddrLen = sizeof(tcpAddress); - int currentBacklog = 3; - - std::vector receptionBuffer; - int tcpSockOpt = 0; - - -}; - -#endif /* FSFW_OSAL_WINDOWS_TCWINTCPSERVER_H_ */ diff --git a/osal/host/QueueMapManager.cpp b/osal/host/QueueMapManager.cpp deleted file mode 100644 index c9100fe9..00000000 --- a/osal/host/QueueMapManager.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include "QueueMapManager.h" - -#include "../../serviceinterface/ServiceInterface.h" -#include "../../ipc/MutexFactory.h" -#include "../../ipc/MutexGuard.h" - -QueueMapManager* QueueMapManager::mqManagerInstance = nullptr; - -QueueMapManager::QueueMapManager() { - mapLock = MutexFactory::instance()->createMutex(); -} - -QueueMapManager::~QueueMapManager() { - MutexFactory::instance()->deleteMutex(mapLock); -} - -QueueMapManager* QueueMapManager::instance() { - if (mqManagerInstance == nullptr){ - mqManagerInstance = new QueueMapManager(); - } - return QueueMapManager::mqManagerInstance; -} - -ReturnValue_t QueueMapManager::addMessageQueue( - MessageQueueIF* queueToInsert, MessageQueueId_t* id) { - /* Not thread-safe, but it is assumed all message queues are created at software initialization - now. If this is to be made thread-safe in the future, it propably would be sufficient to lock - the increment operation here. */ - uint32_t currentId = queueCounter++; - auto returnPair = queueMap.emplace(currentId, queueToInsert); - if(not returnPair.second) { - /* This should never happen for the atomic variable. */ -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "QueueMapManager::addMessageQueue This ID is already " - "inside the map!" << std::endl; -#else - sif::printError("QueueMapManager::addMessageQueue This ID is already " - "inside the map!\n"); -#endif - return HasReturnvaluesIF::RETURN_FAILED; - } - if (id != nullptr) { - *id = currentId; - } - return HasReturnvaluesIF::RETURN_OK; -} - -MessageQueueIF* QueueMapManager::getMessageQueue( - MessageQueueId_t messageQueueId) const { - MutexGuard(mapLock, MutexIF::TimeoutType::WAITING, 50); - auto queueIter = queueMap.find(messageQueueId); - if(queueIter != queueMap.end()) { - return queueIter->second; - } - else { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "QueueMapManager::getQueueHandle: The ID " << messageQueueId << - " does not exists in the map!" << std::endl; -#else - sif::printWarning("QueueMapManager::getQueueHandle: The ID %d does not exist in the map!\n", - messageQueueId); -#endif - return nullptr; - } -} - diff --git a/osal/host/QueueMapManager.h b/osal/host/QueueMapManager.h deleted file mode 100644 index 90c39c2f..00000000 --- a/osal/host/QueueMapManager.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef FSFW_OSAL_HOST_QUEUEMAPMANAGER_H_ -#define FSFW_OSAL_HOST_QUEUEMAPMANAGER_H_ - -#include "../../ipc/MessageQueueSenderIF.h" -#include "../../osal/host/MessageQueue.h" -#include -#include - -using QueueMap = std::unordered_map; - - -/** - * An internal map to map message queue IDs to message queues. - * This propably should be a singleton.. - */ -class QueueMapManager { -public: - //! Returns the single instance of SemaphoreFactory. - static QueueMapManager* instance(); - - /** - * Insert a message queue into the map and returns a message queue ID - * @param queue The message queue to insert. - * @param id The passed value will be set unless a nullptr is passed - * @return - */ - ReturnValue_t addMessageQueue(MessageQueueIF* queue, MessageQueueId_t* - id = nullptr); - /** - * Get the message queue handle by providing a message queue ID. - * @param messageQueueId - * @return - */ - MessageQueueIF* getMessageQueue(MessageQueueId_t messageQueueId) const; - -private: - //! External instantiation is forbidden. - QueueMapManager(); - ~QueueMapManager(); - - uint32_t queueCounter = 0; - MutexIF* mapLock; - QueueMap queueMap; - static QueueMapManager* mqManagerInstance; -}; - - - -#endif /* FSFW_OSAL_HOST_QUEUEMAPMANAGER_H_ */ diff --git a/osal/linux/BinarySemaphore.cpp b/osal/linux/BinarySemaphore.cpp deleted file mode 100644 index 5716e560..00000000 --- a/osal/linux/BinarySemaphore.cpp +++ /dev/null @@ -1,161 +0,0 @@ -#include "BinarySemaphore.h" -#include "../../serviceinterface/ServiceInterfacePrinter.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" - -#include -#include -#include - - -BinarySemaphore::BinarySemaphore() { - // Using unnamed semaphores for now - initSemaphore(); -} - -BinarySemaphore::~BinarySemaphore() { - sem_destroy(&handle); -} - -BinarySemaphore::BinarySemaphore(BinarySemaphore&& s) { - initSemaphore(); -} - -BinarySemaphore& BinarySemaphore::operator =( - BinarySemaphore&& s) { - initSemaphore(); - return * this; -} - -ReturnValue_t BinarySemaphore::acquire(TimeoutType timeoutType, - uint32_t timeoutMs) { - int result = 0; - if(timeoutType == TimeoutType::POLLING) { - result = sem_trywait(&handle); - } - else if(timeoutType == TimeoutType::BLOCKING) { - result = sem_wait(&handle); - } - else if(timeoutType == TimeoutType::WAITING){ - timespec timeOut; - clock_gettime(CLOCK_REALTIME, &timeOut); - uint64_t nseconds = timeOut.tv_sec * 1000000000 + timeOut.tv_nsec; - nseconds += timeoutMs * 1000000; - timeOut.tv_sec = nseconds / 1000000000; - timeOut.tv_nsec = nseconds - timeOut.tv_sec * 1000000000; - result = sem_timedwait(&handle, &timeOut); - if(result != 0 and errno == EINVAL) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::debug << "BinarySemaphore::acquire: Invalid time value possible" - << std::endl; -#endif - } - } - if(result == 0) { - return HasReturnvaluesIF::RETURN_OK; - } - - switch(errno) { - case(EAGAIN): - // Operation could not be performed without blocking (for sem_trywait) - case(ETIMEDOUT): - // Semaphore is 0 - return SemaphoreIF::SEMAPHORE_TIMEOUT; - case(EINVAL): - // Semaphore invalid - return SemaphoreIF::SEMAPHORE_INVALID; - case(EINTR): - // Call was interrupted by signal handler -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::debug << "BinarySemaphore::acquire: Signal handler interrupted." - "Code " << strerror(errno) << std::endl; -#endif - /* No break */ - default: - return HasReturnvaluesIF::RETURN_FAILED; - } -} - -ReturnValue_t BinarySemaphore::release() { - return BinarySemaphore::release(&this->handle); -} - -ReturnValue_t BinarySemaphore::release(sem_t *handle) { - ReturnValue_t countResult = checkCount(handle, 1); - if(countResult != HasReturnvaluesIF::RETURN_OK) { - return countResult; - } - - int result = sem_post(handle); - if(result == 0) { - return HasReturnvaluesIF::RETURN_OK; - } - - switch(errno) { - case(EINVAL): - // Semaphore invalid - return SemaphoreIF::SEMAPHORE_INVALID; - case(EOVERFLOW): - // SEM_MAX_VALUE overflow. This should never happen - default: - return HasReturnvaluesIF::RETURN_FAILED; - } -} - -uint8_t BinarySemaphore::getSemaphoreCounter() const { - // And another ugly cast :-D - return getSemaphoreCounter(const_cast(&this->handle)); -} - -uint8_t BinarySemaphore::getSemaphoreCounter(sem_t *handle) { - int value = 0; - int result = sem_getvalue(handle, &value); - if (result == 0) { - return value; - } - else if(result != 0 and errno == EINVAL) { - // Could be called from interrupt, use lightweight printf - sif::printError("BinarySemaphore::getSemaphoreCounter: " - "Invalid semaphore\n"); - return 0; - } - else { - // This should never happen. - return 0; - } -} - -void BinarySemaphore::initSemaphore(uint8_t initCount) { - auto result = sem_init(&handle, true, initCount); - if(result == -1) { - switch(errno) { - case(EINVAL): - // Value exceeds SEM_VALUE_MAX - case(ENOSYS): { - // System does not support process-shared semaphores -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "BinarySemaphore: Init failed with " - << strerror(errno) << std::endl; -#else - sif::printError("BinarySemaphore: Init failed with %s\n", - strerror(errno)); -#endif - } - } - } -} - -ReturnValue_t BinarySemaphore::checkCount(sem_t* handle, uint8_t maxCount) { - int value = getSemaphoreCounter(handle); - if(value >= maxCount) { - if(maxCount == 1 and value > 1) { - // Binary Semaphore special case. - // This is a config error use lightweight printf is this is called - // from an interrupt - printf("BinarySemaphore::release: Value of binary semaphore greater" - " than 1!\n"); - return HasReturnvaluesIF::RETURN_FAILED; - } - return SemaphoreIF::SEMAPHORE_NOT_OWNED; - } - return HasReturnvaluesIF::RETURN_OK; -} diff --git a/osal/linux/CountingSemaphore.cpp b/osal/linux/CountingSemaphore.cpp deleted file mode 100644 index 07c52212..00000000 --- a/osal/linux/CountingSemaphore.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include "../../osal/linux/CountingSemaphore.h" -#include "../../serviceinterface/ServiceInterface.h" - -#include - -CountingSemaphore::CountingSemaphore(const uint8_t maxCount, uint8_t initCount): - maxCount(maxCount), initCount(initCount) { - if(initCount > maxCount) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "CountingSemaphoreUsingTask: Max count bigger than " - "intial cout. Setting initial count to max count." << std::endl; -#endif - initCount = maxCount; - } - - initSemaphore(initCount); -} - -CountingSemaphore::CountingSemaphore(CountingSemaphore&& other): - maxCount(other.maxCount), initCount(other.initCount) { - initSemaphore(initCount); -} - -CountingSemaphore& CountingSemaphore::operator =( - CountingSemaphore&& other) { - initSemaphore(other.initCount); - return * this; -} - -ReturnValue_t CountingSemaphore::release() { - ReturnValue_t result = checkCount(&handle, maxCount); - if(result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - return CountingSemaphore::release(&this->handle); -} - -ReturnValue_t CountingSemaphore::release(sem_t* handle) { - int result = sem_post(handle); - if(result == 0) { - return HasReturnvaluesIF::RETURN_OK; - } - - switch(errno) { - case(EINVAL): - // Semaphore invalid - return SemaphoreIF::SEMAPHORE_INVALID; - case(EOVERFLOW): - // SEM_MAX_VALUE overflow. This should never happen - default: - return HasReturnvaluesIF::RETURN_FAILED; - } -} - -uint8_t CountingSemaphore::getMaxCount() const { - return maxCount; -} - diff --git a/osal/linux/MessageQueue.cpp b/osal/linux/MessageQueue.cpp deleted file mode 100644 index 12774a58..00000000 --- a/osal/linux/MessageQueue.cpp +++ /dev/null @@ -1,408 +0,0 @@ -#include "MessageQueue.h" -#include "../../serviceinterface/ServiceInterface.h" -#include "../../objectmanager/ObjectManagerIF.h" - -#include - -#include /* For O_* constants */ -#include /* For mode constants */ -#include -#include - - -MessageQueue::MessageQueue(uint32_t messageDepth, size_t maxMessageSize): - id(MessageQueueIF::NO_QUEUE),lastPartner(MessageQueueIF::NO_QUEUE), - defaultDestination(MessageQueueIF::NO_QUEUE), - maxMessageSize(maxMessageSize) { - //debug << "MessageQueue::MessageQueue: Creating a queue" << std::endl; - mq_attr attributes; - this->id = 0; - //Set attributes - attributes.mq_curmsgs = 0; - attributes.mq_maxmsg = messageDepth; - attributes.mq_msgsize = maxMessageSize; - attributes.mq_flags = 0; //Flags are ignored on Linux during mq_open - //Set the name of the queue. The slash is mandatory! - sprintf(name, "/FSFW_MQ%u\n", queueCounter++); - - // Create a nonblocking queue if the name is available (the queue is read - // and writable for the owner as well as the group) - int oflag = O_NONBLOCK | O_RDWR | O_CREAT | O_EXCL; - mode_t mode = S_IWUSR | S_IREAD | S_IWGRP | S_IRGRP | S_IROTH | S_IWOTH; - mqd_t tempId = mq_open(name, oflag, mode, &attributes); - if (tempId == -1) { - handleError(&attributes, messageDepth); - } - else { - //Successful mq_open call - this->id = tempId; - } -} - -MessageQueue::~MessageQueue() { - int status = mq_close(this->id); - if(status != 0){ -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "MessageQueue::Destructor: mq_close Failed with status: " - << strerror(errno) <> - defaultMqMaxMsg and defaultMqMaxMsg < messageDepth) { - /* - See: https://www.man7.org/linux/man-pages/man3/mq_open.3.html - This happens if the msg_max value is not large enough - It is ignored if the executable is run in privileged mode. - Run the unlockRealtime script or grant the mode manually by using: - sudo setcap 'CAP_SYS_RESOURCE=+ep' - - Persistent solution for session: - echo | sudo tee /proc/sys/fs/mqueue/msg_max - - Permanent solution: - sudo nano /etc/sysctl.conf - Append at end: fs/mqueue/msg_max = - Apply changes with: sudo sysctl -p - */ -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "MessageQueue::MessageQueue: Default MQ size " - << defaultMqMaxMsg << " is too small for requested size " - << messageDepth << std::endl; - sif::error << "This error can be fixed by setting the maximum " - "allowed message size higher!" << std::endl; -#endif - - } - break; - } - case(EEXIST): { - // An error occured during open - // We need to distinguish if it is caused by an already created queue - //There's another queue with the same name - //We unlink the other queue - int status = mq_unlink(name); - if (status != 0) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "mq_unlink Failed with status: " << strerror(errno) - << std::endl; -#endif - } - else { - // Successful unlinking, try to open again - mqd_t tempId = mq_open(name, - O_NONBLOCK | O_RDWR | O_CREAT | O_EXCL, - S_IWUSR | S_IREAD | S_IWGRP | S_IRGRP, attributes); - if (tempId != -1) { - //Successful mq_open - this->id = tempId; - return HasReturnvaluesIF::RETURN_OK; - } - } - break; - } - - default: { - // Failed either the first time or the second time -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "MessageQueue::MessageQueue: Creating Queue " << name - << " failed with status: " << strerror(errno) << std::endl; -#else - sif::printError("MessageQueue::MessageQueue: Creating Queue %s" - " failed with status: %s\n", name, strerror(errno)); -#endif - } - } - return HasReturnvaluesIF::RETURN_FAILED; - - - -} - -ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo, - MessageQueueMessageIF* message, bool ignoreFault) { - return sendMessageFrom(sendTo, message, this->getId(), false); -} - -ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessageIF* message) { - return sendToDefaultFrom(message, this->getId()); -} - -ReturnValue_t MessageQueue::reply(MessageQueueMessageIF* message) { - if (this->lastPartner != 0) { - return sendMessageFrom(this->lastPartner, message, this->getId()); - } else { - return NO_REPLY_PARTNER; - } -} - -ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message, - MessageQueueId_t* receivedFrom) { - ReturnValue_t status = this->receiveMessage(message); - *receivedFrom = this->lastPartner; - return status; -} - -ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) { - if(message == nullptr) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "MessageQueue::receiveMessage: Message is " - "nullptr!" << std::endl; -#endif - return HasReturnvaluesIF::RETURN_FAILED; - } - - if(message->getMaximumMessageSize() < maxMessageSize) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "MessageQueue::receiveMessage: Message size " - << message->getMaximumMessageSize() - << " too small to receive data!" << std::endl; -#endif - return HasReturnvaluesIF::RETURN_FAILED; - } - - unsigned int messagePriority = 0; - int status = mq_receive(id,reinterpret_cast(message->getBuffer()), - message->getMaximumMessageSize(),&messagePriority); - if (status > 0) { - this->lastPartner = message->getSender(); - //Check size of incoming message. - if (message->getMessageSize() < message->getMinimumMessageSize()) { - return HasReturnvaluesIF::RETURN_FAILED; - } - return HasReturnvaluesIF::RETURN_OK; - } - else if (status==0) { - //Success but no message received - return MessageQueueIF::EMPTY; - } - else { - //No message was received. Keep lastPartner anyway, I might send - //something later. But still, delete packet content. - memset(message->getData(), 0, message->getMaximumDataSize()); - switch(errno){ - case EAGAIN: - //O_NONBLOCK or MQ_NONBLOCK was set and there are no messages - //currently on the specified queue. - return MessageQueueIF::EMPTY; - case EBADF: - //mqdes doesn't represent a valid queue open for reading. -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "MessageQueue::receive: configuration error " - << strerror(errno) << std::endl; -#endif - /*NO BREAK*/ - case EINVAL: - /* - * This value indicates one of the following: - * - The pointer to the buffer for storing the received message, - * msg_ptr, is NULL. - * - The number of bytes requested, msg_len is less than zero. - * - msg_len is anything other than the mq_msgsize of the specified - * queue, and the QNX extended option MQ_READBUF_DYNAMIC hasn't - * been set in the queue's mq_flags. - */ -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "MessageQueue::receive: configuration error " - << strerror(errno) << std::endl; -#endif - /*NO BREAK*/ - case EMSGSIZE: - /* - * This value indicates one of the following: - * - the QNX extended option MQ_READBUF_DYNAMIC hasn't been set, - * and the given msg_len is shorter than the mq_msgsize for - * the given queue. - * - the extended option MQ_READBUF_DYNAMIC has been set, but the - * given msg_len is too short for the message that would have - * been received. - */ -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "MessageQueue::receive: configuration error " - << strerror(errno) << std::endl; -#endif - /*NO BREAK*/ - case EINTR: - //The operation was interrupted by a signal. - default: - - return HasReturnvaluesIF::RETURN_FAILED; - } - - } -} - -MessageQueueId_t MessageQueue::getLastPartner() const { - return this->lastPartner; -} - -ReturnValue_t MessageQueue::flush(uint32_t* count) { - mq_attr attrib; - int status = mq_getattr(id,&attrib); - if(status != 0){ - switch(errno){ - case EBADF: - //mqdes doesn't represent a valid message queue. -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "MessageQueue::flush configuration error, " - "called flush with an invalid queue ID" << std::endl; -#endif - /*NO BREAK*/ - case EINVAL: - //mq_attr is NULL - default: - return HasReturnvaluesIF::RETURN_FAILED; - } - } - *count = attrib.mq_curmsgs; - attrib.mq_curmsgs = 0; - status = mq_setattr(id,&attrib,NULL); - if(status != 0){ - switch(errno){ - case EBADF: - //mqdes doesn't represent a valid message queue. -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "MessageQueue::flush configuration error, " - "called flush with an invalid queue ID" << std::endl; -#endif - /*NO BREAK*/ - case EINVAL: - /* - * This value indicates one of the following: - * - mq_attr is NULL. - * - MQ_MULT_NOTIFY had been set for this queue, and the given - * mq_flags includes a 0 in the MQ_MULT_NOTIFY bit. Once - * MQ_MULT_NOTIFY has been turned on, it may never be turned off. - */ - default: - return HasReturnvaluesIF::RETURN_FAILED; - } - } - return HasReturnvaluesIF::RETURN_OK; -} - -MessageQueueId_t MessageQueue::getId() const { - return this->id; -} - -void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) { - this->defaultDestination = defaultDestination; -} - -ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessageIF* message, - MessageQueueId_t sentFrom, bool ignoreFault) { - return sendMessageFrom(defaultDestination, message, sentFrom, ignoreFault); -} - - -ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, - MessageQueueMessageIF* message, MessageQueueId_t sentFrom, - bool ignoreFault) { - return sendMessageFromMessageQueue(sendTo,message, sentFrom,ignoreFault); - -} - -MessageQueueId_t MessageQueue::getDefaultDestination() const { - return this->defaultDestination; -} - -bool MessageQueue::isDefaultDestinationSet() const { - return (defaultDestination != NO_QUEUE); -} - -uint16_t MessageQueue::queueCounter = 0; - -ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, - MessageQueueMessageIF *message, MessageQueueId_t sentFrom, - bool ignoreFault) { - if(message == nullptr) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "MessageQueue::sendMessageFromMessageQueue: Message is " - "nullptr!" << std::endl; -#endif - return HasReturnvaluesIF::RETURN_FAILED; - } - - message->setSender(sentFrom); - int result = mq_send(sendTo, - reinterpret_cast(message->getBuffer()), - message->getMessageSize(),0); - - //TODO: Check if we're in ISR. - if (result != 0) { - if(!ignoreFault){ - InternalErrorReporterIF* internalErrorReporter = - objectManager->get( - objects::INTERNAL_ERROR_REPORTER); - if (internalErrorReporter != NULL) { - internalErrorReporter->queueMessageNotSent(); - } - } - switch(errno){ - case EAGAIN: - //The O_NONBLOCK flag was set when opening the queue, or the - //MQ_NONBLOCK flag was set in its attributes, and the - //specified queue is full. - return MessageQueueIF::FULL; - case EBADF: { - //mq_des doesn't represent a valid message queue descriptor, - //or mq_des wasn't opened for writing. -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "MessageQueue::sendMessage: Configuration error, MQ" - << " destination invalid." << std::endl; - sif::error << strerror(errno) << " in " - <<"mq_send to: " << sendTo << " sent from " - << sentFrom << std::endl; -#endif - return DESTINATION_INVALID; - } - case EINTR: - //The call was interrupted by a signal. - case EINVAL: - /* - * This value indicates one of the following: - * - msg_ptr is NULL. - * - msg_len is negative. - * - msg_prio is greater than MQ_PRIO_MAX. - * - msg_prio is less than 0. - * - MQ_PRIO_RESTRICT is set in the mq_attr of mq_des, and - * msg_prio is greater than the priority of the calling process. - */ -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "MessageQueue::sendMessage: Configuration error " - << strerror(errno) << " in mq_send" << std::endl; -#endif - /*NO BREAK*/ - case EMSGSIZE: - // The msg_len is greater than the msgsize associated with - //the specified queue. -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "MessageQueue::sendMessage: Size error [" << - strerror(errno) << "] in mq_send" << std::endl; -#endif - /*NO BREAK*/ - default: - return HasReturnvaluesIF::RETURN_FAILED; - } - } - return HasReturnvaluesIF::RETURN_OK; -} diff --git a/osal/linux/PosixThread.cpp b/osal/linux/PosixThread.cpp deleted file mode 100644 index 72adfb14..00000000 --- a/osal/linux/PosixThread.cpp +++ /dev/null @@ -1,268 +0,0 @@ -#include "PosixThread.h" - -#include "../../serviceinterface/ServiceInterface.h" - -#include -#include - -PosixThread::PosixThread(const char* name_, int priority_, size_t stackSize_): - thread(0), priority(priority_), stackSize(stackSize_) { - name[0] = '\0'; - std::strncat(name, name_, PTHREAD_MAX_NAMELEN - 1); -} - -PosixThread::~PosixThread() { - //No deletion and no free of Stack Pointer -} - -ReturnValue_t PosixThread::sleep(uint64_t ns) { - //TODO sleep might be better with timer instead of sleep() - timespec time; - time.tv_sec = ns/1000000000; - time.tv_nsec = ns - time.tv_sec*1e9; - - //Remaining Time is not set here - int status = nanosleep(&time,NULL); - if(status != 0){ - switch(errno){ - case EINTR: - //The nanosleep() function was interrupted by a signal. - return HasReturnvaluesIF::RETURN_FAILED; - case EINVAL: - //The rqtp argument specified a nanosecond value less than zero or - // greater than or equal to 1000 million. - return HasReturnvaluesIF::RETURN_FAILED; - default: - return HasReturnvaluesIF::RETURN_FAILED; - } - - } - return HasReturnvaluesIF::RETURN_OK; -} - -void PosixThread::suspend() { - //Wait for SIGUSR1 - int caughtSig = 0; - sigset_t waitSignal; - sigemptyset(&waitSignal); - sigaddset(&waitSignal, SIGUSR1); - sigwait(&waitSignal, &caughtSig); - if (caughtSig != SIGUSR1) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "FixedTimeslotTask: Unknown Signal received: " << - caughtSig << std::endl; -#endif - } -} - -void PosixThread::resume(){ - /* Signal the thread to start. Makes sense to call kill to start or? ;) - * - * According to Posix raise(signal) will call pthread_kill(pthread_self(), sig), - * but as the call must be done from the thread itsself this is not possible here - */ - pthread_kill(thread,SIGUSR1); -} - -bool PosixThread::delayUntil(uint64_t* const prevoiusWakeTime_ms, - const uint64_t delayTime_ms) { - uint64_t nextTimeToWake_ms; - bool shouldDelay = false; - //Get current Time - const uint64_t currentTime_ms = getCurrentMonotonicTimeMs(); - /* Generate the tick time at which the task wants to wake. */ - nextTimeToWake_ms = (*prevoiusWakeTime_ms) + delayTime_ms; - - if (currentTime_ms < *prevoiusWakeTime_ms) { - /* The tick count has overflowed since this function was - lasted called. In this case the only time we should ever - actually delay is if the wake time has also overflowed, - and the wake time is greater than the tick time. When this - is the case it is as if neither time had overflowed. */ - if ((nextTimeToWake_ms < *prevoiusWakeTime_ms) - && (nextTimeToWake_ms > currentTime_ms)) { - shouldDelay = true; - } - } else { - /* The tick time has not overflowed. In this case we will - delay if either the wake time has overflowed, and/or the - tick time is less than the wake time. */ - if ((nextTimeToWake_ms < *prevoiusWakeTime_ms) - || (nextTimeToWake_ms > currentTime_ms)) { - shouldDelay = true; - } - } - - /* Update the wake time ready for the next call. */ - - (*prevoiusWakeTime_ms) = nextTimeToWake_ms; - - if (shouldDelay) { - uint64_t sleepTime = nextTimeToWake_ms - currentTime_ms; - PosixThread::sleep(sleepTime * 1000000ull); - return true; - } - //We are shifting the time in case the deadline was missed like rtems - (*prevoiusWakeTime_ms) = currentTime_ms; - return false; - -} - - -uint64_t PosixThread::getCurrentMonotonicTimeMs(){ - timespec timeNow; - clock_gettime(CLOCK_MONOTONIC_RAW, &timeNow); - uint64_t currentTime_ms = (uint64_t) timeNow.tv_sec * 1000 - + timeNow.tv_nsec / 1000000; - - return currentTime_ms; -} - - -void PosixThread::createTask(void* (*fnc_)(void*), void* arg_) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - //sif::debug << "PosixThread::createTask" << std::endl; -#endif - /* - * The attr argument points to a pthread_attr_t structure whose contents - are used at thread creation time to determine attributes for the new - thread; this structure is initialized using pthread_attr_init(3) and - related functions. If attr is NULL, then the thread is created with - default attributes. - */ - pthread_attr_t attributes; - int status = pthread_attr_init(&attributes); - if(status != 0){ -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "Posix Thread attribute init failed with: " << - strerror(status) << std::endl; -#endif - } - void* stackPointer; - status = posix_memalign(&stackPointer, sysconf(_SC_PAGESIZE), stackSize); - if(status != 0){ -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "PosixThread::createTask: Stack init failed with: " << - strerror(status) << std::endl; -#endif - if(errno == ENOMEM) { - size_t stackMb = stackSize/10e6; -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "PosixThread::createTask: Insufficient memory for" - " the requested " << stackMb << " MB" << std::endl; -#else - sif::printError("PosixThread::createTask: Insufficient memory for " - "the requested %lu MB\n", static_cast(stackMb)); -#endif - } - else if(errno == EINVAL) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "PosixThread::createTask: Wrong alignment argument!" - << std::endl; -#else - sif::printError("PosixThread::createTask: " - "Wrong alignment argument!\n"); -#endif - } - return; - } - - status = pthread_attr_setstack(&attributes, stackPointer, stackSize); - if(status != 0){ -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "PosixThread::createTask: pthread_attr_setstack " - " failed with: " << strerror(status) << std::endl; - sif::error << "Make sure the specified stack size is valid and is " - "larger than the minimum allowed stack size." << std::endl; -#endif - } - - status = pthread_attr_setinheritsched(&attributes, PTHREAD_EXPLICIT_SCHED); - if(status != 0){ -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "Posix Thread attribute setinheritsched failed with: " << - strerror(status) << std::endl; -#endif - } -#ifndef FSFW_USE_REALTIME_FOR_LINUX -#error "Please define FSFW_USE_REALTIME_FOR_LINUX with either 0 or 1" -#endif -#if FSFW_USE_REALTIME_FOR_LINUX == 1 - // FIFO -> This needs root privileges for the process - status = pthread_attr_setschedpolicy(&attributes,SCHED_FIFO); - if(status != 0){ -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "Posix Thread attribute schedule policy failed with: " << - strerror(status) << std::endl; -#endif - } - - sched_param scheduleParams; - scheduleParams.__sched_priority = priority; - status = pthread_attr_setschedparam(&attributes, &scheduleParams); - if(status != 0){ -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "Posix Thread attribute schedule params failed with: " << - strerror(status) << std::endl; -#endif - } -#endif - //Set Signal Mask for suspend until startTask is called - sigset_t waitSignal; - sigemptyset(&waitSignal); - sigaddset(&waitSignal, SIGUSR1); - status = pthread_sigmask(SIG_BLOCK, &waitSignal, NULL); - if(status != 0){ -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "Posix Thread sigmask failed failed with: " << - strerror(status) << " errno: " << strerror(errno) << std::endl; -#endif - } - - - status = pthread_create(&thread,&attributes,fnc_,arg_); - if(status != 0){ -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "PosixThread::createTask: Failed with: " << - strerror(status) << std::endl; - sif::error << "For FSFW_USE_REALTIME_FOR_LINUX == 1 make sure to call " << - "\"all sudo setcap 'cap_sys_nice=eip'\" on the application or set " - "/etc/security/limit.conf" << std::endl; -#else - sif::printError("PosixThread::createTask: Create failed with: %s\n", strerror(status)); - sif::printError("For FSFW_USE_REALTIME_FOR_LINUX == 1 make sure to call " - "\"all sudo setcap 'cap_sys_nice=eip'\" on the application or set " - "/etc/security/limit.conf\n"); -#endif - } - - status = pthread_setname_np(thread,name); - if(status != 0){ -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "PosixThread::createTask: setname failed with: " << - strerror(status) << std::endl; -#endif - if(status == ERANGE) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "PosixThread::createTask: Task name length longer" - " than 16 chars. Truncating.." << std::endl; -#endif - name[15] = '\0'; - status = pthread_setname_np(thread,name); - if(status != 0){ -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "PosixThread::createTask: Setting name" - " did not work.." << std::endl; -#endif - } - } - } - - status = pthread_attr_destroy(&attributes); - if(status!=0){ -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "Posix Thread attribute destroy failed with: " << - strerror(status) << std::endl; -#endif - } -} diff --git a/osal/linux/PosixThread.h b/osal/linux/PosixThread.h deleted file mode 100644 index 7d8d349a..00000000 --- a/osal/linux/PosixThread.h +++ /dev/null @@ -1,77 +0,0 @@ -#ifndef FRAMEWORK_OSAL_LINUX_POSIXTHREAD_H_ -#define FRAMEWORK_OSAL_LINUX_POSIXTHREAD_H_ - -#include "../../returnvalues/HasReturnvaluesIF.h" -#include -#include -#include -#include - -class PosixThread { -public: - static constexpr uint8_t PTHREAD_MAX_NAMELEN = 16; - PosixThread(const char* name_, int priority_, size_t stackSize_); - virtual ~PosixThread(); - /** - * Set the Thread to sleep state - * @param ns Nanosecond sleep time - * @return Returns Failed if sleep fails - */ - static ReturnValue_t sleep(uint64_t ns); - /** - * @brief Function to suspend the task until SIGUSR1 was received - * - * @details Will be called in the beginning to suspend execution until startTask() is called explicitly. - */ - void suspend(); - - /** - * @brief Function to allow a other thread to start the thread again from suspend state - * - * @details Restarts the Thread after suspend call - */ - void resume(); - - - /** - * Delay function similar to FreeRtos delayUntil function - * - * @param prevoiusWakeTime_ms Needs the previous wake time and returns the next wakeup time - * @param delayTime_ms Time period to delay - * - * @return False If deadline was missed; True if task was delayed - */ - static bool delayUntil(uint64_t* const prevoiusWakeTime_ms, const uint64_t delayTime_ms); - - /** - * Returns the current time in milliseconds from CLOCK_MONOTONIC - * - * @return current time in milliseconds from CLOCK_MONOTONIC - */ - static uint64_t getCurrentMonotonicTimeMs(); - -protected: - pthread_t thread; - - /** - * @brief Function that has to be called by derived class because the - * derived class pointer has to be valid as argument. - * @details - * This function creates a pthread with the given parameters. As the - * function requires a pointer to the derived object it has to be called - * after the this pointer of the derived object is valid. - * Sets the taskEntryPoint as function to be called by new a thread. - * @param fnc_ Function which will be executed by the thread. - * @param arg_ - * argument of the taskEntryPoint function, needs to be this pointer - * of derived class - */ - void createTask(void* (*fnc_)(void*),void* arg_); - -private: - char name[PTHREAD_MAX_NAMELEN]; - int priority; - size_t stackSize = 0; -}; - -#endif /* FRAMEWORK_OSAL_LINUX_POSIXTHREAD_H_ */ diff --git a/osal/linux/Timer.cpp b/osal/linux/Timer.cpp deleted file mode 100644 index fe0fbebb..00000000 --- a/osal/linux/Timer.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include "Timer.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" -#include - - -Timer::Timer() { - sigevent sigEvent; - sigEvent.sigev_notify = SIGEV_NONE; - sigEvent.sigev_signo = 0; - sigEvent.sigev_value.sival_ptr = &timerId; - int status = timer_create(CLOCK_MONOTONIC, &sigEvent, &timerId); - if(status!=0){ -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "Timer creation failed with: " << status << - " errno: " << errno << std::endl; -#endif - } -} - -Timer::~Timer() { - timer_delete(timerId); -} - -int Timer::setTimer(uint32_t intervalMs) { - itimerspec timer; - timer.it_value.tv_sec = intervalMs / 1000; - timer.it_value.tv_nsec = (intervalMs * 1000000) % (1000000000); - timer.it_interval.tv_sec = 0; - timer.it_interval.tv_nsec = 0; - return timer_settime(timerId, 0, &timer, NULL); -} - - -int Timer::getTimer(uint32_t* remainingTimeMs){ - itimerspec timer; - timer.it_value.tv_sec = 0; - timer.it_value.tv_nsec = 0; - timer.it_interval.tv_sec = 0; - timer.it_interval.tv_nsec = 0; - int status = timer_gettime(timerId, &timer); - - *remainingTimeMs = timer.it_value.tv_sec * 1000 + timer.it_value.tv_nsec / 1000000; - - return status; -} diff --git a/osal/linux/Timer.h b/osal/linux/Timer.h deleted file mode 100644 index f94bca59..00000000 --- a/osal/linux/Timer.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef FRAMEWORK_OSAL_LINUX_TIMER_H_ -#define FRAMEWORK_OSAL_LINUX_TIMER_H_ - -#include -#include -#include - -/** - * This class is a helper for the creation of a Clock Monotonic timer which does not trigger a signal - */ -class Timer { -public: - /** - * Creates the Timer sets the timerId Member - */ - Timer(); - /** - * Deletes the timer - * - * Careful! According to POSIX documentation: - * The treatment of any pending signal generated by the deleted timer is unspecified. - */ - virtual ~Timer(); - - /** - * Set the timer given in timerId to the given interval - * - * @param intervalMs Interval in ms to be set - * @return 0 on Success 1 else - */ - int setTimer(uint32_t intervalMs); - - /** - * Get the remaining time of the timer - * - * @param remainingTimeMs Pointer to integer value which is used to return the remaining time - * @return 0 on Success 1 else (see timer_getime documentation of posix function) - */ - int getTimer(uint32_t* remainingTimeMs); - -private: - timer_t timerId; -}; - -#endif /* FRAMEWORK_OSAL_LINUX_TIMER_H_ */ diff --git a/osal/rtems/RtemsBasic.cpp b/osal/rtems/RtemsBasic.cpp deleted file mode 100644 index 8ab0ddcd..00000000 --- a/osal/rtems/RtemsBasic.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include "RtemsBasic.h" - -// TODO: Can this be removed? - -//ReturnValue_t RtemsBasic::convertReturnCode(rtems_status_code inValue) { -// if (inValue == RTEMS_SUCCESSFUL) { -// return HasReturnvaluesIF::RETURN_OK; -// } else { -// switch(inValue){ -// case RTEMS_SUCCESSFUL: -// return OperatingSystemIF::SUCCESSFUL; -// case RTEMS_TASK_EXITTED: -// return OperatingSystemIF::TASK_EXITTED; -// case RTEMS_MP_NOT_CONFIGURED: -// return OperatingSystemIF::MP_NOT_CONFIGURED; -// case RTEMS_INVALID_NAME: -// return OperatingSystemIF::INVALID_NAME; -// case RTEMS_INVALID_ID: -// return OperatingSystemIF::INVALID_ID; -// case RTEMS_TOO_MANY: -// return OperatingSystemIF::TOO_MANY; -// case RTEMS_TIMEOUT: -// return OperatingSystemIF::TIMEOUT; -// case RTEMS_OBJECT_WAS_DELETED: -// return OperatingSystemIF::OBJECT_WAS_DELETED; -// case RTEMS_INVALID_SIZE: -// return OperatingSystemIF::INVALID_SIZE; -// case RTEMS_INVALID_ADDRESS: -// return OperatingSystemIF::INVALID_ADDRESS; -// case RTEMS_INVALID_NUMBER: -// return OperatingSystemIF::INVALID_NUMBER; -// case RTEMS_NOT_DEFINED: -// return OperatingSystemIF::NOT_DEFINED; -// case RTEMS_RESOURCE_IN_USE: -// return OperatingSystemIF::RESOURCE_IN_USE; -// //TODO RTEMS_UNSATISFIED is double mapped for FLP so it will only return Queue_empty and not unsatisfied -// case RTEMS_UNSATISFIED: -// return OperatingSystemIF::QUEUE_EMPTY; -// case RTEMS_INCORRECT_STATE: -// return OperatingSystemIF::INCORRECT_STATE; -// case RTEMS_ALREADY_SUSPENDED: -// return OperatingSystemIF::ALREADY_SUSPENDED; -// case RTEMS_ILLEGAL_ON_SELF: -// return OperatingSystemIF::ILLEGAL_ON_SELF; -// case RTEMS_ILLEGAL_ON_REMOTE_OBJECT: -// return OperatingSystemIF::ILLEGAL_ON_REMOTE_OBJECT; -// case RTEMS_CALLED_FROM_ISR: -// return OperatingSystemIF::CALLED_FROM_ISR; -// case RTEMS_INVALID_PRIORITY: -// return OperatingSystemIF::INVALID_PRIORITY; -// case RTEMS_INVALID_CLOCK: -// return OperatingSystemIF::INVALID_CLOCK; -// case RTEMS_INVALID_NODE: -// return OperatingSystemIF::INVALID_NODE; -// case RTEMS_NOT_CONFIGURED: -// return OperatingSystemIF::NOT_CONFIGURED; -// case RTEMS_NOT_OWNER_OF_RESOURCE: -// return OperatingSystemIF::NOT_OWNER_OF_RESOURCE; -// case RTEMS_NOT_IMPLEMENTED: -// return OperatingSystemIF::NOT_IMPLEMENTED; -// case RTEMS_INTERNAL_ERROR: -// return OperatingSystemIF::INTERNAL_ERROR; -// case RTEMS_NO_MEMORY: -// return OperatingSystemIF::NO_MEMORY; -// case RTEMS_IO_ERROR: -// return OperatingSystemIF::IO_ERROR; -// default: -// return HasReturnvaluesIF::RETURN_FAILED; -// } -// } -//} diff --git a/returnvalues/FwClassIds.h b/returnvalues/FwClassIds.h deleted file mode 100644 index 4c9f022b..00000000 --- a/returnvalues/FwClassIds.h +++ /dev/null @@ -1,74 +0,0 @@ -#ifndef FSFW_RETURNVALUES_FWCLASSIDS_H_ -#define FSFW_RETURNVALUES_FWCLASSIDS_H_ - -namespace CLASS_ID { -enum { - OPERATING_SYSTEM_ABSTRACTION = 1, //OS - OBJECT_MANAGER_IF, //OM - DEVICE_HANDLER_BASE, //DHB - RMAP_CHANNEL, //RMP - POWER_SWITCH_IF, //PS - HAS_MEMORY_IF, //PP - DEVICE_STATE_MACHINE_BASE, //DSMB - DATA_SET_CLASS, //DPS - POOL_RAW_ACCESS_CLASS, //DPR - CONTROLLER_BASE, //CTR - SUBSYSTEM_BASE, //SB - MODE_STORE_IF, //MS - SUBSYSTEM, //SS - HAS_MODES_IF, //HM - COMMAND_MESSAGE, //CM - CCSDS_TIME_HELPER_CLASS, //TIM - ARRAY_LIST, //AL - ASSEMBLY_BASE, //AB - MEMORY_HELPER, //MH - SERIALIZE_IF, //SE - FIXED_MAP, //FM - FIXED_MULTIMAP, //FMM - HAS_HEALTH_IF, //HHI - FIFO_CLASS, //FF - MESSAGE_PROXY, //MQP - TRIPLE_REDUNDACY_CHECK, //TRC - TC_PACKET_CHECK, //TCC - PACKET_DISTRIBUTION, //TCD - ACCEPTS_TELECOMMANDS_IF, //PUS - DEVICE_SERVICE_BASE, //DSB - COMMAND_SERVICE_BASE, //CSB - TM_STORE_BACKEND_IF, //TMB - TM_STORE_FRONTEND_IF, //TMF - STORAGE_AND_RETRIEVAL_SERVICE, //SR - MATCH_TREE_CLASS, //MT - EVENT_MANAGER_IF, //EV - HANDLES_FAILURES_IF, //FDI - DEVICE_HANDLER_IF, //DHI - STORAGE_MANAGER_IF, //SM - THERMAL_COMPONENT_IF, //TC - INTERNAL_ERROR_CODES, //IEC - TRAP, //TRP - CCSDS_HANDLER_IF, //CCS - PARAMETER_WRAPPER, //PAW - HAS_PARAMETERS_IF, //HPA - ASCII_CONVERTER, //ASC - POWER_SWITCHER, //POS - LIMITS_IF, //LIM - COMMANDS_ACTIONS_IF, //CF - HAS_ACTIONS_IF, //HF - DEVICE_COMMUNICATION_IF, //DC - BSP, //BSP - TIME_STAMPER_IF, //TSI 53 - SGP4PROPAGATOR_CLASS, //SGP4 54 - MUTEX_IF, //MUX 55 - MESSAGE_QUEUE_IF,//MQI 56 - SEMAPHORE_IF, //SPH 57 - LOCAL_POOL_OWNER_IF, //LPIF 58 - POOL_VARIABLE_IF, //PVA 59 - HOUSEKEEPING_MANAGER, //HKM 60 - DLE_ENCODER, //DLEE 61 - PUS_SERVICE_9, //PUS9 62 - FILE_SYSTEM, //FILS 63 - FW_CLASS_ID_COUNT //is actually count + 1 ! - -}; -} - -#endif /* FSFW_RETURNVALUES_FWCLASSIDS_H_ */ diff --git a/scripts/apply-clang-format.sh b/scripts/apply-clang-format.sh new file mode 100755 index 00000000..27202324 --- /dev/null +++ b/scripts/apply-clang-format.sh @@ -0,0 +1,8 @@ +#!/bin/bash +if [[ ! -f README.md ]]; then + cd .. +fi + +find ./src -iname *.h -o -iname *.cpp -o -iname *.c | xargs clang-format --style=file -i +find ./hal -iname *.h -o -iname *.cpp -o -iname *.c | xargs clang-format --style=file -i +find ./tests -iname *.h -o -iname *.cpp -o -iname *.c | xargs clang-format --style=file -i diff --git a/scripts/helper.py b/scripts/helper.py new file mode 100755 index 00000000..0bb430ee --- /dev/null +++ b/scripts/helper.py @@ -0,0 +1,188 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -* +"""Small portable helper script to generate test or doc configuration for the +flight software framework +""" +import os +import argparse +import webbrowser +import shutil +import sys +import time +from typing import List + + +UNITTEST_FOLDER_NAME = 'build-tests' +DOCS_FOLDER_NAME = 'build-docs' + + +def main(): + + parser = argparse.ArgumentParser(description="FSFW helper script") + choices = ('docs', 'tests') + parser.add_argument( + 'type', metavar='type', choices=choices, + help=f'Target type. Choices: {choices}' + ) + parser.add_argument( + '-a', '--all', action='store_true', + help='Create, build and open specified type' + ) + parser.add_argument( + '-c', '--create', action='store_true', + help='Create docs or test build configuration' + ) + parser.add_argument( + '-b', '--build', action='store_true', + help='Build the specified type' + ) + parser.add_argument( + '-o', '--open', action='store_true', + help='Open test or documentation data in webbrowser' + ) + + args = parser.parse_args() + if args.all: + args.build = True + args.create = True + args.open = True + elif not args.build and not args.create and not args.open: + print( + 'Please select at least one operation to perform. ' + 'Use helper.py -h for more information' + ) + sys.exit(1) + + # This script can be called from root and from script folder + if not os.path.isfile('README.md'): + os.chdir('..') + build_dir_list = [] + if not args.create: + build_dir_list = build_build_dir_list() + + if args.type == 'tests': + handle_tests_type(args, build_dir_list) + elif args.type == 'docs': + handle_docs_type(args, build_dir_list) + else: + print('Invalid or unknown type') + sys.exit(1) + + +def handle_docs_type(args, build_dir_list: list): + if args.create: + if os.path.exists(DOCS_FOLDER_NAME): + shutil.rmtree(DOCS_FOLDER_NAME) + create_docs_build_cfg() + build_directory = DOCS_FOLDER_NAME + elif len(build_dir_list) == 0: + print('No valid CMake docs build directory found. Trying to set up docs build system') + shutil.rmtree(DOCS_FOLDER_NAME) + create_docs_build_cfg() + build_directory = DOCS_FOLDER_NAME + elif len(build_dir_list) == 1: + build_directory = build_dir_list[0] + else: + print("Multiple build directories found!") + build_directory = determine_build_dir(build_dir_list) + os.chdir(build_directory) + if args.build: + os.system('cmake --build . -j') + if args.open: + if not os.path.isfile('docs/sphinx/index.html'): + # try again.. + os.system('cmake --build . -j') + if not os.path.isfile('docs/sphinx/index.html'): + print( + "No Sphinx documentation file detected. " + "Try to build it first with the -b argument" + ) + sys.exit(1) + webbrowser.open('docs/sphinx/index.html') + + +def handle_tests_type(args, build_dir_list: list): + if args.create: + if os.path.exists(UNITTEST_FOLDER_NAME): + shutil.rmtree(UNITTEST_FOLDER_NAME) + create_tests_build_cfg() + build_directory = UNITTEST_FOLDER_NAME + elif len(build_dir_list) == 0: + print( + 'No valid CMake tests build directory found. ' + 'Trying to set up test build system' + ) + create_tests_build_cfg() + build_directory = UNITTEST_FOLDER_NAME + elif len(build_dir_list) == 1: + build_directory = build_dir_list[0] + else: + print("Multiple build directories found!") + build_directory = determine_build_dir(build_dir_list) + os.chdir(build_directory) + if args.build: + perform_lcov_operation(build_directory, False) + if args.open: + if not os.path.isdir('fsfw-tests_coverage'): + print("No Unittest folder detected. Try to build them first with the -b argument") + sys.exit(1) + webbrowser.open('fsfw-tests_coverage/index.html') + + +def create_tests_build_cfg(): + os.mkdir(UNITTEST_FOLDER_NAME) + os.chdir(UNITTEST_FOLDER_NAME) + os.system('cmake -DFSFW_OSAL=host -DFSFW_BUILD_UNITTESTS=ON ..') + os.chdir('..') + + +def create_docs_build_cfg(): + os.mkdir(DOCS_FOLDER_NAME) + os.chdir(DOCS_FOLDER_NAME) + os.system('cmake -DFSFW_OSAL=host -DFSFW_BUILD_DOCS=ON ..') + os.chdir('..') + + +def build_build_dir_list() -> list: + build_dir_list = [] + for directory in os.listdir("."): + if os.path.isdir(directory): + os.chdir(directory) + build_dir_list = check_for_cmake_build_dir(build_dir_list) + os.chdir("..") + return build_dir_list + + +def check_for_cmake_build_dir(build_dir_list: list) -> list: + if os.path.isfile("CMakeCache.txt"): + build_dir_list.append(os.getcwd()) + return build_dir_list + + +def perform_lcov_operation(directory: str, chdir: bool): + if chdir: + os.chdir(directory) + os.system("cmake --build . -- fsfw-tests_coverage -j") + + +def determine_build_dir(build_dir_list: List[str]): + build_directory = "" + for idx, directory in enumerate(build_dir_list): + print(f"{idx + 1}: {directory}") + while True: + idx = input("Pick the directory: ") + if not idx.isdigit(): + print("Invalid input!") + continue + + idx = int(idx) + if idx > len(build_dir_list) or idx < 1: + print("Invalid input!") + continue + build_directory = build_dir_list[idx - 1] + break + return build_directory + + +if __name__ == "__main__": + main() diff --git a/serialize/SerializeAdapter.h b/serialize/SerializeAdapter.h deleted file mode 100644 index e6cd247e..00000000 --- a/serialize/SerializeAdapter.h +++ /dev/null @@ -1,193 +0,0 @@ -#ifndef _FSFW_SERIALIZE_SERIALIZEADAPTER_H_ -#define _FSFW_SERIALIZE_SERIALIZEADAPTER_H_ - -#include "../returnvalues/HasReturnvaluesIF.h" -#include "EndianConverter.h" -#include "SerializeIF.h" -#include -#include - - /** - * @brief These adapters provides an interface to use the SerializeIF functions - * with arbitrary template objects to facilitate and simplify the - * serialization of classes with different multiple different data types - * into buffers and vice-versa. - * @details - * The correct serialization or deserialization function is chosen at - * compile time with template type deduction. - * - * @ingroup serialize - */ -class SerializeAdapter { -public: - /*** - * This function can be used to serialize a trivial copy-able type or a - * child of SerializeIF. - * The right template to be called is determined in the function itself. - * For objects of non trivial copy-able type this function is almost never - * called by the user directly. Instead helpers for specific types like - * SerialArrayListAdapter or SerialLinkedListAdapter is the right choice here. - * - * @param[in] object Object to serialize, the used type is deduced from this pointer - * @param[in/out] buffer Buffer to serialize into. Will be moved by the function. - * @param[in/out] size Size of current written buffer. Will be incremented by the function. - * @param[in] maxSize Max size of Buffer - * @param[in] streamEndianness Endianness of serialized element as in according to SerializeIF::Endianness - * @return - * - @c BUFFER_TOO_SHORT The given buffer in is too short - * - @c RETURN_FAILED Generic Error - * - @c RETURN_OK Successful serialization - */ - template - static ReturnValue_t serialize(const T *object, uint8_t **buffer, - size_t *size, size_t maxSize, - SerializeIF::Endianness streamEndianness) { - InternalSerializeAdapter::value> adapter; - return adapter.serialize(object, buffer, size, maxSize, - streamEndianness); - } - /** - * Function to return the serialized size of the object in the pointer. - * May be a trivially copy-able object or a Child of SerializeIF - * - * @param object Pointer to Object - * @return Serialized size of object - */ - template - static size_t getSerializedSize(const T *object){ - InternalSerializeAdapter::value> adapter; - return adapter.getSerializedSize(object); - } - /** - * @brief - * Deserializes a object from a given buffer of given size. - * Object Must be trivially copy-able or a child of SerializeIF. - * - * @details - * Buffer will be moved to the current read location. Size will be decreased by the function. - * - * @param[in/out] buffer Buffer to deSerialize from. Will be moved by the function. - * @param[in/out] size Remaining size of the buffer to read from. Will be decreased by function. - * @param[in] streamEndianness Endianness as in according to SerializeIF::Endianness - * @return - * - @c STREAM_TOO_SHORT The input stream is too short to deSerialize the object - * - @c TOO_MANY_ELEMENTS The buffer has more inputs than expected - * - @c RETURN_FAILED Generic Error - * - @c RETURN_OK Successful deserialization - */ - template - static ReturnValue_t deSerialize(T *object, const uint8_t **buffer, - size_t *size, SerializeIF::Endianness streamEndianness) { - InternalSerializeAdapter::value> adapter; - return adapter.deSerialize(object, buffer, size, streamEndianness); - } -private: - /** - * Internal template to deduce the right function calls at compile time - */ - template class InternalSerializeAdapter; - - /** - * Template to be used if T is not a child of SerializeIF - * - * @tparam T T must be trivially_copyable - */ - template - class InternalSerializeAdapter { - static_assert (std::is_trivially_copyable::value, - "If a type needs to be serialized it must be a child of " - "SerializeIF or trivially copy-able"); - public: - static ReturnValue_t serialize(const T *object, uint8_t **buffer, - size_t *size, size_t max_size, - SerializeIF::Endianness streamEndianness) { - size_t ignoredSize = 0; - if (size == nullptr) { - size = &ignoredSize; - } - // Check remaining size is large enough and check integer - // overflow of *size - size_t newSize = sizeof(T) + *size; - if ((newSize <= max_size) and (newSize > *size)) { - T tmp; - switch (streamEndianness) { - case SerializeIF::Endianness::BIG: - tmp = EndianConverter::convertBigEndian(*object); - break; - case SerializeIF::Endianness::LITTLE: - tmp = EndianConverter::convertLittleEndian(*object); - break; - default: - case SerializeIF::Endianness::MACHINE: - tmp = *object; - break; - } - std::memcpy(*buffer, &tmp, sizeof(T)); - *size += sizeof(T); - (*buffer) += sizeof(T); - return HasReturnvaluesIF::RETURN_OK; - } else { - return SerializeIF::BUFFER_TOO_SHORT; - } - } - - ReturnValue_t deSerialize(T *object, const uint8_t **buffer, - size_t *size, SerializeIF::Endianness streamEndianness) { - T tmp; - if (*size >= sizeof(T)) { - *size -= sizeof(T); - std::memcpy(&tmp, *buffer, sizeof(T)); - switch (streamEndianness) { - case SerializeIF::Endianness::BIG: - *object = EndianConverter::convertBigEndian(tmp); - break; - case SerializeIF::Endianness::LITTLE: - *object = EndianConverter::convertLittleEndian(tmp); - break; - default: - case SerializeIF::Endianness::MACHINE: - *object = tmp; - break; - } - - *buffer += sizeof(T); - return HasReturnvaluesIF::RETURN_OK; - } else { - return SerializeIF::STREAM_TOO_SHORT; - } - } - - uint32_t getSerializedSize(const T *object) { - return sizeof(T); - } - }; - - /** - * Template for objects that inherit from SerializeIF - * - * @tparam T A child of SerializeIF - */ - template - class InternalSerializeAdapter { - public: - ReturnValue_t serialize(const T *object, uint8_t **buffer, size_t *size, - size_t max_size, - SerializeIF::Endianness streamEndianness) const { - size_t ignoredSize = 0; - if (size == nullptr) { - size = &ignoredSize; - } - return object->serialize(buffer, size, max_size, streamEndianness); - } - size_t getSerializedSize(const T *object) const { - return object->getSerializedSize(); - } - - ReturnValue_t deSerialize(T *object, const uint8_t **buffer, - size_t *size, SerializeIF::Endianness streamEndianness) { - return object->deSerialize(buffer, size, streamEndianness); - } - }; -}; - -#endif /* _FSFW_SERIALIZE_SERIALIZEADAPTER_H_ */ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 00000000..e4670807 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,18 @@ +target_include_directories(${LIB_FSFW_NAME} PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} +) + +target_include_directories(${LIB_FSFW_NAME} INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR} +) + +add_subdirectory(fsfw) + +# Configure File + +target_include_directories(${LIB_FSFW_NAME} PRIVATE + ${CMAKE_CURRENT_BINARY_DIR} +) +target_include_directories(${LIB_FSFW_NAME} INTERFACE + ${CMAKE_CURRENT_BINARY_DIR} +) diff --git a/src/fsfw/CMakeLists.txt b/src/fsfw/CMakeLists.txt new file mode 100644 index 00000000..7c665e28 --- /dev/null +++ b/src/fsfw/CMakeLists.txt @@ -0,0 +1,55 @@ +# Core + +add_subdirectory(action) +add_subdirectory(container) +add_subdirectory(controller) +add_subdirectory(datapool) +add_subdirectory(datapoollocal) +add_subdirectory(devicehandlers) +add_subdirectory(events) +add_subdirectory(fdir) +add_subdirectory(globalfunctions) +add_subdirectory(health) +add_subdirectory(housekeeping) +add_subdirectory(internalerror) +add_subdirectory(ipc) +add_subdirectory(memory) +add_subdirectory(modes) +add_subdirectory(objectmanager) +add_subdirectory(parameters) +add_subdirectory(power) +add_subdirectory(serialize) +add_subdirectory(serviceinterface) +add_subdirectory(storagemanager) +add_subdirectory(subsystem) +add_subdirectory(tasks) +add_subdirectory(tcdistribution) +add_subdirectory(thermal) +add_subdirectory(timemanager) +add_subdirectory(tmtcpacket) +add_subdirectory(tmtcservices) + +# Optional + +if(FSFW_ADD_MONITORING) +add_subdirectory(monitoring) +endif() +if(FSFW_ADD_PUS) + add_subdirectory(pus) +endif() +if(FSFW_ADD_TMSTORAGE) + add_subdirectory(tmstorage) +endif() +if(FSFW_ADD_COORDINATES) + add_subdirectory(coordinates) +endif() +if(FSFW_ADD_RMAP) + add_subdirectory(rmap) +endif() +if(FSFW_ADD_DATALINKLAYER) + add_subdirectory(datalinklayer) +endif() + +# OSAL + +add_subdirectory(osal) diff --git a/src/fsfw/FSFW.h.in b/src/fsfw/FSFW.h.in new file mode 100644 index 00000000..7e52b646 --- /dev/null +++ b/src/fsfw/FSFW.h.in @@ -0,0 +1,64 @@ +#ifndef FSFW_FSFW_H_ +#define FSFW_FSFW_H_ + +#include "FSFWConfig.h" + +#cmakedefine FSFW_OSAL_RTEMS +#cmakedefine FSFW_OSAL_FREERTOS +#cmakedefine FSFW_OSAL_LINUX +#cmakedefine FSFW_OSAL_HOST + +#cmakedefine FSFW_ADD_RMAP +#cmakedefine FSFW_ADD_DATALINKLAYER +#cmakedefine FSFW_ADD_TMSTORAGE +#cmakedefine FSFW_ADD_COORDINATES +#cmakedefine FSFW_ADD_PUS +#cmakedefine FSFW_ADD_MONITORING +#cmakedefine FSFW_ADD_SGP4_PROPAGATOR + +// FSFW core defines + +#ifndef FSFW_CPP_OSTREAM_ENABLED +#define FSFW_CPP_OSTREAM_ENABLED 1 +#endif /* FSFW_CPP_OSTREAM_ENABLED */ + +#ifndef FSFW_VERBOSE_LEVEL +#define FSFW_VERBOSE_LEVEL 1 +#endif /* FSFW_VERBOSE_LEVEL */ + +#ifndef FSFW_USE_REALTIME_FOR_LINUX +#define FSFW_USE_REALTIME_FOR_LINUX 0 +#endif /* FSFW_USE_REALTIME_FOR_LINUX */ + +#ifndef FSFW_NO_C99_IO +#define FSFW_NO_C99_IO 0 +#endif /* FSFW_NO_C99_IO */ + +#ifndef FSFW_USE_PUS_C_TELEMETRY +#define FSFW_USE_PUS_C_TELEMETRY 1 +#endif /* FSFW_USE_PUS_C_TELEMETRY */ + +#ifndef FSFW_USE_PUS_C_TELECOMMANDS +#define FSFW_USE_PUS_C_TELECOMMANDS 1 +#endif + +// FSFW HAL defines + +// Can be used for low-level debugging of the SPI bus +#ifndef FSFW_HAL_SPI_WIRETAPPING +#define FSFW_HAL_SPI_WIRETAPPING 0 +#endif + +#ifndef FSFW_HAL_L3GD20_GYRO_DEBUG +#define FSFW_HAL_L3GD20_GYRO_DEBUG 0 +#endif /* FSFW_HAL_L3GD20_GYRO_DEBUG */ + +#ifndef FSFW_HAL_RM3100_MGM_DEBUG +#define FSFW_HAL_RM3100_MGM_DEBUG 0 +#endif /* FSFW_HAL_RM3100_MGM_DEBUG */ + +#ifndef FSFW_HAL_LIS3MDL_MGM_DEBUG +#define FSFW_HAL_LIS3MDL_MGM_DEBUG 0 +#endif /* FSFW_HAL_LIS3MDL_MGM_DEBUG */ + +#endif /* FSFW_FSFW_H_ */ diff --git a/src/fsfw/FSFWVersion.h.in b/src/fsfw/FSFWVersion.h.in new file mode 100644 index 00000000..7935b2f6 --- /dev/null +++ b/src/fsfw/FSFWVersion.h.in @@ -0,0 +1,9 @@ +#ifndef FSFW_VERSION_H_ +#define FSFW_VERSION_H_ + +// Versioning is kept in project CMakeLists.txt file +#define FSFW_VERSION @FSFW_VERSION@ +#define FSFW_SUBVERSION @FSFW_SUBVERSION@ +#define FSFW_REVISION @FSFW_REVISION@ + +#endif /* FSFW_VERSION_H_ */ diff --git a/src/fsfw/action.h b/src/fsfw/action.h new file mode 100644 index 00000000..1300cf17 --- /dev/null +++ b/src/fsfw/action.h @@ -0,0 +1,11 @@ +#ifndef FSFW_INC_FSFW_ACTION_H_ +#define FSFW_INC_FSFW_ACTION_H_ + +#include "fsfw/action/ActionHelper.h" +#include "fsfw/action/ActionMessage.h" +#include "fsfw/action/CommandActionHelper.h" +#include "fsfw/action/HasActionsIF.h" +#include "fsfw/action/CommandsActionsIF.h" +#include "fsfw/action/SimpleActionHelper.h" + +#endif /* FSFW_INC_FSFW_ACTION_H_ */ diff --git a/action/ActionHelper.cpp b/src/fsfw/action/ActionHelper.cpp similarity index 90% rename from action/ActionHelper.cpp rename to src/fsfw/action/ActionHelper.cpp index b2374ed6..bebd55a7 100644 --- a/action/ActionHelper.cpp +++ b/src/fsfw/action/ActionHelper.cpp @@ -1,9 +1,8 @@ -#include "ActionHelper.h" -#include "HasActionsIF.h" +#include "fsfw/action.h" -#include "../ipc/MessageQueueSenderIF.h" -#include "../objectmanager/ObjectManagerIF.h" -#include "../serviceinterface/ServiceInterface.h" +#include "fsfw/ipc/MessageQueueSenderIF.h" +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/serviceinterface/ServiceInterface.h" ActionHelper::ActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue) : @@ -25,7 +24,7 @@ ReturnValue_t ActionHelper::handleActionMessage(CommandMessage* command) { } ReturnValue_t ActionHelper::initialize(MessageQueueIF* queueToUse_) { - ipcStore = objectManager->get(objects::IPC_STORE); + ipcStore = ObjectManager::instance()->get(objects::IPC_STORE); if (ipcStore == nullptr) { return HasReturnvaluesIF::RETURN_FAILED; } @@ -33,6 +32,17 @@ ReturnValue_t ActionHelper::initialize(MessageQueueIF* queueToUse_) { setQueueToUse(queueToUse_); } + if(queueToUse == nullptr) { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "ActionHelper::initialize: No queue set" << std::endl; +#else + sif::printWarning("ActionHelper::initialize: No queue set\n"); +#endif +#endif /* FSFW_VERBOSE_LEVEL >= 1 */ + return HasReturnvaluesIF::RETURN_FAILED; + } + return HasReturnvaluesIF::RETURN_OK; } diff --git a/action/ActionHelper.h b/src/fsfw/action/ActionHelper.h similarity index 100% rename from action/ActionHelper.h rename to src/fsfw/action/ActionHelper.h diff --git a/action/ActionMessage.cpp b/src/fsfw/action/ActionMessage.cpp similarity index 90% rename from action/ActionMessage.cpp rename to src/fsfw/action/ActionMessage.cpp index 66c7f058..7d66c57f 100644 --- a/action/ActionMessage.cpp +++ b/src/fsfw/action/ActionMessage.cpp @@ -1,8 +1,7 @@ -#include "ActionMessage.h" -#include "HasActionsIF.h" +#include "fsfw/action.h" -#include "../objectmanager/ObjectManagerIF.h" -#include "../storagemanager/StorageManagerIF.h" +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/storagemanager/StorageManagerIF.h" ActionMessage::ActionMessage() { } @@ -69,7 +68,7 @@ void ActionMessage::clear(CommandMessage* message) { switch(message->getCommand()) { case EXECUTE_ACTION: case DATA_REPLY: { - StorageManagerIF *ipcStore = objectManager->get( + StorageManagerIF *ipcStore = ObjectManager::instance()->get( objects::IPC_STORE); if (ipcStore != NULL) { ipcStore->deleteData(getStoreId(message)); diff --git a/action/ActionMessage.h b/src/fsfw/action/ActionMessage.h similarity index 92% rename from action/ActionMessage.h rename to src/fsfw/action/ActionMessage.h index 0c64588c..c7570c9d 100644 --- a/action/ActionMessage.h +++ b/src/fsfw/action/ActionMessage.h @@ -1,9 +1,9 @@ #ifndef FSFW_ACTION_ACTIONMESSAGE_H_ #define FSFW_ACTION_ACTIONMESSAGE_H_ -#include "../ipc/CommandMessage.h" -#include "../objectmanager/ObjectManagerIF.h" -#include "../storagemanager/StorageManagerIF.h" +#include "fsfw/ipc/CommandMessage.h" +#include "fsfw/objectmanager/ObjectManagerIF.h" +#include "fsfw/storagemanager/StorageManagerIF.h" using ActionId_t = uint32_t; diff --git a/action/CMakeLists.txt b/src/fsfw/action/CMakeLists.txt similarity index 100% rename from action/CMakeLists.txt rename to src/fsfw/action/CMakeLists.txt diff --git a/action/CommandActionHelper.cpp b/src/fsfw/action/CommandActionHelper.cpp similarity index 91% rename from action/CommandActionHelper.cpp rename to src/fsfw/action/CommandActionHelper.cpp index 148b3657..b46dcceb 100644 --- a/action/CommandActionHelper.cpp +++ b/src/fsfw/action/CommandActionHelper.cpp @@ -1,8 +1,6 @@ -#include "ActionMessage.h" -#include "CommandActionHelper.h" -#include "CommandsActionsIF.h" -#include "HasActionsIF.h" -#include "../objectmanager/ObjectManagerIF.h" +#include "fsfw/action.h" + +#include "fsfw/objectmanager/ObjectManager.h" CommandActionHelper::CommandActionHelper(CommandsActionsIF *setOwner) : owner(setOwner), queueToUse(NULL), ipcStore( @@ -14,7 +12,7 @@ CommandActionHelper::~CommandActionHelper() { ReturnValue_t CommandActionHelper::commandAction(object_id_t commandTo, ActionId_t actionId, SerializeIF *data) { - HasActionsIF *receiver = objectManager->get(commandTo); + HasActionsIF *receiver = ObjectManager::instance()->get(commandTo); if (receiver == NULL) { return CommandsActionsIF::OBJECT_HAS_NO_FUNCTIONS; } @@ -40,7 +38,7 @@ ReturnValue_t CommandActionHelper::commandAction(object_id_t commandTo, // if (commandCount != 0) { // return CommandsFunctionsIF::ALREADY_COMMANDING; // } - HasActionsIF *receiver = objectManager->get(commandTo); + HasActionsIF *receiver = ObjectManager::instance()->get(commandTo); if (receiver == NULL) { return CommandsActionsIF::OBJECT_HAS_NO_FUNCTIONS; } @@ -66,7 +64,7 @@ ReturnValue_t CommandActionHelper::sendCommand(MessageQueueId_t queueId, } ReturnValue_t CommandActionHelper::initialize() { - ipcStore = objectManager->get(objects::IPC_STORE); + ipcStore = ObjectManager::instance()->get(objects::IPC_STORE); if (ipcStore == NULL) { return HasReturnvaluesIF::RETURN_FAILED; } diff --git a/action/CommandActionHelper.h b/src/fsfw/action/CommandActionHelper.h similarity index 82% rename from action/CommandActionHelper.h rename to src/fsfw/action/CommandActionHelper.h index 96ef1763..ce297e66 100644 --- a/action/CommandActionHelper.h +++ b/src/fsfw/action/CommandActionHelper.h @@ -2,11 +2,11 @@ #define COMMANDACTIONHELPER_H_ #include "ActionMessage.h" -#include "../objectmanager/ObjectManagerIF.h" -#include "../returnvalues/HasReturnvaluesIF.h" -#include "../serialize/SerializeIF.h" -#include "../storagemanager/StorageManagerIF.h" -#include "../ipc/MessageQueueIF.h" +#include "fsfw/objectmanager/ObjectManagerIF.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" +#include "fsfw/serialize/SerializeIF.h" +#include "fsfw/storagemanager/StorageManagerIF.h" +#include "fsfw/ipc/MessageQueueIF.h" class CommandsActionsIF; diff --git a/action/CommandsActionsIF.h b/src/fsfw/action/CommandsActionsIF.h similarity index 100% rename from action/CommandsActionsIF.h rename to src/fsfw/action/CommandsActionsIF.h diff --git a/action/HasActionsIF.h b/src/fsfw/action/HasActionsIF.h similarity index 100% rename from action/HasActionsIF.h rename to src/fsfw/action/HasActionsIF.h diff --git a/action/SimpleActionHelper.cpp b/src/fsfw/action/SimpleActionHelper.cpp similarity index 97% rename from action/SimpleActionHelper.cpp rename to src/fsfw/action/SimpleActionHelper.cpp index 8d34f40f..7135ea62 100644 --- a/action/SimpleActionHelper.cpp +++ b/src/fsfw/action/SimpleActionHelper.cpp @@ -1,5 +1,4 @@ -#include "HasActionsIF.h" -#include "SimpleActionHelper.h" +#include "fsfw/action.h" SimpleActionHelper::SimpleActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue) : diff --git a/action/SimpleActionHelper.h b/src/fsfw/action/SimpleActionHelper.h similarity index 100% rename from action/SimpleActionHelper.h rename to src/fsfw/action/SimpleActionHelper.h diff --git a/container/ArrayList.h b/src/fsfw/container/ArrayList.h similarity index 100% rename from container/ArrayList.h rename to src/fsfw/container/ArrayList.h diff --git a/container/BinaryTree.h b/src/fsfw/container/BinaryTree.h similarity index 100% rename from container/BinaryTree.h rename to src/fsfw/container/BinaryTree.h diff --git a/container/CMakeLists.txt b/src/fsfw/container/CMakeLists.txt similarity index 100% rename from container/CMakeLists.txt rename to src/fsfw/container/CMakeLists.txt diff --git a/container/DynamicFIFO.h b/src/fsfw/container/DynamicFIFO.h similarity index 100% rename from container/DynamicFIFO.h rename to src/fsfw/container/DynamicFIFO.h diff --git a/container/FIFO.h b/src/fsfw/container/FIFO.h similarity index 100% rename from container/FIFO.h rename to src/fsfw/container/FIFO.h diff --git a/container/FIFOBase.h b/src/fsfw/container/FIFOBase.h similarity index 100% rename from container/FIFOBase.h rename to src/fsfw/container/FIFOBase.h diff --git a/container/FIFOBase.tpp b/src/fsfw/container/FIFOBase.tpp similarity index 100% rename from container/FIFOBase.tpp rename to src/fsfw/container/FIFOBase.tpp diff --git a/container/FixedArrayList.h b/src/fsfw/container/FixedArrayList.h similarity index 100% rename from container/FixedArrayList.h rename to src/fsfw/container/FixedArrayList.h diff --git a/container/FixedMap.h b/src/fsfw/container/FixedMap.h similarity index 100% rename from container/FixedMap.h rename to src/fsfw/container/FixedMap.h diff --git a/container/FixedOrderedMultimap.h b/src/fsfw/container/FixedOrderedMultimap.h similarity index 100% rename from container/FixedOrderedMultimap.h rename to src/fsfw/container/FixedOrderedMultimap.h diff --git a/container/FixedOrderedMultimap.tpp b/src/fsfw/container/FixedOrderedMultimap.tpp similarity index 100% rename from container/FixedOrderedMultimap.tpp rename to src/fsfw/container/FixedOrderedMultimap.tpp diff --git a/container/HybridIterator.h b/src/fsfw/container/HybridIterator.h similarity index 100% rename from container/HybridIterator.h rename to src/fsfw/container/HybridIterator.h diff --git a/container/IndexedRingMemoryArray.h b/src/fsfw/container/IndexedRingMemoryArray.h similarity index 100% rename from container/IndexedRingMemoryArray.h rename to src/fsfw/container/IndexedRingMemoryArray.h diff --git a/container/PlacementFactory.h b/src/fsfw/container/PlacementFactory.h similarity index 100% rename from container/PlacementFactory.h rename to src/fsfw/container/PlacementFactory.h diff --git a/container/RingBufferBase.h b/src/fsfw/container/RingBufferBase.h similarity index 100% rename from container/RingBufferBase.h rename to src/fsfw/container/RingBufferBase.h diff --git a/container/SharedRingBuffer.cpp b/src/fsfw/container/SharedRingBuffer.cpp similarity index 93% rename from container/SharedRingBuffer.cpp rename to src/fsfw/container/SharedRingBuffer.cpp index fe36341d..f7c97802 100644 --- a/container/SharedRingBuffer.cpp +++ b/src/fsfw/container/SharedRingBuffer.cpp @@ -1,6 +1,6 @@ -#include "SharedRingBuffer.h" -#include "../ipc/MutexFactory.h" -#include "../ipc/MutexGuard.h" +#include "fsfw/container/SharedRingBuffer.h" +#include "fsfw/ipc/MutexFactory.h" +#include "fsfw/ipc/MutexGuard.h" SharedRingBuffer::SharedRingBuffer(object_id_t objectId, const size_t size, bool overwriteOld, size_t maxExcessBytes): diff --git a/container/SharedRingBuffer.h b/src/fsfw/container/SharedRingBuffer.h similarity index 96% rename from container/SharedRingBuffer.h rename to src/fsfw/container/SharedRingBuffer.h index 9d6ea56c..26aa45c1 100644 --- a/container/SharedRingBuffer.h +++ b/src/fsfw/container/SharedRingBuffer.h @@ -3,9 +3,10 @@ #include "SimpleRingBuffer.h" #include "DynamicFIFO.h" -#include "../ipc/MutexIF.h" -#include "../objectmanager/SystemObject.h" -#include "../timemanager/Clock.h" + +#include "fsfw/ipc/MutexIF.h" +#include "fsfw/objectmanager/SystemObject.h" +#include "fsfw/timemanager/Clock.h" /** * @brief Ring buffer which can be shared among multiple objects diff --git a/container/SimpleRingBuffer.cpp b/src/fsfw/container/SimpleRingBuffer.cpp similarity index 98% rename from container/SimpleRingBuffer.cpp rename to src/fsfw/container/SimpleRingBuffer.cpp index 8544acbf..8de9cf08 100644 --- a/container/SimpleRingBuffer.cpp +++ b/src/fsfw/container/SimpleRingBuffer.cpp @@ -1,4 +1,5 @@ -#include "SimpleRingBuffer.h" +#include "fsfw/container/SimpleRingBuffer.h" + #include SimpleRingBuffer::SimpleRingBuffer(const size_t size, bool overwriteOld, diff --git a/container/SimpleRingBuffer.h b/src/fsfw/container/SimpleRingBuffer.h similarity index 100% rename from container/SimpleRingBuffer.h rename to src/fsfw/container/SimpleRingBuffer.h diff --git a/container/SinglyLinkedList.h b/src/fsfw/container/SinglyLinkedList.h similarity index 100% rename from container/SinglyLinkedList.h rename to src/fsfw/container/SinglyLinkedList.h diff --git a/container/group.h b/src/fsfw/container/group.h similarity index 100% rename from container/group.h rename to src/fsfw/container/group.h diff --git a/controller/CMakeLists.txt b/src/fsfw/controller/CMakeLists.txt similarity index 100% rename from controller/CMakeLists.txt rename to src/fsfw/controller/CMakeLists.txt diff --git a/controller/ControllerBase.cpp b/src/fsfw/controller/ControllerBase.cpp similarity index 92% rename from controller/ControllerBase.cpp rename to src/fsfw/controller/ControllerBase.cpp index 89f0ff68..86838068 100644 --- a/controller/ControllerBase.cpp +++ b/src/fsfw/controller/ControllerBase.cpp @@ -1,8 +1,9 @@ -#include "ControllerBase.h" +#include "fsfw/controller/ControllerBase.h" -#include "../subsystem/SubsystemBase.h" -#include "../ipc/QueueFactory.h" -#include "../action/HasActionsIF.h" +#include "fsfw/subsystem/SubsystemBase.h" +#include "fsfw/ipc/QueueFactory.h" +#include "fsfw/action/HasActionsIF.h" +#include "fsfw/objectmanager/ObjectManager.h" ControllerBase::ControllerBase(object_id_t setObjectId, object_id_t parentId, size_t commandQueueDepth) : @@ -25,7 +26,7 @@ ReturnValue_t ControllerBase::initialize() { MessageQueueId_t parentQueue = 0; if (parentId != objects::NO_OBJECT) { - SubsystemBase *parent = objectManager->get(parentId); + SubsystemBase *parent = ObjectManager::instance()->get(parentId); if (parent == nullptr) { return RETURN_FAILED; } diff --git a/controller/ControllerBase.h b/src/fsfw/controller/ControllerBase.h similarity index 89% rename from controller/ControllerBase.h rename to src/fsfw/controller/ControllerBase.h index f583342f..1efe0cc1 100644 --- a/controller/ControllerBase.h +++ b/src/fsfw/controller/ControllerBase.h @@ -1,14 +1,14 @@ #ifndef FSFW_CONTROLLER_CONTROLLERBASE_H_ #define FSFW_CONTROLLER_CONTROLLERBASE_H_ -#include "../health/HasHealthIF.h" -#include "../health/HealthHelper.h" -#include "../modes/HasModesIF.h" -#include "../modes/ModeHelper.h" -#include "../objectmanager/SystemObject.h" -#include "../tasks/ExecutableObjectIF.h" -#include "../tasks/PeriodicTaskIF.h" -#include "../datapool/HkSwitchHelper.h" +#include "fsfw/health/HasHealthIF.h" +#include "fsfw/health/HealthHelper.h" +#include "fsfw/modes/HasModesIF.h" +#include "fsfw/modes/ModeHelper.h" +#include "fsfw/objectmanager/SystemObject.h" +#include "fsfw/tasks/ExecutableObjectIF.h" +#include "fsfw/tasks/PeriodicTaskIF.h" +#include "fsfw/datapool/HkSwitchHelper.h" /** * @brief Generic base class for controller classes diff --git a/controller/ExtendedControllerBase.cpp b/src/fsfw/controller/ExtendedControllerBase.cpp similarity index 98% rename from controller/ExtendedControllerBase.cpp rename to src/fsfw/controller/ExtendedControllerBase.cpp index b5b8c660..f59c50a9 100644 --- a/controller/ExtendedControllerBase.cpp +++ b/src/fsfw/controller/ExtendedControllerBase.cpp @@ -1,5 +1,4 @@ -#include "ExtendedControllerBase.h" - +#include "fsfw/controller/ExtendedControllerBase.h" ExtendedControllerBase::ExtendedControllerBase(object_id_t objectId, object_id_t parentId, size_t commandQueueDepth): diff --git a/controller/ExtendedControllerBase.h b/src/fsfw/controller/ExtendedControllerBase.h similarity index 88% rename from controller/ExtendedControllerBase.h rename to src/fsfw/controller/ExtendedControllerBase.h index d5d43933..4172e03e 100644 --- a/controller/ExtendedControllerBase.h +++ b/src/fsfw/controller/ExtendedControllerBase.h @@ -3,10 +3,9 @@ #include "ControllerBase.h" -#include "../action/HasActionsIF.h" -#include "../datapoollocal/HasLocalDataPoolIF.h" -#include "../action/ActionHelper.h" -#include "../datapoollocal/LocalDataPoolManager.h" +#include "fsfw/action.h" +#include "fsfw/datapoollocal/HasLocalDataPoolIF.h" +#include "fsfw/datapoollocal/LocalDataPoolManager.h" /** * @brief Extendes the basic ControllerBase with the common components @@ -66,6 +65,10 @@ protected: virtual ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap, LocalDataPoolManager& poolManager) override = 0; virtual LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override = 0; + + // Mode abstract functions + virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, + uint32_t *msToReachTheMode) override = 0; }; diff --git a/coordinates/CMakeLists.txt b/src/fsfw/coordinates/CMakeLists.txt similarity index 100% rename from coordinates/CMakeLists.txt rename to src/fsfw/coordinates/CMakeLists.txt diff --git a/coordinates/CoordinateTransformations.cpp b/src/fsfw/coordinates/CoordinateTransformations.cpp similarity index 94% rename from coordinates/CoordinateTransformations.cpp rename to src/fsfw/coordinates/CoordinateTransformations.cpp index 4e2debbe..fe879dd1 100644 --- a/coordinates/CoordinateTransformations.cpp +++ b/src/fsfw/coordinates/CoordinateTransformations.cpp @@ -1,8 +1,9 @@ -#include "CoordinateTransformations.h" -#include "../globalfunctions/constants.h" -#include "../globalfunctions/math/MatrixOperations.h" -#include "../globalfunctions/math/VectorOperations.h" -#include +#include "fsfw/coordinates/CoordinateTransformations.h" +#include "fsfw/globalfunctions/constants.h" +#include "fsfw/globalfunctions/math/MatrixOperations.h" +#include "fsfw/globalfunctions/math/VectorOperations.h" + +#include #include @@ -17,11 +18,13 @@ void CoordinateTransformations::velocityEcfToEci(const double* ecfVelocity, ecfToEci(ecfVelocity, eciVelocity, ecfPosition, timeUTC); } -void CoordinateTransformations::positionEciToEcf(const double* eciCoordinates, double* ecfCoordinates,timeval *timeUTC){ +void CoordinateTransformations::positionEciToEcf(const double* eciCoordinates, + double* ecfCoordinates,timeval *timeUTC){ eciToEcf(eciCoordinates,ecfCoordinates,NULL,timeUTC); }; -void CoordinateTransformations::velocityEciToEcf(const double* eciVelocity,const double* eciPosition, double* ecfVelocity,timeval* timeUTC){ +void CoordinateTransformations::velocityEciToEcf(const double* eciVelocity, + const double* eciPosition, double* ecfVelocity,timeval* timeUTC){ eciToEcf(eciVelocity,ecfVelocity,eciPosition,timeUTC); } diff --git a/coordinates/CoordinateTransformations.h b/src/fsfw/coordinates/CoordinateTransformations.h similarity index 95% rename from coordinates/CoordinateTransformations.h rename to src/fsfw/coordinates/CoordinateTransformations.h index 09ea2c48..ddc715d1 100644 --- a/coordinates/CoordinateTransformations.h +++ b/src/fsfw/coordinates/CoordinateTransformations.h @@ -1,7 +1,8 @@ #ifndef COORDINATETRANSFORMATIONS_H_ #define COORDINATETRANSFORMATIONS_H_ -#include "../timemanager/Clock.h" +#include "coordinatesConf.h" +#include "fsfw/timemanager/Clock.h" #include class CoordinateTransformations { diff --git a/coordinates/Jgm3Model.h b/src/fsfw/coordinates/Jgm3Model.h similarity index 96% rename from coordinates/Jgm3Model.h rename to src/fsfw/coordinates/Jgm3Model.h index 884ed141..0eeaf08f 100644 --- a/coordinates/Jgm3Model.h +++ b/src/fsfw/coordinates/Jgm3Model.h @@ -1,13 +1,14 @@ #ifndef FRAMEWORK_COORDINATES_JGM3MODEL_H_ #define FRAMEWORK_COORDINATES_JGM3MODEL_H_ -#include +#include "coordinatesConf.h" #include "CoordinateTransformations.h" -#include "../globalfunctions/math/VectorOperations.h" -#include "../globalfunctions/timevalOperations.h" -#include "../globalfunctions/constants.h" -#include +#include "fsfw/globalfunctions/math/VectorOperations.h" +#include "fsfw/globalfunctions/timevalOperations.h" +#include "fsfw/globalfunctions/constants.h" +#include +#include template class Jgm3Model { diff --git a/coordinates/Sgp4Propagator.cpp b/src/fsfw/coordinates/Sgp4Propagator.cpp similarity index 95% rename from coordinates/Sgp4Propagator.cpp rename to src/fsfw/coordinates/Sgp4Propagator.cpp index 5cb1497c..a0e66ebd 100644 --- a/coordinates/Sgp4Propagator.cpp +++ b/src/fsfw/coordinates/Sgp4Propagator.cpp @@ -1,10 +1,13 @@ -#include "CoordinateTransformations.h" -#include "Sgp4Propagator.h" -#include "../globalfunctions/constants.h" -#include "../globalfunctions/math/MatrixOperations.h" -#include "../globalfunctions/math/VectorOperations.h" -#include "../globalfunctions/timevalOperations.h" +#include "fsfw/coordinates/CoordinateTransformations.h" +#include "fsfw/coordinates/Sgp4Propagator.h" + +#include "fsfw/globalfunctions/constants.h" +#include "fsfw/globalfunctions/math/MatrixOperations.h" +#include "fsfw/globalfunctions/math/VectorOperations.h" +#include "fsfw/globalfunctions/timevalOperations.h" + #include + Sgp4Propagator::Sgp4Propagator() : initialized(false), epoch({0, 0}), whichconst(wgs84) { diff --git a/coordinates/Sgp4Propagator.h b/src/fsfw/coordinates/Sgp4Propagator.h similarity index 88% rename from coordinates/Sgp4Propagator.h rename to src/fsfw/coordinates/Sgp4Propagator.h index f813c6f4..7c7a0a8c 100644 --- a/coordinates/Sgp4Propagator.h +++ b/src/fsfw/coordinates/Sgp4Propagator.h @@ -1,11 +1,14 @@ #ifndef SGP4PROPAGATOR_H_ #define SGP4PROPAGATOR_H_ -#ifndef WIN32 +#include "coordinatesConf.h" +#include "fsfw/platform.h" + +#ifndef PLATFORM_WIN #include #endif -#include "../contrib/sgp4/sgp4unit.h" -#include "../returnvalues/HasReturnvaluesIF.h" +#include "fsfw_contrib/sgp4/sgp4unit.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" class Sgp4Propagator { public: diff --git a/src/fsfw/coordinates/coordinatesConf.h b/src/fsfw/coordinates/coordinatesConf.h new file mode 100644 index 00000000..9c1c3754 --- /dev/null +++ b/src/fsfw/coordinates/coordinatesConf.h @@ -0,0 +1,16 @@ +#ifndef FSFW_SRC_FSFW_COORDINATES_COORDINATESCONF_H_ +#define FSFW_SRC_FSFW_COORDINATES_COORDINATESCONF_H_ + +#include "fsfw/FSFW.h" + +#ifndef FSFW_ADD_COORDINATES +#warning Coordinates files were included but compilation was \ + not enabled with FSFW_ADD_COORDINATES +#endif + +#ifndef FSFW_ADD_SGP4_PROPAGATOR +#warning Coordinates files were included but SGP4 contributed code compilation was \ + not enabled with FSFW_ADD_SGP4_PROPAGATOR +#endif + +#endif /* FSFW_SRC_FSFW_COORDINATES_COORDINATESCONF_H_ */ diff --git a/datalinklayer/BCFrame.h b/src/fsfw/datalinklayer/BCFrame.h similarity index 98% rename from datalinklayer/BCFrame.h rename to src/fsfw/datalinklayer/BCFrame.h index b7795556..9cedd41b 100644 --- a/datalinklayer/BCFrame.h +++ b/src/fsfw/datalinklayer/BCFrame.h @@ -8,6 +8,7 @@ #ifndef BCFRAME_H_ #define BCFRAME_H_ +#include "dllConf.h" #include "CCSDSReturnValuesIF.h" /** diff --git a/datalinklayer/CCSDSReturnValuesIF.h b/src/fsfw/datalinklayer/CCSDSReturnValuesIF.h similarity index 98% rename from datalinklayer/CCSDSReturnValuesIF.h rename to src/fsfw/datalinklayer/CCSDSReturnValuesIF.h index 805b6969..a31f9ced 100644 --- a/datalinklayer/CCSDSReturnValuesIF.h +++ b/src/fsfw/datalinklayer/CCSDSReturnValuesIF.h @@ -8,7 +8,8 @@ #ifndef CCSDSRETURNVALUESIF_H_ #define CCSDSRETURNVALUESIF_H_ -#include "../returnvalues/HasReturnvaluesIF.h" +#include "dllConf.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" /** * This is a helper class to collect special return values that come up during CCSDS Handling. * @ingroup ccsds_handling diff --git a/datalinklayer/CMakeLists.txt b/src/fsfw/datalinklayer/CMakeLists.txt similarity index 100% rename from datalinklayer/CMakeLists.txt rename to src/fsfw/datalinklayer/CMakeLists.txt diff --git a/datalinklayer/Clcw.cpp b/src/fsfw/datalinklayer/Clcw.cpp similarity index 88% rename from datalinklayer/Clcw.cpp rename to src/fsfw/datalinklayer/Clcw.cpp index 13971929..9f2fe7d3 100644 --- a/datalinklayer/Clcw.cpp +++ b/src/fsfw/datalinklayer/Clcw.cpp @@ -1,14 +1,5 @@ -/** - * @file Clcw.cpp - * @brief This file defines the Clcw class. - * @date 17.04.2013 - * @author baetz - */ - - - -#include "Clcw.h" -#include "../serviceinterface/ServiceInterfaceStream.h" +#include "fsfw/datalinklayer/Clcw.h" +#include "fsfw/serviceinterface/ServiceInterface.h" Clcw::Clcw() { content.raw = 0; diff --git a/datalinklayer/Clcw.h b/src/fsfw/datalinklayer/Clcw.h similarity index 95% rename from datalinklayer/Clcw.h rename to src/fsfw/datalinklayer/Clcw.h index 8116d63b..aa1ee35b 100644 --- a/datalinklayer/Clcw.h +++ b/src/fsfw/datalinklayer/Clcw.h @@ -1,14 +1,9 @@ -/** - * @file Clcw.h - * @brief This file defines the Clcw class. - * @date 17.04.2013 - * @author baetz - */ - #ifndef CLCW_H_ #define CLCW_H_ +#include "dllConf.h" #include "ClcwIF.h" + /** * Small helper method to handle the Clcw values. * It has a content struct that manages the register and can be set externally. diff --git a/datalinklayer/ClcwIF.h b/src/fsfw/datalinklayer/ClcwIF.h similarity index 100% rename from datalinklayer/ClcwIF.h rename to src/fsfw/datalinklayer/ClcwIF.h diff --git a/datalinklayer/DataLinkLayer.cpp b/src/fsfw/datalinklayer/DataLinkLayer.cpp similarity index 97% rename from datalinklayer/DataLinkLayer.cpp rename to src/fsfw/datalinklayer/DataLinkLayer.cpp index 1bdaa4f5..94199bc4 100644 --- a/datalinklayer/DataLinkLayer.cpp +++ b/src/fsfw/datalinklayer/DataLinkLayer.cpp @@ -1,6 +1,6 @@ -#include "DataLinkLayer.h" -#include "../globalfunctions/CRC.h" -#include "../serviceinterface/ServiceInterfaceStream.h" +#include "fsfw/datalinklayer/DataLinkLayer.h" +#include "fsfw/globalfunctions/CRC.h" +#include "fsfw/serviceinterface/ServiceInterface.h" DataLinkLayer::DataLinkLayer(uint8_t* set_frame_buffer, ClcwIF* setClcw, uint8_t set_start_sequence_length, uint16_t set_scid) : diff --git a/datalinklayer/DataLinkLayer.h b/src/fsfw/datalinklayer/DataLinkLayer.h similarity index 89% rename from datalinklayer/DataLinkLayer.h rename to src/fsfw/datalinklayer/DataLinkLayer.h index 17a57d61..9c2a2952 100644 --- a/datalinklayer/DataLinkLayer.h +++ b/src/fsfw/datalinklayer/DataLinkLayer.h @@ -1,11 +1,13 @@ #ifndef DATALINKLAYER_H_ #define DATALINKLAYER_H_ +#include "dllConf.h" #include "CCSDSReturnValuesIF.h" #include "ClcwIF.h" #include "TcTransferFrame.h" #include "VirtualChannelReceptionIF.h" -#include "../events/Event.h" +#include "fsfw/events/Event.h" + #include @@ -19,12 +21,18 @@ class VirtualChannelReception; class DataLinkLayer : public CCSDSReturnValuesIF { public: static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::SYSTEM_1; - static const Event RF_AVAILABLE = MAKE_EVENT(0, severity::INFO); //!< A RF available signal was detected. P1: raw RFA state, P2: 0 - static const Event RF_LOST = MAKE_EVENT(1, severity::INFO); //!< A previously found RF available signal was lost. P1: raw RFA state, P2: 0 - static const Event BIT_LOCK = MAKE_EVENT(2, severity::INFO); //!< A Bit Lock signal. Was detected. P1: raw BLO state, P2: 0 - static const Event BIT_LOCK_LOST = MAKE_EVENT(3, severity::INFO); //!< A previously found Bit Lock signal was lost. P1: raw BLO state, P2: 0 + //! [EXPORT] : [COMMENT] A RF available signal was detected. P1: raw RFA state, P2: 0 + static const Event RF_AVAILABLE = MAKE_EVENT(0, severity::INFO); + //! [EXPORT] : [COMMENT] A previously found RF available signal was lost. + //! P1: raw RFA state, P2: 0 + static const Event RF_LOST = MAKE_EVENT(1, severity::INFO); + //! [EXPORT] : [COMMENT] A Bit Lock signal. Was detected. P1: raw BLO state, P2: 0 + static const Event BIT_LOCK = MAKE_EVENT(2, severity::INFO); + //! [EXPORT] : [COMMENT] A previously found Bit Lock signal was lost. P1: raw BLO state, P2: 0 + static const Event BIT_LOCK_LOST = MAKE_EVENT(3, severity::INFO); // static const Event RF_CHAIN_LOST = MAKE_EVENT(4, severity::INFO); //!< The CCSDS Board detected that either bit lock or RF available or both are lost. No parameters. - static const Event FRAME_PROCESSING_FAILED = MAKE_EVENT(5, severity::LOW); //!< The CCSDS Board could not interpret a TC + //! [EXPORT] : [COMMENT] The CCSDS Board could not interpret a TC + static const Event FRAME_PROCESSING_FAILED = MAKE_EVENT(5, severity::LOW); /** * The Constructor sets the passed parameters and nothing else. * @param set_frame_buffer The buffer in which incoming frame candidates are stored. diff --git a/datalinklayer/Farm1StateIF.h b/src/fsfw/datalinklayer/Farm1StateIF.h similarity index 98% rename from datalinklayer/Farm1StateIF.h rename to src/fsfw/datalinklayer/Farm1StateIF.h index 71794d75..7e1ba2ec 100644 --- a/datalinklayer/Farm1StateIF.h +++ b/src/fsfw/datalinklayer/Farm1StateIF.h @@ -8,7 +8,9 @@ #ifndef FARM1STATEIF_H_ #define FARM1STATEIF_H_ +#include "dllConf.h" #include "CCSDSReturnValuesIF.h" + class VirtualChannelReception; class TcTransferFrame; class ClcwIF; diff --git a/datalinklayer/Farm1StateLockout.cpp b/src/fsfw/datalinklayer/Farm1StateLockout.cpp similarity index 70% rename from datalinklayer/Farm1StateLockout.cpp rename to src/fsfw/datalinklayer/Farm1StateLockout.cpp index 1b339a85..b74d0a5f 100644 --- a/datalinklayer/Farm1StateLockout.cpp +++ b/src/fsfw/datalinklayer/Farm1StateLockout.cpp @@ -1,16 +1,8 @@ -/** - * @file Farm1StateLockout.cpp - * @brief This file defines the Farm1StateLockout class. - * @date 24.04.2013 - * @author baetz - */ +#include "fsfw/datalinklayer/ClcwIF.h" +#include "fsfw/datalinklayer/Farm1StateLockout.h" +#include "fsfw/datalinklayer/TcTransferFrame.h" +#include "fsfw/datalinklayer/VirtualChannelReception.h" - - -#include "ClcwIF.h" -#include "Farm1StateLockout.h" -#include "TcTransferFrame.h" -#include "VirtualChannelReception.h" Farm1StateLockout::Farm1StateLockout(VirtualChannelReception* setMyVC) : myVC(setMyVC) { } diff --git a/datalinklayer/Farm1StateLockout.h b/src/fsfw/datalinklayer/Farm1StateLockout.h similarity index 93% rename from datalinklayer/Farm1StateLockout.h rename to src/fsfw/datalinklayer/Farm1StateLockout.h index 63cdc4d2..a039c89b 100644 --- a/datalinklayer/Farm1StateLockout.h +++ b/src/fsfw/datalinklayer/Farm1StateLockout.h @@ -1,13 +1,7 @@ -/** - * @file Farm1StateLockout.h - * @brief This file defines the Farm1StateLockout class. - * @date 24.04.2013 - * @author baetz - */ - #ifndef FARM1STATELOCKOUT_H_ #define FARM1STATELOCKOUT_H_ +#include "dllConf.h" #include "Farm1StateIF.h" /** diff --git a/datalinklayer/Farm1StateOpen.cpp b/src/fsfw/datalinklayer/Farm1StateOpen.cpp similarity index 79% rename from datalinklayer/Farm1StateOpen.cpp rename to src/fsfw/datalinklayer/Farm1StateOpen.cpp index 61c0997f..6f91df47 100644 --- a/datalinklayer/Farm1StateOpen.cpp +++ b/src/fsfw/datalinklayer/Farm1StateOpen.cpp @@ -1,17 +1,7 @@ -/** - * @file Farm1StateOpen.cpp - * @brief This file defines the Farm1StateOpen class. - * @date 24.04.2013 - * @author baetz - */ - - - - -#include "ClcwIF.h" -#include "Farm1StateOpen.h" -#include "TcTransferFrame.h" -#include "VirtualChannelReception.h" +#include "fsfw/datalinklayer/ClcwIF.h" +#include "fsfw/datalinklayer/Farm1StateOpen.h" +#include "fsfw/datalinklayer/TcTransferFrame.h" +#include "fsfw/datalinklayer/VirtualChannelReception.h" Farm1StateOpen::Farm1StateOpen(VirtualChannelReception* setMyVC) : myVC(setMyVC) { } diff --git a/datalinklayer/Farm1StateOpen.h b/src/fsfw/datalinklayer/Farm1StateOpen.h similarity index 99% rename from datalinklayer/Farm1StateOpen.h rename to src/fsfw/datalinklayer/Farm1StateOpen.h index 3b3a2604..c5506e7a 100644 --- a/datalinklayer/Farm1StateOpen.h +++ b/src/fsfw/datalinklayer/Farm1StateOpen.h @@ -8,6 +8,7 @@ #ifndef FARM1STATEOPEN_H_ #define FARM1STATEOPEN_H_ +#include "dllConf.h" #include "Farm1StateIF.h" /** diff --git a/datalinklayer/Farm1StateWait.cpp b/src/fsfw/datalinklayer/Farm1StateWait.cpp similarity index 78% rename from datalinklayer/Farm1StateWait.cpp rename to src/fsfw/datalinklayer/Farm1StateWait.cpp index 9001e1f5..8d3f97fc 100644 --- a/datalinklayer/Farm1StateWait.cpp +++ b/src/fsfw/datalinklayer/Farm1StateWait.cpp @@ -1,15 +1,7 @@ -/** - * @file Farm1StateWait.cpp - * @brief This file defines the Farm1StateWait class. - * @date 24.04.2013 - * @author baetz - */ - - -#include "ClcwIF.h" -#include "Farm1StateWait.h" -#include "TcTransferFrame.h" -#include "VirtualChannelReception.h" +#include "fsfw/datalinklayer/ClcwIF.h" +#include "fsfw/datalinklayer/Farm1StateWait.h" +#include "fsfw/datalinklayer/TcTransferFrame.h" +#include "fsfw/datalinklayer/VirtualChannelReception.h" Farm1StateWait::Farm1StateWait(VirtualChannelReception* setMyVC) : myVC(setMyVC) { } diff --git a/datalinklayer/Farm1StateWait.h b/src/fsfw/datalinklayer/Farm1StateWait.h similarity index 98% rename from datalinklayer/Farm1StateWait.h rename to src/fsfw/datalinklayer/Farm1StateWait.h index 877c36c2..76704fdb 100644 --- a/datalinklayer/Farm1StateWait.h +++ b/src/fsfw/datalinklayer/Farm1StateWait.h @@ -8,6 +8,7 @@ #ifndef FARM1STATEWAIT_H_ #define FARM1STATEWAIT_H_ +#include "dllConf.h" #include "Farm1StateIF.h" /** diff --git a/datalinklayer/MapPacketExtraction.cpp b/src/fsfw/datalinklayer/MapPacketExtraction.cpp similarity index 88% rename from datalinklayer/MapPacketExtraction.cpp rename to src/fsfw/datalinklayer/MapPacketExtraction.cpp index cdc9ae27..7d06695a 100644 --- a/datalinklayer/MapPacketExtraction.cpp +++ b/src/fsfw/datalinklayer/MapPacketExtraction.cpp @@ -1,10 +1,13 @@ -#include "MapPacketExtraction.h" -#include "../ipc/QueueFactory.h" -#include "../serviceinterface/ServiceInterfaceStream.h" -#include "../storagemanager/StorageManagerIF.h" -#include "../tmtcpacket/SpacePacketBase.h" -#include "../tmtcservices/AcceptsTelecommandsIF.h" -#include "../tmtcservices/TmTcMessage.h" +#include "fsfw/datalinklayer/MapPacketExtraction.h" + +#include "fsfw/ipc/QueueFactory.h" +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/storagemanager/StorageManagerIF.h" +#include "fsfw/tmtcpacket/SpacePacketBase.h" +#include "fsfw/tmtcservices/AcceptsTelecommandsIF.h" +#include "fsfw/tmtcservices/TmTcMessage.h" +#include "fsfw/objectmanager/ObjectManager.h" + #include MapPacketExtraction::MapPacketExtraction(uint8_t setMapId, @@ -131,9 +134,9 @@ void MapPacketExtraction::clearBuffers() { } ReturnValue_t MapPacketExtraction::initialize() { - packetStore = objectManager->get(objects::TC_STORE); - AcceptsTelecommandsIF* distributor = objectManager->get< - AcceptsTelecommandsIF>(packetDestination); + packetStore = ObjectManager::instance()->get(objects::TC_STORE); + AcceptsTelecommandsIF* distributor = ObjectManager::instance()-> + get(packetDestination); if ((packetStore != NULL) && (distributor != NULL)) { tcQueueId = distributor->getRequestQueue(); return RETURN_OK; diff --git a/datalinklayer/MapPacketExtraction.h b/src/fsfw/datalinklayer/MapPacketExtraction.h similarity index 94% rename from datalinklayer/MapPacketExtraction.h rename to src/fsfw/datalinklayer/MapPacketExtraction.h index ddb867fb..30552a8e 100644 --- a/datalinklayer/MapPacketExtraction.h +++ b/src/fsfw/datalinklayer/MapPacketExtraction.h @@ -1,10 +1,11 @@ #ifndef FSFW_DATALINKLAYER_MAPPACKETEXTRACTION_H_ #define FSFW_DATALINKLAYER_MAPPACKETEXTRACTION_H_ +#include "dllConf.h" #include "MapPacketExtractionIF.h" -#include "../objectmanager/ObjectManagerIF.h" -#include "../returnvalues/HasReturnvaluesIF.h" -#include "../ipc/MessageQueueSenderIF.h" +#include "fsfw/objectmanager/ObjectManagerIF.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" +#include "fsfw/ipc/MessageQueueSenderIF.h" class StorageManagerIF; diff --git a/datalinklayer/MapPacketExtractionIF.h b/src/fsfw/datalinklayer/MapPacketExtractionIF.h similarity index 98% rename from datalinklayer/MapPacketExtractionIF.h rename to src/fsfw/datalinklayer/MapPacketExtractionIF.h index e29ac666..7f8a60af 100644 --- a/datalinklayer/MapPacketExtractionIF.h +++ b/src/fsfw/datalinklayer/MapPacketExtractionIF.h @@ -8,6 +8,7 @@ #ifndef MAPPACKETEXTRACTIONIF_H_ #define MAPPACKETEXTRACTIONIF_H_ +#include "dllConf.h" #include "CCSDSReturnValuesIF.h" #include "TcTransferFrame.h" diff --git a/datalinklayer/TcTransferFrame.cpp b/src/fsfw/datalinklayer/TcTransferFrame.cpp similarity index 92% rename from datalinklayer/TcTransferFrame.cpp rename to src/fsfw/datalinklayer/TcTransferFrame.cpp index ee094dc3..42ccf7ca 100644 --- a/datalinklayer/TcTransferFrame.cpp +++ b/src/fsfw/datalinklayer/TcTransferFrame.cpp @@ -1,17 +1,8 @@ -/** - * @file TcTransferFrame.cpp - * @brief This file defines the TcTransferFrame class. - * @date 27.04.2013 - * @author baetz - */ - - - -#include "TcTransferFrame.h" -#include "../serviceinterface/ServiceInterfaceStream.h" +#include "fsfw/datalinklayer/TcTransferFrame.h" +#include "fsfw/serviceinterface/ServiceInterface.h" TcTransferFrame::TcTransferFrame() { - frame = NULL; + frame = nullptr; } TcTransferFrame::TcTransferFrame(uint8_t* setData) { diff --git a/datalinklayer/TcTransferFrame.h b/src/fsfw/datalinklayer/TcTransferFrame.h similarity index 98% rename from datalinklayer/TcTransferFrame.h rename to src/fsfw/datalinklayer/TcTransferFrame.h index b58441fc..9d4f6349 100644 --- a/datalinklayer/TcTransferFrame.h +++ b/src/fsfw/datalinklayer/TcTransferFrame.h @@ -1,8 +1,10 @@ #ifndef TCTRANSFERFRAME_H_ #define TCTRANSFERFRAME_H_ -#include -#include +#include "dllConf.h" + +#include +#include /** * The TcTransferFrame class simplifies handling of such Frames. diff --git a/datalinklayer/TcTransferFrameLocal.cpp b/src/fsfw/datalinklayer/TcTransferFrameLocal.cpp similarity index 83% rename from datalinklayer/TcTransferFrameLocal.cpp rename to src/fsfw/datalinklayer/TcTransferFrameLocal.cpp index de8f568f..f88f79e2 100644 --- a/datalinklayer/TcTransferFrameLocal.cpp +++ b/src/fsfw/datalinklayer/TcTransferFrameLocal.cpp @@ -1,14 +1,8 @@ -/** - * @file TcTransferFrameLocal.cpp - * @brief This file defines the TcTransferFrameLocal class. - * @date 27.04.2013 - * @author baetz - */ +#include "fsfw/datalinklayer/TcTransferFrameLocal.h" +#include "fsfw/globalfunctions/CRC.h" +#include "fsfw/serviceinterface/ServiceInterface.h" -#include "TcTransferFrameLocal.h" -#include "../globalfunctions/CRC.h" -#include "../serviceinterface/ServiceInterfaceStream.h" -#include +#include TcTransferFrameLocal::TcTransferFrameLocal(bool bypass, bool controlCommand, uint16_t scid, uint8_t vcId, uint8_t sequenceNumber, uint8_t setSegmentHeader, uint8_t* data, uint16_t dataSize, uint16_t forceCrc) { @@ -38,7 +32,7 @@ TcTransferFrameLocal::TcTransferFrameLocal(bool bypass, bool controlCommand, uin this->getFullFrame()[getFullSize()-1] = (crc & 0x00FF); } else { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::debug << "TcTransferFrameLocal: dataSize too large: " << dataSize << std::endl; + sif::warning << "TcTransferFrameLocal: dataSize too large: " << dataSize << std::endl; #endif } } else { diff --git a/datalinklayer/TcTransferFrameLocal.h b/src/fsfw/datalinklayer/TcTransferFrameLocal.h similarity index 98% rename from datalinklayer/TcTransferFrameLocal.h rename to src/fsfw/datalinklayer/TcTransferFrameLocal.h index 487d8940..f2bf3275 100644 --- a/datalinklayer/TcTransferFrameLocal.h +++ b/src/fsfw/datalinklayer/TcTransferFrameLocal.h @@ -8,6 +8,7 @@ #ifndef TCTRANSFERFRAMELOCAL_H_ #define TCTRANSFERFRAMELOCAL_H_ +#include "dllConf.h" #include "TcTransferFrame.h" /** diff --git a/datalinklayer/VirtualChannelReception.cpp b/src/fsfw/datalinklayer/VirtualChannelReception.cpp similarity index 96% rename from datalinklayer/VirtualChannelReception.cpp rename to src/fsfw/datalinklayer/VirtualChannelReception.cpp index 3a56fe1e..e0a88e8e 100644 --- a/datalinklayer/VirtualChannelReception.cpp +++ b/src/fsfw/datalinklayer/VirtualChannelReception.cpp @@ -5,9 +5,9 @@ * @author baetz */ -#include "BCFrame.h" -#include "VirtualChannelReception.h" -#include "../serviceinterface/ServiceInterfaceStream.h" +#include "fsfw/datalinklayer/BCFrame.h" +#include "fsfw/datalinklayer/VirtualChannelReception.h" +#include "fsfw/serviceinterface/ServiceInterface.h" VirtualChannelReception::VirtualChannelReception(uint8_t setChannelId, uint8_t setSlidingWindowWidth) : diff --git a/datalinklayer/VirtualChannelReception.h b/src/fsfw/datalinklayer/VirtualChannelReception.h similarity index 99% rename from datalinklayer/VirtualChannelReception.h rename to src/fsfw/datalinklayer/VirtualChannelReception.h index 9b4e2987..314e18ec 100644 --- a/datalinklayer/VirtualChannelReception.h +++ b/src/fsfw/datalinklayer/VirtualChannelReception.h @@ -8,6 +8,7 @@ #ifndef VIRTUALCHANNELRECEPTION_H_ #define VIRTUALCHANNELRECEPTION_H_ +#include "dllConf.h" #include "CCSDSReturnValuesIF.h" #include "Clcw.h" #include "Farm1StateIF.h" @@ -16,6 +17,7 @@ #include "Farm1StateWait.h" #include "MapPacketExtractionIF.h" #include "VirtualChannelReceptionIF.h" + #include /** * Implementation of a TC Virtual Channel. diff --git a/datalinklayer/VirtualChannelReceptionIF.h b/src/fsfw/datalinklayer/VirtualChannelReceptionIF.h similarity index 95% rename from datalinklayer/VirtualChannelReceptionIF.h rename to src/fsfw/datalinklayer/VirtualChannelReceptionIF.h index 36f60e8c..e7a21b3c 100644 --- a/datalinklayer/VirtualChannelReceptionIF.h +++ b/src/fsfw/datalinklayer/VirtualChannelReceptionIF.h @@ -8,9 +8,10 @@ #ifndef VIRTUALCHANNELRECEPTIONIF_H_ #define VIRTUALCHANNELRECEPTIONIF_H_ +#include "dllConf.h" #include "ClcwIF.h" #include "TcTransferFrame.h" -#include "../returnvalues/HasReturnvaluesIF.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" /** * This is the interface for Virtual Channel reception classes. diff --git a/src/fsfw/datalinklayer/dllConf.h b/src/fsfw/datalinklayer/dllConf.h new file mode 100644 index 00000000..dce63ff0 --- /dev/null +++ b/src/fsfw/datalinklayer/dllConf.h @@ -0,0 +1,11 @@ +#ifndef FSFW_SRC_FSFW_DATALINKLAYER_DLLCONF_H_ +#define FSFW_SRC_FSFW_DATALINKLAYER_DLLCONF_H_ + +#include "fsfw/FSFW.h" + +#ifndef FSFW_ADD_DATALINKLAYER +#warning Datalinklayer files were included but compilation was \ + not enabled with FSFW_ADD_DATALINKLAYER +#endif + +#endif /* FSFW_SRC_FSFW_DATALINKLAYER_DLLCONF_H_ */ diff --git a/datapool/CMakeLists.txt b/src/fsfw/datapool/CMakeLists.txt similarity index 100% rename from datapool/CMakeLists.txt rename to src/fsfw/datapool/CMakeLists.txt diff --git a/datapool/DataSetIF.h b/src/fsfw/datapool/DataSetIF.h similarity index 100% rename from datapool/DataSetIF.h rename to src/fsfw/datapool/DataSetIF.h diff --git a/datapool/HkSwitchHelper.cpp b/src/fsfw/datapool/HkSwitchHelper.cpp similarity index 96% rename from datapool/HkSwitchHelper.cpp rename to src/fsfw/datapool/HkSwitchHelper.cpp index 21e37f59..bcf237ba 100644 --- a/datapool/HkSwitchHelper.cpp +++ b/src/fsfw/datapool/HkSwitchHelper.cpp @@ -1,5 +1,5 @@ -#include "../datapool/HkSwitchHelper.h" -#include "../ipc/QueueFactory.h" +#include "fsfw/datapool/HkSwitchHelper.h" +#include "fsfw/ipc/QueueFactory.h" HkSwitchHelper::HkSwitchHelper(EventReportingProxyIF* eventProxy) : commandActionHelper(this), eventProxy(eventProxy) { diff --git a/datapool/HkSwitchHelper.h b/src/fsfw/datapool/HkSwitchHelper.h similarity index 91% rename from datapool/HkSwitchHelper.h rename to src/fsfw/datapool/HkSwitchHelper.h index bb9e7dc6..611c5d86 100644 --- a/datapool/HkSwitchHelper.h +++ b/src/fsfw/datapool/HkSwitchHelper.h @@ -1,9 +1,9 @@ #ifndef FRAMEWORK_DATAPOOL_HKSWITCHHELPER_H_ #define FRAMEWORK_DATAPOOL_HKSWITCHHELPER_H_ -#include "../tasks/ExecutableObjectIF.h" -#include "../action/CommandsActionsIF.h" -#include "../events/EventReportingProxyIF.h" +#include "fsfw/tasks/ExecutableObjectIF.h" +#include "fsfw/action/CommandsActionsIF.h" +#include "fsfw/events/EventReportingProxyIF.h" //TODO this class violations separation between mission and framework //but it is only a transitional solution until the Datapool is diff --git a/datapool/PoolDataSetBase.cpp b/src/fsfw/datapool/PoolDataSetBase.cpp similarity index 98% rename from datapool/PoolDataSetBase.cpp rename to src/fsfw/datapool/PoolDataSetBase.cpp index 1bd58698..7856dc9a 100644 --- a/datapool/PoolDataSetBase.cpp +++ b/src/fsfw/datapool/PoolDataSetBase.cpp @@ -1,7 +1,7 @@ -#include "PoolDataSetBase.h" -#include "ReadCommitIFAttorney.h" +#include "fsfw/datapool/PoolDataSetBase.h" +#include "fsfw/datapool/ReadCommitIFAttorney.h" -#include "../serviceinterface/ServiceInterface.h" +#include "fsfw/serviceinterface/ServiceInterface.h" #include diff --git a/datapool/PoolDataSetBase.h b/src/fsfw/datapool/PoolDataSetBase.h similarity index 99% rename from datapool/PoolDataSetBase.h rename to src/fsfw/datapool/PoolDataSetBase.h index 043c860a..36cf2a30 100644 --- a/datapool/PoolDataSetBase.h +++ b/src/fsfw/datapool/PoolDataSetBase.h @@ -3,8 +3,9 @@ #include "PoolDataSetIF.h" #include "PoolVariableIF.h" -#include "../serialize/SerializeIF.h" -#include "../ipc/MutexIF.h" + +#include "fsfw/serialize/SerializeIF.h" +#include "fsfw/ipc/MutexIF.h" /** * @brief The DataSetBase class manages a set of locally checked out variables. diff --git a/datapool/PoolDataSetIF.h b/src/fsfw/datapool/PoolDataSetIF.h similarity index 100% rename from datapool/PoolDataSetIF.h rename to src/fsfw/datapool/PoolDataSetIF.h diff --git a/datapool/PoolEntry.cpp b/src/fsfw/datapool/PoolEntry.cpp similarity index 94% rename from datapool/PoolEntry.cpp rename to src/fsfw/datapool/PoolEntry.cpp index 6504e20c..0443aa11 100644 --- a/datapool/PoolEntry.cpp +++ b/src/fsfw/datapool/PoolEntry.cpp @@ -1,7 +1,8 @@ -#include "PoolEntry.h" +#include "fsfw/datapool/PoolEntry.h" + +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/globalfunctions/arrayprinter.h" -#include "../serviceinterface/ServiceInterface.h" -#include "../globalfunctions/arrayprinter.h" #include #include diff --git a/datapool/PoolEntry.h b/src/fsfw/datapool/PoolEntry.h similarity index 100% rename from datapool/PoolEntry.h rename to src/fsfw/datapool/PoolEntry.h diff --git a/datapool/PoolEntryIF.h b/src/fsfw/datapool/PoolEntryIF.h similarity index 100% rename from datapool/PoolEntryIF.h rename to src/fsfw/datapool/PoolEntryIF.h diff --git a/datapool/PoolReadGuard.h b/src/fsfw/datapool/PoolReadGuard.h similarity index 100% rename from datapool/PoolReadGuard.h rename to src/fsfw/datapool/PoolReadGuard.h diff --git a/datapool/PoolVarList.h b/src/fsfw/datapool/PoolVarList.h similarity index 100% rename from datapool/PoolVarList.h rename to src/fsfw/datapool/PoolVarList.h diff --git a/datapool/PoolVariableIF.h b/src/fsfw/datapool/PoolVariableIF.h similarity index 100% rename from datapool/PoolVariableIF.h rename to src/fsfw/datapool/PoolVariableIF.h diff --git a/datapool/ReadCommitIF.h b/src/fsfw/datapool/ReadCommitIF.h similarity index 100% rename from datapool/ReadCommitIF.h rename to src/fsfw/datapool/ReadCommitIF.h diff --git a/datapool/ReadCommitIFAttorney.h b/src/fsfw/datapool/ReadCommitIFAttorney.h similarity index 100% rename from datapool/ReadCommitIFAttorney.h rename to src/fsfw/datapool/ReadCommitIFAttorney.h diff --git a/datapool/SharedDataSetIF.h b/src/fsfw/datapool/SharedDataSetIF.h similarity index 100% rename from datapool/SharedDataSetIF.h rename to src/fsfw/datapool/SharedDataSetIF.h diff --git a/src/fsfw/datapoollocal.h b/src/fsfw/datapoollocal.h new file mode 100644 index 00000000..7a3c4c20 --- /dev/null +++ b/src/fsfw/datapoollocal.h @@ -0,0 +1,11 @@ +#ifndef FSFW_DATAPOOLLOCAL_DATAPOOLLOCAL_H_ +#define FSFW_DATAPOOLLOCAL_DATAPOOLLOCAL_H_ + +/* Collected related headers */ +#include "fsfw/datapoollocal/LocalPoolVariable.h" +#include "fsfw/datapoollocal/LocalPoolVector.h" +#include "fsfw/datapoollocal/StaticLocalDataSet.h" +#include "fsfw/datapoollocal/LocalDataSet.h" +#include "fsfw/datapoollocal/SharedLocalDataSet.h" + +#endif /* FSFW_DATAPOOLLOCAL_DATAPOOLLOCAL_H_ */ diff --git a/datapoollocal/AccessLocalPoolF.h b/src/fsfw/datapoollocal/AccessLocalPoolF.h similarity index 100% rename from datapoollocal/AccessLocalPoolF.h rename to src/fsfw/datapoollocal/AccessLocalPoolF.h diff --git a/datapoollocal/CMakeLists.txt b/src/fsfw/datapoollocal/CMakeLists.txt similarity index 100% rename from datapoollocal/CMakeLists.txt rename to src/fsfw/datapoollocal/CMakeLists.txt diff --git a/datapoollocal/HasLocalDataPoolIF.h b/src/fsfw/datapoollocal/HasLocalDataPoolIF.h similarity index 98% rename from datapoollocal/HasLocalDataPoolIF.h rename to src/fsfw/datapoollocal/HasLocalDataPoolIF.h index 74e372c9..6051f068 100644 --- a/datapoollocal/HasLocalDataPoolIF.h +++ b/src/fsfw/datapoollocal/HasLocalDataPoolIF.h @@ -34,7 +34,8 @@ class LocalPoolObjectBase; * can be retrieved using the object manager, provided the target object is a SystemObject. * For example, the following line of code can be used to retrieve the interface * - * HasLocalDataPoolIF* poolIF = objectManager->get(objects::SOME_OBJECT); + * HasLocalDataPoolIF* poolIF = ObjectManager::instance()-> + * get(objects::SOME_OBJECT); * if(poolIF != nullptr) { * doSomething() * } diff --git a/src/fsfw/datapoollocal/LocalDataPoolManager.cpp b/src/fsfw/datapoollocal/LocalDataPoolManager.cpp new file mode 100644 index 00000000..4a706657 --- /dev/null +++ b/src/fsfw/datapoollocal/LocalDataPoolManager.cpp @@ -0,0 +1,946 @@ +#include "fsfw/datapoollocal/LocalDataPoolManager.h" +#include "fsfw/datapoollocal.h" +#include "internal/LocalPoolDataSetAttorney.h" +#include "internal/HasLocalDpIFManagerAttorney.h" + +#include "fsfw/housekeeping/HousekeepingSetPacket.h" +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/housekeeping/HousekeepingSnapshot.h" +#include "fsfw/housekeeping/AcceptsHkPacketsIF.h" +#include "fsfw/timemanager/CCSDSTime.h" +#include "fsfw/ipc/MutexFactory.h" +#include "fsfw/ipc/MutexGuard.h" +#include "fsfw/ipc/QueueFactory.h" + +#include +#include + +object_id_t LocalDataPoolManager::defaultHkDestination = objects::PUS_SERVICE_3_HOUSEKEEPING; + +LocalDataPoolManager::LocalDataPoolManager(HasLocalDataPoolIF* owner, MessageQueueIF* queueToUse, + bool appendValidityBuffer): + appendValidityBuffer(appendValidityBuffer) { + if(owner == nullptr) { + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "LocalDataPoolManager", HasReturnvaluesIF::RETURN_FAILED, + "Invalid supplied owner"); + return; + } + this->owner = owner; + mutex = MutexFactory::instance()->createMutex(); + if(mutex == nullptr) { + printWarningOrError(sif::OutputTypes::OUT_ERROR, + "LocalDataPoolManager", HasReturnvaluesIF::RETURN_FAILED, + "Could not create mutex"); + } + + hkQueue = queueToUse; +} + +LocalDataPoolManager::~LocalDataPoolManager() { + if(mutex != nullptr) { + MutexFactory::instance()->deleteMutex(mutex); + } +} + +ReturnValue_t LocalDataPoolManager::initialize(MessageQueueIF* queueToUse) { + if(queueToUse == nullptr) { + /* Error, all destinations invalid */ + printWarningOrError(sif::OutputTypes::OUT_ERROR, "initialize", + QUEUE_OR_DESTINATION_INVALID); + } + hkQueue = queueToUse; + + ipcStore = ObjectManager::instance()->get(objects::IPC_STORE); + if(ipcStore == nullptr) { + /* Error, all destinations invalid */ + printWarningOrError(sif::OutputTypes::OUT_ERROR, + "initialize", HasReturnvaluesIF::RETURN_FAILED, + "Could not set IPC store."); + return HasReturnvaluesIF::RETURN_FAILED; + } + + + if(defaultHkDestination != objects::NO_OBJECT) { + AcceptsHkPacketsIF* hkPacketReceiver = ObjectManager::instance()-> + get(defaultHkDestination); + if(hkPacketReceiver != nullptr) { + hkDestinationId = hkPacketReceiver->getHkQueue(); + } + else { + printWarningOrError(sif::OutputTypes::OUT_ERROR, + "initialize", QUEUE_OR_DESTINATION_INVALID); + return QUEUE_OR_DESTINATION_INVALID; + } + } + + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t LocalDataPoolManager::initializeAfterTaskCreation( + uint8_t nonDiagInvlFactor) { + setNonDiagnosticIntervalFactor(nonDiagInvlFactor); + return initializeHousekeepingPoolEntriesOnce(); +} + +ReturnValue_t LocalDataPoolManager::initializeHousekeepingPoolEntriesOnce() { + if(not mapInitialized) { + ReturnValue_t result = owner->initializeLocalDataPool(localPoolMap, + *this); + if(result == HasReturnvaluesIF::RETURN_OK) { + mapInitialized = true; + } + return result; + } + + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "initialize", HasReturnvaluesIF::RETURN_FAILED, + "The map should only be initialized once"); + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t LocalDataPoolManager::performHkOperation() { + ReturnValue_t status = HasReturnvaluesIF::RETURN_OK; + for(auto& receiver: hkReceivers) { + switch(receiver.reportingType) { + case(ReportingType::PERIODIC): { + if(receiver.dataType == DataType::LOCAL_POOL_VARIABLE) { + /* Periodic packets shall only be generated from datasets */ + continue; + } + performPeriodicHkGeneration(receiver); + break; + } + case(ReportingType::UPDATE_HK): { + handleHkUpdate(receiver, status); + break; + } + case(ReportingType::UPDATE_NOTIFICATION): { + handleNotificationUpdate(receiver, status); + break; + } + case(ReportingType::UPDATE_SNAPSHOT): { + handleNotificationSnapshot(receiver, status); + break; + } + default: + // This should never happen. + return HasReturnvaluesIF::RETURN_FAILED; + } + } + resetHkUpdateResetHelper(); + return status; +} + +ReturnValue_t LocalDataPoolManager::handleHkUpdate(HkReceiver& receiver, + ReturnValue_t& status) { + if(receiver.dataType == DataType::LOCAL_POOL_VARIABLE) { + /* Update packets shall only be generated from datasets. */ + return HasReturnvaluesIF::RETURN_FAILED; + } + LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, + receiver.dataId.sid); + if(dataSet == nullptr) { + return DATASET_NOT_FOUND; + } + if(dataSet->hasChanged()) { + /* Prepare and send update notification */ + ReturnValue_t result = generateHousekeepingPacket( + receiver.dataId.sid, dataSet, true); + if(result != HasReturnvaluesIF::RETURN_OK) { + status = result; + } + } + handleChangeResetLogic(receiver.dataType, receiver.dataId, + dataSet); + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t LocalDataPoolManager::handleNotificationUpdate(HkReceiver& receiver, + ReturnValue_t& status) { + MarkChangedIF* toReset = nullptr; + if(receiver.dataType == DataType::LOCAL_POOL_VARIABLE) { + LocalPoolObjectBase* poolObj = HasLocalDpIFManagerAttorney::getPoolObjectHandle(owner, + receiver.dataId.localPoolId); + if(poolObj == nullptr) { + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "handleNotificationUpdate", POOLOBJECT_NOT_FOUND); + return POOLOBJECT_NOT_FOUND; + } + if(poolObj->hasChanged()) { + /* Prepare and send update notification. */ + CommandMessage notification; + HousekeepingMessage::setUpdateNotificationVariableCommand(¬ification, + gp_id_t(owner->getObjectId(), receiver.dataId.localPoolId)); + ReturnValue_t result = hkQueue->sendMessage(receiver.destinationQueue, ¬ification); + if(result != HasReturnvaluesIF::RETURN_OK) { + status = result; + } + toReset = poolObj; + } + + } + else { + LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, + receiver.dataId.sid); + if(dataSet == nullptr) { + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "handleNotificationUpdate", DATASET_NOT_FOUND); + return DATASET_NOT_FOUND; + } + if(dataSet->hasChanged()) { + /* Prepare and send update notification */ + CommandMessage notification; + HousekeepingMessage::setUpdateNotificationSetCommand(¬ification, + receiver.dataId.sid); + ReturnValue_t result = hkQueue->sendMessage( + receiver.destinationQueue, ¬ification); + if(result != HasReturnvaluesIF::RETURN_OK) { + status = result; + } + toReset = dataSet; + } + } + if(toReset != nullptr) { + handleChangeResetLogic(receiver.dataType, receiver.dataId, toReset); + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t LocalDataPoolManager::handleNotificationSnapshot( + HkReceiver& receiver, ReturnValue_t& status) { + MarkChangedIF* toReset = nullptr; + /* Check whether data has changed and send messages in case it has */ + if(receiver.dataType == DataType::LOCAL_POOL_VARIABLE) { + LocalPoolObjectBase* poolObj = HasLocalDpIFManagerAttorney::getPoolObjectHandle(owner, + receiver.dataId.localPoolId); + if(poolObj == nullptr) { + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "handleNotificationSnapshot", POOLOBJECT_NOT_FOUND); + return POOLOBJECT_NOT_FOUND; + } + + if (not poolObj->hasChanged()) { + return HasReturnvaluesIF::RETURN_OK; + } + + /* Prepare and send update snapshot */ + timeval now; + Clock::getClock_timeval(&now); + CCSDSTime::CDS_short cds; + CCSDSTime::convertToCcsds(&cds, &now); + HousekeepingSnapshot updatePacket(reinterpret_cast(&cds), sizeof(cds), + HasLocalDpIFManagerAttorney::getPoolObjectHandle( + owner,receiver.dataId.localPoolId)); + + store_address_t storeId; + ReturnValue_t result = addUpdateToStore(updatePacket, storeId); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + CommandMessage notification; + HousekeepingMessage::setUpdateSnapshotVariableCommand(¬ification, + gp_id_t(owner->getObjectId(), receiver.dataId.localPoolId), storeId); + result = hkQueue->sendMessage(receiver.destinationQueue, + ¬ification); + if (result != HasReturnvaluesIF::RETURN_OK) { + status = result; + } + toReset = poolObj; + } + else { + LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, + receiver.dataId.sid); + if(dataSet == nullptr) { + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "handleNotificationSnapshot", DATASET_NOT_FOUND); + return DATASET_NOT_FOUND; + } + + if(not dataSet->hasChanged()) { + return HasReturnvaluesIF::RETURN_OK; + } + + /* Prepare and send update snapshot */ + timeval now; + Clock::getClock_timeval(&now); + CCSDSTime::CDS_short cds; + CCSDSTime::convertToCcsds(&cds, &now); + HousekeepingSnapshot updatePacket(reinterpret_cast(&cds), + sizeof(cds), HasLocalDpIFManagerAttorney::getDataSetHandle(owner, + receiver.dataId.sid)); + + store_address_t storeId; + ReturnValue_t result = addUpdateToStore(updatePacket, storeId); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + CommandMessage notification; + HousekeepingMessage::setUpdateSnapshotSetCommand( + ¬ification, receiver.dataId.sid, storeId); + result = hkQueue->sendMessage(receiver.destinationQueue, ¬ification); + if(result != HasReturnvaluesIF::RETURN_OK) { + status = result; + } + toReset = dataSet; + + } + if(toReset != nullptr) { + handleChangeResetLogic(receiver.dataType, + receiver.dataId, toReset); + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t LocalDataPoolManager::addUpdateToStore( + HousekeepingSnapshot& updatePacket, store_address_t& storeId) { + size_t updatePacketSize = updatePacket.getSerializedSize(); + uint8_t *storePtr = nullptr; + ReturnValue_t result = ipcStore->getFreeElement(&storeId, + updatePacket.getSerializedSize(), &storePtr); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + size_t serializedSize = 0; + result = updatePacket.serialize(&storePtr, &serializedSize, + updatePacketSize, SerializeIF::Endianness::MACHINE); + return result;; +} + +void LocalDataPoolManager::handleChangeResetLogic( + DataType type, DataId dataId, MarkChangedIF* toReset) { + if(hkUpdateResetList == nullptr) { + /* Config error */ + return; + } + HkUpdateResetList& listRef = *hkUpdateResetList; + for(auto& changeInfo: listRef) { + if(changeInfo.dataType != type) { + continue; + } + if((changeInfo.dataType == DataType::DATA_SET) and + (changeInfo.dataId.sid != dataId.sid)) { + continue; + } + if((changeInfo.dataType == DataType::LOCAL_POOL_VARIABLE) and + (changeInfo.dataId.localPoolId != dataId.localPoolId)) { + continue; + } + + /* Only one update recipient, we can reset changes status immediately */ + if(changeInfo.updateCounter <= 1) { + toReset->setChanged(false); + } + /* All recipients have been notified, reset the changed flag */ + else if(changeInfo.currentUpdateCounter <= 1) { + toReset->setChanged(false); + changeInfo.currentUpdateCounter = 0; + } + /* Not all recipiens have been notified yet, decrement */ + else { + changeInfo.currentUpdateCounter--; + } + return; + } +} + +void LocalDataPoolManager::resetHkUpdateResetHelper() { + if(hkUpdateResetList == nullptr) { + return; + } + + for(auto& changeInfo: *hkUpdateResetList) { + changeInfo.currentUpdateCounter = changeInfo.updateCounter; + } +} + +ReturnValue_t LocalDataPoolManager::subscribeForPeriodicPacket(sid_t sid, + bool enableReporting, float collectionInterval, bool isDiagnostics, + object_id_t packetDestination) { + AcceptsHkPacketsIF* hkReceiverObject = ObjectManager::instance()-> + get(packetDestination); + if(hkReceiverObject == nullptr) { + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "subscribeForPeriodicPacket", QUEUE_OR_DESTINATION_INVALID); + return QUEUE_OR_DESTINATION_INVALID; + } + + struct HkReceiver hkReceiver; + hkReceiver.dataId.sid = sid; + hkReceiver.reportingType = ReportingType::PERIODIC; + hkReceiver.dataType = DataType::DATA_SET; + hkReceiver.destinationQueue = hkReceiverObject->getHkQueue(); + + LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid); + if(dataSet != nullptr) { + LocalPoolDataSetAttorney::setReportingEnabled(*dataSet, enableReporting); + LocalPoolDataSetAttorney::setDiagnostic(*dataSet, isDiagnostics); + LocalPoolDataSetAttorney::initializePeriodicHelper(*dataSet, collectionInterval, + owner->getPeriodicOperationFrequency()); + } + + hkReceivers.push_back(hkReceiver); + return HasReturnvaluesIF::RETURN_OK; +} + + +ReturnValue_t LocalDataPoolManager::subscribeForUpdatePacket(sid_t sid, + bool isDiagnostics, bool reportingEnabled, + object_id_t packetDestination) { + AcceptsHkPacketsIF* hkReceiverObject = + ObjectManager::instance()->get(packetDestination); + if(hkReceiverObject == nullptr) { + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "subscribeForPeriodicPacket", QUEUE_OR_DESTINATION_INVALID); + return QUEUE_OR_DESTINATION_INVALID; + } + + struct HkReceiver hkReceiver; + hkReceiver.dataId.sid = sid; + hkReceiver.reportingType = ReportingType::UPDATE_HK; + hkReceiver.dataType = DataType::DATA_SET; + hkReceiver.destinationQueue = hkReceiverObject->getHkQueue(); + + LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid); + if(dataSet != nullptr) { + LocalPoolDataSetAttorney::setReportingEnabled(*dataSet, true); + LocalPoolDataSetAttorney::setDiagnostic(*dataSet, isDiagnostics); + } + + hkReceivers.push_back(hkReceiver); + + handleHkUpdateResetListInsertion(hkReceiver.dataType, hkReceiver.dataId); + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t LocalDataPoolManager::subscribeForSetUpdateMessage( + const uint32_t setId, object_id_t destinationObject, + MessageQueueId_t targetQueueId, bool generateSnapshot) { + struct HkReceiver hkReceiver; + hkReceiver.dataType = DataType::DATA_SET; + hkReceiver.dataId.sid = sid_t(owner->getObjectId(), setId); + hkReceiver.destinationQueue = targetQueueId; + hkReceiver.objectId = destinationObject; + if(generateSnapshot) { + hkReceiver.reportingType = ReportingType::UPDATE_SNAPSHOT; + } + else { + hkReceiver.reportingType = ReportingType::UPDATE_NOTIFICATION; + } + + hkReceivers.push_back(hkReceiver); + + handleHkUpdateResetListInsertion(hkReceiver.dataType, hkReceiver.dataId); + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t LocalDataPoolManager::subscribeForVariableUpdateMessage( + const lp_id_t localPoolId, object_id_t destinationObject, + MessageQueueId_t targetQueueId, bool generateSnapshot) { + struct HkReceiver hkReceiver; + hkReceiver.dataType = DataType::LOCAL_POOL_VARIABLE; + hkReceiver.dataId.localPoolId = localPoolId; + hkReceiver.destinationQueue = targetQueueId; + hkReceiver.objectId = destinationObject; + if(generateSnapshot) { + hkReceiver.reportingType = ReportingType::UPDATE_SNAPSHOT; + } + else { + hkReceiver.reportingType = ReportingType::UPDATE_NOTIFICATION; + } + + hkReceivers.push_back(hkReceiver); + + handleHkUpdateResetListInsertion(hkReceiver.dataType, hkReceiver.dataId); + return HasReturnvaluesIF::RETURN_OK; +} + +void LocalDataPoolManager::handleHkUpdateResetListInsertion(DataType dataType, + DataId dataId) { + if(hkUpdateResetList == nullptr) { + hkUpdateResetList = new std::vector(); + } + + for(auto& updateResetStruct: *hkUpdateResetList) { + if(dataType == DataType::DATA_SET) { + if(updateResetStruct.dataId.sid == dataId.sid) { + updateResetStruct.updateCounter++; + updateResetStruct.currentUpdateCounter++; + return; + } + } + else { + if(updateResetStruct.dataId.localPoolId == dataId.localPoolId) { + updateResetStruct.updateCounter++; + updateResetStruct.currentUpdateCounter++; + return; + } + } + + } + HkUpdateResetHelper hkUpdateResetHelper; + hkUpdateResetHelper.currentUpdateCounter = 1; + hkUpdateResetHelper.updateCounter = 1; + hkUpdateResetHelper.dataType = dataType; + if(dataType == DataType::DATA_SET) { + hkUpdateResetHelper.dataId.sid = dataId.sid; + } + else { + hkUpdateResetHelper.dataId.localPoolId = dataId.localPoolId; + } + hkUpdateResetList->push_back(hkUpdateResetHelper); +} + +ReturnValue_t LocalDataPoolManager::handleHousekeepingMessage( + CommandMessage* message) { + Command_t command = message->getCommand(); + sid_t sid = HousekeepingMessage::getSid(message); + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + switch(command) { + // Houskeeping interface handling. + case(HousekeepingMessage::ENABLE_PERIODIC_DIAGNOSTICS_GENERATION): { + result = togglePeriodicGeneration(sid, true, true); + break; + } + + case(HousekeepingMessage::DISABLE_PERIODIC_DIAGNOSTICS_GENERATION): { + result = togglePeriodicGeneration(sid, false, true); + break; + } + + case(HousekeepingMessage::ENABLE_PERIODIC_HK_REPORT_GENERATION): { + result = togglePeriodicGeneration(sid, true, false); + break; + } + + case(HousekeepingMessage::DISABLE_PERIODIC_HK_REPORT_GENERATION): { + result = togglePeriodicGeneration(sid, false, false); + break; + } + + case(HousekeepingMessage::REPORT_DIAGNOSTICS_REPORT_STRUCTURES): { + result = generateSetStructurePacket(sid, true); + if(result == HasReturnvaluesIF::RETURN_OK) { + return result; + } + break; + } + + case(HousekeepingMessage::REPORT_HK_REPORT_STRUCTURES): { + result = generateSetStructurePacket(sid, false); + if(result == HasReturnvaluesIF::RETURN_OK) { + return result; + } + break; + } + case(HousekeepingMessage::MODIFY_DIAGNOSTICS_REPORT_COLLECTION_INTERVAL): + case(HousekeepingMessage::MODIFY_PARAMETER_REPORT_COLLECTION_INTERVAL): { + float newCollIntvl = 0; + HousekeepingMessage::getCollectionIntervalModificationCommand(message, + &newCollIntvl); + if(command == HousekeepingMessage:: + MODIFY_DIAGNOSTICS_REPORT_COLLECTION_INTERVAL) { + result = changeCollectionInterval(sid, newCollIntvl, true); + } + else { + result = changeCollectionInterval(sid, newCollIntvl, false); + } + break; + } + + case(HousekeepingMessage::GENERATE_ONE_PARAMETER_REPORT): + case(HousekeepingMessage::GENERATE_ONE_DIAGNOSTICS_REPORT): { + LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid); + if(dataSet == nullptr) { + printWarningOrError(sif::OutputTypes::OUT_WARNING, "handleHousekeepingMessage", + DATASET_NOT_FOUND); + return DATASET_NOT_FOUND; + } + if(command == HousekeepingMessage::GENERATE_ONE_PARAMETER_REPORT + and LocalPoolDataSetAttorney::isDiagnostics(*dataSet)) { + result = WRONG_HK_PACKET_TYPE; + break; + } + else if(command == HousekeepingMessage::GENERATE_ONE_DIAGNOSTICS_REPORT + and not LocalPoolDataSetAttorney::isDiagnostics(*dataSet)) { + result = WRONG_HK_PACKET_TYPE; + break; + } + return generateHousekeepingPacket(HousekeepingMessage::getSid(message), + dataSet, true); + } + + /* Notification handling */ + case(HousekeepingMessage::UPDATE_NOTIFICATION_SET): { + owner->handleChangedDataset(sid); + return HasReturnvaluesIF::RETURN_OK; + } + case(HousekeepingMessage::UPDATE_NOTIFICATION_VARIABLE): { + gp_id_t globPoolId = HousekeepingMessage::getUpdateNotificationVariableCommand(message); + owner->handleChangedPoolVariable(globPoolId); + return HasReturnvaluesIF::RETURN_OK; + } + case(HousekeepingMessage::UPDATE_SNAPSHOT_SET): { + store_address_t storeId; + HousekeepingMessage::getUpdateSnapshotSetCommand(message, &storeId); + bool clearMessage = true; + owner->handleChangedDataset(sid, storeId, &clearMessage); + if(clearMessage) { + message->clear(); + } + return HasReturnvaluesIF::RETURN_OK; + } + case(HousekeepingMessage::UPDATE_SNAPSHOT_VARIABLE): { + store_address_t storeId; + gp_id_t globPoolId = HousekeepingMessage::getUpdateSnapshotVariableCommand(message, + &storeId); + bool clearMessage = true; + owner->handleChangedPoolVariable(globPoolId, storeId, &clearMessage); + if(clearMessage) { + message->clear(); + } + return HasReturnvaluesIF::RETURN_OK; + } + + default: + return CommandMessageIF::UNKNOWN_COMMAND; + } + + CommandMessage reply; + if(result != HasReturnvaluesIF::RETURN_OK) { + HousekeepingMessage::setHkRequestFailureReply(&reply, sid, result); + } + else { + HousekeepingMessage::setHkRequestSuccessReply(&reply, sid); + } + hkQueue->sendMessage(hkDestinationId, &reply); + return result; +} + +ReturnValue_t LocalDataPoolManager::printPoolEntry( + lp_id_t localPoolId) { + auto poolIter = localPoolMap.find(localPoolId); + if (poolIter == localPoolMap.end()) { + printWarningOrError(sif::OutputTypes::OUT_WARNING, "printPoolEntry", + localpool::POOL_ENTRY_NOT_FOUND); + return localpool::POOL_ENTRY_NOT_FOUND; + } + poolIter->second->print(); + return HasReturnvaluesIF::RETURN_OK; +} + +MutexIF* LocalDataPoolManager::getMutexHandle() { + return mutex; +} + +HasLocalDataPoolIF* LocalDataPoolManager::getOwner() { + return owner; +} + +ReturnValue_t LocalDataPoolManager::generateHousekeepingPacket(sid_t sid, + LocalPoolDataSetBase* dataSet, bool forDownlink, + MessageQueueId_t destination) { + if(dataSet == nullptr) { + /* Configuration error. */ + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "generateHousekeepingPacket", + DATASET_NOT_FOUND); + return DATASET_NOT_FOUND; + } + + store_address_t storeId; + HousekeepingPacketDownlink hkPacket(sid, dataSet); + size_t serializedSize = 0; + ReturnValue_t result = serializeHkPacketIntoStore(hkPacket, storeId, + forDownlink, &serializedSize); + if(result != HasReturnvaluesIF::RETURN_OK or serializedSize == 0) { + return result; + } + + /* Now we set a HK message and send it the HK packet destination. */ + CommandMessage hkMessage; + if(LocalPoolDataSetAttorney::isDiagnostics(*dataSet)) { + HousekeepingMessage::setHkDiagnosticsReply(&hkMessage, sid, storeId); + } + else { + HousekeepingMessage::setHkReportReply(&hkMessage, sid, storeId); + } + + if(hkQueue == nullptr) { + /* Error, no queue available to send packet with. */ + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "generateHousekeepingPacket", + QUEUE_OR_DESTINATION_INVALID); + return QUEUE_OR_DESTINATION_INVALID; + } + if(destination == MessageQueueIF::NO_QUEUE) { + if(hkDestinationId == MessageQueueIF::NO_QUEUE) { + /* Error, all destinations invalid */ + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "generateHousekeepingPacket", + QUEUE_OR_DESTINATION_INVALID); + } + destination = hkDestinationId; + } + + return hkQueue->sendMessage(destination, &hkMessage); +} + +ReturnValue_t LocalDataPoolManager::serializeHkPacketIntoStore( + HousekeepingPacketDownlink& hkPacket, + store_address_t& storeId, bool forDownlink, + size_t* serializedSize) { + uint8_t* dataPtr = nullptr; + const size_t maxSize = hkPacket.getSerializedSize(); + ReturnValue_t result = ipcStore->getFreeElement(&storeId, + maxSize, &dataPtr); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + if(forDownlink) { + return hkPacket.serialize(&dataPtr, serializedSize, maxSize, + SerializeIF::Endianness::BIG); + } + return hkPacket.serialize(&dataPtr, serializedSize, maxSize, + SerializeIF::Endianness::MACHINE); +} + +void LocalDataPoolManager::setNonDiagnosticIntervalFactor( + uint8_t nonDiagInvlFactor) { + this->nonDiagnosticIntervalFactor = nonDiagInvlFactor; +} + +void LocalDataPoolManager::performPeriodicHkGeneration(HkReceiver& receiver) { + sid_t sid = receiver.dataId.sid; + LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid); + if(dataSet == nullptr) { + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "performPeriodicHkGeneration", + DATASET_NOT_FOUND); + return; + } + + if(not LocalPoolDataSetAttorney::getReportingEnabled(*dataSet)) { + return; + } + + PeriodicHousekeepingHelper* periodicHelper = + LocalPoolDataSetAttorney::getPeriodicHelper(*dataSet); + + if(periodicHelper == nullptr) { + /* Configuration error */ + return; + } + + if(not periodicHelper->checkOpNecessary()) { + return; + } + + ReturnValue_t result = generateHousekeepingPacket( + sid, dataSet, true); + if(result != HasReturnvaluesIF::RETURN_OK) { + /* Configuration error */ +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "LocalDataPoolManager::performHkOperation: HK generation failed." << + std::endl; +#else + sif::printWarning("LocalDataPoolManager::performHkOperation: HK generation failed.\n"); +#endif + } +} + + +ReturnValue_t LocalDataPoolManager::togglePeriodicGeneration(sid_t sid, + bool enable, bool isDiagnostics) { + LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid); + if(dataSet == nullptr) { + printWarningOrError(sif::OutputTypes::OUT_WARNING, "togglePeriodicGeneration", + DATASET_NOT_FOUND); + return DATASET_NOT_FOUND; + } + + if((LocalPoolDataSetAttorney::isDiagnostics(*dataSet) and not isDiagnostics) or + (not LocalPoolDataSetAttorney::isDiagnostics(*dataSet) and isDiagnostics)) { + return WRONG_HK_PACKET_TYPE; + } + + if((LocalPoolDataSetAttorney::getReportingEnabled(*dataSet) and enable) or + (not LocalPoolDataSetAttorney::getReportingEnabled(*dataSet) and not enable)) { + return REPORTING_STATUS_UNCHANGED; + } + + LocalPoolDataSetAttorney::setReportingEnabled(*dataSet, enable); + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t LocalDataPoolManager::changeCollectionInterval(sid_t sid, + float newCollectionInterval, bool isDiagnostics) { + LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid); + if(dataSet == nullptr) { + printWarningOrError(sif::OutputTypes::OUT_WARNING, "changeCollectionInterval", + DATASET_NOT_FOUND); + return DATASET_NOT_FOUND; + } + + bool targetIsDiagnostics = LocalPoolDataSetAttorney::isDiagnostics(*dataSet); + if((targetIsDiagnostics and not isDiagnostics) or + (not targetIsDiagnostics and isDiagnostics)) { + return WRONG_HK_PACKET_TYPE; + } + + PeriodicHousekeepingHelper* periodicHelper = + LocalPoolDataSetAttorney::getPeriodicHelper(*dataSet); + + if(periodicHelper == nullptr) { + /* Configuration error, set might not have a corresponding pool manager */ + return PERIODIC_HELPER_INVALID; + } + + periodicHelper->changeCollectionInterval(newCollectionInterval); + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t LocalDataPoolManager::generateSetStructurePacket(sid_t sid, + bool isDiagnostics) { + /* Get and check dataset first. */ + LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid); + if(dataSet == nullptr) { + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "performPeriodicHkGeneration", DATASET_NOT_FOUND); + return DATASET_NOT_FOUND; + } + + + bool targetIsDiagnostics = LocalPoolDataSetAttorney::isDiagnostics(*dataSet); + if((targetIsDiagnostics and not isDiagnostics) or + (not targetIsDiagnostics and isDiagnostics)) { + return WRONG_HK_PACKET_TYPE; + } + + bool valid = dataSet->isValid(); + bool reportingEnabled = LocalPoolDataSetAttorney::getReportingEnabled(*dataSet); + float collectionInterval = LocalPoolDataSetAttorney::getPeriodicHelper(*dataSet)-> + getCollectionIntervalInSeconds(); + + // Generate set packet which can be serialized. + HousekeepingSetPacket setPacket(sid, + reportingEnabled, valid, collectionInterval, dataSet); + size_t expectedSize = setPacket.getSerializedSize(); + uint8_t* storePtr = nullptr; + store_address_t storeId; + ReturnValue_t result = ipcStore->getFreeElement(&storeId, + expectedSize,&storePtr); + if(result != HasReturnvaluesIF::RETURN_OK) { + printWarningOrError(sif::OutputTypes::OUT_ERROR, + "generateSetStructurePacket", HasReturnvaluesIF::RETURN_FAILED, + "Could not get free element from IPC store."); + return result; + } + + // Serialize set packet into store. + size_t size = 0; + result = setPacket.serialize(&storePtr, &size, expectedSize, + SerializeIF::Endianness::BIG); + if(expectedSize != size) { + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "generateSetStructurePacket", HasReturnvaluesIF::RETURN_FAILED, + "Expected size is not equal to serialized size"); + } + + // Send structure reporting reply. + CommandMessage reply; + if(isDiagnostics) { + HousekeepingMessage::setDiagnosticsStuctureReportReply(&reply, + sid, storeId); + } + else { + HousekeepingMessage::setHkStuctureReportReply(&reply, + sid, storeId); + } + + hkQueue->reply(&reply); + return result; +} + +void LocalDataPoolManager::clearReceiversList() { + /* Clear the vector completely and releases allocated memory. */ + HkReceivers().swap(hkReceivers); + /* Also clear the reset helper if it exists */ + if(hkUpdateResetList != nullptr) { + HkUpdateResetList().swap(*hkUpdateResetList); + } +} + +MutexIF* LocalDataPoolManager::getLocalPoolMutex() { + return this->mutex; +} + +object_id_t LocalDataPoolManager::getCreatorObjectId() const { + return owner->getObjectId(); +} + +void LocalDataPoolManager::printWarningOrError(sif::OutputTypes outputType, + const char* functionName, ReturnValue_t error, const char* errorPrint) { +#if FSFW_VERBOSE_LEVEL >= 1 + if(errorPrint == nullptr) { + if(error == DATASET_NOT_FOUND) { + errorPrint = "Dataset not found"; + } + else if(error == POOLOBJECT_NOT_FOUND) { + errorPrint = "Pool Object not found"; + } + else if(error == HasReturnvaluesIF::RETURN_FAILED) { + if(outputType == sif::OutputTypes::OUT_WARNING) { + errorPrint = "Generic Warning"; + } + else { + errorPrint = "Generic error"; + } + } + else if(error == QUEUE_OR_DESTINATION_INVALID) { + errorPrint = "Queue or destination not set"; + } + else if(error == localpool::POOL_ENTRY_TYPE_CONFLICT) { + errorPrint = "Pool entry type conflict"; + } + else if(error == localpool::POOL_ENTRY_NOT_FOUND) { + errorPrint = "Pool entry not found"; + } + else { + errorPrint = "Unknown error"; + } + } + object_id_t objectId = 0xffffffff; + if(owner != nullptr) { + objectId = owner->getObjectId(); + } + + if(outputType == sif::OutputTypes::OUT_WARNING) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "LocalDataPoolManager::" << functionName << ": Object ID 0x" << + std::setw(8) << std::setfill('0') << std::hex << objectId << " | " << errorPrint << + std::dec << std::setfill(' ') << std::endl; +#else + sif::printWarning("LocalDataPoolManager::%s: Object ID 0x%08x | %s\n", + functionName, objectId, errorPrint); +#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ + } + else if(outputType == sif::OutputTypes::OUT_ERROR) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "LocalDataPoolManager::" << functionName << ": Object ID 0x" << + std::setw(8) << std::setfill('0') << std::hex << objectId << " | " << errorPrint << + std::dec << std::setfill(' ') << std::endl; +#else + sif::printError("LocalDataPoolManager::%s: Object ID 0x%08x | %s\n", + functionName, objectId, errorPrint); +#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ + } +#endif /* #if FSFW_VERBOSE_LEVEL >= 1 */ +} + +LocalDataPoolManager* LocalDataPoolManager::getPoolManagerHandle() { + return this; +} diff --git a/datapoollocal/LocalDataPoolManager.h b/src/fsfw/datapoollocal/LocalDataPoolManager.h similarity index 97% rename from datapoollocal/LocalDataPoolManager.h rename to src/fsfw/datapoollocal/LocalDataPoolManager.h index 2ec81f1c..9f91613b 100644 --- a/datapoollocal/LocalDataPoolManager.h +++ b/src/fsfw/datapoollocal/LocalDataPoolManager.h @@ -4,17 +4,17 @@ #include "ProvidesDataPoolSubscriptionIF.h" #include "AccessLocalPoolF.h" -#include "../serviceinterface/ServiceInterface.h" -#include "../housekeeping/HousekeepingPacketDownlink.h" -#include "../housekeeping/HousekeepingMessage.h" -#include "../housekeeping/PeriodicHousekeepingHelper.h" -#include "../datapool/DataSetIF.h" -#include "../datapool/PoolEntry.h" -#include "../objectmanager/SystemObjectIF.h" -#include "../ipc/MutexIF.h" -#include "../ipc/CommandMessage.h" -#include "../ipc/MessageQueueIF.h" -#include "../ipc/MutexGuard.h" +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/housekeeping/HousekeepingPacketDownlink.h" +#include "fsfw/housekeeping/HousekeepingMessage.h" +#include "fsfw/housekeeping/PeriodicHousekeepingHelper.h" +#include "fsfw/datapool/DataSetIF.h" +#include "fsfw/datapool/PoolEntry.h" +#include "fsfw/objectmanager/SystemObjectIF.h" +#include "fsfw/ipc/MutexIF.h" +#include "fsfw/ipc/CommandMessage.h" +#include "fsfw/ipc/MessageQueueIF.h" +#include "fsfw/ipc/MutexGuard.h" #include #include diff --git a/datapoollocal/LocalDataSet.cpp b/src/fsfw/datapoollocal/LocalDataSet.cpp similarity index 80% rename from datapoollocal/LocalDataSet.cpp rename to src/fsfw/datapoollocal/LocalDataSet.cpp index aeb5c6b3..260f8500 100644 --- a/datapoollocal/LocalDataSet.cpp +++ b/src/fsfw/datapoollocal/LocalDataSet.cpp @@ -1,6 +1,7 @@ -#include "LocalDataSet.h" -#include "../datapoollocal/LocalDataPoolManager.h" -#include "../serialize/SerializeAdapter.h" +#include "fsfw/datapoollocal/LocalDataSet.h" +#include "fsfw/datapoollocal/LocalDataPoolManager.h" + +#include "fsfw/serialize/SerializeAdapter.h" #include #include diff --git a/datapoollocal/LocalDataSet.h b/src/fsfw/datapoollocal/LocalDataSet.h similarity index 100% rename from datapoollocal/LocalDataSet.h rename to src/fsfw/datapoollocal/LocalDataSet.h diff --git a/datapoollocal/LocalPoolDataSetBase.cpp b/src/fsfw/datapoollocal/LocalPoolDataSetBase.cpp similarity index 94% rename from datapoollocal/LocalPoolDataSetBase.cpp rename to src/fsfw/datapoollocal/LocalPoolDataSetBase.cpp index a72e9db1..d1ac0c7f 100644 --- a/datapoollocal/LocalPoolDataSetBase.cpp +++ b/src/fsfw/datapoollocal/LocalPoolDataSetBase.cpp @@ -1,12 +1,12 @@ -#include "LocalPoolDataSetBase.h" -#include "HasLocalDataPoolIF.h" +#include "fsfw/datapoollocal.h" #include "internal/HasLocalDpIFUserAttorney.h" -#include "../serviceinterface/ServiceInterface.h" -#include "../globalfunctions/bitutility.h" -#include "../datapoollocal/LocalDataPoolManager.h" -#include "../housekeeping/PeriodicHousekeepingHelper.h" -#include "../serialize/SerializeAdapter.h" +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/globalfunctions/bitutility.h" +#include "fsfw/datapoollocal/LocalDataPoolManager.h" +#include "fsfw/housekeeping/PeriodicHousekeepingHelper.h" +#include "fsfw/serialize/SerializeAdapter.h" #include #include @@ -45,7 +45,7 @@ LocalPoolDataSetBase::LocalPoolDataSetBase(HasLocalDataPoolIF *hkOwner, LocalPoolDataSetBase::LocalPoolDataSetBase(sid_t sid, PoolVariableIF** registeredVariablesArray, const size_t maxNumberOfVariables): PoolDataSetBase(registeredVariablesArray, maxNumberOfVariables) { - HasLocalDataPoolIF* hkOwner = objectManager->get( + HasLocalDataPoolIF* hkOwner = ObjectManager::instance()->get( sid.objectId); if(hkOwner != nullptr) { AccessPoolManagerIF* accessor = HasLocalDpIFUserAttorney::getAccessorHandle(hkOwner); @@ -110,7 +110,7 @@ ReturnValue_t LocalPoolDataSetBase::serializeWithValidityBuffer(uint8_t **buffer for (uint16_t count = 0; count < fillCount; count++) { if(registeredVariables[count]->isValid()) { /* Set bit at correct position */ - bitutil::bitSet(validityPtr + validBufferIndex, validBufferIndexBit); + bitutil::set(validityPtr + validBufferIndex, validBufferIndexBit); } if(validBufferIndexBit == 7) { validBufferIndex ++; @@ -156,8 +156,8 @@ ReturnValue_t LocalPoolDataSetBase::deSerializeWithValidityBuffer( uint8_t validBufferIndexBit = 0; for (uint16_t count = 0; count < fillCount; count++) { // set validity buffer here. - bool nextVarValid = bitutil::bitGet(*buffer + - validBufferIndex, validBufferIndexBit); + bool nextVarValid = false; + bitutil::get(*buffer + validBufferIndex, validBufferIndexBit, nextVarValid); registeredVariables[count]->setValid(nextVarValid); if(validBufferIndexBit == 7) { diff --git a/datapoollocal/LocalPoolDataSetBase.h b/src/fsfw/datapoollocal/LocalPoolDataSetBase.h similarity index 99% rename from datapoollocal/LocalPoolDataSetBase.h rename to src/fsfw/datapoollocal/LocalPoolDataSetBase.h index ab67dc3f..822e2cb8 100644 --- a/datapoollocal/LocalPoolDataSetBase.h +++ b/src/fsfw/datapoollocal/LocalPoolDataSetBase.h @@ -4,8 +4,8 @@ #include "MarkChangedIF.h" #include "localPoolDefinitions.h" -#include "../datapool/DataSetIF.h" -#include "../datapool/PoolDataSetBase.h" +#include "fsfw/datapool/DataSetIF.h" +#include "fsfw/datapool/PoolDataSetBase.h" #include diff --git a/datapoollocal/LocalPoolObjectBase.cpp b/src/fsfw/datapoollocal/LocalPoolObjectBase.cpp similarity index 92% rename from datapoollocal/LocalPoolObjectBase.cpp rename to src/fsfw/datapoollocal/LocalPoolObjectBase.cpp index b6db0608..96b849c6 100644 --- a/datapoollocal/LocalPoolObjectBase.cpp +++ b/src/fsfw/datapoollocal/LocalPoolObjectBase.cpp @@ -1,10 +1,10 @@ -#include "LocalPoolObjectBase.h" -#include "LocalDataPoolManager.h" -#include "AccessLocalPoolF.h" -#include "HasLocalDataPoolIF.h" +#include "fsfw/datapoollocal/LocalPoolObjectBase.h" +#include "fsfw/datapoollocal/LocalDataPoolManager.h" +#include "fsfw/datapoollocal/AccessLocalPoolF.h" +#include "fsfw/datapoollocal/HasLocalDataPoolIF.h" #include "internal/HasLocalDpIFUserAttorney.h" -#include "../objectmanager/ObjectManagerIF.h" +#include "fsfw/objectmanager/ObjectManager.h" LocalPoolObjectBase::LocalPoolObjectBase(lp_id_t poolId, HasLocalDataPoolIF* hkOwner, @@ -43,7 +43,7 @@ LocalPoolObjectBase::LocalPoolObjectBase(object_id_t poolOwner, lp_id_t poolId, "which is the NO_PARAMETER value!\n"); #endif } - HasLocalDataPoolIF* hkOwner = objectManager->get(poolOwner); + HasLocalDataPoolIF* hkOwner = ObjectManager::instance()->get(poolOwner); if(hkOwner == nullptr) { #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "LocalPoolVariable: The supplied pool owner did not implement the correct " diff --git a/datapoollocal/LocalPoolObjectBase.h b/src/fsfw/datapoollocal/LocalPoolObjectBase.h similarity index 93% rename from datapoollocal/LocalPoolObjectBase.h rename to src/fsfw/datapoollocal/LocalPoolObjectBase.h index 3f7fb6dd..72275646 100644 --- a/datapoollocal/LocalPoolObjectBase.h +++ b/src/fsfw/datapoollocal/LocalPoolObjectBase.h @@ -4,9 +4,9 @@ #include "MarkChangedIF.h" #include "localPoolDefinitions.h" -#include "../objectmanager/SystemObjectIF.h" -#include "../datapool/PoolVariableIF.h" -#include "../returnvalues/HasReturnvaluesIF.h" +#include "fsfw/objectmanager/SystemObjectIF.h" +#include "fsfw/datapool/PoolVariableIF.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" class LocalDataPoolManager; class DataSetIF; diff --git a/datapoollocal/LocalPoolVariable.h b/src/fsfw/datapoollocal/LocalPoolVariable.h similarity index 100% rename from datapoollocal/LocalPoolVariable.h rename to src/fsfw/datapoollocal/LocalPoolVariable.h diff --git a/datapoollocal/LocalPoolVariable.tpp b/src/fsfw/datapoollocal/LocalPoolVariable.tpp similarity index 100% rename from datapoollocal/LocalPoolVariable.tpp rename to src/fsfw/datapoollocal/LocalPoolVariable.tpp diff --git a/datapoollocal/LocalPoolVector.h b/src/fsfw/datapoollocal/LocalPoolVector.h similarity index 100% rename from datapoollocal/LocalPoolVector.h rename to src/fsfw/datapoollocal/LocalPoolVector.h diff --git a/datapoollocal/LocalPoolVector.tpp b/src/fsfw/datapoollocal/LocalPoolVector.tpp similarity index 100% rename from datapoollocal/LocalPoolVector.tpp rename to src/fsfw/datapoollocal/LocalPoolVector.tpp diff --git a/datapoollocal/MarkChangedIF.h b/src/fsfw/datapoollocal/MarkChangedIF.h similarity index 100% rename from datapoollocal/MarkChangedIF.h rename to src/fsfw/datapoollocal/MarkChangedIF.h diff --git a/datapoollocal/ProvidesDataPoolSubscriptionIF.h b/src/fsfw/datapoollocal/ProvidesDataPoolSubscriptionIF.h similarity index 100% rename from datapoollocal/ProvidesDataPoolSubscriptionIF.h rename to src/fsfw/datapoollocal/ProvidesDataPoolSubscriptionIF.h diff --git a/datapoollocal/SharedLocalDataSet.cpp b/src/fsfw/datapoollocal/SharedLocalDataSet.cpp similarity index 96% rename from datapoollocal/SharedLocalDataSet.cpp rename to src/fsfw/datapoollocal/SharedLocalDataSet.cpp index 84c2d1c3..2ee00aca 100644 --- a/datapoollocal/SharedLocalDataSet.cpp +++ b/src/fsfw/datapoollocal/SharedLocalDataSet.cpp @@ -1,4 +1,4 @@ -#include "SharedLocalDataSet.h" +#include "fsfw/datapoollocal/SharedLocalDataSet.h" SharedLocalDataSet::SharedLocalDataSet(object_id_t objectId, sid_t sid, diff --git a/datapoollocal/SharedLocalDataSet.h b/src/fsfw/datapoollocal/SharedLocalDataSet.h similarity index 100% rename from datapoollocal/SharedLocalDataSet.h rename to src/fsfw/datapoollocal/SharedLocalDataSet.h diff --git a/datapoollocal/StaticLocalDataSet.h b/src/fsfw/datapoollocal/StaticLocalDataSet.h similarity index 100% rename from datapoollocal/StaticLocalDataSet.h rename to src/fsfw/datapoollocal/StaticLocalDataSet.h diff --git a/datapoollocal/internal/CMakeLists.txt b/src/fsfw/datapoollocal/internal/CMakeLists.txt similarity index 100% rename from datapoollocal/internal/CMakeLists.txt rename to src/fsfw/datapoollocal/internal/CMakeLists.txt diff --git a/datapoollocal/internal/HasLocalDpIFManagerAttorney.cpp b/src/fsfw/datapoollocal/internal/HasLocalDpIFManagerAttorney.cpp similarity index 76% rename from datapoollocal/internal/HasLocalDpIFManagerAttorney.cpp rename to src/fsfw/datapoollocal/internal/HasLocalDpIFManagerAttorney.cpp index 65feda75..a275626b 100644 --- a/datapoollocal/internal/HasLocalDpIFManagerAttorney.cpp +++ b/src/fsfw/datapoollocal/internal/HasLocalDpIFManagerAttorney.cpp @@ -1,7 +1,7 @@ #include "HasLocalDpIFManagerAttorney.h" -#include "../LocalPoolObjectBase.h" -#include "../LocalPoolDataSetBase.h" -#include "../HasLocalDataPoolIF.h" +#include "fsfw/datapoollocal/LocalPoolObjectBase.h" +#include "fsfw/datapoollocal/LocalPoolDataSetBase.h" +#include "fsfw/datapoollocal/HasLocalDataPoolIF.h" LocalPoolDataSetBase* HasLocalDpIFManagerAttorney::getDataSetHandle(HasLocalDataPoolIF* clientIF, sid_t sid) { diff --git a/datapoollocal/internal/HasLocalDpIFManagerAttorney.h b/src/fsfw/datapoollocal/internal/HasLocalDpIFManagerAttorney.h similarity index 92% rename from datapoollocal/internal/HasLocalDpIFManagerAttorney.h rename to src/fsfw/datapoollocal/internal/HasLocalDpIFManagerAttorney.h index dfe333a6..a82ee489 100644 --- a/datapoollocal/internal/HasLocalDpIFManagerAttorney.h +++ b/src/fsfw/datapoollocal/internal/HasLocalDpIFManagerAttorney.h @@ -1,7 +1,7 @@ #ifndef FSFW_DATAPOOLLOCAL_HASLOCALDPIFMANAGERATTORNEY_H_ #define FSFW_DATAPOOLLOCAL_HASLOCALDPIFMANAGERATTORNEY_H_ -#include "../localPoolDefinitions.h" +#include "fsfw/datapoollocal/localPoolDefinitions.h" class HasLocalDataPoolIF; class LocalPoolDataSetBase; diff --git a/datapoollocal/internal/HasLocalDpIFUserAttorney.cpp b/src/fsfw/datapoollocal/internal/HasLocalDpIFUserAttorney.cpp similarity index 63% rename from datapoollocal/internal/HasLocalDpIFUserAttorney.cpp rename to src/fsfw/datapoollocal/internal/HasLocalDpIFUserAttorney.cpp index 838204a7..8c52fbfb 100644 --- a/datapoollocal/internal/HasLocalDpIFUserAttorney.cpp +++ b/src/fsfw/datapoollocal/internal/HasLocalDpIFUserAttorney.cpp @@ -1,6 +1,6 @@ #include "HasLocalDpIFUserAttorney.h" -#include "../AccessLocalPoolF.h" -#include "../HasLocalDataPoolIF.h" +#include "fsfw/datapoollocal/AccessLocalPoolF.h" +#include "fsfw/datapoollocal/HasLocalDataPoolIF.h" AccessPoolManagerIF* HasLocalDpIFUserAttorney::getAccessorHandle(HasLocalDataPoolIF *clientIF) { return clientIF->getAccessorHandle(); diff --git a/datapoollocal/internal/HasLocalDpIFUserAttorney.h b/src/fsfw/datapoollocal/internal/HasLocalDpIFUserAttorney.h similarity index 100% rename from datapoollocal/internal/HasLocalDpIFUserAttorney.h rename to src/fsfw/datapoollocal/internal/HasLocalDpIFUserAttorney.h diff --git a/datapoollocal/internal/LocalDpManagerAttorney.h b/src/fsfw/datapoollocal/internal/LocalDpManagerAttorney.h similarity index 100% rename from datapoollocal/internal/LocalDpManagerAttorney.h rename to src/fsfw/datapoollocal/internal/LocalDpManagerAttorney.h diff --git a/datapoollocal/internal/LocalPoolDataSetAttorney.h b/src/fsfw/datapoollocal/internal/LocalPoolDataSetAttorney.h similarity index 95% rename from datapoollocal/internal/LocalPoolDataSetAttorney.h rename to src/fsfw/datapoollocal/internal/LocalPoolDataSetAttorney.h index f81428cd..9e46cffd 100644 --- a/datapoollocal/internal/LocalPoolDataSetAttorney.h +++ b/src/fsfw/datapoollocal/internal/LocalPoolDataSetAttorney.h @@ -1,7 +1,7 @@ #ifndef FSFW_DATAPOOLLOCAL_LOCALPOOLDATASETATTORNEY_H_ #define FSFW_DATAPOOLLOCAL_LOCALPOOLDATASETATTORNEY_H_ -#include "../LocalPoolDataSetBase.h" +#include "fsfw/datapoollocal/LocalPoolDataSetBase.h" class LocalPoolDataSetAttorney { private: diff --git a/datapoollocal/localPoolDefinitions.h b/src/fsfw/datapoollocal/localPoolDefinitions.h similarity index 100% rename from datapoollocal/localPoolDefinitions.h rename to src/fsfw/datapoollocal/localPoolDefinitions.h diff --git a/devicehandlers/AcceptsDeviceResponsesIF.h b/src/fsfw/devicehandlers/AcceptsDeviceResponsesIF.h similarity index 100% rename from devicehandlers/AcceptsDeviceResponsesIF.h rename to src/fsfw/devicehandlers/AcceptsDeviceResponsesIF.h diff --git a/devicehandlers/AssemblyBase.cpp b/src/fsfw/devicehandlers/AssemblyBase.cpp similarity index 99% rename from devicehandlers/AssemblyBase.cpp rename to src/fsfw/devicehandlers/AssemblyBase.cpp index 46b2211a..146adfcb 100644 --- a/devicehandlers/AssemblyBase.cpp +++ b/src/fsfw/devicehandlers/AssemblyBase.cpp @@ -1,4 +1,4 @@ -#include "AssemblyBase.h" +#include "fsfw/devicehandlers/AssemblyBase.h" AssemblyBase::AssemblyBase(object_id_t objectId, object_id_t parentId, uint16_t commandQueueDepth) : diff --git a/devicehandlers/AssemblyBase.h b/src/fsfw/devicehandlers/AssemblyBase.h similarity index 100% rename from devicehandlers/AssemblyBase.h rename to src/fsfw/devicehandlers/AssemblyBase.h diff --git a/devicehandlers/CMakeLists.txt b/src/fsfw/devicehandlers/CMakeLists.txt similarity index 100% rename from devicehandlers/CMakeLists.txt rename to src/fsfw/devicehandlers/CMakeLists.txt diff --git a/devicehandlers/ChildHandlerBase.cpp b/src/fsfw/devicehandlers/ChildHandlerBase.cpp similarity index 86% rename from devicehandlers/ChildHandlerBase.cpp rename to src/fsfw/devicehandlers/ChildHandlerBase.cpp index d4ef67ad..e6508727 100644 --- a/devicehandlers/ChildHandlerBase.cpp +++ b/src/fsfw/devicehandlers/ChildHandlerBase.cpp @@ -1,6 +1,5 @@ -#include "ChildHandlerBase.h" -#include "../subsystem/SubsystemBase.h" -#include "../subsystem/SubsystemBase.h" +#include "fsfw/devicehandlers/ChildHandlerBase.h" +#include "fsfw/subsystem/SubsystemBase.h" ChildHandlerBase::ChildHandlerBase(object_id_t setObjectId, object_id_t deviceCommunication, CookieIF * cookie, @@ -30,7 +29,7 @@ ReturnValue_t ChildHandlerBase::initialize() { MessageQueueId_t parentQueue = 0; if (parentId != objects::NO_OBJECT) { - SubsystemBase *parent = objectManager->get(parentId); + SubsystemBase *parent = ObjectManager::instance()->get(parentId); if (parent == NULL) { return RETURN_FAILED; } diff --git a/devicehandlers/ChildHandlerBase.h b/src/fsfw/devicehandlers/ChildHandlerBase.h similarity index 100% rename from devicehandlers/ChildHandlerBase.h rename to src/fsfw/devicehandlers/ChildHandlerBase.h diff --git a/devicehandlers/ChildHandlerFDIR.cpp b/src/fsfw/devicehandlers/ChildHandlerFDIR.cpp similarity index 84% rename from devicehandlers/ChildHandlerFDIR.cpp rename to src/fsfw/devicehandlers/ChildHandlerFDIR.cpp index cb4c75ea..e1d1321d 100644 --- a/devicehandlers/ChildHandlerFDIR.cpp +++ b/src/fsfw/devicehandlers/ChildHandlerFDIR.cpp @@ -1,4 +1,4 @@ -#include "ChildHandlerFDIR.h" +#include "fsfw/devicehandlers/ChildHandlerFDIR.h" ChildHandlerFDIR::ChildHandlerFDIR(object_id_t owner, object_id_t faultTreeParent, uint32_t recoveryCount) : diff --git a/devicehandlers/ChildHandlerFDIR.h b/src/fsfw/devicehandlers/ChildHandlerFDIR.h similarity index 100% rename from devicehandlers/ChildHandlerFDIR.h rename to src/fsfw/devicehandlers/ChildHandlerFDIR.h diff --git a/devicehandlers/CookieIF.h b/src/fsfw/devicehandlers/CookieIF.h similarity index 100% rename from devicehandlers/CookieIF.h rename to src/fsfw/devicehandlers/CookieIF.h diff --git a/devicehandlers/DeviceCommunicationIF.h b/src/fsfw/devicehandlers/DeviceCommunicationIF.h similarity index 100% rename from devicehandlers/DeviceCommunicationIF.h rename to src/fsfw/devicehandlers/DeviceCommunicationIF.h diff --git a/devicehandlers/DeviceHandlerBase.cpp b/src/fsfw/devicehandlers/DeviceHandlerBase.cpp similarity index 93% rename from devicehandlers/DeviceHandlerBase.cpp rename to src/fsfw/devicehandlers/DeviceHandlerBase.cpp index 1623a1ac..535113fd 100644 --- a/devicehandlers/DeviceHandlerBase.cpp +++ b/src/fsfw/devicehandlers/DeviceHandlerBase.cpp @@ -1,17 +1,17 @@ -#include "DeviceHandlerBase.h" -#include "AcceptsDeviceResponsesIF.h" -#include "DeviceTmReportingWrapper.h" +#include "fsfw/devicehandlers/DeviceHandlerBase.h" +#include "fsfw/devicehandlers/AcceptsDeviceResponsesIF.h" +#include "fsfw/devicehandlers/DeviceTmReportingWrapper.h" -#include "../serviceinterface/ServiceInterface.h" -#include "../objectmanager/ObjectManager.h" -#include "../storagemanager/StorageManagerIF.h" -#include "../thermal/ThermalComponentIF.h" -#include "../globalfunctions/CRC.h" -#include "../housekeeping/HousekeepingMessage.h" -#include "../ipc/MessageQueueMessage.h" -#include "../ipc/QueueFactory.h" -#include "../subsystem/SubsystemBase.h" -#include "../datapoollocal/LocalPoolVariable.h" +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/storagemanager/StorageManagerIF.h" +#include "fsfw/thermal/ThermalComponentIF.h" +#include "fsfw/globalfunctions/CRC.h" +#include "fsfw/housekeeping/HousekeepingMessage.h" +#include "fsfw/ipc/MessageQueueMessage.h" +#include "fsfw/ipc/QueueFactory.h" +#include "fsfw/subsystem/SubsystemBase.h" +#include "fsfw/datapoollocal/LocalPoolVariable.h" object_id_t DeviceHandlerBase::powerSwitcherId = objects::NO_OBJECT; object_id_t DeviceHandlerBase::rawDataReceiverId = objects::NO_OBJECT; @@ -119,7 +119,7 @@ ReturnValue_t DeviceHandlerBase::initialize() { return result; } - communicationInterface = objectManager->get( + communicationInterface = ObjectManager::instance()->get( deviceCommunicationId); if (communicationInterface == nullptr) { printWarningOrError(sif::OutputTypes::OUT_ERROR, "initialize", @@ -136,7 +136,7 @@ ReturnValue_t DeviceHandlerBase::initialize() { return result; } - IPCStore = objectManager->get(objects::IPC_STORE); + IPCStore = ObjectManager::instance()->get(objects::IPC_STORE); if (IPCStore == nullptr) { printWarningOrError(sif::OutputTypes::OUT_ERROR, "initialize", ObjectManagerIF::CHILD_INIT_FAILED, "IPC Store not set up"); @@ -144,8 +144,8 @@ ReturnValue_t DeviceHandlerBase::initialize() { } if(rawDataReceiverId != objects::NO_OBJECT) { - AcceptsDeviceResponsesIF *rawReceiver = objectManager->get< - AcceptsDeviceResponsesIF>(rawDataReceiverId); + AcceptsDeviceResponsesIF *rawReceiver = ObjectManager::instance()-> + get(rawDataReceiverId); if (rawReceiver == nullptr) { printWarningOrError(sif::OutputTypes::OUT_ERROR, @@ -164,7 +164,7 @@ ReturnValue_t DeviceHandlerBase::initialize() { } if(powerSwitcherId != objects::NO_OBJECT) { - powerSwitcher = objectManager->get(powerSwitcherId); + powerSwitcher = ObjectManager::instance()->get(powerSwitcherId); if (powerSwitcher == nullptr) { printWarningOrError(sif::OutputTypes::OUT_ERROR, "initialize", ObjectManagerIF::CHILD_INIT_FAILED, @@ -226,16 +226,15 @@ ReturnValue_t DeviceHandlerBase::initialize() { } void DeviceHandlerBase::decrementDeviceReplyMap() { - for (std::map::iterator iter = - deviceReplyMap.begin(); iter != deviceReplyMap.end(); iter++) { - if (iter->second.delayCycles != 0) { - iter->second.delayCycles--; - if (iter->second.delayCycles == 0) { - if (iter->second.periodic) { - iter->second.delayCycles = iter->second.maxDelayCycles; + for (std::pair& replyPair: deviceReplyMap) { + if (replyPair.second.delayCycles != 0) { + replyPair.second.delayCycles--; + if (replyPair.second.delayCycles == 0) { + if (replyPair.second.periodic) { + replyPair.second.delayCycles = replyPair.second.maxDelayCycles; } - replyToReply(iter, TIMEOUT); - missedReply(iter->first); + replyToReply(replyPair.first, replyPair.second, TIMEOUT); + missedReply(replyPair.first); } } } @@ -462,7 +461,7 @@ size_t DeviceHandlerBase::getNextReplyLength(DeviceCommandId_t commandId){ return iter->second.replyLen; }else{ return 0; - } + } } ReturnValue_t DeviceHandlerBase::updateReplyMapEntry(DeviceCommandId_t deviceReply, @@ -470,7 +469,7 @@ ReturnValue_t DeviceHandlerBase::updateReplyMapEntry(DeviceCommandId_t deviceRep auto replyIter = deviceReplyMap.find(deviceReply); if (replyIter == deviceReplyMap.end()) { triggerEvent(INVALID_DEVICE_COMMAND, deviceReply); - return RETURN_FAILED; + return COMMAND_NOT_SUPPORTED; } else { DeviceReplyInfo *info = &(replyIter->second); if (maxDelayCycles != 0) { @@ -482,6 +481,25 @@ ReturnValue_t DeviceHandlerBase::updateReplyMapEntry(DeviceCommandId_t deviceRep } } +ReturnValue_t DeviceHandlerBase::updatePeriodicReply(bool enable, DeviceCommandId_t deviceReply) { + auto replyIter = deviceReplyMap.find(deviceReply); + if (replyIter == deviceReplyMap.end()) { + triggerEvent(INVALID_DEVICE_COMMAND, deviceReply); + return COMMAND_NOT_SUPPORTED; + } else { + DeviceReplyInfo *info = &(replyIter->second); + if(not info->periodic) { + return COMMAND_NOT_SUPPORTED; + } + if(enable) { + info->delayCycles = info->maxDelayCycles; + } + else { + info->delayCycles = 0; + } + } + return HasReturnvaluesIF::RETURN_OK; +} ReturnValue_t DeviceHandlerBase::setReplyDataset(DeviceCommandId_t replyId, LocalPoolDataSetBase *dataSet) { @@ -584,17 +602,28 @@ void DeviceHandlerBase::replyToCommand(ReturnValue_t status, } } -void DeviceHandlerBase::replyToReply(DeviceReplyMap::iterator iter, +void DeviceHandlerBase::replyToReply(const DeviceCommandId_t command, DeviceReplyInfo& replyInfo, ReturnValue_t status) { // No need to check if iter exists, as this is checked by callers. // If someone else uses the method, add check. - if (iter->second.command == deviceCommandMap.end()) { + if (replyInfo.command == deviceCommandMap.end()) { //Is most likely periodic reply. Silent return. return; } + DeviceCommandInfo* info = &replyInfo.command->second; + if (info == nullptr){ + printWarningOrError(sif::OutputTypes::OUT_ERROR, + "replyToReply", HasReturnvaluesIF::RETURN_FAILED, + "Command pointer not found"); + return; + } + + if (info->expectedReplies > 0){ + // Check before to avoid underflow + info->expectedReplies--; + } // Check if more replies are expected. If so, do nothing. - DeviceCommandInfo* info = &(iter->second.command->second); - if (--info->expectedReplies == 0) { + if (info->expectedReplies == 0) { // Check if it was transition or internal command. // Don't send any replies in that case. if (info->sendReplyTo != NO_COMMANDER) { @@ -602,7 +631,7 @@ void DeviceHandlerBase::replyToReply(DeviceReplyMap::iterator iter, if(status == HasReturnvaluesIF::RETURN_OK) { success = true; } - actionHelper.finish(success, info->sendReplyTo, iter->first, status); + actionHelper.finish(success, info->sendReplyTo, command, status); } info->isExecuting = false; } @@ -801,7 +830,7 @@ void DeviceHandlerBase::handleReply(const uint8_t* receivedData, replyRawReplyIfnotWiretapped(receivedData, foundLen); triggerEvent(DEVICE_INTERPRETING_REPLY_FAILED, result, foundId); } - replyToReply(iter, result); + replyToReply(iter->first, iter->second, result); } else { /* Other completion failure messages are created by timeout. @@ -1326,10 +1355,20 @@ void DeviceHandlerBase::buildInternalCommand(void) { DeviceCommandMap::iterator iter = deviceCommandMap.find( deviceCommandId); if (iter == deviceCommandMap.end()) { +#if FSFW_VERBOSE_LEVEL >= 1 + char output[36]; + sprintf(output, "Command 0x%08x unknown", + static_cast(deviceCommandId)); + // so we can track misconfigurations + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "buildInternalCommand", + COMMAND_NOT_SUPPORTED, + output); +#endif result = COMMAND_NOT_SUPPORTED; } else if (iter->second.isExecuting) { -#if FSFW_DISABLE_PRINTOUT == 0 +#if FSFW_VERBOSE_LEVEL >= 1 char output[36]; sprintf(output, "Command 0x%08x is executing", static_cast(deviceCommandId)); @@ -1540,7 +1579,7 @@ LocalDataPoolManager* DeviceHandlerBase::getHkManagerHandle() { return &poolManager; } -MessageQueueId_t DeviceHandlerBase::getCommanderId(DeviceCommandId_t replyId) const { +MessageQueueId_t DeviceHandlerBase::getCommanderQueueId(DeviceCommandId_t replyId) const { auto commandIter = deviceCommandMap.find(replyId); if(commandIter == deviceCommandMap.end()) { return MessageQueueIF::NO_QUEUE; diff --git a/devicehandlers/DeviceHandlerBase.h b/src/fsfw/devicehandlers/DeviceHandlerBase.h similarity index 96% rename from devicehandlers/DeviceHandlerBase.h rename to src/fsfw/devicehandlers/DeviceHandlerBase.h index 496c08ff..b182b611 100644 --- a/devicehandlers/DeviceHandlerBase.h +++ b/src/fsfw/devicehandlers/DeviceHandlerBase.h @@ -6,22 +6,22 @@ #include "DeviceHandlerFailureIsolation.h" #include "DeviceHandlerThermalSet.h" -#include "../serviceinterface/ServiceInterface.h" -#include "../serviceinterface/serviceInterfaceDefintions.h" -#include "../objectmanager/SystemObject.h" -#include "../tasks/ExecutableObjectIF.h" -#include "../returnvalues/HasReturnvaluesIF.h" -#include "../action/HasActionsIF.h" -#include "../datapool/PoolVariableIF.h" -#include "../modes/HasModesIF.h" -#include "../power/PowerSwitchIF.h" -#include "../ipc/MessageQueueIF.h" -#include "../tasks/PeriodicTaskIF.h" -#include "../action/ActionHelper.h" -#include "../health/HealthHelper.h" -#include "../parameters/ParameterHelper.h" -#include "../datapoollocal/HasLocalDataPoolIF.h" -#include "../datapoollocal/LocalDataPoolManager.h" +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/serviceinterface/serviceInterfaceDefintions.h" +#include "fsfw/objectmanager/SystemObject.h" +#include "fsfw/tasks/ExecutableObjectIF.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" +#include "fsfw/action/HasActionsIF.h" +#include "fsfw/datapool/PoolVariableIF.h" +#include "fsfw/modes/HasModesIF.h" +#include "fsfw/power/PowerSwitchIF.h" +#include "fsfw/ipc/MessageQueueIF.h" +#include "fsfw/tasks/PeriodicTaskIF.h" +#include "fsfw/action/ActionHelper.h" +#include "fsfw/health/HealthHelper.h" +#include "fsfw/parameters/ParameterHelper.h" +#include "fsfw/datapoollocal/HasLocalDataPoolIF.h" +#include "fsfw/datapoollocal/LocalDataPoolManager.h" #include @@ -399,7 +399,7 @@ protected: */ virtual ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) = 0; - MessageQueueId_t getCommanderId(DeviceCommandId_t replyId) const; + MessageQueueId_t getCommanderQueueId(DeviceCommandId_t replyId) const; /** * Helper function to get pending command. This is useful for devices * like SPI sensors to identify the last sent command. @@ -449,7 +449,9 @@ protected: * @param replyLen Will be supplied to the requestReceiveMessage call of * the communication interface. * @param periodic Indicates if the command is periodic (i.e. it is sent - * by the device repeatedly without request) or not. Default is aperiodic (0) + * by the device repeatedly without request) or not. Default is aperiodic (0). + * Please note that periodic replies are disabled by default. You can enable them with + * #updatePeriodicReply * @return - @c RETURN_OK when the command was successfully inserted, * - @c RETURN_FAILED else. */ @@ -464,7 +466,9 @@ protected: * @param maxDelayCycles The maximum number of delay cycles the reply waits * until it times out. * @param periodic Indicates if the command is periodic (i.e. it is sent - * by the device repeatedly without request) or not. Default is aperiodic (0) + * by the device repeatedly without request) or not. Default is aperiodic (0). + * Please note that periodic replies are disabled by default. You can enable them with + * #updatePeriodicReply * @return - @c RETURN_OK when the command was successfully inserted, * - @c RETURN_FAILED else. */ @@ -480,6 +484,14 @@ protected: */ ReturnValue_t insertInCommandMap(DeviceCommandId_t deviceCommand); + /** + * Enables a periodic reply for a given command. It sets to delay cycles to the specified + * maximum delay cycles for a given reply ID if enabled or to 0 if disabled. + * @param enable Specify whether to enable or disable a given periodic reply + * @return + */ + ReturnValue_t updatePeriodicReply(bool enable, DeviceCommandId_t deviceReply); + /** * @brief This function returns the reply length of the next reply to read. * @@ -493,16 +505,14 @@ protected: virtual size_t getNextReplyLength(DeviceCommandId_t deviceCommand); /** - * @brief This is a helper method to facilitate updating entries - * in the reply map. + * @brief This is a helper method to facilitate updating entries in the reply map. * @param deviceCommand Identifier of the reply to update. - * @param delayCycles The current number of delay cycles to wait. - * As stated in #fillCommandAndCookieMap, to disable periodic commands, - * this is set to zero. + * @param delayCycles The current number of delay cycles to wait. As stated in + * #fillCommandAndReplyMap, to disable periodic commands, this is set to zero. * @param maxDelayCycles The maximum number of delay cycles the reply waits * until it times out. By passing 0 the entry remains untouched. * @param periodic Indicates if the command is periodic (i.e. it is sent - * by the device repeatedly without request) or not.Default is aperiodic (0). + * by the device repeatedly without request) or not. Default is aperiodic (0). * Warning: The setting always overrides the value that was entered in the map. * @return - @c RETURN_OK when the command was successfully inserted, * - @c RETURN_FAILED else. @@ -667,7 +677,7 @@ protected: static const ReturnValue_t CHILD_TIMEOUT = MAKE_RETURN_CODE(0xE0); static const ReturnValue_t SWITCH_FAILED = MAKE_RETURN_CODE(0xE1); - static const MessageQueueId_t NO_COMMANDER = 0; + static const MessageQueueId_t NO_COMMANDER = MessageQueueIF::NO_QUEUE; //! Pointer to the raw packet that will be sent. uint8_t *rawPacket = nullptr; @@ -1195,7 +1205,8 @@ private: * @foundLen the length of the packet */ void handleReply(const uint8_t *data, DeviceCommandId_t id, uint32_t foundLen); - void replyToReply(DeviceReplyMap::iterator iter, ReturnValue_t status); + void replyToReply(const DeviceCommandId_t command, DeviceReplyInfo& replyInfo, + ReturnValue_t status); /** * Build and send a command to the device. diff --git a/devicehandlers/DeviceHandlerFailureIsolation.cpp b/src/fsfw/devicehandlers/DeviceHandlerFailureIsolation.cpp similarity index 94% rename from devicehandlers/DeviceHandlerFailureIsolation.cpp rename to src/fsfw/devicehandlers/DeviceHandlerFailureIsolation.cpp index ba118090..8b1c1489 100644 --- a/devicehandlers/DeviceHandlerFailureIsolation.cpp +++ b/src/fsfw/devicehandlers/DeviceHandlerFailureIsolation.cpp @@ -1,11 +1,12 @@ -#include "DeviceHandlerFailureIsolation.h" +#include "fsfw/devicehandlers/DeviceHandlerFailureIsolation.h" -#include "../devicehandlers/DeviceHandlerIF.h" -#include "../modes/HasModesIF.h" -#include "../health/HealthTableIF.h" -#include "../power/Fuse.h" -#include "../serviceinterface/ServiceInterfaceStream.h" -#include "../thermal/ThermalComponentIF.h" +#include "fsfw/devicehandlers/DeviceHandlerIF.h" +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/modes/HasModesIF.h" +#include "fsfw/health/HealthTableIF.h" +#include "fsfw/power/Fuse.h" +#include "fsfw/serviceinterface/ServiceInterfaceStream.h" +#include "fsfw/thermal/ThermalComponentIF.h" object_id_t DeviceHandlerFailureIsolation::powerConfirmationId = objects::NO_OBJECT; @@ -175,7 +176,7 @@ ReturnValue_t DeviceHandlerFailureIsolation::initialize() { #endif return result; } - ConfirmsFailuresIF* power = objectManager->get( + ConfirmsFailuresIF* power = ObjectManager::instance()->get( powerConfirmationId); if (power != nullptr) { powerConfirmation = power->getEventReceptionQueue(); diff --git a/devicehandlers/DeviceHandlerFailureIsolation.h b/src/fsfw/devicehandlers/DeviceHandlerFailureIsolation.h similarity index 100% rename from devicehandlers/DeviceHandlerFailureIsolation.h rename to src/fsfw/devicehandlers/DeviceHandlerFailureIsolation.h diff --git a/devicehandlers/DeviceHandlerIF.h b/src/fsfw/devicehandlers/DeviceHandlerIF.h similarity index 99% rename from devicehandlers/DeviceHandlerIF.h rename to src/fsfw/devicehandlers/DeviceHandlerIF.h index fc31cce0..1933c571 100644 --- a/devicehandlers/DeviceHandlerIF.h +++ b/src/fsfw/devicehandlers/DeviceHandlerIF.h @@ -104,7 +104,8 @@ public: static const Event DEVICE_MISSED_REPLY = MAKE_EVENT(5, severity::LOW); static const Event DEVICE_UNKNOWN_REPLY = MAKE_EVENT(6, severity::LOW); static const Event DEVICE_UNREQUESTED_REPLY = MAKE_EVENT(7, severity::LOW); - static const Event INVALID_DEVICE_COMMAND = MAKE_EVENT(8, severity::LOW); //!< Indicates a SW bug in child class. + //! [EXPORT] : [COMMENT] Indicates a SW bug in child class. + static const Event INVALID_DEVICE_COMMAND = MAKE_EVENT(8, severity::LOW); static const Event MONITORING_LIMIT_EXCEEDED = MAKE_EVENT(9, severity::LOW); static const Event MONITORING_AMBIGUOUS = MAKE_EVENT(10, severity::HIGH); diff --git a/devicehandlers/DeviceHandlerMessage.cpp b/src/fsfw/devicehandlers/DeviceHandlerMessage.cpp similarity index 93% rename from devicehandlers/DeviceHandlerMessage.cpp rename to src/fsfw/devicehandlers/DeviceHandlerMessage.cpp index cb9043db..48277c9a 100644 --- a/devicehandlers/DeviceHandlerMessage.cpp +++ b/src/fsfw/devicehandlers/DeviceHandlerMessage.cpp @@ -1,5 +1,5 @@ -#include "DeviceHandlerMessage.h" -#include "../objectmanager/ObjectManagerIF.h" +#include "fsfw/devicehandlers/DeviceHandlerMessage.h" +#include "fsfw/objectmanager/ObjectManager.h" store_address_t DeviceHandlerMessage::getStoreAddress( const CommandMessage* message) { @@ -70,7 +70,7 @@ void DeviceHandlerMessage::clear(CommandMessage* message) { case REPLY_RAW_COMMAND: case REPLY_RAW_REPLY: case REPLY_DIRECT_COMMAND_DATA: { - StorageManagerIF *ipcStore = objectManager->get( + StorageManagerIF *ipcStore = ObjectManager::instance()->get( objects::IPC_STORE); if (ipcStore != nullptr) { ipcStore->deleteData(getStoreAddress(message)); diff --git a/devicehandlers/DeviceHandlerMessage.h b/src/fsfw/devicehandlers/DeviceHandlerMessage.h similarity index 100% rename from devicehandlers/DeviceHandlerMessage.h rename to src/fsfw/devicehandlers/DeviceHandlerMessage.h diff --git a/devicehandlers/DeviceHandlerThermalSet.h b/src/fsfw/devicehandlers/DeviceHandlerThermalSet.h similarity index 100% rename from devicehandlers/DeviceHandlerThermalSet.h rename to src/fsfw/devicehandlers/DeviceHandlerThermalSet.h diff --git a/devicehandlers/DeviceTmReportingWrapper.cpp b/src/fsfw/devicehandlers/DeviceTmReportingWrapper.cpp similarity index 93% rename from devicehandlers/DeviceTmReportingWrapper.cpp rename to src/fsfw/devicehandlers/DeviceTmReportingWrapper.cpp index c70f57d6..0300a24a 100644 --- a/devicehandlers/DeviceTmReportingWrapper.cpp +++ b/src/fsfw/devicehandlers/DeviceTmReportingWrapper.cpp @@ -1,5 +1,5 @@ -#include "DeviceTmReportingWrapper.h" -#include "../serialize/SerializeAdapter.h" +#include "fsfw/devicehandlers/DeviceTmReportingWrapper.h" +#include "fsfw/serialize/SerializeAdapter.h" DeviceTmReportingWrapper::DeviceTmReportingWrapper(object_id_t objectId, ActionId_t actionId, SerializeIF* data) : diff --git a/devicehandlers/DeviceTmReportingWrapper.h b/src/fsfw/devicehandlers/DeviceTmReportingWrapper.h similarity index 100% rename from devicehandlers/DeviceTmReportingWrapper.h rename to src/fsfw/devicehandlers/DeviceTmReportingWrapper.h diff --git a/devicehandlers/HealthDevice.cpp b/src/fsfw/devicehandlers/HealthDevice.cpp similarity index 95% rename from devicehandlers/HealthDevice.cpp rename to src/fsfw/devicehandlers/HealthDevice.cpp index e23dd5b6..2f6e1dfb 100644 --- a/devicehandlers/HealthDevice.cpp +++ b/src/fsfw/devicehandlers/HealthDevice.cpp @@ -1,5 +1,5 @@ -#include "HealthDevice.h" -#include "../ipc/QueueFactory.h" +#include "fsfw/devicehandlers/HealthDevice.h" +#include "fsfw/ipc/QueueFactory.h" HealthDevice::HealthDevice(object_id_t setObjectId, MessageQueueId_t parentQueue) : diff --git a/devicehandlers/HealthDevice.h b/src/fsfw/devicehandlers/HealthDevice.h similarity index 79% rename from devicehandlers/HealthDevice.h rename to src/fsfw/devicehandlers/HealthDevice.h index 738f0c7e..bf9cdb82 100644 --- a/devicehandlers/HealthDevice.h +++ b/src/fsfw/devicehandlers/HealthDevice.h @@ -1,11 +1,11 @@ #ifndef FSFW_DEVICEHANDLERS_HEALTHDEVICE_H_ #define FSFW_DEVICEHANDLERS_HEALTHDEVICE_H_ -#include "../health/HasHealthIF.h" -#include "../health/HealthHelper.h" -#include "../objectmanager/SystemObject.h" -#include "../tasks/ExecutableObjectIF.h" -#include "../ipc/MessageQueueIF.h" +#include "fsfw/health/HasHealthIF.h" +#include "fsfw/health/HealthHelper.h" +#include "fsfw/objectmanager/SystemObject.h" +#include "fsfw/tasks/ExecutableObjectIF.h" +#include "fsfw/ipc/MessageQueueIF.h" class HealthDevice: public SystemObject, public ExecutableObjectIF, diff --git a/src/fsfw/events/CMakeLists.txt b/src/fsfw/events/CMakeLists.txt new file mode 100644 index 00000000..28eec772 --- /dev/null +++ b/src/fsfw/events/CMakeLists.txt @@ -0,0 +1,6 @@ +target_sources(${LIB_FSFW_NAME} PRIVATE + EventManager.cpp + EventMessage.cpp +) + +add_subdirectory(eventmatching) diff --git a/events/Event.h b/src/fsfw/events/Event.h similarity index 100% rename from events/Event.h rename to src/fsfw/events/Event.h diff --git a/src/fsfw/events/EventManager.cpp b/src/fsfw/events/EventManager.cpp new file mode 100644 index 00000000..958076a9 --- /dev/null +++ b/src/fsfw/events/EventManager.cpp @@ -0,0 +1,211 @@ +#include "fsfw/events/EventManager.h" +#include "fsfw/events/EventMessage.h" + +#include "fsfw/ipc/QueueFactory.h" +#include "fsfw/ipc/MutexFactory.h" + +MessageQueueId_t EventManagerIF::eventmanagerQueue = MessageQueueIF::NO_QUEUE; + +// If one checks registerListener calls, there are around 40 (to max 50) +// objects registering for certain events. +// Each listener requires 1 or 2 EventIdMatcher and 1 or 2 ReportRangeMatcher. +// So a good guess is 75 to a max of 100 pools required for each, which fits well. +const LocalPool::LocalPoolConfig EventManager::poolConfig = { + {fsfwconfig::FSFW_EVENTMGMR_MATCHTREE_NODES, + sizeof(EventMatchTree::Node)}, + {fsfwconfig::FSFW_EVENTMGMT_EVENTIDMATCHERS, + sizeof(EventIdRangeMatcher)}, + {fsfwconfig::FSFW_EVENTMGMR_RANGEMATCHERS, + sizeof(ReporterRangeMatcher)} +}; + +EventManager::EventManager(object_id_t setObjectId) : + SystemObject(setObjectId), + factoryBackend(0, poolConfig, false, true) { + mutex = MutexFactory::instance()->createMutex(); + eventReportQueue = QueueFactory::instance()->createMessageQueue( + MAX_EVENTS_PER_CYCLE, EventMessage::EVENT_MESSAGE_SIZE); +} + +EventManager::~EventManager() { + QueueFactory::instance()->deleteMessageQueue(eventReportQueue); + MutexFactory::instance()->deleteMutex(mutex); +} + +MessageQueueId_t EventManager::getEventReportQueue() { + return eventReportQueue->getId(); +} + +ReturnValue_t EventManager::performOperation(uint8_t opCode) { + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + while (result == HasReturnvaluesIF::RETURN_OK) { + EventMessage message; + result = eventReportQueue->receiveMessage(&message); + if (result == HasReturnvaluesIF::RETURN_OK) { +#if FSFW_OBJ_EVENT_TRANSLATION == 1 + printEvent(&message); +#endif + notifyListeners(&message); + } + } + return HasReturnvaluesIF::RETURN_OK; +} + +void EventManager::notifyListeners(EventMessage* message) { + lockMutex(); + for (auto iter = listenerList.begin(); iter != listenerList.end(); ++iter) { + if (iter->second.match(message)) { + MessageQueueSenderIF::sendMessage(iter->first, message, + message->getSender()); + } + } + unlockMutex(); +} + +ReturnValue_t EventManager::registerListener(MessageQueueId_t listener, +bool forwardAllButSelected) { + auto result = listenerList.insert( + std::pair(listener, + EventMatchTree(&factoryBackend, forwardAllButSelected))); + if (!result.second) { + return HasReturnvaluesIF::RETURN_FAILED; + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t EventManager::subscribeToEvent(MessageQueueId_t listener, + EventId_t event) { + return subscribeToEventRange(listener, event); +} + +ReturnValue_t EventManager::subscribeToAllEventsFrom(MessageQueueId_t listener, + object_id_t object) { + return subscribeToEventRange(listener, 0, 0, true, object); +} + +ReturnValue_t EventManager::subscribeToEventRange(MessageQueueId_t listener, + EventId_t idFrom, EventId_t idTo, bool idInverted, + object_id_t reporterFrom, object_id_t reporterTo, + bool reporterInverted) { + auto iter = listenerList.find(listener); + if (iter == listenerList.end()) { + return LISTENER_NOT_FOUND; + } + lockMutex(); + ReturnValue_t result = iter->second.addMatch(idFrom, idTo, idInverted, + reporterFrom, reporterTo, reporterInverted); + unlockMutex(); + return result; +} + +ReturnValue_t EventManager::unsubscribeFromEventRange(MessageQueueId_t listener, + EventId_t idFrom, EventId_t idTo, bool idInverted, + object_id_t reporterFrom, object_id_t reporterTo, + bool reporterInverted) { + auto iter = listenerList.find(listener); + if (iter == listenerList.end()) { + return LISTENER_NOT_FOUND; + } + lockMutex(); + ReturnValue_t result = iter->second.removeMatch(idFrom, idTo, idInverted, + reporterFrom, reporterTo, reporterInverted); + unlockMutex(); + return result; +} + +void EventManager::lockMutex() { + mutex->lockMutex(timeoutType, timeoutMs); +} + +void EventManager::unlockMutex() { + mutex->unlockMutex(); +} + +void EventManager::setMutexTimeout(MutexIF::TimeoutType timeoutType, + uint32_t timeoutMs) { + this->timeoutType = timeoutType; + this->timeoutMs = timeoutMs; +} + +#if FSFW_OBJ_EVENT_TRANSLATION == 1 + +void EventManager::printEvent(EventMessage* message) { + switch (message->getSeverity()) { + case severity::INFO: { +#if FSFW_DEBUG_INFO == 1 + printUtility(sif::OutputTypes::OUT_INFO, message); +#endif /* DEBUG_INFO_EVENT == 1 */ + break; + } + default: + printUtility(sif::OutputTypes::OUT_DEBUG, message); + break; + } +} + +void EventManager::printUtility(sif::OutputTypes printType, EventMessage *message) { + const char *string = 0; + if(printType == sif::OutputTypes::OUT_INFO) { + string = translateObject(message->getReporter()); +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "EventManager: "; + if (string != 0) { + sif::info << string; + } + else { + sif::info << "0x" << std::hex << std::setw(8) << std::setfill('0') << + message->getReporter() << std::setfill(' ') << std::dec; + } + sif::info << " reported event with ID " << message->getEventId() << std::endl; + sif::info << translateEvents(message->getEvent()) << " | " <getParameter1() << " | P1 Dec: " << std::dec << message->getParameter1() << + std::hex << " | P2 Hex: 0x" << message->getParameter2() << " | P2 Dec: " << + std::dec << message->getParameter2() << std::endl; +#else + if (string != 0) { + sif::printInfo("Event Manager: %s reported event with ID %d\n", string, + message->getEventId()); + } + else { + sif::printInfo("Event Manager: Reporter ID 0x%08x reported event with ID %d\n", + message->getReporter(), message->getEventId()); + } + + sif::printInfo("%s | P1 Hex: 0x%x | P1 Dec: %d | P2 Hex: 0x%x | P2 Dec: %d\n", + translateEvents(message->getEvent()), message->getParameter1(), + message->getParameter1(), message->getParameter2(), message->getParameter2()); +#endif /* FSFW_CPP_OSTREAM_ENABLED == 0 */ + } + else { + string = translateObject(message->getReporter()); +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::debug << "EventManager: "; + if (string != 0) { + sif::debug << string; + } + else { + sif::debug << "0x" << std::hex << std::setw(8) << std::setfill('0') << + message->getReporter() << std::setfill(' ') << std::dec; + } + sif::debug << " reported event with ID " << message->getEventId() << std::endl; + sif::debug << translateEvents(message->getEvent()) << " | " <getParameter1() << " | P1 Dec: " << std::dec << message->getParameter1() << + std::hex << " | P2 Hex: 0x" << message->getParameter2() << " | P2 Dec: " << + std::dec << message->getParameter2() << std::endl; +#else + if (string != 0) { + sif::printDebug("Event Manager: %s reported event with ID %d\n", string, + message->getEventId()); + } + else { + sif::printDebug("Event Manager: Reporter ID 0x%08x reported event with ID %d\n", + message->getReporter(), message->getEventId()); + } + sif::printDebug("P1 Hex: 0x%x | P1 Dec: %d | P2 Hex: 0x%x | P2 Dec: %d\n", + message->getParameter1(), message->getParameter1(), + message->getParameter2(), message->getParameter2()); +#endif /* FSFW_CPP_OSTREAM_ENABLED == 0 */ + } +} + +#endif /* FSFW_OBJ_EVENT_TRANSLATION == 1 */ diff --git a/events/EventManager.h b/src/fsfw/events/EventManager.h similarity index 94% rename from events/EventManager.h rename to src/fsfw/events/EventManager.h index abce9b8b..012247db 100644 --- a/events/EventManager.h +++ b/src/fsfw/events/EventManager.h @@ -3,9 +3,9 @@ #include "EventManagerIF.h" #include "eventmatching/EventMatchTree.h" +#include "FSFWConfig.h" -#include - +#include "../serviceinterface/ServiceInterface.h" #include "../objectmanager/SystemObject.h" #include "../storagemanager/LocalPool.h" #include "../tasks/ExecutableObjectIF.h" @@ -67,6 +67,7 @@ protected: #if FSFW_OBJ_EVENT_TRANSLATION == 1 void printEvent(EventMessage *message); + void printUtility(sif::OutputTypes printType, EventMessage* message); #endif void lockMutex(); diff --git a/events/EventManagerIF.h b/src/fsfw/events/EventManagerIF.h similarity index 95% rename from events/EventManagerIF.h rename to src/fsfw/events/EventManagerIF.h index ea22f8ae..0ba126a2 100644 --- a/events/EventManagerIF.h +++ b/src/fsfw/events/EventManagerIF.h @@ -3,7 +3,7 @@ #include "EventMessage.h" #include "eventmatching/eventmatching.h" -#include "../objectmanager/ObjectManagerIF.h" +#include "../objectmanager/ObjectManager.h" #include "../ipc/MessageQueueSenderIF.h" #include "../ipc/MessageQueueIF.h" #include "../serviceinterface/ServiceInterface.h" @@ -43,7 +43,7 @@ public: static void triggerEvent(EventMessage* message, MessageQueueId_t sentFrom = 0) { if (eventmanagerQueue == MessageQueueIF::NO_QUEUE) { - EventManagerIF *eventmanager = objectManager->get( + EventManagerIF *eventmanager = ObjectManager::instance()->get( objects::EVENT_MANAGER); if (eventmanager == nullptr) { #if FSFW_VERBOSE_LEVEL >= 1 diff --git a/events/EventMessage.cpp b/src/fsfw/events/EventMessage.cpp similarity index 98% rename from events/EventMessage.cpp rename to src/fsfw/events/EventMessage.cpp index 548b4f0f..74f42b06 100644 --- a/events/EventMessage.cpp +++ b/src/fsfw/events/EventMessage.cpp @@ -1,4 +1,4 @@ -#include "EventMessage.h" +#include "fsfw/events/EventMessage.h" #include EventMessage::EventMessage() { diff --git a/events/EventMessage.h b/src/fsfw/events/EventMessage.h similarity index 88% rename from events/EventMessage.h rename to src/fsfw/events/EventMessage.h index f2f5ffb5..36e261bd 100644 --- a/events/EventMessage.h +++ b/src/fsfw/events/EventMessage.h @@ -1,9 +1,9 @@ -#ifndef EVENTMESSAGE_H_ -#define EVENTMESSAGE_H_ +#ifndef FSFW_EVENTS_EVENTMESSAGE_H_ +#define FSFW_EVENTS_EVENTMESSAGE_H_ #include "Event.h" -#include "../ipc/MessageQueueMessage.h" -#include "../objectmanager/ObjectManagerIF.h" +#include "fsfw/ipc/MessageQueueMessage.h" +#include "fsfw/objectmanager/ObjectManagerIF.h" /** * Passing on events through IPC. @@ -49,4 +49,4 @@ protected: }; -#endif /* EVENTMESSAGE_H_ */ +#endif /* FSFW_EVENTS_EVENTMESSAGE_H_ */ diff --git a/events/EventReportingProxyIF.h b/src/fsfw/events/EventReportingProxyIF.h similarity index 100% rename from events/EventReportingProxyIF.h rename to src/fsfw/events/EventReportingProxyIF.h diff --git a/events/eventmatching/CMakeLists.txt b/src/fsfw/events/eventmatching/CMakeLists.txt similarity index 100% rename from events/eventmatching/CMakeLists.txt rename to src/fsfw/events/eventmatching/CMakeLists.txt diff --git a/events/eventmatching/EventIdRangeMatcher.cpp b/src/fsfw/events/eventmatching/EventIdRangeMatcher.cpp similarity index 84% rename from events/eventmatching/EventIdRangeMatcher.cpp rename to src/fsfw/events/eventmatching/EventIdRangeMatcher.cpp index 974567d4..92089f7c 100644 --- a/events/eventmatching/EventIdRangeMatcher.cpp +++ b/src/fsfw/events/eventmatching/EventIdRangeMatcher.cpp @@ -1,4 +1,4 @@ -#include "EventIdRangeMatcher.h" +#include "fsfw/events/eventmatching/EventIdRangeMatcher.h" EventIdRangeMatcher::EventIdRangeMatcher(EventId_t lower, EventId_t upper, bool inverted) : EventRangeMatcherBase(lower, upper, inverted) { diff --git a/events/eventmatching/EventIdRangeMatcher.h b/src/fsfw/events/eventmatching/EventIdRangeMatcher.h similarity index 100% rename from events/eventmatching/EventIdRangeMatcher.h rename to src/fsfw/events/eventmatching/EventIdRangeMatcher.h diff --git a/events/eventmatching/EventMatchTree.cpp b/src/fsfw/events/eventmatching/EventMatchTree.cpp similarity index 94% rename from events/eventmatching/EventMatchTree.cpp rename to src/fsfw/events/eventmatching/EventMatchTree.cpp index 55e4083f..66e9e91a 100644 --- a/events/eventmatching/EventMatchTree.cpp +++ b/src/fsfw/events/eventmatching/EventMatchTree.cpp @@ -1,7 +1,7 @@ -#include "EventIdRangeMatcher.h" -#include "EventMatchTree.h" -#include "ReporterRangeMatcher.h" -#include "SeverityRangeMatcher.h" +#include "fsfw/events/eventmatching/EventIdRangeMatcher.h" +#include "fsfw/events/eventmatching/EventMatchTree.h" +#include "fsfw/events/eventmatching/ReporterRangeMatcher.h" +#include "fsfw/events/eventmatching/SeverityRangeMatcher.h" EventMatchTree::EventMatchTree(StorageManagerIF* storageBackend, bool invertedMatch) : diff --git a/events/eventmatching/EventMatchTree.h b/src/fsfw/events/eventmatching/EventMatchTree.h similarity index 100% rename from events/eventmatching/EventMatchTree.h rename to src/fsfw/events/eventmatching/EventMatchTree.h diff --git a/events/eventmatching/EventRangeMatcherBase.h b/src/fsfw/events/eventmatching/EventRangeMatcherBase.h similarity index 100% rename from events/eventmatching/EventRangeMatcherBase.h rename to src/fsfw/events/eventmatching/EventRangeMatcherBase.h diff --git a/events/eventmatching/ReporterRangeMatcher.cpp b/src/fsfw/events/eventmatching/ReporterRangeMatcher.cpp similarity index 84% rename from events/eventmatching/ReporterRangeMatcher.cpp rename to src/fsfw/events/eventmatching/ReporterRangeMatcher.cpp index 61179726..fc3a2f9f 100644 --- a/events/eventmatching/ReporterRangeMatcher.cpp +++ b/src/fsfw/events/eventmatching/ReporterRangeMatcher.cpp @@ -1,4 +1,4 @@ -#include "ReporterRangeMatcher.h" +#include "fsfw/events/eventmatching/ReporterRangeMatcher.h" ReporterRangeMatcher::ReporterRangeMatcher(object_id_t lower, object_id_t upper, bool inverted) : EventRangeMatcherBase(lower, upper, inverted) { diff --git a/events/eventmatching/ReporterRangeMatcher.h b/src/fsfw/events/eventmatching/ReporterRangeMatcher.h similarity index 100% rename from events/eventmatching/ReporterRangeMatcher.h rename to src/fsfw/events/eventmatching/ReporterRangeMatcher.h diff --git a/events/eventmatching/SeverityRangeMatcher.cpp b/src/fsfw/events/eventmatching/SeverityRangeMatcher.cpp similarity index 70% rename from events/eventmatching/SeverityRangeMatcher.cpp rename to src/fsfw/events/eventmatching/SeverityRangeMatcher.cpp index 6fd38271..230e4e77 100644 --- a/events/eventmatching/SeverityRangeMatcher.cpp +++ b/src/fsfw/events/eventmatching/SeverityRangeMatcher.cpp @@ -1,6 +1,6 @@ -#include "SeverityRangeMatcher.h" -#include "../../events/EventMessage.h" -#include "../../serialize/SerializeAdapter.h" +#include "fsfw/events/eventmatching/SeverityRangeMatcher.h" +#include "fsfw/events/EventMessage.h" +#include "fsfw/serialize/SerializeAdapter.h" SeverityRangeMatcher::SeverityRangeMatcher(EventSeverity_t from, EventSeverity_t till, bool inverted) : EventRangeMatcherBase(from, till, inverted) { diff --git a/events/eventmatching/SeverityRangeMatcher.h b/src/fsfw/events/eventmatching/SeverityRangeMatcher.h similarity index 100% rename from events/eventmatching/SeverityRangeMatcher.h rename to src/fsfw/events/eventmatching/SeverityRangeMatcher.h diff --git a/events/eventmatching/eventmatching.h b/src/fsfw/events/eventmatching/eventmatching.h similarity index 100% rename from events/eventmatching/eventmatching.h rename to src/fsfw/events/eventmatching/eventmatching.h diff --git a/src/fsfw/events/fwSubsystemIdRanges.h b/src/fsfw/events/fwSubsystemIdRanges.h new file mode 100644 index 00000000..08fb878d --- /dev/null +++ b/src/fsfw/events/fwSubsystemIdRanges.h @@ -0,0 +1,39 @@ +#ifndef FSFW_EVENTS_FWSUBSYSTEMIDRANGES_H_ +#define FSFW_EVENTS_FWSUBSYSTEMIDRANGES_H_ + +#include + +namespace SUBSYSTEM_ID { +enum: uint8_t { + MEMORY = 22, + OBSW = 26, + CDH = 28, + TCS_1 = 59, + PCDU_1 = 42, + PCDU_2 = 43, + HEATER = 50, + T_SENSORS = 52, + FDIR = 70, + FDIR_1 = 71, + FDIR_2 = 72, + HK = 73, + SYSTEM_MANAGER = 74, + SYSTEM_MANAGER_1 = 75, + SYSTEM_1 = 79, + PUS_SERVICE_1 = 80, + PUS_SERVICE_2 = 82, + PUS_SERVICE_3 = 83, + PUS_SERVICE_5 = 85, + PUS_SERVICE_6 = 86, + PUS_SERVICE_8 = 88, + PUS_SERVICE_9 = 89, + PUS_SERVICE_17 = 97, + PUS_SERVICE_23 = 103, + MGM_LIS3MDL = 106, + MGM_RM3100 = 107, + + FW_SUBSYSTEM_ID_RANGE +}; +} + +#endif /* FSFW_EVENTS_FWSUBSYSTEMIDRANGES_H_ */ diff --git a/fdir/CMakeLists.txt b/src/fsfw/fdir/CMakeLists.txt similarity index 100% rename from fdir/CMakeLists.txt rename to src/fsfw/fdir/CMakeLists.txt diff --git a/fdir/ConfirmsFailuresIF.h b/src/fsfw/fdir/ConfirmsFailuresIF.h similarity index 100% rename from fdir/ConfirmsFailuresIF.h rename to src/fsfw/fdir/ConfirmsFailuresIF.h diff --git a/fdir/EventCorrelation.cpp b/src/fsfw/fdir/EventCorrelation.cpp similarity index 95% rename from fdir/EventCorrelation.cpp rename to src/fsfw/fdir/EventCorrelation.cpp index d60fc6ca..5b023334 100644 --- a/fdir/EventCorrelation.cpp +++ b/src/fsfw/fdir/EventCorrelation.cpp @@ -1,4 +1,4 @@ -#include "EventCorrelation.h" +#include "fsfw/fdir/EventCorrelation.h" EventCorrelation::EventCorrelation(uint32_t timeout) : eventPending(false) { diff --git a/fdir/EventCorrelation.h b/src/fsfw/fdir/EventCorrelation.h similarity index 100% rename from fdir/EventCorrelation.h rename to src/fsfw/fdir/EventCorrelation.h diff --git a/fdir/FailureIsolationBase.cpp b/src/fsfw/fdir/FailureIsolationBase.cpp similarity index 91% rename from fdir/FailureIsolationBase.cpp rename to src/fsfw/fdir/FailureIsolationBase.cpp index 69cb0f01..717e5072 100644 --- a/fdir/FailureIsolationBase.cpp +++ b/src/fsfw/fdir/FailureIsolationBase.cpp @@ -1,9 +1,9 @@ -#include "../events/EventManagerIF.h" -#include "FailureIsolationBase.h" -#include "../health/HasHealthIF.h" -#include "../health/HealthMessage.h" -#include "../ipc/QueueFactory.h" -#include "../objectmanager/ObjectManagerIF.h" +#include "fsfw/events/EventManagerIF.h" +#include "fsfw/fdir/FailureIsolationBase.h" +#include "fsfw/health/HasHealthIF.h" +#include "fsfw/health/HealthMessage.h" +#include "fsfw/ipc/QueueFactory.h" +#include "fsfw/objectmanager/ObjectManager.h" FailureIsolationBase::FailureIsolationBase(object_id_t owner, object_id_t parent, uint8_t messageDepth, uint8_t parameterDomainBase) : @@ -18,7 +18,7 @@ FailureIsolationBase::~FailureIsolationBase() { } ReturnValue_t FailureIsolationBase::initialize() { - EventManagerIF* manager = objectManager->get( + EventManagerIF* manager = ObjectManager::instance()->get( objects::EVENT_MANAGER); if (manager == nullptr) { #if FSFW_CPP_OSTREAM_ENABLED == 1 @@ -36,7 +36,7 @@ ReturnValue_t FailureIsolationBase::initialize() { if (result != HasReturnvaluesIF::RETURN_OK) { return result; } - owner = objectManager->get(ownerId); + owner = ObjectManager::instance()->get(ownerId); if (owner == nullptr) { #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "FailureIsolationBase::intialize: Owner object " @@ -46,7 +46,7 @@ ReturnValue_t FailureIsolationBase::initialize() { } } if (faultTreeParent != objects::NO_OBJECT) { - ConfirmsFailuresIF* parentIF = objectManager->get( + ConfirmsFailuresIF* parentIF = ObjectManager::instance()->get( faultTreeParent); if (parentIF == nullptr) { #if FSFW_CPP_OSTREAM_ENABLED == 1 diff --git a/fdir/FailureIsolationBase.h b/src/fsfw/fdir/FailureIsolationBase.h similarity index 100% rename from fdir/FailureIsolationBase.h rename to src/fsfw/fdir/FailureIsolationBase.h diff --git a/fdir/FaultCounter.cpp b/src/fsfw/fdir/FaultCounter.cpp similarity index 98% rename from fdir/FaultCounter.cpp rename to src/fsfw/fdir/FaultCounter.cpp index 53c1dd7d..0b30a67d 100644 --- a/fdir/FaultCounter.cpp +++ b/src/fsfw/fdir/FaultCounter.cpp @@ -1,4 +1,4 @@ -#include "FaultCounter.h" +#include "fsfw/fdir/FaultCounter.h" FaultCounter::FaultCounter(uint32_t failureThreshold, uint32_t decrementAfterMs, uint8_t setParameterDomain) : diff --git a/fdir/FaultCounter.h b/src/fsfw/fdir/FaultCounter.h similarity index 79% rename from fdir/FaultCounter.h rename to src/fsfw/fdir/FaultCounter.h index e0670c4b..a85e8cf7 100644 --- a/fdir/FaultCounter.h +++ b/src/fsfw/fdir/FaultCounter.h @@ -1,8 +1,8 @@ -#ifndef FRAMEWORK_FDIR_FAULTCOUNTER_H_ -#define FRAMEWORK_FDIR_FAULTCOUNTER_H_ +#ifndef FSFW_FDIR_FAULTCOUNTER_H_ +#define FSFW_FDIR_FAULTCOUNTER_H_ -#include "../parameters/HasParametersIF.h" -#include "../timemanager/Countdown.h" +#include "fsfw/parameters/HasParametersIF.h" +#include "fsfw/timemanager/Countdown.h" class FaultCounter: public HasParametersIF { public: @@ -35,4 +35,4 @@ private: uint32_t failureThreshold; }; -#endif /* FRAMEWORK_FDIR_FAULTCOUNTER_H_ */ +#endif /* FSFW_FDIR_FAULTCOUNTER_H_ */ diff --git a/globalfunctions/AsciiConverter.cpp b/src/fsfw/globalfunctions/AsciiConverter.cpp similarity index 99% rename from globalfunctions/AsciiConverter.cpp rename to src/fsfw/globalfunctions/AsciiConverter.cpp index 9eb3698f..09908815 100644 --- a/globalfunctions/AsciiConverter.cpp +++ b/src/fsfw/globalfunctions/AsciiConverter.cpp @@ -1,4 +1,5 @@ -#include "AsciiConverter.h" +#include "fsfw/globalfunctions/AsciiConverter.h" + #include #include diff --git a/globalfunctions/AsciiConverter.h b/src/fsfw/globalfunctions/AsciiConverter.h similarity index 100% rename from globalfunctions/AsciiConverter.h rename to src/fsfw/globalfunctions/AsciiConverter.h diff --git a/globalfunctions/CMakeLists.txt b/src/fsfw/globalfunctions/CMakeLists.txt similarity index 100% rename from globalfunctions/CMakeLists.txt rename to src/fsfw/globalfunctions/CMakeLists.txt diff --git a/globalfunctions/CRC.cpp b/src/fsfw/globalfunctions/CRC.cpp similarity index 99% rename from globalfunctions/CRC.cpp rename to src/fsfw/globalfunctions/CRC.cpp index 7bb56806..3df6018c 100644 --- a/globalfunctions/CRC.cpp +++ b/src/fsfw/globalfunctions/CRC.cpp @@ -1,4 +1,4 @@ -#include "CRC.h" +#include "fsfw/globalfunctions/CRC.h" #include const uint16_t CRC::crc16ccitt_table[256] = { diff --git a/globalfunctions/CRC.h b/src/fsfw/globalfunctions/CRC.h similarity index 100% rename from globalfunctions/CRC.h rename to src/fsfw/globalfunctions/CRC.h diff --git a/src/fsfw/globalfunctions/DleEncoder.cpp b/src/fsfw/globalfunctions/DleEncoder.cpp new file mode 100644 index 00000000..91db5445 --- /dev/null +++ b/src/fsfw/globalfunctions/DleEncoder.cpp @@ -0,0 +1,298 @@ +#include "fsfw/globalfunctions/DleEncoder.h" + +DleEncoder::DleEncoder(bool escapeStxEtx, bool escapeCr): + escapeStxEtx(escapeStxEtx), escapeCr(escapeCr) {} + +DleEncoder::~DleEncoder() {} + +ReturnValue_t DleEncoder::encode(const uint8_t* sourceStream, + size_t sourceLen, uint8_t* destStream, size_t maxDestLen, + size_t* encodedLen, bool addStxEtx) { + if(escapeStxEtx) { + return encodeStreamEscaped(sourceStream, sourceLen, + destStream, maxDestLen, encodedLen, addStxEtx); + } + else { + return encodeStreamNonEscaped(sourceStream, sourceLen, + destStream, maxDestLen, encodedLen, addStxEtx); + } + +} + +ReturnValue_t DleEncoder::encodeStreamEscaped(const uint8_t *sourceStream, size_t sourceLen, + uint8_t *destStream, size_t maxDestLen, size_t *encodedLen, + bool addStxEtx) { + size_t encodedIndex = 0; + size_t sourceIndex = 0; + uint8_t nextByte = 0; + if(addStxEtx) { + if(maxDestLen < 1) { + return STREAM_TOO_SHORT; + } + destStream[encodedIndex++] = STX_CHAR; + } + while (encodedIndex < maxDestLen and sourceIndex < sourceLen) { + nextByte = sourceStream[sourceIndex]; + // STX, ETX and CR characters in the stream need to be escaped with DLE + if ((nextByte == STX_CHAR or nextByte == ETX_CHAR) or + (this->escapeCr and nextByte == CARRIAGE_RETURN)) { + if (encodedIndex + 1 >= maxDestLen) { + return STREAM_TOO_SHORT; + } + else { + destStream[encodedIndex] = DLE_CHAR; + ++encodedIndex; + /* Escaped byte will be actual byte + 0x40. This prevents + * STX, ETX, and carriage return characters from appearing + * in the encoded data stream at all, so when polling an + * encoded stream, the transmission can be stopped at ETX. + * 0x40 was chosen at random with special requirements: + * - Prevent going from one control char to another + * - Prevent overflow for common characters */ + destStream[encodedIndex] = nextByte + 0x40; + } + } + // DLE characters are simply escaped with DLE. + else if (nextByte == DLE_CHAR) { + if (encodedIndex + 1 >= maxDestLen) { + return STREAM_TOO_SHORT; + } + else { + destStream[encodedIndex] = DLE_CHAR; + ++encodedIndex; + destStream[encodedIndex] = DLE_CHAR; + } + } + else { + destStream[encodedIndex] = nextByte; + } + ++encodedIndex; + ++sourceIndex; + } + + if (sourceIndex == sourceLen) { + if (addStxEtx) { + if(encodedIndex + 1 >= maxDestLen) { + return STREAM_TOO_SHORT; + } + destStream[encodedIndex] = ETX_CHAR; + ++encodedIndex; + } + *encodedLen = encodedIndex; + return RETURN_OK; + } + else { + return STREAM_TOO_SHORT; + } +} + +ReturnValue_t DleEncoder::encodeStreamNonEscaped(const uint8_t *sourceStream, size_t sourceLen, + uint8_t *destStream, size_t maxDestLen, size_t *encodedLen, + bool addStxEtx) { + size_t encodedIndex = 0; + size_t sourceIndex = 0; + uint8_t nextByte = 0; + if(addStxEtx) { + if(maxDestLen < 2) { + return STREAM_TOO_SHORT; + } + destStream[encodedIndex++] = DLE_CHAR; + destStream[encodedIndex++] = STX_CHAR; + } + while (encodedIndex < maxDestLen and sourceIndex < sourceLen) { + nextByte = sourceStream[sourceIndex]; + // DLE characters are simply escaped with DLE. + if (nextByte == DLE_CHAR) { + if (encodedIndex + 1 >= maxDestLen) { + return STREAM_TOO_SHORT; + } + else { + destStream[encodedIndex] = DLE_CHAR; + ++encodedIndex; + destStream[encodedIndex] = DLE_CHAR; + } + } + else { + destStream[encodedIndex] = nextByte; + } + ++encodedIndex; + ++sourceIndex; + } + + if (sourceIndex == sourceLen) { + if (addStxEtx) { + if(encodedIndex + 2 >= maxDestLen) { + return STREAM_TOO_SHORT; + } + destStream[encodedIndex++] = DLE_CHAR; + destStream[encodedIndex++] = ETX_CHAR; + } + *encodedLen = encodedIndex; + return RETURN_OK; + } + else { + return STREAM_TOO_SHORT; + } +} + +ReturnValue_t DleEncoder::decode(const uint8_t *sourceStream, + size_t sourceStreamLen, size_t *readLen, uint8_t *destStream, + size_t maxDestStreamlen, size_t *decodedLen) { + if(escapeStxEtx) { + return decodeStreamEscaped(sourceStream, sourceStreamLen, + readLen, destStream, maxDestStreamlen, decodedLen); + } + else { + return decodeStreamNonEscaped(sourceStream, sourceStreamLen, + readLen, destStream, maxDestStreamlen, decodedLen); + } +} + +ReturnValue_t DleEncoder::decodeStreamEscaped(const uint8_t *sourceStream, size_t sourceStreamLen, + size_t *readLen, uint8_t *destStream, + size_t maxDestStreamlen, size_t *decodedLen) { + size_t encodedIndex = 0; + size_t decodedIndex = 0; + uint8_t nextByte; + + //init to 0 so that we can just return in the first checks (which do not consume anything from + //the source stream) + *readLen = 0; + + if(maxDestStreamlen < 1) { + return STREAM_TOO_SHORT; + } + if (sourceStream[encodedIndex++] != STX_CHAR) { + return DECODING_ERROR; + } + while ((encodedIndex < sourceStreamLen) and (decodedIndex < maxDestStreamlen)) { + switch(sourceStream[encodedIndex]) { + case(DLE_CHAR): { + if(encodedIndex + 1 >= sourceStreamLen) { + //reached the end of the sourceStream + *readLen = sourceStreamLen; + return DECODING_ERROR; + } + nextByte = sourceStream[encodedIndex + 1]; + // The next byte is a DLE character that was escaped by another + // DLE character, so we can write it to the destination stream. + if (nextByte == DLE_CHAR) { + destStream[decodedIndex] = nextByte; + } + else { + /* The next byte is a STX, DTX or 0x0D character which + * was escaped by a DLE character. The actual byte was + * also encoded by adding + 0x40 to prevent having control chars, + * in the stream at all, so we convert it back. */ + if ((nextByte == STX_CHAR + 0x40 or nextByte == ETX_CHAR + 0x40) or + (this->escapeCr and nextByte == CARRIAGE_RETURN + 0x40)) { + destStream[decodedIndex] = nextByte - 0x40; + } + else { + // Set readLen so user can resume parsing after incorrect data + *readLen = encodedIndex + 2; + return DECODING_ERROR; + } + } + ++encodedIndex; + break; + } + case(STX_CHAR): { + *readLen = encodedIndex; + return DECODING_ERROR; + } + case(ETX_CHAR): { + *readLen = ++encodedIndex; + *decodedLen = decodedIndex; + return RETURN_OK; + } + default: { + destStream[decodedIndex] = sourceStream[encodedIndex]; + break; + } + } + ++encodedIndex; + ++decodedIndex; + } + + if(decodedIndex == maxDestStreamlen) { + //so far we did not find anything wrong here, so let user try again + *readLen = 0; + return STREAM_TOO_SHORT; + } else { + *readLen = encodedIndex; + return DECODING_ERROR; + } +} + +ReturnValue_t DleEncoder::decodeStreamNonEscaped(const uint8_t *sourceStream, + size_t sourceStreamLen, size_t *readLen, uint8_t *destStream, + size_t maxDestStreamlen, size_t *decodedLen) { + size_t encodedIndex = 0; + size_t decodedIndex = 0; + uint8_t nextByte; + + //init to 0 so that we can just return in the first checks (which do not consume anything from + //the source stream) + *readLen = 0; + + if(maxDestStreamlen < 2) { + return STREAM_TOO_SHORT; + } + if (sourceStream[encodedIndex++] != DLE_CHAR) { + return DECODING_ERROR; + } + if (sourceStream[encodedIndex++] != STX_CHAR) { + *readLen = 1; + return DECODING_ERROR; + } + while ((encodedIndex < sourceStreamLen) && (decodedIndex < maxDestStreamlen)) { + if (sourceStream[encodedIndex] == DLE_CHAR) { + if(encodedIndex + 1 >= sourceStreamLen) { + *readLen = encodedIndex; + return DECODING_ERROR; + } + nextByte = sourceStream[encodedIndex + 1]; + if(nextByte == STX_CHAR) { + // Set readLen so the DLE/STX char combination is preserved. Could be start of + // another frame + *readLen = encodedIndex; + return DECODING_ERROR; + } + else if(nextByte == DLE_CHAR) { + // The next byte is a DLE character that was escaped by another + // DLE character, so we can write it to the destination stream. + destStream[decodedIndex] = nextByte; + ++encodedIndex; + } + else if(nextByte == ETX_CHAR) { + // End of stream reached + *readLen = encodedIndex + 2; + *decodedLen = decodedIndex; + return RETURN_OK; + } + else { + *readLen = encodedIndex; + return DECODING_ERROR; + } + } + else { + destStream[decodedIndex] = sourceStream[encodedIndex]; + } + ++encodedIndex; + ++decodedIndex; + } + + if(decodedIndex == maxDestStreamlen) { + //so far we did not find anything wrong here, so let user try again + *readLen = 0; + return STREAM_TOO_SHORT; + } else { + *readLen = encodedIndex; + return DECODING_ERROR; + } +} + +void DleEncoder::setEscapeMode(bool escapeStxEtx) { + this->escapeStxEtx = escapeStxEtx; +} diff --git a/src/fsfw/globalfunctions/DleEncoder.h b/src/fsfw/globalfunctions/DleEncoder.h new file mode 100644 index 00000000..09fa2726 --- /dev/null +++ b/src/fsfw/globalfunctions/DleEncoder.h @@ -0,0 +1,118 @@ +#ifndef FRAMEWORK_GLOBALFUNCTIONS_DLEENCODER_H_ +#define FRAMEWORK_GLOBALFUNCTIONS_DLEENCODER_H_ + +#include "fsfw/returnvalues/HasReturnvaluesIF.h" +#include + +/** + * @brief This DLE Encoder (Data Link Encoder) can be used to encode and + * decode arbitrary data with ASCII control characters + * @details + * List of control codes: + * https://en.wikipedia.org/wiki/C0_and_C1_control_codes + * + * This encoder can be used to achieve a basic transport layer when using + * char based transmission systems. There are two implemented variants: + * + * 1. Escaped variant + * + * The encoded stream starts with a STX marker and ends with an ETX marker. + * STX and ETX occurrences in the stream are escaped and internally encoded as well so the + * receiver side can simply check for STX and ETX markers as frame delimiters. When using a + * strictly char based reception of packets encoded with DLE, + * STX can be used to notify a reader that actual data will start to arrive + * while ETX can be used to notify the reader that the data has ended. + * + * 2. Non-escaped variant + * + * The encoded stream starts with DLE STX and ends with DLE ETX. All DLE occurrences in the stream + * are escaped with DLE. If the receiver detects a DLE char, it needs to read the next char + * to determine whether a start (STX) or end (ETX) of a frame has been detected. + */ +class DleEncoder: public HasReturnvaluesIF { +public: + /** + * Create an encoder instance with the given configuration. + * @param escapeStxEtx Determines whether the algorithm works in escaped or non-escaped mode + * @param escapeCr In escaped mode, escape all CR occurrences as well + */ + DleEncoder(bool escapeStxEtx = true, bool escapeCr = false); + + void setEscapeMode(bool escapeStxEtx); + + virtual ~DleEncoder(); + + static constexpr uint8_t INTERFACE_ID = CLASS_ID::DLE_ENCODER; + static constexpr ReturnValue_t STREAM_TOO_SHORT = MAKE_RETURN_CODE(0x01); + static constexpr ReturnValue_t DECODING_ERROR = MAKE_RETURN_CODE(0x02); + + //! Start Of Text character. First character is encoded stream + static constexpr uint8_t STX_CHAR = 0x02; + //! End Of Text character. Last character in encoded stream + static constexpr uint8_t ETX_CHAR = 0x03; + //! Data Link Escape character. Used to escape STX, ETX and DLE occurrences + //! in the source stream. + static constexpr uint8_t DLE_CHAR = 0x10; + static constexpr uint8_t CARRIAGE_RETURN = 0x0D; + + /** + * Encodes the give data stream by preceding it with the STX marker + * and ending it with an ETX marker. DLE characters inside + * the stream are escaped by DLE characters. STX, ETX and CR characters can be escaped with a + * DLE character as well. The escaped characters are also encoded by adding + * 0x40 (which is reverted in the decoding process). This is performed so the source stream + * does not have STX/ETX/CR occurrences anymore, so the receiving side can simply parse for + * start and end markers + * @param sourceStream + * @param sourceLen + * @param destStream + * @param maxDestLen + * @param encodedLen + * @param addStxEtx Adding STX start marker and ETX end marker can be omitted, + * if they are added manually + * @return + * - RETURN_OK for successful encoding operation + * - STREAM_TOO_SHORT if the destination stream is too short + */ + ReturnValue_t encode(const uint8_t *sourceStream, size_t sourceLen, + uint8_t *destStream, size_t maxDestLen, size_t *encodedLen, + bool addStxEtx = true); + + /** + * Converts an encoded stream back. + * @param sourceStream + * @param sourceStreamLen + * @param readLen + * @param destStream + * @param maxDestStreamlen + * @param decodedLen + * @return + * - RETURN_OK for successful decode operation + * - DECODE_ERROR if the source stream is invalid + * - STREAM_TOO_SHORT if the destination stream is too short + */ + ReturnValue_t decode(const uint8_t *sourceStream, + size_t sourceStreamLen, size_t *readLen, uint8_t *destStream, + size_t maxDestStreamlen, size_t *decodedLen); + +private: + + ReturnValue_t encodeStreamEscaped(const uint8_t *sourceStream, size_t sourceLen, + uint8_t *destStream, size_t maxDestLen, size_t *encodedLen, + bool addStxEtx = true); + + ReturnValue_t encodeStreamNonEscaped(const uint8_t *sourceStream, size_t sourceLen, + uint8_t *destStream, size_t maxDestLen, size_t *encodedLen, + bool addStxEtx = true); + + ReturnValue_t decodeStreamEscaped(const uint8_t *sourceStream, size_t sourceStreamLen, + size_t *readLen, uint8_t *destStream, size_t maxDestStreamlen, size_t *decodedLen); + + ReturnValue_t decodeStreamNonEscaped(const uint8_t *sourceStream, size_t sourceStreamLen, + size_t *readLen, uint8_t *destStream, size_t maxDestStreamlen, size_t *decodedLen); + + bool escapeStxEtx; + bool escapeCr; +}; + +#endif /* FRAMEWORK_GLOBALFUNCTIONS_DLEENCODER_H_ */ diff --git a/src/fsfw/globalfunctions/PeriodicOperationDivider.cpp b/src/fsfw/globalfunctions/PeriodicOperationDivider.cpp new file mode 100644 index 00000000..ac6a78e4 --- /dev/null +++ b/src/fsfw/globalfunctions/PeriodicOperationDivider.cpp @@ -0,0 +1,41 @@ +#include "fsfw/globalfunctions/PeriodicOperationDivider.h" + + +PeriodicOperationDivider::PeriodicOperationDivider(uint32_t divider, + bool resetAutomatically): resetAutomatically(resetAutomatically), + divider(divider) { +} + +bool PeriodicOperationDivider::checkAndIncrement() { + bool opNecessary = check(); + if(opNecessary and resetAutomatically) { + resetCounter(); + } + else { + counter++; + } + return opNecessary; +} + +bool PeriodicOperationDivider::check() { + if(counter >= divider) { + return true; + } + return false; +} + +void PeriodicOperationDivider::resetCounter() { + counter = 1; +} + +void PeriodicOperationDivider::setDivider(uint32_t newDivider) { + divider = newDivider; +} + +uint32_t PeriodicOperationDivider::getCounter() const { + return counter; +} + +uint32_t PeriodicOperationDivider::getDivider() const { + return divider; +} diff --git a/src/fsfw/globalfunctions/PeriodicOperationDivider.h b/src/fsfw/globalfunctions/PeriodicOperationDivider.h new file mode 100644 index 00000000..636849c0 --- /dev/null +++ b/src/fsfw/globalfunctions/PeriodicOperationDivider.h @@ -0,0 +1,64 @@ +#ifndef FSFW_GLOBALFUNCTIONS_PERIODICOPERATIONDIVIDER_H_ +#define FSFW_GLOBALFUNCTIONS_PERIODICOPERATIONDIVIDER_H_ + +#include + +/** + * @brief Lightweight helper class to facilitate periodic operation with + * decreased frequencies. + * @details + * This class is useful to perform operations which have to be performed + * with a reduced frequency, like debugging printouts in high periodic tasks + * or low priority operations. + */ +class PeriodicOperationDivider { +public: + /** + * Initialize with the desired divider and specify whether the internal + * counter will be reset automatically. + * @param divider Value of 0 or 1 will cause #check and #checkAndIncrement to always return + * true + * @param resetAutomatically + */ + PeriodicOperationDivider(uint32_t divider, bool resetAutomatically = true); + + /** + * Check whether operation is necessary. If an operation is necessary and the class has been + * configured to be reset automatically, the counter will be reset to 1 automatically + * + * @return + * -@c true if the counter is larger or equal to the divider + * -@c false otherwise + */ + bool checkAndIncrement(); + + /** + * Checks whether an operation is necessary. This function will not increment the counter. + * @return + * -@c true if the counter is larger or equal to the divider + * -@c false otherwise + */ + bool check(); + + /** + * Can be used to reset the counter to 1 manually + */ + void resetCounter(); + uint32_t getCounter() const; + + /** + * Can be used to set a new divider value. + * @param newDivider + */ + void setDivider(uint32_t newDivider); + uint32_t getDivider() const; + +private: + bool resetAutomatically = true; + uint32_t counter = 1; + uint32_t divider = 0; +}; + + + +#endif /* FSFW_GLOBALFUNCTIONS_PERIODICOPERATIONDIVIDER_H_ */ diff --git a/globalfunctions/Type.cpp b/src/fsfw/globalfunctions/Type.cpp similarity index 97% rename from globalfunctions/Type.cpp rename to src/fsfw/globalfunctions/Type.cpp index fa6d2f28..5f1e05d1 100644 --- a/globalfunctions/Type.cpp +++ b/src/fsfw/globalfunctions/Type.cpp @@ -1,5 +1,5 @@ -#include "Type.h" -#include "../serialize/SerializeAdapter.h" +#include "fsfw/globalfunctions/Type.h" +#include "fsfw/serialize/SerializeAdapter.h" Type::Type() : actualType(UNKNOWN_TYPE) { diff --git a/globalfunctions/Type.h b/src/fsfw/globalfunctions/Type.h similarity index 96% rename from globalfunctions/Type.h rename to src/fsfw/globalfunctions/Type.h index fa894e3e..cfbb3cfa 100644 --- a/globalfunctions/Type.h +++ b/src/fsfw/globalfunctions/Type.h @@ -1,8 +1,9 @@ #ifndef FSFW_GLOBALFUNCTIONS_TYPE_H_ #define FSFW_GLOBALFUNCTIONS_TYPE_H_ -#include "../returnvalues/HasReturnvaluesIF.h" -#include "../serialize/SerializeIF.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" +#include "fsfw/serialize/SerializeIF.h" + #include /** diff --git a/globalfunctions/arrayprinter.cpp b/src/fsfw/globalfunctions/arrayprinter.cpp similarity index 79% rename from globalfunctions/arrayprinter.cpp rename to src/fsfw/globalfunctions/arrayprinter.cpp index 0423360b..964b9d04 100644 --- a/globalfunctions/arrayprinter.cpp +++ b/src/fsfw/globalfunctions/arrayprinter.cpp @@ -1,10 +1,20 @@ -#include "arrayprinter.h" -#include "../serviceinterface/ServiceInterface.h" +#include "fsfw/globalfunctions/arrayprinter.h" +#include "fsfw/serviceinterface/ServiceInterface.h" + #include void arrayprinter::print(const uint8_t *data, size_t size, OutputType type, bool printInfo, size_t maxCharPerLine) { + if(size == 0) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "Size is zero, nothing to print" << std::endl; +#else + sif::printInfo("Size is zero, nothing to print\n"); +#endif + return; + } + #if FSFW_CPP_OSTREAM_ENABLED == 1 if(printInfo) { sif::info << "Printing data with size " << size << ": " << std::endl; @@ -35,18 +45,18 @@ void arrayprinter::printHex(const uint8_t *data, size_t size, std::cout << "\r" << std::endl; } - std::cout << "[" << std::hex; + std::cout << "hex [" << std::setfill('0') << std::hex; for(size_t i = 0; i < size; i++) { - std::cout << "0x" << static_cast(data[i]); + std::cout << std::setw(2) << static_cast(data[i]); if(i < size - 1) { - std::cout << " , "; + std::cout << ","; if(i > 0 and (i + 1) % maxCharPerLine == 0) { std::cout << std::endl; } } } - std::cout << std::dec; + std::cout << std::dec << std::setfill(' '); std::cout << "]" << std::endl; #else // General format: 0x01, 0x02, 0x03 so it is number of chars times 6 @@ -59,16 +69,16 @@ void arrayprinter::printHex(const uint8_t *data, size_t size, break; } - currentPos += snprintf(printBuffer + currentPos, 6, "0x%02x", data[i]); + currentPos += snprintf(printBuffer + currentPos, 6, "%02x", data[i]); if(i < size - 1) { - currentPos += sprintf(printBuffer + currentPos, ", "); + currentPos += sprintf(printBuffer + currentPos, ","); if(i > 0 and (i + 1) % maxCharPerLine == 0) { currentPos += sprintf(printBuffer + currentPos, "\n"); } } } #if FSFW_DISABLE_PRINTOUT == 0 - printf("[%s]\n", printBuffer); + printf("hex [%s]\n", printBuffer); #endif /* FSFW_DISABLE_PRINTOUT == 0 */ #endif } @@ -80,11 +90,11 @@ void arrayprinter::printDec(const uint8_t *data, size_t size, std::cout << "\r" << std::endl; } - std::cout << "[" << std::dec; + std::cout << "dec [" << std::dec; for(size_t i = 0; i < size; i++) { std::cout << static_cast(data[i]); if(i < size - 1){ - std::cout << " , "; + std::cout << ","; if(i > 0 and (i + 1) % maxCharPerLine == 0) { std::cout << std::endl; } @@ -104,14 +114,14 @@ void arrayprinter::printDec(const uint8_t *data, size_t size, currentPos += snprintf(printBuffer + currentPos, 3, "%d", data[i]); if(i < size - 1) { - currentPos += sprintf(printBuffer + currentPos, ", "); + currentPos += sprintf(printBuffer + currentPos, ","); if(i > 0 and (i + 1) % maxCharPerLine == 0) { currentPos += sprintf(printBuffer + currentPos, "\n"); } } } #if FSFW_DISABLE_PRINTOUT == 0 - printf("[%s]\n", printBuffer); + printf("dec [%s]\n", printBuffer); #endif /* FSFW_DISABLE_PRINTOUT == 0 */ #endif } diff --git a/globalfunctions/arrayprinter.h b/src/fsfw/globalfunctions/arrayprinter.h similarity index 100% rename from globalfunctions/arrayprinter.h rename to src/fsfw/globalfunctions/arrayprinter.h diff --git a/globalfunctions/bitutility.cpp b/src/fsfw/globalfunctions/bitutility.cpp similarity index 60% rename from globalfunctions/bitutility.cpp rename to src/fsfw/globalfunctions/bitutility.cpp index 5cc92dac..54e94a95 100644 --- a/globalfunctions/bitutility.cpp +++ b/src/fsfw/globalfunctions/bitutility.cpp @@ -1,6 +1,6 @@ -#include "bitutility.h" +#include "fsfw/globalfunctions/bitutility.h" -void bitutil::bitSet(uint8_t *byte, uint8_t position) { +void bitutil::set(uint8_t *byte, uint8_t position) { if(position > 7) { return; } @@ -8,7 +8,7 @@ void bitutil::bitSet(uint8_t *byte, uint8_t position) { *byte |= 1 << shiftNumber; } -void bitutil::bitToggle(uint8_t *byte, uint8_t position) { +void bitutil::toggle(uint8_t *byte, uint8_t position) { if(position > 7) { return; } @@ -16,7 +16,7 @@ void bitutil::bitToggle(uint8_t *byte, uint8_t position) { *byte ^= 1 << shiftNumber; } -void bitutil::bitClear(uint8_t *byte, uint8_t position) { +void bitutil::clear(uint8_t *byte, uint8_t position) { if(position > 7) { return; } @@ -24,10 +24,11 @@ void bitutil::bitClear(uint8_t *byte, uint8_t position) { *byte &= ~(1 << shiftNumber); } -bool bitutil::bitGet(const uint8_t *byte, uint8_t position) { +bool bitutil::get(const uint8_t *byte, uint8_t position, bool& bit) { if(position > 7) { return false; } uint8_t shiftNumber = position + (7 - 2 * position); - return *byte & (1 << shiftNumber); + bit = *byte & (1 << shiftNumber); + return true; } diff --git a/src/fsfw/globalfunctions/bitutility.h b/src/fsfw/globalfunctions/bitutility.h new file mode 100644 index 00000000..00f19310 --- /dev/null +++ b/src/fsfw/globalfunctions/bitutility.h @@ -0,0 +1,41 @@ +#ifndef FSFW_GLOBALFUNCTIONS_BITUTIL_H_ +#define FSFW_GLOBALFUNCTIONS_BITUTIL_H_ + +#include + +namespace bitutil { + +// Helper functions for manipulating the individual bits of a byte. +// Position refers to n-th bit of a byte, going from 0 (most significant bit) to +// 7 (least significant bit) + +/** + * @brief Set the bit in a given byte + * @param byte + * @param position + */ +void set(uint8_t* byte, uint8_t position); +/** + * @brief Toggle the bit in a given byte + * @param byte + * @param position + */ +void toggle(uint8_t* byte, uint8_t position); +/** + * @brief Clear the bit in a given byte + * @param byte + * @param position + */ +void clear(uint8_t* byte, uint8_t position); +/** + * @brief Get the bit in a given byte + * @param byte + * @param position + * @param If the input is valid, this will be set to true if the bit is set and false otherwise. + * @return False if position is invalid, True otherwise + */ +bool get(const uint8_t* byte, uint8_t position, bool& bit); + +} + +#endif /* FSFW_GLOBALFUNCTIONS_BITUTIL_H_ */ diff --git a/globalfunctions/constants.h b/src/fsfw/globalfunctions/constants.h similarity index 100% rename from globalfunctions/constants.h rename to src/fsfw/globalfunctions/constants.h diff --git a/globalfunctions/matching/BinaryMatcher.h b/src/fsfw/globalfunctions/matching/BinaryMatcher.h similarity index 100% rename from globalfunctions/matching/BinaryMatcher.h rename to src/fsfw/globalfunctions/matching/BinaryMatcher.h diff --git a/globalfunctions/matching/DecimalMatcher.h b/src/fsfw/globalfunctions/matching/DecimalMatcher.h similarity index 100% rename from globalfunctions/matching/DecimalMatcher.h rename to src/fsfw/globalfunctions/matching/DecimalMatcher.h diff --git a/globalfunctions/matching/MatchTree.h b/src/fsfw/globalfunctions/matching/MatchTree.h similarity index 100% rename from globalfunctions/matching/MatchTree.h rename to src/fsfw/globalfunctions/matching/MatchTree.h diff --git a/globalfunctions/matching/MatcherIF.h b/src/fsfw/globalfunctions/matching/MatcherIF.h similarity index 100% rename from globalfunctions/matching/MatcherIF.h rename to src/fsfw/globalfunctions/matching/MatcherIF.h diff --git a/globalfunctions/matching/RangeMatcher.h b/src/fsfw/globalfunctions/matching/RangeMatcher.h similarity index 100% rename from globalfunctions/matching/RangeMatcher.h rename to src/fsfw/globalfunctions/matching/RangeMatcher.h diff --git a/globalfunctions/matching/SerializeableMatcherIF.h b/src/fsfw/globalfunctions/matching/SerializeableMatcherIF.h similarity index 100% rename from globalfunctions/matching/SerializeableMatcherIF.h rename to src/fsfw/globalfunctions/matching/SerializeableMatcherIF.h diff --git a/globalfunctions/math/CMakeLists.txt b/src/fsfw/globalfunctions/math/CMakeLists.txt similarity index 100% rename from globalfunctions/math/CMakeLists.txt rename to src/fsfw/globalfunctions/math/CMakeLists.txt diff --git a/globalfunctions/math/MatrixOperations.h b/src/fsfw/globalfunctions/math/MatrixOperations.h similarity index 100% rename from globalfunctions/math/MatrixOperations.h rename to src/fsfw/globalfunctions/math/MatrixOperations.h diff --git a/globalfunctions/math/QuaternionOperations.cpp b/src/fsfw/globalfunctions/math/QuaternionOperations.cpp similarity index 97% rename from globalfunctions/math/QuaternionOperations.cpp rename to src/fsfw/globalfunctions/math/QuaternionOperations.cpp index c09426da..31ba2044 100644 --- a/globalfunctions/math/QuaternionOperations.cpp +++ b/src/fsfw/globalfunctions/math/QuaternionOperations.cpp @@ -1,5 +1,5 @@ -#include "QuaternionOperations.h" -#include "VectorOperations.h" +#include "fsfw/globalfunctions/math/QuaternionOperations.h" +#include "fsfw/globalfunctions/math/VectorOperations.h" #include #include diff --git a/globalfunctions/math/QuaternionOperations.h b/src/fsfw/globalfunctions/math/QuaternionOperations.h similarity index 100% rename from globalfunctions/math/QuaternionOperations.h rename to src/fsfw/globalfunctions/math/QuaternionOperations.h diff --git a/globalfunctions/math/VectorOperations.h b/src/fsfw/globalfunctions/math/VectorOperations.h similarity index 100% rename from globalfunctions/math/VectorOperations.h rename to src/fsfw/globalfunctions/math/VectorOperations.h diff --git a/globalfunctions/sign.h b/src/fsfw/globalfunctions/sign.h similarity index 100% rename from globalfunctions/sign.h rename to src/fsfw/globalfunctions/sign.h diff --git a/globalfunctions/timevalOperations.cpp b/src/fsfw/globalfunctions/timevalOperations.cpp similarity index 98% rename from globalfunctions/timevalOperations.cpp rename to src/fsfw/globalfunctions/timevalOperations.cpp index 1228da04..e91e7f57 100644 --- a/globalfunctions/timevalOperations.cpp +++ b/src/fsfw/globalfunctions/timevalOperations.cpp @@ -1,4 +1,4 @@ -#include "timevalOperations.h" +#include "fsfw/globalfunctions/timevalOperations.h" timeval& operator+=(timeval& lhs, const timeval& rhs) { int64_t sum = lhs.tv_sec * 1000000. + lhs.tv_usec; diff --git a/globalfunctions/timevalOperations.h b/src/fsfw/globalfunctions/timevalOperations.h similarity index 96% rename from globalfunctions/timevalOperations.h rename to src/fsfw/globalfunctions/timevalOperations.h index db68f330..41f4e52f 100644 --- a/globalfunctions/timevalOperations.h +++ b/src/fsfw/globalfunctions/timevalOperations.h @@ -2,8 +2,9 @@ #define TIMEVALOPERATIONS_H_ #include +#include -#ifdef WIN32 +#ifdef PLATFORM_WIN #include #else #include diff --git a/src/fsfw/health.h b/src/fsfw/health.h new file mode 100644 index 00000000..0b7c8793 --- /dev/null +++ b/src/fsfw/health.h @@ -0,0 +1,9 @@ +#ifndef FSFW_INC_FSFW_HEALTH_H_ +#define FSFW_INC_FSFW_HEALTH_H_ + +#include "src/core/health/HasHealthIF.h" +#include "src/core/health/HealthHelper.h" +#include "src/core/health/HealthMessage.h" +#include "src/core/health/HealthTable.h" + +#endif /* FSFW_INC_FSFW_HEALTH_H_ */ diff --git a/health/CMakeLists.txt b/src/fsfw/health/CMakeLists.txt similarity index 100% rename from health/CMakeLists.txt rename to src/fsfw/health/CMakeLists.txt diff --git a/health/HasHealthIF.h b/src/fsfw/health/HasHealthIF.h similarity index 100% rename from health/HasHealthIF.h rename to src/fsfw/health/HasHealthIF.h diff --git a/health/HealthHelper.cpp b/src/fsfw/health/HealthHelper.cpp similarity index 92% rename from health/HealthHelper.cpp rename to src/fsfw/health/HealthHelper.cpp index 231d616e..6bbbe25b 100644 --- a/health/HealthHelper.cpp +++ b/src/fsfw/health/HealthHelper.cpp @@ -1,5 +1,6 @@ -#include "HealthHelper.h" -#include "../serviceinterface/ServiceInterfaceStream.h" +#include "fsfw/health/HealthHelper.h" + +#include "fsfw/serviceinterface/ServiceInterface.h" HealthHelper::HealthHelper(HasHealthIF* owner, object_id_t objectId) : objectId(objectId), owner(owner) { @@ -37,8 +38,8 @@ void HealthHelper::setParentQueue(MessageQueueId_t parentQueue) { } ReturnValue_t HealthHelper::initialize() { - healthTable = objectManager->get(objects::HEALTH_TABLE); - eventSender = objectManager->get(objectId); + healthTable = ObjectManager::instance()->get(objects::HEALTH_TABLE); + eventSender = ObjectManager::instance()->get(objectId); if (healthTable == nullptr) { #if FSFW_CPP_OSTREAM_ENABLED == 1 diff --git a/health/HealthHelper.h b/src/fsfw/health/HealthHelper.h similarity index 100% rename from health/HealthHelper.h rename to src/fsfw/health/HealthHelper.h diff --git a/health/HealthMessage.cpp b/src/fsfw/health/HealthMessage.cpp similarity index 95% rename from health/HealthMessage.cpp rename to src/fsfw/health/HealthMessage.cpp index 52479c26..31b6273b 100644 --- a/health/HealthMessage.cpp +++ b/src/fsfw/health/HealthMessage.cpp @@ -1,4 +1,4 @@ -#include "HealthMessage.h" +#include "fsfw/health/HealthMessage.h" void HealthMessage::setHealthMessage(CommandMessage* message, Command_t command, HasHealthIF::HealthState health, HasHealthIF::HealthState oldHealth) { diff --git a/health/HealthMessage.h b/src/fsfw/health/HealthMessage.h similarity index 96% rename from health/HealthMessage.h rename to src/fsfw/health/HealthMessage.h index fb979c66..3dc58977 100644 --- a/health/HealthMessage.h +++ b/src/fsfw/health/HealthMessage.h @@ -2,7 +2,7 @@ #define FSFW_HEALTH_HEALTHMESSAGE_H_ #include "HasHealthIF.h" -#include "../ipc/CommandMessage.h" +#include "fsfw/ipc/CommandMessage.h" class HealthMessage { public: diff --git a/health/HealthTable.cpp b/src/fsfw/health/HealthTable.cpp similarity index 95% rename from health/HealthTable.cpp rename to src/fsfw/health/HealthTable.cpp index 3fed1deb..a3300462 100644 --- a/health/HealthTable.cpp +++ b/src/fsfw/health/HealthTable.cpp @@ -1,7 +1,8 @@ -#include "HealthTable.h" -#include "../ipc/MutexGuard.h" -#include "../ipc/MutexFactory.h" -#include "../serialize/SerializeAdapter.h" +#include "fsfw/health/HealthTable.h" + +#include "fsfw/ipc/MutexGuard.h" +#include "fsfw/ipc/MutexFactory.h" +#include "fsfw/serialize/SerializeAdapter.h" HealthTable::HealthTable(object_id_t objectid) : SystemObject(objectid) { diff --git a/health/HealthTable.h b/src/fsfw/health/HealthTable.h similarity index 100% rename from health/HealthTable.h rename to src/fsfw/health/HealthTable.h diff --git a/health/HealthTableIF.h b/src/fsfw/health/HealthTableIF.h similarity index 100% rename from health/HealthTableIF.h rename to src/fsfw/health/HealthTableIF.h diff --git a/health/ManagesHealthIF.h b/src/fsfw/health/ManagesHealthIF.h similarity index 100% rename from health/ManagesHealthIF.h rename to src/fsfw/health/ManagesHealthIF.h diff --git a/src/fsfw/housekeeping.h b/src/fsfw/housekeeping.h new file mode 100644 index 00000000..0627d523 --- /dev/null +++ b/src/fsfw/housekeeping.h @@ -0,0 +1,9 @@ +#ifndef FSFW_INC_FSFW_HOUSEKEEPING_H_ +#define FSFW_INC_FSFW_HOUSEKEEPING_H_ + +#include "src/core/housekeeping/HousekeepingMessage.h" +#include "src/core/housekeeping/HousekeepingPacketDownlink.h" +#include "src/core/housekeeping/HousekeepingSetPacket.h" +#include "src/core/housekeeping/HousekeepingSnapshot.h" + +#endif /* FSFW_INC_FSFW_HOUSEKEEPING_H_ */ diff --git a/housekeeping/AcceptsHkPacketsIF.h b/src/fsfw/housekeeping/AcceptsHkPacketsIF.h similarity index 100% rename from housekeeping/AcceptsHkPacketsIF.h rename to src/fsfw/housekeeping/AcceptsHkPacketsIF.h diff --git a/housekeeping/CMakeLists.txt b/src/fsfw/housekeeping/CMakeLists.txt similarity index 100% rename from housekeeping/CMakeLists.txt rename to src/fsfw/housekeeping/CMakeLists.txt diff --git a/housekeeping/HousekeepingMessage.cpp b/src/fsfw/housekeeping/HousekeepingMessage.cpp similarity index 97% rename from housekeeping/HousekeepingMessage.cpp rename to src/fsfw/housekeeping/HousekeepingMessage.cpp index 90ca73c8..432a8620 100644 --- a/housekeeping/HousekeepingMessage.cpp +++ b/src/fsfw/housekeeping/HousekeepingMessage.cpp @@ -1,6 +1,7 @@ -#include "HousekeepingMessage.h" +#include "fsfw/housekeeping/HousekeepingMessage.h" + +#include "fsfw/objectmanager/ObjectManager.h" -#include "../objectmanager/ObjectManagerIF.h" #include HousekeepingMessage::~HousekeepingMessage() {} @@ -161,7 +162,7 @@ void HousekeepingMessage::clear(CommandMessage* message) { case(UPDATE_SNAPSHOT_VARIABLE): { store_address_t storeId; getHkDataReply(message, &storeId); - StorageManagerIF *ipcStore = objectManager->get( + StorageManagerIF *ipcStore = ObjectManager::instance()->get( objects::IPC_STORE); if (ipcStore != nullptr) { ipcStore->deleteData(storeId); diff --git a/housekeeping/HousekeepingMessage.h b/src/fsfw/housekeeping/HousekeepingMessage.h similarity index 95% rename from housekeeping/HousekeepingMessage.h rename to src/fsfw/housekeeping/HousekeepingMessage.h index a38ff73f..509a68c9 100644 --- a/housekeeping/HousekeepingMessage.h +++ b/src/fsfw/housekeeping/HousekeepingMessage.h @@ -1,11 +1,11 @@ #ifndef FSFW_HOUSEKEEPING_HOUSEKEEPINGMESSAGE_H_ #define FSFW_HOUSEKEEPING_HOUSEKEEPINGMESSAGE_H_ -#include "../datapoollocal/localPoolDefinitions.h" -#include "../ipc/CommandMessage.h" -#include "../ipc/FwMessageTypes.h" -#include "../objectmanager/frameworkObjects.h" -#include "../storagemanager/StorageManagerIF.h" +#include "fsfw/datapoollocal/localPoolDefinitions.h" +#include "fsfw/ipc/CommandMessage.h" +#include "fsfw/ipc/FwMessageTypes.h" +#include "fsfw/objectmanager/frameworkObjects.h" +#include "fsfw/storagemanager/StorageManagerIF.h" /** diff --git a/housekeeping/HousekeepingPacketDownlink.h b/src/fsfw/housekeeping/HousekeepingPacketDownlink.h similarity index 100% rename from housekeeping/HousekeepingPacketDownlink.h rename to src/fsfw/housekeeping/HousekeepingPacketDownlink.h diff --git a/housekeeping/HousekeepingSetPacket.h b/src/fsfw/housekeeping/HousekeepingSetPacket.h similarity index 100% rename from housekeeping/HousekeepingSetPacket.h rename to src/fsfw/housekeeping/HousekeepingSetPacket.h diff --git a/housekeeping/HousekeepingSnapshot.h b/src/fsfw/housekeeping/HousekeepingSnapshot.h similarity index 100% rename from housekeeping/HousekeepingSnapshot.h rename to src/fsfw/housekeeping/HousekeepingSnapshot.h diff --git a/housekeeping/PeriodicHousekeepingHelper.cpp b/src/fsfw/housekeeping/PeriodicHousekeepingHelper.cpp similarity index 96% rename from housekeeping/PeriodicHousekeepingHelper.cpp rename to src/fsfw/housekeeping/PeriodicHousekeepingHelper.cpp index 892eb354..68740d33 100644 --- a/housekeeping/PeriodicHousekeepingHelper.cpp +++ b/src/fsfw/housekeeping/PeriodicHousekeepingHelper.cpp @@ -1,6 +1,6 @@ -#include "PeriodicHousekeepingHelper.h" +#include "fsfw/housekeeping/PeriodicHousekeepingHelper.h" -#include "../datapoollocal/LocalPoolDataSetBase.h" +#include "fsfw/datapoollocal/LocalPoolDataSetBase.h" #include PeriodicHousekeepingHelper::PeriodicHousekeepingHelper( diff --git a/housekeeping/PeriodicHousekeepingHelper.h b/src/fsfw/housekeeping/PeriodicHousekeepingHelper.h similarity index 96% rename from housekeeping/PeriodicHousekeepingHelper.h rename to src/fsfw/housekeeping/PeriodicHousekeepingHelper.h index 3256fbff..4e93308b 100644 --- a/housekeeping/PeriodicHousekeepingHelper.h +++ b/src/fsfw/housekeeping/PeriodicHousekeepingHelper.h @@ -1,7 +1,7 @@ #ifndef FSFW_HOUSEKEEPING_PERIODICHOUSEKEEPINGHELPER_H_ #define FSFW_HOUSEKEEPING_PERIODICHOUSEKEEPINGHELPER_H_ -#include "../timemanager/Clock.h" +#include "fsfw/timemanager/Clock.h" #include class LocalPoolDataSetBase; diff --git a/internalError/CMakeLists.txt b/src/fsfw/internalerror/CMakeLists.txt similarity index 100% rename from internalError/CMakeLists.txt rename to src/fsfw/internalerror/CMakeLists.txt diff --git a/internalError/InternalErrorDataset.h b/src/fsfw/internalerror/InternalErrorDataset.h similarity index 100% rename from internalError/InternalErrorDataset.h rename to src/fsfw/internalerror/InternalErrorDataset.h diff --git a/internalError/InternalErrorReporter.cpp b/src/fsfw/internalerror/InternalErrorReporter.cpp similarity index 96% rename from internalError/InternalErrorReporter.cpp rename to src/fsfw/internalerror/InternalErrorReporter.cpp index 78618448..8689ab3e 100644 --- a/internalError/InternalErrorReporter.cpp +++ b/src/fsfw/internalerror/InternalErrorReporter.cpp @@ -1,9 +1,9 @@ -#include "InternalErrorReporter.h" +#include "fsfw/internalerror/InternalErrorReporter.h" -#include "../ipc/QueueFactory.h" -#include "../ipc/MutexFactory.h" -#include "../serviceinterface/ServiceInterface.h" -#include "../datapool/PoolReadGuard.h" +#include "fsfw/ipc/QueueFactory.h" +#include "fsfw/ipc/MutexFactory.h" +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/datapool/PoolReadGuard.h" InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId, uint32_t messageQueueDepth): SystemObject(setObjectId), diff --git a/internalError/InternalErrorReporter.h b/src/fsfw/internalerror/InternalErrorReporter.h similarity index 91% rename from internalError/InternalErrorReporter.h rename to src/fsfw/internalerror/InternalErrorReporter.h index 580cb8f6..57a6a135 100644 --- a/internalError/InternalErrorReporter.h +++ b/src/fsfw/internalerror/InternalErrorReporter.h @@ -3,12 +3,12 @@ #include "InternalErrorReporterIF.h" -#include "../tasks/PeriodicTaskIF.h" -#include "../internalError/InternalErrorDataset.h" -#include "../datapoollocal/LocalDataPoolManager.h" -#include "../tasks/ExecutableObjectIF.h" -#include "../objectmanager/SystemObject.h" -#include "../ipc/MutexIF.h" +#include "fsfw/tasks/PeriodicTaskIF.h" +#include "fsfw/internalerror/InternalErrorDataset.h" +#include "fsfw/datapoollocal/LocalDataPoolManager.h" +#include "fsfw/tasks/ExecutableObjectIF.h" +#include "fsfw/objectmanager/SystemObject.h" +#include "fsfw/ipc/MutexIF.h" /** * @brief This class is used to track internal errors like lost telemetry, diff --git a/internalError/InternalErrorReporterIF.h b/src/fsfw/internalerror/InternalErrorReporterIF.h similarity index 100% rename from internalError/InternalErrorReporterIF.h rename to src/fsfw/internalerror/InternalErrorReporterIF.h diff --git a/ipc/CMakeLists.txt b/src/fsfw/ipc/CMakeLists.txt similarity index 100% rename from ipc/CMakeLists.txt rename to src/fsfw/ipc/CMakeLists.txt diff --git a/ipc/CommandMessage.cpp b/src/fsfw/ipc/CommandMessage.cpp similarity index 97% rename from ipc/CommandMessage.cpp rename to src/fsfw/ipc/CommandMessage.cpp index 513debd3..9448d152 100644 --- a/ipc/CommandMessage.cpp +++ b/src/fsfw/ipc/CommandMessage.cpp @@ -1,5 +1,6 @@ -#include "CommandMessage.h" -#include "CommandMessageCleaner.h" +#include "fsfw/ipc/CommandMessage.h" +#include "fsfw/ipc/CommandMessageCleaner.h" + #include CommandMessage::CommandMessage() { diff --git a/ipc/CommandMessage.h b/src/fsfw/ipc/CommandMessage.h similarity index 100% rename from ipc/CommandMessage.h rename to src/fsfw/ipc/CommandMessage.h diff --git a/ipc/CommandMessageCleaner.cpp b/src/fsfw/ipc/CommandMessageCleaner.cpp similarity index 58% rename from ipc/CommandMessageCleaner.cpp rename to src/fsfw/ipc/CommandMessageCleaner.cpp index 6a364069..0918d739 100644 --- a/ipc/CommandMessageCleaner.cpp +++ b/src/fsfw/ipc/CommandMessageCleaner.cpp @@ -1,14 +1,18 @@ -#include "CommandMessageCleaner.h" +#include "fsfw/FSFW.h" +#include "fsfw/ipc/CommandMessageCleaner.h" -#include "../devicehandlers/DeviceHandlerMessage.h" -#include "../health/HealthMessage.h" -#include "../memory/MemoryMessage.h" -#include "../modes/ModeMessage.h" -#include "../monitoring/MonitoringMessage.h" -#include "../subsystem/modes/ModeSequenceMessage.h" -#include "../tmstorage/TmStoreMessage.h" -#include "../housekeeping/HousekeepingMessage.h" -#include "../parameters/ParameterMessage.h" +#include "fsfw/memory/GenericFileSystemMessage.h" +#include "fsfw/devicehandlers/DeviceHandlerMessage.h" +#include "fsfw/health/HealthMessage.h" +#include "fsfw/memory/MemoryMessage.h" +#include "fsfw/modes/ModeMessage.h" +#include "fsfw/monitoring/MonitoringMessage.h" +#include "fsfw/subsystem/modes/ModeSequenceMessage.h" +#include "fsfw/housekeeping/HousekeepingMessage.h" +#include "fsfw/parameters/ParameterMessage.h" +#ifdef FSFW_ADD_TMSTORAGE +#include "fsfw/tmstorage/TmStoreMessage.h" +#endif void CommandMessageCleaner::clearCommandMessage(CommandMessage* message) { switch(message->getMessageType()){ @@ -33,15 +37,20 @@ void CommandMessageCleaner::clearCommandMessage(CommandMessage* message) { case messagetypes::MONITORING: MonitoringMessage::clear(message); break; +#ifdef FSFW_ADD_TMSTORAGE case messagetypes::TM_STORE: TmStoreMessage::clear(message); break; +#endif case messagetypes::PARAMETER: ParameterMessage::clear(message); break; case messagetypes::HOUSEKEEPING: HousekeepingMessage::clear(message); break; + case messagetypes::FILE_SYSTEM_MESSAGE: + GenericFileSystemMessage::clear(message); + break; default: messagetypes::clearMissionMessage(message); break; diff --git a/ipc/CommandMessageCleaner.h b/src/fsfw/ipc/CommandMessageCleaner.h similarity index 100% rename from ipc/CommandMessageCleaner.h rename to src/fsfw/ipc/CommandMessageCleaner.h diff --git a/ipc/CommandMessageIF.h b/src/fsfw/ipc/CommandMessageIF.h similarity index 100% rename from ipc/CommandMessageIF.h rename to src/fsfw/ipc/CommandMessageIF.h diff --git a/ipc/FwMessageTypes.h b/src/fsfw/ipc/FwMessageTypes.h similarity index 100% rename from ipc/FwMessageTypes.h rename to src/fsfw/ipc/FwMessageTypes.h diff --git a/ipc/MessageQueueIF.h b/src/fsfw/ipc/MessageQueueIF.h similarity index 96% rename from ipc/MessageQueueIF.h rename to src/fsfw/ipc/MessageQueueIF.h index 74ccb29a..217174f6 100644 --- a/ipc/MessageQueueIF.h +++ b/src/fsfw/ipc/MessageQueueIF.h @@ -22,11 +22,11 @@ public: static const uint8_t INTERFACE_ID = CLASS_ID::MESSAGE_QUEUE_IF; //! No new messages on the queue static const ReturnValue_t EMPTY = MAKE_RETURN_CODE(1); - //! No space left for more messages + //! [EXPORT] : [COMMENT] No space left for more messages static const ReturnValue_t FULL = MAKE_RETURN_CODE(2); - //! Returned if a reply method was called without partner + //! [EXPORT] : [COMMENT] Returned if a reply method was called without partner static const ReturnValue_t NO_REPLY_PARTNER = MAKE_RETURN_CODE(3); - //! Returned if the target destination is invalid. + //! [EXPORT] : [COMMENT] Returned if the target destination is invalid. static constexpr ReturnValue_t DESTINATION_INVALID = MAKE_RETURN_CODE(4); virtual ~MessageQueueIF() {} diff --git a/ipc/MessageQueueMessage.cpp b/src/fsfw/ipc/MessageQueueMessage.cpp similarity index 94% rename from ipc/MessageQueueMessage.cpp rename to src/fsfw/ipc/MessageQueueMessage.cpp index 1958af54..62b826e9 100644 --- a/ipc/MessageQueueMessage.cpp +++ b/src/fsfw/ipc/MessageQueueMessage.cpp @@ -1,6 +1,7 @@ -#include "MessageQueueMessage.h" -#include "../serviceinterface/ServiceInterfaceStream.h" -#include "../globalfunctions/arrayprinter.h" +#include "fsfw/ipc/MessageQueueMessage.h" +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/globalfunctions/arrayprinter.h" + #include MessageQueueMessage::MessageQueueMessage() : diff --git a/ipc/MessageQueueMessage.h b/src/fsfw/ipc/MessageQueueMessage.h similarity index 99% rename from ipc/MessageQueueMessage.h rename to src/fsfw/ipc/MessageQueueMessage.h index 111056ca..e9ef6756 100644 --- a/ipc/MessageQueueMessage.h +++ b/src/fsfw/ipc/MessageQueueMessage.h @@ -1,7 +1,7 @@ #ifndef FSFW_IPC_MESSAGEQUEUEMESSAGE_H_ #define FSFW_IPC_MESSAGEQUEUEMESSAGE_H_ -#include "../ipc/MessageQueueMessageIF.h" +#include "fsfw/ipc/MessageQueueMessageIF.h" #include /** diff --git a/ipc/MessageQueueMessageIF.h b/src/fsfw/ipc/MessageQueueMessageIF.h similarity index 100% rename from ipc/MessageQueueMessageIF.h rename to src/fsfw/ipc/MessageQueueMessageIF.h diff --git a/ipc/MessageQueueSenderIF.h b/src/fsfw/ipc/MessageQueueSenderIF.h similarity index 100% rename from ipc/MessageQueueSenderIF.h rename to src/fsfw/ipc/MessageQueueSenderIF.h diff --git a/ipc/MutexFactory.h b/src/fsfw/ipc/MutexFactory.h similarity index 100% rename from ipc/MutexFactory.h rename to src/fsfw/ipc/MutexFactory.h diff --git a/ipc/MutexGuard.h b/src/fsfw/ipc/MutexGuard.h similarity index 100% rename from ipc/MutexGuard.h rename to src/fsfw/ipc/MutexGuard.h diff --git a/ipc/MutexIF.h b/src/fsfw/ipc/MutexIF.h similarity index 100% rename from ipc/MutexIF.h rename to src/fsfw/ipc/MutexIF.h diff --git a/ipc/QueueFactory.h b/src/fsfw/ipc/QueueFactory.h similarity index 100% rename from ipc/QueueFactory.h rename to src/fsfw/ipc/QueueFactory.h diff --git a/ipc/messageQueueDefinitions.h b/src/fsfw/ipc/messageQueueDefinitions.h similarity index 100% rename from ipc/messageQueueDefinitions.h rename to src/fsfw/ipc/messageQueueDefinitions.h diff --git a/memory/AcceptsMemoryMessagesIF.h b/src/fsfw/memory/AcceptsMemoryMessagesIF.h similarity index 100% rename from memory/AcceptsMemoryMessagesIF.h rename to src/fsfw/memory/AcceptsMemoryMessagesIF.h diff --git a/src/fsfw/memory/CMakeLists.txt b/src/fsfw/memory/CMakeLists.txt new file mode 100644 index 00000000..c713cd42 --- /dev/null +++ b/src/fsfw/memory/CMakeLists.txt @@ -0,0 +1,5 @@ +target_sources(${LIB_FSFW_NAME} PRIVATE + MemoryHelper.cpp + MemoryMessage.cpp + GenericFileSystemMessage.cpp +) \ No newline at end of file diff --git a/src/fsfw/memory/FileSystemArgsIF.h b/src/fsfw/memory/FileSystemArgsIF.h new file mode 100644 index 00000000..67d423ff --- /dev/null +++ b/src/fsfw/memory/FileSystemArgsIF.h @@ -0,0 +1,13 @@ +#ifndef FSFW_SRC_FSFW_MEMORY_FILESYSTEMARGS_H_ +#define FSFW_SRC_FSFW_MEMORY_FILESYSTEMARGS_H_ + +/** + * Empty base interface which can be implemented by to pass arguments via the HasFileSystemIF. + * Users can then dynamic_cast the base pointer to the require child pointer. + */ +class FileSystemArgsIF { +public: + virtual~ FileSystemArgsIF() {}; +}; + +#endif /* FSFW_SRC_FSFW_MEMORY_FILESYSTEMARGS_H_ */ diff --git a/src/fsfw/memory/GenericFileSystemMessage.cpp b/src/fsfw/memory/GenericFileSystemMessage.cpp new file mode 100644 index 00000000..bd36d87b --- /dev/null +++ b/src/fsfw/memory/GenericFileSystemMessage.cpp @@ -0,0 +1,168 @@ +#include "fsfw/memory/GenericFileSystemMessage.h" + +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/storagemanager/StorageManagerIF.h" + +void GenericFileSystemMessage::setCreateFileCommand(CommandMessage* message, + store_address_t storeId) { + message->setCommand(CMD_CREATE_FILE); + message->setParameter2(storeId.raw); +} + +void GenericFileSystemMessage::setDeleteFileCommand( + CommandMessage* message, store_address_t storeId) { + message->setCommand(CMD_DELETE_FILE); + message->setParameter2(storeId.raw); +} + +void GenericFileSystemMessage::setCreateDirectoryCommand( + CommandMessage* message, store_address_t storeId) { + message->setCommand(CMD_CREATE_DIRECTORY); + message->setParameter2(storeId.raw); +} + +void GenericFileSystemMessage::setReportFileAttributesCommand(CommandMessage *message, + store_address_t storeId) { + message->setCommand(CMD_REPORT_FILE_ATTRIBUTES); + message->setParameter2(storeId.raw); +} + +void GenericFileSystemMessage::setReportFileAttributesReply(CommandMessage *message, + store_address_t storeId) { + message->setCommand(REPLY_REPORT_FILE_ATTRIBUTES); + message->setParameter2(storeId.raw); +} + +void GenericFileSystemMessage::setDeleteDirectoryCommand(CommandMessage* message, + store_address_t storeId, bool deleteRecursively) { + message->setCommand(CMD_DELETE_DIRECTORY); + message->setParameter(deleteRecursively); + message->setParameter2(storeId.raw); +} + +void GenericFileSystemMessage::setLockFileCommand(CommandMessage *message, + store_address_t storeId) { + message->setCommand(CMD_LOCK_FILE); + message->setParameter2(storeId.raw); +} + +void GenericFileSystemMessage::setUnlockFileCommand(CommandMessage *message, + store_address_t storeId) { + message->setCommand(CMD_UNLOCK_FILE); + message->setParameter2(storeId.raw); +} + +void GenericFileSystemMessage::setSuccessReply(CommandMessage *message) { + message->setCommand(COMPLETION_SUCCESS); +} + +void GenericFileSystemMessage::setFailureReply(CommandMessage *message, + ReturnValue_t errorCode, uint32_t errorParam) { + message->setCommand(COMPLETION_FAILED); + message->setParameter(errorCode); + message->setParameter2(errorParam); +} + +store_address_t GenericFileSystemMessage::getStoreId(const CommandMessage* message) { + store_address_t temp; + temp.raw = message->getParameter2(); + return temp; +} + +ReturnValue_t GenericFileSystemMessage::getFailureReply( + const CommandMessage *message, uint32_t* errorParam) { + if(errorParam != nullptr) { + *errorParam = message->getParameter2(); + } + return message->getParameter(); +} + +void GenericFileSystemMessage::setFinishStopWriteCommand(CommandMessage *message, + store_address_t storeId) { + message->setCommand(CMD_FINISH_APPEND_TO_FILE); + message->setParameter2(storeId.raw); +} + +void GenericFileSystemMessage::setFinishStopWriteReply(CommandMessage *message, + store_address_t storeId) { + message->setCommand(REPLY_FINISH_APPEND); + message->setParameter2(storeId.raw); +} + +void GenericFileSystemMessage::setCopyCommand(CommandMessage* message, + store_address_t storeId) { + message->setCommand(CMD_COPY_FILE); + message->setParameter2(storeId.raw); +} + +void GenericFileSystemMessage::setWriteCommand(CommandMessage* message, + store_address_t storeId) { + message->setCommand(CMD_APPEND_TO_FILE); + message->setParameter2(storeId.raw); +} + +void GenericFileSystemMessage::setReadCommand(CommandMessage* message, + store_address_t storeId) { + message->setCommand(CMD_READ_FROM_FILE); + message->setParameter2(storeId.raw); +} + +void GenericFileSystemMessage::setFinishAppendReply(CommandMessage* message, + store_address_t storageID) { + message->setCommand(REPLY_FINISH_APPEND); + message->setParameter2(storageID.raw); +} + +void GenericFileSystemMessage::setReadReply(CommandMessage* message, + bool readFinished, store_address_t storeId) { + message->setCommand(REPLY_READ_FROM_FILE); + message->setParameter(readFinished); + message->setParameter2(storeId.raw); +} + +void GenericFileSystemMessage::setReadFinishedReply(CommandMessage *message, + store_address_t storeId) { + message->setCommand(REPLY_READ_FINISHED_STOP); + message->setParameter2(storeId.raw); +} + +bool GenericFileSystemMessage::getReadReply(const CommandMessage *message, + store_address_t *storeId) { + if(storeId != nullptr) { + (*storeId).raw = message->getParameter2(); + } + return message->getParameter(); +} + +store_address_t GenericFileSystemMessage::getDeleteDirectoryCommand(const CommandMessage *message, + bool &deleteRecursively) { + deleteRecursively = message->getParameter(); + return getStoreId(message); +} + +ReturnValue_t GenericFileSystemMessage::clear(CommandMessage* message) { + switch(message->getCommand()) { + case(CMD_CREATE_FILE): + case(CMD_DELETE_FILE): + case(CMD_CREATE_DIRECTORY): + case(CMD_REPORT_FILE_ATTRIBUTES): + case(REPLY_REPORT_FILE_ATTRIBUTES): + case(CMD_LOCK_FILE): + case(CMD_UNLOCK_FILE): + case(CMD_COPY_FILE): + case(REPLY_READ_FROM_FILE): + case(CMD_READ_FROM_FILE): + case(CMD_APPEND_TO_FILE): + case(CMD_FINISH_APPEND_TO_FILE): + case(REPLY_READ_FINISHED_STOP): + case(REPLY_FINISH_APPEND): { + store_address_t storeId = GenericFileSystemMessage::getStoreId(message); + auto ipcStore = ObjectManager::instance()->get(objects::IPC_STORE); + if(ipcStore == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + return ipcStore->deleteData(storeId); + } + } + return HasReturnvaluesIF::RETURN_OK; +} diff --git a/src/fsfw/memory/GenericFileSystemMessage.h b/src/fsfw/memory/GenericFileSystemMessage.h new file mode 100644 index 00000000..fcd2075d --- /dev/null +++ b/src/fsfw/memory/GenericFileSystemMessage.h @@ -0,0 +1,117 @@ +#ifndef MISSION_MEMORY_GENERICFILESYSTEMMESSAGE_H_ +#define MISSION_MEMORY_GENERICFILESYSTEMMESSAGE_H_ + +#include + +#include +#include +#include +#include + +/** + * @brief These messages are sent to an object implementing HasFilesystemIF. + * @details + * Enables a message-based file management. The user can add custo commands be implementing + * this generic class. + * @author Jakob Meier, R. Mueller + */ +class GenericFileSystemMessage { +public: + /* Instantiation forbidden */ + GenericFileSystemMessage() = delete; + + static const uint8_t MESSAGE_ID = messagetypes::FILE_SYSTEM_MESSAGE; + /* PUS standard (ECSS-E-ST-70-41C15 2016 p.654) */ + static const Command_t CMD_CREATE_FILE = MAKE_COMMAND_ID(1); + static const Command_t CMD_DELETE_FILE = MAKE_COMMAND_ID(2); + /** Report file attributes */ + static const Command_t CMD_REPORT_FILE_ATTRIBUTES = MAKE_COMMAND_ID(3); + static const Command_t REPLY_REPORT_FILE_ATTRIBUTES = MAKE_COMMAND_ID(4); + /** Command to lock a file, setting it read-only */ + static const Command_t CMD_LOCK_FILE = MAKE_COMMAND_ID(5); + /** Command to unlock a file, enabling further operations on it */ + static const Command_t CMD_UNLOCK_FILE = MAKE_COMMAND_ID(6); + /** + * Find file in repository, using a search pattern. + * Please note that * is the wildcard character. + * For example, when looking for all files which start with have the + * structure tm.bin, tm*.bin can be used. + */ + static const Command_t CMD_FIND_FILE = MAKE_COMMAND_ID(7); + static const Command_t CMD_CREATE_DIRECTORY = MAKE_COMMAND_ID(9); + static const Command_t CMD_DELETE_DIRECTORY = MAKE_COMMAND_ID(10); + static const Command_t CMD_RENAME_DIRECTORY = MAKE_COMMAND_ID(11); + + /** Dump contents of a repository */ + static const Command_t CMD_DUMP_REPOSITORY = MAKE_COMMAND_ID(12); + /** Repository dump reply */ + static const Command_t REPLY_DUMY_REPOSITORY = MAKE_COMMAND_ID(13); + static constexpr Command_t CMD_COPY_FILE = MAKE_COMMAND_ID(14); + static constexpr Command_t CMD_MOVE_FILE = MAKE_COMMAND_ID(15); + + static const Command_t COMPLETION_SUCCESS = MAKE_COMMAND_ID(128); + static const Command_t COMPLETION_FAILED = MAKE_COMMAND_ID(129); + + // These command IDs will remain until CFDP has been introduced and consolidated. + /** Append operation commands */ + static const Command_t CMD_APPEND_TO_FILE = MAKE_COMMAND_ID(130); + static const Command_t CMD_FINISH_APPEND_TO_FILE = MAKE_COMMAND_ID(131); + static const Command_t REPLY_FINISH_APPEND = MAKE_COMMAND_ID(132); + + static const Command_t CMD_READ_FROM_FILE = MAKE_COMMAND_ID(140); + static const Command_t REPLY_READ_FROM_FILE = MAKE_COMMAND_ID(141); + static const Command_t CMD_STOP_READ = MAKE_COMMAND_ID(142); + static const Command_t REPLY_READ_FINISHED_STOP = MAKE_COMMAND_ID(143); + + static void setLockFileCommand(CommandMessage* message, store_address_t storeId); + static void setUnlockFileCommand(CommandMessage* message, store_address_t storeId); + + static void setCreateFileCommand(CommandMessage* message, + store_address_t storeId); + static void setDeleteFileCommand(CommandMessage* message, + store_address_t storeId); + + static void setReportFileAttributesCommand(CommandMessage* message, + store_address_t storeId); + static void setReportFileAttributesReply(CommandMessage* message, + store_address_t storeId); + + static void setCreateDirectoryCommand(CommandMessage* message, + store_address_t storeId); + static void setDeleteDirectoryCommand(CommandMessage* message, + store_address_t storeId, bool deleteRecursively); + static store_address_t getDeleteDirectoryCommand(const CommandMessage* message, + bool& deleteRecursively); + + static void setSuccessReply(CommandMessage* message); + static void setFailureReply(CommandMessage* message, + ReturnValue_t errorCode, uint32_t errorParam = 0); + static void setCopyCommand(CommandMessage* message, store_address_t storeId); + + static void setWriteCommand(CommandMessage* message, + store_address_t storeId); + static void setFinishStopWriteCommand(CommandMessage* message, + store_address_t storeId); + static void setFinishStopWriteReply(CommandMessage* message, + store_address_t storeId); + static void setFinishAppendReply(CommandMessage* message, + store_address_t storeId); + + static void setReadCommand(CommandMessage* message, + store_address_t storeId); + static void setReadFinishedReply(CommandMessage* message, + store_address_t storeId); + static void setReadReply(CommandMessage* message, bool readFinished, + store_address_t storeId); + static bool getReadReply(const CommandMessage* message, + store_address_t* storeId); + + static store_address_t getStoreId(const CommandMessage* message); + static ReturnValue_t getFailureReply(const CommandMessage* message, + uint32_t* errorParam = nullptr); + + static ReturnValue_t clear(CommandMessage* message); + +}; + +#endif /* MISSION_MEMORY_GENERICFILESYSTEMMESSAGE_H_ */ diff --git a/memory/HasFileSystemIF.h b/src/fsfw/memory/HasFileSystemIF.h similarity index 62% rename from memory/HasFileSystemIF.h rename to src/fsfw/memory/HasFileSystemIF.h index 73c93410..be2f8923 100644 --- a/memory/HasFileSystemIF.h +++ b/src/fsfw/memory/HasFileSystemIF.h @@ -1,9 +1,10 @@ #ifndef FSFW_MEMORY_HASFILESYSTEMIF_H_ #define FSFW_MEMORY_HASFILESYSTEMIF_H_ -#include "../returnvalues/HasReturnvaluesIF.h" -#include "../returnvalues/FwClassIds.h" -#include "../ipc/messageQueueDefinitions.h" +#include "FileSystemArgsIF.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" +#include "fsfw/returnvalues/FwClassIds.h" +#include "fsfw/ipc/messageQueueDefinitions.h" #include @@ -36,9 +37,8 @@ public: //! [EXPORT] : P1: Sequence number missing static constexpr ReturnValue_t SEQUENCE_PACKET_MISSING_READ = MAKE_RETURN_CODE(16); - - virtual ~HasFileSystemIF() {} + /** * Function to get the MessageQueueId_t of the implementing object * @return MessageQueueId_t of the object @@ -46,7 +46,7 @@ public: virtual MessageQueueId_t getCommandQueue() const = 0; /** - * Generic function to append to file. + * @brief Generic function to append to file. * @param dirname Directory of the file * @param filename The filename of the file * @param data The data to write to the file @@ -60,30 +60,52 @@ public: */ virtual ReturnValue_t appendToFile(const char* repositoryPath, const char* filename, const uint8_t* data, size_t size, - uint16_t packetNumber, void* args = nullptr) = 0; + uint16_t packetNumber, FileSystemArgsIF* args = nullptr) = 0; /** - * Generic function to create a new file. + * @brief Generic function to create a new file. * @param repositoryPath * @param filename * @param data * @param size - * @param args Any other arguments which an implementation might require. + * @param args Any other arguments which an implementation might require * @return */ virtual ReturnValue_t createFile(const char* repositoryPath, const char* filename, const uint8_t* data = nullptr, - size_t size = 0, void* args = nullptr) = 0; + size_t size = 0, FileSystemArgsIF* args = nullptr) = 0; /** - * Generic function to delete a file. + * @brief Generic function to delete a file. * @param repositoryPath * @param filename - * @param args + * @param args Any other arguments which an implementation might require * @return */ - virtual ReturnValue_t deleteFile(const char* repositoryPath, - const char* filename, void* args = nullptr) = 0; + virtual ReturnValue_t removeFile(const char* repositoryPath, + const char* filename, FileSystemArgsIF* args = nullptr) = 0; + + /** + * @brief Generic function to create a directory + * @param repositoryPath + * @param Equivalent to the -p flag in Unix systems. If some required parent directories + * do not exist, create them as well + * @param args Any other arguments which an implementation might require + * @return + */ + virtual ReturnValue_t createDirectory(const char* repositoryPath, const char* dirname, + bool createParentDirs, FileSystemArgsIF* args = nullptr) = 0; + + /** + * @brief Generic function to remove a directory + * @param repositoryPath + * @param args Any other arguments which an implementation might require + */ + virtual ReturnValue_t removeDirectory(const char* repositoryPath, const char* dirname, + bool deleteRecurively = false, FileSystemArgsIF* args = nullptr) = 0; + + virtual ReturnValue_t renameFile(const char* repositoryPath, const char* oldFilename, + const char* newFilename, FileSystemArgsIF* args = nullptr) = 0; }; diff --git a/memory/HasMemoryIF.h b/src/fsfw/memory/HasMemoryIF.h similarity index 100% rename from memory/HasMemoryIF.h rename to src/fsfw/memory/HasMemoryIF.h diff --git a/memory/MemoryHelper.cpp b/src/fsfw/memory/MemoryHelper.cpp similarity index 94% rename from memory/MemoryHelper.cpp rename to src/fsfw/memory/MemoryHelper.cpp index 42ac2654..2039a488 100644 --- a/memory/MemoryHelper.cpp +++ b/src/fsfw/memory/MemoryHelper.cpp @@ -1,10 +1,10 @@ -#include "MemoryHelper.h" -#include "MemoryMessage.h" +#include "fsfw/memory/MemoryHelper.h" +#include "fsfw/memory/MemoryMessage.h" -#include "../globalfunctions/CRC.h" -#include "../objectmanager/ObjectManagerIF.h" -#include "../serialize/EndianConverter.h" -#include "../serviceinterface/ServiceInterfaceStream.h" +#include "fsfw/globalfunctions/CRC.h" +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/serialize/EndianConverter.h" +#include "fsfw/serviceinterface/ServiceInterface.h" MemoryHelper::MemoryHelper(HasMemoryIF* workOnThis, MessageQueueIF* useThisQueue): @@ -187,7 +187,7 @@ ReturnValue_t MemoryHelper::initialize(MessageQueueIF* queueToUse_) { } ReturnValue_t MemoryHelper::initialize() { - ipcStore = objectManager->get(objects::IPC_STORE); + ipcStore = ObjectManager::instance()->get(objects::IPC_STORE); if (ipcStore != nullptr) { return RETURN_OK; } else { diff --git a/memory/MemoryHelper.h b/src/fsfw/memory/MemoryHelper.h similarity index 100% rename from memory/MemoryHelper.h rename to src/fsfw/memory/MemoryHelper.h diff --git a/memory/MemoryMessage.cpp b/src/fsfw/memory/MemoryMessage.cpp similarity index 94% rename from memory/MemoryMessage.cpp rename to src/fsfw/memory/MemoryMessage.cpp index 94fa4691..9df52609 100644 --- a/memory/MemoryMessage.cpp +++ b/src/fsfw/memory/MemoryMessage.cpp @@ -1,6 +1,6 @@ -#include "MemoryMessage.h" +#include "fsfw/memory/MemoryMessage.h" -#include "../objectmanager/ObjectManagerIF.h" +#include "fsfw/objectmanager/ObjectManager.h" uint32_t MemoryMessage::getAddress(const CommandMessage* message) { return message->getParameter(); @@ -44,7 +44,7 @@ void MemoryMessage::clear(CommandMessage* message) { switch (message->getCommand()) { case CMD_MEMORY_LOAD: case REPLY_MEMORY_DUMP: { - StorageManagerIF *ipcStore = objectManager->get( + StorageManagerIF *ipcStore = ObjectManager::instance()->get( objects::IPC_STORE); if (ipcStore != NULL) { ipcStore->deleteData(getStoreID(message)); diff --git a/memory/MemoryMessage.h b/src/fsfw/memory/MemoryMessage.h similarity index 100% rename from memory/MemoryMessage.h rename to src/fsfw/memory/MemoryMessage.h diff --git a/modes/CMakeLists.txt b/src/fsfw/modes/CMakeLists.txt similarity index 100% rename from modes/CMakeLists.txt rename to src/fsfw/modes/CMakeLists.txt diff --git a/modes/HasModesIF.h b/src/fsfw/modes/HasModesIF.h similarity index 100% rename from modes/HasModesIF.h rename to src/fsfw/modes/HasModesIF.h diff --git a/modes/ModeHelper.cpp b/src/fsfw/modes/ModeHelper.cpp similarity index 95% rename from modes/ModeHelper.cpp rename to src/fsfw/modes/ModeHelper.cpp index 6be4f776..d2c5067d 100644 --- a/modes/ModeHelper.cpp +++ b/src/fsfw/modes/ModeHelper.cpp @@ -1,8 +1,8 @@ -#include "HasModesIF.h" -#include "ModeHelper.h" +#include "fsfw/modes/HasModesIF.h" +#include "fsfw/modes/ModeHelper.h" -#include "../ipc/MessageQueueSenderIF.h" -#include "../serviceinterface/ServiceInterfaceStream.h" +#include "fsfw/ipc/MessageQueueSenderIF.h" +#include "fsfw/serviceinterface/ServiceInterface.h" ModeHelper::ModeHelper(HasModesIF *owner) : commandedMode(HasModesIF::MODE_OFF), diff --git a/modes/ModeHelper.h b/src/fsfw/modes/ModeHelper.h similarity index 89% rename from modes/ModeHelper.h rename to src/fsfw/modes/ModeHelper.h index c2f089ec..27928a29 100644 --- a/modes/ModeHelper.h +++ b/src/fsfw/modes/ModeHelper.h @@ -2,9 +2,9 @@ #define FSFW_MODES_MODEHELPER_H_ #include "ModeMessage.h" -#include "../ipc/MessageQueueIF.h" -#include "../returnvalues/HasReturnvaluesIF.h" -#include "../timemanager/Countdown.h" +#include "fsfw/ipc/MessageQueueIF.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" +#include "fsfw/timemanager/Countdown.h" class HasModesIF; diff --git a/modes/ModeMessage.cpp b/src/fsfw/modes/ModeMessage.cpp similarity index 95% rename from modes/ModeMessage.cpp rename to src/fsfw/modes/ModeMessage.cpp index b33bba60..a228304d 100644 --- a/modes/ModeMessage.cpp +++ b/src/fsfw/modes/ModeMessage.cpp @@ -1,4 +1,4 @@ -#include "ModeMessage.h" +#include "fsfw/modes/ModeMessage.h" Mode_t ModeMessage::getMode(const CommandMessage* message) { return message->getParameter(); diff --git a/modes/ModeMessage.h b/src/fsfw/modes/ModeMessage.h similarity index 100% rename from modes/ModeMessage.h rename to src/fsfw/modes/ModeMessage.h diff --git a/monitoring/AbsLimitMonitor.h b/src/fsfw/monitoring/AbsLimitMonitor.h similarity index 98% rename from monitoring/AbsLimitMonitor.h rename to src/fsfw/monitoring/AbsLimitMonitor.h index 5feb369c..f3bbf04c 100644 --- a/monitoring/AbsLimitMonitor.h +++ b/src/fsfw/monitoring/AbsLimitMonitor.h @@ -1,6 +1,7 @@ #ifndef FSFW_MONITORING_ABSLIMITMONITOR_H_ #define FSFW_MONITORING_ABSLIMITMONITOR_H_ +#include "monitoringConf.h" #include "MonitorBase.h" #include diff --git a/monitoring/CMakeLists.txt b/src/fsfw/monitoring/CMakeLists.txt similarity index 100% rename from monitoring/CMakeLists.txt rename to src/fsfw/monitoring/CMakeLists.txt diff --git a/monitoring/HasMonitorsIF.h b/src/fsfw/monitoring/HasMonitorsIF.h similarity index 96% rename from monitoring/HasMonitorsIF.h rename to src/fsfw/monitoring/HasMonitorsIF.h index 04f63437..20520952 100644 --- a/monitoring/HasMonitorsIF.h +++ b/src/fsfw/monitoring/HasMonitorsIF.h @@ -1,6 +1,7 @@ #ifndef FSFW_MONITORING_HASMONITORSIF_H_ #define FSFW_MONITORING_HASMONITORSIF_H_ +#include "monitoringConf.h" #include "../events/EventReportingProxyIF.h" #include "../objectmanager/ObjectManagerIF.h" #include "../ipc/MessageQueueSenderIF.h" diff --git a/monitoring/LimitMonitor.h b/src/fsfw/monitoring/LimitMonitor.h similarity index 99% rename from monitoring/LimitMonitor.h rename to src/fsfw/monitoring/LimitMonitor.h index cd8b8d13..2565ebaa 100644 --- a/monitoring/LimitMonitor.h +++ b/src/fsfw/monitoring/LimitMonitor.h @@ -1,6 +1,7 @@ #ifndef FRAMEWORK_MONITORING_LIMITMONITOR_H_ #define FRAMEWORK_MONITORING_LIMITMONITOR_H_ +#include "monitoringConf.h" #include "MonitorBase.h" /** diff --git a/monitoring/LimitViolationReporter.cpp b/src/fsfw/monitoring/LimitViolationReporter.cpp similarity index 67% rename from monitoring/LimitViolationReporter.cpp rename to src/fsfw/monitoring/LimitViolationReporter.cpp index c531a6e6..a0b8a4cb 100644 --- a/monitoring/LimitViolationReporter.cpp +++ b/src/fsfw/monitoring/LimitViolationReporter.cpp @@ -1,14 +1,9 @@ -/** - * @file LimitViolationReporter.cpp - * @brief This file defines the LimitViolationReporter class. - * @date 17.07.2014 - * @author baetz - */ -#include "LimitViolationReporter.h" -#include "MonitoringIF.h" -#include "ReceivesMonitoringReportsIF.h" -#include "../objectmanager/ObjectManagerIF.h" -#include "../serialize/SerializeAdapter.h" +#include "fsfw/monitoring/LimitViolationReporter.h" +#include "fsfw/monitoring/MonitoringIF.h" +#include "fsfw/monitoring/ReceivesMonitoringReportsIF.h" + +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/serialize/SerializeAdapter.h" ReturnValue_t LimitViolationReporter::sendLimitViolationReport(const SerializeIF* data) { ReturnValue_t result = checkClassLoaded(); @@ -16,7 +11,7 @@ ReturnValue_t LimitViolationReporter::sendLimitViolationReport(const SerializeIF return result; } store_address_t storeId; - uint8_t* dataTarget = NULL; + uint8_t* dataTarget = nullptr; size_t maxSize = data->getSerializedSize(); if (maxSize > MonitoringIF::VIOLATION_REPORT_MAX_SIZE) { return MonitoringIF::INVALID_SIZE; @@ -38,16 +33,16 @@ ReturnValue_t LimitViolationReporter::sendLimitViolationReport(const SerializeIF ReturnValue_t LimitViolationReporter::checkClassLoaded() { if (reportQueue == 0) { - ReceivesMonitoringReportsIF* receiver = objectManager->get< + ReceivesMonitoringReportsIF* receiver = ObjectManager::instance()->get< ReceivesMonitoringReportsIF>(reportingTarget); - if (receiver == NULL) { + if (receiver == nullptr) { return ObjectManagerIF::NOT_FOUND; } reportQueue = receiver->getCommandQueue(); } - if (ipcStore == NULL) { - ipcStore = objectManager->get(objects::IPC_STORE); - if (ipcStore == NULL) { + if (ipcStore == nullptr) { + ipcStore = ObjectManager::instance()->get(objects::IPC_STORE); + if (ipcStore == nullptr) { return HasReturnvaluesIF::RETURN_FAILED; } } @@ -56,5 +51,5 @@ ReturnValue_t LimitViolationReporter::checkClassLoaded() { //Lazy initialization. MessageQueueId_t LimitViolationReporter::reportQueue = 0; -StorageManagerIF* LimitViolationReporter::ipcStore = NULL; +StorageManagerIF* LimitViolationReporter::ipcStore = nullptr; object_id_t LimitViolationReporter::reportingTarget = 0; diff --git a/monitoring/LimitViolationReporter.h b/src/fsfw/monitoring/LimitViolationReporter.h similarity index 96% rename from monitoring/LimitViolationReporter.h rename to src/fsfw/monitoring/LimitViolationReporter.h index a71b972f..b254e312 100644 --- a/monitoring/LimitViolationReporter.h +++ b/src/fsfw/monitoring/LimitViolationReporter.h @@ -7,6 +7,7 @@ #ifndef LIMITVIOLATIONREPORTER_H_ #define LIMITVIOLATIONREPORTER_H_ +#include "monitoringConf.h" #include "../returnvalues/HasReturnvaluesIF.h" #include "../serialize/SerializeIF.h" #include "../storagemanager/StorageManagerIF.h" diff --git a/monitoring/MonitorBase.h b/src/fsfw/monitoring/MonitorBase.h similarity index 98% rename from monitoring/MonitorBase.h rename to src/fsfw/monitoring/MonitorBase.h index 967f0f62..261b3eac 100644 --- a/monitoring/MonitorBase.h +++ b/src/fsfw/monitoring/MonitorBase.h @@ -1,6 +1,7 @@ #ifndef FSFW_MONITORING_MONITORBASE_H_ #define FSFW_MONITORING_MONITORBASE_H_ +#include "monitoringConf.h" #include "LimitViolationReporter.h" #include "MonitoringIF.h" #include "MonitoringMessageContent.h" diff --git a/monitoring/MonitorReporter.h b/src/fsfw/monitoring/MonitorReporter.h similarity index 99% rename from monitoring/MonitorReporter.h rename to src/fsfw/monitoring/MonitorReporter.h index d155594d..e27d0101 100644 --- a/monitoring/MonitorReporter.h +++ b/src/fsfw/monitoring/MonitorReporter.h @@ -1,6 +1,7 @@ #ifndef FSFW_MONITORING_MONITORREPORTER_H_ #define FSFW_MONITORING_MONITORREPORTER_H_ +#include "monitoringConf.h" #include "LimitViolationReporter.h" #include "MonitoringIF.h" #include "MonitoringMessageContent.h" diff --git a/monitoring/MonitoringIF.h b/src/fsfw/monitoring/MonitoringIF.h similarity index 98% rename from monitoring/MonitoringIF.h rename to src/fsfw/monitoring/MonitoringIF.h index 32c62530..9c35b419 100644 --- a/monitoring/MonitoringIF.h +++ b/src/fsfw/monitoring/MonitoringIF.h @@ -1,8 +1,8 @@ #ifndef FSFW_MONITORING_MONITORINGIF_H_ #define FSFW_MONITORING_MONITORINGIF_H_ +#include "monitoringConf.h" #include "MonitoringMessage.h" -#include "../memory/HasMemoryIF.h" #include "../serialize/SerializeIF.h" class MonitoringIF : public SerializeIF { @@ -62,6 +62,4 @@ public: } }; - - #endif /* FSFW_MONITORING_MONITORINGIF_H_ */ diff --git a/monitoring/MonitoringMessage.cpp b/src/fsfw/monitoring/MonitoringMessage.cpp similarity index 83% rename from monitoring/MonitoringMessage.cpp rename to src/fsfw/monitoring/MonitoringMessage.cpp index 8caa27ae..8bbb7765 100644 --- a/monitoring/MonitoringMessage.cpp +++ b/src/fsfw/monitoring/MonitoringMessage.cpp @@ -1,5 +1,5 @@ -#include "MonitoringMessage.h" -#include "../objectmanager/ObjectManagerIF.h" +#include "fsfw/monitoring/MonitoringMessage.h" +#include "fsfw/objectmanager/ObjectManager.h" MonitoringMessage::~MonitoringMessage() { } @@ -25,7 +25,7 @@ void MonitoringMessage::clear(CommandMessage* message) { message->setCommand(CommandMessage::CMD_NONE); switch (message->getCommand()) { case MonitoringMessage::LIMIT_VIOLATION_REPORT: { - StorageManagerIF *ipcStore = objectManager->get( + StorageManagerIF *ipcStore = ObjectManager::instance()->get( objects::IPC_STORE); if (ipcStore != NULL) { ipcStore->deleteData(getStoreId(message)); diff --git a/monitoring/MonitoringMessage.h b/src/fsfw/monitoring/MonitoringMessage.h similarity index 86% rename from monitoring/MonitoringMessage.h rename to src/fsfw/monitoring/MonitoringMessage.h index 84b02750..a625e388 100644 --- a/monitoring/MonitoringMessage.h +++ b/src/fsfw/monitoring/MonitoringMessage.h @@ -1,8 +1,9 @@ #ifndef MONITORINGMESSAGE_H_ #define MONITORINGMESSAGE_H_ -#include "../ipc/CommandMessage.h" -#include "../storagemanager/StorageManagerIF.h" +#include "monitoringConf.h" +#include "fsfw/ipc/CommandMessage.h" +#include "fsfw/storagemanager/StorageManagerIF.h" class MonitoringMessage: public CommandMessage { public: diff --git a/monitoring/MonitoringMessageContent.h b/src/fsfw/monitoring/MonitoringMessageContent.h similarity index 95% rename from monitoring/MonitoringMessageContent.h rename to src/fsfw/monitoring/MonitoringMessageContent.h index 0314d7ed..cf8c8752 100644 --- a/monitoring/MonitoringMessageContent.h +++ b/src/fsfw/monitoring/MonitoringMessageContent.h @@ -1,11 +1,12 @@ #ifndef FSFW_MONITORING_MONITORINGMESSAGECONTENT_H_ #define FSFW_MONITORING_MONITORINGMESSAGECONTENT_H_ +#include "monitoringConf.h" #include "HasMonitorsIF.h" #include "MonitoringIF.h" #include "../datapoollocal/localPoolDefinitions.h" -#include "../objectmanager/ObjectManagerIF.h" +#include "../objectmanager/ObjectManager.h" #include "../serialize/SerialBufferAdapter.h" #include "../serialize/SerialFixedArrayListAdapter.h" #include "../serialize/SerializeElement.h" @@ -71,7 +72,7 @@ private: } bool checkAndSetStamper() { if (timeStamper == nullptr) { - timeStamper = objectManager->get( timeStamperId ); + timeStamper = ObjectManager::instance()->get( timeStamperId ); if ( timeStamper == nullptr ) { #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "MonitoringReportContent::checkAndSetStamper: " diff --git a/monitoring/ReceivesMonitoringReportsIF.h b/src/fsfw/monitoring/ReceivesMonitoringReportsIF.h similarity index 78% rename from monitoring/ReceivesMonitoringReportsIF.h rename to src/fsfw/monitoring/ReceivesMonitoringReportsIF.h index fb37c16c..6c126c84 100644 --- a/monitoring/ReceivesMonitoringReportsIF.h +++ b/src/fsfw/monitoring/ReceivesMonitoringReportsIF.h @@ -1,7 +1,8 @@ #ifndef RECEIVESMONITORINGREPORTSIF_H_ #define RECEIVESMONITORINGREPORTSIF_H_ -#include "../ipc/MessageQueueSenderIF.h" +#include "monitoringConf.h" +#include "fsfw/ipc/messageQueueDefinitions.h" class ReceivesMonitoringReportsIF { public: diff --git a/monitoring/TriplexMonitor.h b/src/fsfw/monitoring/TriplexMonitor.h similarity index 96% rename from monitoring/TriplexMonitor.h rename to src/fsfw/monitoring/TriplexMonitor.h index d9ee8305..ff995b5d 100644 --- a/monitoring/TriplexMonitor.h +++ b/src/fsfw/monitoring/TriplexMonitor.h @@ -1,11 +1,12 @@ #ifndef FRAMEWORK_MONITORING_TRIPLEXMONITOR_H_ #define FRAMEWORK_MONITORING_TRIPLEXMONITOR_H_ +#include "monitoringConf.h" #include "../datapool/DataSet.h" #include "../datapool/PIDReaderList.h" #include "../health/HealthTableIF.h" #include "../parameters/HasParametersIF.h" -#include "../objectmanager/ObjectManagerIF.h" +#include "../objectmanager/ObjectManager.h" //SHOULDDO: This is by far not perfect. Could be merged with new Monitor classes. But still, it's over-engineering. @@ -64,7 +65,7 @@ public: return result; } ReturnValue_t initialize() { - healthTable = objectManager->get(objects::HEALTH_TABLE); + healthTable = ObjectManager::instance()->get(objects::HEALTH_TABLE); if (healthTable == NULL) { return HasReturnvaluesIF::RETURN_FAILED; } diff --git a/monitoring/TwoValueLimitMonitor.h b/src/fsfw/monitoring/TwoValueLimitMonitor.h similarity index 98% rename from monitoring/TwoValueLimitMonitor.h rename to src/fsfw/monitoring/TwoValueLimitMonitor.h index e690cdae..cd34391c 100644 --- a/monitoring/TwoValueLimitMonitor.h +++ b/src/fsfw/monitoring/TwoValueLimitMonitor.h @@ -1,6 +1,7 @@ #ifndef FRAMEWORK_MONITORING_TWOVALUELIMITMONITOR_H_ #define FRAMEWORK_MONITORING_TWOVALUELIMITMONITOR_H_ +#include "monitoringConf.h" #include "LimitMonitor.h" template diff --git a/src/fsfw/monitoring/monitoringConf.h b/src/fsfw/monitoring/monitoringConf.h new file mode 100644 index 00000000..25cac8db --- /dev/null +++ b/src/fsfw/monitoring/monitoringConf.h @@ -0,0 +1,11 @@ +#ifndef FSFW_MONITORING_MONITORINGCONF_H_ +#define FSFW_MONITORING_MONITORINGCONF_H_ + +#include "fsfw/FSFW.h" + +#ifndef FSFW_ADD_MONITORING +#warning Monitoring files were included but compilation was \ + not enabled with FSFW_ADD_MONITORING +#endif + +#endif /* FSFW_MONITORING_MONITORINGCONF_H_ */ diff --git a/src/fsfw/objectmanager.h b/src/fsfw/objectmanager.h new file mode 100644 index 00000000..50a90c9f --- /dev/null +++ b/src/fsfw/objectmanager.h @@ -0,0 +1,8 @@ +#ifndef FSFW_SRC_FSFW_OBJECTMANAGER_H_ +#define FSFW_SRC_FSFW_OBJECTMANAGER_H_ + +#include "objectmanager/ObjectManager.h" +#include "objectmanager/SystemObject.h" +#include "objectmanager/frameworkObjects.h" + +#endif /* FSFW_SRC_FSFW_OBJECTMANAGER_H_ */ diff --git a/objectmanager/CMakeLists.txt b/src/fsfw/objectmanager/CMakeLists.txt similarity index 100% rename from objectmanager/CMakeLists.txt rename to src/fsfw/objectmanager/CMakeLists.txt diff --git a/objectmanager/ObjectManager.cpp b/src/fsfw/objectmanager/ObjectManager.cpp similarity index 72% rename from objectmanager/ObjectManager.cpp rename to src/fsfw/objectmanager/ObjectManager.cpp index 3c2be532..639688ab 100644 --- a/objectmanager/ObjectManager.cpp +++ b/src/fsfw/objectmanager/ObjectManager.cpp @@ -1,16 +1,28 @@ -#include "ObjectManager.h" -#include "../serviceinterface/ServiceInterface.h" +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/serviceinterface/ServiceInterface.h" #if FSFW_CPP_OSTREAM_ENABLED == 1 #include #endif #include -ObjectManager::ObjectManager( void (*setProducer)() ): - produceObjects(setProducer) { - //There's nothing special to do in the constructor. +ObjectManager* ObjectManager::objManagerInstance = nullptr; + +ObjectManager* ObjectManager::instance() { + if(objManagerInstance == nullptr) { + objManagerInstance = new ObjectManager(); + } + return objManagerInstance; } +void ObjectManager::setObjectFactoryFunction(produce_function_t objFactoryFunc, void *factoryArgs) { + this->objectFactoryFunction = objFactoryFunc; + this->factoryArgs = factoryArgs; +} + + +ObjectManager::ObjectManager() {} + ObjectManager::~ObjectManager() { for (auto const& iter : objectList) { @@ -28,10 +40,13 @@ ReturnValue_t ObjectManager::insert( object_id_t id, SystemObjectIF* object) { return this->RETURN_OK; } else { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "ObjectManager::insert: Object id " << std::hex - << static_cast(id) << std::dec - << " is already in use!" << std::endl; - sif::error << "Terminating program." << std::endl; + sif::error << "ObjectManager::insert: Object ID " << std::hex << + static_cast(id) << std::dec << " is already in use!" << std::endl; + sif::error << "Terminating program" << std::endl; +#else + sif::printError("ObjectManager::insert: Object ID 0x%08x is already in use!\n", + static_cast(id)); + sif::printError("Terminating program"); #endif //This is very severe and difficult to handle in other places. std::exit(INSERTION_FAILED); @@ -66,12 +81,8 @@ SystemObjectIF* ObjectManager::getSystemObject( object_id_t id ) { } } -ObjectManager::ObjectManager() : produceObjects(nullptr) { - -} - void ObjectManager::initialize() { - if(produceObjects == nullptr) { + if(objectFactoryFunction == nullptr) { #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "ObjectManager::initialize: Passed produceObjects " "functions is nullptr!" << std::endl; @@ -80,7 +91,7 @@ void ObjectManager::initialize() { #endif return; } - this->produceObjects(); + objectFactoryFunction(factoryArgs); ReturnValue_t result = RETURN_FAILED; uint32_t errorCount = 0; for (auto const& it : objectList) { @@ -108,9 +119,9 @@ void ObjectManager::initialize() { result = it.second->checkObjectConnections(); if ( result != RETURN_OK ) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "ObjectManager::ObjectManager: Object " << std::hex << - (int) it.first << " connection check failed with code 0x" - << result << std::dec << std::endl; + sif::error << "ObjectManager::ObjectManager: Object 0x" << std::hex << + (int) it.first << " connection check failed with code 0x" << result << + std::dec << std::endl; #endif errorCount++; } diff --git a/src/fsfw/objectmanager/ObjectManager.h b/src/fsfw/objectmanager/ObjectManager.h new file mode 100644 index 00000000..9f5f0c37 --- /dev/null +++ b/src/fsfw/objectmanager/ObjectManager.h @@ -0,0 +1,78 @@ +#ifndef FSFW_OBJECTMANAGER_OBJECTMANAGER_H_ +#define FSFW_OBJECTMANAGER_OBJECTMANAGER_H_ + +#include "ObjectManagerIF.h" +#include "SystemObjectIF.h" +#include + + +/** + * @brief This class implements a global object manager. + * @details This manager handles a list of available objects with system-wide + * relevance, such as device handlers, and TM/TC services. Objects can + * be inserted, removed and retrieved from the list. In addition, the + * class holds a so-called factory, that creates and inserts new + * objects if they are not already in the list. This feature automates + * most of the system initialization. + * As the system is static after initialization, no new objects are + * created or inserted into the list after startup. + * @ingroup system_objects + * @author Bastian Baetz + */ +class ObjectManager : public ObjectManagerIF { +public: + + using produce_function_t = void (*) (void* args); + + /** + * Returns the single instance of TaskFactory. + * The implementation of #instance is found in its subclasses. + * Thus, we choose link-time variability of the instance. + */ + static ObjectManager* instance(); + + void setObjectFactoryFunction(produce_function_t prodFunc, void* args); + + template T* get( object_id_t id ); + + /** + * @brief In the class's destructor, all objects in the list are deleted. + */ + virtual ~ObjectManager(); + ReturnValue_t insert(object_id_t id, SystemObjectIF* object) override; + ReturnValue_t remove(object_id_t id) override; + void initialize() override; + void printList() override; + +protected: + SystemObjectIF* getSystemObject(object_id_t id) override; + /** + * @brief This attribute is initialized with the factory function + * that creates new objects. + * @details The function is called if an object was requested with + * getSystemObject, but not found in objectList. + * @param The id of the object to be created. + * @return Returns a pointer to the newly created object or NULL. + */ + produce_function_t objectFactoryFunction = nullptr; + void* factoryArgs = nullptr; + +private: + ObjectManager(); + + /** + * @brief This is the map of all initialized objects in the manager. + * @details Objects in the List must inherit the SystemObjectIF. + */ + std::map objectList; + static ObjectManager* objManagerInstance; +}; + +// Documentation can be found in the class method declaration above +template +T* ObjectManager::get( object_id_t id ) { + SystemObjectIF* temp = this->getSystemObject(id); + return dynamic_cast(temp); +} + +#endif /* FSFW_OBJECTMANAGER_OBJECTMANAGER_H_ */ diff --git a/objectmanager/ObjectManagerIF.h b/src/fsfw/objectmanager/ObjectManagerIF.h similarity index 56% rename from objectmanager/ObjectManagerIF.h rename to src/fsfw/objectmanager/ObjectManagerIF.h index 8bebb609..561ff352 100644 --- a/objectmanager/ObjectManagerIF.h +++ b/src/fsfw/objectmanager/ObjectManagerIF.h @@ -4,15 +4,15 @@ #include "frameworkObjects.h" #include "SystemObjectIF.h" #include "../returnvalues/HasReturnvaluesIF.h" -#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../serviceinterface/ServiceInterface.h" /** * @brief This class provides an interface to the global object manager. - * @details This manager handles a list of available objects with system-wide - * relevance, such as device handlers, and TM/TC services. They can be - * inserted, removed and retrieved from the list. On getting the - * object, the call checks if the object implements the requested - * interface. + * @details + * This manager handles a list of available objects with system-wide relevance, such as device + * handlers, and TM/TC services. They can be inserted, removed and retrieved from the list. + * On getting the object, the call checks if the object implements the requested interface. + * This interface does not specify a getter function because templates can't be used in interfaces. * @author Bastian Baetz * @ingroup system_objects */ @@ -21,7 +21,8 @@ public: static constexpr uint8_t INTERFACE_ID = CLASS_ID::OBJECT_MANAGER_IF; static constexpr ReturnValue_t INSERTION_FAILED = MAKE_RETURN_CODE( 1 ); static constexpr ReturnValue_t NOT_FOUND = MAKE_RETURN_CODE( 2 ); - static constexpr ReturnValue_t CHILD_INIT_FAILED = MAKE_RETURN_CODE( 3 ); //!< Can be used if the initialization of a SystemObject failed. + //!< Can be used if the initialization of a SystemObject failed. + static constexpr ReturnValue_t CHILD_INIT_FAILED = MAKE_RETURN_CODE( 3 ); static constexpr ReturnValue_t INTERNAL_ERR_REPORTER_UNINIT = MAKE_RETURN_CODE( 4 ); protected: @@ -49,22 +50,11 @@ public: * @li RETURN_OK in case the object was successfully inserted */ virtual ReturnValue_t insert( object_id_t id, SystemObjectIF* object ) = 0; - /** - * @brief With the get call, interfaces of an object can be retrieved in - * a type-safe manner. - * @details With the template-based call, the object list is searched with the - * getSystemObject method and afterwards it is checked, if the object - * implements the requested interface (with a dynamic_cast). - * @param id The object id of the requested object. - * @return The method returns a pointer to an object implementing the - * requested interface, or NULL. - */ - template T* get( object_id_t id ); /** * @brief With this call, an object is removed from the list. * @param id The object id of the object to be removed. - * @return \li NOT_FOUND in case the object was not found - * \li RETURN_OK in case the object was successfully removed + * @return @li NOT_FOUND in case the object was not found + * @li RETURN_OK in case the object was successfully removed */ virtual ReturnValue_t remove( object_id_t id ) = 0; virtual void initialize() = 0; @@ -75,24 +65,4 @@ public: virtual void printList() = 0; }; - -/** - * @brief This is the forward declaration of the global objectManager instance. - */ -// SHOULDDO: maybe put this in the glob namespace to explicitely mark it global? -extern ObjectManagerIF *objectManager; - -/*Documentation can be found in the class method declaration above.*/ -template -T* ObjectManagerIF::get( object_id_t id ) { - if(objectManager == nullptr) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "ObjectManagerIF: Global object manager has not " - "been initialized yet!" << std::endl; -#endif - } - SystemObjectIF* temp = this->getSystemObject(id); - return dynamic_cast(temp); -} - #endif /* OBJECTMANAGERIF_H_ */ diff --git a/objectmanager/SystemObject.cpp b/src/fsfw/objectmanager/SystemObject.cpp similarity index 72% rename from objectmanager/SystemObject.cpp rename to src/fsfw/objectmanager/SystemObject.cpp index 9040002c..bad38975 100644 --- a/objectmanager/SystemObject.cpp +++ b/src/fsfw/objectmanager/SystemObject.cpp @@ -1,21 +1,17 @@ -#include "ObjectManager.h" -#include "SystemObject.h" -#include "../events/EventManagerIF.h" +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/objectmanager/SystemObject.h" +#include "fsfw/events/EventManagerIF.h" SystemObject::SystemObject(object_id_t setObjectId, bool doRegister) : objectId(setObjectId), registered(doRegister) { - if (registered) { - if(objectManager != nullptr) { - objectManager->insert(objectId, this); - } - } + if (registered) { + ObjectManager::instance()->insert(objectId, this); + } } SystemObject::~SystemObject() { if (registered) { - if(objectManager != nullptr) { - objectManager->remove(objectId); - } + ObjectManager::instance()->remove(objectId); } } diff --git a/objectmanager/SystemObject.h b/src/fsfw/objectmanager/SystemObject.h similarity index 93% rename from objectmanager/SystemObject.h rename to src/fsfw/objectmanager/SystemObject.h index d9c4236d..e7d2ae2b 100644 --- a/objectmanager/SystemObject.h +++ b/src/fsfw/objectmanager/SystemObject.h @@ -2,9 +2,9 @@ #define FSFW_OBJECTMANAGER_SYSTEMOBJECT_H_ #include "SystemObjectIF.h" -#include "../events/Event.h" -#include "../events/EventReportingProxyIF.h" -#include "../timemanager/Clock.h" +#include "fsfw/events/Event.h" +#include "fsfw/events/EventReportingProxyIF.h" +#include "fsfw/timemanager/Clock.h" /** * @brief This class automates insertion into the ObjectManager and diff --git a/objectmanager/SystemObjectIF.h b/src/fsfw/objectmanager/SystemObjectIF.h similarity index 100% rename from objectmanager/SystemObjectIF.h rename to src/fsfw/objectmanager/SystemObjectIF.h diff --git a/objectmanager/frameworkObjects.h b/src/fsfw/objectmanager/frameworkObjects.h similarity index 90% rename from objectmanager/frameworkObjects.h rename to src/fsfw/objectmanager/frameworkObjects.h index 2174f829..36010807 100644 --- a/objectmanager/frameworkObjects.h +++ b/src/fsfw/objectmanager/frameworkObjects.h @@ -1,8 +1,9 @@ #ifndef FSFW_OBJECTMANAGER_FRAMEWORKOBJECTS_H_ #define FSFW_OBJECTMANAGER_FRAMEWORKOBJECTS_H_ -#include +#include "SystemObjectIF.h" +// The objects will be instantiated in the ID order namespace objects { enum framework_objects: object_id_t { FSFW_OBJECTS_START = 0x53000000, @@ -16,6 +17,7 @@ enum framework_objects: object_id_t { PUS_SERVICE_17_TEST = 0x53000017, PUS_SERVICE_20_PARAMETERS = 0x53000020, PUS_SERVICE_200_MODE_MGMT = 0x53000200, + PUS_SERVICE_201_HEALTH = 0x53000201, //Generic IDs for IPC, modes, health, events HEALTH_TABLE = 0x53010000, diff --git a/osal/CMakeLists.txt b/src/fsfw/osal/CMakeLists.txt similarity index 80% rename from osal/CMakeLists.txt rename to src/fsfw/osal/CMakeLists.txt index 76b939b1..f3c5cfad 100644 --- a/osal/CMakeLists.txt +++ b/src/fsfw/osal/CMakeLists.txt @@ -1,11 +1,11 @@ # Check the OS_FSFW variable -if(${OS_FSFW} STREQUAL "freertos") - add_subdirectory(FreeRTOS) -elseif(${OS_FSFW} STREQUAL "rtems") +if(FSFW_OSAL MATCHES "freertos") + add_subdirectory(freertos) +elseif(FSFW_OSAL MATCHES "rtems") add_subdirectory(rtems) -elseif(${OS_FSFW} STREQUAL "linux") +elseif(FSFW_OSAL MATCHES "linux") add_subdirectory(linux) -elseif(${OS_FSFW} STREQUAL "host") +elseif(FSFW_OSAL MATCHES "host") add_subdirectory(host) if (WIN32) add_subdirectory(windows) diff --git a/osal/Endiness.h b/src/fsfw/osal/Endiness.h similarity index 100% rename from osal/Endiness.h rename to src/fsfw/osal/Endiness.h diff --git a/src/fsfw/osal/InternalErrorCodes.h b/src/fsfw/osal/InternalErrorCodes.h new file mode 100644 index 00000000..e7522875 --- /dev/null +++ b/src/fsfw/osal/InternalErrorCodes.h @@ -0,0 +1,39 @@ +#ifndef INTERNALERRORCODES_H_ +#define INTERNALERRORCODES_H_ + +#include "fsfw/returnvalues/HasReturnvaluesIF.h" + +class InternalErrorCodes { +public: + static const uint8_t INTERFACE_ID = CLASS_ID::INTERNAL_ERROR_CODES; + + static const ReturnValue_t NO_CONFIGURATION_TABLE = MAKE_RETURN_CODE(0x01 ); + static const ReturnValue_t NO_CPU_TABLE = MAKE_RETURN_CODE(0x02 ); + static const ReturnValue_t INVALID_WORKSPACE_ADDRESS = MAKE_RETURN_CODE(0x03 ); + static const ReturnValue_t TOO_LITTLE_WORKSPACE = MAKE_RETURN_CODE(0x04 ); + static const ReturnValue_t WORKSPACE_ALLOCATION = MAKE_RETURN_CODE(0x05 ); + static const ReturnValue_t INTERRUPT_STACK_TOO_SMALL = MAKE_RETURN_CODE(0x06 ); + static const ReturnValue_t THREAD_EXITTED = MAKE_RETURN_CODE(0x07 ); + static const ReturnValue_t INCONSISTENT_MP_INFORMATION = MAKE_RETURN_CODE(0x08 ); + static const ReturnValue_t INVALID_NODE = MAKE_RETURN_CODE(0x09 ); + static const ReturnValue_t NO_MPCI = MAKE_RETURN_CODE(0x0a ); + static const ReturnValue_t BAD_PACKET = MAKE_RETURN_CODE(0x0b ); + static const ReturnValue_t OUT_OF_PACKETS = MAKE_RETURN_CODE(0x0c ); + static const ReturnValue_t OUT_OF_GLOBAL_OBJECTS = MAKE_RETURN_CODE(0x0d ); + static const ReturnValue_t OUT_OF_PROXIES = MAKE_RETURN_CODE(0x0e ); + static const ReturnValue_t INVALID_GLOBAL_ID = MAKE_RETURN_CODE(0x0f ); + static const ReturnValue_t BAD_STACK_HOOK = MAKE_RETURN_CODE(0x10 ); + static const ReturnValue_t BAD_ATTRIBUTES = MAKE_RETURN_CODE(0x11 ); + static const ReturnValue_t IMPLEMENTATION_KEY_CREATE_INCONSISTENCY = MAKE_RETURN_CODE(0x12 ); + static const ReturnValue_t IMPLEMENTATION_BLOCKING_OPERATION_CANCEL = MAKE_RETURN_CODE(0x13 ); + static const ReturnValue_t MUTEX_OBTAIN_FROM_BAD_STATE = MAKE_RETURN_CODE(0x14 ); + static const ReturnValue_t UNLIMITED_AND_MAXIMUM_IS_0 = MAKE_RETURN_CODE(0x15 ); + + virtual ~InternalErrorCodes(); + + static ReturnValue_t translate(uint8_t code); +private: + InternalErrorCodes(); +}; + +#endif /* INTERNALERRORCODES_H_ */ diff --git a/osal/common/CMakeLists.txt b/src/fsfw/osal/common/CMakeLists.txt similarity index 90% rename from osal/common/CMakeLists.txt rename to src/fsfw/osal/common/CMakeLists.txt index af76484d..b7c8c033 100644 --- a/osal/common/CMakeLists.txt +++ b/src/fsfw/osal/common/CMakeLists.txt @@ -5,6 +5,7 @@ if(DEFINED WIN32 OR DEFINED UNIX) UdpTcPollingTask.cpp UdpTmTcBridge.cpp TcpTmTcServer.cpp + TcpTmTcBridge.cpp ) endif() diff --git a/osal/common/TcpIpBase.cpp b/src/fsfw/osal/common/TcpIpBase.cpp similarity index 83% rename from osal/common/TcpIpBase.cpp rename to src/fsfw/osal/common/TcpIpBase.cpp index 27384ecc..b6b64e13 100644 --- a/osal/common/TcpIpBase.cpp +++ b/src/fsfw/osal/common/TcpIpBase.cpp @@ -1,10 +1,9 @@ -#include "TcpIpBase.h" - -#ifdef __unix__ +#include "fsfw/osal/common/TcpIpBase.h" +#include "fsfw/platform.h" +#ifdef PLATFORM_UNIX #include #include - #endif TcpIpBase::TcpIpBase() { @@ -37,17 +36,17 @@ TcpIpBase::~TcpIpBase() { } int TcpIpBase::closeSocket(socket_t socket) { -#ifdef _WIN32 +#ifdef PLATFORM_WIN return closesocket(socket); -#elif defined(__unix__) +#elif defined(PLATFORM_UNIX) return close(socket); #endif } int TcpIpBase::getLastSocketError() { -#ifdef _WIN32 +#ifdef PLATFORM_WIN return WSAGetLastError(); -#elif defined(__unix__) +#elif defined(PLATFORM_UNIX) return errno; #endif } diff --git a/osal/common/TcpIpBase.h b/src/fsfw/osal/common/TcpIpBase.h similarity index 82% rename from osal/common/TcpIpBase.h rename to src/fsfw/osal/common/TcpIpBase.h index 652d791a..fe6a763c 100644 --- a/osal/common/TcpIpBase.h +++ b/src/fsfw/osal/common/TcpIpBase.h @@ -1,28 +1,25 @@ #ifndef FSFW_OSAL_COMMON_TCPIPIF_H_ #define FSFW_OSAL_COMMON_TCPIPIF_H_ -#include - -#ifdef _WIN32 +#include "../../returnvalues/HasReturnvaluesIF.h" +#include "../../platform.h" +#ifdef PLATFORM_WIN #include - -#elif defined(__unix__) - +#elif defined(PLATFORM_UNIX) #include - #endif class TcpIpBase { protected: -#ifdef _WIN32 +#ifdef PLATFORM_WIN static constexpr int SHUT_RECV = SD_RECEIVE; static constexpr int SHUT_SEND = SD_SEND; static constexpr int SHUT_BOTH = SD_BOTH; using socket_t = SOCKET; -#elif defined(__unix__) +#elif defined(PLATFORM_UNIX) using socket_t = int; static constexpr int INVALID_SOCKET = -1; diff --git a/src/fsfw/osal/common/TcpTmTcBridge.cpp b/src/fsfw/osal/common/TcpTmTcBridge.cpp new file mode 100644 index 00000000..3cd03c36 --- /dev/null +++ b/src/fsfw/osal/common/TcpTmTcBridge.cpp @@ -0,0 +1,75 @@ +#include "fsfw/platform.h" +#include "fsfw/osal/common/TcpTmTcBridge.h" + +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/ipc/MutexGuard.h" +#include "fsfw/osal/common/TcpTmTcBridge.h" + +#ifdef PLATFORM_WIN + +#include + +#elif defined PLATFORM_UNIX + +#include +#include + +#endif + +TcpTmTcBridge::TcpTmTcBridge(object_id_t objectId, object_id_t tcDestination, + object_id_t tmStoreId, object_id_t tcStoreId): + TmTcBridge(objectId, tcDestination, tmStoreId, tcStoreId) { + mutex = MutexFactory::instance()->createMutex(); + // Connection is always up, TM is requested by connecting to server and receiving packets + registerCommConnect(); +} + +ReturnValue_t TcpTmTcBridge::initialize() { + ReturnValue_t result = TmTcBridge::initialize(); + if(result != HasReturnvaluesIF::RETURN_OK) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "TcpTmTcBridge::initialize: TmTcBridge initialization failed!" + << std::endl; +#else + sif::printError("TcpTmTcBridge::initialize: TmTcBridge initialization failed!\n"); +#endif + return result; + } + + return HasReturnvaluesIF::RETURN_OK; +} + +TcpTmTcBridge::~TcpTmTcBridge() { + if(mutex != nullptr) { + MutexFactory::instance()->deleteMutex(mutex); + } +} + +ReturnValue_t TcpTmTcBridge::handleTm() { + // Simply store the telemetry in the FIFO, the server will use it to access the TM + MutexGuard guard(mutex, timeoutType, mutexTimeoutMs); + TmTcMessage message; + ReturnValue_t status = HasReturnvaluesIF::RETURN_OK; + for (ReturnValue_t result = tmTcReceptionQueue->receiveMessage(&message); + result == HasReturnvaluesIF::RETURN_OK; + result = tmTcReceptionQueue->receiveMessage(&message)) + { + status = storeDownlinkData(&message); + if(status != HasReturnvaluesIF::RETURN_OK) { + break; + } + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t TcpTmTcBridge::sendTm(const uint8_t *data, size_t dataLen) { + // Not used. The Server uses the FIFO to access and send the telemetry. + return HasReturnvaluesIF::RETURN_OK; +} + + +void TcpTmTcBridge::setMutexProperties(MutexIF::TimeoutType timeoutType, + dur_millis_t timeoutMs) { + this->timeoutType = timeoutType; + this->mutexTimeoutMs = timeoutMs; +} diff --git a/src/fsfw/osal/common/TcpTmTcBridge.h b/src/fsfw/osal/common/TcpTmTcBridge.h new file mode 100644 index 00000000..dc46f1f0 --- /dev/null +++ b/src/fsfw/osal/common/TcpTmTcBridge.h @@ -0,0 +1,69 @@ +#ifndef FSFW_OSAL_COMMON_TCPTMTCBRIDGE_H_ +#define FSFW_OSAL_COMMON_TCPTMTCBRIDGE_H_ + +#include "TcpIpBase.h" +#include "fsfw/tmtcservices/TmTcBridge.h" + +#ifdef _WIN32 + +#include + +#elif defined(__unix__) + +#include + +#endif + +#include + +/** + * @brief This class should be used with the TcpTmTcServer to implement a TCP server + * for receiving and sending PUS telemetry and telecommands (TMTC) + * @details + * This bridge tasks takes care of filling a FIFO which generated telemetry. The TcpTmTcServer + * will take care of sending the telemetry stored in the FIFO if a client connects to the + * server. This bridge will also be the default destination for telecommands, but the telecommands + * will be relayed to a specified tcDestination directly. + */ +class TcpTmTcBridge: + public TmTcBridge { + friend class TcpTmTcServer; +public: + + /** + * Constructor + * @param objectId Object ID of the TcpTmTcBridge. + * @param tcDestination Destination for received TC packets. Any received telecommands will + * be sent there directly. The destination object needs to implement + * AcceptsTelecommandsIF. + * @param tmStoreId TM store object ID. It is recommended to the default object ID + * @param tcStoreId TC store object ID. It is recommended to the default object ID + */ + TcpTmTcBridge(object_id_t objectId, object_id_t tcDestination, + object_id_t tmStoreId = objects::TM_STORE, + object_id_t tcStoreId = objects::TC_STORE); + virtual~ TcpTmTcBridge(); + + /** + * Set properties of internal mutex. + */ + void setMutexProperties(MutexIF::TimeoutType timeoutType, dur_millis_t timeoutMs); + + ReturnValue_t initialize() override; + + +protected: + ReturnValue_t handleTm() override; + virtual ReturnValue_t sendTm(const uint8_t * data, size_t dataLen) override; + +private: + + //! Access to the FIFO needs to be mutex protected because it is used by the bridge and + //! the server. + MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING; + dur_millis_t mutexTimeoutMs = 20; + MutexIF* mutex; +}; + +#endif /* FSFW_OSAL_COMMON_TCPTMTCBRIDGE_H_ */ + diff --git a/src/fsfw/osal/common/TcpTmTcServer.cpp b/src/fsfw/osal/common/TcpTmTcServer.cpp new file mode 100644 index 00000000..7e6853fc --- /dev/null +++ b/src/fsfw/osal/common/TcpTmTcServer.cpp @@ -0,0 +1,417 @@ +#include "fsfw/platform.h" +#include "fsfw/FSFW.h" + +#include "TcpTmTcServer.h" +#include "TcpTmTcBridge.h" +#include "tcpipHelpers.h" + +#include "fsfw/tmtcservices/SpacePacketParser.h" +#include "fsfw/tasks/TaskFactory.h" +#include "fsfw/globalfunctions/arrayprinter.h" +#include "fsfw/container/SharedRingBuffer.h" +#include "fsfw/ipc/MessageQueueSenderIF.h" +#include "fsfw/ipc/MutexGuard.h" +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/tmtcservices/TmTcMessage.h" + +#ifdef PLATFORM_WIN +#include +#include +#elif defined(PLATFORM_UNIX) +#include +#endif + +const std::string TcpTmTcServer::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT; + +TcpTmTcServer::TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge, + size_t receptionBufferSize, size_t ringBufferSize, std::string customTcpServerPort, + ReceptionModes receptionMode): + SystemObject(objectId), tmtcBridgeId(tmtcTcpBridge), receptionMode(receptionMode), + tcpConfig(customTcpServerPort), receptionBuffer(receptionBufferSize), + ringBuffer(ringBufferSize, true) { +} + +ReturnValue_t TcpTmTcServer::initialize() { + using namespace tcpip; + + ReturnValue_t result = TcpIpBase::initialize(); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + switch(receptionMode) { + case(ReceptionModes::SPACE_PACKETS): { + spacePacketParser = new SpacePacketParser(validPacketIds); + if(spacePacketParser == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } +#if defined PLATFORM_UNIX + tcpConfig.tcpFlags |= MSG_DONTWAIT; +#endif + } + } + tcStore = ObjectManager::instance()->get(objects::TC_STORE); + if (tcStore == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "TcpTmTcServer::initialize: TC store uninitialized!" << std::endl; +#else + sif::printError("TcpTmTcServer::initialize: TC store uninitialized!\n"); +#endif + return ObjectManagerIF::CHILD_INIT_FAILED; + } + + tmtcBridge = ObjectManager::instance()->get(tmtcBridgeId); + + int retval = 0; + struct addrinfo *addrResult = nullptr; + struct addrinfo hints = {}; + + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + hints.ai_flags = AI_PASSIVE; + + // Listen to all addresses (0.0.0.0) by using AI_PASSIVE in the hint flags + retval = getaddrinfo(nullptr, tcpConfig.tcpPort.c_str(), &hints, &addrResult); + if (retval != 0) { + handleError(Protocol::TCP, ErrorSources::GETADDRINFO_CALL); + return HasReturnvaluesIF::RETURN_FAILED; + } + + // Open TCP (stream) socket + listenerTcpSocket = socket(addrResult->ai_family, addrResult->ai_socktype, + addrResult->ai_protocol); + if(listenerTcpSocket == INVALID_SOCKET) { + freeaddrinfo(addrResult); + handleError(Protocol::TCP, ErrorSources::SOCKET_CALL); + return HasReturnvaluesIF::RETURN_FAILED; + } + + // Bind to the address found by getaddrinfo + retval = bind(listenerTcpSocket, addrResult->ai_addr, static_cast(addrResult->ai_addrlen)); + if(retval == SOCKET_ERROR) { + freeaddrinfo(addrResult); + handleError(Protocol::TCP, ErrorSources::BIND_CALL); + return HasReturnvaluesIF::RETURN_FAILED; + } + + freeaddrinfo(addrResult); + return HasReturnvaluesIF::RETURN_OK; +} + + +TcpTmTcServer::~TcpTmTcServer() { + closeSocket(listenerTcpSocket); +} + +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; + int retval = 0; + + // Listen for connection requests permanently for lifetime of program + while(true) { + retval = listen(listenerTcpSocket, tcpConfig.tcpBacklog); + if(retval == SOCKET_ERROR) { + handleError(Protocol::TCP, ErrorSources::LISTEN_CALL, 500); + continue; + } + + //connSocket = accept(listenerTcpSocket, &clientSockAddr, &connectorSockAddrLen); + connSocket = accept(listenerTcpSocket, nullptr, nullptr); + + if(connSocket == INVALID_SOCKET) { + handleError(Protocol::TCP, ErrorSources::ACCEPT_CALL, 500); + closeSocket(connSocket); + continue; + }; + + handleServerOperation(connSocket); + + // Done, shut down connection and go back to listening for client requests + retval = shutdown(connSocket, SHUT_BOTH); + if(retval != 0) { + handleError(Protocol::TCP, ErrorSources::SHUTDOWN_CALL); + } + closeSocket(connSocket); + connSocket = 0; + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t TcpTmTcServer::initializeAfterTaskCreation() { + if(tmtcBridge == nullptr) { + return ObjectManagerIF::CHILD_INIT_FAILED; + } + /* Initialize the destination after task creation. This ensures + that the destination has already been set in the TMTC bridge. */ + targetTcDestination = tmtcBridge->getRequestQueue(); + tcStore = tmtcBridge->tcStore; + tmStore = tmtcBridge->tmStore; + return HasReturnvaluesIF::RETURN_OK; +} + +void TcpTmTcServer::handleServerOperation(socket_t& connSocket) { +#if defined PLATFORM_WIN + setSocketNonBlocking(connSocket); +#endif + + while (true) { + int retval = recv( + connSocket, + reinterpret_cast(receptionBuffer.data()), + receptionBuffer.capacity(), + tcpConfig.tcpFlags + ); + if(retval == 0) { + size_t availableReadData = ringBuffer.getAvailableReadData(); + if(availableReadData > lastRingBufferSize) { + handleTcRingBufferData(availableReadData); + } + return; + } + else if(retval > 0) { + // The ring buffer was configured for overwrite, so the returnvalue does not need to + // be checked for now + ringBuffer.writeData(receptionBuffer.data(), retval); + } + else if(retval < 0) { + int errorValue = getLastSocketError(); +#if defined PLATFORM_UNIX + int wouldBlockValue = EAGAIN; +#elif defined PLATFORM_WIN + int wouldBlockValue = WSAEWOULDBLOCK; +#endif + if(errorValue == wouldBlockValue) { + // No data available. Check whether any packets have been read, then send back + // telemetry if available + bool tcAvailable = false; + bool tmSent = false; + size_t availableReadData = ringBuffer.getAvailableReadData(); + if(availableReadData > lastRingBufferSize) { + tcAvailable = true; + handleTcRingBufferData(availableReadData); + } + ReturnValue_t result = handleTmSending(connSocket, tmSent); + if(result == CONN_BROKEN) { + return; + } + if(not tcAvailable and not tmSent) { + TaskFactory::delayTask(tcpConfig.tcpLoopDelay); + } + } + else { + tcpip::handleError(tcpip::Protocol::TCP, tcpip::ErrorSources::RECV_CALL, 300); + } + } + } +} + +ReturnValue_t TcpTmTcServer::handleTcReception(uint8_t* spacePacket, size_t packetSize) { + if(wiretappingEnabled) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "Received TC:" << std::endl; +#else + sif::printInfo("Received TC:\n"); +#endif + arrayprinter::print(spacePacket, packetSize); + } + + if(spacePacket == nullptr or packetSize == 0) { + return HasReturnvaluesIF::RETURN_FAILED; + } + store_address_t storeId; + ReturnValue_t result = tcStore->addData(&storeId, spacePacket, packetSize); + if (result != HasReturnvaluesIF::RETURN_OK) { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "TcpTmTcServer::handleServerOperation: Data storage with packet size" << + packetSize << " failed" << std::endl; +#else + sif::printWarning("TcpTmTcServer::handleServerOperation: Data storage with packet size %d " + "failed\n", packetSize); +#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ +#endif /* FSFW_VERBOSE_LEVEL >= 1 */ + return result; + } + + TmTcMessage message(storeId); + + result = MessageQueueSenderIF::sendMessage(targetTcDestination, &message); + if (result != HasReturnvaluesIF::RETURN_OK) { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "TcpTmTcServer::handleServerOperation: " + " Sending message to queue failed" << std::endl; +#else + sif::printWarning("TcpTmTcServer::handleServerOperation: " + " Sending message to queue failed\n"); +#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ +#endif /* FSFW_VERBOSE_LEVEL >= 1 */ + tcStore->deleteData(storeId); + } + return result; +} + +std::string TcpTmTcServer::getTcpPort() const { + return tcpConfig.tcpPort; +} + +void TcpTmTcServer::setSpacePacketParsingOptions(std::vector validPacketIds) { + this->validPacketIds = 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); + store_address_t storeId; + while((not tmtcBridge->tmFifo->empty()) and + (tmtcBridge->packetSentCounter < tmtcBridge->sentPacketsPerCycle)) { + // Send can fail, so only peek from the FIFO + tmtcBridge->tmFifo->peek(&storeId); + + // Using the store accessor will take care of deleting TM from the store automatically + ConstStorageAccessor storeAccessor(storeId); + ReturnValue_t result = tmStore->getData(storeId, storeAccessor); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if(wiretappingEnabled) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "Sending TM:" << std::endl; +#else + sif::printInfo("Sending TM:\n"); +#endif + arrayprinter::print(storeAccessor.data(), storeAccessor.size()); + } + int 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(); + tmSent = true; + + } + else if(retval <= 0) { + // Assume that the client has closed the connection here for now + handleSocketError(storeAccessor); + return CONN_BROKEN; + } + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t TcpTmTcServer::handleTcRingBufferData(size_t availableReadData) { + ReturnValue_t status = HasReturnvaluesIF::RETURN_OK; + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + size_t readAmount = availableReadData; + lastRingBufferSize = availableReadData; + if(readAmount >= ringBuffer.getMaxSize()) { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + // Possible configuration error, too much data or/and data coming in too fast, + // requiring larger buffers + sif::warning << "TcpTmTcServer::handleServerOperation: Ring buffer reached " << + "fill count" << std::endl; +#else + sif::printWarning("TcpTmTcServer::handleServerOperation: Ring buffer reached " + "fill count"); +#endif +#endif + } + if(readAmount >= receptionBuffer.size()) { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + // Possible configuration error, too much data or/and data coming in too fast, + // requiring larger buffers + sif::warning << "TcpTmTcServer::handleServerOperation: " + "Reception buffer too small " << std::endl; +#else + sif::printWarning("TcpTmTcServer::handleServerOperation: Reception buffer too small\n"); +#endif +#endif + readAmount = receptionBuffer.size(); + } + ringBuffer.readData(receptionBuffer.data(), readAmount, true); + const uint8_t* bufPtr = receptionBuffer.data(); + const uint8_t** bufPtrPtr = &bufPtr; + size_t startIdx = 0; + size_t foundSize = 0; + size_t readLen = 0; + while(readLen < readAmount) { + result = spacePacketParser->parseSpacePackets(bufPtrPtr, readAmount, + startIdx, foundSize, readLen); + switch(result) { + case(SpacePacketParser::NO_PACKET_FOUND): + case(SpacePacketParser::SPLIT_PACKET): { + break; + } + case(HasReturnvaluesIF::RETURN_OK): { + result = handleTcReception(receptionBuffer.data() + startIdx, foundSize); + if(result != HasReturnvaluesIF::RETURN_OK) { + status = result; + } + } + } + ringBuffer.deleteData(foundSize); + lastRingBufferSize = ringBuffer.getAvailableReadData(); + std::memset(receptionBuffer.data() + startIdx, 0, foundSize); + } + return status; +} + +void TcpTmTcServer::enableWiretapping(bool enable) { + this->wiretappingEnabled = enable; +} + +void TcpTmTcServer::handleSocketError(ConstStorageAccessor &accessor) { + // Don't delete data + accessor.release(); + auto socketError = getLastSocketError(); + switch(socketError) { +#if defined PLATFORM_WIN + case(WSAECONNRESET): { + // See https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-send + // Remote client might have shut down connection + return; + } +#else + case(EPIPE): { + // See https://man7.org/linux/man-pages/man2/send.2.html + // Remote client might have shut down connection + return; + } +#endif + default: { + tcpip::handleError(tcpip::Protocol::TCP, tcpip::ErrorSources::SEND_CALL); + } + } +} + +#if defined PLATFORM_WIN +void TcpTmTcServer::setSocketNonBlocking(socket_t &connSocket) { + u_long iMode = 1; + int iResult = ioctlsocket(connSocket, FIONBIO, &iMode); + if(iResult != NO_ERROR) { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "TcpTmTcServer::handleServerOperation: Setting socket" + " non-blocking failed with error " << iResult; +#else + sif::printWarning("TcpTmTcServer::handleServerOperation: Setting socket" + " non-blocking failed with error %d\n", iResult); +#endif +#endif + } +} +#endif diff --git a/src/fsfw/osal/common/TcpTmTcServer.h b/src/fsfw/osal/common/TcpTmTcServer.h new file mode 100644 index 00000000..64726a30 --- /dev/null +++ b/src/fsfw/osal/common/TcpTmTcServer.h @@ -0,0 +1,144 @@ +#ifndef FSFW_OSAL_COMMON_TCP_TMTC_SERVER_H_ +#define FSFW_OSAL_COMMON_TCP_TMTC_SERVER_H_ + +#include "TcpIpBase.h" + +#include "fsfw/platform.h" +#include "fsfw/osal/common/tcpipHelpers.h" +#include "fsfw/ipc/messageQueueDefinitions.h" +#include "fsfw/container/SimpleRingBuffer.h" +#include "fsfw/ipc/MessageQueueIF.h" +#include "fsfw/objectmanager/frameworkObjects.h" +#include "fsfw/objectmanager/SystemObject.h" +#include "fsfw/storagemanager/StorageManagerIF.h" +#include "fsfw/tasks/ExecutableObjectIF.h" + +#ifdef PLATFORM_UNIX +#include +#endif + +#include +#include + +class TcpTmTcBridge; +class SpacePacketParser; + +/** + * @brief TCP server implementation + * @details + * This server will run for the whole program lifetime and will take care of serving client + * requests on a specified TCP server port. This server was written in a generic way and + * can be used on Unix and on Windows systems. + * + * If a connection is accepted, the server will read all telecommands sent by a client and then + * send all telemetry currently found in the TMTC bridge FIFO. + * + * Reading telemetry without sending telecommands is possible by connecting, shutting down the + * send operation immediately and then reading the telemetry. It is therefore recommended to + * connect to the server regularly, even if no telecommands need to be sent. + * + * The server will listen to a specific port on all addresses (0.0.0.0). + */ +class TcpTmTcServer: + public SystemObject, + public TcpIpBase, + public ExecutableObjectIF { +public: + enum class ReceptionModes { + SPACE_PACKETS + }; + + struct TcpConfig { + public: + TcpConfig(std::string tcpPort): tcpPort(tcpPort) {} + + /** + * Passed to the recv call + */ + int tcpFlags = 0; + int tcpBacklog = 3; + + /** + * If no telecommands packets are being received and no telemetry is being sent, + * the TCP server will delay periodically by this amount to decrease the CPU load + */ + uint32_t tcpLoopDelay = DEFAULT_LOOP_DELAY_MS ; + /** + * Passed to the send call + */ + int tcpTmFlags = 0; + + const std::string tcpPort; + }; + + static const std::string DEFAULT_SERVER_PORT; + + static constexpr size_t ETHERNET_MTU_SIZE = 1500; + static constexpr size_t RING_BUFFER_SIZE = ETHERNET_MTU_SIZE * 3; + static constexpr uint32_t DEFAULT_LOOP_DELAY_MS = 200; + + /** + * TCP Server Constructor + * @param objectId Object ID of the TCP Server + * @param tmtcTcpBridge Object ID of the TCP TMTC Bridge object + * @param receptionBufferSize This will be the size of the reception buffer. Default buffer + * size will be the Ethernet MTU size + * @param customTcpServerPort The user can specify another port than the default (7301) here. + */ + TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge, + size_t receptionBufferSize = RING_BUFFER_SIZE, + size_t ringBufferSize = RING_BUFFER_SIZE, + std::string customTcpServerPort = DEFAULT_SERVER_PORT, + ReceptionModes receptionMode = ReceptionModes::SPACE_PACKETS); + virtual~ TcpTmTcServer(); + + void enableWiretapping(bool enable); + + /** + * Get a handle to the TCP configuration struct, which can be used to configure TCP + * properties + * @return + */ + TcpConfig& getTcpConfigStruct(); + void setSpacePacketParsingOptions(std::vector validPacketIds); + + ReturnValue_t initialize() override; + ReturnValue_t performOperation(uint8_t opCode) override; + ReturnValue_t initializeAfterTaskCreation() override; + + std::string getTcpPort() const; + +protected: + StorageManagerIF* tcStore = nullptr; + StorageManagerIF* tmStore = nullptr; +private: + static constexpr ReturnValue_t CONN_BROKEN = HasReturnvaluesIF::makeReturnCode(1, 0); + //! TMTC bridge is cached. + object_id_t tmtcBridgeId = objects::NO_OBJECT; + TcpTmTcBridge* tmtcBridge = nullptr; + bool wiretappingEnabled = false; + + ReceptionModes receptionMode; + TcpConfig tcpConfig; + struct sockaddr tcpAddress; + socket_t listenerTcpSocket = 0; + + MessageQueueId_t targetTcDestination = MessageQueueIF::NO_QUEUE; + + std::vector receptionBuffer; + SimpleRingBuffer ringBuffer; + std::vector validPacketIds; + SpacePacketParser* spacePacketParser = nullptr; + uint8_t lastRingBufferSize = 0; + + virtual void handleServerOperation(socket_t& connSocket); + ReturnValue_t handleTcReception(uint8_t* spacePacket, size_t packetSize); + ReturnValue_t handleTmSending(socket_t connSocket, bool& tmSent); + ReturnValue_t handleTcRingBufferData(size_t availableReadData); + void handleSocketError(ConstStorageAccessor& accessor); +#if defined PLATFORM_WIN + void setSocketNonBlocking(socket_t& connSocket); +#endif +}; + +#endif /* FSFW_OSAL_COMMON_TCP_TMTC_SERVER_H_ */ diff --git a/osal/common/UdpTcPollingTask.cpp b/src/fsfw/osal/common/UdpTcPollingTask.cpp similarity index 90% rename from osal/common/UdpTcPollingTask.cpp rename to src/fsfw/osal/common/UdpTcPollingTask.cpp index 47f67b29..35e086ee 100644 --- a/osal/common/UdpTcPollingTask.cpp +++ b/src/fsfw/osal/common/UdpTcPollingTask.cpp @@ -1,26 +1,25 @@ -#include "UdpTcPollingTask.h" -#include "tcpipHelpers.h" -#include "../../globalfunctions/arrayprinter.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "fsfw/osal/common/UdpTcPollingTask.h" +#include "fsfw/osal/common/tcpipHelpers.h" -#ifdef _WIN32 +#include "fsfw/platform.h" +#include "fsfw/globalfunctions/arrayprinter.h" +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/objectmanager/ObjectManager.h" +#ifdef PLATFORM_WIN #include - -#else - +#elif defined(PLATFORM_UNIX) #include #include - #endif //! Debugging preprocessor define. #define FSFW_UDP_RECV_WIRETAPPING_ENABLED 0 UdpTcPollingTask::UdpTcPollingTask(object_id_t objectId, - object_id_t tmtcUnixUdpBridge, size_t maxRecvSize, + object_id_t tmtcUdpBridge, size_t maxRecvSize, double timeoutSeconds): SystemObject(objectId), - tmtcBridgeId(tmtcUnixUdpBridge) { + tmtcBridgeId(tmtcUdpBridge) { if(frameSize > 0) { this->frameSize = frameSize; } @@ -119,7 +118,7 @@ ReturnValue_t UdpTcPollingTask::handleSuccessfullTcRead(size_t bytesRead) { } ReturnValue_t UdpTcPollingTask::initialize() { - tcStore = objectManager->get(objects::TC_STORE); + tcStore = ObjectManager::instance()->get(objects::TC_STORE); if (tcStore == nullptr) { #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "UdpTcPollingTask::initialize: TC store uninitialized!" << std::endl; @@ -127,7 +126,7 @@ ReturnValue_t UdpTcPollingTask::initialize() { return ObjectManagerIF::CHILD_INIT_FAILED; } - tmtcBridge = objectManager->get(tmtcBridgeId); + tmtcBridge = ObjectManager::instance()->get(tmtcBridgeId); if(tmtcBridge == nullptr) { #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "UdpTcPollingTask::initialize: Invalid TMTC bridge object!" << @@ -155,7 +154,7 @@ ReturnValue_t UdpTcPollingTask::initializeAfterTaskCreation() { } void UdpTcPollingTask::setTimeout(double timeoutSeconds) { -#ifdef _WIN32 +#ifdef PLATFORM_WIN DWORD timeoutMs = timeoutSeconds * 1000.0; int result = setsockopt(serverSocket, SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast(&timeoutMs), sizeof(DWORD)); @@ -165,7 +164,7 @@ void UdpTcPollingTask::setTimeout(double timeoutSeconds) { "receive timeout failed with " << strerror(errno) << std::endl; #endif } -#elif defined(__unix__) +#elif defined(PLATFORM_UNIX) timeval tval; tval = timevalOperations::toTimeval(timeoutSeconds); int result = setsockopt(serverSocket, SOL_SOCKET, SO_RCVTIMEO, diff --git a/osal/common/UdpTcPollingTask.h b/src/fsfw/osal/common/UdpTcPollingTask.h similarity index 75% rename from osal/common/UdpTcPollingTask.h rename to src/fsfw/osal/common/UdpTcPollingTask.h index 052eced5..9a680fb8 100644 --- a/osal/common/UdpTcPollingTask.h +++ b/src/fsfw/osal/common/UdpTcPollingTask.h @@ -1,5 +1,5 @@ -#ifndef FSFW_OSAL_WINDOWS_TCSOCKETPOLLINGTASK_H_ -#define FSFW_OSAL_WINDOWS_TCSOCKETPOLLINGTASK_H_ +#ifndef FSFW_OSAL_COMMON_UDPTCPOLLINGTASK_H_ +#define FSFW_OSAL_COMMON_UDPTCPOLLINGTASK_H_ #include "UdpTmTcBridge.h" #include "../../objectmanager/SystemObject.h" @@ -9,8 +9,11 @@ #include /** - * @brief This class should be used with the UdpTmTcBridge to implement a UDP server + * @brief This class can be used with the UdpTmTcBridge to implement a UDP server * for receiving and sending PUS TMTC. + * @details + * This task is exclusively used to poll telecommands from a given socket and transfer them + * to the FSFW software bus. It used the blocking recvfrom call to do this. */ class UdpTcPollingTask: public TcpIpBase, @@ -22,7 +25,7 @@ public: //! 0.5 default milliseconds timeout for now. static constexpr timeval DEFAULT_TIMEOUT = {0, 500}; - UdpTcPollingTask(object_id_t objectId, object_id_t tmtcUnixUdpBridge, + UdpTcPollingTask(object_id_t objectId, object_id_t tmtcUdpBridge, size_t maxRecvSize = 0, double timeoutSeconds = -1); virtual~ UdpTcPollingTask(); @@ -45,8 +48,6 @@ private: object_id_t tmtcBridgeId = objects::NO_OBJECT; UdpTmTcBridge* tmtcBridge = nullptr; MessageQueueId_t targetTcDestination = MessageQueueIF::NO_QUEUE; - - //! See: https://docs.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-recvfrom int receptionFlags = 0; std::vector receptionBuffer; @@ -57,4 +58,4 @@ private: ReturnValue_t handleSuccessfullTcRead(size_t bytesRead); }; -#endif /* FRAMEWORK_OSAL_LINUX_TCSOCKETPOLLINGTASK_H_ */ +#endif /* FSFW_OSAL_COMMON_UDPTCPOLLINGTASK_H_ */ diff --git a/osal/common/UdpTmTcBridge.cpp b/src/fsfw/osal/common/UdpTmTcBridge.cpp similarity index 80% rename from osal/common/UdpTmTcBridge.cpp rename to src/fsfw/osal/common/UdpTmTcBridge.cpp index ba23f521..734a2b15 100644 --- a/osal/common/UdpTmTcBridge.cpp +++ b/src/fsfw/osal/common/UdpTmTcBridge.cpp @@ -1,30 +1,29 @@ -#include "tcpipHelpers.h" +#include "fsfw/osal/common/UdpTmTcBridge.h" +#include "fsfw/osal/common/tcpipHelpers.h" -#include -#include -#include - -#ifdef _WIN32 +#include "fsfw/platform.h" +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/ipc/MutexGuard.h" +#ifdef PLATFORM_WIN #include - -#elif defined(__unix__) - +#elif defined(PLATFORM_UNIX) #include #include - #endif //! Debugging preprocessor define. +#ifndef FSFW_UDP_SEND_WIRETAPPING_ENABLED #define FSFW_UDP_SEND_WIRETAPPING_ENABLED 0 +#endif -const std::string UdpTmTcBridge::DEFAULT_UDP_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT; +const std::string UdpTmTcBridge::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT; UdpTmTcBridge::UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination, - object_id_t tmStoreId, object_id_t tcStoreId, std::string udpServerPort): + std::string udpServerPort, object_id_t tmStoreId, object_id_t tcStoreId): TmTcBridge(objectId, tcDestination, tmStoreId, tcStoreId) { if(udpServerPort == "") { - this->udpServerPort = DEFAULT_UDP_SERVER_PORT; + this->udpServerPort = DEFAULT_SERVER_PORT; } else { this->udpServerPort = udpServerPort; @@ -38,7 +37,7 @@ ReturnValue_t UdpTmTcBridge::initialize() { ReturnValue_t result = TmTcBridge::initialize(); if(result != HasReturnvaluesIF::RETURN_OK) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "TmTcUdpBridge::initialize: TmTcBridge initialization failed!" + sif::error << "UdpTmTcBridge::initialize: TmTcBridge initialization failed!" << std::endl; #endif return result; @@ -54,10 +53,10 @@ ReturnValue_t UdpTmTcBridge::initialize() { /* Tell the user that we could not find a usable */ /* Winsock DLL. */ #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "TmTcUdpBridge::TmTcUdpBridge: WSAStartup failed with error: " << + sif::error << "UdpTmTcBridge::UdpTmTcBridge: WSAStartup failed with error: " << err << std::endl; #else - sif::printError("TmTcUdpBridge::TmTcUdpBridge: WSAStartup failed with error: %d\n", + sif::printError("UdpTmTcBridge::UdpTmTcBridge: WSAStartup failed with error: %d\n", err); #endif return HasReturnvaluesIF::RETURN_FAILED; @@ -78,19 +77,12 @@ ReturnValue_t UdpTmTcBridge::initialize() { getaddrinfo to assign the address 0.0.0.0 (any address) */ int retval = getaddrinfo(nullptr, udpServerPort.c_str(), &hints, &addrResult); if (retval != 0) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "TmTcUdpBridge::TmTcUdpBridge: Retrieving address info failed!" << - std::endl; -#endif + tcpip::handleError(tcpip::Protocol::UDP, tcpip::ErrorSources::GETADDRINFO_CALL); return HasReturnvaluesIF::RETURN_FAILED; } serverSocket = socket(addrResult->ai_family, addrResult->ai_socktype, addrResult->ai_protocol); if(serverSocket == INVALID_SOCKET) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "TmTcUdpBridge::TmTcUdpBridge: Could not open UDP socket!" << - std::endl; -#endif freeaddrinfo(addrResult); tcpip::handleError(tcpip::Protocol::UDP, tcpip::ErrorSources::SOCKET_CALL); return HasReturnvaluesIF::RETURN_FAILED; @@ -102,10 +94,6 @@ ReturnValue_t UdpTmTcBridge::initialize() { retval = bind(serverSocket, addrResult->ai_addr, static_cast(addrResult->ai_addrlen)); if(retval != 0) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "TmTcUdpBridge::TmTcUdpBridge: Could not bind " - "local port (" << udpServerPort << ") to server socket!" << std::endl; -#endif freeaddrinfo(addrResult); tcpip::handleError(tcpip::Protocol::UDP, tcpip::ErrorSources::BIND_CALL); return HasReturnvaluesIF::RETURN_FAILED; @@ -120,6 +108,10 @@ UdpTmTcBridge::~UdpTmTcBridge() { } } +std::string UdpTmTcBridge::getUdpPort() const { + return udpServerPort; +} + ReturnValue_t UdpTmTcBridge::sendTm(const uint8_t *data, size_t dataLen) { int flags = 0; diff --git a/osal/common/UdpTmTcBridge.h b/src/fsfw/osal/common/UdpTmTcBridge.h similarity index 56% rename from osal/common/UdpTmTcBridge.h rename to src/fsfw/osal/common/UdpTmTcBridge.h index 8b8d1949..4d634e64 100644 --- a/osal/common/UdpTmTcBridge.h +++ b/src/fsfw/osal/common/UdpTmTcBridge.h @@ -1,24 +1,26 @@ -#ifndef FSFW_OSAL_WINDOWS_TMTCWINUDPBRIDGE_H_ -#define FSFW_OSAL_WINDOWS_TMTCWINUDPBRIDGE_H_ +#ifndef FSFW_OSAL_COMMON_TMTCUDPBRIDGE_H_ +#define FSFW_OSAL_COMMON_TMTCUDPBRIDGE_H_ #include "TcpIpBase.h" -#include "../../tmtcservices/TmTcBridge.h" - -#ifdef _WIN32 +#include "fsfw/platform.h" +#include "fsfw/tmtcservices/TmTcBridge.h" +#ifdef PLATFORM_WIN #include - -#elif defined(__unix__) - +#elif defined(PLATFORM_UNIX) #include - #endif #include /** - * @brief This class should be used with the UdpTcPollingTask to implement a UDP server + * @brief This class can be used with the UdpTcPollingTask to implement a UDP server * for receiving and sending PUS TMTC. + * @details + * This bridge task will take care of sending telemetry back to a UDP client if a connection + * was established and store them in a FIFO if this was not done yet. It is also be the default + * destination for telecommands, but the telecommands will be relayed to a specified tcDestination + * directly. */ class UdpTmTcBridge: public TmTcBridge, @@ -26,10 +28,11 @@ class UdpTmTcBridge: friend class UdpTcPollingTask; public: /* The ports chosen here should not be used by any other process. */ - static const std::string DEFAULT_UDP_SERVER_PORT; + static const std::string DEFAULT_SERVER_PORT; UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination, - object_id_t tmStoreId, object_id_t tcStoreId, std::string udpServerPort = ""); + std::string udpServerPort = "", object_id_t tmStoreId = objects::TM_STORE, + object_id_t tcStoreId = objects::TC_STORE); virtual~ UdpTmTcBridge(); /** @@ -41,6 +44,8 @@ public: void checkAndSetClientAddress(sockaddr& clientAddress); + std::string getUdpPort() const; + protected: virtual ReturnValue_t sendTm(const uint8_t * data, size_t dataLen) override; @@ -56,5 +61,5 @@ private: MutexIF* mutex; }; -#endif /* FSFW_OSAL_HOST_TMTCWINUDPBRIDGE_H_ */ +#endif /* FSFW_OSAL_COMMON_TMTCUDPBRIDGE_H_ */ diff --git a/osal/common/tcpipCommon.cpp b/src/fsfw/osal/common/tcpipCommon.cpp similarity index 80% rename from osal/common/tcpipCommon.cpp rename to src/fsfw/osal/common/tcpipCommon.cpp index 551e2a42..2551496d 100644 --- a/osal/common/tcpipCommon.cpp +++ b/src/fsfw/osal/common/tcpipCommon.cpp @@ -1,7 +1,8 @@ -#include "tcpipCommon.h" -#include +#include "fsfw/platform.h" +#include "fsfw/osal/common/tcpipCommon.h" +#include "fsfw/serviceinterface/ServiceInterface.h" -#ifdef _WIN32 +#ifdef PLATFORM_WIN #include #endif @@ -20,6 +21,9 @@ void tcpip::determineErrorStrings(Protocol protocol, ErrorSources errorSrc, std: if(errorSrc == ErrorSources::SETSOCKOPT_CALL) { srcString = "setsockopt call"; } + if(errorSrc == ErrorSources::BIND_CALL) { + srcString = "bind call"; + } else if(errorSrc == ErrorSources::SOCKET_CALL) { srcString = "socket call"; } @@ -32,9 +36,18 @@ void tcpip::determineErrorStrings(Protocol protocol, ErrorSources errorSrc, std: else if(errorSrc == ErrorSources::RECVFROM_CALL) { srcString = "recvfrom call"; } + else if(errorSrc == ErrorSources::SEND_CALL) { + srcString = "send call"; + } + else if(errorSrc == ErrorSources::SENDTO_CALL) { + srcString = "sendto call"; + } else if(errorSrc == ErrorSources::GETADDRINFO_CALL) { srcString = "getaddrinfo call"; } + else if(errorSrc == ErrorSources::SHUTDOWN_CALL) { + srcString = "shutdown call"; + } else { srcString = "unknown call"; } diff --git a/osal/common/tcpipCommon.h b/src/fsfw/osal/common/tcpipCommon.h similarity index 81% rename from osal/common/tcpipCommon.h rename to src/fsfw/osal/common/tcpipCommon.h index 22b914dc..5a04144e 100644 --- a/osal/common/tcpipCommon.h +++ b/src/fsfw/osal/common/tcpipCommon.h @@ -1,7 +1,7 @@ #ifndef FSFW_OSAL_COMMON_TCPIPCOMMON_H_ #define FSFW_OSAL_COMMON_TCPIPCOMMON_H_ -#include "../../timemanager/clockDefinitions.h" +#include "fsfw/timemanager/clockDefinitions.h" #include #ifdef _WIN32 @@ -13,7 +13,7 @@ namespace tcpip { -const char* const DEFAULT_SERVER_PORT = "7301"; +static constexpr char DEFAULT_SERVER_PORT[] = "7301"; enum class Protocol { UDP, @@ -29,7 +29,9 @@ enum class ErrorSources { RECVFROM_CALL, LISTEN_CALL, ACCEPT_CALL, - SENDTO_CALL + SEND_CALL, + SENDTO_CALL, + SHUTDOWN_CALL }; void determineErrorStrings(Protocol protocol, ErrorSources errorSrc, std::string& protStr, diff --git a/osal/common/tcpipHelpers.h b/src/fsfw/osal/common/tcpipHelpers.h similarity index 85% rename from osal/common/tcpipHelpers.h rename to src/fsfw/osal/common/tcpipHelpers.h index 9764a93f..bf9a7b5a 100644 --- a/osal/common/tcpipHelpers.h +++ b/src/fsfw/osal/common/tcpipHelpers.h @@ -1,7 +1,7 @@ #ifndef FSFW_OSAL_WINDOWS_TCPIPHELPERS_H_ #define FSFW_OSAL_WINDOWS_TCPIPHELPERS_H_ -#include "../../timemanager/clockDefinitions.h" +#include "fsfw/timemanager/clockDefinitions.h" #include "tcpipCommon.h" namespace tcpip { diff --git a/osal/FreeRTOS/BinSemaphUsingTask.cpp b/src/fsfw/osal/freertos/BinSemaphUsingTask.cpp similarity index 95% rename from osal/FreeRTOS/BinSemaphUsingTask.cpp rename to src/fsfw/osal/freertos/BinSemaphUsingTask.cpp index 7d609aee..637c1925 100644 --- a/osal/FreeRTOS/BinSemaphUsingTask.cpp +++ b/src/fsfw/osal/freertos/BinSemaphUsingTask.cpp @@ -1,6 +1,6 @@ -#include "BinSemaphUsingTask.h" -#include "TaskManagement.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "fsfw/osal/freertos/BinSemaphUsingTask.h" +#include "fsfw/osal/freertos/TaskManagement.h" +#include "fsfw/serviceinterface/ServiceInterface.h" #if (tskKERNEL_VERSION_MAJOR == 8 && tskKERNEL_VERSION_MINOR > 2) || \ tskKERNEL_VERSION_MAJOR > 8 diff --git a/osal/FreeRTOS/BinSemaphUsingTask.h b/src/fsfw/osal/freertos/BinSemaphUsingTask.h similarity index 95% rename from osal/FreeRTOS/BinSemaphUsingTask.h rename to src/fsfw/osal/freertos/BinSemaphUsingTask.h index ec434853..0645b1fa 100644 --- a/osal/FreeRTOS/BinSemaphUsingTask.h +++ b/src/fsfw/osal/freertos/BinSemaphUsingTask.h @@ -1,11 +1,11 @@ #ifndef FSFW_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_ #define FSFW_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_ -#include "../../returnvalues/HasReturnvaluesIF.h" -#include "../../tasks/SemaphoreIF.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" +#include "fsfw/tasks/SemaphoreIF.h" -#include -#include +#include "FreeRTOS.h" +#include "task.h" #if (tskKERNEL_VERSION_MAJOR == 8 && tskKERNEL_VERSION_MINOR > 2) || \ tskKERNEL_VERSION_MAJOR > 8 diff --git a/osal/FreeRTOS/BinarySemaphore.cpp b/src/fsfw/osal/freertos/BinarySemaphore.cpp similarity index 94% rename from osal/FreeRTOS/BinarySemaphore.cpp rename to src/fsfw/osal/freertos/BinarySemaphore.cpp index c0349b7c..4ec5d30f 100644 --- a/osal/FreeRTOS/BinarySemaphore.cpp +++ b/src/fsfw/osal/freertos/BinarySemaphore.cpp @@ -1,6 +1,6 @@ -#include "BinarySemaphore.h" -#include "TaskManagement.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "fsfw/osal/freertos/BinarySemaphore.h" +#include "fsfw/osal/freertos/TaskManagement.h" +#include "fsfw/serviceinterface/ServiceInterface.h" BinarySemaphore::BinarySemaphore() { handle = xSemaphoreCreateBinary(); diff --git a/osal/FreeRTOS/BinarySemaphore.h b/src/fsfw/osal/freertos/BinarySemaphore.h similarity index 95% rename from osal/FreeRTOS/BinarySemaphore.h rename to src/fsfw/osal/freertos/BinarySemaphore.h index 8969d503..1ae56ff6 100644 --- a/osal/FreeRTOS/BinarySemaphore.h +++ b/src/fsfw/osal/freertos/BinarySemaphore.h @@ -1,11 +1,11 @@ #ifndef FSFW_OSAL_FREERTOS_BINARYSEMPAHORE_H_ #define FSFW_OSAL_FREERTOS_BINARYSEMPAHORE_H_ -#include "../../returnvalues/HasReturnvaluesIF.h" -#include "../../tasks/SemaphoreIF.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" +#include "fsfw/tasks/SemaphoreIF.h" -#include -#include +#include "FreeRTOS.h" +#include "semphr.h" /** * @brief OS Tool to achieve synchronization of between tasks or between diff --git a/osal/FreeRTOS/CMakeLists.txt b/src/fsfw/osal/freertos/CMakeLists.txt similarity index 72% rename from osal/FreeRTOS/CMakeLists.txt rename to src/fsfw/osal/freertos/CMakeLists.txt index 95462010..40bdcd0f 100644 --- a/osal/FreeRTOS/CMakeLists.txt +++ b/src/fsfw/osal/freertos/CMakeLists.txt @@ -15,16 +15,18 @@ target_sources(${LIB_FSFW_NAME} 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 # library. if(NOT LIB_OS_NAME) - message(FATAL_ERROR - "FreeRTOS needs to be linked as a target and " - "LIB_OS_NAME needs to be set to the target" + 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} + ) endif() - -target_link_libraries(${LIB_FSWFW_NAME} ${LIB_OS_NAME}) \ No newline at end of file diff --git a/osal/FreeRTOS/Clock.cpp b/src/fsfw/osal/freertos/Clock.cpp similarity index 58% rename from osal/FreeRTOS/Clock.cpp rename to src/fsfw/osal/freertos/Clock.cpp index c15971fe..eddf2fec 100644 --- a/osal/FreeRTOS/Clock.cpp +++ b/src/fsfw/osal/freertos/Clock.cpp @@ -1,13 +1,13 @@ -#include "Timekeeper.h" +#include "fsfw/osal/freertos/Timekeeper.h" -#include "../../timemanager/Clock.h" -#include "../../globalfunctions/timevalOperations.h" +#include "fsfw/timemanager/Clock.h" +#include "fsfw/globalfunctions/timevalOperations.h" -#include -#include +#include "FreeRTOS.h" +#include "task.h" -#include -#include +#include +#include //TODO sanitize input? //TODO much of this code can be reused for tick-only systems @@ -134,71 +134,3 @@ ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) { / 3600.; return HasReturnvaluesIF::RETURN_OK; } - -ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) { - //SHOULDDO: works not for dates in the past (might have less leap seconds) - if (timeMutex == nullptr) { - return HasReturnvaluesIF::RETURN_FAILED; - } - - uint16_t leapSeconds; - ReturnValue_t result = getLeapSeconds(&leapSeconds); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - timeval leapSeconds_timeval = { 0, 0 }; - leapSeconds_timeval.tv_sec = leapSeconds; - - //initial offset between UTC and TAI - timeval UTCtoTAI1972 = { 10, 0 }; - - timeval TAItoTT = { 32, 184000 }; - - *tt = utc + leapSeconds_timeval + UTCtoTAI1972 + TAItoTT; - - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) { - if (checkOrCreateClockMutex() != HasReturnvaluesIF::RETURN_OK) { - return HasReturnvaluesIF::RETURN_FAILED; - } - ReturnValue_t result = timeMutex->lockMutex(MutexIF::TimeoutType::BLOCKING); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - leapSeconds = leapSeconds_; - - result = timeMutex->unlockMutex(); - return result; -} - -ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) { - if (timeMutex == NULL) { - return HasReturnvaluesIF::RETURN_FAILED; - } - ReturnValue_t result = timeMutex->lockMutex(MutexIF::TimeoutType::BLOCKING); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - *leapSeconds_ = leapSeconds; - - result = timeMutex->unlockMutex(); - return result; -} - -ReturnValue_t Clock::checkOrCreateClockMutex() { - if (timeMutex == NULL) { - MutexFactory* mutexFactory = MutexFactory::instance(); - if (mutexFactory == NULL) { - return HasReturnvaluesIF::RETURN_FAILED; - } - timeMutex = mutexFactory->createMutex(); - if (timeMutex == NULL) { - return HasReturnvaluesIF::RETURN_FAILED; - } - } - return HasReturnvaluesIF::RETURN_OK; -} diff --git a/osal/FreeRTOS/CountingSemaphUsingTask.cpp b/src/fsfw/osal/freertos/CountingSemaphUsingTask.cpp similarity index 95% rename from osal/FreeRTOS/CountingSemaphUsingTask.cpp rename to src/fsfw/osal/freertos/CountingSemaphUsingTask.cpp index 750ea9d6..a34a6508 100644 --- a/osal/FreeRTOS/CountingSemaphUsingTask.cpp +++ b/src/fsfw/osal/freertos/CountingSemaphUsingTask.cpp @@ -1,7 +1,7 @@ -#include "CountingSemaphUsingTask.h" -#include "TaskManagement.h" +#include "fsfw/osal/freertos/CountingSemaphUsingTask.h" +#include "fsfw/osal/freertos/TaskManagement.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "fsfw/serviceinterface/ServiceInterface.h" #if (tskKERNEL_VERSION_MAJOR == 8 && tskKERNEL_VERSION_MINOR > 2) || \ tskKERNEL_VERSION_MAJOR > 8 diff --git a/osal/FreeRTOS/CountingSemaphUsingTask.h b/src/fsfw/osal/freertos/CountingSemaphUsingTask.h similarity index 97% rename from osal/FreeRTOS/CountingSemaphUsingTask.h rename to src/fsfw/osal/freertos/CountingSemaphUsingTask.h index 45915b6b..eb2fc67b 100644 --- a/osal/FreeRTOS/CountingSemaphUsingTask.h +++ b/src/fsfw/osal/freertos/CountingSemaphUsingTask.h @@ -2,10 +2,10 @@ #define FSFW_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_ #include "CountingSemaphUsingTask.h" -#include "../../tasks/SemaphoreIF.h" +#include "fsfw/tasks/SemaphoreIF.h" -#include -#include +#include "FreeRTOS.h" +#include "task.h" #if (tskKERNEL_VERSION_MAJOR == 8 && tskKERNEL_VERSION_MINOR > 2) || \ tskKERNEL_VERSION_MAJOR > 8 diff --git a/osal/FreeRTOS/CountingSemaphore.cpp b/src/fsfw/osal/freertos/CountingSemaphore.cpp similarity index 87% rename from osal/FreeRTOS/CountingSemaphore.cpp rename to src/fsfw/osal/freertos/CountingSemaphore.cpp index 40884d27..90dc771f 100644 --- a/osal/FreeRTOS/CountingSemaphore.cpp +++ b/src/fsfw/osal/freertos/CountingSemaphore.cpp @@ -1,9 +1,10 @@ -#include "CountingSemaphore.h" -#include "TaskManagement.h" +#include "fsfw/osal/freertos/CountingSemaphore.h" +#include "fsfw/osal/freertos/TaskManagement.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "fsfw/serviceinterface/ServiceInterface.h" -#include +#include "FreeRTOS.h" +#include "semphr.h" // Make sure #define configUSE_COUNTING_SEMAPHORES 1 is set in // free FreeRTOSConfig.h file. diff --git a/osal/FreeRTOS/CountingSemaphore.h b/src/fsfw/osal/freertos/CountingSemaphore.h similarity index 100% rename from osal/FreeRTOS/CountingSemaphore.h rename to src/fsfw/osal/freertos/CountingSemaphore.h diff --git a/osal/FreeRTOS/FixedTimeslotTask.cpp b/src/fsfw/osal/freertos/FixedTimeslotTask.cpp similarity index 95% rename from osal/FreeRTOS/FixedTimeslotTask.cpp rename to src/fsfw/osal/freertos/FixedTimeslotTask.cpp index aa7e6c59..9690991d 100644 --- a/osal/FreeRTOS/FixedTimeslotTask.cpp +++ b/src/fsfw/osal/freertos/FixedTimeslotTask.cpp @@ -1,6 +1,7 @@ -#include "FixedTimeslotTask.h" +#include "fsfw/osal/freertos/FixedTimeslotTask.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/serviceinterface/ServiceInterface.h" uint32_t FixedTimeslotTask::deadlineMissedCount = 0; const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = configMINIMAL_STACK_SIZE; @@ -66,8 +67,7 @@ ReturnValue_t FixedTimeslotTask::startTask() { ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, uint32_t slotTimeMs, int8_t executionStep) { - ExecutableObjectIF* handler = - objectManager->get(componentId); + ExecutableObjectIF* handler = ObjectManager::instance()->get(componentId); if (handler != nullptr) { pst.addSlot(componentId, slotTimeMs, executionStep, handler, this); return HasReturnvaluesIF::RETURN_OK; diff --git a/osal/FreeRTOS/FixedTimeslotTask.h b/src/fsfw/osal/freertos/FixedTimeslotTask.h similarity index 94% rename from osal/FreeRTOS/FixedTimeslotTask.h rename to src/fsfw/osal/freertos/FixedTimeslotTask.h index f2245ba4..ebd902cc 100644 --- a/osal/FreeRTOS/FixedTimeslotTask.h +++ b/src/fsfw/osal/freertos/FixedTimeslotTask.h @@ -2,12 +2,12 @@ #define FSFW_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_ #include "FreeRTOSTaskIF.h" -#include "../../tasks/FixedSlotSequence.h" -#include "../../tasks/FixedTimeslotTaskIF.h" -#include "../../tasks/Typedef.h" +#include "fsfw/tasks/FixedSlotSequence.h" +#include "fsfw/tasks/FixedTimeslotTaskIF.h" +#include "fsfw/tasks/Typedef.h" -#include -#include +#include "FreeRTOS.h" +#include "task.h" class FixedTimeslotTask: public FixedTimeslotTaskIF, public FreeRTOSTaskIF { public: diff --git a/osal/FreeRTOS/FreeRTOSTaskIF.h b/src/fsfw/osal/freertos/FreeRTOSTaskIF.h similarity index 95% rename from osal/FreeRTOS/FreeRTOSTaskIF.h rename to src/fsfw/osal/freertos/FreeRTOSTaskIF.h index 2a2d9494..08f0df25 100644 --- a/osal/FreeRTOS/FreeRTOSTaskIF.h +++ b/src/fsfw/osal/freertos/FreeRTOSTaskIF.h @@ -1,8 +1,8 @@ #ifndef FSFW_OSAL_FREERTOS_FREERTOSTASKIF_H_ #define FSFW_OSAL_FREERTOS_FREERTOSTASKIF_H_ -#include -#include +#include "FreeRTOS.h" +#include "task.h" class FreeRTOSTaskIF { public: diff --git a/src/fsfw/osal/freertos/MessageQueue.cpp b/src/fsfw/osal/freertos/MessageQueue.cpp new file mode 100644 index 00000000..487fa864 --- /dev/null +++ b/src/fsfw/osal/freertos/MessageQueue.cpp @@ -0,0 +1,159 @@ +#include "fsfw/osal/freertos/MessageQueue.h" +#include "fsfw/osal/freertos/QueueMapManager.h" + +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/serviceinterface/ServiceInterface.h" + +MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize): + maxMessageSize(maxMessageSize) { + handle = xQueueCreate(messageDepth, maxMessageSize); + if (handle == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "MessageQueue::MessageQueue: Creation failed" << std::endl; + sif::error << "Specified Message Depth: " << messageDepth << std::endl; + sif::error << "Specified Maximum Message Size: " << maxMessageSize << std::endl; +#else + sif::printError("MessageQueue::MessageQueue: Creation failed\n"); + sif::printError("Specified Message Depth: %d\n", messageDepth); + sif::printError("Specified MAximum Message Size: %d\n", maxMessageSize); +#endif + } + QueueMapManager::instance()->addMessageQueue(handle, &queueId); +} + +MessageQueue::~MessageQueue() { + if (handle != nullptr) { + vQueueDelete(handle); + } +} + +void MessageQueue::switchSystemContext(CallContext callContext) { + this->callContext = callContext; +} + +ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo, + MessageQueueMessageIF* message, bool ignoreFault) { + return sendMessageFrom(sendTo, message, this->getId(), ignoreFault); +} + +ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessageIF* message) { + return sendToDefaultFrom(message, this->getId()); +} + +ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessageIF* message, + MessageQueueId_t sentFrom, bool ignoreFault) { + return sendMessageFrom(defaultDestination,message,sentFrom,ignoreFault); +} + +ReturnValue_t MessageQueue::reply(MessageQueueMessageIF* message) { + if (this->lastPartner != MessageQueueIF::NO_QUEUE) { + return sendMessageFrom(this->lastPartner, message, this->getId()); + } else { + return NO_REPLY_PARTNER; + } +} + +ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, + MessageQueueMessageIF* message, MessageQueueId_t sentFrom, + bool ignoreFault) { + return sendMessageFromMessageQueue(sendTo, message, sentFrom, ignoreFault, + callContext); +} + +QueueHandle_t MessageQueue::getNativeQueueHandle() { + return handle; +} + +ReturnValue_t MessageQueue::handleSendResult(BaseType_t result, bool ignoreFault) { + if (result != pdPASS) { + if (not ignoreFault) { + InternalErrorReporterIF* internalErrorReporter = ObjectManager::instance()-> + get(objects::INTERNAL_ERROR_REPORTER); + if (internalErrorReporter != nullptr) { + internalErrorReporter->queueMessageNotSent(); + } + } + return MessageQueueIF::FULL; + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message, + MessageQueueId_t* receivedFrom) { + ReturnValue_t status = this->receiveMessage(message); + if(status == HasReturnvaluesIF::RETURN_OK) { + *receivedFrom = this->lastPartner; + } + return status; +} + +ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) { + BaseType_t result = xQueueReceive(handle,reinterpret_cast( + message->getBuffer()), 0); + if (result == pdPASS){ + this->lastPartner = message->getSender(); + return HasReturnvaluesIF::RETURN_OK; + } else { + return MessageQueueIF::EMPTY; + } +} + +MessageQueueId_t MessageQueue::getLastPartner() const { + return lastPartner; +} + +ReturnValue_t MessageQueue::flush(uint32_t* count) { + //TODO FreeRTOS does not support flushing partially + //Is always successful + xQueueReset(handle); + return HasReturnvaluesIF::RETURN_OK; +} + +MessageQueueId_t MessageQueue::getId() const { + return queueId; +} + +void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) { + defaultDestinationSet = true; + this->defaultDestination = defaultDestination; +} + +MessageQueueId_t MessageQueue::getDefaultDestination() const { + return defaultDestination; +} + +bool MessageQueue::isDefaultDestinationSet() const { + return defaultDestinationSet; +} + + +// static core function to send messages. +ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, + MessageQueueMessageIF* message, MessageQueueId_t sentFrom, + bool ignoreFault, CallContext callContext) { + BaseType_t result = pdFALSE; + if(sendTo == MessageQueueIF::NO_QUEUE) { + return MessageQueueIF::DESTINATION_INVALID; + } + + QueueHandle_t destination = QueueMapManager::instance()->getMessageQueue(sendTo); + if(destination == nullptr) { + return MessageQueueIF::DESTINATION_INVALID; + } + + message->setSender(sentFrom); + if(callContext == CallContext::TASK) { + result = xQueueSendToBack(destination, static_cast(message->getBuffer()), 0); + } + else { + /* If the call context is from an interrupt, request a context switch if a higher priority + task was blocked by the interrupt. */ + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + result = xQueueSendFromISR(destination, static_cast(message->getBuffer()), + &xHigherPriorityTaskWoken); + if(xHigherPriorityTaskWoken == pdTRUE) { + TaskManagement::requestContextSwitch(callContext); + } + } + return handleSendResult(result, ignoreFault); +} diff --git a/src/fsfw/osal/freertos/MessageQueue.h b/src/fsfw/osal/freertos/MessageQueue.h new file mode 100644 index 00000000..debb3034 --- /dev/null +++ b/src/fsfw/osal/freertos/MessageQueue.h @@ -0,0 +1,150 @@ +#ifndef FSFW_OSAL_FREERTOS_MESSAGEQUEUE_H_ +#define FSFW_OSAL_FREERTOS_MESSAGEQUEUE_H_ + +#include "TaskManagement.h" + +#include "fsfw/internalerror/InternalErrorReporterIF.h" +#include "fsfw/ipc/MessageQueueIF.h" +#include "fsfw/ipc/MessageQueueMessageIF.h" +#include "fsfw/ipc/MessageQueueMessage.h" + +#include "FreeRTOS.h" +#include "queue.h" + +/** + * @brief This class manages sending and receiving of + * message queue messages. + * @details + * Message queues are used to pass asynchronous messages between processes. + * They work like post boxes, where all incoming messages are stored in FIFO + * order. This class creates a new receiving queue and provides methods to fetch + * received messages. Being a child of MessageQueueSender, this class also + * provides methods to send a message to a user-defined or a default destination. + * In addition it also provides a reply method to answer to the queue it + * received its last message from. + * + * The MessageQueue should be used as "post box" for a single owning object. + * So all message queue communication is "n-to-one". + * For creating the queue, as well as sending and receiving messages, the class + * makes use of the operating system calls provided. + * + * Please keep in mind that FreeRTOS offers different calls for message queue + * operations if called from an ISR. + * For now, the system context needs to be switched manually. + * @ingroup osal + * @ingroup message_queue + */ +class MessageQueue : public MessageQueueIF { + friend class MessageQueueSenderIF; +public: + /** + * @brief The constructor initializes and configures the message queue. + * @details + * By making use of the according operating system call, a message queue + * is created and initialized. The message depth - the maximum number of + * messages to be buffered - may be set with the help of a parameter, + * whereas the message size is automatically set to the maximum message + * queue message size. The operating system sets the message queue id, or + * in case of failure, it is set to zero. + * @param message_depth + * The number of messages to be buffered before passing an error to the + * sender. Default is three. + * @param max_message_size + * With this parameter, the maximum message size can be adjusted. + * This should be left default. + */ + MessageQueue( size_t messageDepth = 3, + size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE ); + + /** Copying message queues forbidden */ + MessageQueue(const MessageQueue&) = delete; + MessageQueue& operator=(const MessageQueue&) = delete; + + /** + * @brief The destructor deletes the formerly created message queue. + * @details This is accomplished by using the delete call provided + * by the operating system. + */ + virtual ~MessageQueue(); + + /** + * This function is used to switch the call context. This has to be called + * if a message is sent or received from an ISR! + * @param callContext + */ + void switchSystemContext(CallContext callContext); + + /** MessageQueueIF implementation */ + ReturnValue_t sendMessage(MessageQueueId_t sendTo, + MessageQueueMessageIF* message, bool ignoreFault = false) override; + + ReturnValue_t sendToDefault(MessageQueueMessageIF* message) override; + + ReturnValue_t reply(MessageQueueMessageIF* message) override; + virtual ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, + MessageQueueMessageIF* message, + MessageQueueId_t sentFrom = NO_QUEUE, + bool ignoreFault = false) override; + + virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessageIF* message, + MessageQueueId_t sentFrom = NO_QUEUE, + bool ignoreFault = false) override; + + ReturnValue_t receiveMessage(MessageQueueMessageIF* message, + MessageQueueId_t *receivedFrom) override; + + ReturnValue_t receiveMessage(MessageQueueMessageIF* message) override; + + ReturnValue_t flush(uint32_t* count) override; + + MessageQueueId_t getLastPartner() const override; + + MessageQueueId_t getId() const override; + + void setDefaultDestination(MessageQueueId_t defaultDestination) override; + + MessageQueueId_t getDefaultDestination() const override; + + bool isDefaultDestinationSet() const override; + + QueueHandle_t getNativeQueueHandle(); + +protected: + /** + * @brief Implementation to be called from any send Call within + * MessageQueue and MessageQueueSenderIF. + * @details + * This method takes the message provided, adds the sentFrom information and + * passes it on to the destination provided with an operating system call. + * The OS's return value is returned. + * @param sendTo + * This parameter specifies the message queue id to send the message to. + * @param message + * This is a pointer to a previously created message, which is sent. + * @param sentFrom + * The sentFrom information can be set to inject the sender's queue id into + * the message. This variable is set to zero by default. + * @param ignoreFault + * If set to true, the internal software fault counter is not incremented + * if queue is full. + * @param context Specify whether call is made from task or from an ISR. + */ + static ReturnValue_t sendMessageFromMessageQueue(MessageQueueId_t sendTo, + MessageQueueMessageIF* message, MessageQueueId_t sentFrom = NO_QUEUE, + bool ignoreFault=false, CallContext callContext = CallContext::TASK); + + static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault); + +private: + bool defaultDestinationSet = false; + QueueHandle_t handle; + MessageQueueId_t queueId = MessageQueueIF::NO_QUEUE; + + MessageQueueId_t defaultDestination = MessageQueueIF::NO_QUEUE; + MessageQueueId_t lastPartner = MessageQueueIF::NO_QUEUE; + const size_t maxMessageSize; + //! Stores the current system context + CallContext callContext = CallContext::TASK; +}; + +#endif /* FSFW_OSAL_FREERTOS_MESSAGEQUEUE_H_ */ diff --git a/osal/FreeRTOS/Mutex.cpp b/src/fsfw/osal/freertos/Mutex.cpp similarity index 92% rename from osal/FreeRTOS/Mutex.cpp rename to src/fsfw/osal/freertos/Mutex.cpp index 0b85ca13..8d1313e6 100644 --- a/osal/FreeRTOS/Mutex.cpp +++ b/src/fsfw/osal/freertos/Mutex.cpp @@ -1,6 +1,6 @@ -#include "Mutex.h" +#include "fsfw/osal/freertos/Mutex.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "fsfw/serviceinterface/ServiceInterface.h" Mutex::Mutex() { handle = xSemaphoreCreateMutex(); diff --git a/osal/FreeRTOS/Mutex.h b/src/fsfw/osal/freertos/Mutex.h similarity index 86% rename from osal/FreeRTOS/Mutex.h rename to src/fsfw/osal/freertos/Mutex.h index 156d431c..082679c7 100644 --- a/osal/FreeRTOS/Mutex.h +++ b/src/fsfw/osal/freertos/Mutex.h @@ -1,10 +1,10 @@ #ifndef FRAMEWORK_FREERTOS_MUTEX_H_ #define FRAMEWORK_FREERTOS_MUTEX_H_ -#include "../../ipc/MutexIF.h" +#include "fsfw/ipc/MutexIF.h" -#include -#include +#include "FreeRTOS.h" +#include "semphr.h" /** * @brief OS component to implement MUTual EXclusion diff --git a/osal/FreeRTOS/MutexFactory.cpp b/src/fsfw/osal/freertos/MutexFactory.cpp similarity index 89% rename from osal/FreeRTOS/MutexFactory.cpp rename to src/fsfw/osal/freertos/MutexFactory.cpp index d9569e35..f8b48c7d 100644 --- a/osal/FreeRTOS/MutexFactory.cpp +++ b/src/fsfw/osal/freertos/MutexFactory.cpp @@ -1,6 +1,6 @@ -#include "Mutex.h" +#include "fsfw/osal/freertos/Mutex.h" -#include "../../ipc/MutexFactory.h" +#include "fsfw/ipc/MutexFactory.h" //TODO: Different variant than the lazy loading in QueueFactory. diff --git a/osal/FreeRTOS/PeriodicTask.cpp b/src/fsfw/osal/freertos/PeriodicTask.cpp similarity index 93% rename from osal/FreeRTOS/PeriodicTask.cpp rename to src/fsfw/osal/freertos/PeriodicTask.cpp index 3e830c7f..7ef1c837 100644 --- a/osal/FreeRTOS/PeriodicTask.cpp +++ b/src/fsfw/osal/freertos/PeriodicTask.cpp @@ -1,7 +1,8 @@ -#include "PeriodicTask.h" +#include "fsfw/osal/freertos/PeriodicTask.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" -#include "../../tasks/ExecutableObjectIF.h" +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/tasks/ExecutableObjectIF.h" PeriodicTask::PeriodicTask(const char *name, TaskPriority setPriority, TaskStackSize setStack, TaskPeriod setPeriod, @@ -100,7 +101,7 @@ void PeriodicTask::taskFunctionality() { } ReturnValue_t PeriodicTask::addComponent(object_id_t object) { - ExecutableObjectIF* newObject = objectManager->get( + ExecutableObjectIF* newObject = ObjectManager::instance()->get( object); if (newObject == nullptr) { #if FSFW_CPP_OSTREAM_ENABLED == 1 diff --git a/osal/FreeRTOS/PeriodicTask.h b/src/fsfw/osal/freertos/PeriodicTask.h similarity index 95% rename from osal/FreeRTOS/PeriodicTask.h rename to src/fsfw/osal/freertos/PeriodicTask.h index 36ef568f..e910a0c6 100644 --- a/osal/FreeRTOS/PeriodicTask.h +++ b/src/fsfw/osal/freertos/PeriodicTask.h @@ -2,12 +2,12 @@ #define FSFW_OSAL_FREERTOS_PERIODICTASK_H_ #include "FreeRTOSTaskIF.h" -#include "../../objectmanager/ObjectManagerIF.h" -#include "../../tasks/PeriodicTaskIF.h" -#include "../../tasks/Typedef.h" +#include "fsfw/objectmanager/ObjectManagerIF.h" +#include "fsfw/tasks/PeriodicTaskIF.h" +#include "fsfw/tasks/Typedef.h" -#include -#include +#include "FreeRTOS.h" +#include "task.h" #include diff --git a/osal/FreeRTOS/QueueFactory.cpp b/src/fsfw/osal/freertos/QueueFactory.cpp similarity index 86% rename from osal/FreeRTOS/QueueFactory.cpp rename to src/fsfw/osal/freertos/QueueFactory.cpp index ed29e10c..536c16c0 100644 --- a/osal/FreeRTOS/QueueFactory.cpp +++ b/src/fsfw/osal/freertos/QueueFactory.cpp @@ -1,7 +1,7 @@ -#include "MessageQueue.h" +#include "fsfw/osal/freertos/MessageQueue.h" -#include "../../ipc/MessageQueueSenderIF.h" -#include "../../ipc/QueueFactory.h" +#include "fsfw/ipc/MessageQueueSenderIF.h" +#include "fsfw/ipc/QueueFactory.h" QueueFactory* QueueFactory::factoryInstance = nullptr; diff --git a/src/fsfw/osal/freertos/QueueMapManager.cpp b/src/fsfw/osal/freertos/QueueMapManager.cpp new file mode 100644 index 00000000..7d6b2f12 --- /dev/null +++ b/src/fsfw/osal/freertos/QueueMapManager.cpp @@ -0,0 +1,64 @@ +#include "fsfw/osal/freertos/QueueMapManager.h" +#include "fsfw/ipc/MutexFactory.h" +#include "fsfw/ipc/MutexGuard.h" + +QueueMapManager* QueueMapManager::mqManagerInstance = nullptr; + +QueueMapManager::QueueMapManager() { + mapLock = MutexFactory::instance()->createMutex(); +} + +QueueMapManager* QueueMapManager::instance() { + if (mqManagerInstance == nullptr){ + mqManagerInstance = new QueueMapManager(); + } + return QueueMapManager::mqManagerInstance; +} + +ReturnValue_t QueueMapManager::addMessageQueue(QueueHandle_t queue, MessageQueueId_t* id) { + MutexGuard lock(mapLock); + uint32_t currentId = queueCounter; + queueCounter++; + if(currentId == MessageQueueIF::NO_QUEUE) { + // Skip the NO_QUEUE value + currentId = queueCounter; + queueCounter++; + } + auto returnPair = queueMap.emplace(currentId, queue); + if(not returnPair.second) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "QueueMapManager::addMessageQueue This ID is already " + "inside the map!" << std::endl; +#else + sif::printError("QueueMapManager::addMessageQueue This ID is already " + "inside the map!\n"); +#endif + return HasReturnvaluesIF::RETURN_FAILED; + } + if (id != nullptr) { + *id = currentId; + } + return HasReturnvaluesIF::RETURN_OK; + +} + +QueueHandle_t QueueMapManager::getMessageQueue(MessageQueueId_t messageQueueId) const { + auto queueIter = queueMap.find(messageQueueId); + if(queueIter != queueMap.end()) { + return queueIter->second; + } + else { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "QueueMapManager::getQueueHandle: The ID " << messageQueueId << + " does not exists in the map!" << std::endl; +#else + sif::printWarning("QueueMapManager::getQueueHandle: The ID %d does not exist in the map!\n", + messageQueueId); +#endif + } + return nullptr; +} + +QueueMapManager::~QueueMapManager() { + MutexFactory::instance()->deleteMutex(mapLock); +} diff --git a/src/fsfw/osal/freertos/QueueMapManager.h b/src/fsfw/osal/freertos/QueueMapManager.h new file mode 100644 index 00000000..dbe0526b --- /dev/null +++ b/src/fsfw/osal/freertos/QueueMapManager.h @@ -0,0 +1,50 @@ +#ifndef FSFW_OSAL_FREERTOS_QUEUEMAPMANAGER_H_ +#define FSFW_OSAL_FREERTOS_QUEUEMAPMANAGER_H_ + +#include "fsfw/ipc/MutexIF.h" +#include "fsfw/ipc/messageQueueDefinitions.h" +#include "fsfw/ipc/MessageQueueIF.h" + +#include "FreeRTOS.h" +#include "queue.h" + +#include + +using QueueMap = std::map; + +class QueueMapManager { +public: + + //! Returns the single instance of QueueMapManager + static QueueMapManager* instance(); + + /** + * Insert a message queue and the corresponding QueueHandle into the map + * @param queue The message queue to insert. + * @param id The passed value will be set unless a nullptr is passed + * @return + */ + ReturnValue_t addMessageQueue(QueueHandle_t queue, MessageQueueId_t* id); + + /** + * Get the message queue handle by providing a message queue ID. Returns nullptr + * if the queue ID does not exist in the internal map. + * @param messageQueueId + * @return + */ + QueueHandle_t getMessageQueue(MessageQueueId_t messageQueueId) const; + +private: + //! External instantiation forbidden. Constructor still required for singleton instantiation. + QueueMapManager(); + ~QueueMapManager(); + + uint32_t queueCounter = MessageQueueIF::NO_QUEUE + 1; + MutexIF* mapLock; + QueueMap queueMap; + static QueueMapManager* mqManagerInstance; +}; + + + +#endif /* FSFW_OSAL_FREERTOS_QUEUEMAPMANAGER_H_ */ diff --git a/osal/FreeRTOS/README.md b/src/fsfw/osal/freertos/README.md similarity index 100% rename from osal/FreeRTOS/README.md rename to src/fsfw/osal/freertos/README.md diff --git a/osal/FreeRTOS/SemaphoreFactory.cpp b/src/fsfw/osal/freertos/SemaphoreFactory.cpp similarity index 83% rename from osal/FreeRTOS/SemaphoreFactory.cpp rename to src/fsfw/osal/freertos/SemaphoreFactory.cpp index df005f6a..b6e8f86e 100644 --- a/osal/FreeRTOS/SemaphoreFactory.cpp +++ b/src/fsfw/osal/freertos/SemaphoreFactory.cpp @@ -1,9 +1,10 @@ -#include "../../osal/FreeRTOS/BinarySemaphore.h" -#include "../../osal/FreeRTOS/BinSemaphUsingTask.h" -#include "../../osal/FreeRTOS/CountingSemaphore.h" -#include "../../osal/FreeRTOS/CountingSemaphUsingTask.h" -#include "../../tasks/SemaphoreFactory.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "fsfw/osal/freertos/BinarySemaphore.h" +#include "fsfw/osal/freertos/BinSemaphUsingTask.h" +#include "fsfw/osal/freertos/CountingSemaphore.h" +#include "fsfw/osal/freertos/CountingSemaphUsingTask.h" + +#include "fsfw/tasks/SemaphoreFactory.h" +#include "fsfw/serviceinterface/ServiceInterface.h" SemaphoreFactory* SemaphoreFactory::factoryInstance = nullptr; diff --git a/osal/FreeRTOS/TaskFactory.cpp b/src/fsfw/osal/freertos/TaskFactory.cpp similarity index 88% rename from osal/FreeRTOS/TaskFactory.cpp rename to src/fsfw/osal/freertos/TaskFactory.cpp index 5b64811a..21ca80cb 100644 --- a/osal/FreeRTOS/TaskFactory.cpp +++ b/src/fsfw/osal/freertos/TaskFactory.cpp @@ -1,9 +1,8 @@ -#include "../../tasks/TaskFactory.h" -#include "../../returnvalues/HasReturnvaluesIF.h" - -#include "PeriodicTask.h" -#include "FixedTimeslotTask.h" +#include "fsfw/tasks/TaskFactory.h" +#include "fsfw/osal/freertos/PeriodicTask.h" +#include "fsfw/osal/freertos/FixedTimeslotTask.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" TaskFactory* TaskFactory::factoryInstance = new TaskFactory(); diff --git a/osal/FreeRTOS/TaskManagement.cpp b/src/fsfw/osal/freertos/TaskManagement.cpp similarity index 92% rename from osal/FreeRTOS/TaskManagement.cpp rename to src/fsfw/osal/freertos/TaskManagement.cpp index c0d0067e..f19aa4fd 100644 --- a/osal/FreeRTOS/TaskManagement.cpp +++ b/src/fsfw/osal/freertos/TaskManagement.cpp @@ -1,4 +1,4 @@ -#include "TaskManagement.h" +#include "fsfw/osal/freertos/TaskManagement.h" void TaskManagement::vRequestContextSwitchFromTask() { vTaskDelay(0); diff --git a/osal/FreeRTOS/TaskManagement.h b/src/fsfw/osal/freertos/TaskManagement.h similarity index 91% rename from osal/FreeRTOS/TaskManagement.h rename to src/fsfw/osal/freertos/TaskManagement.h index b9aece48..9aa10797 100644 --- a/osal/FreeRTOS/TaskManagement.h +++ b/src/fsfw/osal/freertos/TaskManagement.h @@ -1,10 +1,10 @@ -#ifndef FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_ -#define FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_ +#ifndef FSFW_OSAL_FREERTOS_TASKMANAGEMENT_H_ +#define FSFW_OSAL_FREERTOS_TASKMANAGEMENT_H_ #include "../../returnvalues/HasReturnvaluesIF.h" -#include -#include +#include "FreeRTOS.h" +#include "task.h" #include diff --git a/osal/FreeRTOS/Timekeeper.cpp b/src/fsfw/osal/freertos/Timekeeper.cpp similarity index 91% rename from osal/FreeRTOS/Timekeeper.cpp rename to src/fsfw/osal/freertos/Timekeeper.cpp index d986d832..1b7dc741 100644 --- a/osal/FreeRTOS/Timekeeper.cpp +++ b/src/fsfw/osal/freertos/Timekeeper.cpp @@ -1,6 +1,6 @@ -#include "Timekeeper.h" +#include "fsfw/osal/freertos/Timekeeper.h" -#include +#include "FreeRTOSConfig.h" Timekeeper * Timekeeper::myinstance = nullptr; diff --git a/osal/FreeRTOS/Timekeeper.h b/src/fsfw/osal/freertos/Timekeeper.h similarity index 93% rename from osal/FreeRTOS/Timekeeper.h rename to src/fsfw/osal/freertos/Timekeeper.h index 7d583f7d..d4d0bc07 100644 --- a/osal/FreeRTOS/Timekeeper.h +++ b/src/fsfw/osal/freertos/Timekeeper.h @@ -3,8 +3,8 @@ #include "../../timemanager/Clock.h" -#include -#include +#include "FreeRTOS.h" +#include "task.h" /** diff --git a/osal/host/CMakeLists.txt b/src/fsfw/osal/host/CMakeLists.txt similarity index 100% rename from osal/host/CMakeLists.txt rename to src/fsfw/osal/host/CMakeLists.txt diff --git a/osal/host/Clock.cpp b/src/fsfw/osal/host/Clock.cpp similarity index 73% rename from osal/host/Clock.cpp rename to src/fsfw/osal/host/Clock.cpp index c097f619..0bdcd8f5 100644 --- a/osal/host/Clock.cpp +++ b/src/fsfw/osal/host/Clock.cpp @@ -1,10 +1,12 @@ -#include "../../serviceinterface/ServiceInterface.h" -#include "../../timemanager/Clock.h" +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/timemanager/Clock.h" +#include "fsfw/platform.h" #include -#if defined(WIN32) + +#if defined(PLATFORM_WIN) #include -#elif defined(LINUX) +#elif defined(PLATFORM_UNIX) #include #endif @@ -46,7 +48,7 @@ ReturnValue_t Clock::setClock(const timeval* time) { } ReturnValue_t Clock::getClock_timeval(timeval* time) { -#if defined(WIN32) +#if defined(PLATFORM_WIN) auto now = std::chrono::system_clock::now(); auto secondsChrono = std::chrono::time_point_cast(now); auto epoch = now.time_since_epoch(); @@ -54,7 +56,7 @@ ReturnValue_t Clock::getClock_timeval(timeval* time) { auto fraction = now - secondsChrono; time->tv_usec = std::chrono::duration_cast(fraction).count(); return HasReturnvaluesIF::RETURN_OK; -#elif defined(LINUX) +#elif defined(PLATFORM_UNIX) timespec timeUnix; int status = clock_gettime(CLOCK_REALTIME,&timeUnix); if(status!=0){ @@ -85,14 +87,14 @@ ReturnValue_t Clock::getClock_usecs(uint64_t* time) { timeval Clock::getUptime() { timeval timeval; -#if defined(WIN32) +#if defined(PLATFORM_WIN) auto uptime = std::chrono::milliseconds(GetTickCount64()); auto secondsChrono = std::chrono::duration_cast(uptime); timeval.tv_sec = secondsChrono.count(); auto fraction = uptime - secondsChrono; timeval.tv_usec = std::chrono::duration_cast( fraction).count(); -#elif defined(LINUX) +#elif defined(PLATFORM_UNIX) double uptimeSeconds; if (std::ifstream("/proc/uptime", std::ios::in) >> uptimeSeconds) { @@ -119,7 +121,6 @@ ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) { return HasReturnvaluesIF::RETURN_OK; } - ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) { /* Do some magic with chrono (C++20!) */ /* Right now, the library doesn't have the new features to get the required values yet. @@ -170,71 +171,3 @@ ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) { / 3600.; return HasReturnvaluesIF::RETURN_OK; } - -ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) { - //SHOULDDO: works not for dates in the past (might have less leap seconds) - if (timeMutex == NULL) { - return HasReturnvaluesIF::RETURN_FAILED; - } - - uint16_t leapSeconds; - ReturnValue_t result = getLeapSeconds(&leapSeconds); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - timeval leapSeconds_timeval = { 0, 0 }; - leapSeconds_timeval.tv_sec = leapSeconds; - - //initial offset between UTC and TAI - timeval UTCtoTAI1972 = { 10, 0 }; - - timeval TAItoTT = { 32, 184000 }; - - *tt = utc + leapSeconds_timeval + UTCtoTAI1972 + TAItoTT; - - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) { - if(checkOrCreateClockMutex()!=HasReturnvaluesIF::RETURN_OK){ - return HasReturnvaluesIF::RETURN_FAILED; - } - ReturnValue_t result = timeMutex->lockMutex(); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - leapSeconds = leapSeconds_; - - result = timeMutex->unlockMutex(); - return result; -} - -ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) { - if(timeMutex == nullptr){ - return HasReturnvaluesIF::RETURN_FAILED; - } - ReturnValue_t result = timeMutex->lockMutex(); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - *leapSeconds_ = leapSeconds; - - result = timeMutex->unlockMutex(); - return result; -} - -ReturnValue_t Clock::checkOrCreateClockMutex(){ - if(timeMutex == nullptr){ - MutexFactory* mutexFactory = MutexFactory::instance(); - if (mutexFactory == nullptr) { - return HasReturnvaluesIF::RETURN_FAILED; - } - timeMutex = mutexFactory->createMutex(); - if (timeMutex == nullptr) { - return HasReturnvaluesIF::RETURN_FAILED; - } - } - return HasReturnvaluesIF::RETURN_OK; -} diff --git a/osal/host/FixedTimeslotTask.cpp b/src/fsfw/osal/host/FixedTimeslotTask.cpp similarity index 91% rename from osal/host/FixedTimeslotTask.cpp rename to src/fsfw/osal/host/FixedTimeslotTask.cpp index 89daa278..f9a0588c 100644 --- a/osal/host/FixedTimeslotTask.cpp +++ b/src/fsfw/osal/host/FixedTimeslotTask.cpp @@ -1,18 +1,21 @@ -#include "taskHelpers.h" -#include "../../osal/host/FixedTimeslotTask.h" -#include "../../ipc/MutexFactory.h" -#include "../../osal/host/Mutex.h" -#include "../../osal/host/FixedTimeslotTask.h" -#include "../../serviceinterface/ServiceInterface.h" -#include "../../tasks/ExecutableObjectIF.h" +#include "fsfw/osal/host/taskHelpers.h" +#include "fsfw/osal/host/FixedTimeslotTask.h" +#include "fsfw/osal/host/FixedTimeslotTask.h" + +#include "fsfw/platform.h" +#include "fsfw/ipc/MutexFactory.h" +#include "fsfw/osal/host/Mutex.h" +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/tasks/ExecutableObjectIF.h" #include #include -#if defined(WIN32) +#if defined(PLATFORM_WIN) #include -#include "../windows/winTaskHelpers.h" -#elif defined(LINUX) +#include "fsfw/osal/windows/winTaskHelpers.h" +#elif defined(PLATFORM_UNIX) #include #endif @@ -109,7 +112,7 @@ void FixedTimeslotTask::taskFunctionality() { ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, uint32_t slotTimeMs, int8_t executionStep) { - ExecutableObjectIF* executableObject = objectManager-> + ExecutableObjectIF* executableObject = ObjectManager::instance()-> get(componentId); if (executableObject != nullptr) { pollingSeqTable.addSlot(componentId, slotTimeMs, executionStep, diff --git a/osal/host/FixedTimeslotTask.h b/src/fsfw/osal/host/FixedTimeslotTask.h similarity index 100% rename from osal/host/FixedTimeslotTask.h rename to src/fsfw/osal/host/FixedTimeslotTask.h diff --git a/osal/host/MessageQueue.cpp b/src/fsfw/osal/host/MessageQueue.cpp similarity index 87% rename from osal/host/MessageQueue.cpp rename to src/fsfw/osal/host/MessageQueue.cpp index 41c55a3d..c7bcb042 100644 --- a/osal/host/MessageQueue.cpp +++ b/src/fsfw/osal/host/MessageQueue.cpp @@ -1,9 +1,12 @@ -#include "MessageQueue.h" -#include "QueueMapManager.h" +#include "fsfw/osal/host/MessageQueue.h" +#include "fsfw/osal/host/QueueMapManager.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" -#include "../../ipc/MutexFactory.h" -#include "../../ipc/MutexGuard.h" +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/ipc/MutexFactory.h" +#include "fsfw/ipc/MutexGuard.h" + +#include MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize): messageSize(maxMessageSize), messageDepth(messageDepth) { @@ -11,8 +14,9 @@ MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize): auto result = QueueMapManager::instance()->addMessageQueue(this, &mqId); if(result != HasReturnvaluesIF::RETURN_OK) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "MessageQueue::MessageQueue:" - << " Could not be created" << std::endl; + sif::error << "MessageQueue::MessageQueue: Could not be created" << std::endl; +#else + sif::printError("MessageQueue::MessageQueue: Could not be created\n"); #endif } } @@ -119,15 +123,13 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, QueueMapManager::instance()->getMessageQueue(sendTo)); if(targetQueue == nullptr) { if(not ignoreFault) { - InternalErrorReporterIF* internalErrorReporter = - objectManager->get( - objects::INTERNAL_ERROR_REPORTER); + InternalErrorReporterIF* internalErrorReporter = ObjectManager::instance()-> + get(objects::INTERNAL_ERROR_REPORTER); if (internalErrorReporter != nullptr) { internalErrorReporter->queueMessageNotSent(); } } - // TODO: Better returnvalue - return HasReturnvaluesIF::RETURN_FAILED; + return MessageQueueIF::DESTINATION_INVALID; } if(targetQueue->messageQueue.size() < targetQueue->messageDepth) { MutexGuard mutexLock(targetQueue->queueLock, MutexIF::TimeoutType::WAITING, 20); diff --git a/osal/host/MessageQueue.h b/src/fsfw/osal/host/MessageQueue.h similarity index 96% rename from osal/host/MessageQueue.h rename to src/fsfw/osal/host/MessageQueue.h index e965123d..0bdfd8fc 100644 --- a/osal/host/MessageQueue.h +++ b/src/fsfw/osal/host/MessageQueue.h @@ -1,11 +1,11 @@ #ifndef FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_ #define FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_ -#include "../../internalError/InternalErrorReporterIF.h" -#include "../../ipc/MessageQueueIF.h" -#include "../../ipc/MessageQueueMessage.h" -#include "../../ipc/MutexIF.h" -#include "../../timemanager/Clock.h" +#include "fsfw/internalerror/InternalErrorReporterIF.h" +#include "fsfw/ipc/MessageQueueIF.h" +#include "fsfw/ipc/MessageQueueMessage.h" +#include "fsfw/ipc/MutexIF.h" +#include "fsfw/timemanager/Clock.h" #include #include @@ -217,15 +217,15 @@ private: * @brief The class stores the queue id it got assigned. * If initialization fails, the queue id is set to zero. */ - MessageQueueId_t mqId = 0; + MessageQueueId_t mqId = MessageQueueIF::NO_QUEUE; size_t messageSize = 0; size_t messageDepth = 0; MutexIF* queueLock; bool defaultDestinationSet = false; - MessageQueueId_t defaultDestination = 0; - MessageQueueId_t lastPartner = 0; + MessageQueueId_t defaultDestination = MessageQueueIF::NO_QUEUE; + MessageQueueId_t lastPartner = MessageQueueIF::NO_QUEUE; }; #endif /* FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_ */ diff --git a/osal/host/Mutex.cpp b/src/fsfw/osal/host/Mutex.cpp similarity index 89% rename from osal/host/Mutex.cpp rename to src/fsfw/osal/host/Mutex.cpp index 892028b2..e423ea93 100644 --- a/osal/host/Mutex.cpp +++ b/src/fsfw/osal/host/Mutex.cpp @@ -1,5 +1,5 @@ -#include "Mutex.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "fsfw/osal/host/Mutex.h" +#include "fsfw/serviceinterface/ServiceInterface.h" Mutex::Mutex() {} diff --git a/osal/host/Mutex.h b/src/fsfw/osal/host/Mutex.h similarity index 95% rename from osal/host/Mutex.h rename to src/fsfw/osal/host/Mutex.h index 0bd93c8a..e90ce932 100644 --- a/osal/host/Mutex.h +++ b/src/fsfw/osal/host/Mutex.h @@ -1,7 +1,7 @@ #ifndef FSFW_OSAL_HOSTED_MUTEX_H_ #define FSFW_OSAL_HOSTED_MUTEX_H_ -#include "../../ipc/MutexIF.h" +#include "fsfw/ipc/MutexIF.h" #include diff --git a/osal/host/MutexFactory.cpp b/src/fsfw/osal/host/MutexFactory.cpp similarity index 90% rename from osal/host/MutexFactory.cpp rename to src/fsfw/osal/host/MutexFactory.cpp index f3b98fd1..87287906 100644 --- a/osal/host/MutexFactory.cpp +++ b/src/fsfw/osal/host/MutexFactory.cpp @@ -1,5 +1,5 @@ -#include "../../ipc/MutexFactory.h" -#include "../../osal/host/Mutex.h" +#include "fsfw/osal/host/Mutex.h" +#include "fsfw/ipc/MutexFactory.h" //TODO: Different variant than the lazy loading in QueueFactory. //What's better and why? -> one is on heap the other on bss/data diff --git a/osal/host/PeriodicTask.cpp b/src/fsfw/osal/host/PeriodicTask.cpp similarity index 89% rename from osal/host/PeriodicTask.cpp rename to src/fsfw/osal/host/PeriodicTask.cpp index 09df410f..def3a6cb 100644 --- a/osal/host/PeriodicTask.cpp +++ b/src/fsfw/osal/host/PeriodicTask.cpp @@ -1,18 +1,20 @@ -#include "Mutex.h" -#include "PeriodicTask.h" -#include "taskHelpers.h" +#include "fsfw/osal/host/Mutex.h" +#include "fsfw/osal/host/PeriodicTask.h" +#include "fsfw/osal/host/taskHelpers.h" -#include "../../ipc/MutexFactory.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" -#include "../../tasks/ExecutableObjectIF.h" +#include "fsfw/platform.h" +#include "fsfw/ipc/MutexFactory.h" +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/tasks/ExecutableObjectIF.h" #include #include -#if defined(WIN32) +#if defined(PLATFORM_WIN) #include -#include -#elif defined(__unix__) +#include "fsfw/osal/windows/winTaskHelpers.h" +#elif defined(PLATFORM_UNIX) #include #endif @@ -24,9 +26,9 @@ PeriodicTask::PeriodicTask(const char *name, TaskPriority setPriority, // It is probably possible to set task priorities by using the native // task handles for Windows / Linux mainThread = std::thread(&PeriodicTask::taskEntryPoint, this, this); -#if defined(_WIN32) +#if defined(PLATFORM_WIN) tasks::setTaskPriority(reinterpret_cast(mainThread.native_handle()), setPriority); -#elif defined(__unix__) +#elif defined(PLATFORM_UNIX) // TODO: We could reuse existing code here. #endif tasks::insertTaskName(mainThread.get_id(), taskName); @@ -102,7 +104,7 @@ void PeriodicTask::taskFunctionality() { } ReturnValue_t PeriodicTask::addComponent(object_id_t object) { - ExecutableObjectIF* newObject = objectManager->get( + ExecutableObjectIF* newObject = ObjectManager::instance()->get( object); if (newObject == nullptr) { return HasReturnvaluesIF::RETURN_FAILED; diff --git a/osal/host/PeriodicTask.h b/src/fsfw/osal/host/PeriodicTask.h similarity index 100% rename from osal/host/PeriodicTask.h rename to src/fsfw/osal/host/PeriodicTask.h diff --git a/osal/host/QueueFactory.cpp b/src/fsfw/osal/host/QueueFactory.cpp similarity index 83% rename from osal/host/QueueFactory.cpp rename to src/fsfw/osal/host/QueueFactory.cpp index 1a679c96..466bb33b 100644 --- a/osal/host/QueueFactory.cpp +++ b/src/fsfw/osal/host/QueueFactory.cpp @@ -1,10 +1,9 @@ +#include "fsfw/osal/host/MessageQueue.h" -#include "MessageQueue.h" - -#include "../../ipc/MessageQueueSenderIF.h" -#include "../../ipc/MessageQueueMessageIF.h" -#include "../../ipc/QueueFactory.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "fsfw/ipc/MessageQueueSenderIF.h" +#include "fsfw/ipc/MessageQueueMessageIF.h" +#include "fsfw/ipc/QueueFactory.h" +#include "fsfw/serviceinterface/ServiceInterface.h" #include diff --git a/src/fsfw/osal/host/QueueMapManager.cpp b/src/fsfw/osal/host/QueueMapManager.cpp new file mode 100644 index 00000000..58575cf6 --- /dev/null +++ b/src/fsfw/osal/host/QueueMapManager.cpp @@ -0,0 +1,69 @@ +#include "fsfw/osal/host/QueueMapManager.h" + +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/ipc/MutexFactory.h" +#include "fsfw/ipc/MutexGuard.h" + +QueueMapManager* QueueMapManager::mqManagerInstance = nullptr; + +QueueMapManager::QueueMapManager() { + mapLock = MutexFactory::instance()->createMutex(); +} + +QueueMapManager::~QueueMapManager() { + MutexFactory::instance()->deleteMutex(mapLock); +} + +QueueMapManager* QueueMapManager::instance() { + if (mqManagerInstance == nullptr){ + mqManagerInstance = new QueueMapManager(); + } + return QueueMapManager::mqManagerInstance; +} + +ReturnValue_t QueueMapManager::addMessageQueue( + MessageQueueIF* queueToInsert, MessageQueueId_t* id) { + MutexGuard lock(mapLock); + uint32_t currentId = queueCounter; + queueCounter++; + if(currentId == MessageQueueIF::NO_QUEUE) { + // Skip the NO_QUEUE value + currentId = queueCounter; + queueCounter++; + } + auto returnPair = queueMap.emplace(currentId, queueToInsert); + if(not returnPair.second) { + /* This should never happen for the atomic variable. */ +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "QueueMapManager::addMessageQueue This ID is already " + "inside the map!" << std::endl; +#else + sif::printError("QueueMapManager::addMessageQueue This ID is already " + "inside the map!\n"); +#endif + return HasReturnvaluesIF::RETURN_FAILED; + } + if (id != nullptr) { + *id = currentId; + } + return HasReturnvaluesIF::RETURN_OK; +} + +MessageQueueIF* QueueMapManager::getMessageQueue( + MessageQueueId_t messageQueueId) const { + auto queueIter = queueMap.find(messageQueueId); + if(queueIter != queueMap.end()) { + return queueIter->second; + } + else { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "QueueMapManager::getQueueHandle: The ID " << messageQueueId << + " does not exists in the map!" << std::endl; +#else + sif::printWarning("QueueMapManager::getQueueHandle: The ID %d does not exist in the map!\n", + messageQueueId); +#endif + } + return nullptr; +} + diff --git a/src/fsfw/osal/host/QueueMapManager.h b/src/fsfw/osal/host/QueueMapManager.h new file mode 100644 index 00000000..2dd2a01d --- /dev/null +++ b/src/fsfw/osal/host/QueueMapManager.h @@ -0,0 +1,52 @@ +#ifndef FSFW_OSAL_HOST_QUEUEMAPMANAGER_H_ +#define FSFW_OSAL_HOST_QUEUEMAPMANAGER_H_ + +#include "../../ipc/MessageQueueSenderIF.h" +#include "../../osal/host/MessageQueue.h" +#include +#include + +using QueueMap = std::unordered_map; + + +/** + * An internal map to map message queue IDs to message queues. + * This propably should be a singleton.. + */ +class QueueMapManager { +public: + + + //! Returns the single instance of QueueMapManager. + static QueueMapManager* instance(); + + /** + * Insert a message queue into the map and returns a message queue ID + * @param queue The message queue to insert. + * @param id The passed value will be set unless a nullptr is passed + * @return + */ + ReturnValue_t addMessageQueue(MessageQueueIF* queue, MessageQueueId_t* + id = nullptr); + /** + * Get the message queue handle by providing a message queue ID. Returns nullptr + * if the queue ID is not contained inside the internal map. + * @param messageQueueId + * @return + */ + MessageQueueIF* getMessageQueue(MessageQueueId_t messageQueueId) const; + +private: + //! External instantiation is forbidden. Constructor still required for singleton instantiation. + QueueMapManager(); + ~QueueMapManager(); + + uint32_t queueCounter = MessageQueueIF::NO_QUEUE + 1; + MutexIF* mapLock; + QueueMap queueMap; + static QueueMapManager* mqManagerInstance; +}; + + + +#endif /* FSFW_OSAL_HOST_QUEUEMAPMANAGER_H_ */ diff --git a/osal/host/SemaphoreFactory.cpp b/src/fsfw/osal/host/SemaphoreFactory.cpp similarity index 91% rename from osal/host/SemaphoreFactory.cpp rename to src/fsfw/osal/host/SemaphoreFactory.cpp index 530b3e45..3ea12877 100644 --- a/osal/host/SemaphoreFactory.cpp +++ b/src/fsfw/osal/host/SemaphoreFactory.cpp @@ -1,5 +1,5 @@ -#include "../../tasks/SemaphoreFactory.h" -#include "../../serviceinterface/ServiceInterface.h" +#include "fsfw/tasks/SemaphoreFactory.h" +#include "fsfw/serviceinterface/ServiceInterface.h" SemaphoreFactory* SemaphoreFactory::factoryInstance = nullptr; diff --git a/osal/host/TaskFactory.cpp b/src/fsfw/osal/host/TaskFactory.cpp similarity index 84% rename from osal/host/TaskFactory.cpp rename to src/fsfw/osal/host/TaskFactory.cpp index 71d0bf8b..ad59bd1a 100644 --- a/osal/host/TaskFactory.cpp +++ b/src/fsfw/osal/host/TaskFactory.cpp @@ -1,10 +1,11 @@ -#include "taskHelpers.h" -#include "../../tasks/TaskFactory.h" -#include "../../osal/host/FixedTimeslotTask.h" -#include "../../osal/host/PeriodicTask.h" -#include "../../returnvalues/HasReturnvaluesIF.h" -#include "../../tasks/PeriodicTaskIF.h" -#include "../../serviceinterface/ServiceInterface.h" +#include "fsfw/osal/host/FixedTimeslotTask.h" +#include "fsfw/osal/host/PeriodicTask.h" +#include "fsfw/osal/host/taskHelpers.h" + +#include "fsfw/tasks/TaskFactory.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" +#include "fsfw/tasks/PeriodicTaskIF.h" +#include "fsfw/serviceinterface/ServiceInterface.h" #include diff --git a/osal/host/taskHelpers.cpp b/src/fsfw/osal/host/taskHelpers.cpp similarity index 94% rename from osal/host/taskHelpers.cpp rename to src/fsfw/osal/host/taskHelpers.cpp index be4c29ad..a7de76d9 100644 --- a/osal/host/taskHelpers.cpp +++ b/src/fsfw/osal/host/taskHelpers.cpp @@ -1,4 +1,4 @@ -#include "taskHelpers.h" +#include "fsfw/osal/host/taskHelpers.h" #include #include diff --git a/osal/host/taskHelpers.h b/src/fsfw/osal/host/taskHelpers.h similarity index 100% rename from osal/host/taskHelpers.h rename to src/fsfw/osal/host/taskHelpers.h diff --git a/src/fsfw/osal/linux/BinarySemaphore.cpp b/src/fsfw/osal/linux/BinarySemaphore.cpp new file mode 100644 index 00000000..3ef04cf0 --- /dev/null +++ b/src/fsfw/osal/linux/BinarySemaphore.cpp @@ -0,0 +1,162 @@ +#include "fsfw/osal/linux/BinarySemaphore.h" +#include "fsfw/osal/linux/unixUtility.h" +#include "fsfw/serviceinterface/ServiceInterfacePrinter.h" +#include "fsfw/serviceinterface/ServiceInterfaceStream.h" + +#include +#include +#include + + +BinarySemaphore::BinarySemaphore() { + // Using unnamed semaphores for now + initSemaphore(); +} + +BinarySemaphore::~BinarySemaphore() { + sem_destroy(&handle); +} + +BinarySemaphore::BinarySemaphore(BinarySemaphore&& s) { + initSemaphore(); +} + +BinarySemaphore& BinarySemaphore::operator =( + BinarySemaphore&& s) { + initSemaphore(); + return * this; +} + +ReturnValue_t BinarySemaphore::acquire(TimeoutType timeoutType, + uint32_t timeoutMs) { + int result = 0; + if(timeoutType == TimeoutType::POLLING) { + result = sem_trywait(&handle); + } + else if(timeoutType == TimeoutType::BLOCKING) { + result = sem_wait(&handle); + } + else if(timeoutType == TimeoutType::WAITING){ + timespec timeOut; + clock_gettime(CLOCK_REALTIME, &timeOut); + uint64_t nseconds = timeOut.tv_sec * 1000000000 + timeOut.tv_nsec; + nseconds += timeoutMs * 1000000; + timeOut.tv_sec = nseconds / 1000000000; + timeOut.tv_nsec = nseconds - timeOut.tv_sec * 1000000000; + result = sem_timedwait(&handle, &timeOut); + if(result != 0 and errno == EINVAL) { + utility::printUnixErrorGeneric(CLASS_NAME, "acquire", "sem_timedwait"); + } + } + if(result == 0) { + return HasReturnvaluesIF::RETURN_OK; + } + + switch(errno) { + case(EAGAIN): + // Operation could not be performed without blocking (for sem_trywait) + case(ETIMEDOUT): { + // Semaphore is 0 + utility::printUnixErrorGeneric(CLASS_NAME, "acquire", "ETIMEDOUT"); + return SemaphoreIF::SEMAPHORE_TIMEOUT; + } + case(EINVAL): { + // Semaphore invalid + utility::printUnixErrorGeneric(CLASS_NAME, "acquire", "EINVAL"); + return SemaphoreIF::SEMAPHORE_INVALID; + } + case(EINTR): { + // Call was interrupted by signal handler + utility::printUnixErrorGeneric(CLASS_NAME, "acquire", "EINTR"); + return HasReturnvaluesIF::RETURN_FAILED; + } + default: + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +ReturnValue_t BinarySemaphore::release() { + return BinarySemaphore::release(&this->handle); +} + +ReturnValue_t BinarySemaphore::release(sem_t *handle) { + ReturnValue_t countResult = checkCount(handle, 1); + if(countResult != HasReturnvaluesIF::RETURN_OK) { + return countResult; + } + + int result = sem_post(handle); + if(result == 0) { + return HasReturnvaluesIF::RETURN_OK; + } + + switch(errno) { + case(EINVAL): { + // Semaphore invalid + utility::printUnixErrorGeneric(CLASS_NAME, "release", "EINVAL"); + return SemaphoreIF::SEMAPHORE_INVALID; + } + case(EOVERFLOW): { + // SEM_MAX_VALUE overflow. This should never happen + utility::printUnixErrorGeneric(CLASS_NAME, "release", "EOVERFLOW"); + return HasReturnvaluesIF::RETURN_FAILED; + } + default: + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +uint8_t BinarySemaphore::getSemaphoreCounter() const { + // And another ugly cast :-D + return getSemaphoreCounter(const_cast(&this->handle)); +} + +uint8_t BinarySemaphore::getSemaphoreCounter(sem_t *handle) { + int value = 0; + int result = sem_getvalue(handle, &value); + if (result == 0) { + return value; + } + else if(result != 0 and errno == EINVAL) { + // Could be called from interrupt, use lightweight printf + sif::printError("BinarySemaphore::getSemaphoreCounter: " + "Invalid semaphore\n"); + return 0; + } + else { + // This should never happen. + return 0; + } +} + +void BinarySemaphore::initSemaphore(uint8_t initCount) { + auto result = sem_init(&handle, true, initCount); + if(result == -1) { + switch(errno) { + case(EINVAL): { + utility::printUnixErrorGeneric(CLASS_NAME, "initSemaphore", "EINVAL"); + break; + } + case(ENOSYS): { + // System does not support process-shared semaphores + utility::printUnixErrorGeneric(CLASS_NAME, "initSemaphore", "ENOSYS"); + break; + } + } + } +} + +ReturnValue_t BinarySemaphore::checkCount(sem_t* handle, uint8_t maxCount) { + int value = getSemaphoreCounter(handle); + if(value >= maxCount) { + if(maxCount == 1 and value > 1) { + // Binary Semaphore special case. + // This is a config error use lightweight printf is this is called + // from an interrupt + printf("BinarySemaphore::release: Value of binary semaphore greater than 1!\n"); + return HasReturnvaluesIF::RETURN_FAILED; + } + return SemaphoreIF::SEMAPHORE_NOT_OWNED; + } + return HasReturnvaluesIF::RETURN_OK; +} diff --git a/osal/linux/BinarySemaphore.h b/src/fsfw/osal/linux/BinarySemaphore.h similarity index 97% rename from osal/linux/BinarySemaphore.h rename to src/fsfw/osal/linux/BinarySemaphore.h index e9bb8bb6..2e6ded15 100644 --- a/osal/linux/BinarySemaphore.h +++ b/src/fsfw/osal/linux/BinarySemaphore.h @@ -76,6 +76,7 @@ public: static ReturnValue_t checkCount(sem_t* handle, uint8_t maxCount); protected: sem_t handle; + static constexpr const char* CLASS_NAME = "BinarySemaphore"; }; #endif /* FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ */ diff --git a/osal/linux/CMakeLists.txt b/src/fsfw/osal/linux/CMakeLists.txt similarity index 96% rename from osal/linux/CMakeLists.txt rename to src/fsfw/osal/linux/CMakeLists.txt index 332fe2f4..41800764 100644 --- a/osal/linux/CMakeLists.txt +++ b/src/fsfw/osal/linux/CMakeLists.txt @@ -13,8 +13,8 @@ target_sources(${LIB_FSFW_NAME} QueueFactory.cpp SemaphoreFactory.cpp TaskFactory.cpp - Timer.cpp tcpipHelpers.cpp + unixUtility.cpp ) find_package(Threads REQUIRED) diff --git a/osal/linux/Clock.cpp b/src/fsfw/osal/linux/Clock.cpp similarity index 68% rename from osal/linux/Clock.cpp rename to src/fsfw/osal/linux/Clock.cpp index 35cbfae0..d79c72be 100644 --- a/osal/linux/Clock.cpp +++ b/src/fsfw/osal/linux/Clock.cpp @@ -1,5 +1,5 @@ -#include "../../serviceinterface/ServiceInterfaceStream.h" -#include "../../timemanager/Clock.h" +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/timemanager/Clock.h" #include #include @@ -153,71 +153,3 @@ ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) { / 3600.; return HasReturnvaluesIF::RETURN_OK; } - -ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) { - //SHOULDDO: works not for dates in the past (might have less leap seconds) - if (timeMutex == NULL) { - return HasReturnvaluesIF::RETURN_FAILED; - } - - uint16_t leapSeconds; - ReturnValue_t result = getLeapSeconds(&leapSeconds); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - timeval leapSeconds_timeval = { 0, 0 }; - leapSeconds_timeval.tv_sec = leapSeconds; - - //initial offset between UTC and TAI - timeval UTCtoTAI1972 = { 10, 0 }; - - timeval TAItoTT = { 32, 184000 }; - - *tt = utc + leapSeconds_timeval + UTCtoTAI1972 + TAItoTT; - - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) { - if(checkOrCreateClockMutex()!=HasReturnvaluesIF::RETURN_OK){ - return HasReturnvaluesIF::RETURN_FAILED; - } - ReturnValue_t result = timeMutex->lockMutex(MutexIF::TimeoutType::BLOCKING); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - leapSeconds = leapSeconds_; - - result = timeMutex->unlockMutex(); - return result; -} - -ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) { - if(timeMutex==NULL){ - return HasReturnvaluesIF::RETURN_FAILED; - } - ReturnValue_t result = timeMutex->lockMutex(MutexIF::TimeoutType::BLOCKING); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - *leapSeconds_ = leapSeconds; - - result = timeMutex->unlockMutex(); - return result; -} - -ReturnValue_t Clock::checkOrCreateClockMutex(){ - if(timeMutex == nullptr){ - MutexFactory* mutexFactory = MutexFactory::instance(); - if (mutexFactory == nullptr) { - return HasReturnvaluesIF::RETURN_FAILED; - } - timeMutex = mutexFactory->createMutex(); - if (timeMutex == nullptr) { - return HasReturnvaluesIF::RETURN_FAILED; - } - } - return HasReturnvaluesIF::RETURN_OK; -} diff --git a/src/fsfw/osal/linux/CountingSemaphore.cpp b/src/fsfw/osal/linux/CountingSemaphore.cpp new file mode 100644 index 00000000..cc2117f3 --- /dev/null +++ b/src/fsfw/osal/linux/CountingSemaphore.cpp @@ -0,0 +1,70 @@ +#include "fsfw/osal/linux/CountingSemaphore.h" +#include "fsfw/osal/linux/unixUtility.h" + +#include "fsfw/serviceinterface/ServiceInterface.h" + +#include + +CountingSemaphore::CountingSemaphore(const uint8_t maxCount, uint8_t initCount): + maxCount(maxCount), initCount(initCount) { + if(initCount > maxCount) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "CountingSemaphoreUsingTask: Max count bigger than " + "intial cout. Setting initial count to max count" << std::endl; +#else + sif::printWarning("CountingSemaphoreUsingTask: Max count bigger than " + "intial cout. Setting initial count to max count\n"); +#endif + initCount = maxCount; + } + + initSemaphore(initCount); +} + +CountingSemaphore::CountingSemaphore(CountingSemaphore&& other): + maxCount(other.maxCount), initCount(other.initCount) { + initSemaphore(initCount); +} + +CountingSemaphore& CountingSemaphore::operator =( + CountingSemaphore&& other) { + initSemaphore(other.initCount); + return * this; +} + +ReturnValue_t CountingSemaphore::release() { + ReturnValue_t result = checkCount(&handle, maxCount); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + return CountingSemaphore::release(&this->handle); +} + +ReturnValue_t CountingSemaphore::release(sem_t* handle) { + int result = sem_post(handle); + if(result == 0) { + return HasReturnvaluesIF::RETURN_OK; + } + + switch(errno) { + case(EINVAL): { + // Semaphore invalid + utility::printUnixErrorGeneric("CountingSemaphore", "release", "EINVAL"); + return SemaphoreIF::SEMAPHORE_INVALID; + } + + case(EOVERFLOW): { + // SEM_MAX_VALUE overflow. This should never happen + utility::printUnixErrorGeneric("CountingSemaphore", "release", "EOVERFLOW"); + return SemaphoreIF::SEMAPHORE_INVALID; + } + + default: + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +uint8_t CountingSemaphore::getMaxCount() const { + return maxCount; +} + diff --git a/osal/linux/CountingSemaphore.h b/src/fsfw/osal/linux/CountingSemaphore.h similarity index 100% rename from osal/linux/CountingSemaphore.h rename to src/fsfw/osal/linux/CountingSemaphore.h diff --git a/osal/linux/FixedTimeslotTask.cpp b/src/fsfw/osal/linux/FixedTimeslotTask.cpp similarity index 92% rename from osal/linux/FixedTimeslotTask.cpp rename to src/fsfw/osal/linux/FixedTimeslotTask.cpp index a545eeb7..f6648299 100644 --- a/osal/linux/FixedTimeslotTask.cpp +++ b/src/fsfw/osal/linux/FixedTimeslotTask.cpp @@ -1,5 +1,7 @@ -#include "FixedTimeslotTask.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "fsfw/osal/linux/FixedTimeslotTask.h" + +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/serviceinterface/ServiceInterface.h" #include @@ -40,7 +42,7 @@ uint32_t FixedTimeslotTask::getPeriodMs() const { ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, uint32_t slotTimeMs, int8_t executionStep) { ExecutableObjectIF* executableObject = - objectManager->get(componentId); + ObjectManager::instance()->get(componentId); if (executableObject != nullptr) { pst.addSlot(componentId, slotTimeMs, executionStep, executableObject,this); diff --git a/osal/linux/FixedTimeslotTask.h b/src/fsfw/osal/linux/FixedTimeslotTask.h similarity index 100% rename from osal/linux/FixedTimeslotTask.h rename to src/fsfw/osal/linux/FixedTimeslotTask.h diff --git a/osal/linux/InternalErrorCodes.cpp b/src/fsfw/osal/linux/InternalErrorCodes.cpp similarity index 84% rename from osal/linux/InternalErrorCodes.cpp rename to src/fsfw/osal/linux/InternalErrorCodes.cpp index a01cc72a..14274535 100644 --- a/osal/linux/InternalErrorCodes.cpp +++ b/src/fsfw/osal/linux/InternalErrorCodes.cpp @@ -1,4 +1,4 @@ -#include "../../osal/InternalErrorCodes.h" +#include "fsfw/osal/InternalErrorCodes.h" ReturnValue_t InternalErrorCodes::translate(uint8_t code) { //TODO This class can be removed diff --git a/src/fsfw/osal/linux/MessageQueue.cpp b/src/fsfw/osal/linux/MessageQueue.cpp new file mode 100644 index 00000000..b068c04f --- /dev/null +++ b/src/fsfw/osal/linux/MessageQueue.cpp @@ -0,0 +1,392 @@ +#include "fsfw/osal/linux/MessageQueue.h" +#include "fsfw/osal/linux/unixUtility.h" + +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/objectmanager/ObjectManager.h" + +#include + +#include /* For O_* constants */ +#include /* For mode constants */ +#include +#include + + +MessageQueue::MessageQueue(uint32_t messageDepth, size_t maxMessageSize): + id(MessageQueueIF::NO_QUEUE),lastPartner(MessageQueueIF::NO_QUEUE), + defaultDestination(MessageQueueIF::NO_QUEUE), maxMessageSize(maxMessageSize) { + mq_attr attributes; + this->id = 0; + //Set attributes + attributes.mq_curmsgs = 0; + attributes.mq_maxmsg = messageDepth; + attributes.mq_msgsize = maxMessageSize; + attributes.mq_flags = 0; //Flags are ignored on Linux during mq_open + //Set the name of the queue. The slash is mandatory! + sprintf(name, "/FSFW_MQ%u\n", queueCounter++); + + // Create a nonblocking queue if the name is available (the queue is read + // and writable for the owner as well as the group) + int oflag = O_NONBLOCK | O_RDWR | O_CREAT | O_EXCL; + mode_t mode = S_IWUSR | S_IREAD | S_IWGRP | S_IRGRP | S_IROTH | S_IWOTH; + mqd_t tempId = mq_open(name, oflag, mode, &attributes); + if (tempId == -1) { + handleOpenError(&attributes, messageDepth); + } + else { + //Successful mq_open call + this->id = tempId; + } +} + +MessageQueue::~MessageQueue() { + int status = mq_close(this->id); + if(status != 0){ + utility::printUnixErrorGeneric(CLASS_NAME, "~MessageQueue", "close"); + } + status = mq_unlink(name); + if(status != 0){ + utility::printUnixErrorGeneric(CLASS_NAME, "~MessageQueue", "unlink"); + } +} + +ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo, + MessageQueueMessageIF* message, bool ignoreFault) { + return sendMessageFrom(sendTo, message, this->getId(), false); +} + +ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessageIF* message) { + return sendToDefaultFrom(message, this->getId()); +} + +ReturnValue_t MessageQueue::reply(MessageQueueMessageIF* message) { + if (this->lastPartner != 0) { + return sendMessageFrom(this->lastPartner, message, this->getId()); + } else { + return NO_REPLY_PARTNER; + } +} + +ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message, + MessageQueueId_t* receivedFrom) { + ReturnValue_t status = this->receiveMessage(message); + *receivedFrom = this->lastPartner; + return status; +} + +ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) { + if(message == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "MessageQueue::receiveMessage: Message is " + "nullptr!" << std::endl; +#endif + return HasReturnvaluesIF::RETURN_FAILED; + } + + if(message->getMaximumMessageSize() < maxMessageSize) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "MessageQueue::receiveMessage: Message size " + << message->getMaximumMessageSize() + << " too small to receive data!" << std::endl; +#endif + return HasReturnvaluesIF::RETURN_FAILED; + } + + unsigned int messagePriority = 0; + int status = mq_receive(id,reinterpret_cast(message->getBuffer()), + message->getMaximumMessageSize(),&messagePriority); + if (status > 0) { + this->lastPartner = message->getSender(); + //Check size of incoming message. + if (message->getMessageSize() < message->getMinimumMessageSize()) { + return HasReturnvaluesIF::RETURN_FAILED; + } + return HasReturnvaluesIF::RETURN_OK; + } + else if (status==0) { + //Success but no message received + return MessageQueueIF::EMPTY; + } + else { + //No message was received. Keep lastPartner anyway, I might send + //something later. But still, delete packet content. + memset(message->getData(), 0, message->getMaximumDataSize()); + switch(errno){ + case EAGAIN: + //O_NONBLOCK or MQ_NONBLOCK was set and there are no messages + //currently on the specified queue. + return MessageQueueIF::EMPTY; + case EBADF: { + //mqdes doesn't represent a valid queue open for reading. + utility::printUnixErrorGeneric(CLASS_NAME, "receiveMessage", "EBADF"); + break; + } + case EINVAL: { + /* + * This value indicates one of the following: + * - The pointer to the buffer for storing the received message, + * msg_ptr, is NULL. + * - The number of bytes requested, msg_len is less than zero. + * - msg_len is anything other than the mq_msgsize of the specified + * queue, and the QNX extended option MQ_READBUF_DYNAMIC hasn't + * been set in the queue's mq_flags. + */ + utility::printUnixErrorGeneric(CLASS_NAME, "receiveMessage", "EINVAL"); + break; + } + case EMSGSIZE: { + /* + * This value indicates one of the following: + * - the QNX extended option MQ_READBUF_DYNAMIC hasn't been set, + * and the given msg_len is shorter than the mq_msgsize for + * the given queue. + * - the extended option MQ_READBUF_DYNAMIC has been set, but the + * given msg_len is too short for the message that would have + * been received. + */ + utility::printUnixErrorGeneric(CLASS_NAME, "receiveMessage", "EMSGSIZE"); + break; + } + + case EINTR: { + //The operation was interrupted by a signal. + utility::printUnixErrorGeneric(CLASS_NAME, "receiveMessage", "EINTR"); + break; + } + case ETIMEDOUT: { + //The operation was interrupted by a signal. + utility::printUnixErrorGeneric(CLASS_NAME, "receiveMessage", "ETIMEDOUT"); + break; + } + + default: + return HasReturnvaluesIF::RETURN_FAILED; + } + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +MessageQueueId_t MessageQueue::getLastPartner() const { + return this->lastPartner; +} + +ReturnValue_t MessageQueue::flush(uint32_t* count) { + mq_attr attrib; + int status = mq_getattr(id,&attrib); + if(status != 0){ + switch(errno){ + case EBADF: + //mqdes doesn't represent a valid message queue. + utility::printUnixErrorGeneric(CLASS_NAME, "flush", "EBADF"); + break; + /*NO BREAK*/ + case EINVAL: + //mq_attr is NULL + utility::printUnixErrorGeneric(CLASS_NAME, "flush", "EINVAL"); + break; + default: + return HasReturnvaluesIF::RETURN_FAILED; + } + return HasReturnvaluesIF::RETURN_FAILED; + } + *count = attrib.mq_curmsgs; + attrib.mq_curmsgs = 0; + status = mq_setattr(id,&attrib,NULL); + if(status != 0){ + switch(errno) { + case EBADF: + //mqdes doesn't represent a valid message queue. + utility::printUnixErrorGeneric(CLASS_NAME, "flush", "EBADF"); + break; + case EINVAL: + /* + * This value indicates one of the following: + * - mq_attr is NULL. + * - MQ_MULT_NOTIFY had been set for this queue, and the given + * mq_flags includes a 0 in the MQ_MULT_NOTIFY bit. Once + * MQ_MULT_NOTIFY has been turned on, it may never be turned off. + */ + utility::printUnixErrorGeneric(CLASS_NAME, "flush", "EINVAL"); + break; + default: + return HasReturnvaluesIF::RETURN_FAILED; + } + return HasReturnvaluesIF::RETURN_FAILED; + } + return HasReturnvaluesIF::RETURN_OK; +} + +MessageQueueId_t MessageQueue::getId() const { + return this->id; +} + +void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) { + this->defaultDestination = defaultDestination; +} + +ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessageIF* message, + MessageQueueId_t sentFrom, bool ignoreFault) { + return sendMessageFrom(defaultDestination, message, sentFrom, ignoreFault); +} + + +ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, + MessageQueueMessageIF* message, MessageQueueId_t sentFrom, + bool ignoreFault) { + return sendMessageFromMessageQueue(sendTo,message, sentFrom,ignoreFault); + +} + +MessageQueueId_t MessageQueue::getDefaultDestination() const { + return this->defaultDestination; +} + +bool MessageQueue::isDefaultDestinationSet() const { + return (defaultDestination != NO_QUEUE); +} + +uint16_t MessageQueue::queueCounter = 0; + +ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, + MessageQueueMessageIF *message, MessageQueueId_t sentFrom, + bool ignoreFault) { + if(message == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "MessageQueue::sendMessageFromMessageQueue: Message is nullptr!" << std::endl; +#else + sif::printError("MessageQueue::sendMessageFromMessageQueue: Message is nullptr!\n"); +#endif + return HasReturnvaluesIF::RETURN_FAILED; + } + + message->setSender(sentFrom); + int result = mq_send(sendTo, + reinterpret_cast(message->getBuffer()), + message->getMessageSize(),0); + + //TODO: Check if we're in ISR. + if (result != 0) { + if(!ignoreFault){ + InternalErrorReporterIF* internalErrorReporter = ObjectManager::instance()-> + get(objects::INTERNAL_ERROR_REPORTER); + if (internalErrorReporter != NULL) { + internalErrorReporter->queueMessageNotSent(); + } + } + switch(errno){ + case EAGAIN: + //The O_NONBLOCK flag was set when opening the queue, or the + //MQ_NONBLOCK flag was set in its attributes, and the + //specified queue is full. + return MessageQueueIF::FULL; + case EBADF: { + //mq_des doesn't represent a valid message queue descriptor, + //or mq_des wasn't opened for writing. + + utility::printUnixErrorGeneric(CLASS_NAME, "sendMessageFromMessageQueue", "EBADF"); +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "mq_send to: " << sendTo << " sent from " + << sentFrom << "failed" << std::endl; +#else + sif::printWarning("mq_send to: %d sent from %d failed\n", sendTo, sentFrom); +#endif + return DESTINATION_INVALID; + } + case EINTR: + //The call was interrupted by a signal. + utility::printUnixErrorGeneric(CLASS_NAME, "sendMessageFromMessageQueue", "EINTR"); + break; + case EINVAL: + /* + * This value indicates one of the following: + * - msg_ptr is NULL. + * - msg_len is negative. + * - msg_prio is greater than MQ_PRIO_MAX. + * - msg_prio is less than 0. + * - MQ_PRIO_RESTRICT is set in the mq_attr of mq_des, and + * msg_prio is greater than the priority of the calling process. + */ + utility::printUnixErrorGeneric(CLASS_NAME, "sendMessageFromMessageQueue", "EINVAL"); + break; + case EMSGSIZE: + // The msg_len is greater than the msgsize associated with + //the specified queue. + utility::printUnixErrorGeneric(CLASS_NAME, "sendMessageFromMessageQueue", "EMSGSIZE"); + break; + default: + return HasReturnvaluesIF::RETURN_FAILED; + } + return HasReturnvaluesIF::RETURN_FAILED; + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t MessageQueue::handleOpenError(mq_attr* attributes, + uint32_t messageDepth) { + switch(errno) { + case(EINVAL): { + utility::printUnixErrorGeneric(CLASS_NAME, "MessageQueue", "EINVAL"); + size_t defaultMqMaxMsg = 0; + // Not POSIX conformant, but should work for all UNIX systems. + // Just an additional helpful printout :-) + if(std::ifstream("/proc/sys/fs/mqueue/msg_max",std::ios::in) >> + defaultMqMaxMsg and defaultMqMaxMsg < messageDepth) { + /* + See: https://www.man7.org/linux/man-pages/man3/mq_open.3.html + This happens if the msg_max value is not large enough + It is ignored if the executable is run in privileged mode. + Run the unlockRealtime script or grant the mode manually by using: + sudo setcap 'CAP_SYS_RESOURCE=+ep' + + Persistent solution for session: + echo | sudo tee /proc/sys/fs/mqueue/msg_max + + Permanent solution: + sudo nano /etc/sysctl.conf + Append at end: fs/mqueue/msg_max = + Apply changes with: sudo sysctl -p + */ +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "MessageQueue::MessageQueue: Default MQ size " << defaultMqMaxMsg << + " is too small for requested size " << messageDepth << std::endl; + sif::error << "This error can be fixed by setting the maximum " + "allowed message size higher!" << std::endl; +#else + sif::printError("MessageQueue::MessageQueue: Default MQ size %d is too small for" + "requested size %d\n"); + sif::printError("This error can be fixes by setting the maximum allowed" + "message size higher!\n"); +#endif + } + break; + } + case(EEXIST): { + // An error occured during open. + // We need to distinguish if it is caused by an already created queue + // There's another queue with the same name + // We unlink the other queue + int status = mq_unlink(name); + if (status != 0) { + utility::printUnixErrorGeneric(CLASS_NAME, "MessageQueue", "EEXIST"); + } + else { + // Successful unlinking, try to open again + mqd_t tempId = mq_open(name, + O_NONBLOCK | O_RDWR | O_CREAT | O_EXCL, + S_IWUSR | S_IREAD | S_IWGRP | S_IRGRP, attributes); + if (tempId != -1) { + //Successful mq_open + this->id = tempId; + return HasReturnvaluesIF::RETURN_OK; + } + } + break; + } + + default: { + // Failed either the first time or the second time + utility::printUnixErrorGeneric(CLASS_NAME, "MessageQueue", "Unknown"); + } + } + return HasReturnvaluesIF::RETURN_FAILED; +} diff --git a/osal/linux/MessageQueue.h b/src/fsfw/osal/linux/MessageQueue.h similarity index 96% rename from osal/linux/MessageQueue.h rename to src/fsfw/osal/linux/MessageQueue.h index 239bbbdb..cf0ac10c 100644 --- a/osal/linux/MessageQueue.h +++ b/src/fsfw/osal/linux/MessageQueue.h @@ -1,9 +1,9 @@ #ifndef FSFW_OSAL_LINUX_MESSAGEQUEUE_H_ #define FSFW_OSAL_LINUX_MESSAGEQUEUE_H_ -#include "../../internalError/InternalErrorReporterIF.h" -#include "../../ipc/MessageQueueIF.h" -#include "../../ipc/MessageQueueMessage.h" +#include "fsfw/internalerror/InternalErrorReporterIF.h" +#include "fsfw/ipc/MessageQueueIF.h" +#include "fsfw/ipc/MessageQueueMessage.h" #include /** @@ -181,7 +181,8 @@ private: static uint16_t queueCounter; const size_t maxMessageSize; - ReturnValue_t handleError(mq_attr* attributes, uint32_t messageDepth); + static constexpr const char* CLASS_NAME = "MessageQueue"; + ReturnValue_t handleOpenError(mq_attr* attributes, uint32_t messageDepth); }; #endif /* FSFW_OSAL_LINUX_MESSAGEQUEUE_H_ */ diff --git a/osal/linux/Mutex.cpp b/src/fsfw/osal/linux/Mutex.cpp similarity index 81% rename from osal/linux/Mutex.cpp rename to src/fsfw/osal/linux/Mutex.cpp index c642b132..7391c6b5 100644 --- a/osal/linux/Mutex.cpp +++ b/src/fsfw/osal/linux/Mutex.cpp @@ -1,43 +1,34 @@ -#include "Mutex.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" -#include "../../timemanager/Clock.h" - -uint8_t Mutex::count = 0; +#include "fsfw/osal/linux/Mutex.h" +#include "fsfw/osal/linux/unixUtility.h" +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/timemanager/Clock.h" #include #include +uint8_t Mutex::count = 0; + Mutex::Mutex() { pthread_mutexattr_t mutexAttr; int status = pthread_mutexattr_init(&mutexAttr); if (status != 0) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "Mutex: Attribute init failed with: " << strerror(status) << std::endl; -#endif + utility::printUnixErrorGeneric("Mutex", "Mutex", "pthread_mutexattr_init"); } status = pthread_mutexattr_setprotocol(&mutexAttr, PTHREAD_PRIO_INHERIT); if (status != 0) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "Mutex: Attribute set PRIO_INHERIT failed with: " << strerror(status) - << std::endl; -#endif + utility::printUnixErrorGeneric("Mutex", "Mutex", "pthread_mutexattr_setprotocol"); } status = pthread_mutex_init(&mutex, &mutexAttr); if (status != 0) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "Mutex: creation with name, id " << mutex.__data.__count - << ", " << " failed with " << strerror(status) << std::endl; -#endif + utility::printUnixErrorGeneric("Mutex", "Mutex", "pthread_mutex_init"); } // After a mutex attributes object has been used to initialize one or more // mutexes, any function affecting the attributes object // (including destruction) shall not affect any previously initialized mutexes. status = pthread_mutexattr_destroy(&mutexAttr); if (status != 0) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "Mutex: Attribute destroy failed with " << strerror(status) << std::endl; -#endif + utility::printUnixErrorGeneric("Mutex", "Mutex", "pthread_mutexattr_destroy"); } } diff --git a/osal/linux/Mutex.h b/src/fsfw/osal/linux/Mutex.h similarity index 100% rename from osal/linux/Mutex.h rename to src/fsfw/osal/linux/Mutex.h diff --git a/osal/linux/MutexFactory.cpp b/src/fsfw/osal/linux/MutexFactory.cpp similarity index 86% rename from osal/linux/MutexFactory.cpp rename to src/fsfw/osal/linux/MutexFactory.cpp index 80211f8b..373ff7da 100644 --- a/osal/linux/MutexFactory.cpp +++ b/src/fsfw/osal/linux/MutexFactory.cpp @@ -1,6 +1,6 @@ -#include "Mutex.h" +#include "fsfw/osal/linux/Mutex.h" -#include "../../ipc/MutexFactory.h" +#include "fsfw/ipc/MutexFactory.h" //TODO: Different variant than the lazy loading in QueueFactory. What's better and why? MutexFactory* MutexFactory::factoryInstance = new MutexFactory(); diff --git a/osal/linux/PeriodicPosixTask.cpp b/src/fsfw/osal/linux/PeriodicPosixTask.cpp similarity index 82% rename from osal/linux/PeriodicPosixTask.cpp rename to src/fsfw/osal/linux/PeriodicPosixTask.cpp index 630dd8e0..0603cf6a 100644 --- a/osal/linux/PeriodicPosixTask.cpp +++ b/src/fsfw/osal/linux/PeriodicPosixTask.cpp @@ -1,7 +1,10 @@ -#include "../../tasks/ExecutableObjectIF.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "fsfw/osal/linux/PeriodicPosixTask.h" + +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/tasks/ExecutableObjectIF.h" +#include "fsfw/serviceinterface/ServiceInterface.h" + #include -#include "PeriodicPosixTask.h" PeriodicPosixTask::PeriodicPosixTask(const char* name_, int priority_, size_t stackSize_, uint32_t period_, void(deadlineMissedFunc_)()): @@ -22,12 +25,15 @@ void* PeriodicPosixTask::taskEntryPoint(void* arg) { } ReturnValue_t PeriodicPosixTask::addComponent(object_id_t object) { - ExecutableObjectIF* newObject = objectManager->get( + ExecutableObjectIF* newObject = ObjectManager::instance()->get( object); if (newObject == nullptr) { #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "PeriodicTask::addComponent: Invalid object. Make sure" << " it implements ExecutableObjectIF!" << std::endl; +#else + sif::printError("PeriodicTask::addComponent: Invalid object. Make sure it " + "implements ExecutableObjectIF!\n"); #endif return HasReturnvaluesIF::RETURN_FAILED; } @@ -44,9 +50,6 @@ ReturnValue_t PeriodicPosixTask::sleepFor(uint32_t ms) { ReturnValue_t PeriodicPosixTask::startTask(void) { started = true; -#if FSFW_CPP_OSTREAM_ENABLED == 1 - //sif::info << stackSize << std::endl; -#endif PosixThread::createTask(&taskEntryPoint,this); return HasReturnvaluesIF::RETURN_OK; } diff --git a/osal/linux/PeriodicPosixTask.h b/src/fsfw/osal/linux/PeriodicPosixTask.h similarity index 100% rename from osal/linux/PeriodicPosixTask.h rename to src/fsfw/osal/linux/PeriodicPosixTask.h diff --git a/src/fsfw/osal/linux/PosixThread.cpp b/src/fsfw/osal/linux/PosixThread.cpp new file mode 100644 index 00000000..5ca41d73 --- /dev/null +++ b/src/fsfw/osal/linux/PosixThread.cpp @@ -0,0 +1,246 @@ +#include "fsfw/osal/linux/PosixThread.h" +#include "fsfw/osal/linux/unixUtility.h" + +#include "fsfw/serviceinterface/ServiceInterface.h" + +#include +#include + +PosixThread::PosixThread(const char* name_, int priority_, size_t stackSize_): + thread(0), priority(priority_), stackSize(stackSize_) { + name[0] = '\0'; + std::strncat(name, name_, PTHREAD_MAX_NAMELEN - 1); +} + +PosixThread::~PosixThread() { + //No deletion and no free of Stack Pointer +} + +ReturnValue_t PosixThread::sleep(uint64_t ns) { + //TODO sleep might be better with timer instead of sleep() + timespec time; + time.tv_sec = ns/1000000000; + time.tv_nsec = ns - time.tv_sec*1e9; + + //Remaining Time is not set here + int status = nanosleep(&time,NULL); + if(status != 0){ + switch(errno){ + case EINTR: + //The nanosleep() function was interrupted by a signal. + return HasReturnvaluesIF::RETURN_FAILED; + case EINVAL: + //The rqtp argument specified a nanosecond value less than zero or + // greater than or equal to 1000 million. + return HasReturnvaluesIF::RETURN_FAILED; + default: + return HasReturnvaluesIF::RETURN_FAILED; + } + + } + return HasReturnvaluesIF::RETURN_OK; +} + +void PosixThread::suspend() { + //Wait for SIGUSR1 + int caughtSig = 0; + sigset_t waitSignal; + sigemptyset(&waitSignal); + sigaddset(&waitSignal, SIGUSR1); + sigwait(&waitSignal, &caughtSig); + if (caughtSig != SIGUSR1) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "FixedTimeslotTask::suspend: Unknown Signal received: " << caughtSig << + std::endl; +#else + sif::printError("FixedTimeslotTask::suspend: Unknown Signal received: %d\n", caughtSig); +#endif + } +} + +void PosixThread::resume(){ + /* Signal the thread to start. Makes sense to call kill to start or? ;) + * + * According to Posix raise(signal) will call pthread_kill(pthread_self(), sig), + * but as the call must be done from the thread itsself this is not possible here + */ + pthread_kill(thread,SIGUSR1); +} + +bool PosixThread::delayUntil(uint64_t* const prevoiusWakeTime_ms, + const uint64_t delayTime_ms) { + uint64_t nextTimeToWake_ms; + bool shouldDelay = false; + //Get current Time + const uint64_t currentTime_ms = getCurrentMonotonicTimeMs(); + /* Generate the tick time at which the task wants to wake. */ + nextTimeToWake_ms = (*prevoiusWakeTime_ms) + delayTime_ms; + + if (currentTime_ms < *prevoiusWakeTime_ms) { + /* The tick count has overflowed since this function was + lasted called. In this case the only time we should ever + actually delay is if the wake time has also overflowed, + and the wake time is greater than the tick time. When this + is the case it is as if neither time had overflowed. */ + if ((nextTimeToWake_ms < *prevoiusWakeTime_ms) + && (nextTimeToWake_ms > currentTime_ms)) { + shouldDelay = true; + } + } else { + /* The tick time has not overflowed. In this case we will + delay if either the wake time has overflowed, and/or the + tick time is less than the wake time. */ + if ((nextTimeToWake_ms < *prevoiusWakeTime_ms) + || (nextTimeToWake_ms > currentTime_ms)) { + shouldDelay = true; + } + } + + /* Update the wake time ready for the next call. */ + + (*prevoiusWakeTime_ms) = nextTimeToWake_ms; + + if (shouldDelay) { + uint64_t sleepTime = nextTimeToWake_ms - currentTime_ms; + PosixThread::sleep(sleepTime * 1000000ull); + return true; + } + //We are shifting the time in case the deadline was missed like rtems + (*prevoiusWakeTime_ms) = currentTime_ms; + return false; + +} + + +uint64_t PosixThread::getCurrentMonotonicTimeMs(){ + timespec timeNow; + clock_gettime(CLOCK_MONOTONIC_RAW, &timeNow); + uint64_t currentTime_ms = (uint64_t) timeNow.tv_sec * 1000 + + timeNow.tv_nsec / 1000000; + + return currentTime_ms; +} + + +void PosixThread::createTask(void* (*fnc_)(void*), void* arg_) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + //sif::debug << "PosixThread::createTask" << std::endl; +#endif + /* + * The attr argument points to a pthread_attr_t structure whose contents + are used at thread creation time to determine attributes for the new + thread; this structure is initialized using pthread_attr_init(3) and + related functions. If attr is NULL, then the thread is created with + default attributes. + */ + pthread_attr_t attributes; + int status = pthread_attr_init(&attributes); + if(status != 0){ + utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "pthread_attr_init"); + } + void* stackPointer; + status = posix_memalign(&stackPointer, sysconf(_SC_PAGESIZE), stackSize); + if(status != 0) { + if(errno == ENOMEM) { + size_t stackMb = stackSize/10e6; +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "PosixThread::createTask: Insufficient memory for" + " the requested " << stackMb << " MB" << std::endl; +#else + sif::printError("PosixThread::createTask: Insufficient memory for " + "the requested %lu MB\n", static_cast(stackMb)); +#endif + utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "ENOMEM"); + } + else if(errno == EINVAL) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "PosixThread::createTask: Wrong alignment argument!" + << std::endl; +#else + sif::printError("PosixThread::createTask: Wrong alignment argument!\n"); +#endif + utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "EINVAL"); + } + return; + } + + status = pthread_attr_setstack(&attributes, stackPointer, stackSize); + if(status != 0) { + utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "pthread_attr_setstack"); +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "Make sure the specified stack size is valid and is " + "larger than the minimum allowed stack size." << std::endl; +#else + sif::printWarning("Make sure the specified stack size is valid and is " + "larger than the minimum allowed stack size.\n"); +#endif + } + + status = pthread_attr_setinheritsched(&attributes, PTHREAD_EXPLICIT_SCHED); + if(status != 0){ + utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "pthread_attr_setinheritsched"); + } +#ifndef FSFW_USE_REALTIME_FOR_LINUX +#error "Please define FSFW_USE_REALTIME_FOR_LINUX with either 0 or 1" +#endif +#if FSFW_USE_REALTIME_FOR_LINUX == 1 + // FIFO -> This needs root privileges for the process + status = pthread_attr_setschedpolicy(&attributes,SCHED_FIFO); + if(status != 0){ + utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "pthread_attr_setschedpolicy"); + } + + sched_param scheduleParams; + scheduleParams.__sched_priority = priority; + status = pthread_attr_setschedparam(&attributes, &scheduleParams); + if(status != 0){ + utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "pthread_attr_setschedparam"); + } +#endif + //Set Signal Mask for suspend until startTask is called + sigset_t waitSignal; + sigemptyset(&waitSignal); + sigaddset(&waitSignal, SIGUSR1); + status = pthread_sigmask(SIG_BLOCK, &waitSignal, NULL); + if(status != 0){ + utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "pthread_sigmask"); + } + + status = pthread_create(&thread,&attributes,fnc_,arg_); + if(status != 0){ + utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "pthread_create"); +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "For FSFW_USE_REALTIME_FOR_LINUX == 1 make sure to call " << + "\"all sudo setcap 'cap_sys_nice=eip'\" on the application or set " + "/etc/security/limit.conf" << std::endl; +#else + sif::printError("For FSFW_USE_REALTIME_FOR_LINUX == 1 make sure to call " + "\"all sudo setcap 'cap_sys_nice=eip'\" on the application or set " + "/etc/security/limit.conf\n"); +#endif + } + + status = pthread_setname_np(thread,name); + if(status != 0){ + utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "pthread_setname_np"); + if(status == ERANGE) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "PosixThread::createTask: Task name length longer" + " than 16 chars. Truncating.." << std::endl; +#else + sif::printWarning("PosixThread::createTask: Task name length longer" + " than 16 chars. Truncating..\n"); +#endif + name[15] = '\0'; + status = pthread_setname_np(thread,name); + if(status != 0){ + utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "pthread_setname_np"); + } + } + } + + status = pthread_attr_destroy(&attributes); + if (status != 0) { + utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "pthread_attr_destroy"); + } +} diff --git a/src/fsfw/osal/linux/PosixThread.h b/src/fsfw/osal/linux/PosixThread.h new file mode 100644 index 00000000..9c0ad39b --- /dev/null +++ b/src/fsfw/osal/linux/PosixThread.h @@ -0,0 +1,79 @@ +#ifndef FRAMEWORK_OSAL_LINUX_POSIXTHREAD_H_ +#define FRAMEWORK_OSAL_LINUX_POSIXTHREAD_H_ + +#include "../../returnvalues/HasReturnvaluesIF.h" +#include +#include +#include +#include + +class PosixThread { +public: + static constexpr uint8_t PTHREAD_MAX_NAMELEN = 16; + PosixThread(const char* name_, int priority_, size_t stackSize_); + virtual ~PosixThread(); + /** + * Set the Thread to sleep state + * @param ns Nanosecond sleep time + * @return Returns Failed if sleep fails + */ + static ReturnValue_t sleep(uint64_t ns); + /** + * @brief Function to suspend the task until SIGUSR1 was received + * + * @details Will be called in the beginning to suspend execution until startTask() is called explicitly. + */ + void suspend(); + + /** + * @brief Function to allow a other thread to start the thread again from suspend state + * + * @details Restarts the Thread after suspend call + */ + void resume(); + + + /** + * Delay function similar to FreeRtos delayUntil function + * + * @param prevoiusWakeTime_ms Needs the previous wake time and returns the next wakeup time + * @param delayTime_ms Time period to delay + * + * @return False If deadline was missed; True if task was delayed + */ + static bool delayUntil(uint64_t* const prevoiusWakeTime_ms, const uint64_t delayTime_ms); + + /** + * Returns the current time in milliseconds from CLOCK_MONOTONIC + * + * @return current time in milliseconds from CLOCK_MONOTONIC + */ + static uint64_t getCurrentMonotonicTimeMs(); + +protected: + pthread_t thread; + + /** + * @brief Function that has to be called by derived class because the + * derived class pointer has to be valid as argument. + * @details + * This function creates a pthread with the given parameters. As the + * function requires a pointer to the derived object it has to be called + * after the this pointer of the derived object is valid. + * Sets the taskEntryPoint as function to be called by new a thread. + * @param fnc_ Function which will be executed by the thread. + * @param arg_ + * argument of the taskEntryPoint function, needs to be this pointer + * of derived class + */ + void createTask(void* (*fnc_)(void*),void* arg_); + +private: + char name[PTHREAD_MAX_NAMELEN]; + int priority; + size_t stackSize = 0; + + static constexpr const char* CLASS_NAME = "PosixThread"; +}; + +#endif /* FRAMEWORK_OSAL_LINUX_POSIXTHREAD_H_ */ diff --git a/osal/linux/QueueFactory.cpp b/src/fsfw/osal/linux/QueueFactory.cpp similarity index 79% rename from osal/linux/QueueFactory.cpp rename to src/fsfw/osal/linux/QueueFactory.cpp index 44def48a..1df26ca9 100644 --- a/osal/linux/QueueFactory.cpp +++ b/src/fsfw/osal/linux/QueueFactory.cpp @@ -1,14 +1,12 @@ -#include "../../ipc/QueueFactory.h" -#include "MessageQueue.h" +#include "fsfw/ipc/QueueFactory.h" +#include "fsfw/osal/linux/MessageQueue.h" -#include "../../ipc/messageQueueDefinitions.h" -#include "../../ipc/MessageQueueSenderIF.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "fsfw/ipc/messageQueueDefinitions.h" +#include "fsfw/ipc/MessageQueueSenderIF.h" #include #include - #include QueueFactory* QueueFactory::factoryInstance = nullptr; diff --git a/osal/linux/SemaphoreFactory.cpp b/src/fsfw/osal/linux/SemaphoreFactory.cpp similarity index 81% rename from osal/linux/SemaphoreFactory.cpp rename to src/fsfw/osal/linux/SemaphoreFactory.cpp index cfb5f12d..0a0974be 100644 --- a/osal/linux/SemaphoreFactory.cpp +++ b/src/fsfw/osal/linux/SemaphoreFactory.cpp @@ -1,8 +1,7 @@ -#include "BinarySemaphore.h" -#include "CountingSemaphore.h" +#include "fsfw/osal/linux/BinarySemaphore.h" +#include "fsfw/osal/linux/CountingSemaphore.h" -#include "../../tasks/SemaphoreFactory.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "fsfw/tasks/SemaphoreFactory.h" SemaphoreFactory* SemaphoreFactory::factoryInstance = nullptr; diff --git a/osal/linux/TaskFactory.cpp b/src/fsfw/osal/linux/TaskFactory.cpp similarity index 88% rename from osal/linux/TaskFactory.cpp rename to src/fsfw/osal/linux/TaskFactory.cpp index 80bf47b7..53aea0ac 100644 --- a/osal/linux/TaskFactory.cpp +++ b/src/fsfw/osal/linux/TaskFactory.cpp @@ -1,9 +1,9 @@ -#include "FixedTimeslotTask.h" -#include "PeriodicPosixTask.h" +#include "fsfw/osal/linux/FixedTimeslotTask.h" +#include "fsfw/osal/linux/PeriodicPosixTask.h" -#include "../../tasks/TaskFactory.h" -#include "../../serviceinterface/ServiceInterface.h" -#include "../../returnvalues/HasReturnvaluesIF.h" +#include "fsfw/tasks/TaskFactory.h" +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" //TODO: Different variant than the lazy loading in QueueFactory. What's better and why? TaskFactory* TaskFactory::factoryInstance = new TaskFactory(); diff --git a/osal/linux/tcpipHelpers.cpp b/src/fsfw/osal/linux/tcpipHelpers.cpp similarity index 94% rename from osal/linux/tcpipHelpers.cpp rename to src/fsfw/osal/linux/tcpipHelpers.cpp index d7c644ec..800c6fb7 100644 --- a/osal/linux/tcpipHelpers.cpp +++ b/src/fsfw/osal/linux/tcpipHelpers.cpp @@ -1,7 +1,7 @@ -#include "../common/tcpipHelpers.h" +#include "fsfw/osal/common/tcpipHelpers.h" -#include "../../serviceinterface/ServiceInterface.h" -#include "../../tasks/TaskFactory.h" +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/tasks/TaskFactory.h" #include #include diff --git a/src/fsfw/osal/linux/unixUtility.cpp b/src/fsfw/osal/linux/unixUtility.cpp new file mode 100644 index 00000000..57e1f17a --- /dev/null +++ b/src/fsfw/osal/linux/unixUtility.cpp @@ -0,0 +1,32 @@ +#include "fsfw/FSFW.h" +#include "fsfw/osal/linux/unixUtility.h" +#include "fsfw/serviceinterface/ServiceInterface.h" + +#include +#include + +void utility::printUnixErrorGeneric(const char* const className, + const char* const function, const char* const failString, + sif::OutputTypes outputType) { + if(className == nullptr or failString == nullptr or function == nullptr) { + return; + } +#if FSFW_VERBOSE_LEVEL >= 1 + if(outputType == sif::OutputTypes::OUT_ERROR) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << className << "::" << function << ": " << failString << " error: " + << strerror(errno) << std::endl; +#else + sif::printError("%s::%s: %s error: %s\n", className, function, failString, strerror(errno)); +#endif + } + else { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << className << "::" << function << ": " << failString << " error: " + << strerror(errno) << std::endl; +#else + sif::printWarning("%s::%s: %s error: %s\n", className, function, failString, strerror(errno)); +#endif + } +#endif +} diff --git a/src/fsfw/osal/linux/unixUtility.h b/src/fsfw/osal/linux/unixUtility.h new file mode 100644 index 00000000..8a964f3a --- /dev/null +++ b/src/fsfw/osal/linux/unixUtility.h @@ -0,0 +1,13 @@ +#ifndef FSFW_OSAL_LINUX_UNIXUTILITY_H_ +#define FSFW_OSAL_LINUX_UNIXUTILITY_H_ + +#include "../../serviceinterface/serviceInterfaceDefintions.h" + +namespace utility { + +void printUnixErrorGeneric(const char* const className, const char* const function, + const char* const failString, sif::OutputTypes outputType = sif::OutputTypes::OUT_ERROR); + +} + +#endif /* FSFW_OSAL_LINUX_UNIXUTILITY_H_ */ diff --git a/src/fsfw/osal/rtems/BinarySemaphore.cpp b/src/fsfw/osal/rtems/BinarySemaphore.cpp new file mode 100644 index 00000000..6d145d98 --- /dev/null +++ b/src/fsfw/osal/rtems/BinarySemaphore.cpp @@ -0,0 +1,23 @@ +#include "BinarySemaphore.h" + +#include + +BinarySemaphore::BinarySemaphore() { +} + +BinarySemaphore::~BinarySemaphore() { + +} + +ReturnValue_t BinarySemaphore::acquire(TimeoutType timeoutType, uint32_t timeoutMs) { + return HasReturnvaluesIF::RETURN_OK; +} + + +ReturnValue_t BinarySemaphore::release() { + return HasReturnvaluesIF::RETURN_OK; +} + +uint8_t BinarySemaphore::getSemaphoreCounter() const { + return 0; +} diff --git a/src/fsfw/osal/rtems/BinarySemaphore.h b/src/fsfw/osal/rtems/BinarySemaphore.h new file mode 100644 index 00000000..a2796af1 --- /dev/null +++ b/src/fsfw/osal/rtems/BinarySemaphore.h @@ -0,0 +1,23 @@ +#ifndef FSFW_OSAL_RTEMS_BINARYSEMAPHORE_H_ +#define FSFW_OSAL_RTEMS_BINARYSEMAPHORE_H_ + +#include "fsfw/tasks/SemaphoreIF.h" + +class BinarySemaphore: public SemaphoreIF { +public: + BinarySemaphore(); + virtual ~BinarySemaphore(); + + // Semaphore IF implementations + ReturnValue_t acquire(TimeoutType timeoutType = + TimeoutType::BLOCKING, uint32_t timeoutMs = 0) override; + ReturnValue_t release() override; + uint8_t getSemaphoreCounter() const override; + +private: + +}; + + + +#endif /* FSFW_SRC_FSFW_OSAL_RTEMS_BINARYSEMAPHORE_H_ */ diff --git a/osal/rtems/CMakeLists.txt b/src/fsfw/osal/rtems/CMakeLists.txt similarity index 86% rename from osal/rtems/CMakeLists.txt rename to src/fsfw/osal/rtems/CMakeLists.txt index cd266125..734566a3 100644 --- a/osal/rtems/CMakeLists.txt +++ b/src/fsfw/osal/rtems/CMakeLists.txt @@ -13,6 +13,8 @@ target_sources(${LIB_FSFW_NAME} RtemsBasic.cpp RTEMSTaskBase.cpp TaskFactory.cpp + BinarySemaphore.cpp + SemaphoreFactory.cpp ) diff --git a/osal/rtems/Clock.cpp b/src/fsfw/osal/rtems/Clock.cpp similarity index 73% rename from osal/rtems/Clock.cpp rename to src/fsfw/osal/rtems/Clock.cpp index b80786f7..42f30dcc 100644 --- a/osal/rtems/Clock.cpp +++ b/src/fsfw/osal/rtems/Clock.cpp @@ -1,7 +1,7 @@ -#include "RtemsBasic.h" +#include "fsfw/osal/rtems/RtemsBasic.h" -#include "../../timemanager/Clock.h" -#include "../../ipc/MutexGuard.h" +#include "fsfw/timemanager/Clock.h" +#include "fsfw/ipc/MutexGuard.h" #include #include @@ -154,65 +154,3 @@ ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) { / 3600.; return HasReturnvaluesIF::RETURN_OK; } - -ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) { - //SHOULDDO: works not for dates in the past (might have less leap seconds) - if (timeMutex == nullptr) { - return HasReturnvaluesIF::RETURN_FAILED; - } - - uint16_t leapSeconds; - ReturnValue_t result = getLeapSeconds(&leapSeconds); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - timeval leapSeconds_timeval = { 0, 0 }; - leapSeconds_timeval.tv_sec = leapSeconds; - - //initial offset between UTC and TAI - timeval UTCtoTAI1972 = { 10, 0 }; - - timeval TAItoTT = { 32, 184000 }; - - *tt = utc + leapSeconds_timeval + UTCtoTAI1972 + TAItoTT; - - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) { - if(checkOrCreateClockMutex()!=HasReturnvaluesIF::RETURN_OK){ - return HasReturnvaluesIF::RETURN_FAILED; - } - MutexGuard helper(timeMutex); - - - leapSeconds = leapSeconds_; - - - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) { - if(timeMutex==nullptr){ - return HasReturnvaluesIF::RETURN_FAILED; - } - MutexGuard helper(timeMutex); - - *leapSeconds_ = leapSeconds; - - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t Clock::checkOrCreateClockMutex(){ - if(timeMutex==nullptr){ - MutexFactory* mutexFactory = MutexFactory::instance(); - if (mutexFactory == nullptr) { - return HasReturnvaluesIF::RETURN_FAILED; - } - timeMutex = mutexFactory->createMutex(); - if (timeMutex == nullptr) { - return HasReturnvaluesIF::RETURN_FAILED; - } - } - return HasReturnvaluesIF::RETURN_OK; -} diff --git a/osal/rtems/CpuUsage.cpp b/src/fsfw/osal/rtems/CpuUsage.cpp similarity index 97% rename from osal/rtems/CpuUsage.cpp rename to src/fsfw/osal/rtems/CpuUsage.cpp index 89c01336..771b52dc 100644 --- a/osal/rtems/CpuUsage.cpp +++ b/src/fsfw/osal/rtems/CpuUsage.cpp @@ -1,6 +1,6 @@ -#include "CpuUsage.h" -#include "../../serialize/SerialArrayListAdapter.h" -#include "../../serialize/SerializeAdapter.h" +#include "fsfw/osal/rtems/CpuUsage.h" +#include "fsfw/serialize/SerialArrayListAdapter.h" +#include "fsfw/serialize/SerializeAdapter.h" #include extern "C" { diff --git a/osal/rtems/CpuUsage.h b/src/fsfw/osal/rtems/CpuUsage.h similarity index 93% rename from osal/rtems/CpuUsage.h rename to src/fsfw/osal/rtems/CpuUsage.h index f487e191..6b6b9910 100644 --- a/osal/rtems/CpuUsage.h +++ b/src/fsfw/osal/rtems/CpuUsage.h @@ -1,8 +1,8 @@ #ifndef CPUUSAGE_H_ #define CPUUSAGE_H_ -#include "../../container/FixedArrayList.h" -#include "../../serialize/SerializeIF.h" +#include "fsfw/container/FixedArrayList.h" +#include "fsfw/serialize/SerializeIF.h" #include class CpuUsage : public SerializeIF { diff --git a/osal/rtems/FixedTimeslotTask.cpp b/src/fsfw/osal/rtems/FixedTimeslotTask.cpp similarity index 91% rename from osal/rtems/FixedTimeslotTask.cpp rename to src/fsfw/osal/rtems/FixedTimeslotTask.cpp index 3a3be6b3..8b313df6 100644 --- a/osal/rtems/FixedTimeslotTask.cpp +++ b/src/fsfw/osal/rtems/FixedTimeslotTask.cpp @@ -1,11 +1,11 @@ -#include "FixedTimeslotTask.h" -#include "RtemsBasic.h" +#include "fsfw/osal/rtems/FixedTimeslotTask.h" +#include "fsfw/osal/rtems/RtemsBasic.h" -#include "../../tasks/FixedSequenceSlot.h" -#include "../../objectmanager/SystemObjectIF.h" -#include "../../objectmanager/ObjectManagerIF.h" -#include "../../returnvalues/HasReturnvaluesIF.h" -#include "../../serviceinterface/ServiceInterface.h" +#include "fsfw/tasks/FixedSequenceSlot.h" +#include "fsfw/objectmanager/SystemObjectIF.h" +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" +#include "fsfw/serviceinterface/ServiceInterface.h" #include #include @@ -81,7 +81,7 @@ ReturnValue_t FixedTimeslotTask::startTask() { ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, uint32_t slotTimeMs, int8_t executionStep) { - ExecutableObjectIF* object = objectManager->get(componentId); + ExecutableObjectIF* object = ObjectManager::instance()->get(componentId); if (object != nullptr) { pst.addSlot(componentId, slotTimeMs, executionStep, object, this); return HasReturnvaluesIF::RETURN_OK; diff --git a/osal/rtems/FixedTimeslotTask.h b/src/fsfw/osal/rtems/FixedTimeslotTask.h similarity index 100% rename from osal/rtems/FixedTimeslotTask.h rename to src/fsfw/osal/rtems/FixedTimeslotTask.h diff --git a/osal/rtems/InitTask.cpp b/src/fsfw/osal/rtems/InitTask.cpp similarity index 52% rename from osal/rtems/InitTask.cpp rename to src/fsfw/osal/rtems/InitTask.cpp index 80afed3d..8a9bb9f6 100644 --- a/osal/rtems/InitTask.cpp +++ b/src/fsfw/osal/rtems/InitTask.cpp @@ -1,5 +1,5 @@ -#include "InitTask.h" -#include "RtemsBasic.h" +#include "fsfw/osal/rtems/InitTask.h" +#include "fsfw/osal/rtems/RtemsBasic.h" diff --git a/osal/rtems/InitTask.h b/src/fsfw/osal/rtems/InitTask.h similarity index 100% rename from osal/rtems/InitTask.h rename to src/fsfw/osal/rtems/InitTask.h diff --git a/osal/rtems/InternalErrorCodes.cpp b/src/fsfw/osal/rtems/InternalErrorCodes.cpp similarity index 97% rename from osal/rtems/InternalErrorCodes.cpp rename to src/fsfw/osal/rtems/InternalErrorCodes.cpp index f4079814..049286d7 100644 --- a/osal/rtems/InternalErrorCodes.cpp +++ b/src/fsfw/osal/rtems/InternalErrorCodes.cpp @@ -1,4 +1,4 @@ -#include "../../osal/InternalErrorCodes.h" +#include "fsfw/osal/InternalErrorCodes.h" #include ReturnValue_t InternalErrorCodes::translate(uint8_t code) { diff --git a/osal/rtems/MessageQueue.cpp b/src/fsfw/osal/rtems/MessageQueue.cpp similarity index 94% rename from osal/rtems/MessageQueue.cpp rename to src/fsfw/osal/rtems/MessageQueue.cpp index 717b80dd..65fe0946 100644 --- a/osal/rtems/MessageQueue.cpp +++ b/src/fsfw/osal/rtems/MessageQueue.cpp @@ -1,8 +1,11 @@ -#include "../../serviceinterface/ServiceInterfaceStream.h" -#include "../../objectmanager/ObjectManagerIF.h" -#include "MessageQueue.h" -#include "RtemsBasic.h" +#include "fsfw/osal/rtems/MessageQueue.h" +#include "fsfw/osal/rtems/RtemsBasic.h" + +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/objectmanager/ObjectManager.h" + #include + MessageQueue::MessageQueue(size_t message_depth, size_t max_message_size) : id(0), lastPartner(0), defaultDestination(NO_QUEUE), internalErrorReporter(nullptr) { rtems_name name = ('Q' << 24) + (queueCounter++ << 8); @@ -94,7 +97,7 @@ ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, //TODO: Check if we're in ISR. if (result != RTEMS_SUCCESSFUL && !ignoreFault) { if (internalErrorReporter == nullptr) { - internalErrorReporter = objectManager->get( + internalErrorReporter = ObjectManager::instance()->get( objects::INTERNAL_ERROR_REPORTER); } if (internalErrorReporter != nullptr) { diff --git a/osal/rtems/MessageQueue.h b/src/fsfw/osal/rtems/MessageQueue.h similarity index 98% rename from osal/rtems/MessageQueue.h rename to src/fsfw/osal/rtems/MessageQueue.h index 342f1e30..fa143ebe 100644 --- a/osal/rtems/MessageQueue.h +++ b/src/fsfw/osal/rtems/MessageQueue.h @@ -1,9 +1,9 @@ #ifndef FSFW_OSAL_RTEMS_MESSAGEQUEUE_H_ #define FSFW_OSAL_RTEMS_MESSAGEQUEUE_H_ -#include "../../internalError/InternalErrorReporterIF.h" -#include "../../ipc/MessageQueueIF.h" -#include "../../ipc/MessageQueueMessage.h" +#include "fsfw/internalerror/InternalErrorReporterIF.h" +#include "fsfw/ipc/MessageQueueIF.h" +#include "fsfw/ipc/MessageQueueMessage.h" #include "RtemsBasic.h" /** diff --git a/osal/rtems/Mutex.cpp b/src/fsfw/osal/rtems/Mutex.cpp similarity index 96% rename from osal/rtems/Mutex.cpp rename to src/fsfw/osal/rtems/Mutex.cpp index f65c1f55..2dfa39fa 100644 --- a/osal/rtems/Mutex.cpp +++ b/src/fsfw/osal/rtems/Mutex.cpp @@ -1,5 +1,5 @@ -#include "Mutex.h" -#include "../../serviceinterface/ServiceInterface.h" +#include "fsfw/osal/rtems/Mutex.h" +#include "fsfw/serviceinterface/ServiceInterface.h" uint8_t Mutex::count = 0; diff --git a/osal/rtems/Mutex.h b/src/fsfw/osal/rtems/Mutex.h similarity index 100% rename from osal/rtems/Mutex.h rename to src/fsfw/osal/rtems/Mutex.h diff --git a/osal/rtems/MutexFactory.cpp b/src/fsfw/osal/rtems/MutexFactory.cpp similarity index 83% rename from osal/rtems/MutexFactory.cpp rename to src/fsfw/osal/rtems/MutexFactory.cpp index adc599e9..bf7ce666 100644 --- a/osal/rtems/MutexFactory.cpp +++ b/src/fsfw/osal/rtems/MutexFactory.cpp @@ -1,6 +1,6 @@ -#include "Mutex.h" +#include "fsfw/osal/rtems/Mutex.h" -#include "../../ipc/MutexFactory.h" +#include "fsfw/ipc/MutexFactory.h" MutexFactory* MutexFactory::factoryInstance = new MutexFactory(); diff --git a/osal/rtems/PeriodicTask.cpp b/src/fsfw/osal/rtems/PeriodicTask.cpp similarity index 90% rename from osal/rtems/PeriodicTask.cpp rename to src/fsfw/osal/rtems/PeriodicTask.cpp index 067983cb..db98153c 100644 --- a/osal/rtems/PeriodicTask.cpp +++ b/src/fsfw/osal/rtems/PeriodicTask.cpp @@ -1,7 +1,8 @@ -#include "PeriodicTask.h" +#include "fsfw/osal/rtems/PeriodicTask.h" -#include "../../serviceinterface/ServiceInterface.h" -#include "../../tasks/ExecutableObjectIF.h" +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/tasks/ExecutableObjectIF.h" PeriodicTask::PeriodicTask(const char *name, rtems_task_priority setPriority, size_t setStack, rtems_interval setPeriod, void (*setDeadlineMissedFunc)()) : @@ -68,7 +69,7 @@ void PeriodicTask::taskFunctionality() { } ReturnValue_t PeriodicTask::addComponent(object_id_t object) { - ExecutableObjectIF* newObject = objectManager->get(object); + ExecutableObjectIF* newObject = ObjectManager::instance()->get(object); if (newObject == nullptr) { return HasReturnvaluesIF::RETURN_FAILED; } diff --git a/osal/rtems/PeriodicTask.h b/src/fsfw/osal/rtems/PeriodicTask.h similarity index 100% rename from osal/rtems/PeriodicTask.h rename to src/fsfw/osal/rtems/PeriodicTask.h diff --git a/osal/rtems/QueueFactory.cpp b/src/fsfw/osal/rtems/QueueFactory.cpp similarity index 90% rename from osal/rtems/QueueFactory.cpp rename to src/fsfw/osal/rtems/QueueFactory.cpp index ff561304..ddcc3959 100644 --- a/osal/rtems/QueueFactory.cpp +++ b/src/fsfw/osal/rtems/QueueFactory.cpp @@ -1,7 +1,8 @@ -#include "../../ipc/QueueFactory.h" -#include "../../ipc/MessageQueueSenderIF.h" -#include "MessageQueue.h" -#include "RtemsBasic.h" +#include "fsfw/osal/rtems/MessageQueue.h" +#include "fsfw/osal/rtems/RtemsBasic.h" + +#include "fsfw/ipc/QueueFactory.h" +#include "fsfw/ipc/MessageQueueSenderIF.h" QueueFactory* QueueFactory::factoryInstance = nullptr; diff --git a/osal/rtems/RTEMSTaskBase.cpp b/src/fsfw/osal/rtems/RTEMSTaskBase.cpp similarity index 96% rename from osal/rtems/RTEMSTaskBase.cpp rename to src/fsfw/osal/rtems/RTEMSTaskBase.cpp index d0cdc876..fc8bbed5 100644 --- a/osal/rtems/RTEMSTaskBase.cpp +++ b/src/fsfw/osal/rtems/RTEMSTaskBase.cpp @@ -1,5 +1,5 @@ -#include "RTEMSTaskBase.h" -#include "../../serviceinterface/ServiceInterface.h" +#include "fsfw/osal/rtems/RTEMSTaskBase.h" +#include "fsfw/serviceinterface/ServiceInterface.h" const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = RTEMS_MINIMUM_STACK_SIZE; diff --git a/osal/rtems/RTEMSTaskBase.h b/src/fsfw/osal/rtems/RTEMSTaskBase.h similarity index 100% rename from osal/rtems/RTEMSTaskBase.h rename to src/fsfw/osal/rtems/RTEMSTaskBase.h diff --git a/src/fsfw/osal/rtems/RtemsBasic.cpp b/src/fsfw/osal/rtems/RtemsBasic.cpp new file mode 100644 index 00000000..463824ad --- /dev/null +++ b/src/fsfw/osal/rtems/RtemsBasic.cpp @@ -0,0 +1 @@ +#include "fsfw/osal/rtems/RtemsBasic.h" diff --git a/osal/rtems/RtemsBasic.h b/src/fsfw/osal/rtems/RtemsBasic.h similarity index 92% rename from osal/rtems/RtemsBasic.h rename to src/fsfw/osal/rtems/RtemsBasic.h index 73f23186..382697a3 100644 --- a/osal/rtems/RtemsBasic.h +++ b/src/fsfw/osal/rtems/RtemsBasic.h @@ -1,7 +1,7 @@ #ifndef FSFW_OSAL_RTEMS_RTEMSBASIC_H_ #define FSFW_OSAL_RTEMS_RTEMSBASIC_H_ -#include "../../returnvalues/HasReturnvaluesIF.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" #include #include diff --git a/src/fsfw/osal/rtems/SemaphoreFactory.cpp b/src/fsfw/osal/rtems/SemaphoreFactory.cpp new file mode 100644 index 00000000..cec4b833 --- /dev/null +++ b/src/fsfw/osal/rtems/SemaphoreFactory.cpp @@ -0,0 +1,34 @@ +#include "fsfw/osal/rtems/BinarySemaphore.h" +//#include "fsfw/osal/rtems/CountingSemaphore.h" + +#include "fsfw/tasks/SemaphoreFactory.h" +#include "fsfw/serviceinterface/ServiceInterface.h" + +SemaphoreFactory* SemaphoreFactory::factoryInstance = nullptr; + +SemaphoreFactory::SemaphoreFactory() { +} + +SemaphoreFactory::~SemaphoreFactory() { + delete factoryInstance; +} + +SemaphoreFactory* SemaphoreFactory::instance() { + if (factoryInstance == nullptr){ + factoryInstance = new SemaphoreFactory(); + } + return SemaphoreFactory::factoryInstance; +} + +SemaphoreIF* SemaphoreFactory::createBinarySemaphore(uint32_t argument) { + return new BinarySemaphore(); +} + +SemaphoreIF* SemaphoreFactory::createCountingSemaphore(uint8_t maxCount, + uint8_t initCount, uint32_t argument) { + return nullptr; +} + +void SemaphoreFactory::deleteSemaphore(SemaphoreIF* semaphore) { + delete semaphore; +} diff --git a/osal/rtems/TaskFactory.cpp b/src/fsfw/osal/rtems/TaskFactory.cpp similarity index 86% rename from osal/rtems/TaskFactory.cpp rename to src/fsfw/osal/rtems/TaskFactory.cpp index 095e9a26..dd3e92fc 100644 --- a/osal/rtems/TaskFactory.cpp +++ b/src/fsfw/osal/rtems/TaskFactory.cpp @@ -1,10 +1,10 @@ -#include "FixedTimeslotTask.h" -#include "PeriodicTask.h" -#include "InitTask.h" -#include "RtemsBasic.h" +#include "fsfw/osal/rtems/FixedTimeslotTask.h" +#include "fsfw/osal/rtems/PeriodicTask.h" +#include "fsfw/osal/rtems/InitTask.h" +#include "fsfw/osal/rtems/RtemsBasic.h" -#include "../../tasks/TaskFactory.h" -#include "../../returnvalues/HasReturnvaluesIF.h" +#include "fsfw/tasks/TaskFactory.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" //TODO: Different variant than the lazy loading in QueueFactory. What's better and why? TaskFactory* TaskFactory::factoryInstance = new TaskFactory(); diff --git a/osal/windows/CMakeLists.txt b/src/fsfw/osal/windows/CMakeLists.txt similarity index 100% rename from osal/windows/CMakeLists.txt rename to src/fsfw/osal/windows/CMakeLists.txt diff --git a/osal/windows/tcpipHelpers.cpp b/src/fsfw/osal/windows/tcpipHelpers.cpp similarity index 86% rename from osal/windows/tcpipHelpers.cpp rename to src/fsfw/osal/windows/tcpipHelpers.cpp index 03278a92..37d6fb2f 100644 --- a/osal/windows/tcpipHelpers.cpp +++ b/src/fsfw/osal/windows/tcpipHelpers.cpp @@ -1,8 +1,8 @@ -#include "../common/tcpipHelpers.h" -#include +#include "fsfw/FSFW.h" +#include "fsfw/osal/common/tcpipHelpers.h" -#include "../../tasks/TaskFactory.h" -#include "../../serviceinterface/ServiceInterface.h" +#include "fsfw/tasks/TaskFactory.h" +#include "fsfw/serviceinterface/ServiceInterface.h" #include @@ -50,8 +50,8 @@ void tcpip::handleError(Protocol protocol, ErrorSources errorSrc, dur_millis_t s sif::warning << "tcpip::handleError: " << protocolString << " | " << errorSrcString << " | " << infoString << std::endl; #else - sif::printWarning("tcpip::handleError: %s | %s | %s\n", protocolString, - errorSrcString, infoString); + sif::printWarning("tcpip::handleError: %s | %s | %s\n", protocolString.c_str(), + errorSrcString.c_str(), infoString.c_str()); #endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ #endif /* FSFW_VERBOSE_LEVEL >= 1 */ diff --git a/osal/windows/winTaskHelpers.cpp b/src/fsfw/osal/windows/winTaskHelpers.cpp similarity index 98% rename from osal/windows/winTaskHelpers.cpp rename to src/fsfw/osal/windows/winTaskHelpers.cpp index 6765b952..20d4d98d 100644 --- a/osal/windows/winTaskHelpers.cpp +++ b/src/fsfw/osal/windows/winTaskHelpers.cpp @@ -1,4 +1,5 @@ -#include +#include "fsfw/osal/windows/winTaskHelpers.h" + #include TaskPriority tasks::makeWinPriority(PriorityClass prioClass, PriorityNumber prioNumber) { diff --git a/osal/windows/winTaskHelpers.h b/src/fsfw/osal/windows/winTaskHelpers.h similarity index 100% rename from osal/windows/winTaskHelpers.h rename to src/fsfw/osal/windows/winTaskHelpers.h diff --git a/parameters/CMakeLists.txt b/src/fsfw/parameters/CMakeLists.txt similarity index 100% rename from parameters/CMakeLists.txt rename to src/fsfw/parameters/CMakeLists.txt diff --git a/parameters/HasParametersIF.h b/src/fsfw/parameters/HasParametersIF.h similarity index 100% rename from parameters/HasParametersIF.h rename to src/fsfw/parameters/HasParametersIF.h diff --git a/parameters/ParameterHelper.cpp b/src/fsfw/parameters/ParameterHelper.cpp similarity index 95% rename from parameters/ParameterHelper.cpp rename to src/fsfw/parameters/ParameterHelper.cpp index e80c2c47..9250a1d4 100644 --- a/parameters/ParameterHelper.cpp +++ b/src/fsfw/parameters/ParameterHelper.cpp @@ -1,6 +1,7 @@ -#include "ParameterHelper.h" -#include "ParameterMessage.h" -#include "../objectmanager/ObjectManagerIF.h" +#include "fsfw/parameters/ParameterHelper.h" +#include "fsfw/parameters/ParameterMessage.h" + +#include "fsfw/objectmanager/ObjectManager.h" ParameterHelper::ParameterHelper(ReceivesParameterMessagesIF* owner): owner(owner) {} @@ -124,7 +125,7 @@ ReturnValue_t ParameterHelper::sendParameter(MessageQueueId_t to, uint32_t id, ReturnValue_t ParameterHelper::initialize() { ownerQueueId = owner->getCommandQueue(); - storage = objectManager->get(objects::IPC_STORE); + storage = ObjectManager::instance()->get(objects::IPC_STORE); if (storage == nullptr) { return ObjectManagerIF::CHILD_INIT_FAILED; } diff --git a/parameters/ParameterHelper.h b/src/fsfw/parameters/ParameterHelper.h similarity index 100% rename from parameters/ParameterHelper.h rename to src/fsfw/parameters/ParameterHelper.h diff --git a/parameters/ParameterMessage.cpp b/src/fsfw/parameters/ParameterMessage.cpp similarity index 91% rename from parameters/ParameterMessage.cpp rename to src/fsfw/parameters/ParameterMessage.cpp index 88a45c80..ee58339c 100644 --- a/parameters/ParameterMessage.cpp +++ b/src/fsfw/parameters/ParameterMessage.cpp @@ -1,5 +1,6 @@ -#include "../parameters/ParameterMessage.h" -#include "../objectmanager/ObjectManagerIF.h" +#include "fsfw/parameters/ParameterMessage.h" + +#include "fsfw/objectmanager/ObjectManager.h" ParameterId_t ParameterMessage::getParameterId(const CommandMessage* message) { return message->getParameter(); @@ -51,7 +52,7 @@ void ParameterMessage::clear(CommandMessage* message) { switch (message->getCommand()) { case CMD_PARAMETER_LOAD: case REPLY_PARAMETER_DUMP: { - StorageManagerIF *ipcStore = objectManager->get( + StorageManagerIF *ipcStore = ObjectManager::instance()->get( objects::IPC_STORE); if (ipcStore != NULL) { ipcStore->deleteData(getStoreId(message)); diff --git a/parameters/ParameterMessage.h b/src/fsfw/parameters/ParameterMessage.h similarity index 100% rename from parameters/ParameterMessage.h rename to src/fsfw/parameters/ParameterMessage.h diff --git a/parameters/ParameterWrapper.cpp b/src/fsfw/parameters/ParameterWrapper.cpp similarity index 98% rename from parameters/ParameterWrapper.cpp rename to src/fsfw/parameters/ParameterWrapper.cpp index 660d7db7..8c09a822 100644 --- a/parameters/ParameterWrapper.cpp +++ b/src/fsfw/parameters/ParameterWrapper.cpp @@ -1,6 +1,6 @@ -#include "ParameterWrapper.h" -#include -#include +#include "fsfw/FSFW.h" +#include "fsfw/parameters/ParameterWrapper.h" +#include "fsfw/serviceinterface/ServiceInterface.h" ParameterWrapper::ParameterWrapper() : pointsToStream(false), type(Type::UNKNOWN_TYPE) { diff --git a/parameters/ParameterWrapper.h b/src/fsfw/parameters/ParameterWrapper.h similarity index 100% rename from parameters/ParameterWrapper.h rename to src/fsfw/parameters/ParameterWrapper.h diff --git a/parameters/ReceivesParameterMessagesIF.h b/src/fsfw/parameters/ReceivesParameterMessagesIF.h similarity index 100% rename from parameters/ReceivesParameterMessagesIF.h rename to src/fsfw/parameters/ReceivesParameterMessagesIF.h diff --git a/src/fsfw/platform.h b/src/fsfw/platform.h new file mode 100644 index 00000000..4bca3398 --- /dev/null +++ b/src/fsfw/platform.h @@ -0,0 +1,10 @@ +#ifndef FSFW_PLATFORM_H_ +#define FSFW_PLATFORM_H_ + +#if defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)) +#define PLATFORM_UNIX +#elif defined(_WIN32) +#define PLATFORM_WIN +#endif + +#endif /* FSFW_PLATFORM_H_ */ diff --git a/power/CMakeLists.txt b/src/fsfw/power/CMakeLists.txt similarity index 100% rename from power/CMakeLists.txt rename to src/fsfw/power/CMakeLists.txt diff --git a/power/Fuse.cpp b/src/fsfw/power/Fuse.cpp similarity index 95% rename from power/Fuse.cpp rename to src/fsfw/power/Fuse.cpp index 91da5388..821bdbc5 100644 --- a/power/Fuse.cpp +++ b/src/fsfw/power/Fuse.cpp @@ -1,10 +1,10 @@ -#include "Fuse.h" +#include "fsfw/power/Fuse.h" -#include "../monitoring/LimitViolationReporter.h" -#include "../monitoring/MonitoringMessageContent.h" -#include "../objectmanager/ObjectManagerIF.h" -#include "../serialize/SerialFixedArrayListAdapter.h" -#include "../ipc/QueueFactory.h" +#include "fsfw/monitoring/LimitViolationReporter.h" +#include "fsfw/monitoring/MonitoringMessageContent.h" +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/serialize/SerialFixedArrayListAdapter.h" +#include "fsfw/ipc/QueueFactory.h" object_id_t Fuse::powerSwitchId = 0; @@ -44,7 +44,7 @@ ReturnValue_t Fuse::initialize() { if (result != RETURN_OK) { return result; } - powerIF = objectManager->get(powerSwitchId); + powerIF = ObjectManager::instance()->get(powerSwitchId); if (powerIF == NULL) { return RETURN_FAILED; } diff --git a/power/Fuse.h b/src/fsfw/power/Fuse.h similarity index 100% rename from power/Fuse.h rename to src/fsfw/power/Fuse.h diff --git a/power/PowerComponent.cpp b/src/fsfw/power/PowerComponent.cpp similarity index 96% rename from power/PowerComponent.cpp rename to src/fsfw/power/PowerComponent.cpp index 9ea84dad..fb66748a 100644 --- a/power/PowerComponent.cpp +++ b/src/fsfw/power/PowerComponent.cpp @@ -1,5 +1,5 @@ -#include "PowerComponent.h" -#include "../serialize/SerializeAdapter.h" +#include "fsfw/power/PowerComponent.h" +#include "fsfw/serialize/SerializeAdapter.h" PowerComponent::PowerComponent(): switchId1(0xFF), switchId2(0xFF), diff --git a/power/PowerComponent.h b/src/fsfw/power/PowerComponent.h similarity index 92% rename from power/PowerComponent.h rename to src/fsfw/power/PowerComponent.h index 6b9778a5..3889a2ae 100644 --- a/power/PowerComponent.h +++ b/src/fsfw/power/PowerComponent.h @@ -3,8 +3,8 @@ #include "PowerComponentIF.h" -#include "../objectmanager/frameworkObjects.h" -#include "../objectmanager/SystemObjectIF.h" +#include "fsfw/objectmanager/frameworkObjects.h" +#include "fsfw/objectmanager/SystemObjectIF.h" class PowerComponent: public PowerComponentIF { diff --git a/power/PowerComponentIF.h b/src/fsfw/power/PowerComponentIF.h similarity index 100% rename from power/PowerComponentIF.h rename to src/fsfw/power/PowerComponentIF.h diff --git a/power/PowerSensor.cpp b/src/fsfw/power/PowerSensor.cpp similarity index 98% rename from power/PowerSensor.cpp rename to src/fsfw/power/PowerSensor.cpp index 40d7afc6..e1e31353 100644 --- a/power/PowerSensor.cpp +++ b/src/fsfw/power/PowerSensor.cpp @@ -1,6 +1,6 @@ -#include "PowerSensor.h" +#include "fsfw/power/PowerSensor.h" -#include "../ipc/QueueFactory.h" +#include "fsfw/ipc/QueueFactory.h" PowerSensor::PowerSensor(object_id_t objectId, sid_t setId, VariableIds ids, DefaultLimits limits, SensorEvents events, uint16_t confirmationCount) : diff --git a/power/PowerSensor.h b/src/fsfw/power/PowerSensor.h similarity index 87% rename from power/PowerSensor.h rename to src/fsfw/power/PowerSensor.h index 5a21ab10..d00c5420 100644 --- a/power/PowerSensor.h +++ b/src/fsfw/power/PowerSensor.h @@ -1,12 +1,12 @@ #ifndef FSFW_POWER_POWERSENSOR_H_ #define FSFW_POWER_POWERSENSOR_H_ -#include "../datapoollocal/StaticLocalDataSet.h" -#include "../devicehandlers/HealthDevice.h" -#include "../monitoring/LimitMonitor.h" -#include "../parameters/ParameterHelper.h" -#include "../objectmanager/SystemObject.h" -#include "../ipc/MessageQueueIF.h" +#include "fsfw/datapoollocal/StaticLocalDataSet.h" +#include "fsfw/devicehandlers/HealthDevice.h" +#include "fsfw/monitoring/LimitMonitor.h" +#include "fsfw/parameters/ParameterHelper.h" +#include "fsfw/objectmanager/SystemObject.h" +#include "fsfw/ipc/MessageQueueIF.h" class PowerController; diff --git a/power/PowerSwitchIF.h b/src/fsfw/power/PowerSwitchIF.h similarity index 100% rename from power/PowerSwitchIF.h rename to src/fsfw/power/PowerSwitchIF.h diff --git a/power/PowerSwitcher.cpp b/src/fsfw/power/PowerSwitcher.cpp similarity index 93% rename from power/PowerSwitcher.cpp rename to src/fsfw/power/PowerSwitcher.cpp index ed37998e..f849a7fb 100644 --- a/power/PowerSwitcher.cpp +++ b/src/fsfw/power/PowerSwitcher.cpp @@ -1,7 +1,7 @@ -#include "PowerSwitcher.h" +#include "fsfw/power/PowerSwitcher.h" -#include "../objectmanager/ObjectManagerIF.h" -#include "../serviceinterface/ServiceInterfaceStream.h" +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/serviceinterface/ServiceInterface.h" PowerSwitcher::PowerSwitcher(uint8_t setSwitch1, uint8_t setSwitch2, PowerSwitcher::State_t setStartState): @@ -10,7 +10,7 @@ PowerSwitcher::PowerSwitcher(uint8_t setSwitch1, uint8_t setSwitch2, } ReturnValue_t PowerSwitcher::initialize(object_id_t powerSwitchId) { - power = objectManager->get(powerSwitchId); + power = ObjectManager::instance()->get(powerSwitchId); if (power == nullptr) { return HasReturnvaluesIF::RETURN_FAILED; } diff --git a/power/PowerSwitcher.h b/src/fsfw/power/PowerSwitcher.h similarity index 100% rename from power/PowerSwitcher.h rename to src/fsfw/power/PowerSwitcher.h diff --git a/pus/CMakeLists.txt b/src/fsfw/pus/CMakeLists.txt similarity index 100% rename from pus/CMakeLists.txt rename to src/fsfw/pus/CMakeLists.txt diff --git a/pus/CService200ModeCommanding.cpp b/src/fsfw/pus/CService200ModeCommanding.cpp similarity index 90% rename from pus/CService200ModeCommanding.cpp rename to src/fsfw/pus/CService200ModeCommanding.cpp index 70caadd1..66c61dbe 100644 --- a/pus/CService200ModeCommanding.cpp +++ b/src/fsfw/pus/CService200ModeCommanding.cpp @@ -1,10 +1,11 @@ -#include "CService200ModeCommanding.h" -#include "servicepackets/Service200Packets.h" +#include "fsfw/pus/CService200ModeCommanding.h" +#include "fsfw/pus/servicepackets/Service200Packets.h" -#include "../modes/HasModesIF.h" -#include "../serviceinterface/ServiceInterfaceStream.h" -#include "../serialize/SerialLinkedListAdapter.h" -#include "../modes/ModeMessage.h" +#include "fsfw/modes/HasModesIF.h" +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/serialize/SerialLinkedListAdapter.h" +#include "fsfw/modes/ModeMessage.h" CService200ModeCommanding::CService200ModeCommanding(object_id_t objectId, uint16_t apid, uint8_t serviceId, uint8_t numParallelCommands, @@ -40,7 +41,7 @@ ReturnValue_t CService200ModeCommanding::getMessageQueueAndObject( ReturnValue_t CService200ModeCommanding::checkInterfaceAndAcquireMessageQueue( MessageQueueId_t* messageQueueToSet, object_id_t* objectId) { - HasModesIF * destination = objectManager->get(*objectId); + HasModesIF * destination = ObjectManager::instance()->get(*objectId); if(destination == nullptr) { return CommandingServiceBase::INVALID_OBJECT; diff --git a/pus/CService200ModeCommanding.h b/src/fsfw/pus/CService200ModeCommanding.h similarity index 98% rename from pus/CService200ModeCommanding.h rename to src/fsfw/pus/CService200ModeCommanding.h index 84040212..d523d6c3 100644 --- a/pus/CService200ModeCommanding.h +++ b/src/fsfw/pus/CService200ModeCommanding.h @@ -1,7 +1,7 @@ #ifndef FSFW_PUS_CSERVICE200MODECOMMANDING_H_ #define FSFW_PUS_CSERVICE200MODECOMMANDING_H_ -#include "../tmtcservices/CommandingServiceBase.h" +#include "fsfw/tmtcservices/CommandingServiceBase.h" /** * @brief Custom PUS service to set mode of all objects implementing HasModesIF diff --git a/pus/CService201HealthCommanding.cpp b/src/fsfw/pus/CService201HealthCommanding.cpp similarity index 90% rename from pus/CService201HealthCommanding.cpp rename to src/fsfw/pus/CService201HealthCommanding.cpp index ca761f14..1e414c82 100644 --- a/pus/CService201HealthCommanding.cpp +++ b/src/fsfw/pus/CService201HealthCommanding.cpp @@ -1,9 +1,11 @@ -#include "CService201HealthCommanding.h" +#include "fsfw/pus/CService201HealthCommanding.h" +#include "fsfw/pus/servicepackets/Service201Packets.h" + +#include "fsfw/health/HasHealthIF.h" +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/health/HealthMessage.h" -#include "../health/HasHealthIF.h" -#include "../serviceinterface/ServiceInterfaceStream.h" -#include "../health/HealthMessage.h" -#include "servicepackets/Service201Packets.h" CService201HealthCommanding::CService201HealthCommanding(object_id_t objectId, uint16_t apid, uint8_t serviceId, uint8_t numParallelCommands, @@ -43,7 +45,7 @@ ReturnValue_t CService201HealthCommanding::getMessageQueueAndObject( ReturnValue_t CService201HealthCommanding::checkInterfaceAndAcquireMessageQueue( MessageQueueId_t* messageQueueToSet, object_id_t* objectId) { - HasHealthIF * destination = objectManager->get(*objectId); + HasHealthIF * destination = ObjectManager::instance()->get(*objectId); if(destination == nullptr) { return CommandingServiceBase::INVALID_OBJECT; } diff --git a/pus/CService201HealthCommanding.h b/src/fsfw/pus/CService201HealthCommanding.h similarity index 100% rename from pus/CService201HealthCommanding.h rename to src/fsfw/pus/CService201HealthCommanding.h diff --git a/pus/Service17Test.cpp b/src/fsfw/pus/Service17Test.cpp similarity index 59% rename from pus/Service17Test.cpp rename to src/fsfw/pus/Service17Test.cpp index 85a32e1e..20227172 100644 --- a/pus/Service17Test.cpp +++ b/src/fsfw/pus/Service17Test.cpp @@ -1,8 +1,9 @@ -#include "Service17Test.h" +#include "fsfw/FSFW.h" +#include "fsfw/pus/Service17Test.h" -#include "../serviceinterface/ServiceInterfaceStream.h" -#include "../objectmanager/SystemObject.h" -#include "../tmtcpacket/pus/TmPacketStored.h" +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/objectmanager/SystemObject.h" +#include "fsfw/tmtcpacket/pus/tm/TmPacketStored.h" Service17Test::Service17Test(object_id_t objectId, @@ -17,15 +18,25 @@ Service17Test::~Service17Test() { ReturnValue_t Service17Test::handleRequest(uint8_t subservice) { switch(subservice) { case Subservice::CONNECTION_TEST: { - TmPacketStored connectionPacket(apid, serviceId, +#if FSFW_USE_PUS_C_TELEMETRY == 0 + TmPacketStoredPusA connectionPacket(apid, serviceId, Subservice::CONNECTION_TEST_REPORT, packetSubCounter++); +#else + TmPacketStoredPusC connectionPacket(apid, serviceId, + Subservice::CONNECTION_TEST_REPORT, packetSubCounter++); +#endif connectionPacket.sendPacket(requestQueue->getDefaultDestination(), requestQueue->getId()); return HasReturnvaluesIF::RETURN_OK; } case Subservice::EVENT_TRIGGER_TEST: { - TmPacketStored connectionPacket(apid, serviceId, +#if FSFW_USE_PUS_C_TELEMETRY == 0 + TmPacketStoredPusA connectionPacket(apid, serviceId, Subservice::CONNECTION_TEST_REPORT, packetSubCounter++); +#else + TmPacketStoredPusC connectionPacket(apid, serviceId, + Subservice::CONNECTION_TEST_REPORT, packetSubCounter++); +#endif connectionPacket.sendPacket(requestQueue->getDefaultDestination(), requestQueue->getId()); triggerEvent(TEST, 1234, 5678); diff --git a/pus/Service17Test.h b/src/fsfw/pus/Service17Test.h similarity index 93% rename from pus/Service17Test.h rename to src/fsfw/pus/Service17Test.h index 83d436ea..d1e1ecce 100644 --- a/pus/Service17Test.h +++ b/src/fsfw/pus/Service17Test.h @@ -1,8 +1,8 @@ #ifndef FSFW_PUS_SERVICE17TEST_H_ #define FSFW_PUS_SERVICE17TEST_H_ -#include "../tmtcservices/PusServiceBase.h" -#include "../objectmanager/SystemObject.h" +#include "fsfw/tmtcservices/PusServiceBase.h" +#include "fsfw/objectmanager/SystemObject.h" /** * @brief Test Service diff --git a/pus/Service1TelecommandVerification.cpp b/src/fsfw/pus/Service1TelecommandVerification.cpp similarity index 77% rename from pus/Service1TelecommandVerification.cpp rename to src/fsfw/pus/Service1TelecommandVerification.cpp index 7ce75478..c6b024f9 100644 --- a/pus/Service1TelecommandVerification.cpp +++ b/src/fsfw/pus/Service1TelecommandVerification.cpp @@ -1,11 +1,12 @@ -#include "Service1TelecommandVerification.h" -#include "servicepackets/Service1Packets.h" +#include "fsfw/pus/Service1TelecommandVerification.h" +#include "fsfw/pus/servicepackets/Service1Packets.h" -#include "../ipc/QueueFactory.h" -#include "../tmtcservices/PusVerificationReport.h" -#include "../tmtcpacket/pus/TmPacketStored.h" -#include "../serviceinterface/ServiceInterfaceStream.h" -#include "../tmtcservices/AcceptsTelemetryIF.h" +#include "fsfw/ipc/QueueFactory.h" +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/tmtcservices/PusVerificationReport.h" +#include "fsfw/tmtcpacket/pus/tm/TmPacketStored.h" +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/tmtcservices/AcceptsTelemetryIF.h" Service1TelecommandVerification::Service1TelecommandVerification( object_id_t objectId, uint16_t apid, uint8_t serviceId, @@ -68,8 +69,13 @@ ReturnValue_t Service1TelecommandVerification::generateFailureReport( message->getTcSequenceControl(), message->getStep(), message->getErrorCode(), message->getParameter1(), message->getParameter2()); - TmPacketStored tmPacket(apid, serviceId, message->getReportId(), +#if FSFW_USE_PUS_C_TELEMETRY == 0 + TmPacketStoredPusA tmPacket(apid, serviceId, message->getReportId(), packetSubCounter++, &report); +#else + TmPacketStoredPusC tmPacket(apid, serviceId, message->getReportId(), + packetSubCounter++, &report); +#endif ReturnValue_t result = tmPacket.sendPacket(tmQueue->getDefaultDestination(), tmQueue->getId()); return result; @@ -79,8 +85,13 @@ ReturnValue_t Service1TelecommandVerification::generateSuccessReport( PusVerificationMessage *message) { SuccessReport report(message->getReportId(),message->getTcPacketId(), message->getTcSequenceControl(),message->getStep()); - TmPacketStored tmPacket(apid, serviceId, message->getReportId(), +#if FSFW_USE_PUS_C_TELEMETRY == 0 + TmPacketStoredPusA tmPacket(apid, serviceId, message->getReportId(), packetSubCounter++, &report); +#else + TmPacketStoredPusC tmPacket(apid, serviceId, message->getReportId(), + packetSubCounter++, &report); +#endif ReturnValue_t result = tmPacket.sendPacket(tmQueue->getDefaultDestination(), tmQueue->getId()); return result; @@ -89,7 +100,7 @@ ReturnValue_t Service1TelecommandVerification::generateSuccessReport( ReturnValue_t Service1TelecommandVerification::initialize() { // Get target object for TC verification messages - AcceptsTelemetryIF* funnel = objectManager-> + AcceptsTelemetryIF* funnel = ObjectManager::instance()-> get(targetDestination); if(funnel == nullptr){ #if FSFW_CPP_OSTREAM_ENABLED == 1 diff --git a/pus/Service1TelecommandVerification.h b/src/fsfw/pus/Service1TelecommandVerification.h similarity index 91% rename from pus/Service1TelecommandVerification.h rename to src/fsfw/pus/Service1TelecommandVerification.h index 3d68a4e0..26284493 100644 --- a/pus/Service1TelecommandVerification.h +++ b/src/fsfw/pus/Service1TelecommandVerification.h @@ -1,12 +1,12 @@ #ifndef FSFW_PUS_SERVICE1TELECOMMANDVERIFICATION_H_ #define FSFW_PUS_SERVICE1TELECOMMANDVERIFICATION_H_ -#include "../objectmanager/SystemObject.h" -#include "../returnvalues/HasReturnvaluesIF.h" -#include "../tasks/ExecutableObjectIF.h" -#include "../tmtcservices/AcceptsVerifyMessageIF.h" -#include "../tmtcservices/PusVerificationReport.h" -#include "../ipc/MessageQueueIF.h" +#include "fsfw/objectmanager/SystemObject.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" +#include "fsfw/tasks/ExecutableObjectIF.h" +#include "fsfw/tmtcservices/AcceptsVerifyMessageIF.h" +#include "fsfw/tmtcservices/PusVerificationReport.h" +#include "fsfw/ipc/MessageQueueIF.h" /** * @brief Verify TC acceptance, start, progress and execution. diff --git a/pus/Service20ParameterManagement.cpp b/src/fsfw/pus/Service20ParameterManagement.cpp similarity index 93% rename from pus/Service20ParameterManagement.cpp rename to src/fsfw/pus/Service20ParameterManagement.cpp index 90e96650..e28e7804 100644 --- a/pus/Service20ParameterManagement.cpp +++ b/src/fsfw/pus/Service20ParameterManagement.cpp @@ -1,11 +1,11 @@ -#include "Service20ParameterManagement.h" -#include "servicepackets/Service20Packets.h" +#include "fsfw/pus/Service20ParameterManagement.h" +#include "fsfw/pus/servicepackets/Service20Packets.h" -#include -#include -#include -#include -#include +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/parameters/HasParametersIF.h" +#include "fsfw/parameters/ParameterMessage.h" +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/parameters/ReceivesParameterMessagesIF.h" Service20ParameterManagement::Service20ParameterManagement(object_id_t objectId, uint16_t apid, @@ -65,7 +65,7 @@ ReturnValue_t Service20ParameterManagement::checkInterfaceAndAcquireMessageQueue MessageQueueId_t* messageQueueToSet, object_id_t* objectId) { // check ReceivesParameterMessagesIF property of target ReceivesParameterMessagesIF* possibleTarget = - objectManager->get(*objectId); + ObjectManager::instance()->get(*objectId); if(possibleTarget == nullptr) { #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "Service20ParameterManagement::checkInterfaceAndAcquire" @@ -133,6 +133,9 @@ ReturnValue_t Service20ParameterManagement::prepareLoadCommand( store_address_t storeAddress; size_t parameterDataLen = tcDataLen - sizeof(object_id_t) - sizeof(ParameterId_t) - sizeof(uint32_t); + if(parameterDataLen == 0) { + return CommandingServiceBase::INVALID_TC; + } ReturnValue_t result = IPCStore->getFreeElement(&storeAddress, parameterDataLen, &storePointer); if(result != HasReturnvaluesIF::RETURN_OK) { diff --git a/pus/Service20ParameterManagement.h b/src/fsfw/pus/Service20ParameterManagement.h similarity index 97% rename from pus/Service20ParameterManagement.h rename to src/fsfw/pus/Service20ParameterManagement.h index 488edfb5..63ec199c 100644 --- a/pus/Service20ParameterManagement.h +++ b/src/fsfw/pus/Service20ParameterManagement.h @@ -1,7 +1,7 @@ #ifndef FSFW_PUS_SERVICE20PARAMETERMANAGEMENT_H_ #define FSFW_PUS_SERVICE20PARAMETERMANAGEMENT_H_ -#include +#include "fsfw/tmtcservices/CommandingServiceBase.h" /** * @brief PUS Service 20 Parameter Service implementation diff --git a/pus/Service2DeviceAccess.cpp b/src/fsfw/pus/Service2DeviceAccess.cpp similarity index 90% rename from pus/Service2DeviceAccess.cpp rename to src/fsfw/pus/Service2DeviceAccess.cpp index 72db82df..0e5edfd3 100644 --- a/pus/Service2DeviceAccess.cpp +++ b/src/fsfw/pus/Service2DeviceAccess.cpp @@ -1,14 +1,15 @@ -#include "Service2DeviceAccess.h" -#include "servicepackets/Service2Packets.h" +#include "fsfw/pus/Service2DeviceAccess.h" +#include "fsfw/pus/servicepackets/Service2Packets.h" -#include "../devicehandlers/DeviceHandlerIF.h" -#include "../storagemanager/StorageManagerIF.h" -#include "../devicehandlers/DeviceHandlerMessage.h" -#include "../serialize/EndianConverter.h" -#include "../action/ActionMessage.h" -#include "../serialize/SerializeAdapter.h" -#include "../serialize/SerialLinkedListAdapter.h" -#include "../serviceinterface/ServiceInterfaceStream.h" +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/devicehandlers/DeviceHandlerIF.h" +#include "fsfw/storagemanager/StorageManagerIF.h" +#include "fsfw/devicehandlers/DeviceHandlerMessage.h" +#include "fsfw/serialize/EndianConverter.h" +#include "fsfw/action/ActionMessage.h" +#include "fsfw/serialize/SerializeAdapter.h" +#include "fsfw/serialize/SerialLinkedListAdapter.h" +#include "fsfw/serviceinterface/ServiceInterface.h" Service2DeviceAccess::Service2DeviceAccess(object_id_t objectId, uint16_t apid, uint8_t serviceId, uint8_t numberOfParallelCommands, @@ -47,7 +48,7 @@ ReturnValue_t Service2DeviceAccess::getMessageQueueAndObject( ReturnValue_t Service2DeviceAccess::checkInterfaceAndAcquireMessageQueue( MessageQueueId_t * messageQueueToSet, object_id_t *objectId) { DeviceHandlerIF* possibleTarget = - objectManager->get(*objectId); + ObjectManager::instance()->get(*objectId); if(possibleTarget == nullptr) { return CommandingServiceBase::INVALID_OBJECT; } diff --git a/pus/Service2DeviceAccess.h b/src/fsfw/pus/Service2DeviceAccess.h similarity index 95% rename from pus/Service2DeviceAccess.h rename to src/fsfw/pus/Service2DeviceAccess.h index b62e6854..e518863c 100644 --- a/pus/Service2DeviceAccess.h +++ b/src/fsfw/pus/Service2DeviceAccess.h @@ -1,9 +1,9 @@ #ifndef FSFW_PUS_SERVICE2DEVICEACCESS_H_ #define FSFW_PUS_SERVICE2DEVICEACCESS_H_ -#include "../objectmanager/SystemObjectIF.h" -#include "../devicehandlers/AcceptsDeviceResponsesIF.h" -#include "../tmtcservices/CommandingServiceBase.h" +#include "fsfw/objectmanager/SystemObjectIF.h" +#include "fsfw/devicehandlers/AcceptsDeviceResponsesIF.h" +#include "fsfw/tmtcservices/CommandingServiceBase.h" /** * @brief Raw Commanding and Wiretapping of devices. diff --git a/pus/Service3Housekeeping.cpp b/src/fsfw/pus/Service3Housekeeping.cpp similarity index 97% rename from pus/Service3Housekeeping.cpp rename to src/fsfw/pus/Service3Housekeeping.cpp index c4f80c2a..2b91f366 100644 --- a/pus/Service3Housekeeping.cpp +++ b/src/fsfw/pus/Service3Housekeeping.cpp @@ -1,7 +1,8 @@ -#include "Service3Housekeeping.h" -#include "servicepackets/Service3Packets.h" -#include "../datapoollocal/HasLocalDataPoolIF.h" +#include "fsfw/pus/Service3Housekeeping.h" +#include "fsfw/pus/servicepackets/Service3Packets.h" +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/datapoollocal/HasLocalDataPoolIF.h" Service3Housekeeping::Service3Housekeeping(object_id_t objectId, uint16_t apid, uint8_t serviceId): @@ -56,7 +57,7 @@ ReturnValue_t Service3Housekeeping::checkInterfaceAndAcquireMessageQueue( MessageQueueId_t* messageQueueToSet, object_id_t* objectId) { // check HasLocalDataPoolIF property of target HasLocalDataPoolIF* possibleTarget = - objectManager->get(*objectId); + ObjectManager::instance()->get(*objectId); if(possibleTarget == nullptr){ return CommandingServiceBase::INVALID_OBJECT; } diff --git a/pus/Service3Housekeeping.h b/src/fsfw/pus/Service3Housekeeping.h similarity index 96% rename from pus/Service3Housekeeping.h rename to src/fsfw/pus/Service3Housekeeping.h index 269710ef..d2dc6066 100644 --- a/pus/Service3Housekeeping.h +++ b/src/fsfw/pus/Service3Housekeeping.h @@ -1,9 +1,9 @@ #ifndef FSFW_PUS_SERVICE3HOUSEKEEPINGSERVICE_H_ #define FSFW_PUS_SERVICE3HOUSEKEEPINGSERVICE_H_ -#include "../housekeeping/AcceptsHkPacketsIF.h" -#include "../housekeeping/HousekeepingMessage.h" -#include "../tmtcservices/CommandingServiceBase.h" +#include "fsfw/housekeeping/AcceptsHkPacketsIF.h" +#include "fsfw/housekeeping/HousekeepingMessage.h" +#include "fsfw/tmtcservices/CommandingServiceBase.h" /** * @brief Manges spacecraft housekeeping reports and diff --git a/pus/Service5EventReporting.cpp b/src/fsfw/pus/Service5EventReporting.cpp similarity index 71% rename from pus/Service5EventReporting.cpp rename to src/fsfw/pus/Service5EventReporting.cpp index 965a27ad..2293ab20 100644 --- a/pus/Service5EventReporting.cpp +++ b/src/fsfw/pus/Service5EventReporting.cpp @@ -1,10 +1,11 @@ -#include "Service5EventReporting.h" -#include "servicepackets/Service5Packets.h" +#include "fsfw/pus/Service5EventReporting.h" +#include "fsfw/pus/servicepackets/Service5Packets.h" -#include "../serviceinterface/ServiceInterfaceStream.h" -#include "../events/EventManagerIF.h" -#include "../ipc/QueueFactory.h" -#include "../tmtcpacket/pus/TmPacketStored.h" +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/events/EventManagerIF.h" +#include "fsfw/ipc/QueueFactory.h" +#include "fsfw/tmtcpacket/pus/tm/TmPacketStored.h" Service5EventReporting::Service5EventReporting(object_id_t objectId, @@ -40,8 +41,7 @@ ReturnValue_t Service5EventReporting::performService() { } } #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::debug << "Service5EventReporting::generateEventReport:" - " Too many events" << std::endl; + sif::warning << "Service5EventReporting::generateEventReport: Too many events" << std::endl; #endif return HasReturnvaluesIF::RETURN_OK; } @@ -52,14 +52,22 @@ ReturnValue_t Service5EventReporting::generateEventReport( { EventReport report(message.getEventId(),message.getReporter(), message.getParameter1(),message.getParameter2()); - TmPacketStored tmPacket(PusServiceBase::apid, PusServiceBase::serviceId, +#if FSFW_USE_PUS_C_TELEMETRY == 0 + TmPacketStoredPusA tmPacket(PusServiceBase::apid, PusServiceBase::serviceId, message.getSeverity(), packetSubCounter++, &report); +#else + TmPacketStoredPusC tmPacket(PusServiceBase::apid, PusServiceBase::serviceId, + message.getSeverity(), packetSubCounter++, &report); +#endif ReturnValue_t result = tmPacket.sendPacket( requestQueue->getDefaultDestination(),requestQueue->getId()); if(result != HasReturnvaluesIF::RETURN_OK) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::debug << "Service5EventReporting::generateEventReport:" - " Could not send TM packet" << std::endl; + sif::warning << "Service5EventReporting::generateEventReport: " + "Could not send TM packet" << std::endl; +#else + sif::printWarning("Service5EventReporting::generateEventReport: " + "Could not send TM packet\n"); #endif } return result; @@ -84,7 +92,7 @@ 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->get( + EventManagerIF* manager = ObjectManager::instance()->get( objects::EVENT_MANAGER); if (manager == NULL) { return RETURN_FAILED; diff --git a/pus/Service5EventReporting.h b/src/fsfw/pus/Service5EventReporting.h similarity index 97% rename from pus/Service5EventReporting.h rename to src/fsfw/pus/Service5EventReporting.h index 69242801..35ff34b6 100644 --- a/pus/Service5EventReporting.h +++ b/src/fsfw/pus/Service5EventReporting.h @@ -1,8 +1,8 @@ #ifndef FSFW_PUS_SERVICE5EVENTREPORTING_H_ #define FSFW_PUS_SERVICE5EVENTREPORTING_H_ -#include "../tmtcservices/PusServiceBase.h" -#include "../events/EventMessage.h" +#include "fsfw/tmtcservices/PusServiceBase.h" +#include "fsfw/events/EventMessage.h" /** * @brief Report on-board events like information or errors diff --git a/pus/Service8FunctionManagement.cpp b/src/fsfw/pus/Service8FunctionManagement.cpp similarity index 89% rename from pus/Service8FunctionManagement.cpp rename to src/fsfw/pus/Service8FunctionManagement.cpp index 54187a82..48820d6e 100644 --- a/pus/Service8FunctionManagement.cpp +++ b/src/fsfw/pus/Service8FunctionManagement.cpp @@ -1,11 +1,12 @@ -#include "Service8FunctionManagement.h" -#include "servicepackets/Service8Packets.h" +#include "fsfw/pus/Service8FunctionManagement.h" +#include "fsfw/pus/servicepackets/Service8Packets.h" -#include "../objectmanager/SystemObjectIF.h" -#include "../action/HasActionsIF.h" -#include "../devicehandlers/DeviceHandlerIF.h" -#include "../serialize/SerializeAdapter.h" -#include "../serviceinterface/ServiceInterfaceStream.h" +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/objectmanager/SystemObjectIF.h" +#include "fsfw/action/HasActionsIF.h" +#include "fsfw/devicehandlers/DeviceHandlerIF.h" +#include "fsfw/serialize/SerializeAdapter.h" +#include "fsfw/serviceinterface/ServiceInterface.h" Service8FunctionManagement::Service8FunctionManagement(object_id_t objectId, uint16_t apid, uint8_t serviceId, uint8_t numParallelCommands, @@ -32,8 +33,8 @@ ReturnValue_t Service8FunctionManagement::getMessageQueueAndObject( if(tcDataLen < sizeof(object_id_t)) { return CommandingServiceBase::INVALID_TC; } - SerializeAdapter::deSerialize(objectId, &tcData, - &tcDataLen, SerializeIF::Endianness::BIG); + // Can't fail, size was checked before + SerializeAdapter::deSerialize(objectId, &tcData, &tcDataLen, SerializeIF::Endianness::BIG); return checkInterfaceAndAcquireMessageQueue(id,objectId); } @@ -41,7 +42,7 @@ ReturnValue_t Service8FunctionManagement::getMessageQueueAndObject( ReturnValue_t Service8FunctionManagement::checkInterfaceAndAcquireMessageQueue( MessageQueueId_t* messageQueueToSet, object_id_t* objectId) { // check HasActionIF property of target - HasActionsIF* possibleTarget = objectManager->get(*objectId); + HasActionsIF* possibleTarget = ObjectManager::instance()->get(*objectId); if(possibleTarget == nullptr){ return CommandingServiceBase::INVALID_OBJECT; } diff --git a/pus/Service8FunctionManagement.h b/src/fsfw/pus/Service8FunctionManagement.h similarity index 96% rename from pus/Service8FunctionManagement.h rename to src/fsfw/pus/Service8FunctionManagement.h index 00153cfb..debdf636 100644 --- a/pus/Service8FunctionManagement.h +++ b/src/fsfw/pus/Service8FunctionManagement.h @@ -1,8 +1,8 @@ #ifndef FSFW_PUS_SERVICE8FUNCTIONMANAGEMENT_H_ #define FSFW_PUS_SERVICE8FUNCTIONMANAGEMENT_H_ -#include "../action/ActionMessage.h" -#include "../tmtcservices/CommandingServiceBase.h" +#include "fsfw/action/ActionMessage.h" +#include "fsfw/tmtcservices/CommandingServiceBase.h" /** * @brief Functional commanding. diff --git a/pus/Service9TimeManagement.cpp b/src/fsfw/pus/Service9TimeManagement.cpp similarity index 84% rename from pus/Service9TimeManagement.cpp rename to src/fsfw/pus/Service9TimeManagement.cpp index 5625bdd8..619b2405 100644 --- a/pus/Service9TimeManagement.cpp +++ b/src/fsfw/pus/Service9TimeManagement.cpp @@ -1,9 +1,9 @@ -#include "Service9TimeManagement.h" -#include "servicepackets/Service9Packets.h" +#include "fsfw/pus/Service9TimeManagement.h" +#include "fsfw/pus/servicepackets/Service9Packets.h" -#include "../timemanager/CCSDSTime.h" -#include "../events/EventManagerIF.h" -#include "../serviceinterface/ServiceInterfaceStream.h" +#include "fsfw/timemanager/CCSDSTime.h" +#include "fsfw/events/EventManagerIF.h" +#include "fsfw/serviceinterface/ServiceInterface.h" Service9TimeManagement::Service9TimeManagement(object_id_t objectId, diff --git a/pus/Service9TimeManagement.h b/src/fsfw/pus/Service9TimeManagement.h similarity index 96% rename from pus/Service9TimeManagement.h rename to src/fsfw/pus/Service9TimeManagement.h index 70b86966..d8e183a4 100644 --- a/pus/Service9TimeManagement.h +++ b/src/fsfw/pus/Service9TimeManagement.h @@ -1,7 +1,7 @@ #ifndef FSFW_PUS_SERVICE9TIMEMANAGEMENT_H_ #define FSFW_PUS_SERVICE9TIMEMANAGEMENT_H_ -#include "../tmtcservices/PusServiceBase.h" +#include "fsfw/tmtcservices/PusServiceBase.h" class Service9TimeManagement: public PusServiceBase { public: diff --git a/pus/servicepackets/Service1Packets.h b/src/fsfw/pus/servicepackets/Service1Packets.h similarity index 98% rename from pus/servicepackets/Service1Packets.h rename to src/fsfw/pus/servicepackets/Service1Packets.h index 2249b4b0..02ae339f 100644 --- a/pus/servicepackets/Service1Packets.h +++ b/src/fsfw/pus/servicepackets/Service1Packets.h @@ -13,10 +13,10 @@ /** * @brief FailureReport class to serialize a failure report - * @brief Subservice 1, 3, 5, 7 + * @brief Subservice 2, 4, 6, 8 * @ingroup spacepackets */ -class FailureReport: public SerializeIF { //!< [EXPORT] : [SUBSERVICE] 1, 3, 5, 7 +class FailureReport: public SerializeIF { //!< [EXPORT] : [SUBSERVICE] 2, 4, 6, 8 public: FailureReport(uint8_t failureSubtype_, uint16_t packetId_, uint16_t packetSequenceControl_, uint8_t stepNumber_, @@ -108,10 +108,10 @@ private: }; /** - * @brief Subservices 2, 4, 6, 8 + * @brief Subservices 1, 3, 5, 7 * @ingroup spacepackets */ -class SuccessReport: public SerializeIF { //!< [EXPORT] : [SUBSERVICE] 2, 4, 6, 8 +class SuccessReport: public SerializeIF { //!< [EXPORT] : [SUBSERVICE] 1, 3, 5, 7 public: SuccessReport(uint8_t subtype_, uint16_t packetId_, uint16_t packetSequenceControl_,uint8_t stepNumber_) : diff --git a/pus/servicepackets/Service200Packets.h b/src/fsfw/pus/servicepackets/Service200Packets.h similarity index 100% rename from pus/servicepackets/Service200Packets.h rename to src/fsfw/pus/servicepackets/Service200Packets.h diff --git a/pus/servicepackets/Service201Packets.h b/src/fsfw/pus/servicepackets/Service201Packets.h similarity index 100% rename from pus/servicepackets/Service201Packets.h rename to src/fsfw/pus/servicepackets/Service201Packets.h diff --git a/pus/servicepackets/Service20Packets.h b/src/fsfw/pus/servicepackets/Service20Packets.h similarity index 96% rename from pus/servicepackets/Service20Packets.h rename to src/fsfw/pus/servicepackets/Service20Packets.h index 33bd153d..6c7eb6f5 100644 --- a/pus/servicepackets/Service20Packets.h +++ b/src/fsfw/pus/servicepackets/Service20Packets.h @@ -27,12 +27,11 @@ public: ParameterCommand(uint8_t* storePointer, size_t parameterDataLen): parameterBuffer(storePointer, parameterDataLen) { #if FSFW_VERBOSE_LEVEL >= 1 - if(parameterDataLen < sizeof(object_id_t) + sizeof(ParameterId_t) + 4) { + if(parameterDataLen == 0) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "ParameterCommand: Parameter data length is less than 12!" - << std::endl; + sif::warning << "ParameterCommand: Parameter data length is 0" << std::endl; #else - sif::printWarning("ParameterCommand: Parameter data length is less than 12!\n"); + sif::printWarning("ParameterCommand: Parameter data length is 0!\n"); #endif } #endif /* FSFW_VERBOSE_LEVEL >= 1 */ diff --git a/pus/servicepackets/Service2Packets.h b/src/fsfw/pus/servicepackets/Service2Packets.h similarity index 100% rename from pus/servicepackets/Service2Packets.h rename to src/fsfw/pus/servicepackets/Service2Packets.h diff --git a/pus/servicepackets/Service3Packets.h b/src/fsfw/pus/servicepackets/Service3Packets.h similarity index 100% rename from pus/servicepackets/Service3Packets.h rename to src/fsfw/pus/servicepackets/Service3Packets.h diff --git a/pus/servicepackets/Service5Packets.h b/src/fsfw/pus/servicepackets/Service5Packets.h similarity index 100% rename from pus/servicepackets/Service5Packets.h rename to src/fsfw/pus/servicepackets/Service5Packets.h diff --git a/pus/servicepackets/Service8Packets.h b/src/fsfw/pus/servicepackets/Service8Packets.h similarity index 100% rename from pus/servicepackets/Service8Packets.h rename to src/fsfw/pus/servicepackets/Service8Packets.h diff --git a/pus/servicepackets/Service9Packets.h b/src/fsfw/pus/servicepackets/Service9Packets.h similarity index 100% rename from pus/servicepackets/Service9Packets.h rename to src/fsfw/pus/servicepackets/Service9Packets.h diff --git a/src/fsfw/returnvalues/FwClassIds.h b/src/fsfw/returnvalues/FwClassIds.h new file mode 100644 index 00000000..9fa0c9ae --- /dev/null +++ b/src/fsfw/returnvalues/FwClassIds.h @@ -0,0 +1,89 @@ +#ifndef FSFW_RETURNVALUES_FWCLASSIDS_H_ +#define FSFW_RETURNVALUES_FWCLASSIDS_H_ + +#include + +// The comment block at the end is used by the returnvalue exporter. +// It is recommended to add it as well for mission returnvalues +namespace CLASS_ID { +enum: uint8_t { + FW_CLASS_ID_START = 0, // [EXPORT] : [START] + OPERATING_SYSTEM_ABSTRACTION, //OS + OBJECT_MANAGER_IF, //OM + DEVICE_HANDLER_BASE, //DHB + RMAP_CHANNEL, //RMP + POWER_SWITCH_IF, //PS + HAS_MEMORY_IF, //PP + DEVICE_STATE_MACHINE_BASE, //DSMB + DATA_SET_CLASS, //DPS + POOL_RAW_ACCESS_CLASS, //DPR + CONTROLLER_BASE, //CTR + SUBSYSTEM_BASE, //SB + MODE_STORE_IF, //MS + SUBSYSTEM, //SS + HAS_MODES_IF, //HM + COMMAND_MESSAGE, //CM + CCSDS_TIME_HELPER_CLASS, //TIM + ARRAY_LIST, //AL + ASSEMBLY_BASE, //AB + MEMORY_HELPER, //MH + SERIALIZE_IF, //SE + FIXED_MAP, //FM + FIXED_MULTIMAP, //FMM + HAS_HEALTH_IF, //HHI + FIFO_CLASS, //FF + MESSAGE_PROXY, //MQP + TRIPLE_REDUNDACY_CHECK, //TRC + TC_PACKET_CHECK, //TCC + PACKET_DISTRIBUTION, //TCD + ACCEPTS_TELECOMMANDS_IF, //PUS + DEVICE_SERVICE_BASE, //DSB + COMMAND_SERVICE_BASE, //CSB + TM_STORE_BACKEND_IF, //TMB + TM_STORE_FRONTEND_IF, //TMF + STORAGE_AND_RETRIEVAL_SERVICE, //SR + MATCH_TREE_CLASS, //MT + EVENT_MANAGER_IF, //EV + HANDLES_FAILURES_IF, //FDI + DEVICE_HANDLER_IF, //DHI + STORAGE_MANAGER_IF, //SM + THERMAL_COMPONENT_IF, //TC + INTERNAL_ERROR_CODES, //IEC + TRAP, //TRP + CCSDS_HANDLER_IF, //CCS + PARAMETER_WRAPPER, //PAW + HAS_PARAMETERS_IF, //HPA + ASCII_CONVERTER, //ASC + POWER_SWITCHER, //POS + LIMITS_IF, //LIM + COMMANDS_ACTIONS_IF, //CF + HAS_ACTIONS_IF, //HF + DEVICE_COMMUNICATION_IF, //DC + BSP, //BSP + TIME_STAMPER_IF, //TSI + SGP4PROPAGATOR_CLASS, //SGP4 + MUTEX_IF, //MUX + MESSAGE_QUEUE_IF,//MQI + SEMAPHORE_IF, //SPH + LOCAL_POOL_OWNER_IF, //LPIF + POOL_VARIABLE_IF, //PVA + HOUSEKEEPING_MANAGER, //HKM + DLE_ENCODER, //DLEE + PUS_SERVICE_3, //PUS3 + PUS_SERVICE_9, //PUS9 + FILE_SYSTEM, //FILS + LINUX_OSAL, //UXOS + HAL_SPI, //HSPI + HAL_UART, //HURT + HAL_I2C, //HI2C + HAL_GPIO, //HGIO + FIXED_SLOT_TASK_IF, //FTIF + MGM_LIS3MDL, //MGMLIS3 + MGM_RM3100, //MGMRM3100 + SPACE_PACKET_PARSER, //SPPA + FW_CLASS_ID_COUNT // [EXPORT] : [END] + +}; +} + +#endif /* FSFW_RETURNVALUES_FWCLASSIDS_H_ */ diff --git a/returnvalues/HasReturnvaluesIF.h b/src/fsfw/returnvalues/HasReturnvaluesIF.h similarity index 83% rename from returnvalues/HasReturnvaluesIF.h rename to src/fsfw/returnvalues/HasReturnvaluesIF.h index 4a3835b6..e9321ace 100644 --- a/returnvalues/HasReturnvaluesIF.h +++ b/src/fsfw/returnvalues/HasReturnvaluesIF.h @@ -22,9 +22,9 @@ public: * @param number * @return */ - static constexpr ReturnValue_t makeReturnCode(uint8_t interfaceId, + static constexpr ReturnValue_t makeReturnCode(uint8_t classId, uint8_t number) { - return (static_cast(interfaceId) << 8) + number; + return (static_cast(classId) << 8) + number; } }; diff --git a/rmap/CMakeLists.txt b/src/fsfw/rmap/CMakeLists.txt similarity index 100% rename from rmap/CMakeLists.txt rename to src/fsfw/rmap/CMakeLists.txt diff --git a/rmap/RMAP.cpp b/src/fsfw/rmap/RMAP.cpp similarity index 93% rename from rmap/RMAP.cpp rename to src/fsfw/rmap/RMAP.cpp index 7ea6e532..6ac4904d 100644 --- a/rmap/RMAP.cpp +++ b/src/fsfw/rmap/RMAP.cpp @@ -1,8 +1,8 @@ -#include "RMAP.h" -#include "rmapStructs.h" -#include "RMAPChannelIF.h" +#include "fsfw/rmap/RMAP.h" +#include "fsfw/rmap/rmapStructs.h" +#include "fsfw/rmap/RMAPChannelIF.h" -#include "../devicehandlers/DeviceCommunicationIF.h" +#include "fsfw/devicehandlers/DeviceCommunicationIF.h" #include diff --git a/rmap/RMAP.h b/src/fsfw/rmap/RMAP.h similarity index 99% rename from rmap/RMAP.h rename to src/fsfw/rmap/RMAP.h index 83e29fed..ff310db0 100644 --- a/rmap/RMAP.h +++ b/src/fsfw/rmap/RMAP.h @@ -1,8 +1,9 @@ #ifndef FSFW_RMAP_RMAP_H_ #define FSFW_RMAP_RMAP_H_ -#include "../returnvalues/HasReturnvaluesIF.h" -#include "../rmap/RMAPCookie.h" +#include "rmapConf.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" +#include "fsfw/rmap/RMAPCookie.h" //SHOULDTODO: clean up includes for RMAP, should be enough to include RMAP.h but right now it's quite chaotic... diff --git a/rmap/RMAPChannelIF.h b/src/fsfw/rmap/RMAPChannelIF.h similarity index 98% rename from rmap/RMAPChannelIF.h rename to src/fsfw/rmap/RMAPChannelIF.h index 0aa809c5..7fbda348 100644 --- a/rmap/RMAPChannelIF.h +++ b/src/fsfw/rmap/RMAPChannelIF.h @@ -1,8 +1,9 @@ #ifndef FSFW_RMAP_RMAPCHANNELIF_H_ #define FSFW_RMAP_RMAPCHANNELIF_H_ +#include "rmapConf.h" #include "RMAPCookie.h" -#include "../returnvalues/HasReturnvaluesIF.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" #include class RMAPChannelIF { diff --git a/rmap/RMAPCookie.cpp b/src/fsfw/rmap/RMAPCookie.cpp similarity index 97% rename from rmap/RMAPCookie.cpp rename to src/fsfw/rmap/RMAPCookie.cpp index f8fe2d3e..393a5ce0 100644 --- a/rmap/RMAPCookie.cpp +++ b/src/fsfw/rmap/RMAPCookie.cpp @@ -1,5 +1,6 @@ -#include "RMAPChannelIF.h" -#include "RMAPCookie.h" +#include "fsfw/rmap/RMAPChannelIF.h" +#include "fsfw/rmap/RMAPCookie.h" + #include diff --git a/rmap/RMAPCookie.h b/src/fsfw/rmap/RMAPCookie.h similarity index 95% rename from rmap/RMAPCookie.h rename to src/fsfw/rmap/RMAPCookie.h index 38542646..032e5a46 100644 --- a/rmap/RMAPCookie.h +++ b/src/fsfw/rmap/RMAPCookie.h @@ -1,8 +1,9 @@ #ifndef FSFW_RMAP_RMAPCOOKIE_H_ #define FSFW_RMAP_RMAPCOOKIE_H_ +#include "rmapConf.h" #include "rmapStructs.h" -#include "../devicehandlers/CookieIF.h" +#include "fsfw/devicehandlers/CookieIF.h" #include class RMAPChannelIF; diff --git a/rmap/RmapDeviceCommunicationIF.cpp b/src/fsfw/rmap/RmapDeviceCommunicationIF.cpp similarity index 94% rename from rmap/RmapDeviceCommunicationIF.cpp rename to src/fsfw/rmap/RmapDeviceCommunicationIF.cpp index d81baabd..2fab613e 100644 --- a/rmap/RmapDeviceCommunicationIF.cpp +++ b/src/fsfw/rmap/RmapDeviceCommunicationIF.cpp @@ -1,5 +1,5 @@ -#include "RmapDeviceCommunicationIF.h" -#include "RMAP.h" +#include "fsfw/rmap/RmapDeviceCommunicationIF.h" +#include "fsfw/rmap/RMAP.h" //TODO Cast here are all potential bugs RmapDeviceCommunicationIF::~RmapDeviceCommunicationIF() { diff --git a/rmap/RmapDeviceCommunicationIF.h b/src/fsfw/rmap/RmapDeviceCommunicationIF.h similarity index 97% rename from rmap/RmapDeviceCommunicationIF.h rename to src/fsfw/rmap/RmapDeviceCommunicationIF.h index 1333966a..36baf87b 100644 --- a/rmap/RmapDeviceCommunicationIF.h +++ b/src/fsfw/rmap/RmapDeviceCommunicationIF.h @@ -1,7 +1,8 @@ #ifndef FSFW_RMAP_RMAPDEVICECOMMUNICATIONINTERFACE_H_ #define FSFW_RMAP_RMAPDEVICECOMMUNICATIONINTERFACE_H_ -#include "../devicehandlers/DeviceCommunicationIF.h" +#include "rmapConf.h" +#include "fsfw/devicehandlers/DeviceCommunicationIF.h" /** * @brief This class is a implementation of a DeviceCommunicationIF for RMAP calls. diff --git a/src/fsfw/rmap/rmapConf.h b/src/fsfw/rmap/rmapConf.h new file mode 100644 index 00000000..c4fa1e54 --- /dev/null +++ b/src/fsfw/rmap/rmapConf.h @@ -0,0 +1,10 @@ +#ifndef FSFW_SRC_FSFW_RMAP_RAMCONF_H_ +#define FSFW_SRC_FSFW_RMAP_RAMCONF_H_ + +#include "fsfw/FSFW.h" + +#ifndef FSFW_ADD_RMAP +#warning RMAP was included but compilation was not enabled with FSFW_ADD_RMAP +#endif + +#endif /* FSFW_SRC_FSFW_RMAP_RAMCONF_H_ */ diff --git a/rmap/rmapStructs.h b/src/fsfw/rmap/rmapStructs.h similarity index 99% rename from rmap/rmapStructs.h rename to src/fsfw/rmap/rmapStructs.h index 11d8bb85..de8b3a59 100644 --- a/rmap/rmapStructs.h +++ b/src/fsfw/rmap/rmapStructs.h @@ -1,6 +1,8 @@ #ifndef FSFW_RMAP_RMAPSTRUCTS_H_ #define FSFW_RMAP_RMAPSTRUCTS_H_ +#include "rmapConf.h" + #include //SHOULDDO: having the defines within a namespace would be nice. Problem are the defines referencing the previous define, eg RMAP_COMMAND_WRITE diff --git a/src/fsfw/serialize.h b/src/fsfw/serialize.h new file mode 100644 index 00000000..7cd735bb --- /dev/null +++ b/src/fsfw/serialize.h @@ -0,0 +1,10 @@ +#ifndef FSFW_INC_FSFW_SERIALIZE_H_ +#define FSFW_INC_FSFW_SERIALIZE_H_ + +#include "src/core/serialize/EndianConverter.h" +#include "src/core/serialize/SerialArrayListAdapter.h" +#include "src/core/serialize/SerialBufferAdapter.h" +#include "src/core/serialize/SerializeElement.h" +#include "src/core/serialize/SerialLinkedListAdapter.h" + +#endif /* FSFW_INC_FSFW_SERIALIZE_H_ */ diff --git a/serialize/CMakeLists.txt b/src/fsfw/serialize/CMakeLists.txt similarity index 100% rename from serialize/CMakeLists.txt rename to src/fsfw/serialize/CMakeLists.txt diff --git a/serialize/EndianConverter.h b/src/fsfw/serialize/EndianConverter.h similarity index 100% rename from serialize/EndianConverter.h rename to src/fsfw/serialize/EndianConverter.h diff --git a/serialize/SerialArrayListAdapter.h b/src/fsfw/serialize/SerialArrayListAdapter.h similarity index 100% rename from serialize/SerialArrayListAdapter.h rename to src/fsfw/serialize/SerialArrayListAdapter.h diff --git a/serialize/SerialBufferAdapter.cpp b/src/fsfw/serialize/SerialBufferAdapter.cpp similarity index 97% rename from serialize/SerialBufferAdapter.cpp rename to src/fsfw/serialize/SerialBufferAdapter.cpp index 53b8c3d5..4f03658a 100644 --- a/serialize/SerialBufferAdapter.cpp +++ b/src/fsfw/serialize/SerialBufferAdapter.cpp @@ -1,5 +1,5 @@ -#include "../serialize/SerialBufferAdapter.h" -#include "../serviceinterface/ServiceInterfaceStream.h" +#include "fsfw/serialize/SerialBufferAdapter.h" +#include "fsfw/serviceinterface/ServiceInterface.h" #include template diff --git a/serialize/SerialBufferAdapter.h b/src/fsfw/serialize/SerialBufferAdapter.h similarity index 96% rename from serialize/SerialBufferAdapter.h rename to src/fsfw/serialize/SerialBufferAdapter.h index 9a89e18b..6c79cd03 100644 --- a/serialize/SerialBufferAdapter.h +++ b/src/fsfw/serialize/SerialBufferAdapter.h @@ -1,8 +1,8 @@ #ifndef SERIALBUFFERADAPTER_H_ #define SERIALBUFFERADAPTER_H_ -#include "../serialize/SerializeIF.h" -#include "../serialize/SerializeAdapter.h" +#include "fsfw/serialize/SerializeIF.h" +#include "fsfw/serialize/SerializeAdapter.h" /** * This adapter provides an interface for SerializeIF to serialize or deserialize diff --git a/serialize/SerialFixedArrayListAdapter.h b/src/fsfw/serialize/SerialFixedArrayListAdapter.h similarity index 100% rename from serialize/SerialFixedArrayListAdapter.h rename to src/fsfw/serialize/SerialFixedArrayListAdapter.h diff --git a/serialize/SerialLinkedListAdapter.h b/src/fsfw/serialize/SerialLinkedListAdapter.h similarity index 100% rename from serialize/SerialLinkedListAdapter.h rename to src/fsfw/serialize/SerialLinkedListAdapter.h diff --git a/src/fsfw/serialize/SerializeAdapter.h b/src/fsfw/serialize/SerializeAdapter.h new file mode 100644 index 00000000..2831472c --- /dev/null +++ b/src/fsfw/serialize/SerializeAdapter.h @@ -0,0 +1,269 @@ +#ifndef _FSFW_SERIALIZE_SERIALIZEADAPTER_H_ +#define _FSFW_SERIALIZE_SERIALIZEADAPTER_H_ + +#include "../returnvalues/HasReturnvaluesIF.h" +#include "EndianConverter.h" +#include "SerializeIF.h" +#include +#include + +/** + * @brief These adapters provides an interface to use the SerializeIF functions + * with arbitrary template objects to facilitate and simplify the + * serialization of classes with different multiple different data types + * into buffers and vice-versa. + * @details + * The correct serialization or deserialization function is chosen at + * compile time with template type deduction. + * + * @ingroup serialize + */ +class SerializeAdapter { +public: + /*** + * @brief Serialize a trivial copy-able type or a child of SerializeIF. + * @details + * The right template to be called is determined in the function itself. + * For objects of non trivial copy-able type this function is almost never + * called by the user directly. Instead helpers for specific types like + * SerialArrayListAdapter or SerialLinkedListAdapter are the right choice here. + * + * @param[in] object: Object to serialize, the used type is deduced from this pointer + * @param[in/out] buffer: Pointer to the buffer to serialize into. Buffer position will be + * incremented by the function. + * @param[in/out] size: Pointer to size of current written buffer. + * SIze will be incremented by the function. + * @param[in] maxSize: Max size of Buffer + * @param[in] streamEndianness: Endianness of serialized element as in according to + * SerializeIF::Endianness + * @return + * - @c BUFFER_TOO_SHORT The given buffer in is too short + * - @c RETURN_FAILED Generic Error + * - @c RETURN_OK Successful serialization + */ + template + static ReturnValue_t serialize(const T *object, uint8_t **buffer, + size_t *size, size_t maxSize, + SerializeIF::Endianness streamEndianness) { + InternalSerializeAdapter::value> adapter; + return adapter.serialize(object, buffer, size, maxSize, + streamEndianness); + } + + /*** + * This function can be used to serialize a trivial copy-able type or a child of SerializeIF. + * The right template to be called is determined in the function itself. + * For objects of non trivial copy-able type this function is almost never + * called by the user directly. Instead helpers for specific types like + * SerialArrayListAdapter or SerialLinkedListAdapter are the right choice here. + * + * @param[in] object: Object to serialize, the used type is deduced from this pointer + * @param[in/out] buffer: Buffer to serialize into. + * @param[out] serSize: Serialized size + * @param[in] maxSize: Max size of buffer + * @param[in] streamEndianness: Endianness of serialized element as in according to + * SerializeIF::Endianness + * @return + * - @c BUFFER_TOO_SHORT The given buffer in is too short + * - @c RETURN_FAILED Generic Error + * - @c RETURN_OK Successful serialization + */ + template + static ReturnValue_t serialize(const T *object, uint8_t* const buffer, size_t* serSize, + size_t maxSize, SerializeIF::Endianness streamEndianness) { + if(object == nullptr or buffer == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + InternalSerializeAdapter::value> adapter; + uint8_t** tempPtr = const_cast(&buffer); + size_t tmpSize = 0; + ReturnValue_t result = adapter.serialize(object, tempPtr, &tmpSize, maxSize, + streamEndianness); + if(serSize != nullptr) { + *serSize = tmpSize; + } + return result; + } + + /** + * @brief Function to return the serialized size of the object in the pointer. + * @details + * May be a trivially copy-able object or a child of SerializeIF. + * + * @param object Pointer to Object + * @return Serialized size of object + */ + template + static size_t getSerializedSize(const T *object){ + InternalSerializeAdapter::value> adapter; + return adapter.getSerializedSize(object); + } + + /** + * @brief Deserializes a object from a given buffer of given size. + * + * @details + * Object Must be trivially copy-able or a child of SerializeIF. + * Buffer will be moved to the current read location. Size will be decreased by the function. + * + * @param[in] object: Pointer to object to deserialize + * @param[in/out] buffer: Pointer to the buffer to deSerialize from. Buffer position will be + * incremented by the function + * @param[in/out] size: Pointer to remaining size of the buffer to read from. + * Will be decreased by function. + * @param[in] streamEndianness: Endianness as in according to SerializeIF::Endianness + * @return + * - @c STREAM_TOO_SHORT The input stream is too short to deSerialize the object + * - @c TOO_MANY_ELEMENTS The buffer has more inputs than expected + * - @c RETURN_FAILED Generic Error + * - @c RETURN_OK Successful deserialization + */ + template + static ReturnValue_t deSerialize(T *object, const uint8_t **buffer, + size_t *size, SerializeIF::Endianness streamEndianness) { + InternalSerializeAdapter::value> adapter; + return adapter.deSerialize(object, buffer, size, streamEndianness); + } + + /** + * @brief Deserializes a object from a given buffer of given size. + * + * @details + * Object Must be trivially copy-able or a child of SerializeIF. + * + * @param[in] object: Pointer to object to deserialize + * @param[in] buffer: Buffer to deSerialize from + * @param[out] deserSize: Deserialized length + * @param[in] streamEndianness: Endianness as in according to SerializeIF::Endianness + * @return + * - @c STREAM_TOO_SHORT The input stream is too short to deSerialize the object + * - @c TOO_MANY_ELEMENTS The buffer has more inputs than expected + * - @c RETURN_FAILED Generic Error + * - @c RETURN_OK Successful deserialization + */ + template + static ReturnValue_t deSerialize(T *object, const uint8_t* buffer, + size_t* deserSize, SerializeIF::Endianness streamEndianness) { + if(object == nullptr or buffer == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + InternalSerializeAdapter::value> adapter; + const uint8_t** tempPtr = &buffer; + size_t maxVal = -1; + ReturnValue_t result = adapter.deSerialize(object, tempPtr, &maxVal, streamEndianness); + if(deserSize != nullptr) { + *deserSize = -1 - maxVal; + } + return result; + } + +private: + /** + * Internal template to deduce the right function calls at compile time + */ + template class InternalSerializeAdapter; + + /** + * Template to be used if T is not a child of SerializeIF + * + * @tparam T T must be trivially_copyable + */ + template + class InternalSerializeAdapter { + static_assert (std::is_trivially_copyable::value, + "If a type needs to be serialized it must be a child of " + "SerializeIF or trivially copy-able"); + public: + static ReturnValue_t serialize(const T *object, uint8_t **buffer, + size_t *size, size_t max_size, + SerializeIF::Endianness streamEndianness) { + size_t ignoredSize = 0; + if (size == nullptr) { + size = &ignoredSize; + } + // Check remaining size is large enough and check integer + // overflow of *size + size_t newSize = sizeof(T) + *size; + if ((newSize <= max_size) and (newSize > *size)) { + T tmp; + switch (streamEndianness) { + case SerializeIF::Endianness::BIG: + tmp = EndianConverter::convertBigEndian(*object); + break; + case SerializeIF::Endianness::LITTLE: + tmp = EndianConverter::convertLittleEndian(*object); + break; + default: + case SerializeIF::Endianness::MACHINE: + tmp = *object; + break; + } + std::memcpy(*buffer, &tmp, sizeof(T)); + *size += sizeof(T); + (*buffer) += sizeof(T); + return HasReturnvaluesIF::RETURN_OK; + } else { + return SerializeIF::BUFFER_TOO_SHORT; + } + } + + ReturnValue_t deSerialize(T *object, const uint8_t **buffer, + size_t *size, SerializeIF::Endianness streamEndianness) { + T tmp; + if (*size >= sizeof(T)) { + *size -= sizeof(T); + std::memcpy(&tmp, *buffer, sizeof(T)); + switch (streamEndianness) { + case SerializeIF::Endianness::BIG: + *object = EndianConverter::convertBigEndian(tmp); + break; + case SerializeIF::Endianness::LITTLE: + *object = EndianConverter::convertLittleEndian(tmp); + break; + default: + case SerializeIF::Endianness::MACHINE: + *object = tmp; + break; + } + + *buffer += sizeof(T); + return HasReturnvaluesIF::RETURN_OK; + } else { + return SerializeIF::STREAM_TOO_SHORT; + } + } + + uint32_t getSerializedSize(const T *object) { + return sizeof(T); + } + }; + + /** + * Template for objects that inherit from SerializeIF + * + * @tparam T A child of SerializeIF + */ + template + class InternalSerializeAdapter { + public: + ReturnValue_t serialize(const T *object, uint8_t **buffer, size_t *size, + size_t max_size, + SerializeIF::Endianness streamEndianness) const { + size_t ignoredSize = 0; + if (size == nullptr) { + size = &ignoredSize; + } + return object->serialize(buffer, size, max_size, streamEndianness); + } + size_t getSerializedSize(const T *object) const { + return object->getSerializedSize(); + } + + ReturnValue_t deSerialize(T *object, const uint8_t **buffer, + size_t *size, SerializeIF::Endianness streamEndianness) { + return object->deSerialize(buffer, size, streamEndianness); + } + }; +}; + +#endif /* _FSFW_SERIALIZE_SERIALIZEADAPTER_H_ */ diff --git a/serialize/SerializeElement.h b/src/fsfw/serialize/SerializeElement.h similarity index 100% rename from serialize/SerializeElement.h rename to src/fsfw/serialize/SerializeElement.h diff --git a/serialize/SerializeIF.h b/src/fsfw/serialize/SerializeIF.h similarity index 97% rename from serialize/SerializeIF.h rename to src/fsfw/serialize/SerializeIF.h index d72218f0..dfd854e3 100644 --- a/serialize/SerializeIF.h +++ b/src/fsfw/serialize/SerializeIF.h @@ -19,7 +19,10 @@ class SerializeIF { public: enum class Endianness : uint8_t { - BIG, LITTLE, MACHINE + BIG, + LITTLE, + MACHINE, + NETWORK = BIG // Added for convenience like htons on sockets }; static const uint8_t INTERFACE_ID = CLASS_ID::SERIALIZE_IF; diff --git a/src/fsfw/serviceinterface.h b/src/fsfw/serviceinterface.h new file mode 100644 index 00000000..2e9a0b7e --- /dev/null +++ b/src/fsfw/serviceinterface.h @@ -0,0 +1,6 @@ +#ifndef FSFW_SRC_FSFW_SERVICEINTERFACE_H_ +#define FSFW_SRC_FSFW_SERVICEINTERFACE_H_ + +#include "serviceinterface/ServiceInterface.h" + +#endif /* FSFW_SRC_FSFW_SERVICEINTERFACE_H_ */ diff --git a/serviceinterface/CMakeLists.txt b/src/fsfw/serviceinterface/CMakeLists.txt similarity index 100% rename from serviceinterface/CMakeLists.txt rename to src/fsfw/serviceinterface/CMakeLists.txt diff --git a/serviceinterface/ServiceInterface.h b/src/fsfw/serviceinterface/ServiceInterface.h similarity index 63% rename from serviceinterface/ServiceInterface.h rename to src/fsfw/serviceinterface/ServiceInterface.h index 1f7e5e84..9f05b96c 100644 --- a/serviceinterface/ServiceInterface.h +++ b/src/fsfw/serviceinterface/ServiceInterface.h @@ -1,13 +1,13 @@ #ifndef FSFW_SERVICEINTERFACE_SERVICEINTERFACE_H_ #define FSFW_SERVICEINTERFACE_SERVICEINTERFACE_H_ -#include +#include "fsfw/FSFW.h" #include "serviceInterfaceDefintions.h" #if FSFW_CPP_OSTREAM_ENABLED == 1 -#include +#include "ServiceInterfaceStream.h" #else -#include +#include "ServiceInterfacePrinter.h" #endif #endif /* FSFW_SERVICEINTERFACE_SERVICEINTERFACE_H_ */ diff --git a/serviceinterface/ServiceInterfaceBuffer.cpp b/src/fsfw/serviceinterface/ServiceInterfaceBuffer.cpp similarity index 92% rename from serviceinterface/ServiceInterfaceBuffer.cpp rename to src/fsfw/serviceinterface/ServiceInterfaceBuffer.cpp index ccc051c3..0411e674 100644 --- a/serviceinterface/ServiceInterfaceBuffer.cpp +++ b/src/fsfw/serviceinterface/ServiceInterfaceBuffer.cpp @@ -1,10 +1,10 @@ -#include "ServiceInterfaceBuffer.h" +#include "fsfw/serviceinterface/ServiceInterfaceBuffer.h" #if FSFW_CPP_OSTREAM_ENABLED == 1 -#include "../timemanager/Clock.h" +#include "fsfw/timemanager/Clock.h" -#include "serviceInterfaceDefintions.h" +#include "fsfw/serviceinterface/serviceInterfaceDefintions.h" #include #include @@ -35,7 +35,7 @@ ServiceInterfaceBuffer::ServiceInterfaceBuffer(std::string setMessage, colorPrefix = sif::ANSI_COLOR_GREEN; } else if(setMessage.find("WARNING") != std::string::npos) { - colorPrefix = sif::ANSI_COLOR_YELLOW; + colorPrefix = sif::ANSI_COLOR_MAGENTA; } else if(setMessage.find("ERROR") != std::string::npos) { colorPrefix = sif::ANSI_COLOR_RED; @@ -146,8 +146,8 @@ std::string* ServiceInterfaceBuffer::getPreamble(size_t * preambleSize) { #endif int32_t charCount = sprintf(parsePosition, - "%s: | %02" SCNu32 ":%02" SCNu32 ":%02" SCNu32 ".%03" SCNu32 " | ", - this->logMessage.c_str(), loggerTime.hour, + "%s%s | %02" SCNu32 ":%02" SCNu32 ":%02" SCNu32 ".%03" SCNu32 " | ", + this->logMessage.c_str(), sif::ANSI_COLOR_RESET, loggerTime.hour, loggerTime.minute, loggerTime.second, loggerTime.usecond /1000); @@ -171,6 +171,12 @@ bool ServiceInterfaceBuffer::crAdditionEnabled() const { return addCrToPreamble; } +#if FSFW_COLORED_OUTPUT == 1 +void ServiceInterfaceBuffer::setAsciiColorPrefix(std::string colorPrefix) { + this->colorPrefix = colorPrefix; +} +#endif + #ifdef UT699 #include "../osal/rtems/Interrupt.h" diff --git a/serviceinterface/ServiceInterfaceBuffer.h b/src/fsfw/serviceinterface/ServiceInterfaceBuffer.h similarity index 98% rename from serviceinterface/ServiceInterfaceBuffer.h rename to src/fsfw/serviceinterface/ServiceInterfaceBuffer.h index 9d3ce069..ad1148a2 100644 --- a/serviceinterface/ServiceInterfaceBuffer.h +++ b/src/fsfw/serviceinterface/ServiceInterfaceBuffer.h @@ -48,6 +48,7 @@ private: #if FSFW_COLORED_OUTPUT == 1 std::string colorPrefix; + void setAsciiColorPrefix(std::string colorPrefix); #endif // For EOF detection diff --git a/serviceinterface/ServiceInterfacePrinter.cpp b/src/fsfw/serviceinterface/ServiceInterfacePrinter.cpp similarity index 85% rename from serviceinterface/ServiceInterfacePrinter.cpp rename to src/fsfw/serviceinterface/ServiceInterfacePrinter.cpp index ce797f1c..e42e515d 100644 --- a/serviceinterface/ServiceInterfacePrinter.cpp +++ b/src/fsfw/serviceinterface/ServiceInterfacePrinter.cpp @@ -1,7 +1,7 @@ -#include -#include "ServiceInterfacePrinter.h" -#include "serviceInterfaceDefintions.h" -#include "../timemanager/Clock.h" +#include "fsfw/FSFW.h" +#include "fsfw/serviceinterface/ServiceInterfacePrinter.h" +#include "fsfw/serviceinterface/serviceInterfaceDefintions.h" +#include "fsfw/timemanager/Clock.h" #include #include @@ -56,25 +56,29 @@ void fsfwPrint(sif::PrintLevel printType, const char* fmt, va_list arg) { #endif if (printType == sif::PrintLevel::INFO_LEVEL) { - len += sprintf(bufferPosition + len, "INFO: "); + len += sprintf(bufferPosition + len, "INFO"); } if(printType == sif::PrintLevel::DEBUG_LEVEL) { - len += sprintf(bufferPosition + len, "DEBUG: "); + len += sprintf(bufferPosition + len, "DEBUG"); } if(printType == sif::PrintLevel::WARNING_LEVEL) { - len += sprintf(bufferPosition + len, "WARNING: "); + len += sprintf(bufferPosition + len, "WARNING"); } if(printType == sif::PrintLevel::ERROR_LEVEL) { - len += sprintf(bufferPosition + len, "ERROR: "); + len += sprintf(bufferPosition + len, "ERROR"); } +#if FSFW_COLORED_OUTPUT == 1 + len += sprintf(bufferPosition + len, sif::ANSI_COLOR_RESET); +#endif + Clock::TimeOfDay_t now; Clock::getDateAndTime(&now); /* * Log current time to terminal if desired. */ - len += sprintf(bufferPosition + len, "| %lu:%02lu:%02lu.%03lu | ", + len += sprintf(bufferPosition + len, " | %lu:%02lu:%02lu.%03lu | ", (unsigned long) now.hour, (unsigned long) now.minute, (unsigned long) now.second, diff --git a/serviceinterface/ServiceInterfacePrinter.h b/src/fsfw/serviceinterface/ServiceInterfacePrinter.h similarity index 93% rename from serviceinterface/ServiceInterfacePrinter.h rename to src/fsfw/serviceinterface/ServiceInterfacePrinter.h index 6b062108..98421444 100644 --- a/serviceinterface/ServiceInterfacePrinter.h +++ b/src/fsfw/serviceinterface/ServiceInterfacePrinter.h @@ -7,6 +7,8 @@ //! https://stackoverflow.com/questions/111928/is-there-a-printf-converter-to-print-in-binary-format //! Can be used to print out binary numbers in human-readable format. +//! Example usage: +//! sif::printInfo("Status register: " BYTE_TO_BINARY_PATTERN "\n",BYTE_TO_BINARY(0x1f)); #define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c" #define BYTE_TO_BINARY(byte) \ (byte & 0x80 ? '1' : '0'), \ diff --git a/serviceinterface/ServiceInterfaceStream.cpp b/src/fsfw/serviceinterface/ServiceInterfaceStream.cpp similarity index 71% rename from serviceinterface/ServiceInterfaceStream.cpp rename to src/fsfw/serviceinterface/ServiceInterfaceStream.cpp index ad14cd04..6139299b 100644 --- a/serviceinterface/ServiceInterfaceStream.cpp +++ b/src/fsfw/serviceinterface/ServiceInterfaceStream.cpp @@ -1,4 +1,4 @@ -#include "ServiceInterfaceStream.h" +#include "fsfw/serviceinterface/ServiceInterfaceStream.h" #if FSFW_CPP_OSTREAM_ENABLED == 1 @@ -19,5 +19,11 @@ bool ServiceInterfaceStream::crAdditionEnabled() const { return streambuf.crAdditionEnabled(); } +#if FSFW_COLORED_OUTPUT == 1 +void ServiceInterfaceStream::setAsciiColorPrefix(std::string asciiColorCode) { + streambuf.setAsciiColorPrefix(asciiColorCode); +} +#endif + #endif diff --git a/serviceinterface/ServiceInterfaceStream.h b/src/fsfw/serviceinterface/ServiceInterfaceStream.h similarity index 95% rename from serviceinterface/ServiceInterfaceStream.h rename to src/fsfw/serviceinterface/ServiceInterfaceStream.h index 0ea44f0b..545ab241 100644 --- a/serviceinterface/ServiceInterfaceStream.h +++ b/src/fsfw/serviceinterface/ServiceInterfaceStream.h @@ -46,6 +46,10 @@ public: */ bool crAdditionEnabled() const; +#if FSFW_COLORED_OUTPUT == 1 + void setAsciiColorPrefix(std::string asciiColorCode); +#endif + protected: ServiceInterfaceBuffer streambuf; }; diff --git a/serviceinterface/serviceInterfaceDefintions.h b/src/fsfw/serviceinterface/serviceInterfaceDefintions.h similarity index 100% rename from serviceinterface/serviceInterfaceDefintions.h rename to src/fsfw/serviceinterface/serviceInterfaceDefintions.h diff --git a/storagemanager/CMakeLists.txt b/src/fsfw/storagemanager/CMakeLists.txt similarity index 100% rename from storagemanager/CMakeLists.txt rename to src/fsfw/storagemanager/CMakeLists.txt diff --git a/storagemanager/ConstStorageAccessor.cpp b/src/fsfw/storagemanager/ConstStorageAccessor.cpp similarity index 92% rename from storagemanager/ConstStorageAccessor.cpp rename to src/fsfw/storagemanager/ConstStorageAccessor.cpp index aab84862..67736d51 100644 --- a/storagemanager/ConstStorageAccessor.cpp +++ b/src/fsfw/storagemanager/ConstStorageAccessor.cpp @@ -1,8 +1,8 @@ -#include "ConstStorageAccessor.h" -#include "StorageManagerIF.h" +#include "fsfw/storagemanager/ConstStorageAccessor.h" +#include "fsfw/storagemanager/StorageManagerIF.h" -#include "../serviceinterface/ServiceInterfaceStream.h" -#include "../globalfunctions/arrayprinter.h" +#include "fsfw/serviceinterface/ServiceInterfaceStream.h" +#include "fsfw/globalfunctions/arrayprinter.h" #include diff --git a/storagemanager/ConstStorageAccessor.h b/src/fsfw/storagemanager/ConstStorageAccessor.h similarity index 100% rename from storagemanager/ConstStorageAccessor.h rename to src/fsfw/storagemanager/ConstStorageAccessor.h diff --git a/storagemanager/LocalPool.cpp b/src/fsfw/storagemanager/LocalPool.cpp similarity index 98% rename from storagemanager/LocalPool.cpp rename to src/fsfw/storagemanager/LocalPool.cpp index 2b733548..c5e74e08 100644 --- a/storagemanager/LocalPool.cpp +++ b/src/fsfw/storagemanager/LocalPool.cpp @@ -1,5 +1,8 @@ -#include "LocalPool.h" -#include +#include "fsfw/FSFW.h" +#include "fsfw/storagemanager/LocalPool.h" + +#include "fsfw/objectmanager/ObjectManager.h" + #include LocalPool::LocalPool(object_id_t setObjectId, const LocalPoolConfig& poolConfig, @@ -185,7 +188,7 @@ ReturnValue_t LocalPool::initialize() { if (result != RETURN_OK) { return result; } - internalErrorReporter = objectManager->get( + internalErrorReporter = ObjectManager::instance()->get( objects::INTERNAL_ERROR_REPORTER); if (internalErrorReporter == nullptr){ return ObjectManagerIF::INTERNAL_ERR_REPORTER_UNINIT; diff --git a/storagemanager/LocalPool.h b/src/fsfw/storagemanager/LocalPool.h similarity index 96% rename from storagemanager/LocalPool.h rename to src/fsfw/storagemanager/LocalPool.h index 6a666485..383d8a94 100644 --- a/storagemanager/LocalPool.h +++ b/src/fsfw/storagemanager/LocalPool.h @@ -1,12 +1,13 @@ #ifndef FSFW_STORAGEMANAGER_LOCALPOOL_H_ #define FSFW_STORAGEMANAGER_LOCALPOOL_H_ -#include "StorageManagerIF.h" -#include "../objectmanager/SystemObject.h" -#include "../objectmanager/ObjectManagerIF.h" -#include "../serviceinterface/ServiceInterfaceStream.h" -#include "../internalError/InternalErrorReporterIF.h" -#include "../storagemanager/StorageAccessor.h" +#include "fsfw/storagemanager/StorageManagerIF.h" + +#include "fsfw/objectmanager/SystemObject.h" +#include "fsfw/objectmanager/ObjectManagerIF.h" +#include "fsfw/serviceinterface/ServiceInterfaceStream.h" +#include "fsfw/internalerror/InternalErrorReporterIF.h" +#include "fsfw/storagemanager/StorageAccessor.h" #include #include diff --git a/storagemanager/PoolManager.cpp b/src/fsfw/storagemanager/PoolManager.cpp similarity index 96% rename from storagemanager/PoolManager.cpp rename to src/fsfw/storagemanager/PoolManager.cpp index eec84907..073371ad 100644 --- a/storagemanager/PoolManager.cpp +++ b/src/fsfw/storagemanager/PoolManager.cpp @@ -1,5 +1,6 @@ -#include "PoolManager.h" -#include +#include "fsfw/FSFW.h" +#include "fsfw/storagemanager/PoolManager.h" + PoolManager::PoolManager(object_id_t setObjectId, const LocalPoolConfig& localPoolConfig): diff --git a/storagemanager/PoolManager.h b/src/fsfw/storagemanager/PoolManager.h similarity index 100% rename from storagemanager/PoolManager.h rename to src/fsfw/storagemanager/PoolManager.h diff --git a/storagemanager/StorageAccessor.cpp b/src/fsfw/storagemanager/StorageAccessor.cpp similarity index 93% rename from storagemanager/StorageAccessor.cpp rename to src/fsfw/storagemanager/StorageAccessor.cpp index a7b4fae4..95f61a75 100644 --- a/storagemanager/StorageAccessor.cpp +++ b/src/fsfw/storagemanager/StorageAccessor.cpp @@ -1,6 +1,7 @@ -#include "StorageAccessor.h" -#include "StorageManagerIF.h" -#include "../serviceinterface/ServiceInterfaceStream.h" +#include "fsfw/storagemanager/StorageAccessor.h" +#include "fsfw/storagemanager/StorageManagerIF.h" + +#include "fsfw/serviceinterface/ServiceInterface.h" #include diff --git a/storagemanager/StorageAccessor.h b/src/fsfw/storagemanager/StorageAccessor.h similarity index 100% rename from storagemanager/StorageAccessor.h rename to src/fsfw/storagemanager/StorageAccessor.h diff --git a/storagemanager/StorageManagerIF.h b/src/fsfw/storagemanager/StorageManagerIF.h similarity index 100% rename from storagemanager/StorageManagerIF.h rename to src/fsfw/storagemanager/StorageManagerIF.h diff --git a/storagemanager/storeAddress.h b/src/fsfw/storagemanager/storeAddress.h similarity index 100% rename from storagemanager/storeAddress.h rename to src/fsfw/storagemanager/storeAddress.h diff --git a/subsystem/CMakeLists.txt b/src/fsfw/subsystem/CMakeLists.txt similarity index 100% rename from subsystem/CMakeLists.txt rename to src/fsfw/subsystem/CMakeLists.txt diff --git a/subsystem/Subsystem.cpp b/src/fsfw/subsystem/Subsystem.cpp similarity index 97% rename from subsystem/Subsystem.cpp rename to src/fsfw/subsystem/Subsystem.cpp index 4de6906c..0c8e3f35 100644 --- a/subsystem/Subsystem.cpp +++ b/src/fsfw/subsystem/Subsystem.cpp @@ -1,10 +1,11 @@ -#include "Subsystem.h" -#include "../health/HealthMessage.h" -#include "../objectmanager/ObjectManagerIF.h" -#include "../serialize/SerialArrayListAdapter.h" -#include "../serialize/SerialFixedArrayListAdapter.h" -#include "../serialize/SerializeElement.h" -#include "../serialize/SerialLinkedListAdapter.h" +#include "fsfw/subsystem/Subsystem.h" + +#include "fsfw/health/HealthMessage.h" +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/serialize/SerialArrayListAdapter.h" +#include "fsfw/serialize/SerialFixedArrayListAdapter.h" +#include "fsfw/serialize/SerializeElement.h" +#include "fsfw/serialize/SerialLinkedListAdapter.h" #include @@ -477,13 +478,13 @@ ReturnValue_t Subsystem::initialize() { return result; } - IPCStore = objectManager->get(objects::IPC_STORE); + IPCStore = ObjectManager::instance()->get(objects::IPC_STORE); if (IPCStore == NULL) { return RETURN_FAILED; } #if FSFW_USE_MODESTORE == 1 - modeStore = objectManager->get(objects::MODE_STORE); + modeStore = ObjectManager::instance()->get(objects::MODE_STORE); if (modeStore == nullptr) { return RETURN_FAILED; diff --git a/subsystem/Subsystem.h b/src/fsfw/subsystem/Subsystem.h similarity index 100% rename from subsystem/Subsystem.h rename to src/fsfw/subsystem/Subsystem.h diff --git a/subsystem/SubsystemBase.cpp b/src/fsfw/subsystem/SubsystemBase.cpp similarity index 95% rename from subsystem/SubsystemBase.cpp rename to src/fsfw/subsystem/SubsystemBase.cpp index 565e0712..afcd43ad 100644 --- a/subsystem/SubsystemBase.cpp +++ b/src/fsfw/subsystem/SubsystemBase.cpp @@ -1,7 +1,8 @@ -#include "../serviceinterface/ServiceInterfaceStream.h" -#include "../serviceinterface/ServiceInterfaceStream.h" -#include "../subsystem/SubsystemBase.h" -#include "../ipc/QueueFactory.h" +#include "fsfw/subsystem/SubsystemBase.h" + +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/ipc/QueueFactory.h" SubsystemBase::SubsystemBase(object_id_t setObjectId, object_id_t parent, Mode_t initialMode, uint16_t commandQueueDepth) : @@ -19,10 +20,10 @@ SubsystemBase::~SubsystemBase() { ReturnValue_t SubsystemBase::registerChild(object_id_t objectId) { ChildInfo info; - HasModesIF *child = objectManager->get(objectId); + HasModesIF *child = ObjectManager::instance()->get(objectId); // This is a rather ugly hack to have the changedHealth info for all // children available. - HasHealthIF* healthChild = objectManager->get(objectId); + HasHealthIF* healthChild = ObjectManager::instance()->get(objectId); if (child == nullptr) { if (healthChild == nullptr) { return CHILD_DOESNT_HAVE_MODES; @@ -174,7 +175,7 @@ ReturnValue_t SubsystemBase::initialize() { } if (parentId != objects::NO_OBJECT) { - SubsystemBase *parent = objectManager->get(parentId); + SubsystemBase *parent = ObjectManager::instance()->get(parentId); if (parent == nullptr) { return RETURN_FAILED; } diff --git a/subsystem/SubsystemBase.h b/src/fsfw/subsystem/SubsystemBase.h similarity index 100% rename from subsystem/SubsystemBase.h rename to src/fsfw/subsystem/SubsystemBase.h diff --git a/subsystem/modes/CMakeLists.txt b/src/fsfw/subsystem/modes/CMakeLists.txt similarity index 100% rename from subsystem/modes/CMakeLists.txt rename to src/fsfw/subsystem/modes/CMakeLists.txt diff --git a/subsystem/modes/HasModeSequenceIF.h b/src/fsfw/subsystem/modes/HasModeSequenceIF.h similarity index 100% rename from subsystem/modes/HasModeSequenceIF.h rename to src/fsfw/subsystem/modes/HasModeSequenceIF.h diff --git a/subsystem/modes/ModeDefinitions.h b/src/fsfw/subsystem/modes/ModeDefinitions.h similarity index 100% rename from subsystem/modes/ModeDefinitions.h rename to src/fsfw/subsystem/modes/ModeDefinitions.h diff --git a/subsystem/modes/ModeSequenceMessage.cpp b/src/fsfw/subsystem/modes/ModeSequenceMessage.cpp similarity index 89% rename from subsystem/modes/ModeSequenceMessage.cpp rename to src/fsfw/subsystem/modes/ModeSequenceMessage.cpp index 7733098e..d7570276 100644 --- a/subsystem/modes/ModeSequenceMessage.cpp +++ b/src/fsfw/subsystem/modes/ModeSequenceMessage.cpp @@ -1,7 +1,7 @@ -#include "ModeSequenceMessage.h" +#include "fsfw/subsystem/modes/ModeSequenceMessage.h" -#include "../../objectmanager/ObjectManagerIF.h" -#include "../../storagemanager/StorageManagerIF.h" +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/storagemanager/StorageManagerIF.h" void ModeSequenceMessage::setModeSequenceMessage(CommandMessage* message, Command_t command, Mode_t sequence, store_address_t storeAddress) { @@ -50,7 +50,7 @@ void ModeSequenceMessage::clear(CommandMessage *message) { case TABLE_LIST: case TABLE: case SEQUENCE: { - StorageManagerIF *ipcStore = objectManager->get( + StorageManagerIF *ipcStore = ObjectManager::instance()->get( objects::IPC_STORE); if (ipcStore != nullptr){ ipcStore->deleteData(ModeSequenceMessage::getStoreAddress(message)); diff --git a/subsystem/modes/ModeSequenceMessage.h b/src/fsfw/subsystem/modes/ModeSequenceMessage.h similarity index 95% rename from subsystem/modes/ModeSequenceMessage.h rename to src/fsfw/subsystem/modes/ModeSequenceMessage.h index 7852c984..0dbe7ffb 100644 --- a/subsystem/modes/ModeSequenceMessage.h +++ b/src/fsfw/subsystem/modes/ModeSequenceMessage.h @@ -3,8 +3,8 @@ #include "ModeDefinitions.h" -#include "../../ipc/CommandMessage.h" -#include "../../storagemanager/StorageManagerIF.h" +#include "fsfw/ipc/CommandMessage.h" +#include "fsfw/storagemanager/StorageManagerIF.h" class ModeSequenceMessage { diff --git a/subsystem/modes/ModeStore.cpp b/src/fsfw/subsystem/modes/ModeStore.cpp similarity index 98% rename from subsystem/modes/ModeStore.cpp rename to src/fsfw/subsystem/modes/ModeStore.cpp index e216a167..e28bbc4f 100644 --- a/subsystem/modes/ModeStore.cpp +++ b/src/fsfw/subsystem/modes/ModeStore.cpp @@ -1,4 +1,4 @@ -#include "ModeStore.h" +#include "fsfw/subsystem/modes/ModeStore.h" // todo: I think some parts are deprecated. If this is used, the define // USE_MODESTORE could be part of the new FSFWConfig.h file. diff --git a/subsystem/modes/ModeStore.h b/src/fsfw/subsystem/modes/ModeStore.h similarity index 100% rename from subsystem/modes/ModeStore.h rename to src/fsfw/subsystem/modes/ModeStore.h diff --git a/subsystem/modes/ModeStoreIF.h b/src/fsfw/subsystem/modes/ModeStoreIF.h similarity index 100% rename from subsystem/modes/ModeStoreIF.h rename to src/fsfw/subsystem/modes/ModeStoreIF.h diff --git a/tasks/CMakeLists.txt b/src/fsfw/tasks/CMakeLists.txt similarity index 100% rename from tasks/CMakeLists.txt rename to src/fsfw/tasks/CMakeLists.txt diff --git a/tasks/ExecutableObjectIF.h b/src/fsfw/tasks/ExecutableObjectIF.h similarity index 100% rename from tasks/ExecutableObjectIF.h rename to src/fsfw/tasks/ExecutableObjectIF.h diff --git a/tasks/FixedSequenceSlot.cpp b/src/fsfw/tasks/FixedSequenceSlot.cpp similarity index 85% rename from tasks/FixedSequenceSlot.cpp rename to src/fsfw/tasks/FixedSequenceSlot.cpp index f5d82178..9f617b58 100644 --- a/tasks/FixedSequenceSlot.cpp +++ b/src/fsfw/tasks/FixedSequenceSlot.cpp @@ -1,5 +1,6 @@ -#include "FixedSequenceSlot.h" -#include "PeriodicTaskIF.h" +#include "fsfw/tasks/FixedSequenceSlot.h" +#include "fsfw/tasks/PeriodicTaskIF.h" + #include FixedSequenceSlot::FixedSequenceSlot(object_id_t handlerId, uint32_t setTime, diff --git a/tasks/FixedSequenceSlot.h b/src/fsfw/tasks/FixedSequenceSlot.h similarity index 97% rename from tasks/FixedSequenceSlot.h rename to src/fsfw/tasks/FixedSequenceSlot.h index 1744ec19..aea77dfe 100644 --- a/tasks/FixedSequenceSlot.h +++ b/src/fsfw/tasks/FixedSequenceSlot.h @@ -2,7 +2,7 @@ #define FSFW_TASKS_FIXEDSEQUENCESLOT_H_ #include "ExecutableObjectIF.h" -#include "../objectmanager/ObjectManagerIF.h" +#include "fsfw/objectmanager/ObjectManagerIF.h" class PeriodicTaskIF; diff --git a/tasks/FixedSlotSequence.cpp b/src/fsfw/tasks/FixedSlotSequence.cpp similarity index 94% rename from tasks/FixedSlotSequence.cpp rename to src/fsfw/tasks/FixedSlotSequence.cpp index 54b6ae6d..5e896af4 100644 --- a/tasks/FixedSlotSequence.cpp +++ b/src/fsfw/tasks/FixedSlotSequence.cpp @@ -1,5 +1,6 @@ -#include "FixedSlotSequence.h" -#include "../serviceinterface/ServiceInterfaceStream.h" +#include "fsfw/tasks/FixedSlotSequence.h" +#include "fsfw/tasks/FixedTimeslotTaskIF.h" +#include "fsfw/serviceinterface/ServiceInterface.h" #include FixedSlotSequence::FixedSlotSequence(uint32_t setLengthMs) : @@ -92,10 +93,9 @@ void FixedSlotSequence::addSlot(object_id_t componentId, uint32_t slotTimeMs, ReturnValue_t FixedSlotSequence::checkSequence() const { if(slotList.empty()) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "FixedSlotSequence::checkSequence:" - << " Slot list is empty!" << std::endl; + sif::warning << "FixedSlotSequence::checkSequence: Slot list is empty!" << std::endl; #endif - return HasReturnvaluesIF::RETURN_FAILED; + return FixedTimeslotTaskIF::SLOT_LIST_EMPTY; } if(customCheckFunction != nullptr) { diff --git a/tasks/FixedSlotSequence.h b/src/fsfw/tasks/FixedSlotSequence.h similarity index 98% rename from tasks/FixedSlotSequence.h rename to src/fsfw/tasks/FixedSlotSequence.h index 077dd10b..7f49ea0c 100644 --- a/tasks/FixedSlotSequence.h +++ b/src/fsfw/tasks/FixedSlotSequence.h @@ -2,7 +2,7 @@ #define FSFW_TASKS_FIXEDSLOTSEQUENCE_H_ #include "FixedSequenceSlot.h" -#include "../objectmanager/SystemObject.h" +#include "fsfw/objectmanager/SystemObject.h" #include @@ -136,6 +136,7 @@ public: * @details * Checks if timing is ok (must be ascending) and if all handlers were found. * @return + * - SLOT_LIST_EMPTY if the slot list is empty */ ReturnValue_t checkSequence() const; @@ -147,6 +148,7 @@ public: * The general check will be continued for now if the custom check function * fails but a diagnostic debug output will be given. * @param customCheckFunction + * */ void addCustomCheck(ReturnValue_t (*customCheckFunction)(const SlotList &)); diff --git a/tasks/FixedTimeslotTaskIF.h b/src/fsfw/tasks/FixedTimeslotTaskIF.h similarity index 81% rename from tasks/FixedTimeslotTaskIF.h rename to src/fsfw/tasks/FixedTimeslotTaskIF.h index 2fc7e092..605239a4 100644 --- a/tasks/FixedTimeslotTaskIF.h +++ b/src/fsfw/tasks/FixedTimeslotTaskIF.h @@ -2,7 +2,8 @@ #define FRAMEWORK_TASKS_FIXEDTIMESLOTTASKIF_H_ #include "PeriodicTaskIF.h" -#include "../objectmanager/ObjectManagerIF.h" +#include "fsfw/objectmanager/ObjectManagerIF.h" +#include "fsfw/returnvalues/FwClassIds.h" /** * @brief Following the same principle as the base class IF. @@ -12,6 +13,8 @@ class FixedTimeslotTaskIF : public PeriodicTaskIF { public: virtual ~FixedTimeslotTaskIF() {} + static constexpr ReturnValue_t SLOT_LIST_EMPTY = HasReturnvaluesIF::makeReturnCode( + CLASS_ID::FIXED_SLOT_TASK_IF, 0); /** * Add an object with a slot time and the execution step to the task. * The execution step will be passed to the object (e.g. as an operation diff --git a/tasks/PeriodicTaskIF.h b/src/fsfw/tasks/PeriodicTaskIF.h similarity index 100% rename from tasks/PeriodicTaskIF.h rename to src/fsfw/tasks/PeriodicTaskIF.h diff --git a/tasks/SemaphoreFactory.h b/src/fsfw/tasks/SemaphoreFactory.h similarity index 97% rename from tasks/SemaphoreFactory.h rename to src/fsfw/tasks/SemaphoreFactory.h index 01c09d1b..2df7d53f 100644 --- a/tasks/SemaphoreFactory.h +++ b/src/fsfw/tasks/SemaphoreFactory.h @@ -1,7 +1,7 @@ #ifndef FSFW_TASKS_SEMAPHOREFACTORY_H_ #define FSFW_TASKS_SEMAPHOREFACTORY_H_ -#include "../tasks/SemaphoreIF.h" +#include "fsfw/tasks/SemaphoreIF.h" /** * Creates Semaphore. diff --git a/tasks/SemaphoreIF.h b/src/fsfw/tasks/SemaphoreIF.h similarity index 100% rename from tasks/SemaphoreIF.h rename to src/fsfw/tasks/SemaphoreIF.h diff --git a/tasks/TaskFactory.h b/src/fsfw/tasks/TaskFactory.h similarity index 100% rename from tasks/TaskFactory.h rename to src/fsfw/tasks/TaskFactory.h diff --git a/tasks/Typedef.h b/src/fsfw/tasks/Typedef.h similarity index 55% rename from tasks/Typedef.h rename to src/fsfw/tasks/Typedef.h index 55f6bda2..f2f9fe65 100644 --- a/tasks/Typedef.h +++ b/src/fsfw/tasks/Typedef.h @@ -1,5 +1,8 @@ -#ifndef FRAMEWORK_TASKS_TYPEDEF_H_ -#define FRAMEWORK_TASKS_TYPEDEF_H_ +#ifndef FSFW_TASKS_TYPEDEF_H_ +#define FSFW_TASKS_TYPEDEF_H_ + +#include +#include typedef const char* TaskName; typedef uint32_t TaskPriority; @@ -7,4 +10,4 @@ typedef size_t TaskStackSize; typedef double TaskPeriod; typedef void (*TaskDeadlineMissedFunction)(); -#endif /* FRAMEWORK_TASKS_TYPEDEF_H_ */ +#endif /* FSFW_TASKS_TYPEDEF_H_ */ diff --git a/tcdistribution/CCSDSDistributor.cpp b/src/fsfw/tcdistribution/CCSDSDistributor.cpp similarity index 92% rename from tcdistribution/CCSDSDistributor.cpp rename to src/fsfw/tcdistribution/CCSDSDistributor.cpp index 62cbfbf2..ffceaecc 100644 --- a/tcdistribution/CCSDSDistributor.cpp +++ b/src/fsfw/tcdistribution/CCSDSDistributor.cpp @@ -1,7 +1,8 @@ -#include "CCSDSDistributor.h" +#include "fsfw/tcdistribution/CCSDSDistributor.h" -#include "../serviceinterface/ServiceInterface.h" -#include "../tmtcpacket/SpacePacketBase.h" +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/tmtcpacket/SpacePacketBase.h" #define CCSDS_DISTRIBUTOR_DEBUGGING 0 @@ -86,7 +87,7 @@ uint16_t CCSDSDistributor::getIdentifier() { ReturnValue_t CCSDSDistributor::initialize() { ReturnValue_t status = this->TcDistributor::initialize(); - this->tcStore = objectManager->get( objects::TC_STORE ); + this->tcStore = ObjectManager::instance()->get( objects::TC_STORE ); if (this->tcStore == nullptr) { #if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_CPP_OSTREAM_ENABLED == 1 diff --git a/tcdistribution/CCSDSDistributor.h b/src/fsfw/tcdistribution/CCSDSDistributor.h similarity index 100% rename from tcdistribution/CCSDSDistributor.h rename to src/fsfw/tcdistribution/CCSDSDistributor.h diff --git a/tcdistribution/CCSDSDistributorIF.h b/src/fsfw/tcdistribution/CCSDSDistributorIF.h similarity index 100% rename from tcdistribution/CCSDSDistributorIF.h rename to src/fsfw/tcdistribution/CCSDSDistributorIF.h diff --git a/src/fsfw/tcdistribution/CMakeLists.txt b/src/fsfw/tcdistribution/CMakeLists.txt new file mode 100644 index 00000000..6f237076 --- /dev/null +++ b/src/fsfw/tcdistribution/CMakeLists.txt @@ -0,0 +1,6 @@ +target_sources(${LIB_FSFW_NAME} PRIVATE + CCSDSDistributor.cpp + PUSDistributor.cpp + TcDistributor.cpp + TcPacketCheck.cpp +) diff --git a/tcdistribution/PUSDistributor.cpp b/src/fsfw/tcdistribution/PUSDistributor.cpp similarity index 76% rename from tcdistribution/PUSDistributor.cpp rename to src/fsfw/tcdistribution/PUSDistributor.cpp index abdd1f8d..adab58c8 100644 --- a/tcdistribution/PUSDistributor.cpp +++ b/src/fsfw/tcdistribution/PUSDistributor.cpp @@ -1,9 +1,9 @@ -#include "CCSDSDistributorIF.h" -#include "PUSDistributor.h" +#include "fsfw/tcdistribution/CCSDSDistributorIF.h" +#include "fsfw/tcdistribution/PUSDistributor.h" -#include "../serviceinterface/ServiceInterface.h" -#include "../tmtcpacket/pus/TcPacketStored.h" -#include "../tmtcservices/PusVerificationReport.h" +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/tmtcservices/PusVerificationReport.h" #define PUS_DISTRIBUTOR_DEBUGGING 0 @@ -29,12 +29,28 @@ PUSDistributor::TcMqMapIter PUSDistributor::selectDestination() { tcStatus = checker.checkPacket(currentPacket); if(tcStatus != HasReturnvaluesIF::RETURN_OK) { #if FSFW_VERBOSE_LEVEL >= 1 + const char* keyword = "unnamed error"; + if(tcStatus == TcPacketCheck::INCORRECT_CHECKSUM) { + keyword = "checksum"; + } + else if(tcStatus == TcPacketCheck::INCORRECT_PRIMARY_HEADER) { + keyword = "incorrect primary header"; + } + else if(tcStatus == TcPacketCheck::ILLEGAL_APID) { + keyword = "illegal APID"; + } + else if(tcStatus == TcPacketCheck::INCORRECT_SECONDARY_HEADER) { + keyword = "incorrect secondary header"; + } + else if(tcStatus == TcPacketCheck::INCOMPLETE_PACKET) { + keyword = "incomplete packet"; + } #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::debug << "PUSDistributor::handlePacket: Packet format invalid, code " << - static_cast(tcStatus) << std::endl; + sif::warning << "PUSDistributor::handlePacket: Packet format invalid, " + << keyword << " error" << std::endl; #else - sif::printDebug("PUSDistributor::handlePacket: Packet format invalid, code %d\n", - static_cast(tcStatus)); + sif::printWarning("PUSDistributor::handlePacket: Packet format invalid, " + "%s error\n", keyword); #endif #endif } @@ -118,14 +134,14 @@ uint16_t PUSDistributor::getIdentifier() { } ReturnValue_t PUSDistributor::initialize() { - currentPacket = new TcPacketStored(); + currentPacket = new TcPacketStoredPus(); if(currentPacket == nullptr) { // Should not happen, memory allocation failed! return ObjectManagerIF::CHILD_INIT_FAILED; } CCSDSDistributorIF* ccsdsDistributor = - objectManager->get(packetSource); + 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/tcdistribution/PUSDistributor.h b/src/fsfw/tcdistribution/PUSDistributor.h similarity index 90% rename from tcdistribution/PUSDistributor.h rename to src/fsfw/tcdistribution/PUSDistributor.h index be3804ef..53a996ca 100644 --- a/tcdistribution/PUSDistributor.h +++ b/src/fsfw/tcdistribution/PUSDistributor.h @@ -5,9 +5,10 @@ #include "TcDistributor.h" #include "TcPacketCheck.h" -#include "../returnvalues/HasReturnvaluesIF.h" -#include "../tmtcservices/AcceptsTelecommandsIF.h" -#include "../tmtcservices/VerificationReporter.h" +#include "fsfw/tmtcpacket/pus/tc.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" +#include "fsfw/tmtcservices/AcceptsTelecommandsIF.h" +#include "fsfw/tmtcservices/VerificationReporter.h" /** * This class accepts PUS Telecommands and forwards them to Application @@ -51,7 +52,8 @@ protected: /** * The currently handled packet is stored here. */ - TcPacketStored* currentPacket = nullptr; + TcPacketStoredPus* currentPacket = nullptr; + /** * With this variable, the current check status is stored to generate * acceptance messages later. diff --git a/tcdistribution/PUSDistributorIF.h b/src/fsfw/tcdistribution/PUSDistributorIF.h similarity index 100% rename from tcdistribution/PUSDistributorIF.h rename to src/fsfw/tcdistribution/PUSDistributorIF.h diff --git a/tcdistribution/TcDistributor.cpp b/src/fsfw/tcdistribution/TcDistributor.cpp similarity index 89% rename from tcdistribution/TcDistributor.cpp rename to src/fsfw/tcdistribution/TcDistributor.cpp index df069556..8384e6ee 100644 --- a/tcdistribution/TcDistributor.cpp +++ b/src/fsfw/tcdistribution/TcDistributor.cpp @@ -1,8 +1,8 @@ -#include "TcDistributor.h" +#include "fsfw/tcdistribution/TcDistributor.h" -#include "../serviceinterface/ServiceInterfaceStream.h" -#include "../tmtcservices/TmTcMessage.h" -#include "../ipc/QueueFactory.h" +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/tmtcservices/TmTcMessage.h" +#include "fsfw/ipc/QueueFactory.h" TcDistributor::TcDistributor(object_id_t objectId) : SystemObject(objectId) { diff --git a/tcdistribution/TcDistributor.h b/src/fsfw/tcdistribution/TcDistributor.h similarity index 93% rename from tcdistribution/TcDistributor.h rename to src/fsfw/tcdistribution/TcDistributor.h index 5d0ca45d..14b532bd 100644 --- a/tcdistribution/TcDistributor.h +++ b/src/fsfw/tcdistribution/TcDistributor.h @@ -1,13 +1,13 @@ #ifndef FSFW_TMTCSERVICES_TCDISTRIBUTOR_H_ #define FSFW_TMTCSERVICES_TCDISTRIBUTOR_H_ -#include "../objectmanager/ObjectManagerIF.h" -#include "../objectmanager/SystemObject.h" -#include "../returnvalues/HasReturnvaluesIF.h" -#include "../storagemanager/StorageManagerIF.h" -#include "../tasks/ExecutableObjectIF.h" -#include "../tmtcservices/TmTcMessage.h" -#include "../ipc/MessageQueueIF.h" +#include "fsfw/objectmanager/ObjectManagerIF.h" +#include "fsfw/objectmanager/SystemObject.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" +#include "fsfw/storagemanager/StorageManagerIF.h" +#include "fsfw/tasks/ExecutableObjectIF.h" +#include "fsfw/tmtcservices/TmTcMessage.h" +#include "fsfw/ipc/MessageQueueIF.h" #include /** diff --git a/src/fsfw/tcdistribution/TcPacketCheck.cpp b/src/fsfw/tcdistribution/TcPacketCheck.cpp new file mode 100644 index 00000000..44501c58 --- /dev/null +++ b/src/fsfw/tcdistribution/TcPacketCheck.cpp @@ -0,0 +1,46 @@ +#include "fsfw/tcdistribution/TcPacketCheck.h" + +#include "fsfw/globalfunctions/CRC.h" +#include "fsfw/tmtcpacket/pus/tc/TcPacketBase.h" +#include "fsfw/tmtcpacket/pus/tc/TcPacketStoredBase.h" +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/storagemanager/StorageManagerIF.h" +#include "fsfw/tmtcservices/VerificationCodes.h" + +TcPacketCheck::TcPacketCheck(uint16_t setApid): apid(setApid) { +} + +ReturnValue_t TcPacketCheck::checkPacket(TcPacketStoredBase* currentPacket) { + TcPacketBase* tcPacketBase = currentPacket->getPacketBase(); + if(tcPacketBase == nullptr) { + return RETURN_FAILED; + } + uint16_t calculated_crc = CRC::crc16ccitt(tcPacketBase->getWholeData(), + tcPacketBase->getFullSize()); + if (calculated_crc != 0) { + return INCORRECT_CHECKSUM; + } + bool condition = (not tcPacketBase->hasSecondaryHeader()) or + (tcPacketBase->getPacketVersionNumber() != CCSDS_VERSION_NUMBER) or + (not tcPacketBase->isTelecommand()); + if (condition) { + return INCORRECT_PRIMARY_HEADER; + } + if (tcPacketBase->getAPID() != this->apid) + return ILLEGAL_APID; + + if (not currentPacket->isSizeCorrect()) { + return INCOMPLETE_PACKET; + } + + condition = (tcPacketBase->getSecondaryHeaderFlag() != CCSDS_SECONDARY_HEADER_FLAG) || + (tcPacketBase->getPusVersionNumber() != PUS_VERSION_NUMBER); + if (condition) { + return INCORRECT_SECONDARY_HEADER; + } + return RETURN_OK; +} + +uint16_t TcPacketCheck::getApid() const { + return apid; +} diff --git a/src/fsfw/tcdistribution/TcPacketCheck.h b/src/fsfw/tcdistribution/TcPacketCheck.h new file mode 100644 index 00000000..519943c7 --- /dev/null +++ b/src/fsfw/tcdistribution/TcPacketCheck.h @@ -0,0 +1,66 @@ +#ifndef FSFW_TCDISTRIBUTION_TCPACKETCHECK_H_ +#define FSFW_TCDISTRIBUTION_TCPACKETCHECK_H_ + +#include "fsfw/FSFW.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" +#include "fsfw/tmtcservices/PusVerificationReport.h" + +class TcPacketStoredBase; + +/** + * This class performs a formal packet check for incoming PUS Telecommand Packets. + * Currently, it only checks if the APID and CRC are correct. + * @ingroup tc_distribution + */ +class TcPacketCheck : public HasReturnvaluesIF { +protected: + /** + * Describes the version number a packet must have to pass. + */ + static constexpr uint8_t CCSDS_VERSION_NUMBER = 0; + /** + * Describes the secondary header a packet must have to pass. + */ + static constexpr uint8_t CCSDS_SECONDARY_HEADER_FLAG = 0; + /** + * Describes the TC Packet PUS Version Number a packet must have to pass. + */ +#if FSFW_USE_PUS_C_TELECOMMANDS == 1 + static constexpr uint8_t PUS_VERSION_NUMBER = 2; +#else + static constexpr uint8_t PUS_VERSION_NUMBER = 1; +#endif + + /** + * The packet id each correct packet should have. + * It is composed of the APID and some static fields. + */ + uint16_t apid; +public: + static const uint8_t INTERFACE_ID = CLASS_ID::TC_PACKET_CHECK; + static const ReturnValue_t ILLEGAL_APID = MAKE_RETURN_CODE( 0 ); + static const ReturnValue_t INCOMPLETE_PACKET = MAKE_RETURN_CODE( 1 ); + static const ReturnValue_t INCORRECT_CHECKSUM = MAKE_RETURN_CODE( 2 ); + static const ReturnValue_t ILLEGAL_PACKET_TYPE = MAKE_RETURN_CODE( 3 ); + static const ReturnValue_t ILLEGAL_PACKET_SUBTYPE = MAKE_RETURN_CODE( 4 ); + static const ReturnValue_t INCORRECT_PRIMARY_HEADER = MAKE_RETURN_CODE( 5 ); + static const ReturnValue_t INCORRECT_SECONDARY_HEADER = MAKE_RETURN_CODE( 6 ); + /** + * The constructor only sets the APID attribute. + * @param set_apid The APID to set. + */ + TcPacketCheck(uint16_t setApid); + /** + * This is the actual method to formally check a certain Telecommand Packet. + * The packet's Application Data can not be checked here. + * @param current_packet The packt to check + * @return - @c RETURN_OK on success. + * - @c INCORRECT_CHECKSUM if checksum is invalid. + * - @c ILLEGAL_APID if APID does not match. + */ + ReturnValue_t checkPacket(TcPacketStoredBase* currentPacket); + + uint16_t getApid() const; +}; + +#endif /* FSFW_TCDISTRIBUTION_TCPACKETCHECK_H_ */ diff --git a/thermal/AbstractTemperatureSensor.cpp b/src/fsfw/thermal/AbstractTemperatureSensor.cpp similarity index 95% rename from thermal/AbstractTemperatureSensor.cpp rename to src/fsfw/thermal/AbstractTemperatureSensor.cpp index 40b305af..68e8d1c0 100644 --- a/thermal/AbstractTemperatureSensor.cpp +++ b/src/fsfw/thermal/AbstractTemperatureSensor.cpp @@ -1,5 +1,5 @@ -#include "AbstractTemperatureSensor.h" -#include "../ipc/QueueFactory.h" +#include "fsfw/thermal/AbstractTemperatureSensor.h" +#include "fsfw/ipc/QueueFactory.h" AbstractTemperatureSensor::AbstractTemperatureSensor(object_id_t setObjectid, ThermalModuleIF *thermalModule) : diff --git a/thermal/AbstractTemperatureSensor.h b/src/fsfw/thermal/AbstractTemperatureSensor.h similarity index 86% rename from thermal/AbstractTemperatureSensor.h rename to src/fsfw/thermal/AbstractTemperatureSensor.h index a1153314..719d84fe 100644 --- a/thermal/AbstractTemperatureSensor.h +++ b/src/fsfw/thermal/AbstractTemperatureSensor.h @@ -1,12 +1,12 @@ #ifndef ABSTRACTSENSOR_H_ #define ABSTRACTSENSOR_H_ -#include "../health/HasHealthIF.h" -#include "../health/HealthHelper.h" -#include "../objectmanager/SystemObject.h" -#include "../tasks/ExecutableObjectIF.h" -#include "../parameters/ParameterHelper.h" -#include "../ipc/MessageQueueIF.h" +#include "fsfw/health/HasHealthIF.h" +#include "fsfw/health/HealthHelper.h" +#include "fsfw/objectmanager/SystemObject.h" +#include "fsfw/tasks/ExecutableObjectIF.h" +#include "fsfw/parameters/ParameterHelper.h" +#include "fsfw/ipc/MessageQueueIF.h" #include "ThermalModuleIF.h" #include "tcsDefinitions.h" diff --git a/thermal/AcceptsThermalMessagesIF.h b/src/fsfw/thermal/AcceptsThermalMessagesIF.h similarity index 100% rename from thermal/AcceptsThermalMessagesIF.h rename to src/fsfw/thermal/AcceptsThermalMessagesIF.h diff --git a/thermal/CMakeLists.txt b/src/fsfw/thermal/CMakeLists.txt similarity index 100% rename from thermal/CMakeLists.txt rename to src/fsfw/thermal/CMakeLists.txt diff --git a/thermal/Heater.cpp b/src/fsfw/thermal/Heater.cpp similarity index 97% rename from thermal/Heater.cpp rename to src/fsfw/thermal/Heater.cpp index 77049438..e6acba13 100644 --- a/thermal/Heater.cpp +++ b/src/fsfw/thermal/Heater.cpp @@ -1,8 +1,9 @@ -#include "Heater.h" +#include "fsfw/thermal/Heater.h" -#include "../devicehandlers/DeviceHandlerFailureIsolation.h" -#include "../power/Fuse.h" -#include "../ipc/QueueFactory.h" +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/devicehandlers/DeviceHandlerFailureIsolation.h" +#include "fsfw/power/Fuse.h" +#include "fsfw/ipc/QueueFactory.h" Heater::Heater(uint32_t objectId, uint8_t switch0, uint8_t switch1) : HealthDevice(objectId, 0), internalState(STATE_OFF), switch0(switch0), switch1(switch1), @@ -239,7 +240,7 @@ ReturnValue_t Heater::initialize() { return result; } - EventManagerIF* manager = objectManager->get( + EventManagerIF* manager = ObjectManager::instance()->get( objects::EVENT_MANAGER); if (manager == NULL) { return HasReturnvaluesIF::RETURN_FAILED; @@ -249,7 +250,7 @@ ReturnValue_t Heater::initialize() { return result; } - ConfirmsFailuresIF* pcdu = objectManager->get( + ConfirmsFailuresIF* pcdu = ObjectManager::instance()->get( DeviceHandlerFailureIsolation::powerConfirmationId); if (pcdu == NULL) { return HasReturnvaluesIF::RETURN_FAILED; diff --git a/thermal/Heater.h b/src/fsfw/thermal/Heater.h similarity index 92% rename from thermal/Heater.h rename to src/fsfw/thermal/Heater.h index 2caddd85..2a40cac6 100644 --- a/thermal/Heater.h +++ b/src/fsfw/thermal/Heater.h @@ -1,11 +1,12 @@ #ifndef FSFW_THERMAL_HEATER_H_ #define FSFW_THERMAL_HEATER_H_ -#include "../devicehandlers/HealthDevice.h" -#include "../parameters/ParameterHelper.h" -#include "../power/PowerSwitchIF.h" -#include "../returnvalues/HasReturnvaluesIF.h" -#include "../timemanager/Countdown.h" +#include "fsfw/devicehandlers/HealthDevice.h" +#include "fsfw/parameters/ParameterHelper.h" +#include "fsfw/power/PowerSwitchIF.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" +#include "fsfw/timemanager/Countdown.h" + #include diff --git a/thermal/RedundantHeater.cpp b/src/fsfw/thermal/RedundantHeater.cpp similarity index 95% rename from thermal/RedundantHeater.cpp rename to src/fsfw/thermal/RedundantHeater.cpp index 6463fcc8..e7b774cb 100644 --- a/thermal/RedundantHeater.cpp +++ b/src/fsfw/thermal/RedundantHeater.cpp @@ -1,4 +1,4 @@ -#include "RedundantHeater.h" +#include "fsfw/thermal/RedundantHeater.h" RedundantHeater::~RedundantHeater() { } diff --git a/thermal/RedundantHeater.h b/src/fsfw/thermal/RedundantHeater.h similarity index 100% rename from thermal/RedundantHeater.h rename to src/fsfw/thermal/RedundantHeater.h diff --git a/thermal/TemperatureSensor.h b/src/fsfw/thermal/TemperatureSensor.h similarity index 100% rename from thermal/TemperatureSensor.h rename to src/fsfw/thermal/TemperatureSensor.h diff --git a/thermal/ThermalComponent.cpp b/src/fsfw/thermal/ThermalComponent.cpp similarity index 99% rename from thermal/ThermalComponent.cpp rename to src/fsfw/thermal/ThermalComponent.cpp index d42c34b3..8d4b7bbd 100644 --- a/thermal/ThermalComponent.cpp +++ b/src/fsfw/thermal/ThermalComponent.cpp @@ -1,4 +1,4 @@ -#include "ThermalComponent.h" +#include "fsfw/thermal/ThermalComponent.h" ThermalComponent::ThermalComponent(object_id_t reportingObjectId, uint8_t domainId, gp_id_t temperaturePoolId, diff --git a/thermal/ThermalComponent.h b/src/fsfw/thermal/ThermalComponent.h similarity index 100% rename from thermal/ThermalComponent.h rename to src/fsfw/thermal/ThermalComponent.h diff --git a/thermal/ThermalComponentCore.cpp b/src/fsfw/thermal/ThermalComponentCore.cpp similarity index 98% rename from thermal/ThermalComponentCore.cpp rename to src/fsfw/thermal/ThermalComponentCore.cpp index 7df04b04..7718ac36 100644 --- a/thermal/ThermalComponentCore.cpp +++ b/src/fsfw/thermal/ThermalComponentCore.cpp @@ -1,5 +1,5 @@ -#include "ThermalComponentCore.h" -#include "tcsDefinitions.h" +#include "fsfw/thermal/ThermalComponentCore.h" +#include "fsfw/thermal/tcsDefinitions.h" ThermalComponentCore::ThermalComponentCore(object_id_t reportingObjectId, uint8_t domainId, gp_id_t temperaturePoolId, diff --git a/thermal/ThermalComponentCore.h b/src/fsfw/thermal/ThermalComponentCore.h similarity index 98% rename from thermal/ThermalComponentCore.h rename to src/fsfw/thermal/ThermalComponentCore.h index a1fa594a..19430015 100644 --- a/thermal/ThermalComponentCore.h +++ b/src/fsfw/thermal/ThermalComponentCore.h @@ -6,7 +6,7 @@ #include "AbstractTemperatureSensor.h" #include "ThermalModule.h" -#include "../datapoollocal/LocalPoolVariable.h" +#include "fsfw/datapoollocal/LocalPoolVariable.h" /** * @brief diff --git a/thermal/ThermalComponentIF.h b/src/fsfw/thermal/ThermalComponentIF.h similarity index 100% rename from thermal/ThermalComponentIF.h rename to src/fsfw/thermal/ThermalComponentIF.h diff --git a/thermal/ThermalModule.cpp b/src/fsfw/thermal/ThermalModule.cpp similarity index 97% rename from thermal/ThermalModule.cpp rename to src/fsfw/thermal/ThermalModule.cpp index de347542..d8108ab3 100644 --- a/thermal/ThermalModule.cpp +++ b/src/fsfw/thermal/ThermalModule.cpp @@ -1,8 +1,8 @@ -#include "ThermalModule.h" -#include "AbstractTemperatureSensor.h" +#include "fsfw/thermal/ThermalModule.h" +#include "fsfw/thermal/AbstractTemperatureSensor.h" -#include "../monitoring/LimitViolationReporter.h" -#include "../monitoring/MonitoringMessageContent.h" +#include "fsfw/monitoring/LimitViolationReporter.h" +#include "fsfw/monitoring/MonitoringMessageContent.h" ThermalModule::ThermalModule(gp_id_t moduleTemperaturePoolId, diff --git a/thermal/ThermalModule.h b/src/fsfw/thermal/ThermalModule.h similarity index 100% rename from thermal/ThermalModule.h rename to src/fsfw/thermal/ThermalModule.h diff --git a/thermal/ThermalModuleIF.h b/src/fsfw/thermal/ThermalModuleIF.h similarity index 100% rename from thermal/ThermalModuleIF.h rename to src/fsfw/thermal/ThermalModuleIF.h diff --git a/thermal/ThermalMonitorReporter.cpp b/src/fsfw/thermal/ThermalMonitorReporter.cpp similarity index 94% rename from thermal/ThermalMonitorReporter.cpp rename to src/fsfw/thermal/ThermalMonitorReporter.cpp index cefc6110..31503203 100644 --- a/thermal/ThermalMonitorReporter.cpp +++ b/src/fsfw/thermal/ThermalMonitorReporter.cpp @@ -1,7 +1,7 @@ -#include "ThermalMonitorReporter.h" -#include "ThermalComponentIF.h" +#include "fsfw/thermal/ThermalMonitorReporter.h" +#include "fsfw/thermal/ThermalComponentIF.h" -#include "../monitoring/MonitoringIF.h" +#include "fsfw/monitoring/MonitoringIF.h" ThermalMonitorReporter::~ThermalMonitorReporter() { } diff --git a/thermal/ThermalMonitorReporter.h b/src/fsfw/thermal/ThermalMonitorReporter.h similarity index 100% rename from thermal/ThermalMonitorReporter.h rename to src/fsfw/thermal/ThermalMonitorReporter.h diff --git a/thermal/tcsDefinitions.h b/src/fsfw/thermal/tcsDefinitions.h similarity index 100% rename from thermal/tcsDefinitions.h rename to src/fsfw/thermal/tcsDefinitions.h diff --git a/timemanager/CCSDSTime.cpp b/src/fsfw/timemanager/CCSDSTime.cpp similarity index 99% rename from timemanager/CCSDSTime.cpp rename to src/fsfw/timemanager/CCSDSTime.cpp index 192c1f57..2475a5eb 100644 --- a/timemanager/CCSDSTime.cpp +++ b/src/fsfw/timemanager/CCSDSTime.cpp @@ -1,5 +1,6 @@ -#include "CCSDSTime.h" -#include +#include "fsfw/FSFW.h" +#include "fsfw/timemanager/CCSDSTime.h" + #include #include #include diff --git a/timemanager/CCSDSTime.h b/src/fsfw/timemanager/CCSDSTime.h similarity index 100% rename from timemanager/CCSDSTime.h rename to src/fsfw/timemanager/CCSDSTime.h diff --git a/src/fsfw/timemanager/CMakeLists.txt b/src/fsfw/timemanager/CMakeLists.txt new file mode 100644 index 00000000..00467772 --- /dev/null +++ b/src/fsfw/timemanager/CMakeLists.txt @@ -0,0 +1,8 @@ +target_sources(${LIB_FSFW_NAME} PRIVATE + CCSDSTime.cpp + Countdown.cpp + Stopwatch.cpp + TimeMessage.cpp + TimeStamper.cpp + ClockCommon.cpp +) diff --git a/timemanager/Clock.h b/src/fsfw/timemanager/Clock.h similarity index 84% rename from timemanager/Clock.h rename to src/fsfw/timemanager/Clock.h index 6400d284..b1d6bfaf 100644 --- a/timemanager/Clock.h +++ b/src/fsfw/timemanager/Clock.h @@ -2,9 +2,9 @@ #define FSFW_TIMEMANAGER_CLOCK_H_ #include "clockDefinitions.h" -#include "../returnvalues/HasReturnvaluesIF.h" -#include "../ipc/MutexFactory.h" -#include "../globalfunctions/timevalOperations.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" +#include "fsfw/ipc/MutexFactory.h" +#include "fsfw/globalfunctions/timevalOperations.h" #include @@ -41,14 +41,14 @@ public: * @return -@c RETURN_OK on success. Otherwise, the OS failure code * is returned. */ - static ReturnValue_t setClock(const TimeOfDay_t* time); + static ReturnValue_t setClock(const TimeOfDay_t *time); /** * This system call sets the system time. * To set the time, it uses a timeval struct. * @param time The struct with the time settings to set. * @return -@c RETURN_OK on success. Otherwise, the OS failure code is returned. */ - static ReturnValue_t setClock(const timeval* time); + static ReturnValue_t setClock(const timeval *time); /** * This system call returns the current system clock in timeval format. * The timval format has the fields @c tv_sec with seconds and @c tv_usec with @@ -56,7 +56,7 @@ public: * @param time A pointer to a timeval struct where the current time is stored. * @return @c RETURN_OK on success. Otherwise, the OS failure code is returned. */ - static ReturnValue_t getClock_timeval(timeval* time); + static ReturnValue_t getClock_timeval(timeval *time); /** * Get the time since boot in a timeval struct @@ -66,7 +66,7 @@ public: * * @deprecated, I do not think this should be able to fail, use timeval getUptime() */ - static ReturnValue_t getUptime(timeval* uptime); + static ReturnValue_t getUptime(timeval *uptime); static timeval getUptime(); @@ -79,7 +79,7 @@ public: * @param ms uptime in ms * @return RETURN_OK on success. Otherwise, the OS failure code is returned. */ - static ReturnValue_t getUptime(uint32_t* uptimeMs); + static ReturnValue_t getUptime(uint32_t *uptimeMs); /** * Returns the time in microseconds since an OS-defined epoch. @@ -89,7 +89,7 @@ public: * - @c RETURN_OK on success. * - Otherwise, the OS failure code is returned. */ - static ReturnValue_t getClock_usecs(uint64_t* time); + static ReturnValue_t getClock_usecs(uint64_t *time); /** * Returns the time in a TimeOfDay_t struct. * @param time A pointer to a TimeOfDay_t struct. @@ -97,7 +97,7 @@ public: * - @c RETURN_OK on success. * - Otherwise, the OS failure code is returned. */ - static ReturnValue_t getDateAndTime(TimeOfDay_t* time); + static ReturnValue_t getDateAndTime(TimeOfDay_t *time); /** * Converts a time of day struct to POSIX seconds. @@ -107,8 +107,8 @@ public: * - @c RETURN_OK on success. * - Otherwise, the OS failure code is returned. */ - static ReturnValue_t convertTimeOfDayToTimeval(const TimeOfDay_t* from, - timeval* to); + static ReturnValue_t convertTimeOfDayToTimeval(const TimeOfDay_t *from, + timeval *to); /** * Converts a time represented as seconds and subseconds since unix @@ -118,12 +118,14 @@ public: * @param[out] JD2000 days since J2000 * @return @c RETURN_OK */ - static ReturnValue_t convertTimevalToJD2000(timeval time, double* JD2000); + static ReturnValue_t convertTimevalToJD2000(timeval time, double *JD2000); /** * Calculates and adds the offset between UTC and TT * * Depends on the leap seconds to be set correctly. + * Therefore, it does not work for historic + * dates as only the current leap seconds are known. * * @param utc timeval, corresponding to UTC time * @param[out] tt timeval, corresponding to Terrestial Time @@ -131,7 +133,7 @@ public: * - @c RETURN_OK on success * - @c RETURN_FAILED if leapSeconds are not set */ - static ReturnValue_t convertUTCToTT(timeval utc, timeval* tt); + static ReturnValue_t convertUTCToTT(timeval utc, timeval *tt); /** * Set the Leap Seconds since 1972 @@ -139,22 +141,22 @@ public: * @param leapSeconds_ * @return * - @c RETURN_OK on success. - * - Otherwise, the OS failure code is returned. */ static ReturnValue_t setLeapSeconds(const uint16_t leapSeconds_); /** * Get the Leap Seconds since 1972 * - * Must be set before! + * Setter must be called before * * @param[out] leapSeconds_ * @return * - @c RETURN_OK on success. - * - Otherwise, the OS failure code is returned. + * - @c RETURN_FAILED on error */ static ReturnValue_t getLeapSeconds(uint16_t *leapSeconds_); +private: /** * Function to check and create the Mutex for the clock * @return @@ -163,10 +165,8 @@ public: */ static ReturnValue_t checkOrCreateClockMutex(); -private: - static MutexIF* timeMutex; + static MutexIF *timeMutex; static uint16_t leapSeconds; }; - #endif /* FSFW_TIMEMANAGER_CLOCK_H_ */ diff --git a/src/fsfw/timemanager/ClockCommon.cpp b/src/fsfw/timemanager/ClockCommon.cpp new file mode 100644 index 00000000..82c65b96 --- /dev/null +++ b/src/fsfw/timemanager/ClockCommon.cpp @@ -0,0 +1,57 @@ +#include "fsfw/timemanager/Clock.h" +#include "fsfw/ipc/MutexGuard.h" + +ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval *tt) { + uint16_t leapSeconds; + ReturnValue_t result = getLeapSeconds(&leapSeconds); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + timeval leapSeconds_timeval = { 0, 0 }; + leapSeconds_timeval.tv_sec = leapSeconds; + + //initial offset between UTC and TAI + timeval UTCtoTAI1972 = { 10, 0 }; + + timeval TAItoTT = { 32, 184000 }; + + *tt = utc + leapSeconds_timeval + UTCtoTAI1972 + TAItoTT; + + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) { + if (checkOrCreateClockMutex() != HasReturnvaluesIF::RETURN_OK) { + return HasReturnvaluesIF::RETURN_FAILED; + } + MutexGuard helper(timeMutex); + + leapSeconds = leapSeconds_; + + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t Clock::getLeapSeconds(uint16_t *leapSeconds_) { + if (timeMutex == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + MutexGuard helper(timeMutex); + + *leapSeconds_ = leapSeconds; + + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t Clock::checkOrCreateClockMutex() { + if (timeMutex == nullptr) { + MutexFactory *mutexFactory = MutexFactory::instance(); + if (mutexFactory == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + timeMutex = mutexFactory->createMutex(); + if (timeMutex == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + } + return HasReturnvaluesIF::RETURN_OK; +} diff --git a/src/fsfw/timemanager/Countdown.cpp b/src/fsfw/timemanager/Countdown.cpp new file mode 100644 index 00000000..23d57477 --- /dev/null +++ b/src/fsfw/timemanager/Countdown.cpp @@ -0,0 +1,51 @@ +#include "fsfw/timemanager/Countdown.h" + +Countdown::Countdown(uint32_t initialTimeout): timeout(initialTimeout) { +} + +Countdown::~Countdown() { +} + +ReturnValue_t Countdown::setTimeout(uint32_t milliseconds) { + ReturnValue_t returnValue = Clock::getUptime( &startTime ); + timeout = milliseconds; + return returnValue; +} + +bool Countdown::hasTimedOut() const { + if ( uint32_t( this->getCurrentTime() - startTime) >= timeout) { + return true; + } else { + return false; + } +} + +bool Countdown::isBusy() const { + return !hasTimedOut(); +} + +ReturnValue_t Countdown::resetTimer() { + return setTimeout(timeout); +} + +void Countdown::timeOut() { + startTime = this->getCurrentTime() - timeout; +} + +uint32_t Countdown::getRemainingMillis() const { + // We fetch the time before the if-statement + // to be sure that the return is in + // range 0 <= number <= timeout + uint32_t currentTime = this->getCurrentTime(); + if (this->hasTimedOut()){ + return 0; + }else{ + return (startTime + timeout) - currentTime; + } +} + +uint32_t Countdown::getCurrentTime() const { + uint32_t currentTime; + Clock::getUptime( ¤tTime ); + return currentTime; +} diff --git a/src/fsfw/timemanager/Countdown.h b/src/fsfw/timemanager/Countdown.h new file mode 100644 index 00000000..c0afdf75 --- /dev/null +++ b/src/fsfw/timemanager/Countdown.h @@ -0,0 +1,80 @@ +#ifndef FSFW_TIMEMANAGER_COUNTDOWN_H_ +#define FSFW_TIMEMANAGER_COUNTDOWN_H_ + +#include "Clock.h" + +/** + * + * Countdown keeps track of a timespan. + * + * Countdown::resetTimer restarts the timer. + * Countdown::setTimeout sets a new countdown duration and resets. + * + * Can be checked with Countdown::hasTimedOut or + * Countdown::isBusy. + * + * Countdown::timeOut will force the timer to time out. + * + */ +class Countdown { +public: + /** + * Constructor which sets the countdown duration in milliseconds + * + * It does not start the countdown! + * Call resetTimer or setTimeout before usage! + * Otherwise a call to hasTimedOut might return True. + * + * @param initialTimeout Countdown duration in milliseconds + */ + Countdown(uint32_t initialTimeout = 0); + ~Countdown(); + /** + * Call to set a new countdown duration. + * + * Resets the countdown! + * + * @param milliseconds new countdown duration in milliseconds + * @return Returnvalue from Clock::getUptime + */ + ReturnValue_t setTimeout(uint32_t milliseconds); + /** + * Returns true if the countdown duration has passed. + * + * @return True if the countdown has passed + * False if it is still running + */ + bool hasTimedOut() const; + /** + * Complementary to hasTimedOut. + * + * @return True if the countdown is till running + * False if it is still running + */ + bool isBusy() const; + /** + * Uses last set timeout value and restarts timer. + */ + ReturnValue_t resetTimer(); + /** + * Returns the remaining milliseconds (0 if timeout) + */ + uint32_t getRemainingMillis() const; + /** + * Makes hasTimedOut() return true + */ + void timeOut(); + /** + * Internal countdown duration in milliseconds + */ + uint32_t timeout; +private: + /** + * Last time the timer was started (uptime) + */ + uint32_t startTime = 0; + + uint32_t getCurrentTime() const; +}; + +#endif /* FSFW_TIMEMANAGER_COUNTDOWN_H_ */ diff --git a/timemanager/ReceivesTimeInfoIF.h b/src/fsfw/timemanager/ReceivesTimeInfoIF.h similarity index 100% rename from timemanager/ReceivesTimeInfoIF.h rename to src/fsfw/timemanager/ReceivesTimeInfoIF.h diff --git a/timemanager/Stopwatch.cpp b/src/fsfw/timemanager/Stopwatch.cpp similarity index 95% rename from timemanager/Stopwatch.cpp rename to src/fsfw/timemanager/Stopwatch.cpp index 04ccab72..a8f87029 100644 --- a/timemanager/Stopwatch.cpp +++ b/src/fsfw/timemanager/Stopwatch.cpp @@ -1,5 +1,5 @@ -#include "Stopwatch.h" -#include "../serviceinterface/ServiceInterface.h" +#include "fsfw/timemanager/Stopwatch.h" +#include "fsfw/serviceinterface/ServiceInterface.h" #if FSFW_CPP_OSTREAM_ENABLED == 1 #include diff --git a/timemanager/Stopwatch.h b/src/fsfw/timemanager/Stopwatch.h similarity index 100% rename from timemanager/Stopwatch.h rename to src/fsfw/timemanager/Stopwatch.h diff --git a/timemanager/TimeMessage.cpp b/src/fsfw/timemanager/TimeMessage.cpp similarity index 94% rename from timemanager/TimeMessage.cpp rename to src/fsfw/timemanager/TimeMessage.cpp index 66aea0f4..320f3000 100644 --- a/timemanager/TimeMessage.cpp +++ b/src/fsfw/timemanager/TimeMessage.cpp @@ -1,4 +1,4 @@ -#include "TimeMessage.h" +#include "fsfw/timemanager/TimeMessage.h" TimeMessage::TimeMessage() { this->messageSize += sizeof(timeval) + sizeof(uint32_t); diff --git a/timemanager/TimeMessage.h b/src/fsfw/timemanager/TimeMessage.h similarity index 100% rename from timemanager/TimeMessage.h rename to src/fsfw/timemanager/TimeMessage.h diff --git a/timemanager/TimeStamper.cpp b/src/fsfw/timemanager/TimeStamper.cpp similarity index 87% rename from timemanager/TimeStamper.cpp rename to src/fsfw/timemanager/TimeStamper.cpp index d9f0f2f3..4926c2d5 100644 --- a/timemanager/TimeStamper.cpp +++ b/src/fsfw/timemanager/TimeStamper.cpp @@ -1,5 +1,6 @@ -#include "TimeStamper.h" -#include "Clock.h" +#include "fsfw/timemanager/TimeStamper.h" +#include "fsfw/timemanager/Clock.h" + #include TimeStamper::TimeStamper(object_id_t objectId): SystemObject(objectId) {} diff --git a/timemanager/TimeStamper.h b/src/fsfw/timemanager/TimeStamper.h similarity index 100% rename from timemanager/TimeStamper.h rename to src/fsfw/timemanager/TimeStamper.h diff --git a/src/fsfw/timemanager/TimeStamperIF.h b/src/fsfw/timemanager/TimeStamperIF.h new file mode 100644 index 00000000..87987499 --- /dev/null +++ b/src/fsfw/timemanager/TimeStamperIF.h @@ -0,0 +1,31 @@ +#ifndef FSFW_TIMEMANAGER_TIMESTAMPERIF_H_ +#define FSFW_TIMEMANAGER_TIMESTAMPERIF_H_ + +#include +#include "../returnvalues/HasReturnvaluesIF.h" +#include + +/** + * A class implementing this IF provides facilities to add a time stamp to the + * buffer provided. + * Implementors need to ensure that calling the method is thread-safe, i.e. + * addTimeStamp may be called in parallel from a different context. + */ +class TimeStamperIF { +public: + static const uint8_t INTERFACE_ID = CLASS_ID::TIME_STAMPER_IF; + static const ReturnValue_t BAD_TIMESTAMP = MAKE_RETURN_CODE(1); + + //! This is a mission-specific constant and determines the total + //! size reserved for timestamps. + + static const uint8_t MISSION_TIMESTAMP_SIZE = fsfwconfig::FSFW_MISSION_TIMESTAMP_SIZE; + + virtual ReturnValue_t addTimeStamp(uint8_t* buffer, + const uint8_t maxSize) = 0; + virtual ~TimeStamperIF() {} +}; + + + +#endif /* FSFW_TIMEMANAGER_TIMESTAMPERIF_H_ */ diff --git a/src/fsfw/timemanager/TimeStamperIF_BACKUP_9594.h b/src/fsfw/timemanager/TimeStamperIF_BACKUP_9594.h new file mode 100644 index 00000000..a9fe8857 --- /dev/null +++ b/src/fsfw/timemanager/TimeStamperIF_BACKUP_9594.h @@ -0,0 +1,35 @@ +#ifndef FSFW_TIMEMANAGER_TIMESTAMPERIF_H_ +#define FSFW_TIMEMANAGER_TIMESTAMPERIF_H_ + +#include +#include "../returnvalues/HasReturnvaluesIF.h" +#include + +/** + * A class implementing this IF provides facilities to add a time stamp to the + * buffer provided. + * Implementors need to ensure that calling the method is thread-safe, i.e. + * addTimeStamp may be called in parallel from a different context. + */ +class TimeStamperIF { +public: + static const uint8_t INTERFACE_ID = CLASS_ID::TIME_STAMPER_IF; + static const ReturnValue_t BAD_TIMESTAMP = MAKE_RETURN_CODE(1); + + //! This is a mission-specific constant and determines the total + //! size reserved for timestamps. +<<<<<<< HEAD:timemanager/TimeStamperIF.h + //! TODO: Default define in FSFWConfig ? + static const uint8_t MISSION_TIMESTAMP_SIZE = 6; +======= + static const uint8_t MISSION_TIMESTAMP_SIZE = fsfwconfig::FSFW_MISSION_TIMESTAMP_SIZE; + +>>>>>>> upstream/master:src/fsfw/timemanager/TimeStamperIF.h + virtual ReturnValue_t addTimeStamp(uint8_t* buffer, + const uint8_t maxSize) = 0; + virtual ~TimeStamperIF() {} +}; + + + +#endif /* FSFW_TIMEMANAGER_TIMESTAMPERIF_H_ */ diff --git a/src/fsfw/timemanager/TimeStamperIF_BASE_9594.h b/src/fsfw/timemanager/TimeStamperIF_BASE_9594.h new file mode 100644 index 00000000..57b7f014 --- /dev/null +++ b/src/fsfw/timemanager/TimeStamperIF_BASE_9594.h @@ -0,0 +1,28 @@ +#ifndef FSFW_TIMEMANAGER_TIMESTAMPERIF_H_ +#define FSFW_TIMEMANAGER_TIMESTAMPERIF_H_ + +#include "../returnvalues/HasReturnvaluesIF.h" + +/** + * A class implementing this IF provides facilities to add a time stamp to the + * buffer provided. + * Implementors need to ensure that calling the method is thread-safe, i.e. + * addTimeStamp may be called in parallel from a different context. + */ +class TimeStamperIF { +public: + static const uint8_t INTERFACE_ID = CLASS_ID::TIME_STAMPER_IF; + static const ReturnValue_t BAD_TIMESTAMP = MAKE_RETURN_CODE(1); + + //! This is a mission-specific constant and determines the total + //! size reserved for timestamps. + //! TODO: Default define in FSFWConfig ? + static const uint8_t MISSION_TIMESTAMP_SIZE = 8; + virtual ReturnValue_t addTimeStamp(uint8_t* buffer, + const uint8_t maxSize) = 0; + virtual ~TimeStamperIF() {} +}; + + + +#endif /* FSFW_TIMEMANAGER_TIMESTAMPERIF_H_ */ diff --git a/timemanager/TimeStamperIF.h b/src/fsfw/timemanager/TimeStamperIF_LOCAL_9594.h similarity index 100% rename from timemanager/TimeStamperIF.h rename to src/fsfw/timemanager/TimeStamperIF_LOCAL_9594.h diff --git a/src/fsfw/timemanager/TimeStamperIF_REMOTE_9594.h b/src/fsfw/timemanager/TimeStamperIF_REMOTE_9594.h new file mode 100644 index 00000000..34990500 --- /dev/null +++ b/src/fsfw/timemanager/TimeStamperIF_REMOTE_9594.h @@ -0,0 +1,30 @@ +#ifndef FSFW_TIMEMANAGER_TIMESTAMPERIF_H_ +#define FSFW_TIMEMANAGER_TIMESTAMPERIF_H_ + +#include +#include "../returnvalues/HasReturnvaluesIF.h" +#include + +/** + * A class implementing this IF provides facilities to add a time stamp to the + * buffer provided. + * Implementors need to ensure that calling the method is thread-safe, i.e. + * addTimeStamp may be called in parallel from a different context. + */ +class TimeStamperIF { +public: + static const uint8_t INTERFACE_ID = CLASS_ID::TIME_STAMPER_IF; + static const ReturnValue_t BAD_TIMESTAMP = MAKE_RETURN_CODE(1); + + //! This is a mission-specific constant and determines the total + //! size reserved for timestamps. + static const uint8_t MISSION_TIMESTAMP_SIZE = fsfwconfig::FSFW_MISSION_TIMESTAMP_SIZE; + + virtual ReturnValue_t addTimeStamp(uint8_t* buffer, + const uint8_t maxSize) = 0; + virtual ~TimeStamperIF() {} +}; + + + +#endif /* FSFW_TIMEMANAGER_TIMESTAMPERIF_H_ */ diff --git a/timemanager/clockDefinitions.h b/src/fsfw/timemanager/clockDefinitions.h similarity index 100% rename from timemanager/clockDefinitions.h rename to src/fsfw/timemanager/clockDefinitions.h diff --git a/tmstorage/CMakeLists.txt b/src/fsfw/tmstorage/CMakeLists.txt similarity index 100% rename from tmstorage/CMakeLists.txt rename to src/fsfw/tmstorage/CMakeLists.txt diff --git a/tmstorage/TmStoreBackendIF.h b/src/fsfw/tmstorage/TmStoreBackendIF.h similarity index 95% rename from tmstorage/TmStoreBackendIF.h rename to src/fsfw/tmstorage/TmStoreBackendIF.h index 4ae77609..4183334b 100644 --- a/tmstorage/TmStoreBackendIF.h +++ b/src/fsfw/tmstorage/TmStoreBackendIF.h @@ -1,11 +1,13 @@ #ifndef FSFW_TMTCSERVICES_TMSTOREBACKENDIF_H_ #define FSFW_TMTCSERVICES_TMSTOREBACKENDIF_H_ -#include "../returnvalues/HasReturnvaluesIF.h" -#include "../objectmanager/SystemObjectIF.h" -#include "../parameters/HasParametersIF.h" -#include "../storagemanager/StorageManagerIF.h" -#include "../timemanager/Clock.h" +#include "tmStorageConf.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" +#include "fsfw/objectmanager/SystemObjectIF.h" +#include "fsfw/parameters/HasParametersIF.h" +#include "fsfw/storagemanager/StorageManagerIF.h" +#include "fsfw/timemanager/Clock.h" + class TmPacketInformation; class TmPacketMinimal; class SpacePacketBase; diff --git a/tmstorage/TmStoreFrontendIF.h b/src/fsfw/tmstorage/TmStoreFrontendIF.h similarity index 95% rename from tmstorage/TmStoreFrontendIF.h rename to src/fsfw/tmstorage/TmStoreFrontendIF.h index beee7ede..11b2a686 100644 --- a/tmstorage/TmStoreFrontendIF.h +++ b/src/fsfw/tmstorage/TmStoreFrontendIF.h @@ -1,9 +1,10 @@ #ifndef FSFW_TMTCSERVICES_TMSTOREFRONTENDIF_H_ #define FSFW_TMTCSERVICES_TMSTOREFRONTENDIF_H_ +#include "tmStorageConf.h" #include "TmStorePackets.h" -#include "../returnvalues/HasReturnvaluesIF.h" -#include "../ipc/MessageQueueSenderIF.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" +#include "fsfw/ipc/MessageQueueSenderIF.h" class TmPacketMinimal; class SpacePacketBase; diff --git a/tmstorage/TmStoreMessage.cpp b/src/fsfw/tmstorage/TmStoreMessage.cpp similarity index 97% rename from tmstorage/TmStoreMessage.cpp rename to src/fsfw/tmstorage/TmStoreMessage.cpp index 033cbb1d..fa5fb541 100644 --- a/tmstorage/TmStoreMessage.cpp +++ b/src/fsfw/tmstorage/TmStoreMessage.cpp @@ -1,5 +1,5 @@ #include "TmStoreMessage.h" -#include "../objectmanager/ObjectManagerIF.h" +#include "fsfw/objectmanager/ObjectManager.h" TmStoreMessage::~TmStoreMessage() { @@ -64,7 +64,7 @@ void TmStoreMessage::clear(CommandMessage* cmd) { case INDEX_REPORT: case DELETE_STORE_CONTENT_TIME: case DOWNLINK_STORE_CONTENT_TIME: { - StorageManagerIF *ipcStore = objectManager->get( + StorageManagerIF *ipcStore = ObjectManager::instance()->get( objects::IPC_STORE); if (ipcStore != NULL) { ipcStore->deleteData(getStoreId(cmd)); diff --git a/tmstorage/TmStoreMessage.h b/src/fsfw/tmstorage/TmStoreMessage.h similarity index 95% rename from tmstorage/TmStoreMessage.h rename to src/fsfw/tmstorage/TmStoreMessage.h index d0178920..51f86b3a 100644 --- a/tmstorage/TmStoreMessage.h +++ b/src/fsfw/tmstorage/TmStoreMessage.h @@ -1,10 +1,11 @@ #ifndef FSFW_TMSTORAGE_TMSTOREMESSAGE_H_ #define FSFW_TMSTORAGE_TMSTOREMESSAGE_H_ +#include "tmStorageConf.h" #include "TmStorePackets.h" -#include "../ipc/CommandMessage.h" -#include "../storagemanager/StorageManagerIF.h" -#include "../objectmanager/SystemObjectIF.h" +#include "fsfw/ipc/CommandMessage.h" +#include "fsfw/storagemanager/StorageManagerIF.h" +#include "fsfw/objectmanager/SystemObjectIF.h" class TmStoreMessage { public: diff --git a/tmstorage/TmStorePackets.h b/src/fsfw/tmstorage/TmStorePackets.h similarity index 95% rename from tmstorage/TmStorePackets.h rename to src/fsfw/tmstorage/TmStorePackets.h index 3abd0c1c..738f7ac2 100644 --- a/tmstorage/TmStorePackets.h +++ b/src/fsfw/tmstorage/TmStorePackets.h @@ -1,14 +1,15 @@ #ifndef FSFW_TMSTORAGE_TMSTOREPACKETS_H_ #define FSFW_TMSTORAGE_TMSTOREPACKETS_H_ -#include "../serialize/SerialFixedArrayListAdapter.h" -#include "../serialize/SerializeElement.h" -#include "../serialize/SerialLinkedListAdapter.h" -#include "../serialize/SerialBufferAdapter.h" -#include "../tmtcpacket/pus/TmPacketMinimal.h" -#include "../timemanager/TimeStamperIF.h" -#include "../timemanager/CCSDSTime.h" -#include "../globalfunctions/timevalOperations.h" +#include "tmStorageConf.h" +#include "fsfw/serialize/SerialFixedArrayListAdapter.h" +#include "fsfw/serialize/SerializeElement.h" +#include "fsfw/serialize/SerialLinkedListAdapter.h" +#include "fsfw/serialize/SerialBufferAdapter.h" +#include "fsfw/tmtcpacket/pus/tm/TmPacketMinimal.h" +#include "fsfw/timemanager/TimeStamperIF.h" +#include "fsfw/timemanager/CCSDSTime.h" +#include "fsfw/globalfunctions/timevalOperations.h" class ServiceSubservice: public SerialLinkedListAdapter { public: diff --git a/src/fsfw/tmstorage/tmStorageConf.h b/src/fsfw/tmstorage/tmStorageConf.h new file mode 100644 index 00000000..e5c3d0d5 --- /dev/null +++ b/src/fsfw/tmstorage/tmStorageConf.h @@ -0,0 +1,11 @@ +#ifndef FSFW_TMSTORAGE_TMSTORAGECONF_H_ +#define FSFW_TMSTORAGE_TMSTORAGECONF_H_ + +#include "fsfw/FSFW.h" + +#ifndef FSFW_ADD_TMSTORAGE +#warning TM storage files were includes but compilation was \ + not enabled with FSFW_ADD_TMSTORAGE +#endif + +#endif /* FSFW_TMSTORAGE_TMSTORAGECONF_H_ */ diff --git a/src/fsfw/tmtcpacket/CMakeLists.txt b/src/fsfw/tmtcpacket/CMakeLists.txt new file mode 100644 index 00000000..fdc884ec --- /dev/null +++ b/src/fsfw/tmtcpacket/CMakeLists.txt @@ -0,0 +1,7 @@ +target_sources(${LIB_FSFW_NAME} PRIVATE + SpacePacket.cpp + SpacePacketBase.cpp +) + +add_subdirectory(packetmatcher) +add_subdirectory(pus) \ No newline at end of file diff --git a/tmtcpacket/SpacePacket.cpp b/src/fsfw/tmtcpacket/SpacePacket.cpp similarity index 66% rename from tmtcpacket/SpacePacket.cpp rename to src/fsfw/tmtcpacket/SpacePacket.cpp index b8ba27e9..cbf82e0d 100644 --- a/tmtcpacket/SpacePacket.cpp +++ b/src/fsfw/tmtcpacket/SpacePacket.cpp @@ -1,10 +1,10 @@ -#include "../serviceinterface/ServiceInterfaceStream.h" -#include "ccsds_header.h" -#include "SpacePacket.h" -#include +#include "fsfw/tmtcpacket/ccsds_header.h" +#include "fsfw/tmtcpacket/SpacePacket.h" +#include -SpacePacket::SpacePacket( uint16_t packetDataLength, bool isTelecommand, uint16_t apid, uint16_t sequenceCount ): -SpacePacketBase( (uint8_t*)&this->localData ) { +SpacePacket::SpacePacket(uint16_t packetDataLength, bool isTelecommand, uint16_t apid, + uint16_t sequenceCount): + SpacePacketBase( (uint8_t*)&this->localData ) { initSpacePacketHeader(isTelecommand, false, apid, sequenceCount); this->setPacketSequenceCount(sequenceCount); if ( packetDataLength <= sizeof(this->localData.fields.buffer) ) { diff --git a/src/fsfw/tmtcpacket/SpacePacket.h b/src/fsfw/tmtcpacket/SpacePacket.h new file mode 100644 index 00000000..a092712c --- /dev/null +++ b/src/fsfw/tmtcpacket/SpacePacket.h @@ -0,0 +1,92 @@ +#ifndef SPACEPACKET_H_ +#define SPACEPACKET_H_ + +#include "SpacePacketBase.h" + +/** + * The SpacePacket class is a representation of a simple CCSDS Space Packet + * without (control over) a secondary header. + * It can be instantiated with a size smaller than \c PACKET_MAX_SIZE. Its + * main use is to serve as an idle packet in case no other packets are sent. + * For the ECSS PUS part the TcPacket and TmPacket classes are used. + * A pointer to \c local_data is passed to the \c SpacePacketBase parent class, + * so the parent's methods are reachable. + * @ingroup tmtcpackets + */ +class SpacePacket: public SpacePacketBase { +public: + static const uint16_t PACKET_MAX_SIZE = 1024; + /** + * The constructor initializes the packet and sets all header information + * according to the passed parameters. + * @param packetDataLength Sets the packet data length field and therefore specifies + * the size of the packet. + * @param isTelecommand Sets the packet type field to either TC (true) or TM (false). + * @param apid Sets the packet's APID field. The default value describes an idle packet. + * @param sequenceCount ets the packet's Source Sequence Count field. + */ + SpacePacket(uint16_t packetDataLength, bool isTelecommand = false, + uint16_t apid = APID_IDLE_PACKET, uint16_t sequenceCount = 0); + /** + * The class's default destructor. + */ + virtual ~SpacePacket(); + /** + * With this call, the complete data content (including the CCSDS Primary + * Header) is overwritten with the byte stream given. + * @param p_data Pointer to data to overwrite the content with + * @param packet_size Size of the data + * @return @li \c true if packet_size is smaller than \c MAX_PACKET_SIZE. + * @li \c false else. + */ + bool addWholeData(const uint8_t* p_data, uint32_t packet_size); + +protected: + /** + * This structure defines the data structure of a Space Packet as local data. + * There's a buffer which corresponds to the Space Packet Data Field with a + * maximum size of \c PACKET_MAX_SIZE. + */ + struct PacketStructured { + CCSDSPrimaryHeader header; + uint8_t buffer[PACKET_MAX_SIZE]; + }; + /** + * This union simplifies accessing the full data content of the Space Packet. + * This is achieved by putting the \c PacketStructured struct in a union with + * a plain buffer. + */ + union SpacePacketData { + PacketStructured fields; + uint8_t byteStream[PACKET_MAX_SIZE + sizeof(CCSDSPrimaryHeader)]; + }; + /** + * This is the data representation of the class. + * It is a struct of CCSDS Primary Header and a data field, which again is + * packed in an union, so the data can be accessed as a byte stream without + * a cast. + */ + SpacePacketData localData; +}; + +namespace spacepacket { + +constexpr uint16_t getSpacePacketIdFromApid(bool isTc, uint16_t apid, + bool secondaryHeaderFlag = true) { + return ((isTc << 4) | (secondaryHeaderFlag << 3) | + ((apid >> 8) & 0x07)) << 8 | (apid & 0x00ff); +} + +constexpr uint16_t getTcSpacePacketIdFromApid(uint16_t apid, + bool secondaryHeaderFlag = true) { + return getSpacePacketIdFromApid(true, apid, secondaryHeaderFlag); +} + +constexpr uint16_t getTmSpacePacketIdFromApid(uint16_t apid, + bool secondaryHeaderFlag = true) { + return getSpacePacketIdFromApid(false, apid, secondaryHeaderFlag); +} + +} + +#endif /* SPACEPACKET_H_ */ diff --git a/src/fsfw/tmtcpacket/SpacePacketBase.cpp b/src/fsfw/tmtcpacket/SpacePacketBase.cpp new file mode 100644 index 00000000..16883d7f --- /dev/null +++ b/src/fsfw/tmtcpacket/SpacePacketBase.cpp @@ -0,0 +1,123 @@ +#include "fsfw/tmtcpacket/SpacePacketBase.h" +#include "fsfw/serviceinterface/ServiceInterface.h" + +#include + +SpacePacketBase::SpacePacketBase(const uint8_t* setAddress) { + this->data = reinterpret_cast(const_cast(setAddress)); +} + +SpacePacketBase::~SpacePacketBase() { +}; + +//CCSDS Methods: +uint8_t SpacePacketBase::getPacketVersionNumber( void ) { + return (this->data->header.packet_id_h & 0b11100000) >> 5; +} + +ReturnValue_t SpacePacketBase::initSpacePacketHeader(bool isTelecommand, + bool hasSecondaryHeader, uint16_t apid, uint16_t sequenceCount) { + if(data == nullptr) { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "SpacePacketBase::initSpacePacketHeader: Data pointer is invalid" + << std::endl; +#else + sif::printWarning("SpacePacketBase::initSpacePacketHeader: Data pointer is invalid!\n"); +#endif +#endif + return HasReturnvaluesIF::RETURN_FAILED; + } + //reset header to zero: + memset(data, 0, sizeof(this->data->header) ); + //Set TC/TM bit. + data->header.packet_id_h = ((isTelecommand? 1 : 0)) << 4; + //Set secondaryHeader bit + data->header.packet_id_h |= ((hasSecondaryHeader? 1 : 0)) << 3; + this->setAPID( apid ); + //Always initialize as standalone packets. + data->header.sequence_control_h = 0b11000000; + setPacketSequenceCount(sequenceCount); + return HasReturnvaluesIF::RETURN_OK; +} + +bool SpacePacketBase::isTelecommand( void ) { + return (this->data->header.packet_id_h & 0b00010000) >> 4; +} + +bool SpacePacketBase::hasSecondaryHeader( void ) { + return (this->data->header.packet_id_h & 0b00001000) >> 3; +} + +uint16_t SpacePacketBase::getPacketId() { + return ( (this->data->header.packet_id_h) << 8 ) + + this->data->header.packet_id_l; +} + +uint16_t SpacePacketBase::getAPID( void ) const { + return ( (this->data->header.packet_id_h & 0b00000111) << 8 ) + + this->data->header.packet_id_l; +} + +void SpacePacketBase::setAPID( uint16_t new_apid ) { + // Use first three bits of new APID, but keep rest of packet id as it was (see specification). + this->data->header.packet_id_h = (this->data->header.packet_id_h & 0b11111000) | + ( ( new_apid & 0x0700 ) >> 8 ); + this->data->header.packet_id_l = ( new_apid & 0x00FF ); +} + +void SpacePacketBase::setSequenceFlags( uint8_t sequenceflags ) { + this->data->header.sequence_control_h &= 0x3F; + this->data->header.sequence_control_h |= sequenceflags << 6; +} + +uint16_t SpacePacketBase::getPacketSequenceControl( void ) { + return ( (this->data->header.sequence_control_h) << 8 ) + + this->data->header.sequence_control_l; +} + +uint8_t SpacePacketBase::getSequenceFlags( void ) { + return (this->data->header.sequence_control_h & 0b11000000) >> 6 ; +} + +uint16_t SpacePacketBase::getPacketSequenceCount( void ) const { + return ( (this->data->header.sequence_control_h & 0b00111111) << 8 ) + + this->data->header.sequence_control_l; +} + +void SpacePacketBase::setPacketSequenceCount( uint16_t new_count) { + this->data->header.sequence_control_h = ( this->data->header.sequence_control_h & 0b11000000 ) | + ( ( (new_count%LIMIT_SEQUENCE_COUNT) & 0x3F00 ) >> 8 ); + this->data->header.sequence_control_l = ( (new_count%LIMIT_SEQUENCE_COUNT) & 0x00FF ); +} + +uint16_t SpacePacketBase::getPacketDataLength() const { + return ( (this->data->header.packet_length_h) << 8 ) + + this->data->header.packet_length_l; +} + +void SpacePacketBase::setPacketDataLength( uint16_t new_length) { + this->data->header.packet_length_h = ( ( new_length & 0xFF00 ) >> 8 ); + this->data->header.packet_length_l = ( new_length & 0x00FF ); +} + +size_t SpacePacketBase::getFullSize() { + // +1 is done because size in packet data length field is: size of data field -1 + return this->getPacketDataLength() + sizeof(this->data->header) + 1; +} + +uint8_t* SpacePacketBase::getWholeData() { + return (uint8_t*)this->data; +} + +void SpacePacketBase::setData( const uint8_t* p_Data ) { + this->data = (SpacePacketPointer*)p_Data; +} + +uint32_t SpacePacketBase::getApidAndSequenceCount() const { + return (getAPID() << 16) + getPacketSequenceCount(); +} + +uint8_t* SpacePacketBase::getPacketData() { + return &(data->packet_data); +} diff --git a/src/fsfw/tmtcpacket/SpacePacketBase.h b/src/fsfw/tmtcpacket/SpacePacketBase.h new file mode 100644 index 00000000..1ebc484f --- /dev/null +++ b/src/fsfw/tmtcpacket/SpacePacketBase.h @@ -0,0 +1,190 @@ +#ifndef FSFW_TMTCPACKET_SPACEPACKETBASE_H_ +#define FSFW_TMTCPACKET_SPACEPACKETBASE_H_ + +#include "ccsds_header.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" + +#include + +/** + * @defgroup tmtcpackets Space Packets + * This is the group, where all classes associated with Telecommand and + * Telemetry packets belong to. + * The class hierarchy resembles the dependency between the different standards + * applied, namely the CCSDS Space Packet standard and the ECCSS Packet + * Utilization Standard. Most field and structure names are taken from these + * standards. + */ + +/** + * This struct defines the data structure of a Space Packet when accessed + * via a pointer. + * @ingroup tmtcpackets + */ +struct SpacePacketPointer { + CCSDSPrimaryHeader header; + uint8_t packet_data; +}; + +/** + * This class is the basic data handler for any CCSDS Space Packet + * compatible Telecommand and Telemetry packet. + * It does not contain the packet data itself but a pointer to the + * data must be set on instantiation. An invalid pointer may cause + * damage, as no getter method checks data validity. Anyway, a NULL + * check can be performed by making use of the getWholeData method. + * Remark: All bit numbers in this documentation are counted from + * the most significant bit (from left). + * @ingroup tmtcpackets + */ +class SpacePacketBase { +protected: + /** + * A pointer to a structure which defines the data structure of + * the packet header. + * To be hardware-safe, all elements are of byte size. + */ + SpacePacketPointer* data; +public: + static const uint16_t LIMIT_APID = 2048; //2^1 + static const uint16_t LIMIT_SEQUENCE_COUNT = 16384; // 2^14 + static const uint16_t APID_IDLE_PACKET = 0x7FF; + static const uint8_t TELECOMMAND_PACKET = 1; + static const uint8_t TELEMETRY_PACKET = 0; + /** + * This definition defines the CRC size in byte. + */ + static const uint8_t CRC_SIZE = 2; + /** + * This is the minimum size of a SpacePacket. + */ + static const uint16_t MINIMUM_SIZE = sizeof(CCSDSPrimaryHeader) + CRC_SIZE; + /** + * This is the default constructor. + * It sets its internal data pointer to the address passed. + * @param set_address The position where the packet data lies. + */ + SpacePacketBase( const uint8_t* set_address ); + /** + * No data is allocated, so the destructor is empty. + */ + virtual ~SpacePacketBase(); + + //CCSDS Methods + + /** + * Getter for the packet version number field. + * @return Returns the highest three bit of the packet in one byte. + */ + uint8_t getPacketVersionNumber( void ); + /** + * This method checks the type field in the header. + * This bit specifies, if the command is interpreted as Telecommand of + * as Telemetry. For a Telecommand, the bit is set. + * @return Returns true if the bit is set and false if not. + */ + bool isTelecommand( void ); + + ReturnValue_t initSpacePacketHeader(bool isTelecommand, bool hasSecondaryHeader, + uint16_t apid, uint16_t sequenceCount = 0); + /** + * The CCSDS header provides a secondary header flag (the fifth-highest bit), + * which is checked with this method. + * @return Returns true if the bit is set and false if not. + */ + bool hasSecondaryHeader( void ); + /** + * Returns the complete first two bytes of the packet, which together form + * the CCSDS packet id. + * @return The CCSDS packet id. + */ + uint16_t getPacketId( void ); + /** + * Returns the APID of a packet, which are the lowest 11 bit of the packet + * id. + * @return The CCSDS APID. + */ + uint16_t getAPID( void ) const; + /** + * Sets the APID of a packet, which are the lowest 11 bit of the packet + * id. + * @param The APID to set. The highest five bits of the parameter are + * ignored. + */ + void setAPID( uint16_t setAPID ); + + /** + * Sets the sequence flags of a packet, which are bit 17 and 18 in the space packet header. + * @param The sequence flags to set + */ + void setSequenceFlags( uint8_t sequenceflags ); + + /** + * Returns the CCSDS packet sequence control field, which are the third and + * the fourth byte of the CCSDS primary header. + * @return The CCSDS packet sequence control field. + */ + uint16_t getPacketSequenceControl( void ); + /** + * Returns the SequenceFlags, which are the highest two bit of the packet + * sequence control field. + * @return The CCSDS sequence flags. + */ + uint8_t getSequenceFlags( void ); + /** + * Returns the packet sequence count, which are the lowest 14 bit of the + * packet sequence control field. + * @return The CCSDS sequence count. + */ + uint16_t getPacketSequenceCount( void ) const; + /** + * Sets the packet sequence count, which are the lowest 14 bit of the + * packet sequence control field. + * setCount is modulo-divided by \c LIMIT_SEQUENCE_COUNT to avoid overflows. + * @param setCount The value to set the count to. + */ + void setPacketSequenceCount( uint16_t setCount ); + /** + * Returns the packet data length, which is the fifth and sixth byte of the + * CCSDS Primary Header. The packet data length is the size of every kind + * of data \b after the CCSDS Primary Header \b -1. + * @return + * The CCSDS packet data length. uint16_t is sufficient, + * because this is limit in CCSDS standard + */ + uint16_t getPacketDataLength(void) const; + /** + * Sets the packet data length, which is the fifth and sixth byte of the + * CCSDS Primary Header. + * @param setLength The value of the length to set. It must fit the true + * CCSDS packet data length . The packet data length is + * the size of every kind of data \b after the CCSDS + * Primary Header \b -1. + */ + void setPacketDataLength( uint16_t setLength ); + + // Helper methods + /** + * This method returns a raw uint8_t pointer to the packet. + * @return A \c uint8_t pointer to the first byte of the CCSDS primary header. + */ + virtual uint8_t* getWholeData( void ); + + uint8_t* getPacketData(); + /** + * With this method, the packet data pointer can be redirected to another + * location. + * @param p_Data A pointer to another raw Space Packet. + */ + virtual void setData( const uint8_t* p_Data ); + /** + * This method returns the full raw packet size. + * @return The full size of the packet in bytes. + */ + size_t getFullSize(); + + uint32_t getApidAndSequenceCount() const; + +}; + +#endif /* FSFW_TMTCPACKET_SPACEPACKETBASE_H_ */ diff --git a/tmtcpacket/ccsds_header.h b/src/fsfw/tmtcpacket/ccsds_header.h similarity index 100% rename from tmtcpacket/ccsds_header.h rename to src/fsfw/tmtcpacket/ccsds_header.h diff --git a/src/fsfw/tmtcpacket/packetmatcher/ApidMatcher.h b/src/fsfw/tmtcpacket/packetmatcher/ApidMatcher.h new file mode 100644 index 00000000..33db7151 --- /dev/null +++ b/src/fsfw/tmtcpacket/packetmatcher/ApidMatcher.h @@ -0,0 +1,40 @@ +#ifndef FSFW_TMTCPACKET_PACKETMATCHER_APIDMATCHER_H_ +#define FSFW_TMTCPACKET_PACKETMATCHER_APIDMATCHER_H_ + +#include "../../globalfunctions/matching/SerializeableMatcherIF.h" +#include "../../serialize/SerializeAdapter.h" +#include "../../tmtcpacket/pus/tm/TmPacketMinimal.h" + +class ApidMatcher: public SerializeableMatcherIF { +private: + uint16_t apid; +public: + ApidMatcher(uint16_t setApid) : + apid(setApid) { + } + ApidMatcher(TmPacketMinimal* test) : + apid(test->getAPID()) { + } + bool match(TmPacketMinimal* packet) { + if (packet->getAPID() == apid) { + return true; + } else { + return false; + } + } + ReturnValue_t serialize(uint8_t** buffer, size_t* size, + size_t maxSize, Endianness streamEndianness) const { + return SerializeAdapter::serialize(&apid, buffer, size, maxSize, streamEndianness); + } + size_t getSerializedSize() const { + return SerializeAdapter::getSerializedSize(&apid); + } + ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + Endianness streamEndianness) { + return SerializeAdapter::deSerialize(&apid, buffer, size, streamEndianness); + } +}; + + + +#endif /* FRAMEWORK_TMTCPACKET_PACKETMATCHER_APIDMATCHER_H_ */ diff --git a/tmtcpacket/packetmatcher/CMakeLists.txt b/src/fsfw/tmtcpacket/packetmatcher/CMakeLists.txt similarity index 100% rename from tmtcpacket/packetmatcher/CMakeLists.txt rename to src/fsfw/tmtcpacket/packetmatcher/CMakeLists.txt diff --git a/src/fsfw/tmtcpacket/packetmatcher/PacketMatchTree.cpp b/src/fsfw/tmtcpacket/packetmatcher/PacketMatchTree.cpp new file mode 100644 index 00000000..7f8aae9a --- /dev/null +++ b/src/fsfw/tmtcpacket/packetmatcher/PacketMatchTree.cpp @@ -0,0 +1,198 @@ +#include "fsfw/tmtcpacket/packetmatcher/ApidMatcher.h" +#include "fsfw/tmtcpacket/packetmatcher/PacketMatchTree.h" +#include "fsfw/tmtcpacket/packetmatcher/ServiceMatcher.h" +#include "fsfw/tmtcpacket/packetmatcher/SubserviceMatcher.h" + +// This should be configurable.. +const LocalPool::LocalPoolConfig PacketMatchTree::poolConfig = { + {10, sizeof(ServiceMatcher)}, + {20, sizeof(SubServiceMatcher)}, + {2, sizeof(ApidMatcher)}, + {40, sizeof(PacketMatchTree::Node)} +}; + +PacketMatchTree::PacketMatchTree(Node* root): MatchTree(root, 2), + factoryBackend(0, poolConfig, false, true), + factory(&factoryBackend) { +} + +PacketMatchTree::PacketMatchTree(iterator root): MatchTree(root.element, 2), + factoryBackend(0, poolConfig, false, true), + factory(&factoryBackend) { +} + +PacketMatchTree::PacketMatchTree(): MatchTree((Node*) NULL, 2), + factoryBackend(0, poolConfig, false, true), + factory(&factoryBackend) { +} + +PacketMatchTree::~PacketMatchTree() { +} + +ReturnValue_t PacketMatchTree::addMatch(uint16_t apid, uint8_t type, + uint8_t subtype) { + //We assume adding APID is always requested. + TmPacketMinimal::TmPacketMinimalPointer data; + data.data_field.service_type = type; + data.data_field.service_subtype = subtype; + TmPacketMinimal testPacket((uint8_t*) &data); + testPacket.setAPID(apid); + iterator lastTest; + iterator rollback; + ReturnValue_t result = findOrInsertMatch( + this->begin(), &testPacket, &lastTest); + if (result == NEW_NODE_CREATED) { + rollback = lastTest; + } else if (result != RETURN_OK) { + return result; + } + if (type == 0) { + //Check if lastTest has no children, otherwise, delete them, + //as a more general check is requested. + if (lastTest.left() != this->end()) { + removeElementAndAllChildren(lastTest.left()); + } + return RETURN_OK; + } + //Type insertion required. + result = findOrInsertMatch( + lastTest.left(), &testPacket, &lastTest); + if (result == NEW_NODE_CREATED) { + if (rollback == this->end()) { + rollback = lastTest; + } + } else if (result != RETURN_OK) { + if (rollback != this->end()) { + removeElementAndAllChildren(rollback); + } + return result; + } + if (subtype == 0) { + if (lastTest.left() != this->end()) { + //See above + removeElementAndAllChildren(lastTest.left()); + } + return RETURN_OK; + } + //Subtype insertion required. + result = findOrInsertMatch( + lastTest.left(), &testPacket, &lastTest); + if (result == NEW_NODE_CREATED) { + return RETURN_OK; + } else if (result != RETURN_OK) { + if (rollback != this->end()) { + removeElementAndAllChildren(rollback); + } + return result; + } + return RETURN_OK; +} + +template +ReturnValue_t PacketMatchTree::findOrInsertMatch(iterator startAt, VALUE_T test, + iterator* lastTest) { + bool attachToBranch = AND; + iterator iter = startAt; + while (iter != this->end()) { + bool isMatch = iter->match(test); + attachToBranch = OR; + *lastTest = iter; + if (isMatch) { + return RETURN_OK; + } else { + //Go down OR branch. + iter = iter.right(); + } + } + //Only reached if nothing was found. + SerializeableMatcherIF* newContent = factory.generate( + test); + if (newContent == NULL) { + return FULL; + } + Node* newNode = factory.generate(newContent); + if (newNode == NULL) { + //Need to make sure partially generated content is deleted, otherwise, that's a leak. + factory.destroy(static_cast(newContent)); + return FULL; + } + *lastTest = insert(attachToBranch, *lastTest, newNode); + if (*lastTest == end()) { + //This actaully never fails, so creating a dedicated returncode seems an overshoot. + return RETURN_FAILED; + } + return NEW_NODE_CREATED; +} + +ReturnValue_t PacketMatchTree::removeMatch(uint16_t apid, uint8_t type, + uint8_t subtype) { + TmPacketMinimal::TmPacketMinimalPointer data; + data.data_field.service_type = type; + data.data_field.service_subtype = subtype; + TmPacketMinimal testPacket((uint8_t*) &data); + testPacket.setAPID(apid); + iterator foundElement = findMatch(begin(), &testPacket); + if (foundElement == this->end()) { + return NO_MATCH; + } + if (type == 0) { + if (foundElement.left() == end()) { + return removeElementAndReconnectChildren(foundElement); + } else { + return TOO_GENERAL_REQUEST; + } + } + //Go down AND branch. Will abort if empty. + foundElement = findMatch(foundElement.left(), &testPacket); + if (foundElement == this->end()) { + return NO_MATCH; + } + if (subtype == 0) { + if (foundElement.left() == end()) { + return removeElementAndReconnectChildren(foundElement); + } else { + return TOO_GENERAL_REQUEST; + } + } + //Again, go down AND branch. + foundElement = findMatch(foundElement.left(), &testPacket); + if (foundElement == end()) { + return NO_MATCH; + } + return removeElementAndReconnectChildren(foundElement); +} + +PacketMatchTree::iterator PacketMatchTree::findMatch(iterator startAt, + TmPacketMinimal* test) { + iterator iter = startAt; + while (iter != end()) { + bool isMatch = iter->match(test); + if (isMatch) { + break; + } else { + iter = iter.right(); //next OR element + } + } + return iter; +} + +ReturnValue_t PacketMatchTree::initialize() { + return factoryBackend.initialize(); +} + + +ReturnValue_t PacketMatchTree::changeMatch(bool addToMatch, uint16_t apid, + uint8_t type, uint8_t subtype) { + if (addToMatch) { + return addMatch(apid, type, subtype); + } else { + return removeMatch(apid, type, subtype); + } +} + +ReturnValue_t PacketMatchTree::cleanUpElement(iterator position) { + factory.destroy(position.element->value); + //Go on anyway, there's nothing we can do. + //SHOULDDO: Throw event, or write debug message? + return factory.destroy(position.element); +} diff --git a/src/fsfw/tmtcpacket/packetmatcher/PacketMatchTree.h b/src/fsfw/tmtcpacket/packetmatcher/PacketMatchTree.h new file mode 100644 index 00000000..e2439c74 --- /dev/null +++ b/src/fsfw/tmtcpacket/packetmatcher/PacketMatchTree.h @@ -0,0 +1,37 @@ +#ifndef FSFW_TMTCPACKET_PACKETMATCHER_PACKETMATCHTREE_H_ +#define FSFW_TMTCPACKET_PACKETMATCHER_PACKETMATCHTREE_H_ + +#include "fsfw/container/PlacementFactory.h" +#include "fsfw/globalfunctions/matching/MatchTree.h" +#include "fsfw/storagemanager/LocalPool.h" +#include "fsfw/tmtcpacket/pus/tm/TmPacketMinimal.h" + +class PacketMatchTree: public MatchTree, public HasReturnvaluesIF { +public: + PacketMatchTree(Node* root); + PacketMatchTree(iterator root); + PacketMatchTree(); + virtual ~PacketMatchTree(); + ReturnValue_t changeMatch(bool addToMatch, uint16_t apid, uint8_t type = 0, + uint8_t subtype = 0); + ReturnValue_t addMatch(uint16_t apid, uint8_t type = 0, + uint8_t subtype = 0); + ReturnValue_t removeMatch(uint16_t apid, uint8_t type = 0, + uint8_t subtype = 0); + ReturnValue_t initialize(); +protected: + ReturnValue_t cleanUpElement(iterator position); +private: + static const uint8_t N_POOLS = 4; + LocalPool factoryBackend; + PlacementFactory factory; + static const LocalPool::LocalPoolConfig poolConfig; + static const uint16_t POOL_SIZES[N_POOLS]; + static const uint16_t N_ELEMENTS[N_POOLS]; + template + ReturnValue_t findOrInsertMatch(iterator startAt, VALUE_T test, iterator* lastTest); + iterator findMatch(iterator startAt, TmPacketMinimal* test); +}; + +#endif /* FRAMEWORK_TMTCPACKET_PACKETMATCHER_PACKETMATCHTREE_H_ */ + diff --git a/src/fsfw/tmtcpacket/packetmatcher/ServiceMatcher.h b/src/fsfw/tmtcpacket/packetmatcher/ServiceMatcher.h new file mode 100644 index 00000000..67d09d2b --- /dev/null +++ b/src/fsfw/tmtcpacket/packetmatcher/ServiceMatcher.h @@ -0,0 +1,39 @@ +#ifndef FRAMEWORK_TMTCPACKET_PACKETMATCHER_SERVICEMATCHER_H_ +#define FRAMEWORK_TMTCPACKET_PACKETMATCHER_SERVICEMATCHER_H_ + +#include "../../globalfunctions/matching/SerializeableMatcherIF.h" +#include "../../serialize/SerializeAdapter.h" +#include "../pus/tm/TmPacketMinimal.h" + +class ServiceMatcher: public SerializeableMatcherIF { +private: + uint8_t service; +public: + ServiceMatcher(uint8_t setService) : + service(setService) { + } + ServiceMatcher(TmPacketMinimal* test) : + service(test->getService()) { + } + bool match(TmPacketMinimal* packet) { + if (packet->getService() == service) { + return true; + } else { + return false; + } + } + ReturnValue_t serialize(uint8_t** buffer, size_t* size, + size_t maxSize, Endianness streamEndianness) const { + return SerializeAdapter::serialize(&service, buffer, size, maxSize, streamEndianness); + } + size_t getSerializedSize() const { + return SerializeAdapter::getSerializedSize(&service); + } + ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + Endianness streamEndianness) { + return SerializeAdapter::deSerialize(&service, buffer, size, streamEndianness); + } +}; + + +#endif /* FRAMEWORK_TMTCPACKET_PACKETMATCHER_SERVICEMATCHER_H_ */ diff --git a/src/fsfw/tmtcpacket/packetmatcher/SubserviceMatcher.h b/src/fsfw/tmtcpacket/packetmatcher/SubserviceMatcher.h new file mode 100644 index 00000000..e570b452 --- /dev/null +++ b/src/fsfw/tmtcpacket/packetmatcher/SubserviceMatcher.h @@ -0,0 +1,40 @@ +#ifndef FSFW_TMTCPACKET_PACKETMATCHER_SUBSERVICEMATCHER_H_ +#define FSFW_TMTCPACKET_PACKETMATCHER_SUBSERVICEMATCHER_H_ + +#include "../../globalfunctions/matching/SerializeableMatcherIF.h" +#include "../../serialize/SerializeAdapter.h" +#include "../pus/tm/TmPacketMinimal.h" + +class SubServiceMatcher: public SerializeableMatcherIF { +public: + SubServiceMatcher(uint8_t subService) : + subService(subService) { + } + SubServiceMatcher(TmPacketMinimal* test) : + subService(test->getSubService()) { + } + bool match(TmPacketMinimal* packet) { + if (packet->getSubService() == subService) { + return true; + } else { + return false; + } + } + ReturnValue_t serialize(uint8_t** buffer, size_t* size, + size_t maxSize, Endianness streamEndianness) const { + return SerializeAdapter::serialize(&subService, buffer, size, maxSize, streamEndianness); + } + size_t getSerializedSize() const { + return SerializeAdapter::getSerializedSize(&subService); + } + ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + Endianness streamEndianness) { + return SerializeAdapter::deSerialize(&subService, buffer, size, streamEndianness); + } +private: + uint8_t subService; +}; + + + +#endif /* FRAMEWORK_TMTCPACKET_PACKETMATCHER_SUBSERVICEMATCHER_H_ */ diff --git a/src/fsfw/tmtcpacket/pus/CMakeLists.txt b/src/fsfw/tmtcpacket/pus/CMakeLists.txt new file mode 100644 index 00000000..32c80dd3 --- /dev/null +++ b/src/fsfw/tmtcpacket/pus/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(tm) +add_subdirectory(tc) diff --git a/src/fsfw/tmtcpacket/pus/PacketTimestampInterpreterIF.h b/src/fsfw/tmtcpacket/pus/PacketTimestampInterpreterIF.h new file mode 100644 index 00000000..b839223a --- /dev/null +++ b/src/fsfw/tmtcpacket/pus/PacketTimestampInterpreterIF.h @@ -0,0 +1,19 @@ +#ifndef FSFW_TMTCPACKET_PUS_PACKETTIMESTAMPINTERPRETERIF_H_ +#define FSFW_TMTCPACKET_PUS_PACKETTIMESTAMPINTERPRETERIF_H_ + +#include "fsfw/returnvalues/HasReturnvaluesIF.h" + +class TmPacketMinimal; + +class PacketTimestampInterpreterIF { +public: + virtual ~PacketTimestampInterpreterIF() {} + virtual ReturnValue_t getPacketTime(TmPacketMinimal* packet, + timeval* timestamp) const = 0; + virtual ReturnValue_t getPacketTimeRaw(TmPacketMinimal* packet, const uint8_t** timePtr, + uint32_t* size) const = 0; +}; + + + +#endif /* FSFW_TMTCPACKET_PUS_PACKETTIMESTAMPINTERPRETERIF_H_ */ diff --git a/src/fsfw/tmtcpacket/pus/definitions.h b/src/fsfw/tmtcpacket/pus/definitions.h new file mode 100644 index 00000000..d92ab312 --- /dev/null +++ b/src/fsfw/tmtcpacket/pus/definitions.h @@ -0,0 +1,16 @@ +#ifndef FSFW_SRC_FSFW_TMTCPACKET_PUS_TM_DEFINITIONS_H_ +#define FSFW_SRC_FSFW_TMTCPACKET_PUS_TM_DEFINITIONS_H_ + +#include + +namespace pus { + +//! Version numbers according to ECSS-E-ST-70-41C p.439 +enum PusVersion: uint8_t { + PUS_A_VERSION = 1, + PUS_C_VERSION = 2 +}; + +} + +#endif /* FSFW_SRC_FSFW_TMTCPACKET_PUS_TM_DEFINITIONS_H_ */ diff --git a/src/fsfw/tmtcpacket/pus/tc.h b/src/fsfw/tmtcpacket/pus/tc.h new file mode 100644 index 00000000..156e49fe --- /dev/null +++ b/src/fsfw/tmtcpacket/pus/tc.h @@ -0,0 +1,7 @@ +#ifndef FSFW_TMTCPACKET_PUS_TC_H_ +#define FSFW_TMTCPACKET_PUS_TC_H_ + +#include "tc/TcPacketStoredPus.h" +#include "tc/TcPacketPus.h" + +#endif /* FSFW_TMTCPACKET_PUS_TC_H_ */ diff --git a/src/fsfw/tmtcpacket/pus/tc/CMakeLists.txt b/src/fsfw/tmtcpacket/pus/tc/CMakeLists.txt new file mode 100644 index 00000000..723b7943 --- /dev/null +++ b/src/fsfw/tmtcpacket/pus/tc/CMakeLists.txt @@ -0,0 +1,6 @@ +target_sources(${LIB_FSFW_NAME} PRIVATE + TcPacketBase.cpp + TcPacketPus.cpp + TcPacketStoredBase.cpp + TcPacketStoredPus.cpp +) diff --git a/src/fsfw/tmtcpacket/pus/tc/TcPacketBase.cpp b/src/fsfw/tmtcpacket/pus/tc/TcPacketBase.cpp new file mode 100644 index 00000000..0c7a4183 --- /dev/null +++ b/src/fsfw/tmtcpacket/pus/tc/TcPacketBase.cpp @@ -0,0 +1,20 @@ +#include "fsfw/tmtcpacket/pus/tc/TcPacketBase.h" + +#include "fsfw/globalfunctions/CRC.h" +#include "fsfw/globalfunctions/arrayprinter.h" +#include "fsfw/serviceinterface/ServiceInterface.h" + +#include + +TcPacketBase::TcPacketBase(const uint8_t* setData): SpacePacketBase(setData) {} + +TcPacketBase::~TcPacketBase() {} + +void TcPacketBase::print() { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "TcPacketBase::print:" << std::endl; +#else + sif::printInfo("TcPacketBase::print:\n"); +#endif + arrayprinter::print(getWholeData(), getFullSize()); +} diff --git a/src/fsfw/tmtcpacket/pus/tc/TcPacketBase.h b/src/fsfw/tmtcpacket/pus/tc/TcPacketBase.h new file mode 100644 index 00000000..14356c8c --- /dev/null +++ b/src/fsfw/tmtcpacket/pus/tc/TcPacketBase.h @@ -0,0 +1,150 @@ +#ifndef TMTCPACKET_PUS_TCPACKETBASE_H_ +#define TMTCPACKET_PUS_TCPACKETBASE_H_ + +#include "fsfw/tmtcpacket/SpacePacketBase.h" +#include + +/** + * This class is the basic data handler for any ECSS PUS Telecommand packet. + * + * In addition to #SpacePacketBase, the class provides methods to handle + * the standardized entries of the PUS TC Packet Data Field Header. + * It does not contain the packet data itself but a pointer to the + * data must be set on instantiation. An invalid pointer may cause + * damage, as no getter method checks data validity. Anyway, a NULL + * check can be performed by making use of the getWholeData method. + * @ingroup tmtcpackets + */ +class TcPacketBase : public SpacePacketBase { + friend class TcPacketStoredBase; +public: + + enum AckField { + //! No acknowledgements are expected. + ACK_NONE = 0b0000, + //! Acknowledgements on acceptance are expected. + ACK_ACCEPTANCE = 0b0001, + //! Acknowledgements on start are expected. + ACK_START = 0b0010, + //! Acknowledgements on step are expected. + ACK_STEP = 0b0100, + //! Acknowledfgement on completion are expected. + ACK_COMPLETION = 0b1000 + }; + + static constexpr uint8_t ACK_ALL = ACK_ACCEPTANCE | ACK_START | ACK_STEP | + ACK_COMPLETION; + + /** + * This is the default constructor. + * It sets its internal data pointer to the address passed and also + * forwards the data pointer to the parent SpacePacketBase class. + * @param setData The position where the packet data lies. + */ + TcPacketBase( const uint8_t* setData ); + /** + * This is the empty default destructor. + */ + virtual ~TcPacketBase(); + + /** + * This command returns the CCSDS Secondary Header Flag. + * It shall always be zero for PUS Packets. This is the + * highest bit of the first byte of the Data Field Header. + * @return the CCSDS Secondary Header Flag + */ + virtual uint8_t getSecondaryHeaderFlag() const = 0; + /** + * This command returns the TC Packet PUS Version Number. + * The version number of ECSS PUS 2003 is 1. + * It consists of the second to fourth highest bits of the + * first byte. + * @return + */ + virtual uint8_t getPusVersionNumber() const = 0; + /** + * This is a getter for the packet's Ack field, which are the lowest four + * bits of the first byte of the Data Field Header. + * + * It is packed in a uint8_t variable. + * @return The packet's PUS Ack field. + */ + virtual uint8_t getAcknowledgeFlags() const = 0; + /** + * This is a getter for the packet's PUS Service ID, which is the second + * byte of the Data Field Header. + * @return The packet's PUS Service ID. + */ + virtual uint8_t getService() const = 0; + /** + * This is a getter for the packet's PUS Service Subtype, which is the + * third byte of the Data Field Header. + * @return The packet's PUS Service Subtype. + */ + virtual uint8_t getSubService() const = 0; + /** + * The source ID can be used to have an additional identifier, e.g. for different ground + * station. + * @return + */ + virtual uint16_t getSourceId() const = 0; + + /** + * This is a getter for a pointer to the packet's Application data. + * + * These are the bytes that follow after the Data Field Header. They form + * the packet's application data. + * @return A pointer to the PUS Application Data. + */ + virtual const uint8_t* getApplicationData() const = 0; + /** + * This method calculates the size of the PUS Application data field. + * + * It takes the information stored in the CCSDS Packet Data Length field + * and subtracts the Data Field Header size and the CRC size. + * @return The size of the PUS Application Data (without Error Control + * field) + */ + virtual uint16_t getApplicationDataSize() const = 0; + /** + * This getter returns the Error Control Field of the packet. + * + * The field is placed after any possible Application Data. If no + * Application Data is present there's still an Error Control field. It is + * supposed to be a 16bit-CRC. + * @return The PUS Error Control + */ + virtual uint16_t getErrorControl() const = 0; + /** + * With this method, the Error Control Field is updated to match the + * current content of the packet. + */ + virtual void setErrorControl() = 0; + + /** + * Calculate full packet length from application data length. + * @param appDataLen + * @return + */ + virtual size_t calculateFullPacketLength(size_t appDataLen) const = 0; + + /** + * This is a debugging helper method that prints the whole packet content + * to the screen. + */ + void print(); +protected: + + /** + * With this method, the packet data pointer can be redirected to another + * location. + * This call overwrites the parent's setData method to set both its + * @c tc_data pointer and the parent's @c data pointer. + * + * @param p_data A pointer to another PUS Telecommand Packet. + */ + void setData( const uint8_t* pData ) = 0; +}; + + +#endif /* TMTCPACKET_PUS_TCPACKETBASE_H_ */ diff --git a/src/fsfw/tmtcpacket/pus/tc/TcPacketPus.cpp b/src/fsfw/tmtcpacket/pus/tc/TcPacketPus.cpp new file mode 100644 index 00000000..2b97b0d2 --- /dev/null +++ b/src/fsfw/tmtcpacket/pus/tc/TcPacketPus.cpp @@ -0,0 +1,97 @@ +#include "TcPacketPus.h" +#include "fsfw/globalfunctions/CRC.h" + +#include + +TcPacketPus::TcPacketPus(const uint8_t *setData): TcPacketBase(setData) { + tcData = reinterpret_cast(const_cast(setData)); +} + +void TcPacketPus::initializeTcPacket(uint16_t apid, uint16_t sequenceCount, + uint8_t ack, uint8_t service, uint8_t subservice, pus::PusVersion pusVersion, + uint16_t sourceId) { + initSpacePacketHeader(true, true, apid, sequenceCount); + std::memset(&tcData->dataField, 0, sizeof(tcData->dataField)); + setPacketDataLength(sizeof(PUSTcDataFieldHeader) + CRC_SIZE - 1); + // Data Field Header. For PUS A, the first bit (CCSDS Secondary Header Flag) is zero + tcData->dataField.versionTypeAck = pusVersion << 4 | (ack & 0x0F); + tcData->dataField.serviceType = service; + tcData->dataField.serviceSubtype = subservice; +#if FSFW_USE_PUS_C_TELECOMMANDS == 1 + tcData->dataField.sourceIdH = (sourceId >> 8) | 0xff; + tcData->dataField.sourceIdL = sourceId & 0xff; +#else + tcData->dataField.sourceId = sourceId; +#endif +} + +uint8_t TcPacketPus::getService() const { + return tcData->dataField.serviceType; +} + +uint8_t TcPacketPus::getSubService() const { + return tcData->dataField.serviceSubtype; +} + +uint8_t TcPacketPus::getAcknowledgeFlags() const { + return tcData->dataField.versionTypeAck & 0b00001111; +} + +const uint8_t* TcPacketPus::getApplicationData() const { + return &tcData->appData; +} + +uint16_t TcPacketPus::getApplicationDataSize() const { + return getPacketDataLength() - sizeof(tcData->dataField) - CRC_SIZE + 1; +} + +uint16_t TcPacketPus::getErrorControl() const { + uint16_t size = getApplicationDataSize() + CRC_SIZE; + uint8_t* p_to_buffer = &tcData->appData; + return (p_to_buffer[size - 2] << 8) + p_to_buffer[size - 1]; +} + +void TcPacketPus::setErrorControl() { + uint32_t full_size = getFullSize(); + uint16_t crc = CRC::crc16ccitt(getWholeData(), full_size - CRC_SIZE); + uint32_t size = getApplicationDataSize(); + (&tcData->appData)[size] = (crc & 0XFF00) >> 8; // CRCH + (&tcData->appData)[size + 1] = (crc) & 0X00FF; // CRCL +} + +void TcPacketPus::setData(const uint8_t* pData) { + SpacePacketBase::setData(pData); + // This function is const-correct, but it was decided to keep the pointer non-const + // for convenience. Therefore, cast aways constness here and then cast to packet type. + tcData = reinterpret_cast(const_cast(pData)); +} + +uint8_t TcPacketPus::getSecondaryHeaderFlag() const { +#if FSFW_USE_PUS_C_TELECOMMANDS == 1 + // Does not exist for PUS C + return 0; +#else + return (tcData->dataField.versionTypeAck & 0b10000000) >> 7; +#endif +} + +uint8_t TcPacketPus::getPusVersionNumber() const { +#if FSFW_USE_PUS_C_TELECOMMANDS == 1 + return (tcData->dataField.versionTypeAck & 0b11110000) >> 4; +#else + return (tcData->dataField.versionTypeAck & 0b01110000) >> 4; +#endif +} + +uint16_t TcPacketPus::getSourceId() const { +#if FSFW_USE_PUS_C_TELECOMMANDS == 1 + return (tcData->dataField.sourceIdH << 8) | tcData->dataField.sourceIdL; +#else + return tcData->dataField.sourceId; +#endif +} + +size_t TcPacketPus::calculateFullPacketLength(size_t appDataLen) const { + return sizeof(CCSDSPrimaryHeader) + sizeof(PUSTcDataFieldHeader) + + appDataLen + TcPacketBase::CRC_SIZE; +} diff --git a/src/fsfw/tmtcpacket/pus/tc/TcPacketPus.h b/src/fsfw/tmtcpacket/pus/tc/TcPacketPus.h new file mode 100644 index 00000000..1bacc3a7 --- /dev/null +++ b/src/fsfw/tmtcpacket/pus/tc/TcPacketPus.h @@ -0,0 +1,92 @@ +#ifndef FSFW_TMTCPACKET_PUS_TCPACKETPUSA_H_ +#define FSFW_TMTCPACKET_PUS_TCPACKETPUSA_H_ + +#include "fsfw/FSFW.h" +#include "../definitions.h" +#include "fsfw/tmtcpacket/ccsds_header.h" +#include "TcPacketBase.h" + +#include + +/** + * This struct defines a byte-wise structured PUS TC A Data Field Header. + * Any optional fields in the header must be added or removed here. + * Currently, the Source Id field is present with one byte. + * @ingroup tmtcpackets + */ +struct PUSTcDataFieldHeader { + uint8_t versionTypeAck; + uint8_t serviceType; + uint8_t serviceSubtype; +#if FSFW_USE_PUS_C_TELECOMMANDS == 1 + uint8_t sourceIdH; + uint8_t sourceIdL; +#else + uint8_t sourceId; +#endif +}; + +/** + * This struct defines the data structure of a PUS Telecommand A packet when + * accessed via a pointer. + * @ingroup tmtcpackets + */ +struct TcPacketPointer { + CCSDSPrimaryHeader primary; + PUSTcDataFieldHeader dataField; + uint8_t appData; +}; + + +class TcPacketPus: public TcPacketBase { +public: + static const uint16_t TC_PACKET_MIN_SIZE = (sizeof(CCSDSPrimaryHeader) + + sizeof(PUSTcDataFieldHeader) + 2); + + /** + * Initialize a PUS A telecommand packet which already exists. You can also + * create an empty (invalid) object by passing nullptr as the data pointer + * @param setData + */ + TcPacketPus(const uint8_t* setData); + + // Base class overrides + uint8_t getSecondaryHeaderFlag() const override; + uint8_t getPusVersionNumber() const override; + uint8_t getAcknowledgeFlags() const override; + uint8_t getService() const override; + uint8_t getSubService() const override; + uint16_t getSourceId() const override; + const uint8_t* getApplicationData() const override; + uint16_t getApplicationDataSize() const override; + uint16_t getErrorControl() const override; + void setErrorControl() override; + size_t calculateFullPacketLength(size_t appDataLen) const override; + +protected: + + void setData(const uint8_t* pData) override; + + /** + * Initializes the Tc Packet header. + * @param apid APID used. + * @param sequenceCount Sequence Count in the primary header. + * @param ack Which acknowledeges are expected from the receiver. + * @param service PUS Service + * @param subservice PUS Subservice + */ + void initializeTcPacket(uint16_t apid, uint16_t sequenceCount, uint8_t ack, + uint8_t service, uint8_t subservice, pus::PusVersion pusVersion, + uint16_t sourceId = 0); + + /** + * A pointer to a structure which defines the data structure of + * the packet's data. + * + * To be hardware-safe, all elements are of byte size. + */ + TcPacketPointer* tcData = nullptr; +}; + + +#endif /* FSFW_TMTCPACKET_PUS_TCPACKETPUSA_H_ */ diff --git a/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredBase.cpp b/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredBase.cpp new file mode 100644 index 00000000..98ce1725 --- /dev/null +++ b/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredBase.cpp @@ -0,0 +1,72 @@ +#include "fsfw/tmtcpacket/pus/tc/TcPacketStoredBase.h" + +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/objectmanager/frameworkObjects.h" + +#include + +StorageManagerIF* TcPacketStoredBase::store = nullptr; + +TcPacketStoredBase::TcPacketStoredBase() { + this->storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; + this->checkAndSetStore(); + +} + +TcPacketStoredBase::~TcPacketStoredBase() { +} + +ReturnValue_t TcPacketStoredBase::getData(const uint8_t ** dataPtr, + size_t* dataSize) { + auto result = this->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; +#else + sif::printWarning("TcPacketStoredBase: Could not get data!\n"); +#endif + } + return result; +} + + + +bool TcPacketStoredBase::checkAndSetStore() { + if (this->store == nullptr) { + this->store = ObjectManager::instance()->get(objects::TC_STORE); + if (this->store == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "TcPacketStoredBase::TcPacketStoredBase: TC Store not found!" + << std::endl; +#endif + return false; + } + } + return true; +} + +void TcPacketStoredBase::setStoreAddress(store_address_t setAddress) { + this->storeAddress = setAddress; + const uint8_t* tempData = nullptr; + size_t tempSize; + ReturnValue_t status = StorageManagerIF::RETURN_FAILED; + if (this->checkAndSetStore()) { + status = this->store->getData(this->storeAddress, &tempData, &tempSize); + } + TcPacketBase* tcPacketBase = this->getPacketBase(); + if(tcPacketBase == nullptr) { + return; + } + if (status == StorageManagerIF::RETURN_OK) { + tcPacketBase->setData(tempData); + } + else { + tcPacketBase->setData(nullptr); + this->storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; + } +} + +store_address_t TcPacketStoredBase::getStoreAddress() { + return this->storeAddress; +} diff --git a/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredBase.h b/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredBase.h new file mode 100644 index 00000000..1e1681f6 --- /dev/null +++ b/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredBase.h @@ -0,0 +1,90 @@ +#ifndef TMTCPACKET_PUS_TCPACKETSTORED_H_ +#define TMTCPACKET_PUS_TCPACKETSTORED_H_ + +#include "TcPacketStoredIF.h" +#include "../../../storagemanager/StorageManagerIF.h" + +/** + * This class generates a ECSS PUS Telecommand packet within a given + * intermediate storage. + * As most packets are passed between tasks with the help of a storage + * anyway, it seems logical to create a Packet-In-Storage access class + * which saves the user almost all storage handling operation. + * Packets can both be newly created with the class and be "linked" to + * packets in a store with the help of a storeAddress. + * @ingroup tmtcpackets + */ +class TcPacketStoredBase: public TcPacketStoredIF { +public: + /** + * This is a default constructor which does not set the data pointer to initialize + * with an empty cached store address + */ + TcPacketStoredBase(); + /** + * Constructor to set to an existing store address. + * @param setAddress + */ + TcPacketStoredBase(store_address_t setAddress); + /** + * Another constructor to create a TcPacket from a raw packet stream. + * Takes the data and adds it unchecked to the TcStore. + * @param data Pointer to the complete TC Space Packet. + * @param Size size of the packet. + */ + TcPacketStoredBase(const uint8_t* data, uint32_t size); + + virtual~ TcPacketStoredBase(); + + /** + * Getter function for the raw data. + * @param dataPtr [out] Pointer to the data pointer to set + * @param dataSize [out] Address of size to set. + * @return -@c RETURN_OK if data was retrieved successfully. + */ + ReturnValue_t getData(const uint8_t ** dataPtr, size_t* dataSize) override; + + void setStoreAddress(store_address_t setAddress) override; + store_address_t getStoreAddress() override; + + /** + * With this call, the packet is deleted. + * It removes itself from the store and sets its data pointer to NULL. + * @return returncode from deleting the data. + */ + virtual ReturnValue_t deletePacket() = 0; + + /** + * This method performs a size check. + * It reads the stored size and compares it with the size entered in the + * packet header. This class is the optimal place for such a check as it + * has access to both the header data and the store. + * @return true if size is correct, false if packet is not registered in + * store or size is incorrect. + */ + virtual bool isSizeCorrect() = 0; + +protected: + /** + * This is a pointer to the store all instances of the class use. + * If the store is not yet set (i.e. @c store is NULL), every constructor + * call tries to set it and throws an error message in case of failures. + * The default store is objects::TC_STORE. + */ + static StorageManagerIF* store; + /** + * The address where the packet data of the object instance is stored. + */ + store_address_t storeAddress; + /** + * A helper method to check if a store is assigned to the class. + * If not, the method tries to retrieve the store from the global + * ObjectManager. + * @return @li @c true if the store is linked or could be created. + * @li @c false otherwise. + */ + bool checkAndSetStore(); +}; + + +#endif /* TMTCPACKET_PUS_TcPacketStoredBase_H_ */ diff --git a/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredIF.h b/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredIF.h new file mode 100644 index 00000000..3d356725 --- /dev/null +++ b/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredIF.h @@ -0,0 +1,38 @@ +#ifndef FSFW_TMTCPACKET_PUS_TCPACKETSTOREDIF_H_ +#define FSFW_TMTCPACKET_PUS_TCPACKETSTOREDIF_H_ + +#include "TcPacketBase.h" +#include "../../../storagemanager/storeAddress.h" +#include "../../../returnvalues/HasReturnvaluesIF.h" + +class TcPacketStoredIF { +public: + virtual~TcPacketStoredIF() {}; + + /** + * With this call, the stored packet can be set to another packet in a store. This is useful + * if the packet is a class member and used for more than one packet. + * @param setAddress The new packet id to link to. + */ + virtual void setStoreAddress(store_address_t setAddress) = 0; + + virtual store_address_t getStoreAddress() = 0; + + /** + * Getter function for the raw data. + * @param dataPtr [out] Pointer to the data pointer to set + * @param dataSize [out] Address of size to set. + * @return -@c RETURN_OK if data was retrieved successfully. + */ + virtual ReturnValue_t getData(const uint8_t ** dataPtr, size_t* dataSize) = 0; + + /** + * Get packet base pointer which can be used to get access to PUS packet fields + * @return + */ + virtual TcPacketBase* getPacketBase() = 0; +}; + + + +#endif /* FSFW_TMTCPACKET_PUS_TCPACKETSTOREDIF_H_ */ diff --git a/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredPus.cpp b/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredPus.cpp new file mode 100644 index 00000000..7f8f4ac8 --- /dev/null +++ b/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredPus.cpp @@ -0,0 +1,84 @@ +#include "fsfw/tmtcpacket/pus/tc/TcPacketStoredPus.h" + +#include "fsfw/serviceinterface/ServiceInterface.h" + +#include + +TcPacketStoredPus::TcPacketStoredPus(uint16_t apid, uint8_t service, + uint8_t subservice, uint8_t sequenceCount, const uint8_t* data, + size_t size, uint8_t ack) : + TcPacketPus(nullptr) { + this->storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; + if (not this->checkAndSetStore()) { + return; + } + uint8_t* pData = nullptr; + ReturnValue_t returnValue = 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 + return; + } + this->setData(pData); +#if FSFW_USE_PUS_C_TELECOMMANDS == 1 + pus::PusVersion pusVersion = pus::PusVersion::PUS_C_VERSION; +#else + pus::PusVersion pusVersion = pus::PusVersion::PUS_A_VERSION; +#endif + initializeTcPacket(apid, sequenceCount, ack, service, subservice, pusVersion); + std::memcpy(&tcData->appData, data, size); + this->setPacketDataLength( + size + sizeof(PUSTcDataFieldHeader) + CRC_SIZE - 1); + this->setErrorControl(); +} + +TcPacketStoredPus::TcPacketStoredPus(): TcPacketStoredBase(), TcPacketPus(nullptr) { +} + +TcPacketStoredPus::TcPacketStoredPus(store_address_t setAddress): TcPacketPus(nullptr) { + TcPacketStoredBase::setStoreAddress(setAddress); +} + +TcPacketStoredPus::TcPacketStoredPus(const uint8_t* data, size_t size): TcPacketPus(data) { + if (this->getFullSize() != size) { + return; + } + if (this->checkAndSetStore()) { + ReturnValue_t status = store->addData(&storeAddress, data, size); + if (status != HasReturnvaluesIF::RETURN_OK) { + this->setData(nullptr); + } + const uint8_t* storePtr = nullptr; + // Repoint base data pointer to the data in the store. + store->getData(storeAddress, &storePtr, &size); + this->setData(storePtr); + } +} + +ReturnValue_t TcPacketStoredPus::deletePacket() { + ReturnValue_t result = this->store->deleteData(this->storeAddress); + this->storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; + this->setData(nullptr); + return result; +} + +TcPacketBase* 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); + if (status == StorageManagerIF::RETURN_OK) { + if (this->getFullSize() == temp_size) { + return true; + } + } + return false; +} diff --git a/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredPus.h b/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredPus.h new file mode 100644 index 00000000..8b318733 --- /dev/null +++ b/src/fsfw/tmtcpacket/pus/tc/TcPacketStoredPus.h @@ -0,0 +1,53 @@ +#ifndef FSFW_TMTCPACKET_PUS_TCPACKETSTOREDPUSA_H_ +#define FSFW_TMTCPACKET_PUS_TCPACKETSTOREDPUSA_H_ + +#include "TcPacketStoredBase.h" +#include "TcPacketPus.h" + +class TcPacketStoredPus: + public TcPacketStoredBase, + public TcPacketPus { +public: + /** + * With this constructor, new space is allocated in the packet store and + * a new PUS Telecommand Packet is created there. + * Packet Application Data passed in data is copied into the packet. + * @param apid Sets the packet's APID field. + * @param service Sets the packet's Service ID field. + * This specifies the destination service. + * @param subservice Sets the packet's Service Subtype field. + * This specifies the destination sub-service. + * @param sequence_count Sets the packet's Source Sequence Count field. + * @param data The data to be copied to the Application Data Field. + * @param size The amount of data to be copied. + * @param ack Set's the packet's Ack field, which specifies + * number of verification packets returned + * for this command. + */ + TcPacketStoredPus(uint16_t apid, uint8_t service, uint8_t subservice, + uint8_t sequence_count = 0, const uint8_t* data = nullptr, + size_t size = 0, uint8_t ack = TcPacketBase::ACK_ALL); + /** + * Create stored packet with existing data. + * @param data + * @param size + */ + TcPacketStoredPus(const uint8_t* data, size_t size); + /** + * Create stored packet from existing packet in store + * @param setAddress + */ + TcPacketStoredPus(store_address_t setAddress); + TcPacketStoredPus(); + + ReturnValue_t deletePacket() override; + TcPacketBase* getPacketBase() override; + +private: + + bool isSizeCorrect() override; +}; + + + +#endif /* FSFW_TMTCPACKET_PUS_TCPACKETSTOREDPUSA_H_ */ diff --git a/src/fsfw/tmtcpacket/pus/tm.h b/src/fsfw/tmtcpacket/pus/tm.h new file mode 100644 index 00000000..afbe8251 --- /dev/null +++ b/src/fsfw/tmtcpacket/pus/tm.h @@ -0,0 +1,16 @@ +#ifndef FSFW_TMTCPACKET_PUS_TM_H_ +#define FSFW_TMTCPACKET_PUS_TM_H_ + +#include "fsfw/FSFW.h" + +#if FSFW_USE_PUS_C_TELEMETRY == 1 +#include "tm/TmPacketPusC.h" +#include "tm/TmPacketStoredPusC.h" +#else +#include "tm/TmPacketPusA.h" +#include "tm/TmPacketStoredPusA.h" +#endif + +#include "tm/TmPacketMinimal.h" + +#endif /* FSFW_TMTCPACKET_PUS_TM_H_ */ diff --git a/src/fsfw/tmtcpacket/pus/tm/CMakeLists.txt b/src/fsfw/tmtcpacket/pus/tm/CMakeLists.txt new file mode 100644 index 00000000..ace87820 --- /dev/null +++ b/src/fsfw/tmtcpacket/pus/tm/CMakeLists.txt @@ -0,0 +1,9 @@ +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/tmtcpacket/pus/tm/TmPacketBase.cpp b/src/fsfw/tmtcpacket/pus/tm/TmPacketBase.cpp new file mode 100644 index 00000000..d448fe5e --- /dev/null +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketBase.cpp @@ -0,0 +1,67 @@ +#include "fsfw/tmtcpacket/pus/tm/TmPacketBase.h" + +#include "fsfw/globalfunctions/CRC.h" +#include "fsfw/globalfunctions/arrayprinter.h" +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/timemanager/CCSDSTime.h" + +#include + +TimeStamperIF* TmPacketBase::timeStamper = nullptr; +object_id_t TmPacketBase::timeStamperId = objects::NO_OBJECT; + +TmPacketBase::TmPacketBase(uint8_t* setData): SpacePacketBase(setData) {} + +TmPacketBase::~TmPacketBase() { + //Nothing to do. +} + + +uint16_t TmPacketBase::getSourceDataSize() { + return getPacketDataLength() - getDataFieldSize() - CRC_SIZE + 1; +} + +uint16_t TmPacketBase::getErrorControl() { + uint32_t size = getSourceDataSize() + CRC_SIZE; + uint8_t* p_to_buffer = getSourceData(); + return (p_to_buffer[size - 2] << 8) + p_to_buffer[size - 1]; +} + +void TmPacketBase::setErrorControl() { + uint32_t full_size = getFullSize(); + uint16_t crc = CRC::crc16ccitt(getWholeData(), full_size - CRC_SIZE); + uint32_t size = getSourceDataSize(); + getSourceData()[size] = (crc & 0XFF00) >> 8; // CRCH + getSourceData()[size + 1] = (crc) & 0X00FF; // CRCL +} + +ReturnValue_t TmPacketBase::getPacketTime(timeval* timestamp) const { + size_t tempSize = 0; + return CCSDSTime::convertFromCcsds(timestamp, getPacketTimeRaw(), + &tempSize, getTimestampSize()); +} + +bool TmPacketBase::checkAndSetStamper() { + if (timeStamper == NULL) { + timeStamper = ObjectManager::instance()->get(timeStamperId); + if (timeStamper == NULL) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "TmPacketBase::checkAndSetStamper: Stamper not found!" << std::endl; +#else + sif::printWarning("TmPacketBase::checkAndSetStamper: Stamper not found!\n"); +#endif + return false; + } + } + return true; +} + +void TmPacketBase::print() { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "TmPacketBase::print:" << std::endl; +#else + sif::printInfo("TmPacketBase::print:\n"); +#endif + arrayprinter::print(getWholeData(), getFullSize()); +} diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketBase.h b/src/fsfw/tmtcpacket/pus/tm/TmPacketBase.h new file mode 100644 index 00000000..31bfe3c8 --- /dev/null +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketBase.h @@ -0,0 +1,137 @@ +#ifndef TMTCPACKET_PUS_TMPACKETBASE_H_ +#define TMTCPACKET_PUS_TMPACKETBASE_H_ + +#include "fsfw/tmtcpacket/SpacePacketBase.h" +#include "fsfw/timemanager/TimeStamperIF.h" +#include "fsfw/timemanager/Clock.h" +#include "fsfw/objectmanager/SystemObjectIF.h" + +namespace Factory { + +void setStaticFrameworkObjectIds(); + +} + + +/** + * This class is the basic data handler for any ECSS PUS Telemetry packet. + * + * In addition to #SpacePacketBase, the class provides methods to handle + * the standardized entries of the PUS TM Packet Data Field Header. + * It does not contain the packet data itself but a pointer to the + * data must be set on instantiation. An invalid pointer may cause + * damage, as no getter method checks data validity. Anyway, a NULL + * check can be performed by making use of the getWholeData method. + * @ingroup tmtcpackets + */ +class TmPacketBase : public SpacePacketBase { + friend void (Factory::setStaticFrameworkObjectIds)(); +public: + + //! Maximum size of a TM Packet in this mission. + //! TODO: Make this dependant on a config variable. + static const uint32_t MISSION_TM_PACKET_MAX_SIZE = 2048; + + /** + * This is the default constructor. + * It sets its internal data pointer to the address passed and also + * forwards the data pointer to the parent SpacePacketBase class. + * @param set_address The position where the packet data lies. + */ + TmPacketBase( uint8_t* setData ); + /** + * This is the empty default destructor. + */ + virtual ~TmPacketBase(); + + /** + * This is a getter for the packet's PUS Service ID, which is the second + * byte of the Data Field Header. + * @return The packet's PUS Service ID. + */ + virtual uint8_t getService() = 0; + /** + * This is a getter for the packet's PUS Service Subtype, which is the + * third byte of the Data Field Header. + * @return The packet's PUS Service Subtype. + */ + virtual uint8_t getSubService() = 0; + /** + * This is a getter for a pointer to the packet's Source data. + * + * These are the bytes that follow after the Data Field Header. They form + * the packet's source data. + * @return A pointer to the PUS Source Data. + */ + virtual uint8_t* getSourceData() = 0; + /** + * This method calculates the size of the PUS Source data field. + * + * It takes the information stored in the CCSDS Packet Data Length field + * and subtracts the Data Field Header size and the CRC size. + * @return The size of the PUS Source Data (without Error Control field) + */ + virtual uint16_t getSourceDataSize() = 0; + + /** + * Get size of data field which can differ based on implementation + * @return + */ + virtual uint16_t getDataFieldSize() = 0; + + virtual size_t getPacketMinimumSize() const = 0; + + /** + * Interprets the "time"-field in the secondary header and returns it in + * timeval format. + * @return Converted timestamp of packet. + */ + virtual ReturnValue_t getPacketTime(timeval* timestamp) const; + /** + * Returns a raw pointer to the beginning of the time field. + * @return Raw pointer to time field. + */ + virtual uint8_t* getPacketTimeRaw() const = 0; + + virtual size_t getTimestampSize() const = 0; + + /** + * This is a debugging helper method that prints the whole packet content + * to the screen. + */ + void print(); + /** + * With this method, the Error Control Field is updated to match the + * current content of the packet. This method is not protected because + * a recalculation by the user might be necessary when manipulating fields + * like the sequence count. + */ + void setErrorControl(); + /** + * This getter returns the Error Control Field of the packet. + * + * The field is placed after any possible Source Data. If no + * Source Data is present there's still an Error Control field. It is + * supposed to be a 16bit-CRC. + * @return The PUS Error Control + */ + uint16_t getErrorControl(); + +protected: + /** + * The timeStamper is responsible for adding a timestamp to the packet. + * It is initialized lazy. + */ + static TimeStamperIF* timeStamper; + //! The ID to use when looking for a time stamper. + static object_id_t timeStamperId; + + /** + * Checks if a time stamper is available and tries to set it if not. + * @return Returns false if setting failed. + */ + bool checkAndSetStamper(); +}; + + +#endif /* TMTCPACKET_PUS_TMPACKETBASE_H_ */ diff --git a/tmtcpacket/pus/TmPacketMinimal.cpp b/src/fsfw/tmtcpacket/pus/tm/TmPacketMinimal.cpp similarity index 88% rename from tmtcpacket/pus/TmPacketMinimal.cpp rename to src/fsfw/tmtcpacket/pus/tm/TmPacketMinimal.cpp index c79582a8..53308359 100644 --- a/tmtcpacket/pus/TmPacketMinimal.cpp +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketMinimal.cpp @@ -1,7 +1,8 @@ -#include "TmPacketMinimal.h" -#include -#include -#include "PacketTimestampInterpreterIF.h" +#include "fsfw/tmtcpacket/pus/tm/TmPacketMinimal.h" +#include "fsfw/tmtcpacket/pus/PacketTimestampInterpreterIF.h" + +#include +#include TmPacketMinimal::TmPacketMinimal(const uint8_t* set_data) : SpacePacketBase( set_data ) { this->tm_data = (TmPacketMinimalPointer*)set_data; diff --git a/tmtcpacket/pus/TmPacketMinimal.h b/src/fsfw/tmtcpacket/pus/tm/TmPacketMinimal.h similarity index 96% rename from tmtcpacket/pus/TmPacketMinimal.h rename to src/fsfw/tmtcpacket/pus/tm/TmPacketMinimal.h index 0d8cd75b..ad0eb859 100644 --- a/tmtcpacket/pus/TmPacketMinimal.h +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketMinimal.h @@ -2,8 +2,8 @@ #define FRAMEWORK_TMTCPACKET_PUS_TMPACKETMINIMAL_H_ -#include "../../tmtcpacket/SpacePacketBase.h" -#include "../../returnvalues/HasReturnvaluesIF.h" +#include "../../SpacePacketBase.h" +#include "../../../returnvalues/HasReturnvaluesIF.h" struct timeval; class PacketTimestampInterpreterIF; diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketPusA.cpp b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusA.cpp new file mode 100644 index 00000000..ccf5a8ac --- /dev/null +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusA.cpp @@ -0,0 +1,83 @@ +#include "../definitions.h" +#include "TmPacketPusA.h" +#include "TmPacketBase.h" + +#include "fsfw/globalfunctions/CRC.h" +#include "fsfw/globalfunctions/arrayprinter.h" +#include "fsfw/objectmanager/ObjectManagerIF.h" +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/timemanager/CCSDSTime.h" + +#include + + +TmPacketPusA::TmPacketPusA(uint8_t* setData) : TmPacketBase(setData) { + tmData = reinterpret_cast(setData); +} + +TmPacketPusA::~TmPacketPusA() { + //Nothing to do. +} + +uint8_t TmPacketPusA::getService() { + return tmData->data_field.service_type; +} + +uint8_t TmPacketPusA::getSubService() { + return tmData->data_field.service_subtype; +} + +uint8_t* TmPacketPusA::getSourceData() { + return &tmData->data; +} + +uint16_t TmPacketPusA::getSourceDataSize() { + return getPacketDataLength() - sizeof(tmData->data_field) + - CRC_SIZE + 1; +} + +void TmPacketPusA::setData(const uint8_t* p_Data) { + SpacePacketBase::setData(p_Data); + tmData = (TmPacketPointerPusA*) p_Data; +} + + +size_t TmPacketPusA::getPacketMinimumSize() const { + return TM_PACKET_MIN_SIZE; +} + +uint16_t TmPacketPusA::getDataFieldSize() { + return sizeof(PUSTmDataFieldHeaderPusA); +} + +uint8_t* TmPacketPusA::getPacketTimeRaw() const { + return tmData->data_field.time; + +} + +void TmPacketPusA::initializeTmPacket(uint16_t apid, uint8_t service, + uint8_t subservice, uint8_t packetSubcounter) { + //Set primary header: + initSpacePacketHeader(false, true, apid); + //Set data Field Header: + //First, set to zero. + memset(&tmData->data_field, 0, sizeof(tmData->data_field)); + + tmData->data_field.version_type_ack = pus::PusVersion::PUS_A_VERSION << 4; + tmData->data_field.service_type = service; + tmData->data_field.service_subtype = subservice; + tmData->data_field.subcounter = packetSubcounter; + //Timestamp packet + if (TmPacketBase::checkAndSetStamper()) { + timeStamper->addTimeStamp(tmData->data_field.time, + sizeof(tmData->data_field.time)); + } +} + +void TmPacketPusA::setSourceDataSize(uint16_t size) { + setPacketDataLength(size + sizeof(PUSTmDataFieldHeaderPusA) + CRC_SIZE - 1); +} + +size_t TmPacketPusA::getTimestampSize() const { + return sizeof(tmData->data_field.time); +} diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketPusA.h b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusA.h new file mode 100644 index 00000000..3856c779 --- /dev/null +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusA.h @@ -0,0 +1,128 @@ +#ifndef FSFW_TMTCPACKET_PUS_TMPACKETPUSA_H_ +#define FSFW_TMTCPACKET_PUS_TMPACKETPUSA_H_ + +#include "TmPacketBase.h" +#include "fsfw/tmtcpacket/SpacePacketBase.h" +#include "fsfw/timemanager/TimeStamperIF.h" +#include "fsfw/timemanager/Clock.h" +#include "fsfw/objectmanager/SystemObjectIF.h" + +namespace Factory{ +void setStaticFrameworkObjectIds(); +} + +/** + * This struct defines a byte-wise structured PUS TM Data Field Header. + * Any optional fields in the header must be added or removed here. + * Currently, no Destination field is present, but an eigth-byte representation + * for a time tag. + * @ingroup tmtcpackets + */ +struct PUSTmDataFieldHeaderPusA { + uint8_t version_type_ack; + uint8_t service_type; + uint8_t service_subtype; + uint8_t subcounter; + // uint8_t destination; + uint8_t time[TimeStamperIF::MISSION_TIMESTAMP_SIZE]; +}; + +/** + * This struct defines the data structure of a PUS Telecommand Packet when + * accessed via a pointer. + * @ingroup tmtcpackets + */ +struct TmPacketPointerPusA { + CCSDSPrimaryHeader primary; + PUSTmDataFieldHeaderPusA data_field; + uint8_t data; +}; + +/** + * PUS A packet implementation + * @ingroup tmtcpackets + */ +class TmPacketPusA: public TmPacketBase { + friend void (Factory::setStaticFrameworkObjectIds)(); +public: + /** + * This constant defines the minimum size of a valid PUS Telemetry Packet. + */ + static const uint32_t TM_PACKET_MIN_SIZE = (sizeof(CCSDSPrimaryHeader) + + sizeof(PUSTmDataFieldHeaderPusA) + 2); + //! Maximum size of a TM Packet in this mission. + static const uint32_t MISSION_TM_PACKET_MAX_SIZE = fsfwconfig::FSFW_MAX_TM_PACKET_SIZE; + + /** + * This is the default constructor. + * It sets its internal data pointer to the address passed and also + * forwards the data pointer to the parent SpacePacketBase class. + * @param set_address The position where the packet data lies. + */ + TmPacketPusA( uint8_t* setData ); + /** + * This is the empty default destructor. + */ + virtual ~TmPacketPusA(); + + /* TmPacketBase implementations */ + uint8_t getService() override; + uint8_t getSubService() override; + uint8_t* getSourceData() override; + uint16_t getSourceDataSize() override; + uint16_t getDataFieldSize() override; + + /** + * Returns a raw pointer to the beginning of the time field. + * @return Raw pointer to time field. + */ + uint8_t* getPacketTimeRaw() const override; + size_t getTimestampSize() const override; + + size_t getPacketMinimumSize() const override; + +protected: + /** + * A pointer to a structure which defines the data structure of + * the packet's data. + * + * To be hardware-safe, all elements are of byte size. + */ + TmPacketPointerPusA* tmData; + + /** + * Initializes the Tm Packet header. + * Does set the timestamp (to now), but not the error control field. + * @param apid APID used. + * @param service PUS Service + * @param subservice PUS Subservice + * @param packetSubcounter Additional subcounter used. + */ + void initializeTmPacket(uint16_t apid, uint8_t service, uint8_t subservice, + uint8_t packetSubcounter); + + /** + * With this method, the packet data pointer can be redirected to another + * location. + * + * This call overwrites the parent's setData method to set both its + * @c tc_data pointer and the parent's @c data pointer. + * + * @param p_data A pointer to another PUS Telemetry Packet. + */ + void setData( const uint8_t* pData ); + + /** + * In case data was filled manually (almost never the case). + * @param size Size of source data (without CRC and data filed header!). + */ + void setSourceDataSize(uint16_t size); + + /** + * Checks if a time stamper is available and tries to set it if not. + * @return Returns false if setting failed. + */ + bool checkAndSetStamper(); +}; + +#endif /* FSFW_TMTCPACKET_PUS_TMPACKETPUSA_H_ */ diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.cpp b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.cpp new file mode 100644 index 00000000..003d565e --- /dev/null +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.cpp @@ -0,0 +1,93 @@ +#include "../definitions.h" +#include "TmPacketPusC.h" +#include "TmPacketBase.h" + +#include "fsfw/globalfunctions/CRC.h" +#include "fsfw/globalfunctions/arrayprinter.h" +#include "fsfw/objectmanager/ObjectManagerIF.h" +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/timemanager/CCSDSTime.h" + +#include + + +TmPacketPusC::TmPacketPusC(uint8_t* setData) : TmPacketBase(setData) { + tmData = reinterpret_cast(setData); +} + +TmPacketPusC::~TmPacketPusC() { + //Nothing to do. +} + +uint8_t TmPacketPusC::getService() { + return tmData->dataField.serviceType; +} + +uint8_t TmPacketPusC::getSubService() { + return tmData->dataField.serviceSubtype; +} + +uint8_t* TmPacketPusC::getSourceData() { + return &tmData->data; +} + +uint16_t TmPacketPusC::getSourceDataSize() { + return getPacketDataLength() - sizeof(tmData->dataField) - CRC_SIZE + 1; +} + +void TmPacketPusC::setData(const uint8_t* p_Data) { + SpacePacketBase::setData(p_Data); + tmData = (TmPacketPointerPusC*) p_Data; +} + + +size_t TmPacketPusC::getPacketMinimumSize() const { + return TM_PACKET_MIN_SIZE; +} + +uint16_t TmPacketPusC::getDataFieldSize() { + return sizeof(PUSTmDataFieldHeaderPusC); +} + +uint8_t* TmPacketPusC::getPacketTimeRaw() const{ + return tmData->dataField.time; + +} + +ReturnValue_t TmPacketPusC::initializeTmPacket(uint16_t apid, uint8_t service, + uint8_t subservice, uint16_t packetSubcounter, uint16_t destinationId, + uint8_t timeRefField) { + //Set primary header: + ReturnValue_t result = initSpacePacketHeader(false, true, apid); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + //Set data Field Header: + //First, set to zero. + memset(&tmData->dataField, 0, sizeof(tmData->dataField)); + + /* Only account for last 4 bytes for time reference field */ + timeRefField &= 0b1111; + tmData->dataField.versionTimeReferenceField = + (pus::PusVersion::PUS_C_VERSION << 4) | timeRefField; + tmData->dataField.serviceType = service; + tmData->dataField.serviceSubtype = subservice; + tmData->dataField.subcounterMsb = packetSubcounter << 8 & 0xff; + tmData->dataField.subcounterLsb = packetSubcounter & 0xff; + tmData->dataField.destinationIdMsb = destinationId << 8 & 0xff; + tmData->dataField.destinationIdLsb = destinationId & 0xff; + //Timestamp packet + if (TmPacketBase::checkAndSetStamper()) { + timeStamper->addTimeStamp(tmData->dataField.time, + sizeof(tmData->dataField.time)); + } + return HasReturnvaluesIF::RETURN_OK; +} + +void TmPacketPusC::setSourceDataSize(uint16_t size) { + setPacketDataLength(size + sizeof(PUSTmDataFieldHeaderPusC) + CRC_SIZE - 1); +} + +size_t TmPacketPusC::getTimestampSize() const { + return sizeof(tmData->dataField.time); +} diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.h b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.h new file mode 100644 index 00000000..3a9be132 --- /dev/null +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketPusC.h @@ -0,0 +1,125 @@ +#ifndef FSFW_TMTCPACKET_PUS_TMPACKETPUSC_H_ +#define FSFW_TMTCPACKET_PUS_TMPACKETPUSC_H_ + +#include "TmPacketBase.h" +#include "fsfw/tmtcpacket/SpacePacketBase.h" +#include "fsfw/timemanager/TimeStamperIF.h" +#include "fsfw/timemanager/Clock.h" +#include "fsfw/objectmanager/SystemObjectIF.h" + +namespace Factory{ +void setStaticFrameworkObjectIds(); +} + +/** + * This struct defines a byte-wise structured PUS TM Data Field Header. + * Any optional fields in the header must be added or removed here. + * Currently, no Destination field is present, but an eigth-byte representation + * for a time tag. + * @ingroup tmtcpackets + */ +struct PUSTmDataFieldHeaderPusC { + uint8_t versionTimeReferenceField; + uint8_t serviceType; + uint8_t serviceSubtype; + uint8_t subcounterMsb; + uint8_t subcounterLsb; + uint8_t destinationIdMsb; + uint8_t destinationIdLsb; + uint8_t time[TimeStamperIF::MISSION_TIMESTAMP_SIZE]; +}; + +/** + * This struct defines the data structure of a PUS Telecommand Packet when + * accessed via a pointer. + * @ingroup tmtcpackets + */ +struct TmPacketPointerPusC { + CCSDSPrimaryHeader primary; + PUSTmDataFieldHeaderPusC dataField; + uint8_t data; +}; + +/** + * PUS A packet implementation + * @ingroup tmtcpackets + */ +class TmPacketPusC: public TmPacketBase { + friend void (Factory::setStaticFrameworkObjectIds)(); +public: + /** + * This constant defines the minimum size of a valid PUS Telemetry Packet. + */ + static const uint32_t TM_PACKET_MIN_SIZE = (sizeof(CCSDSPrimaryHeader) + + sizeof(PUSTmDataFieldHeaderPusC) + 2); + //! Maximum size of a TM Packet in this mission. + static const uint32_t MISSION_TM_PACKET_MAX_SIZE = fsfwconfig::FSFW_MAX_TM_PACKET_SIZE; + + /** + * This is the default constructor. + * It sets its internal data pointer to the address passed and also + * forwards the data pointer to the parent SpacePacketBase class. + * @param set_address The position where the packet data lies. + */ + TmPacketPusC( uint8_t* setData ); + /** + * This is the empty default destructor. + */ + virtual ~TmPacketPusC(); + + /* TmPacketBase implementations */ + uint8_t getService() override; + uint8_t getSubService() override; + uint8_t* getSourceData() override; + uint16_t getSourceDataSize() override; + uint16_t getDataFieldSize() override; + + /** + * Returns a raw pointer to the beginning of the time field. + * @return Raw pointer to time field. + */ + uint8_t* getPacketTimeRaw() const override; + size_t getTimestampSize() const override; + + size_t getPacketMinimumSize() const override; + +protected: + /** + * A pointer to a structure which defines the data structure of + * the packet's data. + * + * To be hardware-safe, all elements are of byte size. + */ + TmPacketPointerPusC* tmData; + + /** + * Initializes the Tm Packet header. + * Does set the timestamp (to now), but not the error control field. + * @param apid APID used. + * @param service PUS Service + * @param subservice PUS Subservice + * @param packetSubcounter Additional subcounter used. + */ + ReturnValue_t initializeTmPacket(uint16_t apid, uint8_t service, uint8_t subservice, + uint16_t packetSubcounter, uint16_t destinationId = 0, uint8_t timeRefField = 0); + + /** + * With this method, the packet data pointer can be redirected to another + * location. + * + * This call overwrites the parent's setData method to set both its + * @c tc_data pointer and the parent's @c data pointer. + * + * @param p_data A pointer to another PUS Telemetry Packet. + */ + void setData( const uint8_t* pData ); + + /** + * In case data was filled manually (almost never the case). + * @param size Size of source data (without CRC and data filed header!). + */ + void setSourceDataSize(uint16_t size); + +}; + +#endif /* FSFW_TMTCPACKET_PUS_TMPACKETPUSC_H_ */ diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketStored.h b/src/fsfw/tmtcpacket/pus/tm/TmPacketStored.h new file mode 100644 index 00000000..fadda561 --- /dev/null +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketStored.h @@ -0,0 +1,13 @@ +#ifndef FSFW_TMTCPACKET_PUS_TMPACKETSTORED_H_ +#define FSFW_TMTCPACKET_PUS_TMPACKETSTORED_H_ + +#include + +#if FSFW_USE_PUS_C_TELEMETRY == 1 +#include "TmPacketStoredPusC.h" +#else +#include "TmPacketStoredPusA.h" +#endif + + +#endif /* FSFW_TMTCPACKET_PUS_TMPACKETSTORED_H_ */ diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredBase.cpp b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredBase.cpp new file mode 100644 index 00000000..523fb619 --- /dev/null +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredBase.cpp @@ -0,0 +1,124 @@ +#include "fsfw/tmtcpacket/pus/tm/TmPacketStoredBase.h" + +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/tmtcservices/TmTcMessage.h" + +#include + +StorageManagerIF *TmPacketStoredBase::store = nullptr; +InternalErrorReporterIF *TmPacketStoredBase::internalErrorReporter = nullptr; + +TmPacketStoredBase::TmPacketStoredBase(store_address_t setAddress): storeAddress(setAddress) { + setStoreAddress(storeAddress); +} + +TmPacketStoredBase::TmPacketStoredBase() { +} + + +TmPacketStoredBase::~TmPacketStoredBase() { +} + +store_address_t TmPacketStoredBase::getStoreAddress() { + return storeAddress; +} + +void TmPacketStoredBase::deletePacket() { + store->deleteData(storeAddress); + storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; + setDataPointer(nullptr); +} + +void TmPacketStoredBase::setStoreAddress(store_address_t setAddress) { + storeAddress = setAddress; + const uint8_t* tempData = nullptr; + size_t tempSize; + if (not checkAndSetStore()) { + return; + } + ReturnValue_t status = store->getData(storeAddress, &tempData, &tempSize); + if (status == StorageManagerIF::RETURN_OK) { + setDataPointer(tempData); + } else { + setDataPointer(nullptr); + storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; + } +} + +bool TmPacketStoredBase::checkAndSetStore() { + if (store == nullptr) { + store = ObjectManager::instance()->get(objects::TM_STORE); + if (store == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "TmPacketStored::TmPacketStored: TM Store not found!" + << std::endl; +#endif + return false; + } + } + return true; +} + +ReturnValue_t TmPacketStoredBase::sendPacket(MessageQueueId_t destination, + MessageQueueId_t sentFrom, bool doErrorReporting) { + if (getAllTmData() == nullptr) { + //SHOULDDO: More decent code. + return HasReturnvaluesIF::RETURN_FAILED; + } + TmTcMessage tmMessage(getStoreAddress()); + ReturnValue_t result = MessageQueueSenderIF::sendMessage(destination, + &tmMessage, sentFrom); + if (result != HasReturnvaluesIF::RETURN_OK) { + deletePacket(); + if (doErrorReporting) { + checkAndReportLostTm(); + } + return result; + } + //SHOULDDO: In many cases, some counter is incremented for successfully sent packets. The check is often not done, but just incremented. + return HasReturnvaluesIF::RETURN_OK; + +} + +void TmPacketStoredBase::checkAndReportLostTm() { + if (internalErrorReporter == nullptr) { + internalErrorReporter = ObjectManager::instance()->get( + objects::INTERNAL_ERROR_REPORTER); + } + if (internalErrorReporter != nullptr) { + internalErrorReporter->lostTm(); + } +} + +void TmPacketStoredBase::handleStoreFailure(const char *const packetType, ReturnValue_t result, + size_t sizeToReserve) { + checkAndReportLostTm(); +#if FSFW_VERBOSE_LEVEL >= 1 + switch(result) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + case(StorageManagerIF::DATA_STORAGE_FULL): { + sif::warning << "TmPacketStoredPus" << packetType << ": " << + "Store full for packet with size" << sizeToReserve << std::endl; + break; + } + case(StorageManagerIF::DATA_TOO_LARGE): { + sif::warning << "TmPacketStoredPus" << packetType << ": Data with size " << + sizeToReserve << " too large" << std::endl; + break; + } +#else + case(StorageManagerIF::DATA_STORAGE_FULL): { + sif::printWarning("TmPacketStoredPus%s: Store full for packet with " + "size %d\n", packetType, sizeToReserve); + break; + } + case(StorageManagerIF::DATA_TOO_LARGE): { + sif::printWarning("TmPacketStoredPus%s: Data with size " + "%d too large\n", packetType, sizeToReserve); + break; + } +#endif + } +#endif +} diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredBase.h b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredBase.h new file mode 100644 index 00000000..91ca2f93 --- /dev/null +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredBase.h @@ -0,0 +1,92 @@ +#ifndef FSFW_TMTCPACKET_PUS_TMPACKETSTOREDBASE_H_ +#define FSFW_TMTCPACKET_PUS_TMPACKETSTOREDBASE_H_ + +#include "fsfw/FSFW.h" +#include "TmPacketBase.h" +#include "TmPacketStoredBase.h" +#include "TmPacketPusA.h" + +#include "fsfw/serialize/SerializeIF.h" +#include "fsfw/storagemanager/StorageManagerIF.h" +#include "fsfw/internalerror/InternalErrorReporterIF.h" +#include "fsfw/ipc/MessageQueueSenderIF.h" + +/** + * This class generates a ECSS PUS Telemetry packet within a given + * intermediate storage. + * As most packets are passed between tasks with the help of a storage + * anyway, it seems logical to create a Packet-In-Storage access class + * which saves the user almost all storage handling operation. + * Packets can both be newly created with the class and be "linked" to + * packets in a store with the help of a storeAddress. + * @ingroup tmtcpackets + */ +class TmPacketStoredBase { +public: + /** + * This is a default constructor which does not set the data pointer. + * However, it does try to set the packet store. + */ + TmPacketStoredBase( store_address_t setAddress ); + TmPacketStoredBase(); + + virtual ~TmPacketStoredBase(); + + virtual uint8_t* getAllTmData() = 0; + virtual void setDataPointer(const uint8_t* newPointer) = 0; + + /** + * This is a getter for the current store address of the packet. + * @return The current store address. The (raw) value is + * @c StorageManagerIF::INVALID_ADDRESS if + * the packet is not linked. + */ + store_address_t getStoreAddress(); + /** + * With this call, the packet is deleted. + * It removes itself from the store and sets its data pointer to NULL. + */ + void deletePacket(); + /** + * With this call, a packet can be linked to another store. This is useful + * if the packet is a class member and used for more than one packet. + * @param setAddress The new packet id to link to. + */ + void setStoreAddress(store_address_t setAddress); + + ReturnValue_t sendPacket(MessageQueueId_t destination, MessageQueueId_t sentFrom, + bool doErrorReporting = true); + +protected: + /** + * This is a pointer to the store all instances of the class use. + * If the store is not yet set (i.e. @c store is NULL), every constructor + * call tries to set it and throws an error message in case of failures. + * The default store is objects::TM_STORE. + */ + static StorageManagerIF* store; + + static InternalErrorReporterIF *internalErrorReporter; + + /** + * The address where the packet data of the object instance is stored. + */ + store_address_t storeAddress; + /** + * A helper method to check if a store is assigned to the class. + * If not, the method tries to retrieve the store from the global + * ObjectManager. + * @return @li @c true if the store is linked or could be created. + * @li @c false otherwise. + */ + bool checkAndSetStore(); + + void checkAndReportLostTm(); + + void handleStoreFailure(const char* const packetType, ReturnValue_t result, + size_t sizeToReserve); +}; + + +#endif /* FSFW_TMTCPACKET_PUS_TMPACKETSTOREDBASE_H_ */ + diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusA.cpp b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusA.cpp new file mode 100644 index 00000000..4ffacce4 --- /dev/null +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusA.cpp @@ -0,0 +1,80 @@ +#include "fsfw/tmtcpacket/pus/tm/TmPacketStoredPusA.h" + +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/tmtcservices/TmTcMessage.h" + +#include + +TmPacketStoredPusA::TmPacketStoredPusA(store_address_t setAddress): + TmPacketStoredBase(setAddress), TmPacketPusA(nullptr){ +} + +TmPacketStoredPusA::TmPacketStoredPusA(uint16_t apid, uint8_t service, + uint8_t subservice, uint8_t packetSubcounter, const uint8_t *data, + uint32_t size, const uint8_t *headerData, uint32_t headerSize): + TmPacketPusA(nullptr) { + storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; + if (not TmPacketStoredBase::checkAndSetStore()) { + return; + } + uint8_t *pData = nullptr; + size_t sizeToReserve = getPacketMinimumSize() + size + headerSize; + ReturnValue_t returnValue = store->getFreeElement(&storeAddress, + sizeToReserve, &pData); + + if (returnValue != store->RETURN_OK) { + handleStoreFailure("A", returnValue, sizeToReserve); + return; + } + setData(pData); + initializeTmPacket(apid, service, subservice, packetSubcounter); + memcpy(getSourceData(), headerData, headerSize); + memcpy(getSourceData() + headerSize, data, size); + setPacketDataLength(size + headerSize + sizeof(PUSTmDataFieldHeaderPusA) + CRC_SIZE - 1); +} + +TmPacketStoredPusA::TmPacketStoredPusA(uint16_t apid, uint8_t service, + uint8_t subservice, uint8_t packetSubcounter, SerializeIF *content, + SerializeIF *header) : + TmPacketPusA(nullptr) { + storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; + if (not TmPacketStoredBase::checkAndSetStore()) { + return; + } + size_t sourceDataSize = 0; + if (content != nullptr) { + sourceDataSize += content->getSerializedSize(); + } + if (header != nullptr) { + sourceDataSize += header->getSerializedSize(); + } + uint8_t *pData = nullptr; + size_t sizeToReserve = getPacketMinimumSize() + sourceDataSize; + ReturnValue_t returnValue = store->getFreeElement(&storeAddress, + sizeToReserve, &pData); + if (returnValue != store->RETURN_OK) { + handleStoreFailure("A", returnValue, sizeToReserve); + return; + } + setData(pData); + initializeTmPacket(apid, service, subservice, packetSubcounter); + uint8_t *putDataHere = getSourceData(); + size_t size = 0; + if (header != nullptr) { + header->serialize(&putDataHere, &size, sourceDataSize, + SerializeIF::Endianness::BIG); + } + if (content != nullptr) { + content->serialize(&putDataHere, &size, sourceDataSize, + SerializeIF::Endianness::BIG); + } + setPacketDataLength(sourceDataSize + sizeof(PUSTmDataFieldHeaderPusA) + CRC_SIZE - 1); +} + +uint8_t* TmPacketStoredPusA::getAllTmData() { + return getWholeData(); +} + +void TmPacketStoredPusA::setDataPointer(const uint8_t *newPointer) { + setData(newPointer); +} diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusA.h b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusA.h new file mode 100644 index 00000000..6a338cd5 --- /dev/null +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusA.h @@ -0,0 +1,65 @@ +#ifndef FSFW_TMTCPACKET_PUS_TMPACKETSTORED_PUSA_H_ +#define FSFW_TMTCPACKET_PUS_TMPACKETSTORED_PUSA_H_ + +#include "TmPacketStoredBase.h" +#include "TmPacketPusA.h" +#include + +/** + * This class generates a ECSS PUS A Telemetry packet within a given + * intermediate storage. + * As most packets are passed between tasks with the help of a storage + * anyway, it seems logical to create a Packet-In-Storage access class + * which saves the user almost all storage handling operation. + * Packets can both be newly created with the class and be "linked" to + * packets in a store with the help of a storeAddress. + * @ingroup tmtcpackets + */ +class TmPacketStoredPusA: + public TmPacketStoredBase, + public TmPacketPusA { +public: + /** + * This is a default constructor which does not set the data pointer. + * However, it does try to set the packet store. + */ + TmPacketStoredPusA( store_address_t setAddress ); + /** + * With this constructor, new space is allocated in the packet store and + * a new PUS Telemetry Packet is created there. + * Packet Application Data passed in data is copied into the packet. + * The Application data is passed in two parts, first a header, then a + * data field. This allows building a Telemetry Packet from two separate + * data sources. + * @param apid Sets the packet's APID field. + * @param service Sets the packet's Service ID field. + * This specifies the source service. + * @param subservice Sets the packet's Service Subtype field. + * This specifies the source sub-service. + * @param packet_counter Sets the Packet counter field of this packet + * @param data The payload data to be copied to the + * Application Data Field + * @param size The amount of data to be copied. + * @param headerData The header Data of the Application field, + * will be copied in front of data + * @param headerSize The size of the headerDataF + */ + TmPacketStoredPusA( uint16_t apid, uint8_t service, uint8_t subservice, + uint8_t packet_counter = 0, const uint8_t* data = nullptr, + uint32_t size = 0, const uint8_t* headerData = nullptr, + uint32_t headerSize = 0); + /** + * Another ctor to directly pass structured content and header data to the + * packet to avoid additional buffers. + */ + TmPacketStoredPusA( uint16_t apid, uint8_t service, uint8_t subservice, + uint8_t packet_counter, SerializeIF* content, + SerializeIF* header = nullptr); + + uint8_t* getAllTmData() override; + void setDataPointer(const uint8_t* newPointer) override; + +}; + + +#endif /* FSFW_TMTCPACKET_PUS_TMPACKETSTORED_PUSA_H_ */ diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.cpp b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.cpp new file mode 100644 index 00000000..ee574299 --- /dev/null +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.cpp @@ -0,0 +1,81 @@ +#include "fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.h" + +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/tmtcservices/TmTcMessage.h" + +#include + +TmPacketStoredPusC::TmPacketStoredPusC(store_address_t setAddress) : + TmPacketStoredBase(setAddress), TmPacketPusC(nullptr){ +} + +TmPacketStoredPusC::TmPacketStoredPusC(uint16_t apid, uint8_t service, + uint8_t subservice, uint16_t packetSubcounter, const uint8_t *data, + uint32_t size, const uint8_t *headerData, uint32_t headerSize, uint16_t destinationId, + uint8_t timeRefField) : + TmPacketPusC(nullptr) { + storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; + if (not TmPacketStoredBase::checkAndSetStore()) { + return; + } + uint8_t *pData = nullptr; + size_t sizeToReserve = getPacketMinimumSize() + size + headerSize; + ReturnValue_t returnValue = store->getFreeElement(&storeAddress, + sizeToReserve, &pData); + + if (returnValue != store->RETURN_OK) { + handleStoreFailure("C", returnValue, sizeToReserve); + return; + } + setData(pData); + initializeTmPacket(apid, service, subservice, packetSubcounter, destinationId, timeRefField); + memcpy(getSourceData(), headerData, headerSize); + memcpy(getSourceData() + headerSize, data, size); + setPacketDataLength(size + headerSize + sizeof(PUSTmDataFieldHeaderPusC) + CRC_SIZE - 1); +} + +TmPacketStoredPusC::TmPacketStoredPusC(uint16_t apid, uint8_t service, + uint8_t subservice, uint16_t packetSubcounter, SerializeIF *content, + SerializeIF *header, uint16_t destinationId, uint8_t timeRefField) : + TmPacketPusC(nullptr) { + storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; + if (not TmPacketStoredBase::checkAndSetStore()) { + return; + } + size_t sourceDataSize = 0; + if (content != nullptr) { + sourceDataSize += content->getSerializedSize(); + } + if (header != nullptr) { + sourceDataSize += header->getSerializedSize(); + } + uint8_t *pData = nullptr; + size_t sizeToReserve = getPacketMinimumSize() + sourceDataSize; + ReturnValue_t returnValue = store->getFreeElement(&storeAddress, sizeToReserve, &pData); + if (returnValue != store->RETURN_OK) { + handleStoreFailure("C", returnValue, sizeToReserve); + return; + } + setData(pData); + initializeTmPacket(apid, service, subservice, packetSubcounter, destinationId, timeRefField); + uint8_t *putDataHere = getSourceData(); + size_t size = 0; + if (header != nullptr) { + header->serialize(&putDataHere, &size, sourceDataSize, + SerializeIF::Endianness::BIG); + } + if (content != nullptr) { + content->serialize(&putDataHere, &size, sourceDataSize, + SerializeIF::Endianness::BIG); + } + setPacketDataLength( + sourceDataSize + sizeof(PUSTmDataFieldHeaderPusC) + CRC_SIZE - 1); +} + +uint8_t* TmPacketStoredPusC::getAllTmData() { + return getWholeData(); +} + +void TmPacketStoredPusC::setDataPointer(const uint8_t *newPointer) { + setData(newPointer); +} diff --git a/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.h b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.h new file mode 100644 index 00000000..35c66083 --- /dev/null +++ b/src/fsfw/tmtcpacket/pus/tm/TmPacketStoredPusC.h @@ -0,0 +1,68 @@ +#ifndef FSFW_TMTCPACKET_PUS_TMPACKETSTOREDPUSC_H_ +#define FSFW_TMTCPACKET_PUS_TMPACKETSTOREDPUSC_H_ + +#include "TmPacketPusC.h" +#include "TmPacketStoredBase.h" + +/** + * This class generates a ECSS PUS C Telemetry packet within a given + * intermediate storage. + * As most packets are passed between tasks with the help of a storage + * anyway, it seems logical to create a Packet-In-Storage access class + * which saves the user almost all storage handling operation. + * Packets can both be newly created with the class and be "linked" to + * packets in a store with the help of a storeAddress. + * @ingroup tmtcpackets + */ +class TmPacketStoredPusC: + public TmPacketStoredBase, + public TmPacketPusC { +public: + /** + * This is a default constructor which does not set the data pointer. + * However, it does try to set the packet store. + */ + TmPacketStoredPusC( store_address_t setAddress ); + /** + * With this constructor, new space is allocated in the packet store and + * a new PUS Telemetry Packet is created there. + * Packet Application Data passed in data is copied into the packet. + * The Application data is passed in two parts, first a header, then a + * data field. This allows building a Telemetry Packet from two separate + * data sources. + * @param apid Sets the packet's APID field. + * @param service Sets the packet's Service ID field. + * This specifies the source service. + * @param subservice Sets the packet's Service Subtype field. + * This specifies the source sub-service. + * @param packet_counter Sets the Packet counter field of this packet + * @param data The payload data to be copied to the + * Application Data Field + * @param size The amount of data to be copied. + * @param headerData The header Data of the Application field, + * will be copied in front of data + * @param headerSize The size of the headerDataF + * @param destinationId Destination ID containing the application process ID as specified + * by PUS C + * @param timeRefField 4 bit time reference field as specified by PUS C + */ + TmPacketStoredPusC( uint16_t apid, uint8_t service, uint8_t subservice, + uint16_t packetCounter = 0, const uint8_t* data = nullptr, + uint32_t size = 0, const uint8_t* headerData = nullptr, + uint32_t headerSize = 0, uint16_t destinationId = 0, uint8_t timeRefField = 0); + /** + * Another ctor to directly pass structured content and header data to the + * packet to avoid additional buffers. + */ + TmPacketStoredPusC( uint16_t apid, uint8_t service, uint8_t subservice, + uint16_t packetCounter, SerializeIF* content, + SerializeIF* header = nullptr, uint16_t destinationId = 0, uint8_t timeRefField = 0); + + uint8_t* getAllTmData() override; + void setDataPointer(const uint8_t* newPointer) override; + +}; + + + +#endif /* FSFW_TMTCPACKET_PUS_TMPACKETSTOREDPUSC_H_ */ diff --git a/tmtcservices/AcceptsTelecommandsIF.h b/src/fsfw/tmtcservices/AcceptsTelecommandsIF.h similarity index 100% rename from tmtcservices/AcceptsTelecommandsIF.h rename to src/fsfw/tmtcservices/AcceptsTelecommandsIF.h diff --git a/tmtcservices/AcceptsTelemetryIF.h b/src/fsfw/tmtcservices/AcceptsTelemetryIF.h similarity index 100% rename from tmtcservices/AcceptsTelemetryIF.h rename to src/fsfw/tmtcservices/AcceptsTelemetryIF.h diff --git a/tmtcservices/AcceptsVerifyMessageIF.h b/src/fsfw/tmtcservices/AcceptsVerifyMessageIF.h similarity index 100% rename from tmtcservices/AcceptsVerifyMessageIF.h rename to src/fsfw/tmtcservices/AcceptsVerifyMessageIF.h diff --git a/tmtcservices/CMakeLists.txt b/src/fsfw/tmtcservices/CMakeLists.txt similarity index 87% rename from tmtcservices/CMakeLists.txt rename to src/fsfw/tmtcservices/CMakeLists.txt index c30af214..96cf99b5 100644 --- a/tmtcservices/CMakeLists.txt +++ b/src/fsfw/tmtcservices/CMakeLists.txt @@ -6,4 +6,5 @@ target_sources(${LIB_FSFW_NAME} TmTcBridge.cpp TmTcMessage.cpp VerificationReporter.cpp + SpacePacketParser.cpp ) \ No newline at end of file diff --git a/tmtcservices/CommandingServiceBase.cpp b/src/fsfw/tmtcservices/CommandingServiceBase.cpp similarity index 83% rename from tmtcservices/CommandingServiceBase.cpp rename to src/fsfw/tmtcservices/CommandingServiceBase.cpp index 8b6f7a09..10805b47 100644 --- a/tmtcservices/CommandingServiceBase.cpp +++ b/src/fsfw/tmtcservices/CommandingServiceBase.cpp @@ -1,13 +1,13 @@ -#include "AcceptsTelemetryIF.h" -#include "CommandingServiceBase.h" -#include "TmTcMessage.h" +#include "fsfw/tmtcservices/CommandingServiceBase.h" +#include "fsfw/tmtcservices/AcceptsTelemetryIF.h" +#include "fsfw/tmtcservices/TmTcMessage.h" -#include "../tcdistribution/PUSDistributorIF.h" -#include "../objectmanager/ObjectManagerIF.h" -#include "../ipc/QueueFactory.h" -#include "../tmtcpacket/pus/TcPacketStored.h" -#include "../tmtcpacket/pus/TmPacketStored.h" -#include "../serviceinterface/ServiceInterface.h" +#include "fsfw/tcdistribution/PUSDistributorIF.h" +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/ipc/QueueFactory.h" +#include "fsfw/tmtcpacket/pus/tc.h" +#include "fsfw/tmtcpacket/pus/tm.h" +#include "fsfw/serviceinterface/ServiceInterface.h" object_id_t CommandingServiceBase::defaultPacketSource = objects::NO_OBJECT; object_id_t CommandingServiceBase::defaultPacketDestination = objects::NO_OBJECT; @@ -67,12 +67,12 @@ ReturnValue_t CommandingServiceBase::initialize() { packetDestination = defaultPacketDestination; } AcceptsTelemetryIF* packetForwarding = - objectManager->get(packetDestination); + ObjectManager::instance()->get(packetDestination); if(packetSource == objects::NO_OBJECT) { packetSource = defaultPacketSource; } - PUSDistributorIF* distributor = objectManager->get( + PUSDistributorIF* distributor = ObjectManager::instance()->get( packetSource); if (packetForwarding == nullptr or distributor == nullptr) { @@ -87,8 +87,8 @@ ReturnValue_t CommandingServiceBase::initialize() { requestQueue->setDefaultDestination( packetForwarding->getReportReceptionQueue()); - IPCStore = objectManager->get(objects::IPC_STORE); - TCStore = objectManager->get(objects::TC_STORE); + IPCStore = ObjectManager::instance()->get(objects::IPC_STORE); + TCStore = ObjectManager::instance()->get(objects::TC_STORE); if (IPCStore == nullptr or TCStore == nullptr) { #if FSFW_CPP_OSTREAM_ENABLED == 1 @@ -245,7 +245,7 @@ void CommandingServiceBase::handleRequestQueue() { TmTcMessage message; ReturnValue_t result; store_address_t address; - TcPacketStored packet; + TcPacketStoredPus packet; MessageQueueId_t queue; object_id_t objectId; for (result = requestQueue->receiveMessage(&message); result == RETURN_OK; @@ -258,6 +258,7 @@ void CommandingServiceBase::handleRequestQueue() { rejectPacket(tc_verification::START_FAILURE, &packet, INVALID_SUBSERVICE); continue; } + result = getMessageQueueAndObject(packet.getSubService(), packet.getApplicationData(), packet.getApplicationDataSize(), &queue, &objectId); @@ -293,8 +294,13 @@ void CommandingServiceBase::handleRequestQueue() { ReturnValue_t CommandingServiceBase::sendTmPacket(uint8_t subservice, const uint8_t* data, size_t dataLen, const uint8_t* headerData, size_t headerSize) { - TmPacketStored tmPacketStored(this->apid, this->service, subservice, +#if FSFW_USE_PUS_C_TELEMETRY == 0 + TmPacketStoredPusA tmPacketStored(this->apid, this->service, subservice, this->tmPacketCounter, data, dataLen, headerData, headerSize); +#else + TmPacketStoredPusC tmPacketStored(this->apid, this->service, subservice, + this->tmPacketCounter, data, dataLen, headerData, headerSize); +#endif ReturnValue_t result = tmPacketStored.sendPacket( requestQueue->getDefaultDestination(), requestQueue->getId()); if (result == HasReturnvaluesIF::RETURN_OK) { @@ -311,8 +317,13 @@ ReturnValue_t CommandingServiceBase::sendTmPacket(uint8_t subservice, size_t size = 0; SerializeAdapter::serialize(&objectId, &pBuffer, &size, sizeof(object_id_t), SerializeIF::Endianness::BIG); - TmPacketStored tmPacketStored(this->apid, this->service, subservice, +#if FSFW_USE_PUS_C_TELEMETRY == 0 + TmPacketStoredPusA tmPacketStored(this->apid, this->service, subservice, this->tmPacketCounter, data, dataLen, buffer, size); +#else + TmPacketStoredPusC tmPacketStored(this->apid, this->service, subservice, + this->tmPacketCounter, data, dataLen, buffer, size); +#endif ReturnValue_t result = tmPacketStored.sendPacket( requestQueue->getDefaultDestination(), requestQueue->getId()); if (result == HasReturnvaluesIF::RETURN_OK) { @@ -324,8 +335,13 @@ ReturnValue_t CommandingServiceBase::sendTmPacket(uint8_t subservice, ReturnValue_t CommandingServiceBase::sendTmPacket(uint8_t subservice, SerializeIF* content, SerializeIF* header) { - TmPacketStored tmPacketStored(this->apid, this->service, subservice, +#if FSFW_USE_PUS_C_TELEMETRY == 0 + TmPacketStoredPusA tmPacketStored(this->apid, this->service, subservice, this->tmPacketCounter, content, header); +#else + TmPacketStoredPusC tmPacketStored(this->apid, this->service, subservice, + this->tmPacketCounter, content, header); +#endif ReturnValue_t result = tmPacketStored.sendPacket( requestQueue->getDefaultDestination(), requestQueue->getId()); if (result == HasReturnvaluesIF::RETURN_OK) { @@ -335,14 +351,18 @@ ReturnValue_t CommandingServiceBase::sendTmPacket(uint8_t subservice, } -void CommandingServiceBase::startExecution(TcPacketStored *storedPacket, +void CommandingServiceBase::startExecution(TcPacketStoredBase *storedPacket, CommandMapIter iter) { ReturnValue_t result = RETURN_OK; CommandMessage command; - iter->second.subservice = storedPacket->getSubService(); + TcPacketBase* tcPacketBase = storedPacket->getPacketBase(); + if(tcPacketBase == nullptr) { + return; + } + iter->second.subservice = tcPacketBase->getSubService(); result = prepareCommand(&command, iter->second.subservice, - storedPacket->getApplicationData(), - storedPacket->getApplicationDataSize(), &iter->second.state, + tcPacketBase->getApplicationData(), + tcPacketBase->getApplicationDataSize(), &iter->second.state, iter->second.objectId); ReturnValue_t sendResult = RETURN_OK; @@ -355,12 +375,12 @@ void CommandingServiceBase::startExecution(TcPacketStored *storedPacket, if (sendResult == RETURN_OK) { Clock::getUptime(&iter->second.uptimeOfStart); iter->second.step = 0; - iter->second.subservice = storedPacket->getSubService(); + iter->second.subservice = tcPacketBase->getSubService(); iter->second.command = command.getCommand(); - iter->second.tcInfo.ackFlags = storedPacket->getAcknowledgeFlags(); - iter->second.tcInfo.tcPacketId = storedPacket->getPacketId(); + iter->second.tcInfo.ackFlags = tcPacketBase->getAcknowledgeFlags(); + iter->second.tcInfo.tcPacketId = tcPacketBase->getPacketId(); iter->second.tcInfo.tcSequenceControl = - storedPacket->getPacketSequenceControl(); + tcPacketBase->getPacketSequenceControl(); acceptPacket(tc_verification::START_SUCCESS, storedPacket); } else { command.clearCommandMessage(); @@ -376,7 +396,7 @@ void CommandingServiceBase::startExecution(TcPacketStored *storedPacket, } if (sendResult == RETURN_OK) { verificationReporter.sendSuccessReport(tc_verification::START_SUCCESS, - storedPacket); + storedPacket->getPacketBase()); acceptPacket(tc_verification::COMPLETION_SUCCESS, storedPacket); checkAndExecuteFifo(iter); } else { @@ -393,16 +413,16 @@ void CommandingServiceBase::startExecution(TcPacketStored *storedPacket, } -void CommandingServiceBase::rejectPacket(uint8_t report_id, - TcPacketStored* packet, ReturnValue_t error_code) { - verificationReporter.sendFailureReport(report_id, packet, error_code); +void CommandingServiceBase::rejectPacket(uint8_t reportId, + TcPacketStoredBase* packet, ReturnValue_t errorCode) { + verificationReporter.sendFailureReport(reportId, packet->getPacketBase(), errorCode); packet->deletePacket(); } void CommandingServiceBase::acceptPacket(uint8_t reportId, - TcPacketStored* packet) { - verificationReporter.sendSuccessReport(reportId, packet); + TcPacketStoredBase* packet) { + verificationReporter.sendSuccessReport(reportId, packet->getPacketBase()); packet->deletePacket(); } @@ -412,7 +432,7 @@ void CommandingServiceBase::checkAndExecuteFifo(CommandMapIter& iter) { if (iter->second.fifo.retrieve(&address) != RETURN_OK) { commandMap.erase(&iter); } else { - TcPacketStored newPacket(address); + TcPacketStoredPus newPacket(address); startExecution(&newPacket, iter); } } diff --git a/tmtcservices/CommandingServiceBase.h b/src/fsfw/tmtcservices/CommandingServiceBase.h similarity index 95% rename from tmtcservices/CommandingServiceBase.h rename to src/fsfw/tmtcservices/CommandingServiceBase.h index e10f2ddd..b6709693 100644 --- a/tmtcservices/CommandingServiceBase.h +++ b/src/fsfw/tmtcservices/CommandingServiceBase.h @@ -3,19 +3,19 @@ #include "AcceptsTelecommandsIF.h" #include "VerificationReporter.h" +#include "fsfw/FSFW.h" -#include "../objectmanager/SystemObject.h" -#include "../storagemanager/StorageManagerIF.h" -#include "../tasks/ExecutableObjectIF.h" -#include "../ipc/MessageQueueIF.h" -#include "../ipc/CommandMessage.h" -#include "../container/FixedMap.h" -#include "../container/FIFO.h" -#include "../serialize/SerializeIF.h" - -#include +#include "fsfw/objectmanager/SystemObject.h" +#include "fsfw/storagemanager/StorageManagerIF.h" +#include "fsfw/tasks/ExecutableObjectIF.h" +#include "fsfw/ipc/MessageQueueIF.h" +#include "fsfw/ipc/CommandMessage.h" +#include "fsfw/container/FixedMap.h" +#include "fsfw/container/FIFO.h" +#include "fsfw/serialize/SerializeIF.h" class TcPacketStored; +class TcPacketStoredBase; namespace Factory{ void setStaticFrameworkObjectIds(); @@ -351,12 +351,12 @@ private: */ void handleRequestQueue(); - void rejectPacket(uint8_t reportId, TcPacketStored* packet, + void rejectPacket(uint8_t reportId, TcPacketStoredBase* packet, ReturnValue_t errorCode); - void acceptPacket(uint8_t reportId, TcPacketStored* packet); + void acceptPacket(uint8_t reportId, TcPacketStoredBase* packet); - void startExecution(TcPacketStored *storedPacket, CommandMapIter iter); + void startExecution(TcPacketStoredBase *storedPacket, CommandMapIter iter); void handleCommandMessage(CommandMessage* reply); void handleReplyHandlerResult(ReturnValue_t result, CommandMapIter iter, diff --git a/tmtcservices/PusServiceBase.cpp b/src/fsfw/tmtcservices/PusServiceBase.cpp similarity index 87% rename from tmtcservices/PusServiceBase.cpp rename to src/fsfw/tmtcservices/PusServiceBase.cpp index 0a5cb202..866e0844 100644 --- a/tmtcservices/PusServiceBase.cpp +++ b/src/fsfw/tmtcservices/PusServiceBase.cpp @@ -1,11 +1,12 @@ -#include "PusServiceBase.h" -#include "AcceptsTelemetryIF.h" -#include "PusVerificationReport.h" -#include "TmTcMessage.h" +#include "fsfw/tmtcservices/PusServiceBase.h" +#include "fsfw/tmtcservices/AcceptsTelemetryIF.h" +#include "fsfw/tmtcservices/PusVerificationReport.h" +#include "fsfw/tmtcservices/TmTcMessage.h" -#include "../serviceinterface/ServiceInterfaceStream.h" -#include "../tcdistribution/PUSDistributorIF.h" -#include "../ipc/QueueFactory.h" +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/tcdistribution/PUSDistributorIF.h" +#include "fsfw/ipc/QueueFactory.h" object_id_t PusServiceBase::packetSource = 0; object_id_t PusServiceBase::packetDestination = 0; @@ -105,9 +106,9 @@ ReturnValue_t PusServiceBase::initialize() { if (result != RETURN_OK) { return result; } - AcceptsTelemetryIF* destService = objectManager->get( + AcceptsTelemetryIF* destService = ObjectManager::instance()->get( packetDestination); - PUSDistributorIF* distributor = objectManager->get( + PUSDistributorIF* distributor = ObjectManager::instance()->get( packetSource); if (destService == nullptr or distributor == nullptr) { #if FSFW_CPP_OSTREAM_ENABLED == 1 diff --git a/tmtcservices/PusServiceBase.h b/src/fsfw/tmtcservices/PusServiceBase.h similarity index 94% rename from tmtcservices/PusServiceBase.h rename to src/fsfw/tmtcservices/PusServiceBase.h index 4d3d99bc..ea4147fe 100644 --- a/tmtcservices/PusServiceBase.h +++ b/src/fsfw/tmtcservices/PusServiceBase.h @@ -5,12 +5,12 @@ #include "VerificationCodes.h" #include "VerificationReporter.h" -#include "../objectmanager/ObjectManagerIF.h" -#include "../objectmanager/SystemObject.h" -#include "../returnvalues/HasReturnvaluesIF.h" -#include "../tasks/ExecutableObjectIF.h" -#include "../tmtcpacket/pus/TcPacketStored.h" -#include "../ipc/MessageQueueIF.h" +#include "fsfw/objectmanager/ObjectManagerIF.h" +#include "fsfw/objectmanager/SystemObject.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" +#include "fsfw/tasks/ExecutableObjectIF.h" +#include "fsfw/tmtcpacket/pus/tc.h" +#include "fsfw/ipc/MessageQueueIF.h" namespace Factory{ void setStaticFrameworkObjectIds(); @@ -141,7 +141,7 @@ protected: * The current Telecommand to be processed. * It is deleted after handleRequest was executed. */ - TcPacketStored currentPacket; + TcPacketStoredPus currentPacket; static object_id_t packetSource; diff --git a/tmtcservices/PusVerificationReport.cpp b/src/fsfw/tmtcservices/PusVerificationReport.cpp similarity index 97% rename from tmtcservices/PusVerificationReport.cpp rename to src/fsfw/tmtcservices/PusVerificationReport.cpp index c64e5feb..827486ce 100644 --- a/tmtcservices/PusVerificationReport.cpp +++ b/src/fsfw/tmtcservices/PusVerificationReport.cpp @@ -1,5 +1,5 @@ -#include "../serialize/SerializeAdapter.h" -#include "../tmtcservices/PusVerificationReport.h" +#include "fsfw/serialize/SerializeAdapter.h" +#include "fsfw/tmtcservices/PusVerificationReport.h" PusVerificationMessage::PusVerificationMessage() { } diff --git a/tmtcservices/PusVerificationReport.h b/src/fsfw/tmtcservices/PusVerificationReport.h similarity index 93% rename from tmtcservices/PusVerificationReport.h rename to src/fsfw/tmtcservices/PusVerificationReport.h index 9dce95ac..c22ba535 100644 --- a/tmtcservices/PusVerificationReport.h +++ b/src/fsfw/tmtcservices/PusVerificationReport.h @@ -3,9 +3,9 @@ #include "VerificationCodes.h" -#include "../ipc/MessageQueueMessage.h" -#include "../tmtcpacket/pus/TcPacketBase.h" -#include "../returnvalues/HasReturnvaluesIF.h" +#include "fsfw/ipc/MessageQueueMessage.h" +#include "fsfw/tmtcpacket/pus/tc/TcPacketBase.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" class PusVerificationMessage: public MessageQueueMessage { private: diff --git a/tmtcservices/SourceSequenceCounter.h b/src/fsfw/tmtcservices/SourceSequenceCounter.h similarity index 100% rename from tmtcservices/SourceSequenceCounter.h rename to src/fsfw/tmtcservices/SourceSequenceCounter.h diff --git a/src/fsfw/tmtcservices/SpacePacketParser.cpp b/src/fsfw/tmtcservices/SpacePacketParser.cpp new file mode 100644 index 00000000..3d442458 --- /dev/null +++ b/src/fsfw/tmtcservices/SpacePacketParser.cpp @@ -0,0 +1,77 @@ +#include +#include +#include + +SpacePacketParser::SpacePacketParser(std::vector validPacketIds): + validPacketIds(validPacketIds) { +} + +ReturnValue_t SpacePacketParser::parseSpacePackets(const uint8_t *buffer, + const size_t maxSize, size_t& startIndex, size_t& foundSize) { + const uint8_t** tempPtr = &buffer; + size_t readLen = 0; + return parseSpacePackets(tempPtr, maxSize, startIndex, foundSize, readLen); +} + +ReturnValue_t SpacePacketParser::parseSpacePackets(const uint8_t **buffer, const size_t maxSize, + size_t &startIndex, size_t &foundSize, size_t& readLen) { + if(buffer == nullptr or maxSize < 5) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "SpacePacketParser::parseSpacePackets: Frame invalid" << std::endl; +#else + sif::printWarning("SpacePacketParser::parseSpacePackets: Frame invalid\n"); +#endif + return HasReturnvaluesIF::RETURN_FAILED; + } + const uint8_t* bufPtr = *buffer; + + auto verifyLengthField = [&](size_t idx) { + uint16_t lengthField = bufPtr[idx + 4] << 8 | bufPtr[idx + 5]; + size_t packetSize = lengthField + 7; + startIndex = idx; + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + if(lengthField == 0) { + // Skip whole header for now + foundSize = 6; + result = NO_PACKET_FOUND; + } + else if(packetSize + idx > maxSize) { + // Don't increment buffer and read length here, user has to decide what to do + foundSize = packetSize; + return SPLIT_PACKET; + } + else { + foundSize = packetSize; + } + *buffer += foundSize; + readLen += idx + foundSize; + return result; + }; + + size_t idx = 0; + // Space packet ID as start marker + if(validPacketIds.size() > 0) { + while(idx < maxSize - 5) { + uint16_t currentPacketId = bufPtr[idx] << 8 | bufPtr[idx + 1]; + if(std::find(validPacketIds.begin(), validPacketIds.end(), currentPacketId) != + validPacketIds.end()) { + if(idx + 5 >= maxSize) { + return SPLIT_PACKET; + } + return verifyLengthField(idx); + } + else { + idx++; + } + } + startIndex = 0; + foundSize = maxSize; + *buffer += foundSize; + readLen += foundSize; + return NO_PACKET_FOUND; + } + // Assume that the user verified a valid start of a space packet + else { + return verifyLengthField(idx); + } +} diff --git a/src/fsfw/tmtcservices/SpacePacketParser.h b/src/fsfw/tmtcservices/SpacePacketParser.h new file mode 100644 index 00000000..bed3369b --- /dev/null +++ b/src/fsfw/tmtcservices/SpacePacketParser.h @@ -0,0 +1,78 @@ +#ifndef FRAMEWORK_TMTCSERVICES_PUSPARSER_H_ +#define FRAMEWORK_TMTCSERVICES_PUSPARSER_H_ + +#include "fsfw/container/DynamicFIFO.h" +#include "fsfw/returnvalues/FwClassIds.h" + +#include +#include + +/** + * @brief This small helper class scans a given buffer for space packets. + * Can be used if space packets are serialized in a tightly packed frame. + * @details + * The parser uses the length field field and the 16-bit TC packet ID of the space packets to find + * find space packets in a given data stream + * @author R. Mueller + */ +class SpacePacketParser { +public: + //! The first entry is the index inside the buffer while the second index + //! is the size of the PUS packet starting at that index. + using IndexSizePair = std::pair; + + static constexpr uint8_t INTERFACE_ID = CLASS_ID::SPACE_PACKET_PARSER; + static constexpr ReturnValue_t NO_PACKET_FOUND = MAKE_RETURN_CODE(0x00); + static constexpr ReturnValue_t SPLIT_PACKET = MAKE_RETURN_CODE(0x01); + + /** + * @brief Parser constructor. + * @param validPacketIds This vector contains the allowed 16-bit TC packet ID start markers + * The parser will search for these stark markers to detect the start of a space packet. + * It is also possible to pass an empty vector here, but this is not recommended. + * If an empty vector is passed, the parser will assume that the start of the given stream + * contains the start of a new space packet. + */ + SpacePacketParser(std::vector validPacketIds); + + /** + * Parse a given frame for space packets but also increment the given buffer and assign the + * total number of bytes read so far + * @param buffer Parser will look for space packets in this buffer + * @param maxSize Maximum size of the buffer + * @param startIndex Start index of a found space packet + * @param foundSize Found size of the space packet + * @param readLen Length read so far. This value is incremented by the number of parsed + * bytes which also includes the size of a found packet + * -@c NO_PACKET_FOUND if no packet was found in the given buffer or the length field is + * invalid. foundSize will be set to the size of the space packet header. buffer and + * readLen will be incremented accordingly. + * -@c SPLIT_PACKET if a packet was found but the detected size exceeds maxSize. foundSize + * will be set to the detected packet size and startIndex will be set to the start of the + * detected packet. buffer and read length will not be incremented but the found length + * will be assigned. + * -@c RETURN_OK if a packet was found + */ + ReturnValue_t parseSpacePackets(const uint8_t **buffer, const size_t maxSize, + size_t& startIndex, size_t& foundSize, size_t& readLen); + + /** + * Parse a given frame for space packets + * @param buffer Parser will look for space packets in this buffer + * @param maxSize Maximum size of the buffer + * @param startIndex Start index of a found space packet + * @param foundSize Found size of the space packet + * -@c NO_PACKET_FOUND if no packet was found in the given buffer or the length field is + * invalid. foundSize will be set to the size of the space packet header + * -@c SPLIT_PACKET if a packet was found but the detected size exceeds maxSize. foundSize + * will be set to the detected packet size and startIndex will be set to the start of the + * detected packet + * -@c RETURN_OK if a packet was found + */ + ReturnValue_t parseSpacePackets(const uint8_t* buffer, const size_t maxSize, + size_t& startIndex, size_t& foundSize); +private: + std::vector validPacketIds; +}; + +#endif /* FRAMEWORK_TMTCSERVICES_PUSPARSER_H_ */ diff --git a/tmtcservices/TmTcBridge.cpp b/src/fsfw/tmtcservices/TmTcBridge.cpp similarity index 90% rename from tmtcservices/TmTcBridge.cpp rename to src/fsfw/tmtcservices/TmTcBridge.cpp index dcffac41..7346cfe2 100644 --- a/tmtcservices/TmTcBridge.cpp +++ b/src/fsfw/tmtcservices/TmTcBridge.cpp @@ -1,8 +1,9 @@ -#include "TmTcBridge.h" +#include "fsfw/tmtcservices/TmTcBridge.h" -#include "../ipc/QueueFactory.h" -#include "../serviceinterface/ServiceInterface.h" -#include "../globalfunctions/arrayprinter.h" +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/ipc/QueueFactory.h" +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/globalfunctions/arrayprinter.h" #define TMTCBRIDGE_WIRETAPPING 0 @@ -53,7 +54,7 @@ ReturnValue_t TmTcBridge::setMaxNumberOfPacketsStored( } ReturnValue_t TmTcBridge::initialize() { - tcStore = objectManager->get(tcStoreId); + tcStore = ObjectManager::instance()->get(tcStoreId); if (tcStore == nullptr) { #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "TmTcBridge::initialize: TC store invalid. Make sure" @@ -61,7 +62,7 @@ ReturnValue_t TmTcBridge::initialize() { #endif return ObjectManagerIF::CHILD_INIT_FAILED; } - tmStore = objectManager->get(tmStoreId); + tmStore = ObjectManager::instance()->get(tmStoreId); if (tmStore == nullptr) { #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "TmTcBridge::initialize: TM store invalid. Make sure" @@ -70,7 +71,7 @@ ReturnValue_t TmTcBridge::initialize() { return ObjectManagerIF::CHILD_INIT_FAILED; } AcceptsTelecommandsIF* tcDistributor = - objectManager->get(tcDestination); + ObjectManager::instance()->get(tcDestination); if (tcDistributor == nullptr) { #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "TmTcBridge::initialize: TC Distributor invalid" @@ -183,8 +184,11 @@ ReturnValue_t TmTcBridge::storeDownlinkData(TmTcMessage *message) { if(tmFifo->full()) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::debug << "TmTcBridge::storeDownlinkData: TM downlink max. number " - << "of stored packet IDs reached! " << std::endl; + sif::warning << "TmTcBridge::storeDownlinkData: TM downlink max. number " + "of stored packet IDs reached!" << std::endl; +#else + sif::printWarning("TmTcBridge::storeDownlinkData: TM downlink max. number " + "of stored packet IDs reached!\n"); #endif if(overwriteOld) { tmFifo->retrieve(&storeId); diff --git a/tmtcservices/TmTcBridge.h b/src/fsfw/tmtcservices/TmTcBridge.h similarity index 91% rename from tmtcservices/TmTcBridge.h rename to src/fsfw/tmtcservices/TmTcBridge.h index 0177648c..4980caff 100644 --- a/tmtcservices/TmTcBridge.h +++ b/src/fsfw/tmtcservices/TmTcBridge.h @@ -4,12 +4,12 @@ #include "AcceptsTelemetryIF.h" #include "AcceptsTelecommandsIF.h" -#include "../objectmanager/SystemObject.h" -#include "../tasks/ExecutableObjectIF.h" -#include "../ipc/MessageQueueIF.h" -#include "../storagemanager/StorageManagerIF.h" -#include "../container/DynamicFIFO.h" -#include "../tmtcservices/TmTcMessage.h" +#include "fsfw/objectmanager/SystemObject.h" +#include "fsfw/tasks/ExecutableObjectIF.h" +#include "fsfw/ipc/MessageQueueIF.h" +#include "fsfw/storagemanager/StorageManagerIF.h" +#include "fsfw/container/DynamicFIFO.h" +#include "fsfw/tmtcservices/TmTcMessage.h" class TmTcBridge : public AcceptsTelemetryIF, public AcceptsTelecommandsIF, @@ -19,7 +19,7 @@ class TmTcBridge : public AcceptsTelemetryIF, public: static constexpr uint8_t TMTC_RECEPTION_QUEUE_DEPTH = 20; static constexpr uint8_t LIMIT_STORED_DATA_SENT_PER_CYCLE = 15; - static constexpr uint8_t LIMIT_DOWNLINK_PACKETS_STORED = 20; + static constexpr uint8_t LIMIT_DOWNLINK_PACKETS_STORED = 200; static constexpr uint8_t DEFAULT_STORED_DATA_SENT_PER_CYCLE = 5; static constexpr uint8_t DEFAULT_DOWNLINK_PACKETS_STORED = 10; @@ -150,8 +150,7 @@ protected: void printData(uint8_t * data, size_t dataLen); /** - * This fifo can be used to store downlink data - * which can not be sent at the moment. + * This FIFO can be used to store downlink data which can not be sent at the moment. */ DynamicFIFO* tmFifo = nullptr; uint8_t sentPacketsPerCycle = DEFAULT_STORED_DATA_SENT_PER_CYCLE; diff --git a/tmtcservices/TmTcMessage.cpp b/src/fsfw/tmtcservices/TmTcMessage.cpp similarity index 86% rename from tmtcservices/TmTcMessage.cpp rename to src/fsfw/tmtcservices/TmTcMessage.cpp index ae028315..9dbd8fd8 100644 --- a/tmtcservices/TmTcMessage.cpp +++ b/src/fsfw/tmtcservices/TmTcMessage.cpp @@ -1,4 +1,4 @@ -#include "TmTcMessage.h" +#include "fsfw/tmtcservices/TmTcMessage.h" #include @@ -21,7 +21,7 @@ TmTcMessage::TmTcMessage(store_address_t storeId) { this->setStorageId(storeId); } -size_t TmTcMessage::getMinimumMessageSize() { +size_t TmTcMessage::getMinimumMessageSize() const { return this->HEADER_SIZE + sizeof(store_address_t); } diff --git a/tmtcservices/TmTcMessage.h b/src/fsfw/tmtcservices/TmTcMessage.h similarity index 91% rename from tmtcservices/TmTcMessage.h rename to src/fsfw/tmtcservices/TmTcMessage.h index 41fe198a..5e6647fe 100644 --- a/tmtcservices/TmTcMessage.h +++ b/src/fsfw/tmtcservices/TmTcMessage.h @@ -1,8 +1,8 @@ #ifndef FSFW_TMTCSERVICES_TMTCMESSAGE_H_ #define FSFW_TMTCSERVICES_TMTCMESSAGE_H_ -#include "../ipc/MessageQueueMessage.h" -#include "../storagemanager/StorageManagerIF.h" +#include "fsfw/ipc/MessageQueueMessage.h" +#include "fsfw/storagemanager/StorageManagerIF.h" /** * @brief This message class is used to pass Telecommand and Telemetry * packets between tasks. @@ -18,7 +18,7 @@ protected: * @brief This call always returns the same fixed size of the message. * @return Returns HEADER_SIZE + @c sizeof(store_address_t). */ - size_t getMinimumMessageSize(); + size_t getMinimumMessageSize() const override; public: /** * @brief In the default constructor, only the message_size is set. diff --git a/tmtcservices/VerificationCodes.h b/src/fsfw/tmtcservices/VerificationCodes.h similarity index 100% rename from tmtcservices/VerificationCodes.h rename to src/fsfw/tmtcservices/VerificationCodes.h diff --git a/tmtcservices/VerificationReporter.cpp b/src/fsfw/tmtcservices/VerificationReporter.cpp similarity index 78% rename from tmtcservices/VerificationReporter.cpp rename to src/fsfw/tmtcservices/VerificationReporter.cpp index ff6f54f9..2b371d1e 100644 --- a/tmtcservices/VerificationReporter.cpp +++ b/src/fsfw/tmtcservices/VerificationReporter.cpp @@ -1,10 +1,11 @@ -#include "VerificationReporter.h" -#include "AcceptsVerifyMessageIF.h" -#include "PusVerificationReport.h" +#include "fsfw/tmtcservices/VerificationReporter.h" +#include "fsfw/tmtcservices/AcceptsVerifyMessageIF.h" +#include "fsfw/tmtcservices/PusVerificationReport.h" -#include "../ipc/MessageQueueIF.h" -#include "../serviceinterface/ServiceInterfaceStream.h" -#include "../objectmanager/frameworkObjects.h" +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/ipc/MessageQueueIF.h" +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/objectmanager/frameworkObjects.h" object_id_t VerificationReporter::messageReceiver = objects::PUS_SERVICE_1_VERIFICATION; @@ -16,14 +17,17 @@ VerificationReporter::VerificationReporter() : VerificationReporter::~VerificationReporter() {} void VerificationReporter::sendSuccessReport(uint8_t set_report_id, - TcPacketBase* current_packet, uint8_t set_step) { + TcPacketBase* currentPacket, uint8_t set_step) { if (acknowledgeQueue == MessageQueueIF::NO_QUEUE) { this->initialize(); } + if(currentPacket == nullptr) { + return; + } PusVerificationMessage message(set_report_id, - current_packet->getAcknowledgeFlags(), - current_packet->getPacketId(), - current_packet->getPacketSequenceControl(), 0, set_step); + currentPacket->getAcknowledgeFlags(), + currentPacket->getPacketId(), + currentPacket->getPacketSequenceControl(), 0, set_step); ReturnValue_t status = MessageQueueSenderIF::sendMessage(acknowledgeQueue, &message); if (status != HasReturnvaluesIF::RETURN_OK) { @@ -55,15 +59,18 @@ void VerificationReporter::sendSuccessReport(uint8_t set_report_id, } void VerificationReporter::sendFailureReport(uint8_t report_id, - TcPacketBase* current_packet, ReturnValue_t error_code, uint8_t step, + TcPacketBase* currentPacket, ReturnValue_t error_code, uint8_t step, uint32_t parameter1, uint32_t parameter2) { if (acknowledgeQueue == MessageQueueIF::NO_QUEUE) { this->initialize(); } + if(currentPacket == nullptr) { + return; + } PusVerificationMessage message(report_id, - current_packet->getAcknowledgeFlags(), - current_packet->getPacketId(), - current_packet->getPacketSequenceControl(), error_code, step, + currentPacket->getAcknowledgeFlags(), + currentPacket->getPacketId(), + currentPacket->getPacketSequenceControl(), error_code, step, parameter1, parameter2); ReturnValue_t status = MessageQueueSenderIF::sendMessage(acknowledgeQueue, &message); @@ -104,7 +111,7 @@ void VerificationReporter::initialize() { #endif return; } - AcceptsVerifyMessageIF* temp = objectManager->get( + AcceptsVerifyMessageIF* temp = ObjectManager::instance()->get( messageReceiver); if (temp == nullptr) { #if FSFW_CPP_OSTREAM_ENABLED == 1 diff --git a/tmtcservices/VerificationReporter.h b/src/fsfw/tmtcservices/VerificationReporter.h similarity index 97% rename from tmtcservices/VerificationReporter.h rename to src/fsfw/tmtcservices/VerificationReporter.h index f26fa54f..4a64d3df 100644 --- a/tmtcservices/VerificationReporter.h +++ b/src/fsfw/tmtcservices/VerificationReporter.h @@ -2,7 +2,7 @@ #define FSFW_TMTCSERVICES_VERIFICATIONREPORTER_H_ #include "PusVerificationReport.h" -#include "../objectmanager/ObjectManagerIF.h" +#include "fsfw/objectmanager/ObjectManagerIF.h" namespace Factory{ void setStaticFrameworkObjectIds(); diff --git a/tcdistribution/CMakeLists.txt b/tcdistribution/CMakeLists.txt deleted file mode 100644 index 17dc186c..00000000 --- a/tcdistribution/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -target_sources(${LIB_FSFW_NAME} - PRIVATE - CCSDSDistributor.cpp - PUSDistributor.cpp - TcDistributor.cpp - TcPacketCheck.cpp -) diff --git a/tcdistribution/TcPacketCheck.cpp b/tcdistribution/TcPacketCheck.cpp deleted file mode 100644 index 38ed04aa..00000000 --- a/tcdistribution/TcPacketCheck.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include "TcPacketCheck.h" - -#include "../globalfunctions/CRC.h" -#include "../serviceinterface/ServiceInterfaceStream.h" -#include "../storagemanager/StorageManagerIF.h" -#include "../tmtcservices/VerificationCodes.h" - -TcPacketCheck::TcPacketCheck( uint16_t setApid ) : apid(setApid) { -} - -ReturnValue_t TcPacketCheck::checkPacket( TcPacketStored* currentPacket ) { - uint16_t calculated_crc = CRC::crc16ccitt( currentPacket->getWholeData(), - currentPacket->getFullSize() ); - if ( calculated_crc != 0 ) { - return INCORRECT_CHECKSUM; - } - bool condition = (not currentPacket->hasSecondaryHeader()) or - (currentPacket->getPacketVersionNumber() != CCSDS_VERSION_NUMBER) or - (not currentPacket->isTelecommand()); - if ( condition ) { - return INCORRECT_PRIMARY_HEADER; - } - if ( currentPacket->getAPID() != this->apid ) - return ILLEGAL_APID; - - if ( not currentPacket->isSizeCorrect() ) { - return INCOMPLETE_PACKET; - } - condition = (currentPacket->getSecondaryHeaderFlag() != CCSDS_SECONDARY_HEADER_FLAG) || - (currentPacket->getPusVersionNumber() != PUS_VERSION_NUMBER); - if ( condition ) { - return INCORRECT_SECONDARY_HEADER; - } - return RETURN_OK; -} - -uint16_t TcPacketCheck::getApid() const { - return apid; -} diff --git a/tcdistribution/TcPacketCheck.h b/tcdistribution/TcPacketCheck.h deleted file mode 100644 index 703bb1bb..00000000 --- a/tcdistribution/TcPacketCheck.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef FSFW_TCDISTRIBUTION_TCPACKETCHECK_H_ -#define FSFW_TCDISTRIBUTION_TCPACKETCHECK_H_ - -#include "../returnvalues/HasReturnvaluesIF.h" -#include "../tmtcpacket/pus/TcPacketStored.h" -#include "../tmtcservices/PusVerificationReport.h" - -/** - * This class performs a formal packet check for incoming PUS Telecommand Packets. - * Currently, it only checks if the APID and CRC are correct. - * @ingroup tc_distribution - */ -class TcPacketCheck : public HasReturnvaluesIF { -protected: - /** - * Describes the version number a packet must have to pass. - */ - static constexpr uint8_t CCSDS_VERSION_NUMBER = 0; - /** - * Describes the secondary header a packet must have to pass. - */ - static constexpr uint8_t CCSDS_SECONDARY_HEADER_FLAG = 0; - /** - * Describes the TC Packet PUS Version Number a packet must have to pass. - */ - static constexpr uint8_t PUS_VERSION_NUMBER = 1; - /** - * The packet id each correct packet should have. - * It is composed of the APID and some static fields. - */ - uint16_t apid; -public: - static const uint8_t INTERFACE_ID = CLASS_ID::TC_PACKET_CHECK; - static const ReturnValue_t ILLEGAL_APID = MAKE_RETURN_CODE( 0 ); - static const ReturnValue_t INCOMPLETE_PACKET = MAKE_RETURN_CODE( 1 ); - static const ReturnValue_t INCORRECT_CHECKSUM = MAKE_RETURN_CODE( 2 ); - static const ReturnValue_t ILLEGAL_PACKET_TYPE = MAKE_RETURN_CODE( 3 ); - static const ReturnValue_t ILLEGAL_PACKET_SUBTYPE = MAKE_RETURN_CODE( 4 ); - static const ReturnValue_t INCORRECT_PRIMARY_HEADER = MAKE_RETURN_CODE( 5 ); - static const ReturnValue_t INCORRECT_SECONDARY_HEADER = MAKE_RETURN_CODE( 6 ); - /** - * The constructor only sets the APID attribute. - * @param set_apid The APID to set. - */ - TcPacketCheck( uint16_t setApid ); - /** - * This is the actual method to formally check a certain Telecommand Packet. - * The packet's Application Data can not be checked here. - * @param current_packet The packt to check - * @return - @c RETURN_OK on success. - * - @c INCORRECT_CHECKSUM if checksum is invalid. - * - @c ILLEGAL_APID if APID does not match. - */ - ReturnValue_t checkPacket( TcPacketStored* currentPacket ); - - uint16_t getApid() const; -}; - - -#endif /* FSFW_TCDISTRIBUTION_TCPACKETCHECK_H_ */ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 00000000..febd4f0a --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(src) diff --git a/tests/src/CMakeLists.txt b/tests/src/CMakeLists.txt new file mode 100644 index 00000000..6673f1e4 --- /dev/null +++ b/tests/src/CMakeLists.txt @@ -0,0 +1,9 @@ +target_include_directories(${LIB_FSFW_NAME} PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} +) + +target_include_directories(${LIB_FSFW_NAME} INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR} +) + +add_subdirectory(fsfw_tests) diff --git a/tests/src/fsfw_tests/CMakeLists.txt b/tests/src/fsfw_tests/CMakeLists.txt new file mode 100644 index 00000000..f6e1b8ab --- /dev/null +++ b/tests/src/fsfw_tests/CMakeLists.txt @@ -0,0 +1,9 @@ +if(FSFW_ADD_INTERNAL_TESTS) + add_subdirectory(internal) +endif() + +if(FSFW_BUILD_UNITTESTS) + add_subdirectory(unit) +else() + add_subdirectory(integration) +endif() diff --git a/tests/src/fsfw_tests/integration/CMakeLists.txt b/tests/src/fsfw_tests/integration/CMakeLists.txt new file mode 100644 index 00000000..e44fbee7 --- /dev/null +++ b/tests/src/fsfw_tests/integration/CMakeLists.txt @@ -0,0 +1,4 @@ +add_subdirectory(assemblies) +add_subdirectory(controller) +add_subdirectory(devices) +add_subdirectory(task) diff --git a/tests/src/fsfw_tests/integration/assemblies/CMakeLists.txt b/tests/src/fsfw_tests/integration/assemblies/CMakeLists.txt new file mode 100644 index 00000000..22c06600 --- /dev/null +++ b/tests/src/fsfw_tests/integration/assemblies/CMakeLists.txt @@ -0,0 +1,3 @@ +target_sources(${LIB_FSFW_NAME} PRIVATE + TestAssembly.cpp +) \ No newline at end of file diff --git a/tests/src/fsfw_tests/integration/assemblies/TestAssembly.cpp b/tests/src/fsfw_tests/integration/assemblies/TestAssembly.cpp new file mode 100644 index 00000000..0ead4bfd --- /dev/null +++ b/tests/src/fsfw_tests/integration/assemblies/TestAssembly.cpp @@ -0,0 +1,201 @@ +#include "TestAssembly.h" + +#include + + +TestAssembly::TestAssembly(object_id_t objectId, object_id_t parentId, object_id_t testDevice0, + object_id_t testDevice1): + AssemblyBase(objectId, parentId), deviceHandler0Id(testDevice0), + deviceHandler1Id(testDevice1) { + ModeListEntry newModeListEntry; + newModeListEntry.setObject(testDevice0); + newModeListEntry.setMode(MODE_OFF); + newModeListEntry.setSubmode(SUBMODE_NONE); + + commandTable.insert(newModeListEntry); + + newModeListEntry.setObject(testDevice1); + newModeListEntry.setMode(MODE_OFF); + newModeListEntry.setSubmode(SUBMODE_NONE); + + commandTable.insert(newModeListEntry); + +} + +TestAssembly::~TestAssembly() { +} + +ReturnValue_t TestAssembly::commandChildren(Mode_t mode, + Submode_t submode) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "TestAssembly: Received command to go to mode " << mode << + " submode " << (int) submode << std::endl; +#else + sif::printInfo("TestAssembly: Received command to go to mode %d submode %d\n", mode, submode); +#endif + ReturnValue_t result = RETURN_OK; + if(mode == MODE_OFF){ + commandTable[0].setMode(MODE_OFF); + commandTable[0].setSubmode(SUBMODE_NONE); + commandTable[1].setMode(MODE_OFF); + commandTable[1].setSubmode(SUBMODE_NONE); + } + else if(mode == DeviceHandlerIF::MODE_NORMAL) { + if(submode == submodes::SINGLE){ + commandTable[0].setMode(MODE_OFF); + commandTable[0].setSubmode(SUBMODE_NONE); + commandTable[1].setMode(MODE_OFF); + commandTable[1].setSubmode(SUBMODE_NONE); + // We try to prefer 0 here but we try to switch to 1 even if it might fail + if(isDeviceAvailable(deviceHandler0Id)) { + if (childrenMap[deviceHandler0Id].mode == MODE_ON) { + commandTable[0].setMode(mode); + commandTable[0].setSubmode(SUBMODE_NONE); + } + else { + commandTable[0].setMode(MODE_ON); + commandTable[0].setSubmode(SUBMODE_NONE); + result = NEED_SECOND_STEP; + } + } + else { + if (childrenMap[deviceHandler1Id].mode == MODE_ON) { + commandTable[1].setMode(mode); + commandTable[1].setSubmode(SUBMODE_NONE); + } + else{ + commandTable[1].setMode(MODE_ON); + commandTable[1].setSubmode(SUBMODE_NONE); + result = NEED_SECOND_STEP; + } + } + } + else{ + // Dual Mode Normal + if (childrenMap[deviceHandler0Id].mode == MODE_ON) { + commandTable[0].setMode(mode); + commandTable[0].setSubmode(SUBMODE_NONE); + } + else{ + commandTable[0].setMode(MODE_ON); + commandTable[0].setSubmode(SUBMODE_NONE); + result = NEED_SECOND_STEP; + } + if (childrenMap[deviceHandler1Id].mode == MODE_ON) { + commandTable[1].setMode(mode); + commandTable[1].setSubmode(SUBMODE_NONE); + } + else{ + commandTable[1].setMode(MODE_ON); + commandTable[1].setSubmode(SUBMODE_NONE); + result = NEED_SECOND_STEP; + } + } + } + else{ + //Mode ON + if(submode == submodes::SINGLE){ + commandTable[0].setMode(MODE_OFF); + commandTable[0].setSubmode(SUBMODE_NONE); + commandTable[1].setMode(MODE_OFF); + commandTable[1].setSubmode(SUBMODE_NONE); + // We try to prefer 0 here but we try to switch to 1 even if it might fail + if(isDeviceAvailable(deviceHandler0Id)){ + commandTable[0].setMode(MODE_ON); + commandTable[0].setSubmode(SUBMODE_NONE); + } + else{ + commandTable[1].setMode(MODE_ON); + commandTable[1].setSubmode(SUBMODE_NONE); + } + } + else{ + commandTable[0].setMode(MODE_ON); + commandTable[0].setSubmode(SUBMODE_NONE); + commandTable[1].setMode(MODE_ON); + commandTable[1].setSubmode(SUBMODE_NONE); + } + } + + + + HybridIterator iter(commandTable.begin(), + commandTable.end()); + executeTable(iter); + return result; +} + +ReturnValue_t TestAssembly::isModeCombinationValid(Mode_t mode, + Submode_t submode) { + switch (mode) { + case MODE_OFF: + if (submode == SUBMODE_NONE) { + return RETURN_OK; + } else { + return INVALID_SUBMODE; + } + case DeviceHandlerIF::MODE_NORMAL: + case MODE_ON: + if (submode < 3) { + return RETURN_OK; + } else { + return INVALID_SUBMODE; + } + } + return INVALID_MODE; +} + +ReturnValue_t TestAssembly::initialize() { + ReturnValue_t result = AssemblyBase::initialize(); + if(result != RETURN_OK){ + return result; + } + handler0 = ObjectManager::instance()->get(deviceHandler0Id); + handler1 = ObjectManager::instance()->get(deviceHandler1Id); + if((handler0 == nullptr) or (handler1 == nullptr)){ + return HasReturnvaluesIF::RETURN_FAILED; + } + + handler0->setParentQueue(this->getCommandQueue()); + handler1->setParentQueue(this->getCommandQueue()); + + + result = registerChild(deviceHandler0Id); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = registerChild(deviceHandler1Id); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + return result; +} + +ReturnValue_t TestAssembly::checkChildrenStateOn( + Mode_t wantedMode, Submode_t wantedSubmode) { + if(submode == submodes::DUAL){ + for(const auto& info:childrenMap) { + if(info.second.mode != wantedMode or info.second.mode != wantedSubmode){ + return NOT_ENOUGH_CHILDREN_IN_CORRECT_STATE; + } + } + return RETURN_OK; + } + else if(submode == submodes::SINGLE) { + for(const auto& info:childrenMap) { + if(info.second.mode == wantedMode and info.second.mode != wantedSubmode){ + return RETURN_OK; + } + } + } + return INVALID_SUBMODE; +} + +bool TestAssembly::isDeviceAvailable(object_id_t object) { + if(healthHelper.healthTable->getHealth(object) == HasHealthIF::HEALTHY){ + return true; + } + else{ + return false; + } +} diff --git a/tests/src/fsfw_tests/integration/assemblies/TestAssembly.h b/tests/src/fsfw_tests/integration/assemblies/TestAssembly.h new file mode 100644 index 00000000..3cc6f450 --- /dev/null +++ b/tests/src/fsfw_tests/integration/assemblies/TestAssembly.h @@ -0,0 +1,56 @@ +#ifndef MISSION_ASSEMBLIES_TESTASSEMBLY_H_ +#define MISSION_ASSEMBLIES_TESTASSEMBLY_H_ + +#include +#include "../devices/TestDeviceHandler.h" + +class TestAssembly: public AssemblyBase { +public: + TestAssembly(object_id_t objectId, object_id_t parentId, object_id_t testDevice0, + object_id_t testDevice1); + virtual ~TestAssembly(); + ReturnValue_t initialize() override; + + enum submodes: Submode_t{ + SINGLE = 0, + DUAL = 1 + }; + +protected: + /** + * Command children to reach [mode,submode] combination + * Can be done by setting #commandsOutstanding correctly, + * or using executeTable() + * @param mode + * @param submode + * @return + * - @c RETURN_OK if ok + * - @c NEED_SECOND_STEP if children need to be commanded again + */ + ReturnValue_t commandChildren(Mode_t mode, Submode_t submode) override; + /** + * Check whether desired assembly mode was achieved by checking the modes + * or/and health states of child device handlers. + * The assembly template class will also call this function if a health + * or mode change of a child device handler was detected. + * @param wantedMode + * @param wantedSubmode + * @return + */ + ReturnValue_t isModeCombinationValid(Mode_t mode, Submode_t submode) + override; + + ReturnValue_t checkChildrenStateOn(Mode_t wantedMode, + Submode_t wantedSubmode) override; +private: + FixedArrayList commandTable; + object_id_t deviceHandler0Id = 0; + object_id_t deviceHandler1Id = 0; + TestDevice* handler0 = nullptr; + TestDevice* handler1 = nullptr; + + + bool isDeviceAvailable(object_id_t object); +}; + +#endif /* MISSION_ASSEMBLIES_TESTASSEMBLY_H_ */ diff --git a/tests/src/fsfw_tests/integration/controller/CMakeLists.txt b/tests/src/fsfw_tests/integration/controller/CMakeLists.txt new file mode 100644 index 00000000..f5655b71 --- /dev/null +++ b/tests/src/fsfw_tests/integration/controller/CMakeLists.txt @@ -0,0 +1,3 @@ +target_sources(${LIB_FSFW_NAME} PRIVATE + TestController.cpp +) \ No newline at end of file diff --git a/tests/src/fsfw_tests/integration/controller/TestController.cpp b/tests/src/fsfw_tests/integration/controller/TestController.cpp new file mode 100644 index 00000000..8c2c9330 --- /dev/null +++ b/tests/src/fsfw_tests/integration/controller/TestController.cpp @@ -0,0 +1,48 @@ +#include "TestController.h" + +#include +#include +#include + +TestController::TestController(object_id_t objectId, object_id_t parentId, + size_t commandQueueDepth): + ExtendedControllerBase(objectId, parentId, commandQueueDepth) { +} + +TestController::~TestController() { +} + +ReturnValue_t TestController::handleCommandMessage(CommandMessage *message) { + return HasReturnvaluesIF::RETURN_OK; +} + +void TestController::performControlOperation() { + +} + +void TestController::handleChangedDataset(sid_t sid, store_address_t storeId, bool* clearMessage) { + +} + +void TestController::handleChangedPoolVariable(gp_id_t globPoolId, store_address_t storeId, + bool* clearMessage) { +} + +LocalPoolDataSetBase* TestController::getDataSetHandle(sid_t sid) { + return nullptr; +} + +ReturnValue_t TestController::initializeLocalDataPool(localpool::DataPool &localDataPoolMap, + LocalDataPoolManager &poolManager) { + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t TestController::initializeAfterTaskCreation() { + return ExtendedControllerBase::initializeAfterTaskCreation(); +} + +ReturnValue_t TestController::checkModeCommand(Mode_t mode, Submode_t submode, + uint32_t *msToReachTheMode) { + return HasReturnvaluesIF::RETURN_OK; +} + diff --git a/tests/src/fsfw_tests/integration/controller/TestController.h b/tests/src/fsfw_tests/integration/controller/TestController.h new file mode 100644 index 00000000..7d94367d --- /dev/null +++ b/tests/src/fsfw_tests/integration/controller/TestController.h @@ -0,0 +1,38 @@ +#ifndef MISSION_CONTROLLER_TESTCONTROLLER_H_ +#define MISSION_CONTROLLER_TESTCONTROLLER_H_ + +#include "../devices/devicedefinitions/testDeviceDefinitions.h" +#include + + +class TestController: + public ExtendedControllerBase { +public: + TestController(object_id_t objectId, object_id_t parentId, size_t commandQueueDepth = 10); + virtual~ TestController(); +protected: + + // Extended Controller Base overrides + ReturnValue_t handleCommandMessage(CommandMessage *message) override; + void performControlOperation() override; + + // HasLocalDatapoolIF callbacks + virtual void handleChangedDataset(sid_t sid, store_address_t storeId, + bool* clearMessage) override; + virtual void handleChangedPoolVariable(gp_id_t globPoolId, store_address_t storeId, + bool* clearMessage) override; + + LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override; + ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap, + LocalDataPoolManager& poolManager) override; + + ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, + uint32_t *msToReachTheMode) override; + + ReturnValue_t initializeAfterTaskCreation() override; + +private: +}; + + +#endif /* MISSION_CONTROLLER_TESTCONTROLLER_H_ */ diff --git a/tests/src/fsfw_tests/integration/controller/ctrldefinitions/testCtrlDefinitions.h b/tests/src/fsfw_tests/integration/controller/ctrldefinitions/testCtrlDefinitions.h new file mode 100644 index 00000000..7bf045df --- /dev/null +++ b/tests/src/fsfw_tests/integration/controller/ctrldefinitions/testCtrlDefinitions.h @@ -0,0 +1,18 @@ +#ifndef MISSION_CONTROLLER_CTRLDEFINITIONS_TESTCTRLDEFINITIONS_H_ +#define MISSION_CONTROLLER_CTRLDEFINITIONS_TESTCTRLDEFINITIONS_H_ + +#include +#include + +namespace testcontroller { + +enum sourceObjectIds: object_id_t { + DEVICE_0_ID = objects::TEST_DEVICE_HANDLER_0, + DEVICE_1_ID = objects::TEST_DEVICE_HANDLER_1, +}; + +} + + + +#endif /* MISSION_CONTROLLER_CTRLDEFINITIONS_TESTCTRLDEFINITIONS_H_ */ diff --git a/tests/src/fsfw_tests/integration/devices/CMakeLists.txt b/tests/src/fsfw_tests/integration/devices/CMakeLists.txt new file mode 100644 index 00000000..cfd238d2 --- /dev/null +++ b/tests/src/fsfw_tests/integration/devices/CMakeLists.txt @@ -0,0 +1,5 @@ +target_sources(${LIB_FSFW_NAME} PRIVATE + TestCookie.cpp + TestDeviceHandler.cpp + TestEchoComIF.cpp +) diff --git a/tests/src/fsfw_tests/integration/devices/TestCookie.cpp b/tests/src/fsfw_tests/integration/devices/TestCookie.cpp new file mode 100644 index 00000000..91098f80 --- /dev/null +++ b/tests/src/fsfw_tests/integration/devices/TestCookie.cpp @@ -0,0 +1,14 @@ +#include "TestCookie.h" + +TestCookie::TestCookie(address_t address, size_t replyMaxLen): + address(address), replyMaxLen(replyMaxLen) {} + +TestCookie::~TestCookie() {} + +address_t TestCookie::getAddress() const { + return address; +} + +size_t TestCookie::getReplyMaxLen() const { + return replyMaxLen; +} diff --git a/tests/src/fsfw_tests/integration/devices/TestCookie.h b/tests/src/fsfw_tests/integration/devices/TestCookie.h new file mode 100644 index 00000000..5dac3f25 --- /dev/null +++ b/tests/src/fsfw_tests/integration/devices/TestCookie.h @@ -0,0 +1,22 @@ +#ifndef MISSION_DEVICES_TESTCOOKIE_H_ +#define MISSION_DEVICES_TESTCOOKIE_H_ + +#include +#include + +/** + * @brief Really simple cookie which does not do a lot. + */ +class TestCookie: public CookieIF { +public: + TestCookie(address_t address, size_t maxReplyLen); + virtual ~TestCookie(); + + address_t getAddress() const; + size_t getReplyMaxLen() const; +private: + address_t address = 0; + size_t replyMaxLen = 0; +}; + +#endif /* MISSION_DEVICES_TESTCOOKIE_H_ */ diff --git a/tests/src/fsfw_tests/integration/devices/TestDeviceHandler.cpp b/tests/src/fsfw_tests/integration/devices/TestDeviceHandler.cpp new file mode 100644 index 00000000..46138c56 --- /dev/null +++ b/tests/src/fsfw_tests/integration/devices/TestDeviceHandler.cpp @@ -0,0 +1,798 @@ +#include "TestDeviceHandler.h" +#include "FSFWConfig.h" + +#include "fsfw/datapool/PoolReadGuard.h" + +#include + +TestDevice::TestDevice(object_id_t objectId, object_id_t comIF, + CookieIF * cookie, testdevice::DeviceIndex deviceIdx, bool fullInfoPrintout, + bool changingDataset): + DeviceHandlerBase(objectId, comIF, cookie), deviceIdx(deviceIdx), + dataset(this), fullInfoPrintout(fullInfoPrintout) { +} + +TestDevice::~TestDevice() {} + +void TestDevice::performOperationHook() { + if(periodicPrintout) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "TestDevice" << deviceIdx << "::performOperationHook: Alive!" << std::endl; +#else + sif::printInfo("TestDevice%d::performOperationHook: Alive!", deviceIdx); +#endif + } + + if(oneShot) { + oneShot = false; + } +} + + +void TestDevice::doStartUp() { + if(fullInfoPrintout) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "TestDevice" << deviceIdx << "::doStartUp: Switching On" << std::endl; +#else + sif::printInfo("TestDevice%d::doStartUp: Switching On\n", static_cast(deviceIdx)); +#endif + } + + setMode(_MODE_TO_ON); + return; +} + + +void TestDevice::doShutDown() { + if(fullInfoPrintout) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "TestDevice" << deviceIdx << "::doShutDown: Switching Off" << std::endl; +#else + sif::printInfo("TestDevice%d::doShutDown: Switching Off\n", static_cast(deviceIdx)); +#endif + } + + setMode(_MODE_SHUT_DOWN); + return; +} + + +ReturnValue_t TestDevice::buildNormalDeviceCommand(DeviceCommandId_t* id) { + using namespace testdevice; + *id = TEST_NORMAL_MODE_CMD; + if(DeviceHandlerBase::isAwaitingReply()) { + return NOTHING_TO_SEND; + } + return buildCommandFromCommand(*id, nullptr, 0); +} + +ReturnValue_t TestDevice::buildTransitionDeviceCommand(DeviceCommandId_t* id) { + if(mode == _MODE_TO_ON) { + if(fullInfoPrintout) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "TestDevice" << deviceIdx << "::buildTransitionDeviceCommand: Was called" + " from _MODE_TO_ON mode" << std::endl; +#else + sif::printInfo("TestDevice%d::buildTransitionDeviceCommand: " + "Was called from _MODE_TO_ON mode\n", deviceIdx); +#endif + } + + } + if(mode == _MODE_TO_NORMAL) { + if(fullInfoPrintout) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "TestDevice" << deviceIdx << "::buildTransitionDeviceCommand: Was called " + "from _MODE_TO_NORMAL mode" << std::endl; +#else + sif::printInfo("TestDevice%d::buildTransitionDeviceCommand: Was called from " + " _MODE_TO_NORMAL mode\n", deviceIdx); +#endif + } + + setMode(MODE_NORMAL); + } + if(mode == _MODE_SHUT_DOWN) { + if(fullInfoPrintout) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "TestDevice" << deviceIdx << "::buildTransitionDeviceCommand: Was called " + "from _MODE_SHUT_DOWN mode" << std::endl; +#else + sif::printInfo("TestDevice%d::buildTransitionDeviceCommand: Was called from " + "_MODE_SHUT_DOWN mode\n", deviceIdx); +#endif + } + + setMode(MODE_OFF); + } + return NOTHING_TO_SEND; +} + +void TestDevice::doTransition(Mode_t modeFrom, Submode_t submodeFrom) { + if(mode == _MODE_TO_NORMAL) { + if(fullInfoPrintout) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "TestDevice" << deviceIdx << "::doTransition: Custom transition to " + "normal mode" << std::endl; +#else + sif::printInfo("TestDevice%d::doTransition: Custom transition to normal mode\n", + deviceIdx); +#endif + } + + } + else { + DeviceHandlerBase::doTransition(modeFrom, submodeFrom); + } +} + +ReturnValue_t TestDevice::buildCommandFromCommand( + DeviceCommandId_t deviceCommand, const uint8_t* commandData, + size_t commandDataLen) { + using namespace testdevice; + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + switch(deviceCommand) { + case(TEST_NORMAL_MODE_CMD): { + commandSent = true; + result = buildNormalModeCommand(deviceCommand, commandData, commandDataLen); + break; + } + + case(TEST_COMMAND_0): { + commandSent = true; + result = buildTestCommand0(deviceCommand, commandData, commandDataLen); + break; + } + + case(TEST_COMMAND_1): { + commandSent = true; + result = buildTestCommand1(deviceCommand, commandData, commandDataLen); + break; + } + case(TEST_NOTIF_SNAPSHOT_VAR): { + if(changingDatasets) { + changingDatasets = false; + } + + PoolReadGuard readHelper(&dataset.testUint8Var); + if(deviceIdx == testdevice::DeviceIndex::DEVICE_0) { + /* This will trigger a variable notification to the demo controller */ + dataset.testUint8Var = 220; + dataset.testUint8Var.setValid(true); + } + else if(deviceIdx == testdevice::DeviceIndex::DEVICE_1) { + /* This will trigger a variable snapshot to the demo controller */ + dataset.testUint8Var = 30; + dataset.testUint8Var.setValid(true); + } + + break; + } + case(TEST_NOTIF_SNAPSHOT_SET): { + if(changingDatasets) { + changingDatasets = false; + } + + PoolReadGuard readHelper(&dataset.testFloat3Vec); + + if(deviceIdx == testdevice::DeviceIndex::DEVICE_0) { + /* This will trigger a variable notification to the demo controller */ + dataset.testFloat3Vec.value[0] = 60; + dataset.testFloat3Vec.value[1] = 70; + dataset.testFloat3Vec.value[2] = 55; + dataset.testFloat3Vec.setValid(true); + } + else if(deviceIdx == testdevice::DeviceIndex::DEVICE_1) { + /* This will trigger a variable notification to the demo controller */ + dataset.testFloat3Vec.value[0] = -60; + dataset.testFloat3Vec.value[1] = -70; + dataset.testFloat3Vec.value[2] = -55; + dataset.testFloat3Vec.setValid(true); + } + break; + } + default: + result = DeviceHandlerIF::COMMAND_NOT_SUPPORTED; + } + return result; +} + + +ReturnValue_t TestDevice::buildNormalModeCommand(DeviceCommandId_t deviceCommand, + const uint8_t* commandData, size_t commandDataLen) { + if(fullInfoPrintout) { +#if OBSW_VERBOSE_LEVEL >= 3 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "TestDevice::buildTestCommand1: Building normal command" << std::endl; +#else + sif::printInfo("TestDevice::buildTestCommand1: Building command from TEST_COMMAND_1\n"); +#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ +#endif /* OBSW_VERBOSE_LEVEL >= 3 */ + } + + if(commandDataLen > MAX_BUFFER_SIZE - sizeof(DeviceCommandId_t)) { + return DeviceHandlerIF::INVALID_NUMBER_OR_LENGTH_OF_PARAMETERS; + } + /* The command is passed on in the command buffer as it is */ + passOnCommand(deviceCommand, commandData, commandDataLen); + return RETURN_OK; +} + +ReturnValue_t TestDevice::buildTestCommand0(DeviceCommandId_t deviceCommand, + const uint8_t* commandData, size_t commandDataLen) { + using namespace testdevice; + if(fullInfoPrintout) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "TestDevice" << deviceIdx << "::buildTestCommand0: Executing simple command " + " with completion reply" << std::endl; +#else + sif::printInfo("TestDevice%d::buildTestCommand0: Executing simple command with " + "completion reply\n", deviceIdx); +#endif + } + + if(commandDataLen > MAX_BUFFER_SIZE - sizeof(DeviceCommandId_t)) { + return DeviceHandlerIF::INVALID_NUMBER_OR_LENGTH_OF_PARAMETERS; + } + + /* The command is passed on in the command buffer as it is */ + passOnCommand(deviceCommand, commandData, commandDataLen); + return RETURN_OK; +} + +ReturnValue_t TestDevice::buildTestCommand1(DeviceCommandId_t deviceCommand, + const uint8_t* commandData, + size_t commandDataLen) { + using namespace testdevice; + if(commandDataLen < 7) { + return DeviceHandlerIF::INVALID_NUMBER_OR_LENGTH_OF_PARAMETERS; + } + if(fullInfoPrintout) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "TestDevice" << deviceIdx << "::buildTestCommand1: Executing command with " + "data reply" << std::endl; +#else + sif::printInfo("TestDevice%d:buildTestCommand1: Executing command with data reply\n", + deviceIdx); +#endif + } + + deviceCommand = EndianConverter::convertBigEndian(deviceCommand); + memcpy(commandBuffer, &deviceCommand, sizeof(deviceCommand)); + + /* Assign and check parameters */ + uint16_t parameter1 = 0; + size_t size = commandDataLen; + ReturnValue_t result = SerializeAdapter::deSerialize(¶meter1, + &commandData, &size, SerializeIF::Endianness::BIG); + if(result == HasReturnvaluesIF::RETURN_FAILED) { + return result; + } + + /* Parameter 1 needs to be correct */ + if(parameter1 != testdevice::COMMAND_1_PARAM1) { + return DeviceHandlerIF::INVALID_COMMAND_PARAMETER; + } + uint64_t parameter2 = 0; + result = SerializeAdapter::deSerialize(¶meter2, + &commandData, &size, SerializeIF::Endianness::BIG); + if(parameter2!= testdevice::COMMAND_1_PARAM2){ + return DeviceHandlerIF::INVALID_COMMAND_PARAMETER; + } + + /* Pass on the parameters to the Echo IF */ + commandBuffer[4] = (parameter1 & 0xFF00) >> 8; + commandBuffer[5] = (parameter1 & 0xFF); + parameter2 = EndianConverter::convertBigEndian(parameter2); + memcpy(commandBuffer + 6, ¶meter2, sizeof(parameter2)); + rawPacket = commandBuffer; + rawPacketLen = sizeof(deviceCommand) + sizeof(parameter1) + + sizeof(parameter2); + return RETURN_OK; +} + +void TestDevice::passOnCommand(DeviceCommandId_t command, const uint8_t *commandData, + size_t commandDataLen) { + DeviceCommandId_t deviceCommandBe = EndianConverter::convertBigEndian(command); + memcpy(commandBuffer, &deviceCommandBe, sizeof(deviceCommandBe)); + memcpy(commandBuffer + 4, commandData, commandDataLen); + rawPacket = commandBuffer; + rawPacketLen = sizeof(deviceCommandBe) + commandDataLen; +} + +void TestDevice::fillCommandAndReplyMap() { + namespace td = testdevice; + insertInCommandAndReplyMap(testdevice::TEST_NORMAL_MODE_CMD, 5, &dataset); + insertInCommandAndReplyMap(testdevice::TEST_COMMAND_0, 5); + insertInCommandAndReplyMap(testdevice::TEST_COMMAND_1, 5); + + /* No reply expected for these commands */ + insertInCommandMap(td::TEST_NOTIF_SNAPSHOT_SET); + insertInCommandMap(td::TEST_NOTIF_SNAPSHOT_VAR); +} + + +ReturnValue_t TestDevice::scanForReply(const uint8_t *start, size_t len, + DeviceCommandId_t *foundId, size_t *foundLen) { + using namespace testdevice; + + /* Unless a command was sent explicitely, we don't expect any replies and ignore this + the packet. On a real device, there might be replies which are sent without a previous + command. */ + if(not commandSent) { + return DeviceHandlerBase::IGNORE_FULL_PACKET; + } + else { + commandSent = false; + } + + if(len < sizeof(object_id_t)) { + return DeviceHandlerIF::LENGTH_MISSMATCH; + } + + size_t size = len; + ReturnValue_t result = SerializeAdapter::deSerialize(foundId, &start, &size, + SerializeIF::Endianness::BIG); + if (result != RETURN_OK) { + return result; + } + + DeviceCommandId_t pendingCmd = this->getPendingCommand(); + + switch(pendingCmd) { + + case(TEST_NORMAL_MODE_CMD): { + if(fullInfoPrintout) { +#if OBSW_VERBOSE_LEVEL >= 3 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "TestDevice::scanForReply: Reply for normal commnand (ID " << + TEST_NORMAL_MODE_CMD << ") received!" << std::endl; +#else + sif::printInfo("TestDevice%d::scanForReply: Reply for normal command (ID %d) " + "received!\n", deviceIdx, TEST_NORMAL_MODE_CMD); +#endif +#endif + } + + *foundLen = len; + *foundId = pendingCmd; + return RETURN_OK; + } + + case(TEST_COMMAND_0): { + if(len < TEST_COMMAND_0_SIZE) { + return DeviceHandlerIF::LENGTH_MISSMATCH; + } + if(fullInfoPrintout) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "TestDevice" << deviceIdx << "::scanForReply: Reply for simple command " + "(ID " << TEST_COMMAND_0 << ") received!" << std::endl; +#else + sif::printInfo("TestDevice%d::scanForReply: Reply for simple command (ID %d) " + "received!\n", deviceIdx, TEST_COMMAND_0); +#endif + } + + *foundLen = TEST_COMMAND_0_SIZE; + *foundId = pendingCmd; + return RETURN_OK; + } + + case(TEST_COMMAND_1): { + if(fullInfoPrintout) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "TestDevice" << deviceIdx << "::scanForReply: Reply for data command " + "(ID " << TEST_COMMAND_1 << ") received!" << std::endl; +#else + sif::printInfo("TestDevice%d::scanForReply: Reply for data command (ID %d) " + "received\n", deviceIdx, TEST_COMMAND_1); +#endif + } + + *foundLen = len; + *foundId = pendingCmd; + return RETURN_OK; + } + + default: + return DeviceHandlerIF::DEVICE_REPLY_INVALID; + } +} + + +ReturnValue_t TestDevice::interpretDeviceReply(DeviceCommandId_t id, + const uint8_t* packet) { + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + switch(id) { + /* Periodic replies */ + case testdevice::TEST_NORMAL_MODE_CMD: { + result = interpretingNormalModeReply(); + break; + } + /* Simple reply */ + case testdevice::TEST_COMMAND_0: { + result = interpretingTestReply0(id, packet); + break; + } + /* Data reply */ + case testdevice::TEST_COMMAND_1: { + result = interpretingTestReply1(id, packet); + break; + } + default: + return DeviceHandlerIF::DEVICE_REPLY_INVALID; + } + return result; +} + +ReturnValue_t TestDevice::interpretingNormalModeReply() { + CommandMessage directReplyMessage; + if(changingDatasets) { + PoolReadGuard readHelper(&dataset); + if(dataset.testUint8Var.value == 0) { + dataset.testUint8Var.value = 10; + dataset.testUint32Var.value = 777; + dataset.testFloat3Vec.value[0] = 2.5; + dataset.testFloat3Vec.value[1] = -2.5; + dataset.testFloat3Vec.value[2] = 2.5; + dataset.setValidity(true, true); + } + else { + dataset.testUint8Var.value = 0; + dataset.testUint32Var.value = 0; + dataset.testFloat3Vec.value[0] = 0.0; + dataset.testFloat3Vec.value[1] = 0.0; + dataset.testFloat3Vec.value[2] = 0.0; + dataset.setValidity(false, true); + } + return RETURN_OK; + } + + PoolReadGuard readHelper(&dataset); + if(dataset.testUint8Var.value == 0) { + /* Reset state */ + dataset.testUint8Var.value = 128; + } + else if(dataset.testUint8Var.value > 200) { + if(not resetAfterChange) { + /* This will trigger an update notification to the controller */ + dataset.testUint8Var.setChanged(true); + resetAfterChange = true; + /* Decrement by 30 automatically. This will prevent any additional notifications. */ + dataset.testUint8Var.value -= 30; + } + } + /* If the value is greater than 0, it will be decremented in a linear way */ + else if(dataset.testUint8Var.value > 128) { + size_t sizeToDecrement = 0; + if(dataset.testUint8Var.value > 128 + 30) { + sizeToDecrement = 30; + } + else { + sizeToDecrement = dataset.testUint8Var.value - 128; + resetAfterChange = false; + } + dataset.testUint8Var.value -= sizeToDecrement; + } + else if(dataset.testUint8Var.value < 50) { + if(not resetAfterChange) { + /* This will trigger an update snapshot to the controller */ + dataset.testUint8Var.setChanged(true); + resetAfterChange = true; + } + else { + /* Increment by 30 automatically. */ + dataset.testUint8Var.value += 30; + } + } + /* Increment in linear way */ + else if(dataset.testUint8Var.value < 128) { + size_t sizeToIncrement = 0; + if(dataset.testUint8Var.value < 128 - 20) { + sizeToIncrement = 20; + } + else { + sizeToIncrement = 128 - dataset.testUint8Var.value; + resetAfterChange = false; + } + dataset.testUint8Var.value += sizeToIncrement; + } + + /* TODO: Same for vector */ + float vectorMean = (dataset.testFloat3Vec.value[0] + dataset.testFloat3Vec.value[1] + + dataset.testFloat3Vec.value[2]) / 3.0; + + /* Lambda (private local function) */ + auto sizeToAdd = [](bool tooHigh, float currentVal) { + if(tooHigh) { + if(currentVal - 20.0 > 10.0) { + return -10.0; + } + else { + return 20.0 - currentVal; + } + } + else { + if(std::abs(currentVal + 20.0) > 10.0) { + return 10.0; + } + else { + return -20.0 - currentVal; + } + } + }; + + if(vectorMean > 20.0 and std::abs(vectorMean - 20.0) > 1.0) { + if(not resetAfterChange) { + dataset.testFloat3Vec.setChanged(true); + resetAfterChange = true; + } + else { + float sizeToDecrementVal0 = 0; + float sizeToDecrementVal1 = 0; + float sizeToDecrementVal2 = 0; + + sizeToDecrementVal0 = sizeToAdd(true, dataset.testFloat3Vec.value[0]); + sizeToDecrementVal1 = sizeToAdd(true, dataset.testFloat3Vec.value[1]); + sizeToDecrementVal2 = sizeToAdd(true, dataset.testFloat3Vec.value[2]); + + dataset.testFloat3Vec.value[0] += sizeToDecrementVal0; + dataset.testFloat3Vec.value[1] += sizeToDecrementVal1; + dataset.testFloat3Vec.value[2] += sizeToDecrementVal2; + } + } + else if (vectorMean < -20.0 and std::abs(vectorMean + 20.0) < 1.0) { + if(not resetAfterChange) { + dataset.testFloat3Vec.setChanged(true); + resetAfterChange = true; + } + else { + float sizeToDecrementVal0 = 0; + float sizeToDecrementVal1 = 0; + float sizeToDecrementVal2 = 0; + + sizeToDecrementVal0 = sizeToAdd(false, dataset.testFloat3Vec.value[0]); + sizeToDecrementVal1 = sizeToAdd(false, dataset.testFloat3Vec.value[1]); + sizeToDecrementVal2 = sizeToAdd(false, dataset.testFloat3Vec.value[2]); + + dataset.testFloat3Vec.value[0] += sizeToDecrementVal0; + dataset.testFloat3Vec.value[1] += sizeToDecrementVal1; + dataset.testFloat3Vec.value[2] += sizeToDecrementVal2; + } + } + else { + if(resetAfterChange) { + resetAfterChange = false; + } + } + + return RETURN_OK; +} + +ReturnValue_t TestDevice::interpretingTestReply0(DeviceCommandId_t id, const uint8_t* packet) { + CommandMessage commandMessage; + if(fullInfoPrintout) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "TestDevice::interpretingTestReply0: Generating step and finish reply" << + std::endl; +#else + sif::printInfo("TestDevice::interpretingTestReply0: Generating step and finish reply\n"); +#endif + } + + MessageQueueId_t commander = getCommanderQueueId(id); + /* Generate one step reply and the finish reply */ + actionHelper.step(1, commander, id); + actionHelper.finish(true, commander, id); + + return RETURN_OK; +} + +ReturnValue_t TestDevice::interpretingTestReply1(DeviceCommandId_t id, + const uint8_t* packet) { + CommandMessage directReplyMessage; + if(fullInfoPrintout) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "TestDevice" << deviceIdx << "::interpretingReply1: Setting data reply" << + std::endl; +#else + sif::printInfo("TestDevice%d::interpretingReply1: Setting data reply\n", deviceIdx); +#endif + } + + MessageQueueId_t commander = getCommanderQueueId(id); + /* Send reply with data */ + ReturnValue_t result = actionHelper.reportData(commander, id, packet, + testdevice::TEST_COMMAND_1_SIZE, false); + + if (result != RETURN_OK) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "TestDevice" << deviceIdx << "::interpretingReply1: Sending data " + "reply failed!" << std::endl; +#else + sif::printError("TestDevice%d::interpretingReply1: Sending data reply failed!\n", + deviceIdx); +#endif + return result; + } + + if(result == HasReturnvaluesIF::RETURN_OK) { + /* Finish reply */ + actionHelper.finish(true, commander, id); + } + else { + /* Finish reply */ + actionHelper.finish(false, commander, id, result); + } + + return RETURN_OK; +} + +uint32_t TestDevice::getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo) { + return 5000; +} + +void TestDevice::enableFullDebugOutput(bool enable) { + this->fullInfoPrintout = enable; +} + +ReturnValue_t TestDevice::initializeLocalDataPool(localpool::DataPool &localDataPoolMap, + LocalDataPoolManager &poolManager) { + namespace td = testdevice; + localDataPoolMap.emplace(td::PoolIds::TEST_UINT8_ID, new PoolEntry({0})); + localDataPoolMap.emplace(td::PoolIds::TEST_UINT32_ID, new PoolEntry({0})); + localDataPoolMap.emplace(td::PoolIds::TEST_FLOAT_VEC_3_ID, + new PoolEntry({0.0, 0.0, 0.0})); + + sid_t sid(this->getObjectId(), td::TEST_SET_ID); + /* Subscribe for periodic HK packets but do not enable reporting for now. + Non-diangostic with a period of one second */ + poolManager.subscribeForPeriodicPacket(sid, false, 1.0, false); + return HasReturnvaluesIF::RETURN_OK; +} + + +ReturnValue_t TestDevice::getParameter(uint8_t domainId, uint8_t uniqueId, + ParameterWrapper* parameterWrapper, const ParameterWrapper* newValues, + uint16_t startAtIndex) { + using namespace testdevice; + switch (uniqueId) { + case ParameterUniqueIds::TEST_UINT32_0: { + if(fullInfoPrintout) { + uint32_t newValue = 0; + ReturnValue_t result = newValues->getElement(&newValue, 0, 0); + if(result == HasReturnvaluesIF::RETURN_OK) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "TestDevice" << deviceIdx << "::getParameter: Setting parameter 0 to " + "new value " << newValue << std::endl; +#else + sif::printInfo("TestDevice%d::getParameter: Setting parameter 0 to new value %lu\n", + deviceIdx, static_cast(newValue)); +#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ + } + } + parameterWrapper->set(testParameter0); + break; + } + case ParameterUniqueIds::TEST_INT32_1: { + if(fullInfoPrintout) { + int32_t newValue = 0; + ReturnValue_t result = newValues->getElement(&newValue, 0, 0); + if(result == HasReturnvaluesIF::RETURN_OK) { +#if OBSW_DEVICE_HANDLER_PRINTOUT == 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "TestDevice" << deviceIdx << "::getParameter: Setting parameter 1 to " + "new value " << newValue << std::endl; +#else + sif::printInfo("TestDevice%d::getParameter: Setting parameter 1 to new value %lu\n", + deviceIdx, static_cast(newValue)); +#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ +#endif /* OBSW_DEVICE_HANDLER_PRINTOUT == 1 */ + } + } + parameterWrapper->set(testParameter1); + break; + } + case ParameterUniqueIds::TEST_FLOAT_VEC3_2: { + if(fullInfoPrintout) { + float newVector[3]; + if(newValues->getElement(newVector, 0, 0) != RETURN_OK or + newValues->getElement(newVector + 1, 0, 1) != RETURN_OK or + newValues->getElement(newVector + 2, 0, 2) != RETURN_OK) { + return HasReturnvaluesIF::RETURN_FAILED; + } +#if OBSW_DEVICE_HANDLER_PRINTOUT == 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "TestDevice" << deviceIdx << "::getParameter: Setting parameter 3 to " + "(float vector with 3 entries) to new values [" << newVector[0] << ", " << + newVector[1] << ", " << newVector[2] << "]" << std::endl; +#else + sif::printInfo("TestDevice%d::getParameter: Setting parameter 3 to new values " + "[%f, %f, %f]\n", deviceIdx, newVector[0], newVector[1], newVector[2]); +#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ +#endif /* OBSW_DEVICE_HANDLER_PRINTOUT == 1 */ + } + parameterWrapper->setVector(vectorFloatParams2); + break; + } + case(ParameterUniqueIds::PERIODIC_PRINT_ENABLED): { + if(fullInfoPrintout) { + uint8_t enabled = 0; + ReturnValue_t result = newValues->getElement(&enabled, 0, 0); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + char const* printout = nullptr; + if (enabled) { + printout = "enabled"; + } + else { + printout = "disabled"; + } +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "TestDevice" << deviceIdx << "::getParameter: Periodic printout " << + printout << std::endl; +#else + sif::printInfo("TestDevice%d::getParameter: Periodic printout %s", printout); +#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ + } + + parameterWrapper->set(periodicPrintout); + break; + } + case(ParameterUniqueIds::CHANGING_DATASETS): { + + uint8_t enabled = 0; + ReturnValue_t result = newValues->getElement(&enabled, 0, 0); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if(not enabled) { + PoolReadGuard readHelper(&dataset); + dataset.testUint8Var.value = 0; + dataset.testUint32Var.value = 0; + dataset.testFloat3Vec.value[0] = 0.0; + dataset.testFloat3Vec.value[0] = 0.0; + dataset.testFloat3Vec.value[1] = 0.0; + } + + if(fullInfoPrintout) { + char const* printout = nullptr; + if (enabled) { + printout = "enabled"; + } + else { + printout = "disabled"; + } +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "TestDevice" << deviceIdx << "::getParameter: Changing datasets " << + printout << std::endl; +#else + sif::printInfo("TestDevice%d::getParameter: Changing datasets %s", printout); +#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ + } + + parameterWrapper->set(changingDatasets); + break; + } + default: + return INVALID_IDENTIFIER_ID; + } + return HasReturnvaluesIF::RETURN_OK; +} + +LocalPoolObjectBase* TestDevice::getPoolObjectHandle(lp_id_t localPoolId) { + namespace td = testdevice; + if (localPoolId == td::PoolIds::TEST_UINT8_ID) { + return &dataset.testUint8Var; + } + else if (localPoolId == td::PoolIds::TEST_UINT32_ID) { + return &dataset.testUint32Var; + } + else if(localPoolId == td::PoolIds::TEST_FLOAT_VEC_3_ID) { + return &dataset.testFloat3Vec; + } + else { + return nullptr; + } +} diff --git a/tests/src/fsfw_tests/integration/devices/TestDeviceHandler.h b/tests/src/fsfw_tests/integration/devices/TestDeviceHandler.h new file mode 100644 index 00000000..0eb47731 --- /dev/null +++ b/tests/src/fsfw_tests/integration/devices/TestDeviceHandler.h @@ -0,0 +1,142 @@ +#ifndef TEST_TESTDEVICES_TESTDEVICEHANDLER_H_ +#define TEST_TESTDEVICES_TESTDEVICEHANDLER_H_ + +#include "devicedefinitions/testDeviceDefinitions.h" + +#include "fsfw/devicehandlers/DeviceHandlerBase.h" +#include "fsfw/globalfunctions/PeriodicOperationDivider.h" +#include "fsfw/timemanager/Countdown.h" + +/** + * @brief Basic dummy device handler to test device commanding without a physical device. + * @details + * This test device handler provided a basic demo for the device handler object. + * It can also be commanded with the following PUS services, using + * the specified object ID of the test device handler. + * + * 1. PUS Service 8 - Functional commanding + * 2. PUS Service 2 - Device access, raw commanding + * 3. PUS Service 20 - Parameter Management + * 4. PUS Service 3 - Housekeeping + + * @author R. Mueller + * @ingroup devices + */ +class TestDevice: public DeviceHandlerBase { +public: + /** + * Build the test device in the factory. + * @param objectId This ID will be assigned to the test device handler. + * @param comIF The ID of the Communication IF used by test device handler. + * @param cookie Cookie object used by the test device handler. This is + * also used and passed to the comIF object. + * @param onImmediately This will start a transition to MODE_ON immediately + * so the device handler jumps into #doStartUp. Should only be used + * in development to reduce need of commanding while debugging. + * @param changingDataset + * Will be used later to change the local datasets containeds in the device. + */ + TestDevice(object_id_t objectId, object_id_t comIF, CookieIF * cookie, + testdevice::DeviceIndex deviceIdx = testdevice::DeviceIndex::DEVICE_0, + bool fullInfoPrintout = false, bool changingDataset = true); + + /** + * This can be used to enable and disable a lot of demo print output. + * @param enable + */ + void enableFullDebugOutput(bool enable); + + virtual ~ TestDevice(); + + //! Size of internal buffer used for communication. + static constexpr uint8_t MAX_BUFFER_SIZE = 255; + + //! Unique index if the device handler is created multiple times. + testdevice::DeviceIndex deviceIdx = testdevice::DeviceIndex::DEVICE_0; + +protected: + testdevice::TestDataSet dataset; + //! This is used to reset the dataset after a commanded change has been made. + bool resetAfterChange = false; + bool commandSent = false; + + /** DeviceHandlerBase overrides (see DHB documentation) */ + + /** + * Hook into the DHB #performOperation call which is executed + * periodically. + */ + void performOperationHook() override; + + virtual void doStartUp() override; + virtual void doShutDown() override; + + virtual ReturnValue_t buildNormalDeviceCommand( + DeviceCommandId_t * id) override; + virtual ReturnValue_t buildTransitionDeviceCommand( + DeviceCommandId_t * id) override; + virtual ReturnValue_t buildCommandFromCommand(DeviceCommandId_t + deviceCommand, const uint8_t * commandData, + size_t commandDataLen) override; + + virtual void fillCommandAndReplyMap() override; + + virtual ReturnValue_t scanForReply(const uint8_t *start, size_t len, + DeviceCommandId_t *foundId, size_t *foundLen) override; + virtual ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, + const uint8_t *packet) override; + virtual uint32_t getTransitionDelayMs(Mode_t modeFrom, + Mode_t modeTo) override; + + virtual void doTransition(Mode_t modeFrom, Submode_t subModeFrom) override; + + virtual ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap, + LocalDataPoolManager& poolManager) override; + virtual LocalPoolObjectBase* getPoolObjectHandle(lp_id_t localPoolId) override; + + /* HasParametersIF overrides */ + virtual ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueId, + ParameterWrapper *parameterWrapper, + const ParameterWrapper *newValues, uint16_t startAtIndex) override; + + uint8_t commandBuffer[MAX_BUFFER_SIZE]; + + bool fullInfoPrintout = false; + bool oneShot = true; + + /* Variables for parameter service */ + uint32_t testParameter0 = 0; + int32_t testParameter1 = -2; + float vectorFloatParams2[3] = {}; + + /* Change device handler functionality, changeable via parameter service */ + uint8_t periodicPrintout = false; + uint8_t changingDatasets = false; + + ReturnValue_t buildNormalModeCommand(DeviceCommandId_t deviceCommand, + const uint8_t* commandData, size_t commandDataLen); + ReturnValue_t buildTestCommand0(DeviceCommandId_t deviceCommand, const uint8_t* commandData, + size_t commandDataLen); + ReturnValue_t buildTestCommand1(DeviceCommandId_t deviceCommand, const uint8_t* commandData, + size_t commandDataLen); + void passOnCommand(DeviceCommandId_t command, const uint8_t* commandData, + size_t commandDataLen); + + ReturnValue_t interpretingNormalModeReply(); + ReturnValue_t interpretingTestReply0(DeviceCommandId_t id, + const uint8_t* packet); + ReturnValue_t interpretingTestReply1(DeviceCommandId_t id, + const uint8_t* packet); + ReturnValue_t interpretingTestReply2(DeviceCommandId_t id, const uint8_t* packet); + + /* Some timer utilities */ + uint8_t divider1 = 2; + PeriodicOperationDivider opDivider1 = PeriodicOperationDivider(divider1); + uint8_t divider2 = 10; + PeriodicOperationDivider opDivider2 = PeriodicOperationDivider(divider2); + static constexpr uint32_t initTimeout = 2000; + Countdown countdown1 = Countdown(initTimeout); +}; + + +#endif /* TEST_TESTDEVICES_TESTDEVICEHANDLER_H_ */ diff --git a/tests/src/fsfw_tests/integration/devices/TestEchoComIF.cpp b/tests/src/fsfw_tests/integration/devices/TestEchoComIF.cpp new file mode 100644 index 00000000..afb23a06 --- /dev/null +++ b/tests/src/fsfw_tests/integration/devices/TestEchoComIF.cpp @@ -0,0 +1,86 @@ +#include "TestEchoComIF.h" +#include "TestCookie.h" + +#include +#include +#include +#include + + +TestEchoComIF::TestEchoComIF(object_id_t objectId): + SystemObject(objectId) { +} + +TestEchoComIF::~TestEchoComIF() {} + +ReturnValue_t TestEchoComIF::initializeInterface(CookieIF * cookie) { + TestCookie* dummyCookie = dynamic_cast(cookie); + if(dummyCookie == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "TestEchoComIF::initializeInterface: Invalid cookie!" << std::endl; +#else + sif::printWarning("TestEchoComIF::initializeInterface: Invalid cookie!\n"); +#endif + return NULLPOINTER; + } + + auto resultPair = replyMap.emplace( + dummyCookie->getAddress(), ReplyBuffer(dummyCookie->getReplyMaxLen())); + if(not resultPair.second) { + return HasReturnvaluesIF::RETURN_FAILED; + } + return RETURN_OK; +} + +ReturnValue_t TestEchoComIF::sendMessage(CookieIF *cookie, + const uint8_t * sendData, size_t sendLen) { + TestCookie* dummyCookie = dynamic_cast(cookie); + if(dummyCookie == nullptr) { + return NULLPOINTER; + } + + ReplyBuffer& replyBuffer = replyMap.find(dummyCookie->getAddress())->second; + if(sendLen > replyBuffer.capacity()) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "TestEchoComIF::sendMessage: Send length " << sendLen << " larger than " + "current reply buffer length!" << std::endl; +#else + sif::printWarning("TestEchoComIF::sendMessage: Send length %d larger than current " + "reply buffer length!\n", sendLen); +#endif + return HasReturnvaluesIF::RETURN_FAILED; + } + replyBuffer.resize(sendLen); + memcpy(replyBuffer.data(), sendData, sendLen); + return RETURN_OK; +} + +ReturnValue_t TestEchoComIF::getSendSuccess(CookieIF *cookie) { + return RETURN_OK; +} + +ReturnValue_t TestEchoComIF::requestReceiveMessage(CookieIF *cookie, + size_t requestLen) { + return RETURN_OK; +} + +ReturnValue_t TestEchoComIF::readReceivedMessage(CookieIF *cookie, + uint8_t **buffer, size_t *size) { + TestCookie* dummyCookie = dynamic_cast(cookie); + if(dummyCookie == nullptr) { + return NULLPOINTER; + } + + ReplyBuffer& replyBuffer = replyMap.find(dummyCookie->getAddress())->second; + *buffer = replyBuffer.data(); + *size = replyBuffer.size(); + + dummyReplyCounter ++; + if(dummyReplyCounter == 10) { + // add anything that needs to be read periodically by dummy handler + dummyReplyCounter = 0; + } + return RETURN_OK; + +} + diff --git a/tests/src/fsfw_tests/integration/devices/TestEchoComIF.h b/tests/src/fsfw_tests/integration/devices/TestEchoComIF.h new file mode 100644 index 00000000..38270cfe --- /dev/null +++ b/tests/src/fsfw_tests/integration/devices/TestEchoComIF.h @@ -0,0 +1,56 @@ +#ifndef TEST_TESTDEVICES_TESTECHOCOMIF_H_ +#define TEST_TESTDEVICES_TESTECHOCOMIF_H_ + +#include +#include +#include +#include + +#include + +/** + * @brief Used to simply returned sent data from device handler + * @details Assign this com IF in the factory when creating the device handler + * @ingroup test + */ +class TestEchoComIF: public DeviceCommunicationIF, public SystemObject { +public: + TestEchoComIF(object_id_t objectId); + virtual ~TestEchoComIF(); + + /** + * DeviceCommunicationIF overrides + * (see DeviceCommunicationIF documentation + */ + ReturnValue_t initializeInterface(CookieIF * cookie) override; + ReturnValue_t sendMessage(CookieIF *cookie, const uint8_t * sendData, + size_t sendLen) override; + ReturnValue_t getSendSuccess(CookieIF *cookie) override; + ReturnValue_t requestReceiveMessage(CookieIF *cookie, + size_t requestLen) override; + ReturnValue_t readReceivedMessage(CookieIF *cookie, uint8_t **buffer, + size_t *size) override; + +private: + + /** + * Send TM packet which contains received data as TM[17,130]. + * Wiretapping will do the same. + * @param data + * @param len + */ + void sendTmPacket(const uint8_t *data,uint32_t len); + + AcceptsTelemetryIF* funnel = nullptr; + MessageQueueIF* tmQueue = nullptr; + size_t replyMaxLen = 0; + + using ReplyBuffer = std::vector; + std::map replyMap; + + uint8_t dummyReplyCounter = 0; + + uint16_t packetSubCounter = 0; +}; + +#endif /* TEST_TESTDEVICES_TESTECHOCOMIF_H_ */ diff --git a/tests/src/fsfw_tests/integration/devices/devicedefinitions/testDeviceDefinitions.h b/tests/src/fsfw_tests/integration/devices/devicedefinitions/testDeviceDefinitions.h new file mode 100644 index 00000000..1c112e3f --- /dev/null +++ b/tests/src/fsfw_tests/integration/devices/devicedefinitions/testDeviceDefinitions.h @@ -0,0 +1,97 @@ +#ifndef MISSION_DEVICES_DEVICEDEFINITIONS_TESTDEVICEDEFINITIONS_H_ +#define MISSION_DEVICES_DEVICEDEFINITIONS_TESTDEVICEDEFINITIONS_H_ + +#include +#include + +namespace testdevice { + +enum ParameterUniqueIds: uint8_t { + TEST_UINT32_0, + TEST_INT32_1, + TEST_FLOAT_VEC3_2, + PERIODIC_PRINT_ENABLED, + CHANGING_DATASETS +}; + +enum DeviceIndex: uint32_t { + DEVICE_0, + DEVICE_1 +}; + +/** Normal mode command. This ID is also used to access the set variable via the housekeeping +service */ +static constexpr DeviceCommandId_t TEST_NORMAL_MODE_CMD = 0; + +//! Test completion reply +static constexpr DeviceCommandId_t TEST_COMMAND_0 = 1; +//! Test data reply +static constexpr DeviceCommandId_t TEST_COMMAND_1 = 2; + +/** + * Can be used to trigger a notification to the demo controller. For DEVICE_0, only notifications + * messages will be generated while for DEVICE_1, snapshot messages will be generated. + * + * DEVICE_0 VAR: Sets the set variable 0 above a treshold (200) to trigger a variable + * notification. + * DEVICE_0 SET: Sets the vector mean values above a treshold (mean larger than 20) to trigger a + * set notification. + * + * DEVICE_1 VAR: Sets the set variable 0 below a treshold (less than 50 but not 0) to trigger a + * variable snapshot. + * DEVICE_1 SET: Sets the set vector mean values below a treshold (mean smaller than -20) to + * trigger a set snapshot message. + */ +static constexpr DeviceCommandId_t TEST_NOTIF_SNAPSHOT_VAR = 3; +static constexpr DeviceCommandId_t TEST_NOTIF_SNAPSHOT_SET = 4; + +/** + * Can be used to trigger a snapshot message to the demo controller. + * Depending on the device index, a notification will be triggered for different set variables. + * + * DEVICE_0: Sets the set variable 0 below a treshold (below 50 but not 0) to trigger + * a variable snapshot + * DEVICE_1: Sets the vector mean values below a treshold (mean less than -20) to trigger a + * set snapshot + */ +static constexpr DeviceCommandId_t TEST_SNAPSHOT = 5; + +//! Generates a random value for variable 1 of the dataset. +static constexpr DeviceCommandId_t GENERATE_SET_VAR_1_RNG_VALUE = 6; + + +/** + * These parameters are sent back with the command ID as a data reply + */ +static constexpr uint16_t COMMAND_1_PARAM1 = 0xBAB0; //!< param1, 2 bytes +//! param2, 8 bytes +static constexpr uint64_t COMMAND_1_PARAM2 = 0x000000524F42494E; + +static constexpr size_t TEST_COMMAND_0_SIZE = sizeof(TEST_COMMAND_0); +static constexpr size_t TEST_COMMAND_1_SIZE = sizeof(TEST_COMMAND_1) + sizeof(COMMAND_1_PARAM1) + + sizeof(COMMAND_1_PARAM2); + +enum PoolIds: lp_id_t { + TEST_UINT8_ID = 0, + TEST_UINT32_ID = 1, + TEST_FLOAT_VEC_3_ID = 2 +}; + +static constexpr uint8_t TEST_SET_ID = TEST_NORMAL_MODE_CMD; + +class TestDataSet: public StaticLocalDataSet<3> { +public: + TestDataSet(HasLocalDataPoolIF* owner): StaticLocalDataSet(owner, TEST_SET_ID) {} + TestDataSet(object_id_t owner): StaticLocalDataSet(sid_t(owner, TEST_SET_ID)) {} + + lp_var_t testUint8Var = lp_var_t( + gp_id_t(this->getCreatorObjectId(), PoolIds::TEST_UINT8_ID), this); + lp_var_t testUint32Var = lp_var_t( + gp_id_t(this->getCreatorObjectId(), PoolIds::TEST_UINT32_ID), this); + lp_vec_t testFloat3Vec = lp_vec_t( + gp_id_t(this->getCreatorObjectId(), PoolIds::TEST_FLOAT_VEC_3_ID), this); +}; + +} + +#endif /* MISSION_DEVICES_DEVICEDEFINITIONS_TESTDEVICEDEFINITIONS_H_ */ diff --git a/tests/src/fsfw_tests/integration/task/CMakeLists.txt b/tests/src/fsfw_tests/integration/task/CMakeLists.txt new file mode 100644 index 00000000..4cd481bf --- /dev/null +++ b/tests/src/fsfw_tests/integration/task/CMakeLists.txt @@ -0,0 +1,3 @@ +target_sources(${LIB_FSFW_NAME} PRIVATE + TestTask.cpp +) \ No newline at end of file diff --git a/tests/src/fsfw_tests/integration/task/TestTask.cpp b/tests/src/fsfw_tests/integration/task/TestTask.cpp new file mode 100644 index 00000000..b33bd51c --- /dev/null +++ b/tests/src/fsfw_tests/integration/task/TestTask.cpp @@ -0,0 +1,68 @@ +#include "TestTask.h" + +#include +#include + +bool TestTask::oneShotAction = true; +MutexIF* TestTask::testLock = nullptr; + +TestTask::TestTask(object_id_t objectId): + SystemObject(objectId), testMode(testModes::A) { + if(testLock == nullptr) { + testLock = MutexFactory::instance()->createMutex(); + } + IPCStore = ObjectManager::instance()->get(objects::IPC_STORE); +} + +TestTask::~TestTask() { +} + +ReturnValue_t TestTask::performOperation(uint8_t operationCode) { + ReturnValue_t result = RETURN_OK; + testLock->lockMutex(MutexIF::TimeoutType::WAITING, 20); + if(oneShotAction) { + // Add code here which should only be run once + performOneShotAction(); + oneShotAction = false; + } + testLock->unlockMutex(); + + // Add code here which should only be run once per performOperation + performPeriodicAction(); + + // Add code here which should only be run on alternating cycles. + if(testMode == testModes::A) { + performActionA(); + testMode = testModes::B; + } + else if(testMode == testModes::B) { + performActionB(); + testMode = testModes::A; + } + return result; +} + +ReturnValue_t TestTask::performOneShotAction() { + /* Everything here will only be performed once. */ + return HasReturnvaluesIF::RETURN_OK; +} + + +ReturnValue_t TestTask::performPeriodicAction() { + /* This is performed each task cycle */ + ReturnValue_t result = RETURN_OK; + return result; +} + +ReturnValue_t TestTask::performActionA() { + /* This is performed each alternating task cycle */ + ReturnValue_t result = RETURN_OK; + return result; +} + +ReturnValue_t TestTask::performActionB() { + /* This is performed each alternating task cycle */ + ReturnValue_t result = RETURN_OK; + return result; +} + diff --git a/tests/src/fsfw_tests/integration/task/TestTask.h b/tests/src/fsfw_tests/integration/task/TestTask.h new file mode 100644 index 00000000..e56b5581 --- /dev/null +++ b/tests/src/fsfw_tests/integration/task/TestTask.h @@ -0,0 +1,43 @@ +#ifndef MISSION_DEMO_TESTTASK_H_ +#define MISSION_DEMO_TESTTASK_H_ + +#include +#include +#include + +/** + * @brief Test class for general C++ testing and any other code which will not be part of the + * primary mission software. + * @details + * Should not be used for board specific tests. Instead, a derived board test class should be used. + */ +class TestTask : + public SystemObject, + public ExecutableObjectIF, + public HasReturnvaluesIF { +public: + TestTask(object_id_t objectId); + virtual ~TestTask(); + virtual ReturnValue_t performOperation(uint8_t operationCode = 0) override; + +protected: + virtual ReturnValue_t performOneShotAction(); + virtual ReturnValue_t performPeriodicAction(); + virtual ReturnValue_t performActionA(); + virtual ReturnValue_t performActionB(); + + enum testModes: uint8_t { + A, + B + }; + + testModes testMode; + bool testFlag = false; + +private: + static bool oneShotAction; + static MutexIF* testLock; + StorageManagerIF* IPCStore; +}; + +#endif /* TESTTASK_H_ */ diff --git a/unittest/internal/CMakeLists.txt b/tests/src/fsfw_tests/internal/CMakeLists.txt similarity index 57% rename from unittest/internal/CMakeLists.txt rename to tests/src/fsfw_tests/internal/CMakeLists.txt index 11fd2b2f..2a144a9b 100644 --- a/unittest/internal/CMakeLists.txt +++ b/tests/src/fsfw_tests/internal/CMakeLists.txt @@ -1,4 +1,4 @@ -target_sources(${TARGET_NAME} PRIVATE +target_sources(${LIB_FSFW_NAME} PRIVATE InternalUnitTester.cpp UnittDefinitions.cpp ) diff --git a/tests/src/fsfw_tests/internal/InternalUnitTester.cpp b/tests/src/fsfw_tests/internal/InternalUnitTester.cpp new file mode 100644 index 00000000..3c8eec1e --- /dev/null +++ b/tests/src/fsfw_tests/internal/InternalUnitTester.cpp @@ -0,0 +1,45 @@ +#include "fsfw_tests/internal/InternalUnitTester.h" +#include "fsfw_tests/internal/UnittDefinitions.h" + +#include "fsfw_tests/internal/osal/testMq.h" +#include "fsfw_tests/internal/osal/testSemaphore.h" +#include "fsfw_tests/internal/osal/testMutex.h" +#include "fsfw_tests/internal/serialize/IntTestSerialization.h" +#include "fsfw_tests/internal/globalfunctions/TestArrayPrinter.h" + +#include + +InternalUnitTester::InternalUnitTester() {} + +InternalUnitTester::~InternalUnitTester() {} + +ReturnValue_t InternalUnitTester::performTests( + const struct InternalUnitTester::TestConfig& testConfig) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "Running internal unit tests.. Error messages might follow" << + std::endl; +#else + sif::printInfo("Running internal unit tests..\n"); +#endif + + testserialize::test_serialization(); + testmq::testMq(); + if(testConfig.testSemaphores) { + testsemaph::testBinSemaph(); + testsemaph::testCountingSemaph(); + } + testmutex::testMutex(); + if(testConfig.testArrayPrinter) { + arrayprinter::testArrayPrinter(); + } + +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "Internal unit tests finished." << std::endl; +#else + sif::printInfo("Internal unit tests finished.\n"); +#endif + return RETURN_OK; +} + + + diff --git a/unittest/internal/InternalUnitTester.h b/tests/src/fsfw_tests/internal/InternalUnitTester.h similarity index 77% rename from unittest/internal/InternalUnitTester.h rename to tests/src/fsfw_tests/internal/InternalUnitTester.h index ae954c6a..433a0f1f 100644 --- a/unittest/internal/InternalUnitTester.h +++ b/tests/src/fsfw_tests/internal/InternalUnitTester.h @@ -2,7 +2,7 @@ #define FRAMEWORK_TEST_UNITTESTCLASS_H_ #include "UnittDefinitions.h" -#include "../../returnvalues/HasReturnvaluesIF.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" /** @@ -17,7 +17,8 @@ class InternalUnitTester: public HasReturnvaluesIF { public: struct TestConfig { - bool testArrayPrinter; + bool testArrayPrinter = false; + bool testSemaphores = true; }; InternalUnitTester(); @@ -27,7 +28,7 @@ public: * Some function which calls all other tests * @return */ - virtual ReturnValue_t performTests(struct InternalUnitTester::TestConfig& testConfig); + virtual ReturnValue_t performTests(const struct InternalUnitTester::TestConfig& testConfig); }; diff --git a/unittest/internal/UnittDefinitions.cpp b/tests/src/fsfw_tests/internal/UnittDefinitions.cpp similarity index 87% rename from unittest/internal/UnittDefinitions.cpp rename to tests/src/fsfw_tests/internal/UnittDefinitions.cpp index ed4b59c1..7f754a0a 100644 --- a/unittest/internal/UnittDefinitions.cpp +++ b/tests/src/fsfw_tests/internal/UnittDefinitions.cpp @@ -1,4 +1,4 @@ -#include "UnittDefinitions.h" +#include "fsfw_tests/internal/UnittDefinitions.h" ReturnValue_t unitt::put_error(std::string errorId) { #if FSFW_CPP_OSTREAM_ENABLED == 1 diff --git a/unittest/internal/UnittDefinitions.h b/tests/src/fsfw_tests/internal/UnittDefinitions.h similarity index 88% rename from unittest/internal/UnittDefinitions.h rename to tests/src/fsfw_tests/internal/UnittDefinitions.h index 3e14fec5..7e7e06a6 100644 --- a/unittest/internal/UnittDefinitions.h +++ b/tests/src/fsfw_tests/internal/UnittDefinitions.h @@ -1,8 +1,9 @@ #ifndef UNITTEST_INTERNAL_UNITTDEFINITIONS_H_ #define UNITTEST_INTERNAL_UNITTDEFINITIONS_H_ -#include "../../returnvalues/HasReturnvaluesIF.h" -#include "../../serviceinterface/ServiceInterface.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" +#include "fsfw/serviceinterface/ServiceInterface.h" + #include #include #include diff --git a/tests/src/fsfw_tests/internal/globalfunctions/CMakeLists.txt b/tests/src/fsfw_tests/internal/globalfunctions/CMakeLists.txt new file mode 100644 index 00000000..cde97734 --- /dev/null +++ b/tests/src/fsfw_tests/internal/globalfunctions/CMakeLists.txt @@ -0,0 +1,3 @@ +target_sources(${LIB_FSFW_NAME} PRIVATE + TestArrayPrinter.cpp +) diff --git a/unittest/internal/globalfunctions/TestArrayPrinter.cpp b/tests/src/fsfw_tests/internal/globalfunctions/TestArrayPrinter.cpp similarity index 94% rename from unittest/internal/globalfunctions/TestArrayPrinter.cpp rename to tests/src/fsfw_tests/internal/globalfunctions/TestArrayPrinter.cpp index de016d19..b4311343 100644 --- a/unittest/internal/globalfunctions/TestArrayPrinter.cpp +++ b/tests/src/fsfw_tests/internal/globalfunctions/TestArrayPrinter.cpp @@ -1,4 +1,4 @@ -#include "TestArrayPrinter.h" +#include "fsfw_tests/internal/globalfunctions/TestArrayPrinter.h" void arrayprinter::testArrayPrinter() { { diff --git a/unittest/internal/globalfunctions/TestArrayPrinter.h b/tests/src/fsfw_tests/internal/globalfunctions/TestArrayPrinter.h similarity index 100% rename from unittest/internal/globalfunctions/TestArrayPrinter.h rename to tests/src/fsfw_tests/internal/globalfunctions/TestArrayPrinter.h diff --git a/tests/src/fsfw_tests/internal/osal/CMakeLists.txt b/tests/src/fsfw_tests/internal/osal/CMakeLists.txt new file mode 100644 index 00000000..8d79d759 --- /dev/null +++ b/tests/src/fsfw_tests/internal/osal/CMakeLists.txt @@ -0,0 +1,5 @@ +target_sources(${LIB_FSFW_NAME} PRIVATE + testMq.cpp + testMutex.cpp + testSemaphore.cpp +) diff --git a/unittest/internal/osal/IntTestMq.cpp b/tests/src/fsfw_tests/internal/osal/testMq.cpp similarity index 94% rename from unittest/internal/osal/IntTestMq.cpp rename to tests/src/fsfw_tests/internal/osal/testMq.cpp index fc8e963e..8a252910 100644 --- a/unittest/internal/osal/IntTestMq.cpp +++ b/tests/src/fsfw_tests/internal/osal/testMq.cpp @@ -1,5 +1,5 @@ -#include "IntTestMq.h" -#include +#include "testMq.h" +#include "fsfw_tests/internal/UnittDefinitions.h" #include #include @@ -49,5 +49,4 @@ void testmq::testMq() { if(senderId != testSenderMqId) { unitt::put_error(id); } - } diff --git a/unittest/internal/osal/IntTestMq.h b/tests/src/fsfw_tests/internal/osal/testMq.h similarity index 100% rename from unittest/internal/osal/IntTestMq.h rename to tests/src/fsfw_tests/internal/osal/testMq.h diff --git a/unittest/internal/osal/IntTestMutex.cpp b/tests/src/fsfw_tests/internal/osal/testMutex.cpp similarity index 79% rename from unittest/internal/osal/IntTestMutex.cpp rename to tests/src/fsfw_tests/internal/osal/testMutex.cpp index 13d87a8b..9b50121a 100644 --- a/unittest/internal/osal/IntTestMutex.cpp +++ b/tests/src/fsfw_tests/internal/osal/testMutex.cpp @@ -1,10 +1,12 @@ -#include "IntTestMutex.h" +#include "testMutex.h" +#include "fsfw_tests/internal/UnittDefinitions.h" +#include "fsfw/platform.h" #include -#include -#if defined(WIN32) || defined(UNIX) -#include +#if defined PLATFORM_WIN || defined PLATFORM_UNIX +#include "fsfw/osal/host/Mutex.h" + #include #include #endif @@ -20,7 +22,7 @@ void testmutex::testMutex() { // timed_mutex from the C++ library specifies undefined behaviour if // the timed mutex is locked twice from the same thread. // TODO: we should pass a define like FSFW_OSAL_HOST to the build. -#if defined(WIN32) || defined(UNIX) +#if defined PLATFORM_WIN || defined PLATFORM_UNIX // This calls the function from // another thread and stores the returnvalue in a future. auto future = std::async(&MutexIF::lockMutex, mutex, MutexIF::TimeoutType::WAITING, 1); @@ -37,8 +39,7 @@ void testmutex::testMutex() { unitt::put_error(id); } - // TODO: we should pass a define like FSFW_OSAL_HOST to the build. -#if !defined(WIN32) && !defined(UNIX) +#if !defined PLATFORM_WIN && !defined PLATFORM_UNIX result = mutex->unlockMutex(); if(result != MutexIF::CURR_THREAD_DOES_NOT_OWN_MUTEX) { unitt::put_error(id); diff --git a/unittest/internal/osal/IntTestMutex.h b/tests/src/fsfw_tests/internal/osal/testMutex.h similarity index 100% rename from unittest/internal/osal/IntTestMutex.h rename to tests/src/fsfw_tests/internal/osal/testMutex.h diff --git a/unittest/internal/osal/IntTestSemaphore.cpp b/tests/src/fsfw_tests/internal/osal/testSemaphore.cpp similarity index 93% rename from unittest/internal/osal/IntTestSemaphore.cpp rename to tests/src/fsfw_tests/internal/osal/testSemaphore.cpp index 43990c2c..458dcb04 100644 --- a/unittest/internal/osal/IntTestSemaphore.cpp +++ b/tests/src/fsfw_tests/internal/osal/testSemaphore.cpp @@ -1,9 +1,10 @@ -#include "IntTestSemaphore.h" -#include +#include "fsfw/FSFW.h" +#include "testSemaphore.h" +#include "fsfw_tests/internal/UnittDefinitions.h" -#include -#include -#include +#include "fsfw/tasks/SemaphoreFactory.h" +#include "fsfw/serviceinterface/ServiceInterface.h" +#include "fsfw/timemanager/Stopwatch.h" #include @@ -16,7 +17,7 @@ void testsemaph::testBinSemaph() { } testBinSemaphoreImplementation(binSemaph, id); SemaphoreFactory::instance()->deleteSemaphore(binSemaph); -#if defined(freeRTOS) +#if defined FSFW_OSAL_FREERTOS SemaphoreIF* binSemaphUsingTask = SemaphoreFactory::instance()->createBinarySemaphore(1); testBinSemaphoreImplementation(binSemaphUsingTask, id); @@ -36,7 +37,7 @@ void testsemaph::testCountingSemaph() { } testBinSemaphoreImplementation(countingSemaph, id); SemaphoreFactory::instance()->deleteSemaphore(countingSemaph); -#if defined(freeRTOS) +#if defined FSFW_OSAL_FREERTOS countingSemaph = SemaphoreFactory::instance()-> createCountingSemaphore(1, 1, 1); testBinSemaphoreImplementation(countingSemaph, id); @@ -50,7 +51,7 @@ void testsemaph::testCountingSemaph() { createCountingSemaphore(3,3); testCountingSemaphImplementation(countingSemaph, id); SemaphoreFactory::instance()->deleteSemaphore(countingSemaph); -#if defined(freeRTOS) +#if defined FSFW_OSAL_FREERTOS countingSemaph = SemaphoreFactory::instance()-> createCountingSemaphore(3, 0, 1); uint8_t semaphCount = countingSemaph->getSemaphoreCounter(); diff --git a/unittest/internal/osal/IntTestSemaphore.h b/tests/src/fsfw_tests/internal/osal/testSemaphore.h similarity index 100% rename from unittest/internal/osal/IntTestSemaphore.h rename to tests/src/fsfw_tests/internal/osal/testSemaphore.h diff --git a/tests/src/fsfw_tests/internal/serialize/CMakeLists.txt b/tests/src/fsfw_tests/internal/serialize/CMakeLists.txt new file mode 100644 index 00000000..47e8b538 --- /dev/null +++ b/tests/src/fsfw_tests/internal/serialize/CMakeLists.txt @@ -0,0 +1,3 @@ +target_sources(${LIB_FSFW_NAME} PRIVATE + IntTestSerialization.cpp +) diff --git a/unittest/internal/serialize/IntTestSerialization.cpp b/tests/src/fsfw_tests/internal/serialize/IntTestSerialization.cpp similarity index 98% rename from unittest/internal/serialize/IntTestSerialization.cpp rename to tests/src/fsfw_tests/internal/serialize/IntTestSerialization.cpp index 69d82942..4720f706 100644 --- a/unittest/internal/serialize/IntTestSerialization.cpp +++ b/tests/src/fsfw_tests/internal/serialize/IntTestSerialization.cpp @@ -1,5 +1,5 @@ -#include "IntTestSerialization.h" -#include +#include "fsfw_tests/internal/serialize/IntTestSerialization.h" +#include "fsfw_tests/internal/UnittDefinitions.h" #include #include diff --git a/unittest/internal/serialize/IntTestSerialization.h b/tests/src/fsfw_tests/internal/serialize/IntTestSerialization.h similarity index 88% rename from unittest/internal/serialize/IntTestSerialization.h rename to tests/src/fsfw_tests/internal/serialize/IntTestSerialization.h index 8706e057..0767fb44 100644 --- a/unittest/internal/serialize/IntTestSerialization.h +++ b/tests/src/fsfw_tests/internal/serialize/IntTestSerialization.h @@ -1,7 +1,7 @@ #ifndef FSFW_UNITTEST_INTERNAL_INTTESTSERIALIZATION_H_ #define FSFW_UNITTEST_INTERNAL_INTTESTSERIALIZATION_H_ -#include "../../../returnvalues/HasReturnvaluesIF.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" #include namespace testserialize { diff --git a/tests/src/fsfw_tests/unit/CMakeLists.txt b/tests/src/fsfw_tests/unit/CMakeLists.txt new file mode 100644 index 00000000..164e3bde --- /dev/null +++ b/tests/src/fsfw_tests/unit/CMakeLists.txt @@ -0,0 +1,23 @@ +target_sources(${FSFW_TEST_TGT} PRIVATE + CatchDefinitions.cpp + CatchFactory.cpp + printChar.cpp +) + +# if(FSFW_CUSTOM_UNITTEST_RUNNER) + target_sources(${FSFW_TEST_TGT} PRIVATE + CatchRunner.cpp + CatchSetup.cpp + ) +# endif() + +add_subdirectory(testcfg) +add_subdirectory(action) +add_subdirectory(container) +add_subdirectory(osal) +add_subdirectory(serialize) +add_subdirectory(datapoollocal) +add_subdirectory(storagemanager) +add_subdirectory(globalfunctions) +add_subdirectory(timemanager) +add_subdirectory(tmtcpacket) diff --git a/unittest/user/unittest/core/CatchDefinitions.cpp b/tests/src/fsfw_tests/unit/CatchDefinitions.cpp similarity index 68% rename from unittest/user/unittest/core/CatchDefinitions.cpp rename to tests/src/fsfw_tests/unit/CatchDefinitions.cpp index bae02875..c44a561e 100644 --- a/unittest/user/unittest/core/CatchDefinitions.cpp +++ b/tests/src/fsfw_tests/unit/CatchDefinitions.cpp @@ -1,10 +1,10 @@ #include "CatchDefinitions.h" #include -#include +#include StorageManagerIF* tglob::getIpcStoreHandle() { - if(objectManager != nullptr) { - return objectManager->get(objects::IPC_STORE); + if(ObjectManager::instance() != nullptr) { + return ObjectManager::instance()->get(objects::IPC_STORE); } else { #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "Global object manager uninitialized" << std::endl; diff --git a/unittest/user/unittest/core/CatchDefinitions.h b/tests/src/fsfw_tests/unit/CatchDefinitions.h similarity index 100% rename from unittest/user/unittest/core/CatchDefinitions.h rename to tests/src/fsfw_tests/unit/CatchDefinitions.h diff --git a/unittest/user/unittest/core/CatchFactory.cpp b/tests/src/fsfw_tests/unit/CatchFactory.cpp similarity index 86% rename from unittest/user/unittest/core/CatchFactory.cpp rename to tests/src/fsfw_tests/unit/CatchFactory.cpp index eabaa21d..42cb927e 100644 --- a/unittest/user/unittest/core/CatchFactory.cpp +++ b/tests/src/fsfw_tests/unit/CatchFactory.cpp @@ -1,17 +1,22 @@ +#include "CatchFactory.h" +#include "tests/TestsConfig.h" +#include "datapoollocal/LocalPoolOwnerBase.h" +#include "mocks/HkReceiverMock.h" + #include #include -#include "CatchFactory.h" #include #include -#include +#include #include #include -#include +#include #include #include -#include -#include + + +#if FSFW_ADD_DEFAULT_FACTORY_FUNCTIONS == 1 /** * @brief Produces system objects. @@ -26,7 +31,7 @@ * * @ingroup init */ -void Factory::produce(void) { +void Factory::produceFrameworkObjects(void* args) { setStaticFrameworkObjectIds(); new EventManager(objects::EVENT_MANAGER); new HealthTable(objects::HEALTH_TABLE); @@ -55,7 +60,6 @@ void Factory::produce(void) { }; new PoolManager(objects::IPC_STORE, poolCfg); } - } void Factory::setStaticFrameworkObjectIds() { @@ -74,8 +78,7 @@ void Factory::setStaticFrameworkObjectIds() { DeviceHandlerFailureIsolation::powerConfirmationId = objects::NO_OBJECT; - TmPacketStored::timeStamperId = objects::NO_OBJECT; + TmPacketBase::timeStamperId = objects::NO_OBJECT; } - - +#endif diff --git a/tests/src/fsfw_tests/unit/CatchFactory.h b/tests/src/fsfw_tests/unit/CatchFactory.h new file mode 100644 index 00000000..cc14e3d9 --- /dev/null +++ b/tests/src/fsfw_tests/unit/CatchFactory.h @@ -0,0 +1,24 @@ +#ifndef FSFW_CATCHFACTORY_H_ +#define FSFW_CATCHFACTORY_H_ + +#include "tests/TestsConfig.h" +#include "fsfw/objectmanager/SystemObjectIF.h" +#include "fsfw/objectmanager/ObjectManager.h" + +// TODO: It is possible to solve this more cleanly using a special class which +// is allowed to set the object IDs and has virtual functions. +#if FSFW_ADD_DEFAULT_FACTORY_FUNCTIONS == 1 + +namespace Factory { + /** + * @brief Creates all SystemObject elements which are persistent + * during execution. + */ + void produceFrameworkObjects(void* args); + void setStaticFrameworkObjectIds(); + +} + +#endif /* FSFW_ADD_DEFAULT_FSFW_FACTORY == 1 */ + +#endif /* FSFW_CATCHFACTORY_H_ */ diff --git a/unittest/user/unittest/core/CatchRunner.cpp b/tests/src/fsfw_tests/unit/CatchRunner.cpp similarity index 80% rename from unittest/user/unittest/core/CatchRunner.cpp rename to tests/src/fsfw_tests/unit/CatchRunner.cpp index 886d641f..1ea3ab35 100644 --- a/unittest/user/unittest/core/CatchRunner.cpp +++ b/tests/src/fsfw_tests/unit/CatchRunner.cpp @@ -6,7 +6,7 @@ * from the eclipse market place to get colored characters. */ -#include +#include "CatchRunner.h" #define CATCH_CONFIG_COLOUR_WINDOWS @@ -14,11 +14,11 @@ extern int customSetup(); -int main( int argc, char* argv[] ) { +int main(int argc, char* argv[]) { customSetup(); // Catch internal function call - int result = Catch::Session().run( argc, argv ); + int result = Catch::Session().run(argc, argv); // global clean-up return result; diff --git a/tests/src/fsfw_tests/unit/CatchRunner.h b/tests/src/fsfw_tests/unit/CatchRunner.h new file mode 100644 index 00000000..06ff07b6 --- /dev/null +++ b/tests/src/fsfw_tests/unit/CatchRunner.h @@ -0,0 +1,14 @@ +#ifndef FSFW_TESTS_USER_UNITTEST_CORE_CATCHRUNNER_H_ +#define FSFW_TESTS_USER_UNITTEST_CORE_CATCHRUNNER_H_ + +namespace fsfwtest { + +/** + * Can be called by upper level main() if default Catch2 main is overriden + * @return + */ +//int customMain(int argc, char* argv[]); + +} + +#endif /* FSFW_TESTS_USER_UNITTEST_CORE_CATCHRUNNER_H_ */ diff --git a/unittest/user/unittest/core/CatchSetup.cpp b/tests/src/fsfw_tests/unit/CatchSetup.cpp similarity index 57% rename from unittest/user/unittest/core/CatchSetup.cpp rename to tests/src/fsfw_tests/unit/CatchSetup.cpp index bda31400..a0791bc9 100644 --- a/unittest/user/unittest/core/CatchSetup.cpp +++ b/tests/src/fsfw_tests/unit/CatchSetup.cpp @@ -5,10 +5,9 @@ #include #endif -#include -#include -#include -#include +#include "fsfw/objectmanager/ObjectManager.h" +#include "fsfw/storagemanager/StorageManagerIF.h" +#include "fsfw/serviceinterface/ServiceInterface.h" /* Global instantiations normally done in main.cpp */ @@ -24,13 +23,11 @@ ServiceInterfaceStream warning("WARNING"); } #endif -/* Global object manager */ -ObjectManagerIF *objectManager; - int customSetup() { // global setup - objectManager = new ObjectManager(Factory::produce); - objectManager -> initialize(); + ObjectManager* objMan = ObjectManager::instance(); + objMan->setObjectFactoryFunction(Factory::produceFrameworkObjects, nullptr); + objMan->initialize(); return 0; } diff --git a/tests/src/fsfw_tests/unit/action/CMakeLists.txt b/tests/src/fsfw_tests/unit/action/CMakeLists.txt new file mode 100644 index 00000000..659f251a --- /dev/null +++ b/tests/src/fsfw_tests/unit/action/CMakeLists.txt @@ -0,0 +1,3 @@ +target_sources(${FSFW_TEST_TGT} PRIVATE + TestActionHelper.cpp +) diff --git a/unittest/tests/action/TestActionHelper.cpp b/tests/src/fsfw_tests/unit/action/TestActionHelper.cpp similarity index 97% rename from unittest/tests/action/TestActionHelper.cpp rename to tests/src/fsfw_tests/unit/action/TestActionHelper.cpp index d8bd58c9..3129b001 100644 --- a/unittest/tests/action/TestActionHelper.cpp +++ b/tests/src/fsfw_tests/unit/action/TestActionHelper.cpp @@ -1,13 +1,10 @@ #include "TestActionHelper.h" - -#include +#include "fsfw_tests/unit/mocks/MessageQueueMockBase.h" #include #include -#include #include - #include diff --git a/unittest/tests/action/TestActionHelper.h b/tests/src/fsfw_tests/unit/action/TestActionHelper.h similarity index 96% rename from unittest/tests/action/TestActionHelper.h rename to tests/src/fsfw_tests/unit/action/TestActionHelper.h index 641ea2c6..34b228c0 100644 --- a/unittest/tests/action/TestActionHelper.h +++ b/tests/src/fsfw_tests/unit/action/TestActionHelper.h @@ -1,12 +1,11 @@ #ifndef UNITTEST_HOSTED_TESTACTIONHELPER_H_ #define UNITTEST_HOSTED_TESTACTIONHELPER_H_ +#include "fsfw_tests/unit/CatchDefinitions.h" #include #include -#include #include - class ActionHelperOwnerMockBase: public HasActionsIF { public: bool getCommandQueueCalled = false; diff --git a/unittest/tests/container/CMakeLists.txt b/tests/src/fsfw_tests/unit/container/CMakeLists.txt similarity index 81% rename from unittest/tests/container/CMakeLists.txt rename to tests/src/fsfw_tests/unit/container/CMakeLists.txt index 966c5834..5dae974c 100644 --- a/unittest/tests/container/CMakeLists.txt +++ b/tests/src/fsfw_tests/unit/container/CMakeLists.txt @@ -1,4 +1,4 @@ -target_sources(${TARGET_NAME} PRIVATE +target_sources(${FSFW_TEST_TGT} PRIVATE RingBufferTest.cpp TestArrayList.cpp TestDynamicFifo.cpp diff --git a/unittest/tests/container/RingBufferTest.cpp b/tests/src/fsfw_tests/unit/container/RingBufferTest.cpp similarity index 99% rename from unittest/tests/container/RingBufferTest.cpp rename to tests/src/fsfw_tests/unit/container/RingBufferTest.cpp index 32a2502d..0be8b2a7 100644 --- a/unittest/tests/container/RingBufferTest.cpp +++ b/tests/src/fsfw_tests/unit/container/RingBufferTest.cpp @@ -1,4 +1,4 @@ -#include +#include "fsfw_tests/unit/CatchDefinitions.h" #include #include @@ -78,7 +78,7 @@ TEST_CASE("Ring Buffer Test" , "[RingBufferTest]") { TEST_CASE("Ring Buffer Test2" , "[RingBufferTest2]") { uint8_t testData[13]= {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; uint8_t readBuffer[10] = {13, 13, 13, 13, 13, 13, 13, 13, 13, 13}; - uint8_t* newBuffer = new uint8_t[10]; + uint8_t* newBuffer = new uint8_t[15]; SimpleRingBuffer ringBuffer(newBuffer, 10, true, 5); SECTION("Simple Test") { @@ -168,7 +168,7 @@ TEST_CASE("Ring Buffer Test2" , "[RingBufferTest2]") { TEST_CASE("Ring Buffer Test3" , "[RingBufferTest3]") { uint8_t testData[13]= {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; uint8_t readBuffer[10] = {13, 13, 13, 13, 13, 13, 13, 13, 13, 13}; - uint8_t* newBuffer = new uint8_t[10]; + uint8_t* newBuffer = new uint8_t[25]; SimpleRingBuffer ringBuffer(newBuffer, 10, true, 15); SECTION("Simple Test") { diff --git a/unittest/tests/container/TestArrayList.cpp b/tests/src/fsfw_tests/unit/container/TestArrayList.cpp similarity index 98% rename from unittest/tests/container/TestArrayList.cpp rename to tests/src/fsfw_tests/unit/container/TestArrayList.cpp index 1fd330b6..9417144c 100644 --- a/unittest/tests/container/TestArrayList.cpp +++ b/tests/src/fsfw_tests/unit/container/TestArrayList.cpp @@ -1,8 +1,9 @@ +#include "fsfw_tests/unit/CatchDefinitions.h" + #include #include #include -#include /** * @brief Array List test diff --git a/unittest/tests/container/TestDynamicFifo.cpp b/tests/src/fsfw_tests/unit/container/TestDynamicFifo.cpp similarity index 99% rename from unittest/tests/container/TestDynamicFifo.cpp rename to tests/src/fsfw_tests/unit/container/TestDynamicFifo.cpp index 2b572d52..a1bab3ba 100644 --- a/unittest/tests/container/TestDynamicFifo.cpp +++ b/tests/src/fsfw_tests/unit/container/TestDynamicFifo.cpp @@ -1,9 +1,10 @@ +#include "fsfw_tests/unit/CatchDefinitions.h" + #include #include #include #include -#include TEST_CASE( "Dynamic Fifo Tests", "[TestDynamicFifo]") { INFO("Dynamic Fifo Tests"); diff --git a/unittest/tests/container/TestFifo.cpp b/tests/src/fsfw_tests/unit/container/TestFifo.cpp similarity index 98% rename from unittest/tests/container/TestFifo.cpp rename to tests/src/fsfw_tests/unit/container/TestFifo.cpp index fbcd40cc..311dd8fd 100644 --- a/unittest/tests/container/TestFifo.cpp +++ b/tests/src/fsfw_tests/unit/container/TestFifo.cpp @@ -1,9 +1,10 @@ +#include "fsfw_tests/unit/CatchDefinitions.h" + #include #include #include #include -#include TEST_CASE( "Static Fifo Tests", "[TestFifo]") { INFO("Fifo Tests"); diff --git a/unittest/tests/container/TestFixedArrayList.cpp b/tests/src/fsfw_tests/unit/container/TestFixedArrayList.cpp similarity index 95% rename from unittest/tests/container/TestFixedArrayList.cpp rename to tests/src/fsfw_tests/unit/container/TestFixedArrayList.cpp index 1a85f30d..ed597f73 100644 --- a/unittest/tests/container/TestFixedArrayList.cpp +++ b/tests/src/fsfw_tests/unit/container/TestFixedArrayList.cpp @@ -1,8 +1,9 @@ +#include "fsfw_tests/unit/CatchDefinitions.h" + #include #include #include -#include TEST_CASE( "FixedArrayList Tests", "[TestFixedArrayList]") { diff --git a/unittest/tests/container/TestFixedMap.cpp b/tests/src/fsfw_tests/unit/container/TestFixedMap.cpp similarity index 99% rename from unittest/tests/container/TestFixedMap.cpp rename to tests/src/fsfw_tests/unit/container/TestFixedMap.cpp index 297171ca..488418b9 100644 --- a/unittest/tests/container/TestFixedMap.cpp +++ b/tests/src/fsfw_tests/unit/container/TestFixedMap.cpp @@ -1,8 +1,9 @@ +#include "fsfw_tests/unit/CatchDefinitions.h" + #include #include #include -#include template class FixedMap; diff --git a/unittest/tests/container/TestFixedOrderedMultimap.cpp b/tests/src/fsfw_tests/unit/container/TestFixedOrderedMultimap.cpp similarity index 99% rename from unittest/tests/container/TestFixedOrderedMultimap.cpp rename to tests/src/fsfw_tests/unit/container/TestFixedOrderedMultimap.cpp index a47d6efb..23d91744 100644 --- a/unittest/tests/container/TestFixedOrderedMultimap.cpp +++ b/tests/src/fsfw_tests/unit/container/TestFixedOrderedMultimap.cpp @@ -1,8 +1,9 @@ +#include "fsfw_tests/unit/CatchDefinitions.h" + #include #include #include -#include TEST_CASE( "FixedOrderedMultimap Tests", "[TestFixedOrderedMultimap]") { INFO("FixedOrderedMultimap Tests"); diff --git a/unittest/tests/container/TestPlacementFactory.cpp b/tests/src/fsfw_tests/unit/container/TestPlacementFactory.cpp similarity index 97% rename from unittest/tests/container/TestPlacementFactory.cpp rename to tests/src/fsfw_tests/unit/container/TestPlacementFactory.cpp index 14cf8eb4..1e328fc7 100644 --- a/unittest/tests/container/TestPlacementFactory.cpp +++ b/tests/src/fsfw_tests/unit/container/TestPlacementFactory.cpp @@ -1,10 +1,11 @@ +#include "fsfw_tests/unit/CatchDefinitions.h" + #include #include #include #include #include -#include TEST_CASE( "PlacementFactory Tests", "[TestPlacementFactory]") { INFO("PlacementFactory Tests"); diff --git a/unittest/tests/datapoollocal/CMakeLists.txt b/tests/src/fsfw_tests/unit/datapoollocal/CMakeLists.txt similarity index 75% rename from unittest/tests/datapoollocal/CMakeLists.txt rename to tests/src/fsfw_tests/unit/datapoollocal/CMakeLists.txt index 1c98e7dc..bf465282 100644 --- a/unittest/tests/datapoollocal/CMakeLists.txt +++ b/tests/src/fsfw_tests/unit/datapoollocal/CMakeLists.txt @@ -1,4 +1,4 @@ -target_sources(${TARGET_NAME} PRIVATE +target_sources(${FSFW_TEST_TGT} PRIVATE LocalPoolVariableTest.cpp LocalPoolVectorTest.cpp DataSetTest.cpp diff --git a/unittest/tests/datapoollocal/DataSetTest.cpp b/tests/src/fsfw_tests/unit/datapoollocal/DataSetTest.cpp similarity index 94% rename from unittest/tests/datapoollocal/DataSetTest.cpp rename to tests/src/fsfw_tests/unit/datapoollocal/DataSetTest.cpp index d0b13e86..e84f07b6 100644 --- a/unittest/tests/datapoollocal/DataSetTest.cpp +++ b/tests/src/fsfw_tests/unit/datapoollocal/DataSetTest.cpp @@ -1,18 +1,19 @@ #include "LocalPoolOwnerBase.h" +#include "tests/TestsConfig.h" +#include "fsfw_tests/unit/CatchDefinitions.h" -#include -#include - +#include #include #include #include #include #include -#include +#include +#include TEST_CASE("DataSetTest" , "[DataSetTest]") { - LocalPoolOwnerBase* poolOwner = objectManager-> + LocalPoolOwnerBase* poolOwner = ObjectManager::instance()-> get(objects::TEST_LOCAL_POOL_OWNER_BASE); REQUIRE(poolOwner != nullptr); REQUIRE(poolOwner->initializeHkManager() == retval::CATCH_OK); @@ -170,14 +171,19 @@ TEST_CASE("DataSetTest" , "[DataSetTest]") { /* We can do it like this because the buffer only has one byte for less than 8 variables */ uint8_t* validityByte = buffer + sizeof(buffer) - 1; - CHECK(bitutil::bitGet(validityByte, 0) == true); - CHECK(bitutil::bitGet(validityByte, 1) == false); - CHECK(bitutil::bitGet(validityByte, 2) == true); + bool bitSet = false; + bitutil::get(validityByte, 0, bitSet); + + CHECK(bitSet == true); + bitutil::get(validityByte, 1, bitSet); + CHECK(bitSet == false); + bitutil::get(validityByte, 2, bitSet); + CHECK(bitSet == true); /* Now we manipulate the validity buffer for the deserialization */ - bitutil::bitClear(validityByte, 0); - bitutil::bitSet(validityByte, 1); - bitutil::bitClear(validityByte, 2); + bitutil::clear(validityByte, 0); + bitutil::set(validityByte, 1); + bitutil::clear(validityByte, 2); /* Zero out everything except validity buffer */ std::memset(buffer, 0, sizeof(buffer) - 1); sizeToDeserialize = maxSize; @@ -238,8 +244,11 @@ TEST_CASE("DataSetTest" , "[DataSetTest]") { std::memcpy(validityBuffer.data(), buffer + 9 + sizeof(uint16_t) * 3, 2); /* The first 9 variables should be valid */ CHECK(validityBuffer[0] == 0xff); - CHECK(bitutil::bitGet(validityBuffer.data() + 1, 0) == true); - CHECK(bitutil::bitGet(validityBuffer.data() + 1, 1) == false); + bool bitSet = false; + bitutil::get(validityBuffer.data() + 1, 0, bitSet); + CHECK(bitSet == true); + bitutil::get(validityBuffer.data() + 1, 1, bitSet); + CHECK(bitSet == false); /* Now we invert the validity */ validityBuffer[0] = 0; diff --git a/unittest/tests/datapoollocal/LocalPoolManagerTest.cpp b/tests/src/fsfw_tests/unit/datapoollocal/LocalPoolManagerTest.cpp similarity index 99% rename from unittest/tests/datapoollocal/LocalPoolManagerTest.cpp rename to tests/src/fsfw_tests/unit/datapoollocal/LocalPoolManagerTest.cpp index 52485b01..b1160254 100644 --- a/unittest/tests/datapoollocal/LocalPoolManagerTest.cpp +++ b/tests/src/fsfw_tests/unit/datapoollocal/LocalPoolManagerTest.cpp @@ -1,20 +1,22 @@ #include "LocalPoolOwnerBase.h" +#include "fsfw_tests/unit/CatchDefinitions.h" -#include -#include - +#include #include #include #include #include #include #include -#include + +#include +#include + #include TEST_CASE("LocalPoolManagerTest" , "[LocManTest]") { - LocalPoolOwnerBase* poolOwner = objectManager-> + LocalPoolOwnerBase* poolOwner = ObjectManager::instance()-> get(objects::TEST_LOCAL_POOL_OWNER_BASE); REQUIRE(poolOwner != nullptr); REQUIRE(poolOwner->initializeHkManager() == retval::CATCH_OK); @@ -141,7 +143,7 @@ TEST_CASE("LocalPoolManagerTest" , "[LocManTest]") { CHECK(cdsShort.msDay_h == Catch::Approx(timeCdsNow.msDay_h).margin(1)); CHECK(cdsShort.msDay_hh == Catch::Approx(timeCdsNow.msDay_hh).margin(1)); CHECK(cdsShort.msDay_l == Catch::Approx(timeCdsNow.msDay_l).margin(1)); - CHECK(cdsShort.msDay_ll == Catch::Approx(timeCdsNow.msDay_ll).margin(1)); + CHECK(cdsShort.msDay_ll == Catch::Approx(timeCdsNow.msDay_ll).margin(5)); } SECTION("VariableSnapshotTest") { @@ -203,7 +205,7 @@ TEST_CASE("LocalPoolManagerTest" , "[LocManTest]") { CHECK(cdsShort.msDay_h == Catch::Approx(timeCdsNow.msDay_h).margin(1)); CHECK(cdsShort.msDay_hh == Catch::Approx(timeCdsNow.msDay_hh).margin(1)); CHECK(cdsShort.msDay_l == Catch::Approx(timeCdsNow.msDay_l).margin(1)); - CHECK(cdsShort.msDay_ll == Catch::Approx(timeCdsNow.msDay_ll).margin(1)); + CHECK(cdsShort.msDay_ll == Catch::Approx(timeCdsNow.msDay_ll).margin(5)); } SECTION("VariableNotificationTest") { diff --git a/unittest/tests/datapoollocal/LocalPoolOwnerBase.cpp b/tests/src/fsfw_tests/unit/datapoollocal/LocalPoolOwnerBase.cpp similarity index 100% rename from unittest/tests/datapoollocal/LocalPoolOwnerBase.cpp rename to tests/src/fsfw_tests/unit/datapoollocal/LocalPoolOwnerBase.cpp diff --git a/unittest/tests/datapoollocal/LocalPoolOwnerBase.h b/tests/src/fsfw_tests/unit/datapoollocal/LocalPoolOwnerBase.h similarity index 98% rename from unittest/tests/datapoollocal/LocalPoolOwnerBase.h rename to tests/src/fsfw_tests/unit/datapoollocal/LocalPoolOwnerBase.h index 8d2073b0..1f532568 100644 --- a/unittest/tests/datapoollocal/LocalPoolOwnerBase.h +++ b/tests/src/fsfw_tests/unit/datapoollocal/LocalPoolOwnerBase.h @@ -1,7 +1,8 @@ #ifndef FSFW_UNITTEST_TESTS_DATAPOOLLOCAL_LOCALPOOLOWNERBASE_H_ #define FSFW_UNITTEST_TESTS_DATAPOOLLOCAL_LOCALPOOLOWNERBASE_H_ -#include +#include "tests/TestsConfig.h" +#include "../mocks/MessageQueueMockBase.h" #include #include @@ -10,7 +11,6 @@ #include #include #include -#include #include namespace lpool { diff --git a/unittest/tests/datapoollocal/LocalPoolVariableTest.cpp b/tests/src/fsfw_tests/unit/datapoollocal/LocalPoolVariableTest.cpp similarity index 96% rename from unittest/tests/datapoollocal/LocalPoolVariableTest.cpp rename to tests/src/fsfw_tests/unit/datapoollocal/LocalPoolVariableTest.cpp index 980ffda1..b029ec26 100644 --- a/unittest/tests/datapoollocal/LocalPoolVariableTest.cpp +++ b/tests/src/fsfw_tests/unit/datapoollocal/LocalPoolVariableTest.cpp @@ -1,12 +1,14 @@ #include "LocalPoolOwnerBase.h" +#include "tests/TestsConfig.h" +#include "fsfw_tests/unit/CatchDefinitions.h" + +#include +#include #include -#include -#include - TEST_CASE("LocalPoolVariable" , "[LocPoolVarTest]") { - LocalPoolOwnerBase* poolOwner = objectManager-> + LocalPoolOwnerBase* poolOwner = ObjectManager::instance()-> get(objects::TEST_LOCAL_POOL_OWNER_BASE); REQUIRE(poolOwner != nullptr); REQUIRE(poolOwner->initializeHkManager() == retval::CATCH_OK); diff --git a/unittest/tests/datapoollocal/LocalPoolVectorTest.cpp b/tests/src/fsfw_tests/unit/datapoollocal/LocalPoolVectorTest.cpp similarity index 96% rename from unittest/tests/datapoollocal/LocalPoolVectorTest.cpp rename to tests/src/fsfw_tests/unit/datapoollocal/LocalPoolVectorTest.cpp index db76fc00..5298e5b9 100644 --- a/unittest/tests/datapoollocal/LocalPoolVectorTest.cpp +++ b/tests/src/fsfw_tests/unit/datapoollocal/LocalPoolVectorTest.cpp @@ -1,11 +1,14 @@ #include "LocalPoolOwnerBase.h" +#include "tests/TestsConfig.h" +#include "fsfw_tests/unit/CatchDefinitions.h" #include +#include #include -#include + TEST_CASE("LocalPoolVector" , "[LocPoolVecTest]") { - LocalPoolOwnerBase* poolOwner = objectManager-> + LocalPoolOwnerBase* poolOwner = ObjectManager::instance()-> get(objects::TEST_LOCAL_POOL_OWNER_BASE); REQUIRE(poolOwner != nullptr); REQUIRE(poolOwner->initializeHkManager() == retval::CATCH_OK); diff --git a/tests/src/fsfw_tests/unit/globalfunctions/CMakeLists.txt b/tests/src/fsfw_tests/unit/globalfunctions/CMakeLists.txt new file mode 100644 index 00000000..3b29f23f --- /dev/null +++ b/tests/src/fsfw_tests/unit/globalfunctions/CMakeLists.txt @@ -0,0 +1,5 @@ +target_sources(${FSFW_TEST_TGT} PRIVATE + testDleEncoder.cpp + testOpDivider.cpp + testBitutil.cpp +) diff --git a/tests/src/fsfw_tests/unit/globalfunctions/testBitutil.cpp b/tests/src/fsfw_tests/unit/globalfunctions/testBitutil.cpp new file mode 100644 index 00000000..2627adcf --- /dev/null +++ b/tests/src/fsfw_tests/unit/globalfunctions/testBitutil.cpp @@ -0,0 +1,64 @@ +#include "fsfw/globalfunctions/bitutility.h" +#include + +TEST_CASE("Bitutility" , "[Bitutility]") { + uint8_t dummyByte = 0; + bool bitSet = false; + for(uint8_t pos = 0; pos < 8; pos++) { + bitutil::set(&dummyByte, pos); + REQUIRE(dummyByte == (1 << (7 - pos))); + bitutil::get(&dummyByte, pos, bitSet); + REQUIRE(bitSet == 1); + dummyByte = 0; + } + + dummyByte = 0xff; + for(uint8_t pos = 0; pos < 8; pos++) { + bitutil::get(&dummyByte, pos, bitSet); + REQUIRE(bitSet == 1); + bitutil::clear(&dummyByte, pos); + bitutil::get(&dummyByte, pos, bitSet); + REQUIRE(bitSet == 0); + dummyByte = 0xff; + } + + dummyByte = 0xf0; + for(uint8_t pos = 0; pos < 8; pos++) { + if(pos < 4) { + bitutil::get(&dummyByte, pos, bitSet); + REQUIRE(bitSet == 1); + bitutil::toggle(&dummyByte, pos); + bitutil::get(&dummyByte, pos, bitSet); + REQUIRE(bitSet == 0); + } + else { + bitutil::get(&dummyByte, pos, bitSet); + REQUIRE(bitSet == false); + bitutil::toggle(&dummyByte, pos); + bitutil::get(&dummyByte, pos, bitSet); + REQUIRE(bitSet == true); + } + } + REQUIRE(dummyByte == 0x0f); + + dummyByte = 0; + bitutil::set(&dummyByte, 8); + REQUIRE(dummyByte == 0); + bitutil::set(&dummyByte, -1); + REQUIRE(dummyByte == 0); + dummyByte = 0xff; + bitutil::clear(&dummyByte, 8); + REQUIRE(dummyByte == 0xff); + bitutil::clear(&dummyByte, -1); + REQUIRE(dummyByte == 0xff); + dummyByte = 0x00; + bitutil::toggle(&dummyByte, 8); + REQUIRE(dummyByte == 0x00); + bitutil::toggle(&dummyByte, -1); + REQUIRE(dummyByte == 0x00); + + REQUIRE(bitutil::get(&dummyByte, 8, bitSet) == false); +} + + + diff --git a/tests/src/fsfw_tests/unit/globalfunctions/testDleEncoder.cpp b/tests/src/fsfw_tests/unit/globalfunctions/testDleEncoder.cpp new file mode 100644 index 00000000..cffd5308 --- /dev/null +++ b/tests/src/fsfw_tests/unit/globalfunctions/testDleEncoder.cpp @@ -0,0 +1,227 @@ +#include "fsfw/globalfunctions/DleEncoder.h" +#include "fsfw_tests/unit/CatchDefinitions.h" +#include "catch2/catch_test_macros.hpp" + +#include + +const std::vector TEST_ARRAY_0 = { 0, 0, 0, 0, 0 }; +const std::vector TEST_ARRAY_1 = { 0, DleEncoder::DLE_CHAR, 5}; +const std::vector TEST_ARRAY_2 = { 0, DleEncoder::STX_CHAR, 5}; +const std::vector TEST_ARRAY_3 = { 0, DleEncoder::CARRIAGE_RETURN, DleEncoder::ETX_CHAR}; +const std::vector TEST_ARRAY_4 = { DleEncoder::DLE_CHAR, DleEncoder::ETX_CHAR, + DleEncoder::STX_CHAR }; + +const std::vector TEST_ARRAY_0_ENCODED_ESCAPED = { + DleEncoder::STX_CHAR, 0, 0, 0, 0, 0, DleEncoder::ETX_CHAR +}; +const std::vector TEST_ARRAY_0_ENCODED_NON_ESCAPED = { + DleEncoder::DLE_CHAR, DleEncoder::STX_CHAR, 0, 0, 0, 0, 0, + DleEncoder::DLE_CHAR, DleEncoder::ETX_CHAR +}; + +const std::vector TEST_ARRAY_1_ENCODED_ESCAPED = { + DleEncoder::STX_CHAR, 0, DleEncoder::DLE_CHAR, DleEncoder::DLE_CHAR, 5, DleEncoder::ETX_CHAR +}; +const std::vector TEST_ARRAY_1_ENCODED_NON_ESCAPED = { + DleEncoder::DLE_CHAR, DleEncoder::STX_CHAR, 0, DleEncoder::DLE_CHAR, DleEncoder::DLE_CHAR, + 5, DleEncoder::DLE_CHAR, DleEncoder::ETX_CHAR +}; + +const std::vector TEST_ARRAY_2_ENCODED_ESCAPED = { + DleEncoder::STX_CHAR, 0, DleEncoder::DLE_CHAR, DleEncoder::STX_CHAR + 0x40, + 5, DleEncoder::ETX_CHAR +}; +const std::vector TEST_ARRAY_2_ENCODED_NON_ESCAPED = { + DleEncoder::DLE_CHAR, DleEncoder::STX_CHAR, 0, + DleEncoder::STX_CHAR, 5, DleEncoder::DLE_CHAR, DleEncoder::ETX_CHAR +}; + +const std::vector TEST_ARRAY_3_ENCODED_ESCAPED = { + DleEncoder::STX_CHAR, 0, DleEncoder::CARRIAGE_RETURN, + DleEncoder::DLE_CHAR, DleEncoder::ETX_CHAR + 0x40, DleEncoder::ETX_CHAR +}; +const std::vector TEST_ARRAY_3_ENCODED_NON_ESCAPED = { + DleEncoder::DLE_CHAR, DleEncoder::STX_CHAR, 0, + DleEncoder::CARRIAGE_RETURN, DleEncoder::ETX_CHAR, DleEncoder::DLE_CHAR, + DleEncoder::ETX_CHAR +}; + +const std::vector TEST_ARRAY_4_ENCODED_ESCAPED = { + DleEncoder::STX_CHAR, DleEncoder::DLE_CHAR, DleEncoder::DLE_CHAR, + DleEncoder::DLE_CHAR, DleEncoder::ETX_CHAR + 0x40, DleEncoder::DLE_CHAR, + DleEncoder::STX_CHAR + 0x40, DleEncoder::ETX_CHAR +}; +const std::vector TEST_ARRAY_4_ENCODED_NON_ESCAPED = { + DleEncoder::DLE_CHAR, DleEncoder::STX_CHAR, DleEncoder::DLE_CHAR, DleEncoder::DLE_CHAR, + DleEncoder::ETX_CHAR, DleEncoder::STX_CHAR, DleEncoder::DLE_CHAR, DleEncoder::ETX_CHAR +}; + + +TEST_CASE("DleEncoder" , "[DleEncoder]") { + DleEncoder dleEncoder; + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + std::array buffer; + + size_t encodedLen = 0; + size_t readLen = 0; + size_t decodedLen = 0; + + auto testLambdaEncode = [&](DleEncoder& encoder, const std::vector& vecToEncode, + const std::vector& expectedVec) { + result = encoder.encode(vecToEncode.data(), vecToEncode.size(), + buffer.data(), buffer.size(), &encodedLen); + REQUIRE(result == retval::CATCH_OK); + for(size_t idx = 0; idx < expectedVec.size(); idx++) { + REQUIRE(buffer[idx] == expectedVec[idx]); + } + REQUIRE(encodedLen == expectedVec.size()); + }; + + auto testLambdaDecode = [&](DleEncoder& encoder, const std::vector& testVecEncoded, + const std::vector& expectedVec) { + result = encoder.decode(testVecEncoded.data(), + testVecEncoded.size(), + &readLen, buffer.data(), buffer.size(), &decodedLen); + REQUIRE(result == retval::CATCH_OK); + REQUIRE(readLen == testVecEncoded.size()); + REQUIRE(decodedLen == expectedVec.size()); + for(size_t idx = 0; idx < decodedLen; idx++) { + REQUIRE(buffer[idx] == expectedVec[idx]); + } + }; + + SECTION("Encoding") { + testLambdaEncode(dleEncoder, TEST_ARRAY_0, TEST_ARRAY_0_ENCODED_ESCAPED); + testLambdaEncode(dleEncoder, TEST_ARRAY_1, TEST_ARRAY_1_ENCODED_ESCAPED); + testLambdaEncode(dleEncoder, TEST_ARRAY_2, TEST_ARRAY_2_ENCODED_ESCAPED); + testLambdaEncode(dleEncoder, TEST_ARRAY_3, TEST_ARRAY_3_ENCODED_ESCAPED); + testLambdaEncode(dleEncoder, TEST_ARRAY_4, TEST_ARRAY_4_ENCODED_ESCAPED); + + auto testFaultyEncoding = [&](const std::vector& vecToEncode, + const std::vector& expectedVec) { + + for(size_t faultyDestSize = 0; faultyDestSize < expectedVec.size(); faultyDestSize ++) { + result = dleEncoder.encode(vecToEncode.data(), vecToEncode.size(), + buffer.data(), faultyDestSize, &encodedLen); + REQUIRE(result == static_cast(DleEncoder::STREAM_TOO_SHORT)); + } + }; + + testFaultyEncoding(TEST_ARRAY_0, TEST_ARRAY_0_ENCODED_ESCAPED); + testFaultyEncoding(TEST_ARRAY_1, TEST_ARRAY_1_ENCODED_ESCAPED); + testFaultyEncoding(TEST_ARRAY_2, TEST_ARRAY_2_ENCODED_ESCAPED); + testFaultyEncoding(TEST_ARRAY_3, TEST_ARRAY_3_ENCODED_ESCAPED); + testFaultyEncoding(TEST_ARRAY_4, TEST_ARRAY_4_ENCODED_ESCAPED); + + dleEncoder.setEscapeMode(false); + testLambdaEncode(dleEncoder, TEST_ARRAY_0, TEST_ARRAY_0_ENCODED_NON_ESCAPED); + testLambdaEncode(dleEncoder, TEST_ARRAY_1, TEST_ARRAY_1_ENCODED_NON_ESCAPED); + testLambdaEncode(dleEncoder, TEST_ARRAY_2, TEST_ARRAY_2_ENCODED_NON_ESCAPED); + testLambdaEncode(dleEncoder, TEST_ARRAY_3, TEST_ARRAY_3_ENCODED_NON_ESCAPED); + testLambdaEncode(dleEncoder, TEST_ARRAY_4, TEST_ARRAY_4_ENCODED_NON_ESCAPED); + + testFaultyEncoding(TEST_ARRAY_0, TEST_ARRAY_0_ENCODED_NON_ESCAPED); + testFaultyEncoding(TEST_ARRAY_1, TEST_ARRAY_1_ENCODED_NON_ESCAPED); + testFaultyEncoding(TEST_ARRAY_2, TEST_ARRAY_2_ENCODED_NON_ESCAPED); + testFaultyEncoding(TEST_ARRAY_3, TEST_ARRAY_3_ENCODED_NON_ESCAPED); + testFaultyEncoding(TEST_ARRAY_4, TEST_ARRAY_4_ENCODED_NON_ESCAPED); + dleEncoder.setEscapeMode(true); + } + + SECTION("Decoding") { + testLambdaDecode(dleEncoder, TEST_ARRAY_0_ENCODED_ESCAPED, TEST_ARRAY_0); + testLambdaDecode(dleEncoder, TEST_ARRAY_1_ENCODED_ESCAPED, TEST_ARRAY_1); + testLambdaDecode(dleEncoder, TEST_ARRAY_2_ENCODED_ESCAPED, TEST_ARRAY_2); + testLambdaDecode(dleEncoder, TEST_ARRAY_3_ENCODED_ESCAPED, TEST_ARRAY_3); + testLambdaDecode(dleEncoder, TEST_ARRAY_4_ENCODED_ESCAPED, TEST_ARRAY_4); + + // Faulty source data + auto testArray1EncodedFaulty = TEST_ARRAY_1_ENCODED_ESCAPED; + testArray1EncodedFaulty[3] = 0; + result = dleEncoder.decode(testArray1EncodedFaulty.data(), testArray1EncodedFaulty.size(), + &readLen, buffer.data(), buffer.size(), &encodedLen); + REQUIRE(result == static_cast(DleEncoder::DECODING_ERROR)); + auto testArray2EncodedFaulty = TEST_ARRAY_2_ENCODED_ESCAPED; + testArray2EncodedFaulty[5] = 0; + result = dleEncoder.decode(testArray2EncodedFaulty.data(), testArray2EncodedFaulty.size(), + &readLen, buffer.data(), buffer.size(), &encodedLen); + REQUIRE(result == static_cast(DleEncoder::DECODING_ERROR)); + auto testArray4EncodedFaulty = TEST_ARRAY_4_ENCODED_ESCAPED; + testArray4EncodedFaulty[2] = 0; + result = dleEncoder.decode(testArray4EncodedFaulty.data(), testArray4EncodedFaulty.size(), + &readLen, buffer.data(), buffer.size(), &encodedLen); + REQUIRE(result == static_cast(DleEncoder::DECODING_ERROR)); + auto testArray4EncodedFaulty2 = TEST_ARRAY_4_ENCODED_ESCAPED; + testArray4EncodedFaulty2[4] = 0; + result = dleEncoder.decode(testArray4EncodedFaulty2.data(), testArray4EncodedFaulty2.size(), + &readLen, buffer.data(), buffer.size(), &encodedLen); + REQUIRE(result == static_cast(DleEncoder::DECODING_ERROR)); + + auto testFaultyDecoding = [&](const std::vector& vecToDecode, + const std::vector& expectedVec) { + for(size_t faultyDestSizes = 0; + faultyDestSizes < expectedVec.size(); + faultyDestSizes ++) { + result = dleEncoder.decode(vecToDecode.data(), + vecToDecode.size(), &readLen, + buffer.data(), faultyDestSizes, &decodedLen); + REQUIRE(result == static_cast(DleEncoder::STREAM_TOO_SHORT)); + } + }; + + testFaultyDecoding(TEST_ARRAY_0_ENCODED_ESCAPED, TEST_ARRAY_0); + testFaultyDecoding(TEST_ARRAY_1_ENCODED_ESCAPED, TEST_ARRAY_1); + testFaultyDecoding(TEST_ARRAY_2_ENCODED_ESCAPED, TEST_ARRAY_2); + testFaultyDecoding(TEST_ARRAY_3_ENCODED_ESCAPED, TEST_ARRAY_3); + testFaultyDecoding(TEST_ARRAY_4_ENCODED_ESCAPED, TEST_ARRAY_4); + + dleEncoder.setEscapeMode(false); + testLambdaDecode(dleEncoder, TEST_ARRAY_0_ENCODED_NON_ESCAPED, TEST_ARRAY_0); + testLambdaDecode(dleEncoder, TEST_ARRAY_1_ENCODED_NON_ESCAPED, TEST_ARRAY_1); + testLambdaDecode(dleEncoder, TEST_ARRAY_2_ENCODED_NON_ESCAPED, TEST_ARRAY_2); + testLambdaDecode(dleEncoder, TEST_ARRAY_3_ENCODED_NON_ESCAPED, TEST_ARRAY_3); + testLambdaDecode(dleEncoder, TEST_ARRAY_4_ENCODED_NON_ESCAPED, TEST_ARRAY_4); + + testFaultyDecoding(TEST_ARRAY_0_ENCODED_NON_ESCAPED, TEST_ARRAY_0); + testFaultyDecoding(TEST_ARRAY_1_ENCODED_NON_ESCAPED, TEST_ARRAY_1); + testFaultyDecoding(TEST_ARRAY_2_ENCODED_NON_ESCAPED, TEST_ARRAY_2); + testFaultyDecoding(TEST_ARRAY_3_ENCODED_NON_ESCAPED, TEST_ARRAY_3); + testFaultyDecoding(TEST_ARRAY_4_ENCODED_NON_ESCAPED, TEST_ARRAY_4); + + // Faulty source data + testArray1EncodedFaulty = TEST_ARRAY_1_ENCODED_NON_ESCAPED; + auto prevVal = testArray1EncodedFaulty[0]; + testArray1EncodedFaulty[0] = 0; + result = dleEncoder.decode(testArray1EncodedFaulty.data(), testArray1EncodedFaulty.size(), + &readLen, buffer.data(), buffer.size(), &encodedLen); + REQUIRE(result == static_cast(DleEncoder::DECODING_ERROR)); + testArray1EncodedFaulty[0] = prevVal; + testArray1EncodedFaulty[1] = 0; + result = dleEncoder.decode(testArray1EncodedFaulty.data(), testArray1EncodedFaulty.size(), + &readLen, buffer.data(), buffer.size(), &encodedLen); + REQUIRE(result == static_cast(DleEncoder::DECODING_ERROR)); + + testArray1EncodedFaulty = TEST_ARRAY_1_ENCODED_NON_ESCAPED; + testArray1EncodedFaulty[6] = 0; + result = dleEncoder.decode(testArray1EncodedFaulty.data(), testArray1EncodedFaulty.size(), + &readLen, buffer.data(), buffer.size(), &encodedLen); + REQUIRE(result == static_cast(DleEncoder::DECODING_ERROR)); + testArray1EncodedFaulty = TEST_ARRAY_1_ENCODED_NON_ESCAPED; + testArray1EncodedFaulty[7] = 0; + result = dleEncoder.decode(testArray1EncodedFaulty.data(), testArray1EncodedFaulty.size(), + &readLen, buffer.data(), buffer.size(), &encodedLen); + REQUIRE(result == static_cast(DleEncoder::DECODING_ERROR)); + testArray4EncodedFaulty = TEST_ARRAY_4_ENCODED_NON_ESCAPED; + testArray4EncodedFaulty[3] = 0; + result = dleEncoder.decode(testArray4EncodedFaulty.data(), testArray4EncodedFaulty.size(), + &readLen, buffer.data(), buffer.size(), &encodedLen); + REQUIRE(result == static_cast(DleEncoder::DECODING_ERROR)); + + dleEncoder.setEscapeMode(true); + testArray1EncodedFaulty = TEST_ARRAY_1_ENCODED_ESCAPED; + testArray1EncodedFaulty[5] = 0; + result = dleEncoder.decode(testArray1EncodedFaulty.data(), testArray1EncodedFaulty.size(), + &readLen, buffer.data(), buffer.size(), &encodedLen); + REQUIRE(result == static_cast(DleEncoder::DECODING_ERROR)); + } +} diff --git a/tests/src/fsfw_tests/unit/globalfunctions/testOpDivider.cpp b/tests/src/fsfw_tests/unit/globalfunctions/testOpDivider.cpp new file mode 100644 index 00000000..c02ada83 --- /dev/null +++ b/tests/src/fsfw_tests/unit/globalfunctions/testOpDivider.cpp @@ -0,0 +1,64 @@ +#include "fsfw/globalfunctions/PeriodicOperationDivider.h" +#include + +TEST_CASE("OpDivider" , "[OpDivider]") { + auto opDivider = PeriodicOperationDivider(1); + REQUIRE(opDivider.getDivider() == 1); + REQUIRE(opDivider.getCounter() == 1); + REQUIRE(opDivider.check() == true); + REQUIRE(opDivider.checkAndIncrement() == true); + REQUIRE(opDivider.getCounter() == 1); + REQUIRE(opDivider.check() == true); + REQUIRE(opDivider.checkAndIncrement() == true); + REQUIRE(opDivider.checkAndIncrement() == true); + + opDivider.setDivider(0); + REQUIRE(opDivider.getCounter() == 1); + REQUIRE(opDivider.checkAndIncrement() == true); + REQUIRE(opDivider.getCounter() == 1); + REQUIRE(opDivider.checkAndIncrement() == true); + REQUIRE(opDivider.checkAndIncrement() == true); + + opDivider.setDivider(2); + opDivider.resetCounter(); + REQUIRE(opDivider.getDivider() == 2); + REQUIRE(opDivider.getCounter() == 1); + REQUIRE(opDivider.check() == false); + REQUIRE(opDivider.checkAndIncrement() == false); + REQUIRE(opDivider.getCounter() == 2); + REQUIRE(opDivider.check() == true); + REQUIRE(opDivider.checkAndIncrement() == true); + REQUIRE(opDivider.getCounter() == 1); + REQUIRE(opDivider.check() == false); + REQUIRE(opDivider.checkAndIncrement() == false); + REQUIRE(opDivider.getCounter() == 2); + REQUIRE(opDivider.checkAndIncrement() == true); + REQUIRE(opDivider.checkAndIncrement() == false); + REQUIRE(opDivider.checkAndIncrement() == true); + REQUIRE(opDivider.checkAndIncrement() == false); + + opDivider.setDivider(3); + opDivider.resetCounter(); + REQUIRE(opDivider.checkAndIncrement() == false); + REQUIRE(opDivider.checkAndIncrement() == false); + REQUIRE(opDivider.getCounter() == 3); + REQUIRE(opDivider.checkAndIncrement() == true); + REQUIRE(opDivider.getCounter() == 1); + REQUIRE(opDivider.checkAndIncrement() == false); + + auto opDividerNonResetting = PeriodicOperationDivider(2, false); + REQUIRE(opDividerNonResetting.getCounter() == 1); + REQUIRE(opDividerNonResetting.check() == false); + REQUIRE(opDividerNonResetting.checkAndIncrement() == false); + REQUIRE(opDividerNonResetting.getCounter() == 2); + REQUIRE(opDividerNonResetting.check() == true); + REQUIRE(opDividerNonResetting.checkAndIncrement() == true); + REQUIRE(opDividerNonResetting.getCounter() == 3); + REQUIRE(opDividerNonResetting.checkAndIncrement() == true); + REQUIRE(opDividerNonResetting.getCounter() == 4); + opDividerNonResetting.resetCounter(); + REQUIRE(opDividerNonResetting.getCounter() == 1); + REQUIRE(opDividerNonResetting.check() == false); + REQUIRE(opDividerNonResetting.checkAndIncrement() == false); + REQUIRE(opDividerNonResetting.getCounter() == 2); +} diff --git a/unittest/tests/mocks/HkReceiverMock.h b/tests/src/fsfw_tests/unit/mocks/HkReceiverMock.h similarity index 100% rename from unittest/tests/mocks/HkReceiverMock.h rename to tests/src/fsfw_tests/unit/mocks/HkReceiverMock.h diff --git a/unittest/tests/mocks/MessageQueueMockBase.h b/tests/src/fsfw_tests/unit/mocks/MessageQueueMockBase.h similarity index 95% rename from unittest/tests/mocks/MessageQueueMockBase.h rename to tests/src/fsfw_tests/unit/mocks/MessageQueueMockBase.h index 3000f7fb..93a00b7a 100644 --- a/unittest/tests/mocks/MessageQueueMockBase.h +++ b/tests/src/fsfw_tests/unit/mocks/MessageQueueMockBase.h @@ -1,9 +1,12 @@ #ifndef FSFW_UNITTEST_TESTS_MOCKS_MESSAGEQUEUEMOCKBASE_H_ #define FSFW_UNITTEST_TESTS_MOCKS_MESSAGEQUEUEMOCKBASE_H_ -#include -#include -#include +#include "fsfw_tests/unit/CatchDefinitions.h" + +#include "fsfw/ipc/CommandMessage.h" +#include "fsfw/ipc/MessageQueueIF.h" +#include "fsfw/ipc/MessageQueueMessage.h" + #include #include diff --git a/unittest/tests/osal/CMakeLists.txt b/tests/src/fsfw_tests/unit/osal/CMakeLists.txt similarity index 51% rename from unittest/tests/osal/CMakeLists.txt rename to tests/src/fsfw_tests/unit/osal/CMakeLists.txt index 5ca5e400..293be2e8 100644 --- a/unittest/tests/osal/CMakeLists.txt +++ b/tests/src/fsfw_tests/unit/osal/CMakeLists.txt @@ -1,4 +1,4 @@ -target_sources(${TARGET_NAME} PRIVATE +target_sources(${FSFW_TEST_TGT} PRIVATE TestMessageQueue.cpp TestSemaphore.cpp ) diff --git a/unittest/tests/osal/TestMessageQueue.cpp b/tests/src/fsfw_tests/unit/osal/TestMessageQueue.cpp similarity index 96% rename from unittest/tests/osal/TestMessageQueue.cpp rename to tests/src/fsfw_tests/unit/osal/TestMessageQueue.cpp index e33b7240..07197bf7 100644 --- a/unittest/tests/osal/TestMessageQueue.cpp +++ b/tests/src/fsfw_tests/unit/osal/TestMessageQueue.cpp @@ -1,8 +1,9 @@ +#include "fsfw_tests/unit/CatchDefinitions.h" + #include #include #include -#include #include diff --git a/unittest/tests/osal/TestSemaphore.cpp b/tests/src/fsfw_tests/unit/osal/TestSemaphore.cpp similarity index 100% rename from unittest/tests/osal/TestSemaphore.cpp rename to tests/src/fsfw_tests/unit/osal/TestSemaphore.cpp diff --git a/unittest/user/unittest/core/printChar.cpp b/tests/src/fsfw_tests/unit/printChar.cpp similarity index 100% rename from unittest/user/unittest/core/printChar.cpp rename to tests/src/fsfw_tests/unit/printChar.cpp diff --git a/unittest/user/unittest/core/printChar.h b/tests/src/fsfw_tests/unit/printChar.h similarity index 100% rename from unittest/user/unittest/core/printChar.h rename to tests/src/fsfw_tests/unit/printChar.h diff --git a/unittest/tests/serialize/CMakeLists.txt b/tests/src/fsfw_tests/unit/serialize/CMakeLists.txt similarity index 67% rename from unittest/tests/serialize/CMakeLists.txt rename to tests/src/fsfw_tests/unit/serialize/CMakeLists.txt index 5a9d9a0f..96c80f4a 100644 --- a/unittest/tests/serialize/CMakeLists.txt +++ b/tests/src/fsfw_tests/unit/serialize/CMakeLists.txt @@ -1,4 +1,4 @@ -target_sources(${TARGET_NAME} PRIVATE +target_sources(${FSFW_TEST_TGT} PRIVATE TestSerialBufferAdapter.cpp TestSerialization.cpp TestSerialLinkedPacket.cpp diff --git a/unittest/tests/serialize/TestSerialBufferAdapter.cpp b/tests/src/fsfw_tests/unit/serialize/TestSerialBufferAdapter.cpp similarity index 99% rename from unittest/tests/serialize/TestSerialBufferAdapter.cpp rename to tests/src/fsfw_tests/unit/serialize/TestSerialBufferAdapter.cpp index 1938746d..01d75881 100644 --- a/unittest/tests/serialize/TestSerialBufferAdapter.cpp +++ b/tests/src/fsfw_tests/unit/serialize/TestSerialBufferAdapter.cpp @@ -1,7 +1,9 @@ +#include "fsfw_tests/unit/CatchDefinitions.h" + #include #include -#include + #include diff --git a/unittest/tests/serialize/TestSerialLinkedPacket.cpp b/tests/src/fsfw_tests/unit/serialize/TestSerialLinkedPacket.cpp similarity index 96% rename from unittest/tests/serialize/TestSerialLinkedPacket.cpp rename to tests/src/fsfw_tests/unit/serialize/TestSerialLinkedPacket.cpp index b90ae9f8..b6bb214d 100644 --- a/unittest/tests/serialize/TestSerialLinkedPacket.cpp +++ b/tests/src/fsfw_tests/unit/serialize/TestSerialLinkedPacket.cpp @@ -1,10 +1,9 @@ #include "TestSerialLinkedPacket.h" -#include +#include "fsfw_tests/unit/CatchDefinitions.h" #include #include -#include #include diff --git a/unittest/tests/serialize/TestSerialLinkedPacket.h b/tests/src/fsfw_tests/unit/serialize/TestSerialLinkedPacket.h similarity index 100% rename from unittest/tests/serialize/TestSerialLinkedPacket.h rename to tests/src/fsfw_tests/unit/serialize/TestSerialLinkedPacket.h diff --git a/tests/src/fsfw_tests/unit/serialize/TestSerialization.cpp b/tests/src/fsfw_tests/unit/serialize/TestSerialization.cpp new file mode 100644 index 00000000..f883fe78 --- /dev/null +++ b/tests/src/fsfw_tests/unit/serialize/TestSerialization.cpp @@ -0,0 +1,216 @@ +#include "fsfw_tests/unit/CatchDefinitions.h" +#include + +#include +#include +#include + +#include + +static bool testBool = true; +static uint8_t tvUint8 {5}; +static uint16_t tvUint16 {283}; +static uint32_t tvUint32 {929221}; +static uint64_t tvUint64 {2929329429}; + +static int8_t tvInt8 {-16}; +static int16_t tvInt16 {-829}; +static int32_t tvInt32 {-2312}; + +static float tvFloat {8.2149214}; +static float tvSfloat = {-922.2321321}; +static double tvDouble {9.2132142141e8}; +static double tvSdouble {-2.2421e19}; + +static std::array TEST_ARRAY; + +TEST_CASE( "Serialization size tests", "[SerSizeTest]") { + //REQUIRE(unitTestClass.test_autoserialization() == 0); + REQUIRE(SerializeAdapter::getSerializedSize(&testBool) == + sizeof(testBool)); + REQUIRE(SerializeAdapter::getSerializedSize(&tvUint8) == + sizeof(tvUint8)); + REQUIRE(SerializeAdapter::getSerializedSize(&tvUint16) == + sizeof(tvUint16)); + REQUIRE(SerializeAdapter::getSerializedSize(&tvUint32 ) == + sizeof(tvUint32)); + REQUIRE(SerializeAdapter::getSerializedSize(&tvUint64) == + sizeof(tvUint64)); + REQUIRE(SerializeAdapter::getSerializedSize(&tvInt8) == + sizeof(tvInt8)); + REQUIRE(SerializeAdapter::getSerializedSize(&tvInt16) == + sizeof(tvInt16)); + REQUIRE(SerializeAdapter::getSerializedSize(&tvInt32) == + sizeof(tvInt32)); + REQUIRE(SerializeAdapter::getSerializedSize(&tvFloat) == + sizeof(tvFloat)); + REQUIRE(SerializeAdapter::getSerializedSize(&tvSfloat) == + sizeof(tvSfloat )); + REQUIRE(SerializeAdapter::getSerializedSize(&tvDouble) == + sizeof(tvDouble)); + REQUIRE(SerializeAdapter::getSerializedSize(&tvSdouble) == + sizeof(tvSdouble)); +} + +TEST_CASE("Auto Serialize Adapter", "[SerAdapter]") { + size_t serializedSize = 0; + uint8_t * pArray = TEST_ARRAY.data(); + + SECTION("SerDe") { + size_t deserSize = 0; + SerializeAdapter::serialize(&testBool, TEST_ARRAY.data(), &deserSize, TEST_ARRAY.size(), + SerializeIF::Endianness::MACHINE); + REQUIRE(deserSize == 1); + REQUIRE(TEST_ARRAY[0] == true); + bool readBack = false; + SerializeAdapter::deSerialize(&readBack, TEST_ARRAY.data(), &deserSize, + SerializeIF::Endianness::MACHINE); + REQUIRE(deserSize == 1); + REQUIRE(readBack == true); + SerializeAdapter::serialize(&tvUint8, TEST_ARRAY.data(), &deserSize, TEST_ARRAY.size(), + SerializeIF::Endianness::MACHINE); + REQUIRE(deserSize == 1); + REQUIRE(TEST_ARRAY[0] == 5); + uint8_t readBackUint8 = 0; + uint8_t* const testPtr = TEST_ARRAY.data(); + uint8_t* const shouldStayConst = testPtr; + SerializeAdapter::deSerialize(&readBackUint8, testPtr, &deserSize, + SerializeIF::Endianness::MACHINE); + REQUIRE(testPtr == shouldStayConst); + REQUIRE(deserSize == 1); + REQUIRE(readBackUint8 == 5); + SerializeAdapter::serialize(&tvUint16, TEST_ARRAY.data(), &deserSize, TEST_ARRAY.size(), + SerializeIF::Endianness::MACHINE); + REQUIRE(deserSize == 2); + deserSize = 0; + uint16_t readBackUint16 = 0; + SerializeAdapter::deSerialize(&readBackUint16, TEST_ARRAY.data(), &deserSize, + SerializeIF::Endianness::MACHINE); + REQUIRE(deserSize == 2); + REQUIRE(readBackUint16 == 283); + + SerializeAdapter::serialize(&tvUint32, TEST_ARRAY.data(), &deserSize, TEST_ARRAY.size(), + SerializeIF::Endianness::MACHINE); + REQUIRE(deserSize == 4); + uint32_t readBackUint32 = 0; + deserSize = 0; + SerializeAdapter::deSerialize(&readBackUint32, TEST_ARRAY.data(), &deserSize, + SerializeIF::Endianness::MACHINE); + REQUIRE(deserSize == 4); + REQUIRE(readBackUint32 == 929221); + + SerializeAdapter::serialize(&tvInt16, TEST_ARRAY.data(), &deserSize, TEST_ARRAY.size(), + SerializeIF::Endianness::MACHINE); + REQUIRE(deserSize == 2); + int16_t readBackInt16 = 0; + SerializeAdapter::deSerialize(&readBackInt16, TEST_ARRAY.data(), &deserSize, + SerializeIF::Endianness::MACHINE); + REQUIRE(readBackInt16 == -829); + REQUIRE(deserSize == 2); + + SerializeAdapter::serialize(&tvFloat, TEST_ARRAY.data(), &deserSize, TEST_ARRAY.size(), + SerializeIF::Endianness::MACHINE); + float readBackFloat = 0.0; + SerializeAdapter::deSerialize(&readBackFloat, TEST_ARRAY.data(), &deserSize, + SerializeIF::Endianness::MACHINE); + REQUIRE(readBackFloat == Catch::Approx(8.214921)); + + SerializeAdapter::serialize(&tvSdouble, TEST_ARRAY.data(), &deserSize, TEST_ARRAY.size(), + SerializeIF::Endianness::MACHINE); + double readBackSignedDouble = 0.0; + SerializeAdapter::deSerialize(&readBackSignedDouble, TEST_ARRAY.data(), &deserSize, + SerializeIF::Endianness::MACHINE); + REQUIRE(readBackSignedDouble == Catch::Approx(-2.2421e19)); + + uint8_t testBuf[4] = {1, 2, 3, 4}; + SerialBufferAdapter bufferAdapter(testBuf, sizeof(testBuf)); + SerializeAdapter::serialize(&bufferAdapter, TEST_ARRAY.data(), &deserSize, + TEST_ARRAY.size(), SerializeIF::Endianness::MACHINE); + REQUIRE(deserSize == 4); + for(uint8_t idx = 0; idx < 4; idx++) { + REQUIRE(TEST_ARRAY[idx] == idx + 1); + } + deserSize = 0; + testBuf[0] = 0; + testBuf[1] = 12; + SerializeAdapter::deSerialize(&bufferAdapter, TEST_ARRAY.data(), &deserSize, + SerializeIF::Endianness::MACHINE); + REQUIRE(deserSize == 4); + for(uint8_t idx = 0; idx < 4; idx++) { + REQUIRE(testBuf[idx] == idx + 1); + } + } + + SECTION("Serialize incrementing") { + SerializeAdapter::serialize(&testBool, &pArray, &serializedSize, + TEST_ARRAY.size(), SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tvUint8, &pArray, &serializedSize, + TEST_ARRAY.size(), SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tvUint16, &pArray, &serializedSize, + TEST_ARRAY.size(), SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tvUint32, &pArray, &serializedSize, + TEST_ARRAY.size(), SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tvInt8, &pArray, &serializedSize, + TEST_ARRAY.size(), SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tvInt16, &pArray, &serializedSize, + TEST_ARRAY.size(), SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tvInt32, &pArray, &serializedSize, + TEST_ARRAY.size(), SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tvUint64, &pArray, &serializedSize, + TEST_ARRAY.size(), SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tvFloat, &pArray, &serializedSize, + TEST_ARRAY.size(), SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tvDouble, &pArray, &serializedSize, TEST_ARRAY.size(), + SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tvSfloat, &pArray, &serializedSize, TEST_ARRAY.size(), + SerializeIF::Endianness::MACHINE); + SerializeAdapter::serialize(&tvSdouble, &pArray, &serializedSize, TEST_ARRAY.size(), + SerializeIF::Endianness::MACHINE); + REQUIRE (serializedSize == 47); + } + + SECTION("Deserialize decrementing") { + pArray = TEST_ARRAY.data(); + size_t remaining_size = serializedSize; + SerializeAdapter::deSerialize(&testBool, const_cast(&pArray), + &remaining_size, SerializeIF::Endianness::MACHINE); + SerializeAdapter::deSerialize(&tvUint8, const_cast(&pArray), + &remaining_size, SerializeIF::Endianness::MACHINE); + SerializeAdapter::deSerialize(&tvUint16, const_cast(&pArray), + &remaining_size, SerializeIF::Endianness::MACHINE); + SerializeAdapter::deSerialize(&tvUint32, const_cast(&pArray), + &remaining_size, SerializeIF::Endianness::MACHINE); + SerializeAdapter::deSerialize(&tvInt8, const_cast(&pArray), + &remaining_size, SerializeIF::Endianness::MACHINE); + SerializeAdapter::deSerialize(&tvInt16, const_cast(&pArray), + &remaining_size, SerializeIF::Endianness::MACHINE); + SerializeAdapter::deSerialize(&tvInt32, const_cast(&pArray), + &remaining_size, SerializeIF::Endianness::MACHINE); + SerializeAdapter::deSerialize(&tvUint64, + const_cast(&pArray), &remaining_size, SerializeIF::Endianness::MACHINE); + SerializeAdapter::deSerialize(&tvFloat, + const_cast(&pArray), &remaining_size, SerializeIF::Endianness::MACHINE); + SerializeAdapter::deSerialize(&tvDouble, + const_cast(&pArray), &remaining_size, SerializeIF::Endianness::MACHINE); + SerializeAdapter::deSerialize(&tvSfloat, + const_cast(&pArray), &remaining_size, SerializeIF::Endianness::MACHINE); + SerializeAdapter::deSerialize(&tvSdouble, + const_cast(&pArray), &remaining_size, SerializeIF::Endianness::MACHINE); + + REQUIRE(testBool == true); + REQUIRE(tvUint8 == 5); + REQUIRE(tvUint16 == 283); + REQUIRE(tvUint32 == 929221); + REQUIRE(tvUint64 == 2929329429); + REQUIRE(tvInt8 == -16); + REQUIRE(tvInt16 == -829); + REQUIRE(tvInt32 == -2312); + + REQUIRE(tvFloat == Catch::Approx(8.214921)); + REQUIRE(tvDouble == Catch::Approx(9.2132142141e8)); + REQUIRE(tvSfloat == Catch::Approx(-922.2321321)); + REQUIRE(tvSdouble == Catch::Approx(-2.2421e19)); + } +} + + diff --git a/tests/src/fsfw_tests/unit/storagemanager/CMakeLists.txt b/tests/src/fsfw_tests/unit/storagemanager/CMakeLists.txt new file mode 100644 index 00000000..7b6280df --- /dev/null +++ b/tests/src/fsfw_tests/unit/storagemanager/CMakeLists.txt @@ -0,0 +1,4 @@ +target_sources(${FSFW_TEST_TGT} PRIVATE + TestNewAccessor.cpp + TestPool.cpp +) diff --git a/unittest/tests/storagemanager/TestNewAccessor.cpp b/tests/src/fsfw_tests/unit/storagemanager/TestNewAccessor.cpp similarity index 99% rename from unittest/tests/storagemanager/TestNewAccessor.cpp rename to tests/src/fsfw_tests/unit/storagemanager/TestNewAccessor.cpp index 10d05c6b..bd1634b7 100644 --- a/unittest/tests/storagemanager/TestNewAccessor.cpp +++ b/tests/src/fsfw_tests/unit/storagemanager/TestNewAccessor.cpp @@ -1,6 +1,9 @@ +#include "fsfw_tests/unit/CatchDefinitions.h" + #include + #include -#include + #include #include diff --git a/unittest/tests/storagemanager/TestPool.cpp b/tests/src/fsfw_tests/unit/storagemanager/TestPool.cpp similarity index 99% rename from unittest/tests/storagemanager/TestPool.cpp rename to tests/src/fsfw_tests/unit/storagemanager/TestPool.cpp index d05a3dd6..013ecf86 100644 --- a/unittest/tests/storagemanager/TestPool.cpp +++ b/tests/src/fsfw_tests/unit/storagemanager/TestPool.cpp @@ -1,8 +1,9 @@ +#include "fsfw_tests/unit/CatchDefinitions.h" + #include #include #include -#include #include diff --git a/tests/src/fsfw_tests/unit/testcfg/CMakeLists.txt b/tests/src/fsfw_tests/unit/testcfg/CMakeLists.txt new file mode 100644 index 00000000..f840e38b --- /dev/null +++ b/tests/src/fsfw_tests/unit/testcfg/CMakeLists.txt @@ -0,0 +1,23 @@ +target_sources(${FSFW_TEST_TGT} PRIVATE + ipc/MissionMessageTypes.cpp + pollingsequence/PollingSequenceFactory.cpp +) + +# Add include paths for the executable +target_include_directories(${FSFW_TEST_TGT} PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} +) + +# If a special translation file for object IDs exists, compile it. +if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/objects/translateObjects.cpp") + target_sources(${FSFW_TEST_TGT} PRIVATE + objects/translateObjects.cpp + ) +endif() + +# If a special translation file for events exists, compile it. +if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/objects/translateObjects.cpp") + target_sources(${FSFW_TEST_TGT} PRIVATE + events/translateEvents.cpp + ) +endif() \ No newline at end of file diff --git a/unittest/user/testcfg/FSFWConfig.h b/tests/src/fsfw_tests/unit/testcfg/FSFWConfig.h.in similarity index 62% rename from unittest/user/testcfg/FSFWConfig.h rename to tests/src/fsfw_tests/unit/testcfg/FSFWConfig.h.in index ed86e6e1..f05ef40b 100644 --- a/unittest/user/testcfg/FSFWConfig.h +++ b/tests/src/fsfw_tests/unit/testcfg/FSFWConfig.h.in @@ -7,27 +7,30 @@ //! Used to determine whether C++ ostreams are used which can increase //! the binary size significantly. If this is disabled, //! the C stdio functions can be used alternatively -#define FSFW_CPP_OSTREAM_ENABLED 1 +#define FSFW_CPP_OSTREAM_ENABLED 0 //! More FSFW related printouts depending on level. Useful for development. -#define FSFW_VERBOSE_LEVEL 1 +#define FSFW_VERBOSE_LEVEL 0 //! Can be used to completely disable printouts, even the C stdio ones. #if FSFW_CPP_OSTREAM_ENABLED == 0 && FSFW_VERBOSE_LEVEL == 0 - #define FSFW_DISABLE_PRINTOUT 0 + #define FSFW_DISABLE_PRINTOUT 1 #endif +#define FSFW_USE_PUS_C_TELEMETRY 1 +#define FSFW_USE_PUS_C_TELECOMMANDS 1 + //! Can be used to disable the ANSI color sequences for C stdio. -#define FSFW_COLORED_OUTPUT 1 +#define FSFW_COLORED_OUTPUT 1 //! If FSFW_OBJ_EVENT_TRANSLATION is set to one, //! additional output which requires the translation files translateObjects //! and translateEvents (and their compiled source files) -#define FSFW_OBJ_EVENT_TRANSLATION 0 +#define FSFW_OBJ_EVENT_TRANSLATION 0 #if FSFW_OBJ_EVENT_TRANSLATION == 1 //! Specify whether info events are printed too. -#define FSFW_DEBUG_INFO 1 +#define FSFW_DEBUG_INFO 1 #include "objects/translateObjects.h" #include "events/translateEvents.h" #else @@ -35,15 +38,22 @@ //! When using the newlib nano library, C99 support for stdio facilities //! will not be provided. This define should be set to 1 if this is the case. -#define FSFW_NO_C99_IO 1 +#define FSFW_NO_C99_IO 1 //! Specify whether a special mode store is used for Subsystem components. -#define FSFW_USE_MODESTORE 0 +#define FSFW_USE_MODESTORE 0 + +//! Defines if the real time scheduler for linux should be used. +//! If set to 0, this will also disable priority settings for linux +//! as most systems will not allow to set nice values without privileges +//! For embedded linux system set this to 1. +//! If set to 1 the binary needs "cap_sys_nice=eip" privileges to run +#define FSFW_USE_REALTIME_FOR_LINUX 1 namespace fsfwconfig { -//! Default timestamp size. The default timestamp will be an eight byte CDC -//! short timestamp. -static constexpr uint8_t FSFW_MISSION_TIMESTAMP_SIZE = 8; + +//! Default timestamp size. The default timestamp will be an seven byte CDC short timestamp. +static constexpr uint8_t FSFW_MISSION_TIMESTAMP_SIZE = 7; //! Configure the allocated pool sizes for the event manager. static constexpr size_t FSFW_EVENTMGMR_MATCHTREE_NODES = 240; @@ -52,11 +62,14 @@ static constexpr size_t FSFW_EVENTMGMR_RANGEMATCHERS = 120; //! Defines the FIFO depth of each commanding service base which //! also determines how many commands a CSB service can handle in one cycle -//! simulataneously. This will increase the required RAM for +//! simultaneously. This will increase the required RAM for //! each CSB service ! static constexpr uint8_t FSFW_CSB_FIFO_DEPTH = 6; static constexpr size_t FSFW_PRINT_BUFFER_SIZE = 124; + +static constexpr size_t FSFW_MAX_TM_PACKET_SIZE = 2048; + } #endif /* CONFIG_FSFWCONFIG_H_ */ diff --git a/tests/src/fsfw_tests/unit/testcfg/OBSWConfig.h.in b/tests/src/fsfw_tests/unit/testcfg/OBSWConfig.h.in new file mode 100644 index 00000000..5d8a9255 --- /dev/null +++ b/tests/src/fsfw_tests/unit/testcfg/OBSWConfig.h.in @@ -0,0 +1,15 @@ +#ifndef CONFIG_TMTC_TMTCSIZE_H_ +#define CONFIG_TMTC_TMTCSIZE_H_ + +#include +#include + +#define OBSW_PRINT_MISSED_DEADLINES 0 +#define OBSW_VERBOSE_LEVEL 0 +#define OBSW_ADD_TEST_CODE 1 + +namespace config { +static constexpr uint32_t MAX_STORED_TELECOMMANDS = 2000; +} + +#endif /* CONFIG_TMTC_TMTCSIZE_H_ */ diff --git a/tests/src/fsfw_tests/unit/testcfg/TestsConfig.h.in b/tests/src/fsfw_tests/unit/testcfg/TestsConfig.h.in new file mode 100644 index 00000000..7d950070 --- /dev/null +++ b/tests/src/fsfw_tests/unit/testcfg/TestsConfig.h.in @@ -0,0 +1,21 @@ +#ifndef FSFW_UNITTEST_CONFIG_TESTSCONFIG_H_ +#define FSFW_UNITTEST_CONFIG_TESTSCONFIG_H_ + +#define FSFW_ADD_DEFAULT_FACTORY_FUNCTIONS 1 + +#ifdef __cplusplus + +#include "objects/systemObjectList.h" +#include "events/subsystemIdRanges.h" +#include "returnvalues/classIds.h" + +namespace config { +#endif + +/* Add mission configuration flags here */ + +#ifdef __cplusplus +} +#endif + +#endif /* FSFW_UNITTEST_CONFIG_TESTSCONFIG_H_ */ diff --git a/unittest/user/testcfg/devices/logicalAddresses.cpp b/tests/src/fsfw_tests/unit/testcfg/devices/logicalAddresses.cpp similarity index 100% rename from unittest/user/testcfg/devices/logicalAddresses.cpp rename to tests/src/fsfw_tests/unit/testcfg/devices/logicalAddresses.cpp diff --git a/unittest/user/testcfg/devices/logicalAddresses.h b/tests/src/fsfw_tests/unit/testcfg/devices/logicalAddresses.h similarity index 84% rename from unittest/user/testcfg/devices/logicalAddresses.h rename to tests/src/fsfw_tests/unit/testcfg/devices/logicalAddresses.h index cdf87025..d7b73e15 100644 --- a/unittest/user/testcfg/devices/logicalAddresses.h +++ b/tests/src/fsfw_tests/unit/testcfg/devices/logicalAddresses.h @@ -2,7 +2,7 @@ #define CONFIG_DEVICES_LOGICALADDRESSES_H_ #include -#include + #include namespace addresses { diff --git a/unittest/user/testcfg/devices/powerSwitcherList.cpp b/tests/src/fsfw_tests/unit/testcfg/devices/powerSwitcherList.cpp similarity index 100% rename from unittest/user/testcfg/devices/powerSwitcherList.cpp rename to tests/src/fsfw_tests/unit/testcfg/devices/powerSwitcherList.cpp diff --git a/unittest/user/testcfg/devices/powerSwitcherList.h b/tests/src/fsfw_tests/unit/testcfg/devices/powerSwitcherList.h similarity index 100% rename from unittest/user/testcfg/devices/powerSwitcherList.h rename to tests/src/fsfw_tests/unit/testcfg/devices/powerSwitcherList.h diff --git a/unittest/user/testcfg/events/subsystemIdRanges.h b/tests/src/fsfw_tests/unit/testcfg/events/subsystemIdRanges.h similarity index 81% rename from unittest/user/testcfg/events/subsystemIdRanges.h rename to tests/src/fsfw_tests/unit/testcfg/events/subsystemIdRanges.h index 24eee819..b14c4bc5 100644 --- a/unittest/user/testcfg/events/subsystemIdRanges.h +++ b/tests/src/fsfw_tests/unit/testcfg/events/subsystemIdRanges.h @@ -1,8 +1,9 @@ #ifndef CONFIG_EVENTS_SUBSYSTEMIDRANGES_H_ #define CONFIG_EVENTS_SUBSYSTEMIDRANGES_H_ +#include "fsfw/events/fwSubsystemIdRanges.h" #include -#include + /** * @brief Custom subsystem IDs can be added here @@ -12,6 +13,7 @@ namespace SUBSYSTEM_ID { enum: uint8_t { SUBSYSTEM_ID_START = FW_SUBSYSTEM_ID_RANGE, + SUBSYSTEM_ID_END // [EXPORT] : [END] }; } diff --git a/unittest/user/testcfg/ipc/MissionMessageTypes.cpp b/tests/src/fsfw_tests/unit/testcfg/ipc/MissionMessageTypes.cpp similarity index 100% rename from unittest/user/testcfg/ipc/MissionMessageTypes.cpp rename to tests/src/fsfw_tests/unit/testcfg/ipc/MissionMessageTypes.cpp diff --git a/unittest/user/testcfg/ipc/MissionMessageTypes.h b/tests/src/fsfw_tests/unit/testcfg/ipc/MissionMessageTypes.h similarity index 100% rename from unittest/user/testcfg/ipc/MissionMessageTypes.h rename to tests/src/fsfw_tests/unit/testcfg/ipc/MissionMessageTypes.h diff --git a/unittest/user/testcfg/objects/systemObjectList.h b/tests/src/fsfw_tests/unit/testcfg/objects/systemObjectList.h similarity index 79% rename from unittest/user/testcfg/objects/systemObjectList.h rename to tests/src/fsfw_tests/unit/testcfg/objects/systemObjectList.h index 88b92131..accf0d81 100644 --- a/unittest/user/testcfg/objects/systemObjectList.h +++ b/tests/src/fsfw_tests/unit/testcfg/objects/systemObjectList.h @@ -1,8 +1,8 @@ #ifndef HOSTED_CONFIG_OBJECTS_SYSTEMOBJECTLIST_H_ #define HOSTED_CONFIG_OBJECTS_SYSTEMOBJECTLIST_H_ +#include "fsfw/objectmanager/frameworkObjects.h" #include -#include // The objects will be instantiated in the ID order namespace objects { @@ -11,10 +11,6 @@ namespace objects { FSFW_CONFIG_RESERVED_START = PUS_SERVICE_1_VERIFICATION, FSFW_CONFIG_RESERVED_END = TM_STORE, - CCSDS_DISTRIBUTOR = 10, - PUS_DISTRIBUTOR = 11, - TM_FUNNEL = 12, - UDP_BRIDGE = 15, UDP_POLLING_TASK = 16, @@ -22,7 +18,10 @@ namespace objects { TEST_DEVICE = 21, HK_RECEIVER_MOCK = 22, - TEST_LOCAL_POOL_OWNER_BASE = 25 + TEST_LOCAL_POOL_OWNER_BASE = 25, + + SHARED_SET_ID = 26 + }; } diff --git a/tests/src/fsfw_tests/unit/testcfg/pollingsequence/PollingSequenceFactory.cpp b/tests/src/fsfw_tests/unit/testcfg/pollingsequence/PollingSequenceFactory.cpp new file mode 100644 index 00000000..1d29ef86 --- /dev/null +++ b/tests/src/fsfw_tests/unit/testcfg/pollingsequence/PollingSequenceFactory.cpp @@ -0,0 +1,39 @@ +#include "PollingSequenceFactory.h" + +#include "tests/TestsConfig.h" + +#include +#include +#include + +ReturnValue_t pst::pollingSequenceInitDefault( + FixedTimeslotTaskIF *thisSequence) { + /* Length of a communication cycle */ + uint32_t length = thisSequence->getPeriodMs(); + + /* Add polling sequence table here */ + thisSequence->addSlot(objects::TEST_DEVICE, 0, + DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::TEST_DEVICE, 0.3, + DeviceHandlerIF::SEND_WRITE); + thisSequence->addSlot(objects::TEST_DEVICE, 0.45 * length, + DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::TEST_DEVICE, 0.6 * length, + DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::TEST_DEVICE, 0.8 * length, + DeviceHandlerIF::GET_READ); + + if (thisSequence->checkSequence() == HasReturnvaluesIF::RETURN_OK) { + return HasReturnvaluesIF::RETURN_OK; + } + else { +#if FSFW_CPP_OSTREAM_ENABLED + sif::error << "pst::pollingSequenceInitDefault: Sequence invalid!" + << std::endl; +#else + sif::printError("pst::pollingSequenceInitDefault: Sequence invalid!"); +#endif + return HasReturnvaluesIF::RETURN_FAILED; + } +} + diff --git a/unittest/user/testcfg/pollingsequence/PollingSequenceFactory.h b/tests/src/fsfw_tests/unit/testcfg/pollingsequence/PollingSequenceFactory.h similarity index 100% rename from unittest/user/testcfg/pollingsequence/PollingSequenceFactory.h rename to tests/src/fsfw_tests/unit/testcfg/pollingsequence/PollingSequenceFactory.h diff --git a/unittest/user/testcfg/returnvalues/classIds.h b/tests/src/fsfw_tests/unit/testcfg/returnvalues/classIds.h similarity index 87% rename from unittest/user/testcfg/returnvalues/classIds.h rename to tests/src/fsfw_tests/unit/testcfg/returnvalues/classIds.h index 606cc60b..1001d012 100644 --- a/unittest/user/testcfg/returnvalues/classIds.h +++ b/tests/src/fsfw_tests/unit/testcfg/returnvalues/classIds.h @@ -1,7 +1,7 @@ #ifndef CONFIG_RETURNVALUES_CLASSIDS_H_ #define CONFIG_RETURNVALUES_CLASSIDS_H_ -#include +#include "fsfw/returnvalues/FwClassIds.h" /** * @brief CLASS_ID defintions which are required for custom returnvalues. diff --git a/unittest/user/testcfg/tmtc/apid.h b/tests/src/fsfw_tests/unit/testcfg/tmtc/apid.h similarity index 100% rename from unittest/user/testcfg/tmtc/apid.h rename to tests/src/fsfw_tests/unit/testcfg/tmtc/apid.h diff --git a/unittest/user/testcfg/tmtc/pusIds.h b/tests/src/fsfw_tests/unit/testcfg/tmtc/pusIds.h similarity index 100% rename from unittest/user/testcfg/tmtc/pusIds.h rename to tests/src/fsfw_tests/unit/testcfg/tmtc/pusIds.h diff --git a/unittest/user/testtemplate/TestTemplate.cpp b/tests/src/fsfw_tests/unit/testtemplate/TestTemplate.cpp similarity index 90% rename from unittest/user/testtemplate/TestTemplate.cpp rename to tests/src/fsfw_tests/unit/testtemplate/TestTemplate.cpp index 6b5fc3d2..a779d80c 100644 --- a/unittest/user/testtemplate/TestTemplate.cpp +++ b/tests/src/fsfw_tests/unit/testtemplate/TestTemplate.cpp @@ -1,6 +1,5 @@ -#include -#include - +#include "fsfw_tests/unit/CatchDefinitions.h" +#include /** * @brief Template test file diff --git a/tests/src/fsfw_tests/unit/timemanager/CMakeLists.txt b/tests/src/fsfw_tests/unit/timemanager/CMakeLists.txt new file mode 100644 index 00000000..6ce1c6c6 --- /dev/null +++ b/tests/src/fsfw_tests/unit/timemanager/CMakeLists.txt @@ -0,0 +1,3 @@ +target_sources(${FSFW_TEST_TGT} PRIVATE + TestCountdown.cpp +) diff --git a/tests/src/fsfw_tests/unit/timemanager/TestCountdown.cpp b/tests/src/fsfw_tests/unit/timemanager/TestCountdown.cpp new file mode 100644 index 00000000..b1b26679 --- /dev/null +++ b/tests/src/fsfw_tests/unit/timemanager/TestCountdown.cpp @@ -0,0 +1,27 @@ +#include "fsfw_tests/unit/CatchDefinitions.h" +#include +#include + + +TEST_CASE( "Countdown Tests", "[TestCountdown]") { + INFO("Countdown Tests"); + Countdown count(20); + REQUIRE(count.timeout == 20); + REQUIRE(count.setTimeout(100) == static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(count.timeout == 100); + REQUIRE(count.setTimeout(150) == static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(count.isBusy()); + REQUIRE(not count.hasTimedOut()); + uint32_t number = count.getRemainingMillis(); + REQUIRE(number > 0); + bool blocked = false; + while(not count.hasTimedOut()){ + blocked = true; + }; + REQUIRE(blocked); + number = count.getRemainingMillis(); + REQUIRE(number==0); + count.resetTimer(); + REQUIRE(not count.hasTimedOut()); + REQUIRE(count.isBusy()); +} diff --git a/tests/src/fsfw_tests/unit/tmtcpacket/CMakeLists.txt b/tests/src/fsfw_tests/unit/tmtcpacket/CMakeLists.txt new file mode 100644 index 00000000..958bda40 --- /dev/null +++ b/tests/src/fsfw_tests/unit/tmtcpacket/CMakeLists.txt @@ -0,0 +1,3 @@ +target_sources(${FSFW_TEST_TGT} PRIVATE + testCcsds.cpp +) diff --git a/tests/src/fsfw_tests/unit/tmtcpacket/PusTmTest.cpp b/tests/src/fsfw_tests/unit/tmtcpacket/PusTmTest.cpp new file mode 100644 index 00000000..b28b04f6 --- /dev/null +++ b/tests/src/fsfw_tests/unit/tmtcpacket/PusTmTest.cpp @@ -0,0 +1,3 @@ + + + diff --git a/tests/src/fsfw_tests/unit/tmtcpacket/testCcsds.cpp b/tests/src/fsfw_tests/unit/tmtcpacket/testCcsds.cpp new file mode 100644 index 00000000..8f531805 --- /dev/null +++ b/tests/src/fsfw_tests/unit/tmtcpacket/testCcsds.cpp @@ -0,0 +1,11 @@ +#include + +#include "fsfw/tmtcpacket/SpacePacket.h" + +TEST_CASE( "CCSDS Test" , "[ccsds]") { + REQUIRE(spacepacket::getTcSpacePacketIdFromApid(0x22) == 0x1822); + REQUIRE(spacepacket::getTmSpacePacketIdFromApid(0x22) == 0x0822); + + REQUIRE(spacepacket::getTcSpacePacketIdFromApid(0x7ff) == 0x1fff); + REQUIRE(spacepacket::getTmSpacePacketIdFromApid(0x7ff) == 0xfff); +} diff --git a/timemanager/CMakeLists.txt b/timemanager/CMakeLists.txt deleted file mode 100644 index 3367775f..00000000 --- a/timemanager/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -target_sources(${LIB_FSFW_NAME} - PRIVATE - CCSDSTime.cpp - Countdown.cpp - Stopwatch.cpp - TimeMessage.cpp - TimeStamper.cpp -) diff --git a/timemanager/Countdown.cpp b/timemanager/Countdown.cpp deleted file mode 100644 index 20b56189..00000000 --- a/timemanager/Countdown.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include "Countdown.h" - -Countdown::Countdown(uint32_t initialTimeout): timeout(initialTimeout) { -} - -Countdown::~Countdown() { -} - -ReturnValue_t Countdown::setTimeout(uint32_t miliseconds) { - ReturnValue_t return_value = Clock::getUptime( &startTime ); - timeout = miliseconds; - return return_value; -} - -bool Countdown::hasTimedOut() const { - uint32_t current_time; - Clock::getUptime( ¤t_time ); - if ( uint32_t(current_time - startTime) >= timeout) { - return true; - } else { - return false; - } -} - -bool Countdown::isBusy() const { - return !hasTimedOut(); -} - -ReturnValue_t Countdown::resetTimer() { - return setTimeout(timeout); -} - -void Countdown::timeOut() { - uint32_t current_time; - Clock::getUptime( ¤t_time ); - startTime= current_time - timeout; -} diff --git a/timemanager/Countdown.h b/timemanager/Countdown.h deleted file mode 100644 index f6a41e73..00000000 --- a/timemanager/Countdown.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef FSFW_TIMEMANAGER_COUNTDOWN_H_ -#define FSFW_TIMEMANAGER_COUNTDOWN_H_ - -#include "Clock.h" - -/** - * @brief This file defines the Countdown class. - * @author baetz - */ -class Countdown { -public: - uint32_t timeout; - Countdown(uint32_t initialTimeout = 0); - ~Countdown(); - ReturnValue_t setTimeout(uint32_t miliseconds); - - bool hasTimedOut() const; - - bool isBusy() const; - - //!< Use last set timeout value and restart timer. - ReturnValue_t resetTimer(); - - //!< Make hasTimedOut() return true - void timeOut(); - -private: - uint32_t startTime = 0; -}; - -#endif /* FSFW_TIMEMANAGER_COUNTDOWN_H_ */ diff --git a/tmtcpacket/CMakeLists.txt b/tmtcpacket/CMakeLists.txt deleted file mode 100644 index fe3d2a4d..00000000 --- a/tmtcpacket/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -target_sources(${LIB_FSFW_NAME} - PRIVATE - SpacePacket.cpp - SpacePacketBase.cpp -) - -add_subdirectory(packetmatcher) -add_subdirectory(pus) \ No newline at end of file diff --git a/tmtcpacket/SpacePacket.h b/tmtcpacket/SpacePacket.h deleted file mode 100644 index 49dd5ae5..00000000 --- a/tmtcpacket/SpacePacket.h +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef SPACEPACKET_H_ -#define SPACEPACKET_H_ - -#include "SpacePacketBase.h" - -/** - * The SpacePacket class is a representation of a simple CCSDS Space Packet - * without (control over) a secondary header. - * It can be instantiated with a size smaller than \c PACKET_MAX_SIZE. Its - * main use is to serve as an idle packet in case no other packets are sent. - * For the ECSS PUS part the TcPacket and TmPacket classes are used. - * A pointer to \c local_data is passed to the \c SpacePacketBase parent class, - * so the parent's methods are reachable. - * @ingroup tmtcpackets - */ -class SpacePacket: public SpacePacketBase { -public: - static const uint16_t PACKET_MAX_SIZE = 1024; - /** - * The constructor initializes the packet and sets all header information - * according to the passed parameters. - * @param packetDataLength Sets the packet data length field and therefore specifies the size of the packet. - * @param isTelecommand Sets the packet type field to either TC (true) or TM (false). - * @param apid Sets the packet's APID field. The default value describes an idle packet. - * @param sequenceCount ets the packet's Source Sequence Count field. - */ - SpacePacket(uint16_t packetDataLength, bool isTelecommand = false, - uint16_t apid = APID_IDLE_PACKET, uint16_t sequenceCount = 0); - /** - * The class's default destructor. - */ - virtual ~SpacePacket(); - /** - * With this call, the complete data content (including the CCSDS Primary - * Header) is overwritten with the byte stream given. - * @param p_data Pointer to data to overwrite the content with - * @param packet_size Size of the data - * @return @li \c true if packet_size is smaller than \c MAX_PACKET_SIZE. - * @li \c false else. - */ - bool addWholeData(const uint8_t* p_data, uint32_t packet_size); -protected: - /** - * This structure defines the data structure of a Space Packet as local data. - * There's a buffer which corresponds to the Space Packet Data Field with a - * maximum size of \c PACKET_MAX_SIZE. - */ - struct PacketStructured { - CCSDSPrimaryHeader header; - uint8_t buffer[PACKET_MAX_SIZE]; - }; - /** - * This union simplifies accessing the full data content of the Space Packet. - * This is achieved by putting the \c PacketStructured struct in a union with - * a plain buffer. - */ - union SpacePacketData { - PacketStructured fields; - uint8_t byteStream[PACKET_MAX_SIZE + sizeof(CCSDSPrimaryHeader)]; - }; - /** - * This is the data representation of the class. - * It is a struct of CCSDS Primary Header and a data field, which again is - * packed in an union, so the data can be accessed as a byte stream without - * a cast. - */ - SpacePacketData localData; -}; - -#endif /* SPACEPACKET_H_ */ diff --git a/tmtcpacket/SpacePacketBase.cpp b/tmtcpacket/SpacePacketBase.cpp deleted file mode 100644 index e13af8d0..00000000 --- a/tmtcpacket/SpacePacketBase.cpp +++ /dev/null @@ -1,104 +0,0 @@ -#include "SpacePacketBase.h" -#include "../serviceinterface/ServiceInterfaceStream.h" -#include - -SpacePacketBase::SpacePacketBase( const uint8_t* set_address ) { - this->data = (SpacePacketPointer*) set_address; -} - -SpacePacketBase::~SpacePacketBase() { -}; - -//CCSDS Methods: -uint8_t SpacePacketBase::getPacketVersionNumber( void ) { - return (this->data->header.packet_id_h & 0b11100000) >> 5; -} - -void SpacePacketBase::initSpacePacketHeader(bool isTelecommand, - bool hasSecondaryHeader, uint16_t apid, uint16_t sequenceCount) { - //reset header to zero: - memset(data,0, sizeof(this->data->header) ); - //Set TC/TM bit. - data->header.packet_id_h = ((isTelecommand? 1 : 0)) << 4; - //Set secondaryHeader bit - data->header.packet_id_h |= ((hasSecondaryHeader? 1 : 0)) << 3; - this->setAPID( apid ); - //Always initialize as standalone packets. - data->header.sequence_control_h = 0b11000000; - setPacketSequenceCount(sequenceCount); - -} - -bool SpacePacketBase::isTelecommand( void ) { - return (this->data->header.packet_id_h & 0b00010000) >> 4; -} - -bool SpacePacketBase::hasSecondaryHeader( void ) { - return (this->data->header.packet_id_h & 0b00001000) >> 3; -} - -uint16_t SpacePacketBase::getPacketId() { - return ( (this->data->header.packet_id_h) << 8 ) + - this->data->header.packet_id_l; -} - -uint16_t SpacePacketBase::getAPID( void ) const { - return ( (this->data->header.packet_id_h & 0b00000111) << 8 ) + - this->data->header.packet_id_l; -} - -void SpacePacketBase::setAPID( uint16_t new_apid ) { - //Use first three bits of new APID, but keep rest of packet id as it was (see specification). - this->data->header.packet_id_h = (this->data->header.packet_id_h & 0b11111000) | ( ( new_apid & 0x0700 ) >> 8 ); - this->data->header.packet_id_l = ( new_apid & 0x00FF ); -} - -uint16_t SpacePacketBase::getPacketSequenceControl( void ) { - return ( (this->data->header.sequence_control_h) << 8 ) - + this->data->header.sequence_control_l; -} - -uint8_t SpacePacketBase::getSequenceFlags( void ) { - return (this->data->header.sequence_control_h & 0b11000000) >> 6 ; -} - -uint16_t SpacePacketBase::getPacketSequenceCount( void ) const { - return ( (this->data->header.sequence_control_h & 0b00111111) << 8 ) - + this->data->header.sequence_control_l; -} - -void SpacePacketBase::setPacketSequenceCount( uint16_t new_count) { - this->data->header.sequence_control_h = ( this->data->header.sequence_control_h & 0b11000000 ) | ( ( (new_count%LIMIT_SEQUENCE_COUNT) & 0x3F00 ) >> 8 ); - this->data->header.sequence_control_l = ( (new_count%LIMIT_SEQUENCE_COUNT) & 0x00FF ); -} - -uint16_t SpacePacketBase::getPacketDataLength( void ) { - return ( (this->data->header.packet_length_h) << 8 ) - + this->data->header.packet_length_l; -} - -void SpacePacketBase::setPacketDataLength( uint16_t new_length) { - this->data->header.packet_length_h = ( ( new_length & 0xFF00 ) >> 8 ); - this->data->header.packet_length_l = ( new_length & 0x00FF ); -} - -size_t SpacePacketBase::getFullSize() { - //+1 is done because size in packet data length field is: size of data field -1 - return this->getPacketDataLength() + sizeof(this->data->header) + 1; -} - -uint8_t* SpacePacketBase::getWholeData() { - return (uint8_t*)this->data; -} - -void SpacePacketBase::setData( const uint8_t* p_Data ) { - this->data = (SpacePacketPointer*)p_Data; -} - -uint32_t SpacePacketBase::getApidAndSequenceCount() const { - return (getAPID() << 16) + getPacketSequenceCount(); -} - -uint8_t* SpacePacketBase::getPacketData() { - return &(data->packet_data); -} diff --git a/tmtcpacket/SpacePacketBase.h b/tmtcpacket/SpacePacketBase.h deleted file mode 100644 index 19cbd074..00000000 --- a/tmtcpacket/SpacePacketBase.h +++ /dev/null @@ -1,178 +0,0 @@ -#ifndef FSFW_TMTCPACKET_SPACEPACKETBASE_H_ -#define FSFW_TMTCPACKET_SPACEPACKETBASE_H_ - -#include "ccsds_header.h" -#include - -/** - * @defgroup tmtcpackets Space Packets - * This is the group, where all classes associated with Telecommand and - * Telemetry packets belong to. - * The class hierarchy resembles the dependency between the different standards - * applied, namely the CCSDS Space Packet standard and the ECCSS Packet - * Utilization Standard. Most field and structure names are taken from these - * standards. - */ - -/** - * This struct defines the data structure of a Space Packet when accessed - * via a pointer. - * @ingroup tmtcpackets - */ -struct SpacePacketPointer { - CCSDSPrimaryHeader header; - uint8_t packet_data; -}; - -/** - * This class is the basic data handler for any CCSDS Space Packet - * compatible Telecommand and Telemetry packet. - * It does not contain the packet data itself but a pointer to the - * data must be set on instantiation. An invalid pointer may cause - * damage, as no getter method checks data validity. Anyway, a NULL - * check can be performed by making use of the getWholeData method. - * Remark: All bit numbers in this documentation are counted from - * the most significant bit (from left). - * @ingroup tmtcpackets - */ -class SpacePacketBase { -protected: - /** - * A pointer to a structure which defines the data structure of - * the packet header. - * To be hardware-safe, all elements are of byte size. - */ - SpacePacketPointer* data; -public: - static const uint16_t LIMIT_APID = 2048; //2^1 - static const uint16_t LIMIT_SEQUENCE_COUNT = 16384; // 2^14 - static const uint16_t APID_IDLE_PACKET = 0x7FF; - static const uint8_t TELECOMMAND_PACKET = 1; - static const uint8_t TELEMETRY_PACKET = 0; - /** - * This definition defines the CRC size in byte. - */ - static const uint8_t CRC_SIZE = 2; - /** - * This is the minimum size of a SpacePacket. - */ - static const uint16_t MINIMUM_SIZE = sizeof(CCSDSPrimaryHeader) + CRC_SIZE; - /** - * This is the default constructor. - * It sets its internal data pointer to the address passed. - * @param set_address The position where the packet data lies. - */ - SpacePacketBase( const uint8_t* set_address ); - /** - * No data is allocated, so the destructor is empty. - */ - virtual ~SpacePacketBase(); - - //CCSDS Methods: - /** - * Getter for the packet version number field. - * @return Returns the highest three bit of the packet in one byte. - */ - uint8_t getPacketVersionNumber( void ); - /** - * This method checks the type field in the header. - * This bit specifies, if the command is interpreted as Telecommand of - * as Telemetry. For a Telecommand, the bit is set. - * @return Returns true if the bit is set and false if not. - */ - bool isTelecommand( void ); - - void initSpacePacketHeader(bool isTelecommand, bool hasSecondaryHeader, - uint16_t apid, uint16_t sequenceCount = 0); - /** - * The CCSDS header provides a secondary header flag (the fifth-highest bit), - * which is checked with this method. - * @return Returns true if the bit is set and false if not. - */ - bool hasSecondaryHeader( void ); - /** - * Returns the complete first two bytes of the packet, which together form - * the CCSDS packet id. - * @return The CCSDS packet id. - */ - uint16_t getPacketId( void ); - /** - * Returns the APID of a packet, which are the lowest 11 bit of the packet - * id. - * @return The CCSDS APID. - */ - uint16_t getAPID( void ) const; - /** - * Sets the APID of a packet, which are the lowest 11 bit of the packet - * id. - * @param The APID to set. The highest five bits of the parameter are - * ignored. - */ - void setAPID( uint16_t setAPID ); - /** - * Returns the CCSDS packet sequence control field, which are the third and - * the fourth byte of the CCSDS primary header. - * @return The CCSDS packet sequence control field. - */ - uint16_t getPacketSequenceControl( void ); - /** - * Returns the SequenceFlags, which are the highest two bit of the packet - * sequence control field. - * @return The CCSDS sequence flags. - */ - uint8_t getSequenceFlags( void ); - /** - * Returns the packet sequence count, which are the lowest 14 bit of the - * packet sequence control field. - * @return The CCSDS sequence count. - */ - uint16_t getPacketSequenceCount( void ) const; - /** - * Sets the packet sequence count, which are the lowest 14 bit of the - * packet sequence control field. - * setCount is modulo-divided by \c LIMIT_SEQUENCE_COUNT to avoid overflows. - * @param setCount The value to set the count to. - */ - void setPacketSequenceCount( uint16_t setCount ); - /** - * Returns the packet data length, which is the fifth and sixth byte of the - * CCSDS Primary Header. The packet data length is the size of every kind - * of data \b after the CCSDS Primary Header \b -1. - * @return The CCSDS packet data length. - */ - uint16_t getPacketDataLength( void ); //uint16_t is sufficient, because this is limit in CCSDS standard - /** - * Sets the packet data length, which is the fifth and sixth byte of the - * CCSDS Primary Header. - * @param setLength The value of the length to set. It must fit the true - * CCSDS packet data length . The packet data length is - * the size of every kind of data \b after the CCSDS - * Primary Header \b -1. - */ - void setPacketDataLength( uint16_t setLength ); - - //Helper methods: - /** - * This method returns a raw uint8_t pointer to the packet. - * @return A \c uint8_t pointer to the first byte of the CCSDS primary header. - */ - virtual uint8_t* getWholeData( void ); - - uint8_t* getPacketData(); - /** - * With this method, the packet data pointer can be redirected to another - * location. - * @param p_Data A pointer to another raw Space Packet. - */ - virtual void setData( const uint8_t* p_Data ); - /** - * This method returns the full raw packet size. - * @return The full size of the packet in bytes. - */ - size_t getFullSize(); - - uint32_t getApidAndSequenceCount() const; - -}; - -#endif /* FSFW_TMTCPACKET_SPACEPACKETBASE_H_ */ diff --git a/tmtcpacket/packetmatcher/ApidMatcher.h b/tmtcpacket/packetmatcher/ApidMatcher.h deleted file mode 100644 index 4f196ac9..00000000 --- a/tmtcpacket/packetmatcher/ApidMatcher.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef FRAMEWORK_TMTCPACKET_PACKETMATCHER_APIDMATCHER_H_ -#define FRAMEWORK_TMTCPACKET_PACKETMATCHER_APIDMATCHER_H_ - -#include "../../globalfunctions/matching/SerializeableMatcherIF.h" -#include "../../serialize/SerializeAdapter.h" -#include "../../tmtcpacket/pus/TmPacketMinimal.h" - -class ApidMatcher: public SerializeableMatcherIF { -private: - uint16_t apid; -public: - ApidMatcher(uint16_t setApid) : - apid(setApid) { - } - ApidMatcher(TmPacketMinimal* test) : - apid(test->getAPID()) { - } - bool match(TmPacketMinimal* packet) { - if (packet->getAPID() == apid) { - return true; - } else { - return false; - } - } - ReturnValue_t serialize(uint8_t** buffer, size_t* size, - size_t maxSize, Endianness streamEndianness) const { - return SerializeAdapter::serialize(&apid, buffer, size, maxSize, streamEndianness); - } - size_t getSerializedSize() const { - return SerializeAdapter::getSerializedSize(&apid); - } - ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - Endianness streamEndianness) { - return SerializeAdapter::deSerialize(&apid, buffer, size, streamEndianness); - } -}; - - - -#endif /* FRAMEWORK_TMTCPACKET_PACKETMATCHER_APIDMATCHER_H_ */ diff --git a/tmtcpacket/packetmatcher/PacketMatchTree.cpp b/tmtcpacket/packetmatcher/PacketMatchTree.cpp deleted file mode 100644 index ac72b3e7..00000000 --- a/tmtcpacket/packetmatcher/PacketMatchTree.cpp +++ /dev/null @@ -1,201 +0,0 @@ -#include "ApidMatcher.h" -#include "PacketMatchTree.h" -#include "ServiceMatcher.h" -#include "SubserviceMatcher.h" - -// This should be configurable.. -const LocalPool::LocalPoolConfig PacketMatchTree::poolConfig = { - {10, sizeof(ServiceMatcher)}, - {20, sizeof(SubServiceMatcher)}, - {2, sizeof(ApidMatcher)}, - {40, sizeof(PacketMatchTree::Node)} -}; - -PacketMatchTree::PacketMatchTree(Node* root) : - MatchTree(root, 2), - factoryBackend(0, poolConfig, false, true), - factory(&factoryBackend) { -} - -PacketMatchTree::PacketMatchTree(iterator root) : - MatchTree(root.element, 2), - factoryBackend(0, poolConfig, false, true), - factory(&factoryBackend) { -} - -PacketMatchTree::PacketMatchTree() : - MatchTree((Node*) NULL, 2), - factoryBackend(0, poolConfig, false, true), - factory(&factoryBackend) { -} - -PacketMatchTree::~PacketMatchTree() { -} - -ReturnValue_t PacketMatchTree::addMatch(uint16_t apid, uint8_t type, - uint8_t subtype) { - //We assume adding APID is always requested. - TmPacketMinimal::TmPacketMinimalPointer data; - data.data_field.service_type = type; - data.data_field.service_subtype = subtype; - TmPacketMinimal testPacket((uint8_t*) &data); - testPacket.setAPID(apid); - iterator lastTest; - iterator rollback; - ReturnValue_t result = findOrInsertMatch( - this->begin(), &testPacket, &lastTest); - if (result == NEW_NODE_CREATED) { - rollback = lastTest; - } else if (result != RETURN_OK) { - return result; - } - if (type == 0) { - //Check if lastTest has no children, otherwise, delete them, - //as a more general check is requested. - if (lastTest.left() != this->end()) { - removeElementAndAllChildren(lastTest.left()); - } - return RETURN_OK; - } - //Type insertion required. - result = findOrInsertMatch( - lastTest.left(), &testPacket, &lastTest); - if (result == NEW_NODE_CREATED) { - if (rollback == this->end()) { - rollback = lastTest; - } - } else if (result != RETURN_OK) { - if (rollback != this->end()) { - removeElementAndAllChildren(rollback); - } - return result; - } - if (subtype == 0) { - if (lastTest.left() != this->end()) { - //See above - removeElementAndAllChildren(lastTest.left()); - } - return RETURN_OK; - } - //Subtype insertion required. - result = findOrInsertMatch( - lastTest.left(), &testPacket, &lastTest); - if (result == NEW_NODE_CREATED) { - return RETURN_OK; - } else if (result != RETURN_OK) { - if (rollback != this->end()) { - removeElementAndAllChildren(rollback); - } - return result; - } - return RETURN_OK; -} - -template -ReturnValue_t PacketMatchTree::findOrInsertMatch(iterator startAt, VALUE_T test, - iterator* lastTest) { - bool attachToBranch = AND; - iterator iter = startAt; - while (iter != this->end()) { - bool isMatch = iter->match(test); - attachToBranch = OR; - *lastTest = iter; - if (isMatch) { - return RETURN_OK; - } else { - //Go down OR branch. - iter = iter.right(); - } - } - //Only reached if nothing was found. - SerializeableMatcherIF* newContent = factory.generate( - test); - if (newContent == NULL) { - return FULL; - } - Node* newNode = factory.generate(newContent); - if (newNode == NULL) { - //Need to make sure partially generated content is deleted, otherwise, that's a leak. - factory.destroy(static_cast(newContent)); - return FULL; - } - *lastTest = insert(attachToBranch, *lastTest, newNode); - if (*lastTest == end()) { - //This actaully never fails, so creating a dedicated returncode seems an overshoot. - return RETURN_FAILED; - } - return NEW_NODE_CREATED; -} - -ReturnValue_t PacketMatchTree::removeMatch(uint16_t apid, uint8_t type, - uint8_t subtype) { - TmPacketMinimal::TmPacketMinimalPointer data; - data.data_field.service_type = type; - data.data_field.service_subtype = subtype; - TmPacketMinimal testPacket((uint8_t*) &data); - testPacket.setAPID(apid); - iterator foundElement = findMatch(begin(), &testPacket); - if (foundElement == this->end()) { - return NO_MATCH; - } - if (type == 0) { - if (foundElement.left() == end()) { - return removeElementAndReconnectChildren(foundElement); - } else { - return TOO_GENERAL_REQUEST; - } - } - //Go down AND branch. Will abort if empty. - foundElement = findMatch(foundElement.left(), &testPacket); - if (foundElement == this->end()) { - return NO_MATCH; - } - if (subtype == 0) { - if (foundElement.left() == end()) { - return removeElementAndReconnectChildren(foundElement); - } else { - return TOO_GENERAL_REQUEST; - } - } - //Again, go down AND branch. - foundElement = findMatch(foundElement.left(), &testPacket); - if (foundElement == end()) { - return NO_MATCH; - } - return removeElementAndReconnectChildren(foundElement); -} - -PacketMatchTree::iterator PacketMatchTree::findMatch(iterator startAt, - TmPacketMinimal* test) { - iterator iter = startAt; - while (iter != end()) { - bool isMatch = iter->match(test); - if (isMatch) { - break; - } else { - iter = iter.right(); //next OR element - } - } - return iter; -} - -ReturnValue_t PacketMatchTree::initialize() { - return factoryBackend.initialize(); -} - - -ReturnValue_t PacketMatchTree::changeMatch(bool addToMatch, uint16_t apid, - uint8_t type, uint8_t subtype) { - if (addToMatch) { - return addMatch(apid, type, subtype); - } else { - return removeMatch(apid, type, subtype); - } -} - -ReturnValue_t PacketMatchTree::cleanUpElement(iterator position) { - factory.destroy(position.element->value); - //Go on anyway, there's nothing we can do. - //SHOULDDO: Throw event, or write debug message? - return factory.destroy(position.element); -} diff --git a/tmtcpacket/packetmatcher/PacketMatchTree.h b/tmtcpacket/packetmatcher/PacketMatchTree.h deleted file mode 100644 index 54fc856c..00000000 --- a/tmtcpacket/packetmatcher/PacketMatchTree.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef FRAMEWORK_TMTCPACKET_PACKETMATCHER_PACKETMATCHTREE_H_ -#define FRAMEWORK_TMTCPACKET_PACKETMATCHER_PACKETMATCHTREE_H_ - -#include "../../container/PlacementFactory.h" -#include "../../globalfunctions/matching/MatchTree.h" -#include "../../storagemanager/LocalPool.h" -#include "../../tmtcpacket/pus/TmPacketMinimal.h" - -class PacketMatchTree: public MatchTree, public HasReturnvaluesIF { -public: - PacketMatchTree(Node* root); - PacketMatchTree(iterator root); - PacketMatchTree(); - virtual ~PacketMatchTree(); - ReturnValue_t changeMatch(bool addToMatch, uint16_t apid, uint8_t type = 0, - uint8_t subtype = 0); - ReturnValue_t addMatch(uint16_t apid, uint8_t type = 0, - uint8_t subtype = 0); - ReturnValue_t removeMatch(uint16_t apid, uint8_t type = 0, - uint8_t subtype = 0); - ReturnValue_t initialize(); -protected: - ReturnValue_t cleanUpElement(iterator position); -private: - static const uint8_t N_POOLS = 4; - LocalPool factoryBackend; - PlacementFactory factory; - static const LocalPool::LocalPoolConfig poolConfig; - static const uint16_t POOL_SIZES[N_POOLS]; - static const uint16_t N_ELEMENTS[N_POOLS]; - template - ReturnValue_t findOrInsertMatch(iterator startAt, VALUE_T test, iterator* lastTest); - iterator findMatch(iterator startAt, TmPacketMinimal* test); -}; - -#endif /* FRAMEWORK_TMTCPACKET_PACKETMATCHER_PACKETMATCHTREE_H_ */ - diff --git a/tmtcpacket/packetmatcher/ServiceMatcher.h b/tmtcpacket/packetmatcher/ServiceMatcher.h deleted file mode 100644 index eba23d75..00000000 --- a/tmtcpacket/packetmatcher/ServiceMatcher.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef FRAMEWORK_TMTCPACKET_PACKETMATCHER_SERVICEMATCHER_H_ -#define FRAMEWORK_TMTCPACKET_PACKETMATCHER_SERVICEMATCHER_H_ - -#include "../../globalfunctions/matching/SerializeableMatcherIF.h" -#include "../../serialize/SerializeAdapter.h" -#include "../../tmtcpacket/pus/TmPacketMinimal.h" - -class ServiceMatcher: public SerializeableMatcherIF { -private: - uint8_t service; -public: - ServiceMatcher(uint8_t setService) : - service(setService) { - } - ServiceMatcher(TmPacketMinimal* test) : - service(test->getService()) { - } - bool match(TmPacketMinimal* packet) { - if (packet->getService() == service) { - return true; - } else { - return false; - } - } - ReturnValue_t serialize(uint8_t** buffer, size_t* size, - size_t maxSize, Endianness streamEndianness) const { - return SerializeAdapter::serialize(&service, buffer, size, maxSize, streamEndianness); - } - size_t getSerializedSize() const { - return SerializeAdapter::getSerializedSize(&service); - } - ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - Endianness streamEndianness) { - return SerializeAdapter::deSerialize(&service, buffer, size, streamEndianness); - } -}; - - -#endif /* FRAMEWORK_TMTCPACKET_PACKETMATCHER_SERVICEMATCHER_H_ */ diff --git a/tmtcpacket/packetmatcher/SubserviceMatcher.h b/tmtcpacket/packetmatcher/SubserviceMatcher.h deleted file mode 100644 index a9b6def8..00000000 --- a/tmtcpacket/packetmatcher/SubserviceMatcher.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef FRAMEWORK_TMTCPACKET_PACKETMATCHER_SUBSERVICEMATCHER_H_ -#define FRAMEWORK_TMTCPACKET_PACKETMATCHER_SUBSERVICEMATCHER_H_ - -#include "../../globalfunctions/matching/SerializeableMatcherIF.h" -#include "../../serialize/SerializeAdapter.h" -#include "../../tmtcpacket/pus/TmPacketMinimal.h" - -class SubServiceMatcher: public SerializeableMatcherIF { -public: - SubServiceMatcher(uint8_t subService) : - subService(subService) { - } - SubServiceMatcher(TmPacketMinimal* test) : - subService(test->getSubService()) { - } - bool match(TmPacketMinimal* packet) { - if (packet->getSubService() == subService) { - return true; - } else { - return false; - } - } - ReturnValue_t serialize(uint8_t** buffer, size_t* size, - size_t maxSize, Endianness streamEndianness) const { - return SerializeAdapter::serialize(&subService, buffer, size, maxSize, streamEndianness); - } - size_t getSerializedSize() const { - return SerializeAdapter::getSerializedSize(&subService); - } - ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - Endianness streamEndianness) { - return SerializeAdapter::deSerialize(&subService, buffer, size, streamEndianness); - } -private: - uint8_t subService; -}; - - - -#endif /* FRAMEWORK_TMTCPACKET_PACKETMATCHER_SUBSERVICEMATCHER_H_ */ diff --git a/tmtcpacket/pus/CMakeLists.txt b/tmtcpacket/pus/CMakeLists.txt deleted file mode 100644 index fcfc82d2..00000000 --- a/tmtcpacket/pus/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -target_sources(${LIB_FSFW_NAME} - PRIVATE - TcPacketBase.cpp - TcPacketStored.cpp - TmPacketBase.cpp - TmPacketMinimal.cpp - TmPacketStored.cpp -) diff --git a/tmtcpacket/pus/PacketTimestampInterpreterIF.h b/tmtcpacket/pus/PacketTimestampInterpreterIF.h deleted file mode 100644 index 40e7a2ea..00000000 --- a/tmtcpacket/pus/PacketTimestampInterpreterIF.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef FRAMEWORK_TMTCPACKET_PUS_PACKETTIMESTAMPINTERPRETERIF_H_ -#define FRAMEWORK_TMTCPACKET_PUS_PACKETTIMESTAMPINTERPRETERIF_H_ - -#include "../../returnvalues/HasReturnvaluesIF.h" -class TmPacketMinimal; - -class PacketTimestampInterpreterIF { -public: - virtual ~PacketTimestampInterpreterIF() {} - virtual ReturnValue_t getPacketTime(TmPacketMinimal* packet, - timeval* timestamp) const = 0; - virtual ReturnValue_t getPacketTimeRaw(TmPacketMinimal* packet, const uint8_t** timePtr, uint32_t* size) const = 0; -}; - - - -#endif /* FRAMEWORK_TMTCPACKET_PUS_PACKETTIMESTAMPINTERPRETERIF_H_ */ diff --git a/tmtcpacket/pus/TcPacketBase.cpp b/tmtcpacket/pus/TcPacketBase.cpp deleted file mode 100644 index ca3e2a99..00000000 --- a/tmtcpacket/pus/TcPacketBase.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include "TcPacketBase.h" - -#include "../../globalfunctions/CRC.h" -#include "../../globalfunctions/arrayprinter.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" - -#include - -TcPacketBase::TcPacketBase(const uint8_t* setData) : - SpacePacketBase(setData) { - tcData = reinterpret_cast(const_cast(setData)); -} - -TcPacketBase::~TcPacketBase() { - //Nothing to do. -} - -uint8_t TcPacketBase::getService() { - return tcData->dataField.service_type; -} - -uint8_t TcPacketBase::getSubService() { - return tcData->dataField.service_subtype; -} - -uint8_t TcPacketBase::getAcknowledgeFlags() { - return tcData->dataField.version_type_ack & 0b00001111; -} - -const uint8_t* TcPacketBase::getApplicationData() const { - return &tcData->appData; -} - -uint16_t TcPacketBase::getApplicationDataSize() { - return getPacketDataLength() - sizeof(tcData->dataField) - CRC_SIZE + 1; -} - -uint16_t TcPacketBase::getErrorControl() { - uint16_t size = getApplicationDataSize() + CRC_SIZE; - uint8_t* p_to_buffer = &tcData->appData; - return (p_to_buffer[size - 2] << 8) + p_to_buffer[size - 1]; -} - -void TcPacketBase::setErrorControl() { - uint32_t full_size = getFullSize(); - uint16_t crc = CRC::crc16ccitt(getWholeData(), full_size - CRC_SIZE); - uint32_t size = getApplicationDataSize(); - (&tcData->appData)[size] = (crc & 0XFF00) >> 8; // CRCH - (&tcData->appData)[size + 1] = (crc) & 0X00FF; // CRCL -} - -void TcPacketBase::setData(const uint8_t* pData) { - SpacePacketBase::setData(pData); - tcData = (TcPacketPointer*) pData; -} - -uint8_t TcPacketBase::getSecondaryHeaderFlag() { - return (tcData->dataField.version_type_ack & 0b10000000) >> 7; -} - -uint8_t TcPacketBase::getPusVersionNumber() { - return (tcData->dataField.version_type_ack & 0b01110000) >> 4; -} - -void TcPacketBase::print() { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::debug << "TcPacketBase::print: " << std::endl; -#endif - arrayprinter::print(getWholeData(), getFullSize()); -} - -void TcPacketBase::initializeTcPacket(uint16_t apid, uint16_t sequenceCount, - uint8_t ack, uint8_t service, uint8_t subservice) { - initSpacePacketHeader(true, true, apid, sequenceCount); - std::memset(&tcData->dataField, 0, sizeof(tcData->dataField)); - setPacketDataLength(sizeof(PUSTcDataFieldHeader) + CRC_SIZE - 1); - //Data Field Header: - //Set CCSDS_secondary_header_flag to 0 and version number to 001 - tcData->dataField.version_type_ack = 0b00010000; - tcData->dataField.version_type_ack |= (ack & 0x0F); - tcData->dataField.service_type = service; - tcData->dataField.service_subtype = subservice; -} - -size_t TcPacketBase::calculateFullPacketLength(size_t appDataLen) { - return sizeof(CCSDSPrimaryHeader) + sizeof(PUSTcDataFieldHeader) + - appDataLen + TcPacketBase::CRC_SIZE; -} diff --git a/tmtcpacket/pus/TcPacketBase.h b/tmtcpacket/pus/TcPacketBase.h deleted file mode 100644 index 582a2214..00000000 --- a/tmtcpacket/pus/TcPacketBase.h +++ /dev/null @@ -1,187 +0,0 @@ -#ifndef TMTCPACKET_PUS_TCPACKETBASE_H_ -#define TMTCPACKET_PUS_TCPACKETBASE_H_ - -#include "../../tmtcpacket/SpacePacketBase.h" -#include - - -/** - * This struct defines a byte-wise structured PUS TC Data Field Header. - * Any optional fields in the header must be added or removed here. - * Currently, the Source Id field is present with one byte. - * @ingroup tmtcpackets - */ -struct PUSTcDataFieldHeader { - uint8_t version_type_ack; - uint8_t service_type; - uint8_t service_subtype; - uint8_t source_id; -}; - -/** - * This struct defines the data structure of a PUS Telecommand Packet when - * accessed via a pointer. - * @ingroup tmtcpackets - */ -struct TcPacketPointer { - CCSDSPrimaryHeader primary; - PUSTcDataFieldHeader dataField; - uint8_t appData; -}; - -/** - * This class is the basic data handler for any ECSS PUS Telecommand packet. - * - * In addition to #SpacePacketBase, the class provides methods to handle - * the standardized entries of the PUS TC Packet Data Field Header. - * It does not contain the packet data itself but a pointer to the - * data must be set on instantiation. An invalid pointer may cause - * damage, as no getter method checks data validity. Anyway, a NULL - * check can be performed by making use of the getWholeData method. - * @ingroup tmtcpackets - */ -class TcPacketBase : public SpacePacketBase { -public: - static const uint16_t TC_PACKET_MIN_SIZE = (sizeof(CCSDSPrimaryHeader) + - sizeof(PUSTcDataFieldHeader) + 2); - - enum AckField { - //! No acknowledgements are expected. - ACK_NONE = 0b0000, - //! Acknowledgements on acceptance are expected. - ACK_ACCEPTANCE = 0b0001, - //! Acknowledgements on start are expected. - ACK_START = 0b0010, - //! Acknowledgements on step are expected. - ACK_STEP = 0b0100, - //! Acknowledfgement on completion are expected. - ACK_COMPLETION = 0b1000 - }; - - static constexpr uint8_t ACK_ALL = ACK_ACCEPTANCE | ACK_START | ACK_STEP | - ACK_COMPLETION; - - /** - * This is the default constructor. - * It sets its internal data pointer to the address passed and also - * forwards the data pointer to the parent SpacePacketBase class. - * @param setData The position where the packet data lies. - */ - TcPacketBase( const uint8_t* setData ); - /** - * This is the empty default destructor. - */ - virtual ~TcPacketBase(); - - /** - * This command returns the CCSDS Secondary Header Flag. - * It shall always be zero for PUS Packets. This is the - * highest bit of the first byte of the Data Field Header. - * @return the CCSDS Secondary Header Flag - */ - uint8_t getSecondaryHeaderFlag(); - /** - * This command returns the TC Packet PUS Version Number. - * The version number of ECSS PUS 2003 is 1. - * It consists of the second to fourth highest bits of the - * first byte. - * @return - */ - uint8_t getPusVersionNumber(); - /** - * This is a getter for the packet's Ack field, which are the lowest four - * bits of the first byte of the Data Field Header. - * - * It is packed in a uint8_t variable. - * @return The packet's PUS Ack field. - */ - uint8_t getAcknowledgeFlags(); - /** - * This is a getter for the packet's PUS Service ID, which is the second - * byte of the Data Field Header. - * @return The packet's PUS Service ID. - */ - uint8_t getService(); - /** - * This is a getter for the packet's PUS Service Subtype, which is the - * third byte of the Data Field Header. - * @return The packet's PUS Service Subtype. - */ - uint8_t getSubService(); - /** - * This is a getter for a pointer to the packet's Application data. - * - * These are the bytes that follow after the Data Field Header. They form - * the packet's application data. - * @return A pointer to the PUS Application Data. - */ - const uint8_t* getApplicationData() const; - /** - * This method calculates the size of the PUS Application data field. - * - * It takes the information stored in the CCSDS Packet Data Length field - * and subtracts the Data Field Header size and the CRC size. - * @return The size of the PUS Application Data (without Error Control - * field) - */ - uint16_t getApplicationDataSize(); - /** - * This getter returns the Error Control Field of the packet. - * - * The field is placed after any possible Application Data. If no - * Application Data is present there's still an Error Control field. It is - * supposed to be a 16bit-CRC. - * @return The PUS Error Control - */ - uint16_t getErrorControl(); - /** - * With this method, the Error Control Field is updated to match the - * current content of the packet. - */ - void setErrorControl(); - - /** - * This is a debugging helper method that prints the whole packet content - * to the screen. - */ - void print(); - /** - * Calculate full packet length from application data length. - * @param appDataLen - * @return - */ - static size_t calculateFullPacketLength(size_t appDataLen); - -protected: - /** - * A pointer to a structure which defines the data structure of - * the packet's data. - * - * To be hardware-safe, all elements are of byte size. - */ - TcPacketPointer* tcData; - - /** - * Initializes the Tc Packet header. - * @param apid APID used. - * @param sequenceCount Sequence Count in the primary header. - * @param ack Which acknowledeges are expected from the receiver. - * @param service PUS Service - * @param subservice PUS Subservice - */ - void initializeTcPacket(uint16_t apid, uint16_t sequenceCount, uint8_t ack, - uint8_t service, uint8_t subservice); - - /** - * With this method, the packet data pointer can be redirected to another - * location. - * This call overwrites the parent's setData method to set both its - * @c tc_data pointer and the parent's @c data pointer. - * - * @param p_data A pointer to another PUS Telecommand Packet. - */ - void setData( const uint8_t* pData ); -}; - - -#endif /* TMTCPACKET_PUS_TCPACKETBASE_H_ */ diff --git a/tmtcpacket/pus/TcPacketStored.cpp b/tmtcpacket/pus/TcPacketStored.cpp deleted file mode 100644 index f320386c..00000000 --- a/tmtcpacket/pus/TcPacketStored.cpp +++ /dev/null @@ -1,123 +0,0 @@ -#include "TcPacketStored.h" -#include "../../objectmanager/ObjectManagerIF.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" - -#include - -StorageManagerIF* TcPacketStored::store = nullptr; - -TcPacketStored::TcPacketStored(store_address_t setAddress) : - TcPacketBase(nullptr), storeAddress(setAddress) { - setStoreAddress(storeAddress); -} - -TcPacketStored::TcPacketStored(uint16_t apid, uint8_t service, - uint8_t subservice, uint8_t sequenceCount, const uint8_t* data, - size_t size, uint8_t ack) : - TcPacketBase(nullptr) { - this->storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; - if (not this->checkAndSetStore()) { - return; - } - uint8_t* pData = nullptr; - ReturnValue_t returnValue = 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 << "TcPacketStored: Could not get free element from store!" - << std::endl; -#endif - return; - } - this->setData(pData); - initializeTcPacket(apid, sequenceCount, ack, service, subservice); - memcpy(&tcData->appData, data, size); - this->setPacketDataLength( - size + sizeof(PUSTcDataFieldHeader) + CRC_SIZE - 1); - this->setErrorControl(); -} - -ReturnValue_t TcPacketStored::getData(const uint8_t ** dataPtr, - size_t* dataSize) { - auto result = this->store->getData(storeAddress, dataPtr, dataSize); - if(result != HasReturnvaluesIF::RETURN_OK) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "TcPacketStored: Could not get data!" << std::endl; -#endif - } - return result; -} - -TcPacketStored::TcPacketStored(): TcPacketBase(nullptr) { - this->storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; - this->checkAndSetStore(); - -} - -ReturnValue_t TcPacketStored::deletePacket() { - ReturnValue_t result = this->store->deleteData(this->storeAddress); - this->storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; - this->setData(nullptr); - return result; -} - -bool TcPacketStored::checkAndSetStore() { - if (this->store == nullptr) { - this->store = objectManager->get(objects::TC_STORE); - if (this->store == nullptr) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "TcPacketStored::TcPacketStored: TC Store not found!" - << std::endl; -#endif - return false; - } - } - return true; -} - -void TcPacketStored::setStoreAddress(store_address_t setAddress) { - this->storeAddress = setAddress; - const uint8_t* tempData = nullptr; - size_t temp_size; - ReturnValue_t status = StorageManagerIF::RETURN_FAILED; - if (this->checkAndSetStore()) { - status = this->store->getData(this->storeAddress, &tempData, - &temp_size); - } - if (status == StorageManagerIF::RETURN_OK) { - this->setData(tempData); - } else { - this->setData(nullptr); - this->storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; - } -} - -store_address_t TcPacketStored::getStoreAddress() { - return this->storeAddress; -} - -bool TcPacketStored::isSizeCorrect() { - const uint8_t* temp_data = nullptr; - size_t 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; - } - } - return false; -} - -TcPacketStored::TcPacketStored(const uint8_t* data, uint32_t size) : - TcPacketBase(data) { - if (getFullSize() != size) { - return; - } - if (this->checkAndSetStore()) { - ReturnValue_t status = store->addData(&storeAddress, data, size); - if (status != HasReturnvaluesIF::RETURN_OK) { - this->setData(nullptr); - } - } -} diff --git a/tmtcpacket/pus/TcPacketStored.h b/tmtcpacket/pus/TcPacketStored.h deleted file mode 100644 index 1666107b..00000000 --- a/tmtcpacket/pus/TcPacketStored.h +++ /dev/null @@ -1,117 +0,0 @@ -#ifndef TMTCPACKET_PUS_TCPACKETSTORED_H_ -#define TMTCPACKET_PUS_TCPACKETSTORED_H_ - -#include "TcPacketBase.h" -#include "../../storagemanager/StorageManagerIF.h" - -/** - * This class generates a ECSS PUS Telecommand packet within a given - * intermediate storage. - * As most packets are passed between tasks with the help of a storage - * anyway, it seems logical to create a Packet-In-Storage access class - * which saves the user almost all storage handling operation. - * Packets can both be newly created with the class and be "linked" to - * packets in a store with the help of a storeAddress. - * @ingroup tmtcpackets - */ -class TcPacketStored : public TcPacketBase { -public: - /** - * This is a default constructor which does not set the data pointer. - * However, it does try to set the packet store. - */ - TcPacketStored(); - /** - * With this constructor, the class instance is linked to an existing - * packet in the packet store. - * The packet content is neither checked nor changed with this call. If - * the packet could not be found, the data pointer is set to NULL. - */ - TcPacketStored( store_address_t setAddress ); - /** - * With this constructor, new space is allocated in the packet store and - * a new PUS Telecommand Packet is created there. - * Packet Application Data passed in data is copied into the packet. - * @param apid Sets the packet's APID field. - * @param service Sets the packet's Service ID field. - * This specifies the destination service. - * @param subservice Sets the packet's Service Subtype field. - * This specifies the destination sub-service. - * @param sequence_count Sets the packet's Source Sequence Count field. - * @param data The data to be copied to the Application Data Field. - * @param size The amount of data to be copied. - * @param ack Set's the packet's Ack field, which specifies - * number of verification packets returned - * for this command. - */ - TcPacketStored(uint16_t apid, uint8_t service, uint8_t subservice, - uint8_t sequence_count = 0, const uint8_t* data = nullptr, - size_t size = 0, uint8_t ack = TcPacketBase::ACK_ALL); - /** - * Another constructor to create a TcPacket from a raw packet stream. - * Takes the data and adds it unchecked to the TcStore. - * @param data Pointer to the complete TC Space Packet. - * @param Size size of the packet. - */ - TcPacketStored( const uint8_t* data, uint32_t size); - - /** - * Getter function for the raw data. - * @param dataPtr [out] Pointer to the data pointer to set - * @param dataSize [out] Address of size to set. - * @return -@c RETURN_OK if data was retrieved successfully. - */ - ReturnValue_t getData(const uint8_t ** dataPtr, - size_t* dataSize); - /** - * This is a getter for the current store address of the packet. - * @return The current store address. The (raw) value is - * @c StorageManagerIF::INVALID_ADDRESS if the packet is not linked. - */ - store_address_t getStoreAddress(); - /** - * With this call, the packet is deleted. - * It removes itself from the store and sets its data pointer to NULL. - * @return returncode from deleting the data. - */ - ReturnValue_t deletePacket(); - /** - * With this call, a packet can be linked to another store. This is useful - * if the packet is a class member and used for more than one packet. - * @param setAddress The new packet id to link to. - */ - void setStoreAddress( store_address_t setAddress ); - /** - * This method performs a size check. - * It reads the stored size and compares it with the size entered in the - * packet header. This class is the optimal place for such a check as it - * has access to both the header data and the store. - * @return true if size is correct, false if packet is not registered in - * store or size is incorrect. - */ - bool isSizeCorrect(); - -private: - /** - * This is a pointer to the store all instances of the class use. - * If the store is not yet set (i.e. @c store is NULL), every constructor - * call tries to set it and throws an error message in case of failures. - * The default store is objects::TC_STORE. - */ - static StorageManagerIF* store; - /** - * The address where the packet data of the object instance is stored. - */ - store_address_t storeAddress; - /** - * A helper method to check if a store is assigned to the class. - * If not, the method tries to retrieve the store from the global - * ObjectManager. - * @return @li @c true if the store is linked or could be created. - * @li @c false otherwise. - */ - bool checkAndSetStore(); -}; - - -#endif /* TMTCPACKET_PUS_TCPACKETSTORED_H_ */ diff --git a/tmtcpacket/pus/TmPacketBase.cpp b/tmtcpacket/pus/TmPacketBase.cpp deleted file mode 100644 index 148e50dd..00000000 --- a/tmtcpacket/pus/TmPacketBase.cpp +++ /dev/null @@ -1,121 +0,0 @@ -#include "TmPacketBase.h" - -#include "../../globalfunctions/CRC.h" -#include "../../globalfunctions/arrayprinter.h" -#include "../../objectmanager/ObjectManagerIF.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" -#include "../../timemanager/CCSDSTime.h" - -#include - -TimeStamperIF* TmPacketBase::timeStamper = nullptr; -object_id_t TmPacketBase::timeStamperId = 0; - -TmPacketBase::TmPacketBase(uint8_t* setData) : - SpacePacketBase(setData) { - tmData = reinterpret_cast(setData); -} - -TmPacketBase::~TmPacketBase() { - //Nothing to do. -} - -uint8_t TmPacketBase::getService() { - return tmData->data_field.service_type; -} - -uint8_t TmPacketBase::getSubService() { - return tmData->data_field.service_subtype; -} - -uint8_t* TmPacketBase::getSourceData() { - return &tmData->data; -} - -uint16_t TmPacketBase::getSourceDataSize() { - return getPacketDataLength() - sizeof(tmData->data_field) - - CRC_SIZE + 1; -} - -uint16_t TmPacketBase::getErrorControl() { - uint32_t size = getSourceDataSize() + CRC_SIZE; - uint8_t* p_to_buffer = &tmData->data; - return (p_to_buffer[size - 2] << 8) + p_to_buffer[size - 1]; -} - -void TmPacketBase::setErrorControl() { - uint32_t full_size = getFullSize(); - uint16_t crc = CRC::crc16ccitt(getWholeData(), full_size - CRC_SIZE); - uint32_t size = getSourceDataSize(); - getSourceData()[size] = (crc & 0XFF00) >> 8; // CRCH - getSourceData()[size + 1] = (crc) & 0X00FF; // CRCL -} - -void TmPacketBase::setData(const uint8_t* p_Data) { - SpacePacketBase::setData(p_Data); - tmData = (TmPacketPointer*) p_Data; -} - -void TmPacketBase::print() { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::debug << "TmPacketBase::print: " << std::endl; -#endif - arrayprinter::print(getWholeData(), getFullSize()); -} - -bool TmPacketBase::checkAndSetStamper() { - if (timeStamper == NULL) { - timeStamper = objectManager->get(timeStamperId); - if (timeStamper == NULL) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "TmPacketBase::checkAndSetStamper: Stamper not found!" - << std::endl; -#endif - return false; - } - } - return true; -} - -ReturnValue_t TmPacketBase::getPacketTime(timeval* timestamp) const { - size_t tempSize = 0; - return CCSDSTime::convertFromCcsds(timestamp, tmData->data_field.time, - &tempSize, sizeof(tmData->data_field.time)); -} - -uint8_t* TmPacketBase::getPacketTimeRaw() const{ - return tmData->data_field.time; - -} - -void TmPacketBase::initializeTmPacket(uint16_t apid, uint8_t service, - uint8_t subservice , uint8_t packetSubcounter) { - //Set primary header: - initSpacePacketHeader(false, true, apid); - //Set data Field Header: - //First, set to zero. - memset(&tmData->data_field, 0, sizeof(tmData->data_field)); - - // NOTE: In PUS-C, the PUS Version is 2 and specified for the first 4 bits. - // The other 4 bits of the first byte are the spacecraft time reference - // status. To change to PUS-C, set 0b00100000. - // Set CCSDS_secondary header flag to 0, version number to 001 and ack - // to 0000 - tmData->data_field.version_type_ack = 0b00010000; - tmData->data_field.service_type = service; - tmData->data_field.service_subtype = subservice; - //tmData->data_field.subcounter = packetSubcounter; - //Timestamp packet - if (checkAndSetStamper()) { - timeStamper->addTimeStamp(tmData->data_field.time, - sizeof(tmData->data_field.time)); - } -} - -void TmPacketBase::setSourceDataSize(uint16_t size) { - setPacketDataLength(size + sizeof(PUSTmDataFieldHeader) + CRC_SIZE - 1); -} - -size_t TmPacketBase::getTimestampSize() const { - return sizeof(tmData->data_field.time); -} diff --git a/tmtcpacket/pus/TmPacketBase.h b/tmtcpacket/pus/TmPacketBase.h deleted file mode 100644 index c4556cd8..00000000 --- a/tmtcpacket/pus/TmPacketBase.h +++ /dev/null @@ -1,195 +0,0 @@ -#ifndef TMTCPACKET_PUS_TMPACKETBASE_H_ -#define TMTCPACKET_PUS_TMPACKETBASE_H_ - -#include "../SpacePacketBase.h" -#include "../../timemanager/TimeStamperIF.h" -#include "../../timemanager/Clock.h" -#include "../../objectmanager/SystemObjectIF.h" - -namespace Factory{ -void setStaticFrameworkObjectIds(); -} - -/** - * This struct defines a byte-wise structured PUS TM Data Field Header. - * Any optional fields in the header must be added or removed here. - * Currently, no Destination field is present, but an eigth-byte representation - * for a time tag. - * @ingroup tmtcpackets - */ -struct PUSTmDataFieldHeader { - uint8_t version_type_ack; - uint8_t service_type; - uint8_t service_subtype; -// uint8_t subcounter; -// uint8_t destination; - uint8_t time[TimeStamperIF::MISSION_TIMESTAMP_SIZE]; -}; - -/** - * This struct defines the data structure of a PUS Telecommand Packet when - * accessed via a pointer. - * @ingroup tmtcpackets - */ -struct TmPacketPointer { - CCSDSPrimaryHeader primary; - PUSTmDataFieldHeader data_field; - uint8_t data; -}; - -/** - * This class is the basic data handler for any ECSS PUS Telemetry packet. - * - * In addition to #SpacePacketBase, the class provides methods to handle - * the standardized entries of the PUS TM Packet Data Field Header. - * It does not contain the packet data itself but a pointer to the - * data must be set on instantiation. An invalid pointer may cause - * damage, as no getter method checks data validity. Anyway, a NULL - * check can be performed by making use of the getWholeData method. - * @ingroup tmtcpackets - */ -class TmPacketBase : public SpacePacketBase { - friend void (Factory::setStaticFrameworkObjectIds)(); -public: - /** - * This constant defines the minimum size of a valid PUS Telemetry Packet. - */ - static const uint32_t TM_PACKET_MIN_SIZE = (sizeof(CCSDSPrimaryHeader) + - sizeof(PUSTmDataFieldHeader) + 2); - //! Maximum size of a TM Packet in this mission. - //! TODO: Make this dependant on a config variable. - static const uint32_t MISSION_TM_PACKET_MAX_SIZE = 1024; - //! First byte of secondary header for PUS-A packets. - //! TODO: Maybe also support PUS-C via config? - static const uint8_t VERSION_NUMBER_BYTE_PUS_A = 0b00010000; - - /** - * This is the default constructor. - * It sets its internal data pointer to the address passed and also - * forwards the data pointer to the parent SpacePacketBase class. - * @param set_address The position where the packet data lies. - */ - TmPacketBase( uint8_t* setData ); - /** - * This is the empty default destructor. - */ - virtual ~TmPacketBase(); - - /** - * This is a getter for the packet's PUS Service ID, which is the second - * byte of the Data Field Header. - * @return The packet's PUS Service ID. - */ - uint8_t getService(); - /** - * This is a getter for the packet's PUS Service Subtype, which is the - * third byte of the Data Field Header. - * @return The packet's PUS Service Subtype. - */ - uint8_t getSubService(); - /** - * This is a getter for a pointer to the packet's Source data. - * - * These are the bytes that follow after the Data Field Header. They form - * the packet's source data. - * @return A pointer to the PUS Source Data. - */ - uint8_t* getSourceData(); - /** - * This method calculates the size of the PUS Source data field. - * - * It takes the information stored in the CCSDS Packet Data Length field - * and subtracts the Data Field Header size and the CRC size. - * @return The size of the PUS Source Data (without Error Control field) - */ - uint16_t getSourceDataSize(); - - /** - * With this method, the Error Control Field is updated to match the - * current content of the packet. This method is not protected because - * a recalculation by the user might be necessary when manipulating fields - * like the sequence count. - */ - void setErrorControl(); - - /** - * This getter returns the Error Control Field of the packet. - * - * The field is placed after any possible Source Data. If no - * Source Data is present there's still an Error Control field. It is - * supposed to be a 16bit-CRC. - * @return The PUS Error Control - */ - uint16_t getErrorControl(); - - /** - * This is a debugging helper method that prints the whole packet content - * to the screen. - */ - void print(); - /** - * Interprets the "time"-field in the secondary header and returns it in - * timeval format. - * @return Converted timestamp of packet. - */ - ReturnValue_t getPacketTime(timeval* timestamp) const; - /** - * Returns a raw pointer to the beginning of the time field. - * @return Raw pointer to time field. - */ - uint8_t* getPacketTimeRaw() const; - - size_t getTimestampSize() const; - -protected: - /** - * A pointer to a structure which defines the data structure of - * the packet's data. - * - * To be hardware-safe, all elements are of byte size. - */ - TmPacketPointer* tmData; - /** - * The timeStamper is responsible for adding a timestamp to the packet. - * It is initialized lazy. - */ - static TimeStamperIF* timeStamper; - //! The ID to use when looking for a time stamper. - static object_id_t timeStamperId; - - /** - * Initializes the Tm Packet header. - * Does set the timestamp (to now), but not the error control field. - * @param apid APID used. - * @param service PUS Service - * @param subservice PUS Subservice - * @param packetSubcounter Additional subcounter used. - */ - void initializeTmPacket(uint16_t apid, uint8_t service, uint8_t subservice, uint8_t packetSubcounter); - - /** - * With this method, the packet data pointer can be redirected to another - * location. - * - * This call overwrites the parent's setData method to set both its - * @c tc_data pointer and the parent's @c data pointer. - * - * @param p_data A pointer to another PUS Telemetry Packet. - */ - void setData( const uint8_t* pData ); - - /** - * In case data was filled manually (almost never the case). - * @param size Size of source data (without CRC and data filed header!). - */ - void setSourceDataSize(uint16_t size); - - /** - * Checks if a time stamper is available and tries to set it if not. - * @return Returns false if setting failed. - */ - bool checkAndSetStamper(); -}; - - -#endif /* TMTCPACKET_PUS_TMPACKETBASE_H_ */ diff --git a/tmtcpacket/pus/TmPacketStored.cpp b/tmtcpacket/pus/TmPacketStored.cpp deleted file mode 100644 index 0fd2a4a0..00000000 --- a/tmtcpacket/pus/TmPacketStored.cpp +++ /dev/null @@ -1,147 +0,0 @@ -#include "TmPacketStored.h" - -#include "../../objectmanager/ObjectManagerIF.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" -#include "../../tmtcservices/TmTcMessage.h" - -#include - -StorageManagerIF *TmPacketStored::store = nullptr; -InternalErrorReporterIF *TmPacketStored::internalErrorReporter = nullptr; - -TmPacketStored::TmPacketStored(store_address_t setAddress) : - TmPacketBase(nullptr), storeAddress(setAddress) { - setStoreAddress(storeAddress); -} - -TmPacketStored::TmPacketStored(uint16_t apid, uint8_t service, - uint8_t subservice, uint8_t packetSubcounter, const uint8_t *data, - uint32_t size, const uint8_t *headerData, uint32_t headerSize) : - TmPacketBase(NULL) { - storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; - if (not checkAndSetStore()) { - return; - } - uint8_t *pData = nullptr; - ReturnValue_t returnValue = store->getFreeElement(&storeAddress, - (TmPacketBase::TM_PACKET_MIN_SIZE + size + headerSize), &pData); - - if (returnValue != store->RETURN_OK) { - checkAndReportLostTm(); - return; - } - setData(pData); - initializeTmPacket(apid, service, subservice, packetSubcounter); - memcpy(getSourceData(), headerData, headerSize); - memcpy(getSourceData() + headerSize, data, size); - setPacketDataLength( - size + headerSize + sizeof(PUSTmDataFieldHeader) + CRC_SIZE - 1); -} - -TmPacketStored::TmPacketStored(uint16_t apid, uint8_t service, - uint8_t subservice, uint8_t packetSubcounter, SerializeIF *content, - SerializeIF *header) : - TmPacketBase(NULL) { - storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; - if (not checkAndSetStore()) { - return; - } - size_t sourceDataSize = 0; - if (content != NULL) { - sourceDataSize += content->getSerializedSize(); - } - if (header != NULL) { - sourceDataSize += header->getSerializedSize(); - } - uint8_t *p_data = NULL; - ReturnValue_t returnValue = store->getFreeElement(&storeAddress, - (TmPacketBase::TM_PACKET_MIN_SIZE + sourceDataSize), &p_data); - if (returnValue != store->RETURN_OK) { - checkAndReportLostTm(); - } - setData(p_data); - initializeTmPacket(apid, service, subservice, packetSubcounter); - uint8_t *putDataHere = getSourceData(); - size_t size = 0; - if (header != NULL) { - header->serialize(&putDataHere, &size, sourceDataSize, - SerializeIF::Endianness::BIG); - } - if (content != NULL) { - content->serialize(&putDataHere, &size, sourceDataSize, - SerializeIF::Endianness::BIG); - } - setPacketDataLength( - sourceDataSize + sizeof(PUSTmDataFieldHeader) + CRC_SIZE - 1); -} - -store_address_t TmPacketStored::getStoreAddress() { - return storeAddress; -} - -void TmPacketStored::deletePacket() { - store->deleteData(storeAddress); - storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; - setData(nullptr); -} - -void TmPacketStored::setStoreAddress(store_address_t setAddress) { - storeAddress = setAddress; - const uint8_t* tempData = nullptr; - size_t tempSize; - if (not checkAndSetStore()) { - return; - } - ReturnValue_t status = store->getData(storeAddress, &tempData, &tempSize); - if (status == StorageManagerIF::RETURN_OK) { - setData(tempData); - } else { - setData(nullptr); - storeAddress.raw = StorageManagerIF::INVALID_ADDRESS; - } -} - -bool TmPacketStored::checkAndSetStore() { - if (store == nullptr) { - store = objectManager->get(objects::TM_STORE); - if (store == nullptr) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "TmPacketStored::TmPacketStored: TM Store not found!" - << std::endl; -#endif - return false; - } - } - return true; -} - -ReturnValue_t TmPacketStored::sendPacket(MessageQueueId_t destination, - MessageQueueId_t sentFrom, bool doErrorReporting) { - if (getWholeData() == nullptr) { - //SHOULDDO: More decent code. - return HasReturnvaluesIF::RETURN_FAILED; - } - TmTcMessage tmMessage(getStoreAddress()); - ReturnValue_t result = MessageQueueSenderIF::sendMessage(destination, - &tmMessage, sentFrom); - if (result != HasReturnvaluesIF::RETURN_OK) { - deletePacket(); - if (doErrorReporting) { - checkAndReportLostTm(); - } - return result; - } - //SHOULDDO: In many cases, some counter is incremented for successfully sent packets. The check is often not done, but just incremented. - return HasReturnvaluesIF::RETURN_OK; - -} - -void TmPacketStored::checkAndReportLostTm() { - if (internalErrorReporter == nullptr) { - internalErrorReporter = objectManager->get( - objects::INTERNAL_ERROR_REPORTER); - } - if (internalErrorReporter != nullptr) { - internalErrorReporter->lostTm(); - } -} diff --git a/tmtcpacket/pus/TmPacketStored.h b/tmtcpacket/pus/TmPacketStored.h deleted file mode 100644 index b231407d..00000000 --- a/tmtcpacket/pus/TmPacketStored.h +++ /dev/null @@ -1,108 +0,0 @@ -#ifndef FSFW_TMTCPACKET_PUS_TMPACKETSTORED_H_ -#define FSFW_TMTCPACKET_PUS_TMPACKETSTORED_H_ - -#include "TmPacketBase.h" - -#include "../../serialize/SerializeIF.h" -#include "../../storagemanager/StorageManagerIF.h" -#include "../../internalError/InternalErrorReporterIF.h" -#include "../../ipc/MessageQueueSenderIF.h" - -/** - * This class generates a ECSS PUS Telemetry packet within a given - * intermediate storage. - * As most packets are passed between tasks with the help of a storage - * anyway, it seems logical to create a Packet-In-Storage access class - * which saves the user almost all storage handling operation. - * Packets can both be newly created with the class and be "linked" to - * packets in a store with the help of a storeAddress. - * @ingroup tmtcpackets - */ -class TmPacketStored : public TmPacketBase { -public: - /** - * This is a default constructor which does not set the data pointer. - * However, it does try to set the packet store. - */ - TmPacketStored( store_address_t setAddress ); - /** - * With this constructor, new space is allocated in the packet store and - * a new PUS Telemetry Packet is created there. - * Packet Application Data passed in data is copied into the packet. - * The Application data is passed in two parts, first a header, then a - * data field. This allows building a Telemetry Packet from two separate - * data sources. - * @param apid Sets the packet's APID field. - * @param service Sets the packet's Service ID field. - * This specifies the source service. - * @param subservice Sets the packet's Service Subtype field. - * This specifies the source sub-service. - * @param packet_counter Sets the Packet counter field of this packet - * @param data The payload data to be copied to the - * Application Data Field - * @param size The amount of data to be copied. - * @param headerData The header Data of the Application field, - * will be copied in front of data - * @param headerSize The size of the headerDataF - */ - TmPacketStored( uint16_t apid, uint8_t service, uint8_t subservice, - uint8_t packet_counter = 0, const uint8_t* data = nullptr, - uint32_t size = 0, const uint8_t* headerData = nullptr, - uint32_t headerSize = 0); - /** - * Another ctor to directly pass structured content and header data to the - * packet to avoid additional buffers. - */ - TmPacketStored( uint16_t apid, uint8_t service, uint8_t subservice, - uint8_t packet_counter, SerializeIF* content, - SerializeIF* header = nullptr); - /** - * This is a getter for the current store address of the packet. - * @return The current store address. The (raw) value is - * @c StorageManagerIF::INVALID_ADDRESS if - * the packet is not linked. - */ - store_address_t getStoreAddress(); - /** - * With this call, the packet is deleted. - * It removes itself from the store and sets its data pointer to NULL. - */ - void deletePacket(); - /** - * With this call, a packet can be linked to another store. This is useful - * if the packet is a class member and used for more than one packet. - * @param setAddress The new packet id to link to. - */ - void setStoreAddress( store_address_t setAddress ); - - ReturnValue_t sendPacket( MessageQueueId_t destination, - MessageQueueId_t sentFrom, bool doErrorReporting = true ); -private: - /** - * This is a pointer to the store all instances of the class use. - * If the store is not yet set (i.e. @c store is NULL), every constructor - * call tries to set it and throws an error message in case of failures. - * The default store is objects::TM_STORE. - */ - static StorageManagerIF* store; - - static InternalErrorReporterIF *internalErrorReporter; - - /** - * The address where the packet data of the object instance is stored. - */ - store_address_t storeAddress; - /** - * A helper method to check if a store is assigned to the class. - * If not, the method tries to retrieve the store from the global - * ObjectManager. - * @return @li @c true if the store is linked or could be created. - * @li @c false otherwise. - */ - bool checkAndSetStore(); - - void checkAndReportLostTm(); -}; - - -#endif /* FSFW_TMTCPACKET_PUS_TMPACKETSTORED_H_ */ diff --git a/unittest/CMakeLists.txt b/unittest/CMakeLists.txt deleted file mode 100644 index 24f8ef6f..00000000 --- a/unittest/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -add_subdirectory(internal) - -if(LINK_CATCH2) - add_subdirectory(tests) -endif() \ No newline at end of file diff --git a/unittest/README.md b/unittest/README.md deleted file mode 100644 index d6a4bb85..00000000 --- a/unittest/README.md +++ /dev/null @@ -1,19 +0,0 @@ -## FSFW Testing - -This folder contains testing and unit testing components. - -### Instructions - -The easiest way to run the unittest contained in this folder is to follow -the steps in the [test repository](https://egit.irs.uni-stuttgart.de/fsfw/fsfw_tests). -This is recommended even if the goal is to set up a custom test repository to have -a starting point. - -To set up a custom test repository or project, following steps can be performed: - -1. Copy the user folder content into the project root. -2. Clone [Catch2](https://github.com/catchorg/Catch2) in the project root. -3. Use the `CMakeLists.txt` as a starting point to add tests and build the test - executable. - - diff --git a/unittest/internal/InternalUnitTester.cpp b/unittest/internal/InternalUnitTester.cpp deleted file mode 100644 index a9394ad3..00000000 --- a/unittest/internal/InternalUnitTester.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include "InternalUnitTester.h" -#include "UnittDefinitions.h" - -#include "osal/IntTestMq.h" -#include "osal/IntTestSemaphore.h" -#include "osal/IntTestMutex.h" -#include "serialize/IntTestSerialization.h" -#include "globalfunctions/TestArrayPrinter.h" - -#include - -InternalUnitTester::InternalUnitTester() {} - -InternalUnitTester::~InternalUnitTester() {} - -ReturnValue_t InternalUnitTester::performTests(struct InternalUnitTester::TestConfig& testConfig) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::info << "Running internal unit tests.." << std::endl; -#else - sif::printInfo("Running internal unit tests..\n"); -#endif - - testserialize::test_serialization(); - testmq::testMq(); - testsemaph::testBinSemaph(); - testsemaph::testCountingSemaph(); - testmutex::testMutex(); - if(testConfig.testArrayPrinter) { - arrayprinter::testArrayPrinter(); - } - -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::info << "Internal unit tests finished." << std::endl; -#else - sif::printInfo("Internal unit tests finished.\n"); -#endif - return RETURN_OK; -} - - - diff --git a/unittest/internal/globalfunctions/CMakeLists.txt b/unittest/internal/globalfunctions/CMakeLists.txt deleted file mode 100644 index 4ea49bf7..00000000 --- a/unittest/internal/globalfunctions/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -target_sources(${TARGET_NAME} PRIVATE - TestArrayPrinter.cpp -) diff --git a/unittest/internal/internal.mk b/unittest/internal/internal.mk deleted file mode 100644 index 1d4c9c99..00000000 --- a/unittest/internal/internal.mk +++ /dev/null @@ -1,4 +0,0 @@ -CXXSRC += $(wildcard $(CURRENTPATH)/osal/*.cpp) -CXXSRC += $(wildcard $(CURRENTPATH)/serialize/*.cpp) -CXXSRC += $(wildcard $(CURRENTPATH)/globalfunctions/*.cpp) -CXXSRC += $(wildcard $(CURRENTPATH)/*.cpp) \ No newline at end of file diff --git a/unittest/internal/osal/CMakeLists.txt b/unittest/internal/osal/CMakeLists.txt deleted file mode 100644 index c6f1eb95..00000000 --- a/unittest/internal/osal/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -target_sources(${TARGET_NAME} PRIVATE - IntTestMq.cpp - IntTestMutex.cpp - IntTestSemaphore.cpp -) diff --git a/unittest/internal/serialize/CMakeLists.txt b/unittest/internal/serialize/CMakeLists.txt deleted file mode 100644 index e8dc5717..00000000 --- a/unittest/internal/serialize/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -target_sources(${TARGET_NAME} PRIVATE - IntTestSerialization.cpp -) diff --git a/unittest/lcov.sh b/unittest/lcov.sh deleted file mode 100644 index 4db16e5f..00000000 --- a/unittest/lcov.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -lcov --capture --directory . --output-file coverage.info -genhtml coverage.info --output-directory _coverage diff --git a/unittest/tests/CMakeLists.txt b/unittest/tests/CMakeLists.txt deleted file mode 100644 index 180e1a51..00000000 --- a/unittest/tests/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -add_subdirectory(action) -add_subdirectory(container) -add_subdirectory(osal) -add_subdirectory(serialize) -add_subdirectory(datapoollocal) -add_subdirectory(storagemanager) - diff --git a/unittest/tests/action/CMakeLists.txt b/unittest/tests/action/CMakeLists.txt deleted file mode 100644 index 0339000f..00000000 --- a/unittest/tests/action/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -target_sources(${TARGET_NAME} PRIVATE - TestActionHelper.cpp -) diff --git a/unittest/tests/globalfunctions/CMakeLists.txt b/unittest/tests/globalfunctions/CMakeLists.txt deleted file mode 100644 index 4ea49bf7..00000000 --- a/unittest/tests/globalfunctions/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -target_sources(${TARGET_NAME} PRIVATE - TestArrayPrinter.cpp -) diff --git a/unittest/tests/serialize/TestSerialization.cpp b/unittest/tests/serialize/TestSerialization.cpp deleted file mode 100644 index 3de581ec..00000000 --- a/unittest/tests/serialize/TestSerialization.cpp +++ /dev/null @@ -1,131 +0,0 @@ -#include - -#include -#include -#include - -#include - -static bool test_value_bool = true; -static uint8_t tv_uint8 {5}; -static uint16_t tv_uint16 {283}; -static uint32_t tv_uint32 {929221}; -static uint64_t tv_uint64 {2929329429}; - -static int8_t tv_int8 {-16}; -static int16_t tv_int16 {-829}; -static int32_t tv_int32 {-2312}; - -static float tv_float {8.2149214}; -static float tv_sfloat = {-922.2321321}; -static double tv_double {9.2132142141e8}; -static double tv_sdouble {-2.2421e19}; - -static std::array test_array; - -TEST_CASE( "Serialization size tests", "[TestSerialization]") { - //REQUIRE(unitTestClass.test_autoserialization() == 0); - REQUIRE(SerializeAdapter::getSerializedSize(&test_value_bool) == - sizeof(test_value_bool)); - REQUIRE(SerializeAdapter::getSerializedSize(&tv_uint8) == - sizeof(tv_uint8)); - REQUIRE(SerializeAdapter::getSerializedSize(&tv_uint16) == - sizeof(tv_uint16)); - REQUIRE(SerializeAdapter::getSerializedSize(&tv_uint32 ) == - sizeof(tv_uint32)); - REQUIRE(SerializeAdapter::getSerializedSize(&tv_uint64) == - sizeof(tv_uint64)); - REQUIRE(SerializeAdapter::getSerializedSize(&tv_int8) == - sizeof(tv_int8)); - REQUIRE(SerializeAdapter::getSerializedSize(&tv_int16) == - sizeof(tv_int16)); - REQUIRE(SerializeAdapter::getSerializedSize(&tv_int32) == - sizeof(tv_int32)); - REQUIRE(SerializeAdapter::getSerializedSize(&tv_float) == - sizeof(tv_float)); - REQUIRE(SerializeAdapter::getSerializedSize(&tv_sfloat) == - sizeof(tv_sfloat )); - REQUIRE(SerializeAdapter::getSerializedSize(&tv_double) == - sizeof(tv_double)); - REQUIRE(SerializeAdapter::getSerializedSize(&tv_sdouble) == - sizeof(tv_sdouble)); -} - - -TEST_CASE("Auto Serialize Adapter testing", "[single-file]") { - size_t serialized_size = 0; - uint8_t * p_array = test_array.data(); - - SECTION("Serializing...") { - SerializeAdapter::serialize(&test_value_bool, &p_array, - &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); - SerializeAdapter::serialize(&tv_uint8, &p_array, - &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); - SerializeAdapter::serialize(&tv_uint16, &p_array, - &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); - SerializeAdapter::serialize(&tv_uint32, &p_array, - &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); - SerializeAdapter::serialize(&tv_int8, &p_array, - &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); - SerializeAdapter::serialize(&tv_int16, &p_array, - &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); - SerializeAdapter::serialize(&tv_int32, &p_array, - &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); - SerializeAdapter::serialize(&tv_uint64, &p_array, - &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); - SerializeAdapter::serialize(&tv_float, &p_array, - &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); - SerializeAdapter::serialize(&tv_double, &p_array, - &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); - SerializeAdapter::serialize(&tv_sfloat, &p_array, - &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); - SerializeAdapter::serialize(&tv_sdouble, &p_array, - &serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE); - REQUIRE (serialized_size == 47); - } - - SECTION("Deserializing") { - p_array = test_array.data(); - size_t remaining_size = serialized_size; - SerializeAdapter::deSerialize(&test_value_bool, - const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); - SerializeAdapter::deSerialize(&tv_uint8, - const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); - SerializeAdapter::deSerialize(&tv_uint16, - const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); - SerializeAdapter::deSerialize(&tv_uint32, - const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); - SerializeAdapter::deSerialize(&tv_int8, - const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); - SerializeAdapter::deSerialize(&tv_int16, - const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); - SerializeAdapter::deSerialize(&tv_int32, - const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); - SerializeAdapter::deSerialize(&tv_uint64, - const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); - SerializeAdapter::deSerialize(&tv_float, - const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); - SerializeAdapter::deSerialize(&tv_double, - const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); - SerializeAdapter::deSerialize(&tv_sfloat, - const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); - SerializeAdapter::deSerialize(&tv_sdouble, - const_cast(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE); - - REQUIRE(test_value_bool == true); - REQUIRE(tv_uint8 == 5); - REQUIRE(tv_uint16 == 283); - REQUIRE(tv_uint32 == 929221); - REQUIRE(tv_uint64 == 2929329429); - REQUIRE(tv_int8 == -16); - REQUIRE(tv_int16 == -829); - REQUIRE(tv_int32 == -2312); - - REQUIRE(tv_float == Catch::Approx(8.214921)); - REQUIRE(tv_double == Catch::Approx(9.2132142141e8)); - REQUIRE(tv_sfloat == Catch::Approx(-922.2321321)); - REQUIRE(tv_sdouble == Catch::Approx(-2.2421e19)); - } -} - - diff --git a/unittest/tests/storagemanager/CMakeLists.txt b/unittest/tests/storagemanager/CMakeLists.txt deleted file mode 100644 index ed7be7d5..00000000 --- a/unittest/tests/storagemanager/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -target_sources(${TARGET_NAME} PRIVATE - TestNewAccessor.cpp - TestPool.cpp -) diff --git a/unittest/tests/tests.mk b/unittest/tests/tests.mk deleted file mode 100644 index 47e634a2..00000000 --- a/unittest/tests/tests.mk +++ /dev/null @@ -1,8 +0,0 @@ -CXXSRC += $(wildcard $(CURRENTPATH)/container/*.cpp) -CXXSRC += $(wildcard $(CURRENTPATH)/action/*.cpp) -CXXSRC += $(wildcard $(CURRENTPATH)/serialize/*.cpp) -CXXSRC += $(wildcard $(CURRENTPATH)/storagemanager/*.cpp) - -# OSAL not included for now. - -INCLUDES += $(CURRENTPATH) \ No newline at end of file diff --git a/unittest/user/CMakeLists.txt b/unittest/user/CMakeLists.txt deleted file mode 100644 index 722cc424..00000000 --- a/unittest/user/CMakeLists.txt +++ /dev/null @@ -1,257 +0,0 @@ -################################################################################ -# CMake support for the Flight Software Framework Tests -# -# Developed in an effort to replace Make with a modern build system. -# -# Author: R. Mueller -################################################################################ - -################################################################################ -# Pre-Project preparation -################################################################################ -cmake_minimum_required(VERSION 3.13) - -# set(CMAKE_VERBOSE TRUE) - -set(CMAKE_SCRIPT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") - -option(TMTC_TEST "Build binary for manual or automatic TMTC tests" FALSE) -option(GENERATE_COVERAGE - "Specify whether coverage data is generated with GCOV" - TRUE -) - -if(TMTC_TEST) - set(LINK_CATCH2 FALSE) -else() - set(LINK_CATCH2 TRUE) -endif() - -# Tests can be built with the Host OSAL or with the Linux OSAL. -if(NOT OS_FSFW) - set(OS_FSFW host CACHE STRING "OS for the FSFW.") -endif() - -option(CUSTOM_UNITTEST_RUNNER - "Specify whether custom main or Catch2 main is used" TRUE -) - -# Perform steps like loading toolchain files where applicable. -#include(${CMAKE_SCRIPT_PATH}/PreProjectConfig.cmake) -#pre_project_config() - -# Project Name -project(fsfw_tests C CXX) - -################################################################################ -# Pre-Sources preparation -################################################################################ - -# Specify the C++ standard -set(CMAKE_CXX_STANDARD 11) -set(CMAKE_CXX_STANDARD_REQUIRED True) - -# Set names and variables -set(TARGET_NAME ${CMAKE_PROJECT_NAME}) -if(CUSTOM_UNITTEST_RUNNER) - set(CATCH2_TARGET Catch2) -else() - set(CATCH2_TARGET Catch2WithMain) -endif() -set(LIB_FSFW_NAME fsfw) - -# Set path names -set(FSFW_PATH fsfw) -set(CATCH2_PATH Catch2) -set(FSFW_TESTS_PATH fsfw/unittest) -set(TEST_SETUP_PATH unittest) -set(TMTC_TEST_PATH tests) - -# Analyse different OS and architecture/target options and -# determine BSP_PATH - -# FreeRTOS -if(${OS_FSFW} STREQUAL linux) - add_definitions(-DUNIX -DLINUX) - find_package(Threads REQUIRED) -# Hosted -else() - if(WIN32) - add_definitions(-DWIN32) - elseif(UNIX) - find_package(Threads REQUIRED) - add_definitions(-DUNIX -DLINUX) - endif() -endif() - -if(GENERATE_COVERAGE) - list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/cmake-modules) - if(CMAKE_COMPILER_IS_GNUCXX) - include(CodeCoverage) - # Add compile options on target base, we don't want coverage for Catch2 - # append_coverage_compiler_flags() - endif() -endif() - -set(FSFW_CONFIG_PATH testcfg) - -################################################################################ -# Executable and Sources -################################################################################ - -# Add executable -add_executable(${TARGET_NAME}) - -# Add subdirectories -add_subdirectory(${FSFW_PATH}) -add_subdirectory(${FSFW_CONFIG_PATH}) - -if(LINK_CATCH2) - add_subdirectory(${CATCH2_PATH}) - add_subdirectory(${FSFW_TESTS_PATH}) - add_subdirectory(${TEST_SETUP_PATH}) -else() - add_subdirectory(${TMTC_TEST_PATH}) -endif() - - -################################################################################ -# Post-Sources preparation -################################################################################ - -# Add libraries for all sources. -target_link_libraries(${TARGET_NAME} PRIVATE - ${LIB_FSFW_NAME} -) - -if(LINK_CATCH2) - target_link_libraries(${TARGET_NAME} PRIVATE - ${CATCH2_TARGET} - ) -endif() - -if(GENERATE_COVERAGE) - if(CMAKE_COMPILER_IS_GNUCXX) - set(CODE_COVERAGE_VERBOSE TRUE) - include(CodeCoverage) - - # 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(${TARGET_NAME} PRIVATE - "${COVERAGE_COMPILER_FLAGS}" - ) - target_compile_options(${LIB_FSFW_NAME} PRIVATE - "${COVERAGE_COMPILER_FLAGS}" - ) - - # Exclude internal unittest from coverage for now. - if(WIN32) - set(GCOVR_ADDITIONAL_ARGS - "--exclude-throw-branches" - "--exclude-unreachable-branches" - ) - set(COVERAGE_EXCLUDES - "/c/msys64/mingw64/*" "Catch2" - "${CMAKE_CURRENT_SOURCE_DIR}/fsfw/unittest/internal" - ) - elseif(UNIX) - set(COVERAGE_EXCLUDES - "/usr/include/*" "/usr/bin/*" "Catch2/*" - "fsfw/unittest/internal/*" - ) - endif() - - target_link_options(${TARGET_NAME} PRIVATE - -fprofile-arcs - -ftest-coverage - ) - target_link_options(${LIB_FSFW_NAME} PRIVATE - -fprofile-arcs - -ftest-coverage - ) - - if(WIN32) - setup_target_for_coverage_gcovr_html( - NAME ${TARGET_NAME}_coverage - EXECUTABLE ${TARGET_NAME} - DEPENDENCIES ${TARGET_NAME} - ) - else() - setup_target_for_coverage_lcov( - NAME ${TARGET_NAME}_coverage - EXECUTABLE ${TARGET_NAME} - DEPENDENCIES ${TARGET_NAME} - ) - endif() - endif() -endif() - -# Add include paths for all sources. -target_include_directories(${TARGET_NAME} PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR} - ${FSFW_CONFIG_PATH} -) - -if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - set(WARNING_FLAGS - -Wall - -Wextra - -Wshadow=local - -Wimplicit-fallthrough=1 - -Wno-unused-parameter - -Wno-psabi - ) - - # Remove unused sections. - target_compile_options(${TARGET_NAME} PRIVATE - "-ffunction-sections" - "-fdata-sections" - ) - - # Removed unused sections. - target_link_options(${TARGET_NAME} PRIVATE - "-Wl,--gc-sections" - ) - -elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") - set(COMPILER_FLAGS "/permissive-") -endif() - -if(CMAKE_VERBOSE) - message(STATUS "Warning flags: ${WARNING_FLAGS}") -endif() - - -# Compile options for all sources. -target_compile_options(${TARGET_NAME} PRIVATE - $<$:${WARNING_FLAGS} ${COMPILER_FLAGS}> - $<$:${WARNING_FLAGS} ${COMPILER_FLAGS}> - ${ABI_FLAGS} -) - -if(NOT CMAKE_SIZE) - set(CMAKE_SIZE size) - if(WIN32) - set(FILE_SUFFIX ".exe") - endif() -endif() - -add_custom_command(TARGET ${TARGET_NAME} - POST_BUILD - COMMAND echo "Build directory: ${CMAKE_BINARY_DIR}" - COMMAND echo "Target OSAL: ${OS_FSFW}" - COMMAND echo "Target Build Type: ${CMAKE_BUILD_TYPE}" - COMMAND ${CMAKE_SIZE} ${TARGET_NAME}${FILE_SUFFIX} -) - -include (${CMAKE_SCRIPT_PATH}/BuildType.cmake) -set_build_type() - - - - - diff --git a/unittest/user/testcfg/CMakeLists.txt b/unittest/user/testcfg/CMakeLists.txt deleted file mode 100644 index dbf0256f..00000000 --- a/unittest/user/testcfg/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -target_sources(${TARGET_NAME} - PRIVATE - ipc/MissionMessageTypes.cpp - pollingsequence/PollingSequenceFactory.cpp -) - -# Add include paths for the executable -target_include_directories(${TARGET_NAME} - PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR} -) diff --git a/unittest/user/testcfg/Makefile-FSFW-Tests b/unittest/user/testcfg/Makefile-FSFW-Tests deleted file mode 100644 index 550fd1de..00000000 --- a/unittest/user/testcfg/Makefile-FSFW-Tests +++ /dev/null @@ -1,416 +0,0 @@ -#------------------------------------------------------------------------------- -# Makefile for FSFW Test -#------------------------------------------------------------------------------- -# User-modifiable options -#------------------------------------------------------------------------------- -# Fundamentals on the build process of C/C++ Software: -# https://www3.ntu.edu.sg/home/ehchua/programming/cpp/gcc_make.html - -# Make documentation: https://www.gnu.org/software/make/manual/make.pdf -# Online: https://www.gnu.org/software/make/manual/make.html -# General rules: http://make.mad-scientist.net/papers/rules-of-makefiles/#rule3 -SHELL = /bin/sh - -# Chip & board used for compilation -# (can be overriden by adding CHIP=chip and BOARD=board to the command-line) -# Unit Test can only be run on host machine for now (Linux) -FRAMEWORK_PATH = fsfw -TEST_FILE_ROOT = $(FRAMEWORK_PATH)/unittest -BOARD = unittest -LINUX = 1 -OS_FSFW = linux -CUSTOM_DEFINES += -D$(OS_FSFW) - -# Copied from stackoverflow, can be used to differentiate between Windows -# and Linux -ifeq ($(OS),Windows_NT) - CUSTOM_DEFINES += -DWIN32 - ifeq ($(PROCESSOR_ARCHITEW6432),AMD64) - CUSTOM_DEFINES += -DAMD64 - else - ifeq ($(PROCESSOR_ARCHITECTURE),AMD64) - CUSTOM_DEFINES += -DAMD64 - endif - ifeq ($(PROCESSOR_ARCHITECTURE),x86) - CUSTOM_DEFINES += -DIA32 - endif - endif -else - UNAME_S := $(shell uname -s) - ifeq ($(UNAME_S),Linux) - DETECTED_OS = LINUX - CUSTOM_DEFINES += -DLINUX - endif - ifeq ($(UNAME_S),Darwin) - CUSTOM_DEFINES += -DOSX - endif - UNAME_P := $(shell uname -p) - ifeq ($(UNAME_P),x86_64) - CUSTOM_DEFINES += -DAMD64 - endif - ifneq ($(filter %86,$(UNAME_P)),) - CUSTOM_DEFINES += -DIA32 - endif - ifneq ($(filter arm%,$(UNAME_P)),) - CUSTOM_DEFINES += -DARM - endif -endif - -UNIT_TEST = 1 -# General folder paths -CONFIG_PATH = testcfg -# Core copy has to be copied as well. -CORE_PATH = core -UNIT_TEST_PATH = $(TEST_FILE_ROOT)/tests - -# Output file basename -BASENAME = fsfw -BINARY_NAME := $(BASENAME)-$(BOARD) -# Output files will be put in this directory inside -OUTPUT_FOLDER = $(OS) - -# Optimization level. Optimized for debugging. -OPTIMIZATION = -O0 - -# Default debug output. Optimized for debugging. -DEBUG_LEVEL = -g3 - -ifdef GCOV -CUSTOM_DEFINES += -DGCOV -endif - - -# Output directories -BUILDPATH = _bin -DEPENDPATH = _dep -OBJECTPATH = _obj - -ifeq ($(MAKECMDGOALS),mission) -BUILD_FOLDER = mission -else -BUILD_FOLDER = devel -endif - -DEPENDDIR = $(DEPENDPATH)/$(OUTPUT_FOLDER)/$(BUILD_FOLDER) -OBJDIR = $(OBJECTPATH)/$(OUTPUT_FOLDER)/$(BUILD_FOLDER) -BINDIR = $(BUILDPATH) - -CLEANDEP = $(DEPENDPATH)/$(OUTPUT_FOLDER) -CLEANOBJ = $(OBJECTPATH)/$(OUTPUT_FOLDER) -CLEANBIN = $(BUILDPATH) -#------------------------------------------------------------------------------- -# Tools and Includes -#------------------------------------------------------------------------------- - -# Tool suffix when cross-compiling -CROSS_COMPILE = - -# C Compiler -CC = $(CROSS_COMPILE)gcc - -# C++ compiler -CXX = $(CROSS_COMPILE)g++ - -# Additional Tools -SIZE = $(CROSS_COMPILE)size -STRIP = $(CROSS_COMPILE)strip -CP = $(CROSS_COMPILE)objcopy - -HEXCOPY = $(CP) -O ihex -BINCOPY = $(CP) -O binary -# files to be compiled, will be filled in by include makefiles -# := assignment is neccessary so we get all paths right -# https://www.gnu.org/software/make/manual/html_node/Flavors.html -CSRC := -CXXSRC := -ASRC := -INCLUDES := - -# Directories where $(directoryname).mk files should be included from -SUBDIRS := $(FRAMEWORK_PATH) $(TEST_PATH) $(UNIT_TEST_PATH) $(CONFIG_PATH) \ - $(CORE_PATH) - - -I_INCLUDES += $(addprefix -I, $(INCLUDES)) - -# This is a hack from http://make.mad-scientist.net/the-eval-function/ -# -# The problem is, that included makefiles should be aware of their relative path -# but not need to guess or hardcode it. So we set $(CURRENTPATH) for them. If -# we do this globally and the included makefiles want to include other makefiles as -# well, they would overwrite $(CURRENTPATH), screwing the include after them. -# -# By using a for-loop with an eval'd macro, we can generate the code to include all -# sub-makefiles (with the correct $(CURRENTPATH) set) before actually evaluating -# (and by this possibly changing $(CURRENTPATH)) them. -# -# This works recursively, if an included makefile wants to include, it can safely set -# $(SUBDIRS) (which has already been evaluated here) and do -# "$(foreach S,$(SUBDIRS),$(eval $(INCLUDE_FILE)))" -# $(SUBDIRS) must be relative to the project root, so to include subdir foo, set -# $(SUBDIRS) = $(CURRENTPATH)/foo. -define INCLUDE_FILE -CURRENTPATH := $S -include $(S)/$(notdir $S).mk -endef -$(foreach S,$(SUBDIRS),$(eval $(INCLUDE_FILE))) - -INCLUDES += $(TEST_FILE_ROOT) -INCLUDES += $(TEST_FILE_ROOT)/catch2/ - -#------------------------------------------------------------------------------- -# Source Files -#------------------------------------------------------------------------------- - -# All source files which are not includes by the .mk files are added here -# Please ensure that no files are included by both .mk file and here ! - -# if a target is not listed in the current directory, -# make searches in the directories specified with VPATH - -# All C Sources included by .mk files are assigned here -# Add the objects to sources so dependency handling works -C_OBJECTS += $(CSRC:.c=.o) - -# Objects built from Assembly source files -ASM_OBJECTS = $(ASRC:.S=.o) - -# Objects built from C++ source files -CXX_OBJECTS += $(CXXSRC:.cpp=.o) - -#------------------------------------------------------------------------------- -# Build Configuration + Output -#------------------------------------------------------------------------------- - -TARGET = Debug build. -DEBUG_MESSAGE = Off -OPTIMIZATION_MESSAGE = Off - -# Define Messages -MSG_INFO = Software: Hosted unittest \(Catch2\) for the FSFW. -MSG_OPTIMIZATION = Optimization: $(OPTIMIZATION), $(OPTIMIZATION_MESSAGE) -MSG_TARGET = Target Build: $(TARGET) -MSG_DEBUG = Debug level: $(DEBUG_LEVEL), FSFW Debugging: $(DEBUG_MESSAGE) - -MSG_LINKING = Linking: -MSG_COMPILING = Compiling: -MSG_ASSEMBLING = Assembling: -MSG_DEPENDENCY = Collecting dependencies for: -MSG_BINARY = Generate binary: - -# See https://stackoverflow.com/questions/6687630/how-to-remove-unused-c-c-symbols-with-gcc-and-ld -# Used to throw away unused code. Reduces code size significantly ! -# -Wl,--gc-sections: needs to be passed to the linker to throw aways unused code -ifdef KEEP_UNUSED_CODE -PROTOTYPE_OPTIMIZATION = -UNUSED_CODE_REMOVAL = -else -PROTOTYPE_OPTIMIZATION = -ffunction-sections -fdata-sections -UNUSED_CODE_REMOVAL = -Wl,--gc-sections -# Link time optimization -# See https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html for reference -# Link time is larger and size of object files can not be retrieved -# but resulting binary is smaller. Could be used in mission/deployment build -# Requires -ffunction-section in linker call -LINK_TIME_OPTIMIZATION = -flto -OPTIMIZATION += $(PROTOTYPE_OPTIMIZATION) -endif - -# Dependency Flags -# These flags tell the compiler to build dependencies -# See: https://www.gnu.org/software/make/manual/html_node/Automatic-Prerequisites.html -# Using following guide: http://make.mad-scientist.net/papers/advanced-auto-dependency-generation/#combine -DEPFLAGS = -MT $@ -MMD -MP -MF $(DEPENDDIR)/$*.d - -# Flags for the compiler call -# - std: Which C++ version to use. Common versions: c++11, c++14 and c++17 -# - Wall: enable all warnings -# - Wextra: enable extra warnings -# - g: defines debug level -# - fmessage-length: to control the formatting algorithm for diagnostic messages; -# =0 means no line-wrapping is done; each error message appears on a single line -# - fno-exceptions: stops generating extra code needed to propagate exceptions, -# which can produce significant data size overhead -CUSTOM_DEFINES += -DUNIT_TEST -WARNING_FLAGS = -Wall -Wshadow=local -Wextra -Wimplicit-fallthrough=1 \ - -Wno-unused-parameter - -CXXDEFINES := $(CUSTOM_DEFINES) -CFLAGS += -CXXFLAGS += -I. $(DEBUG_LEVEL) $(WARNING_FLAGS) $(DEPFLAGS) -fmessage-length=0 $(OPTIMIZATION)\ - $(I_INCLUDES) $(CXXDEFINES) -CPPFLAGS += -std=c++11 - -# Flags for the linker call -# LINK_INCLUDES specify the path to used libraries and the linker script -# LINK_LIBRARIES: Link real time support -LDFLAGS := $(DEBUG_LEVEL) $(UNUSED_CODE_REMOVAL) $(OPTIMIZATION) -pthread -LINK_INCLUDES := -LINK_LIBRARIES := - -ifdef LINUX -LINK_LIBRARIES += -lrt -endif - -ifeq ($(OS),Windows_NT) -LINK_LIBRARIES += -lwsock32 -lws2_32 -LDFLASGS += -fuse-ld=lld -endif - -# Gnu Coverage Tools Flags -ifdef GCOV -GCOV_CXXFLAGS = -fprofile-arcs -ftest-coverage --coverage -fno-inline \ - -fno-inline-small-functions -fno-default-inline -CXXFLAGS += $(GCOV_CXXFLAGS) -GCOV_LINKER_LIBS = -lgcov -fprofile-arcs -ftest-coverage -LINK_LIBRARIES += $(GCOV_LINKER_LIBS) -endif - -# $(info $${CXXFLAGS} is [${CXXFLAGS}]) - -#------------------------------------------------------------------------------- -# Rules -#------------------------------------------------------------------------------- -# the call function assigns parameters to temporary variables -# https://www.gnu.org/software/make/manual/make.html#Call-Function -# $(1) = Memory names -# Rules are called for each memory type -# Two Expansion Symbols $$ are to escape the dollar sign for eval. -# See: http://make.mad-scientist.net/the-eval-function/ - -default: all - -# Cleans all files -hardclean: - -rm -rf $(BUILDPATH) - -rm -rf $(OBJECTPATH) - -rm -rf $(DEPENDPATH) - -# Only clean files for current build -clean: - -rm -rf $(CLEANOBJ) - -rm -rf $(CLEANBIN) - -rm -rf $(CLEANDEP) - -# Only clean binaries. Useful for changing the binary type when object files -# are already compiled so complete rebuild is not necessary -cleanbin: - -rm -rf $(CLEANBIN) - -# In this section, the binaries are built for all selected memories -# notestfw: all -all: executable - -# Build target configuration -release: OPTIMIZATION = -Os $(PROTOTYPE_OPTIMIZATION) $(LINK_TIME_OPTIMIZATION) -release: LINK_TIME_OPTIMIZATION = -flto -release: TARGET = Mission build. -release: OPTIMIZATION_MESSAGE = On with Link Time Optimization - -debug: CXXDEFINES += -DDEBUG -debug: TARGET = Debug -debug: DEBUG_MESSAGE = On - -ifndef KEEP_UNUSED_CODE -debug release: OPTIMIZATION_MESSAGE += , no unused code removal -endif - -debug release notestfw: executable - -executable: $(BINDIR)/$(BINARY_NAME).elf - @echo - @echo $(MSG_INFO) - @echo $(MSG_TARGET) - @echo $(MSG_OPTIMIZATION) - @echo $(MSG_DEBUG) - -C_OBJECTS_PREFIXED = $(addprefix $(OBJDIR)/, $(C_OBJECTS)) -CXX_OBJECTS_PREFIXED = $(addprefix $(OBJDIR)/, $(CXX_OBJECTS)) -ASM_OBJECTS_PREFIXED = $(addprefix $(OBJDIR)/, $(ASM_OBJECTS)) -ALL_OBJECTS = $(ASM_OBJECTS_PREFIXED) $(C_OBJECTS_PREFIXED) \ - $(CXX_OBJECTS_PREFIXED) - -# Useful for debugging the Makefile -# Also see: https://www.oreilly.com/openbook/make3/book/ch12.pdf -# $(info $${ALL_OBJECTS} is [${ALL_OBJECTS}]) -# $(info $${CXXSRC} is [${CXXSRC}]) - -# Automatic variables are used here extensively. Some of them -# are escaped($$) to suppress immediate evaluation. The most important ones are: -# $@: Name of Target (left side of rule) -# $<: Name of the first prerequisite (right side of rule) -# @^: List of all prerequisite, omitting duplicates -# @D: Directory and file-within-directory part of $@ - -# Generates binary and displays all build properties -# -p with mkdir ignores error and creates directory when needed. - -# SHOW_DETAILS = 1 - - -# Link with required libraries: HAL (Hardware Abstraction Layer) and -# HCC (File System Library) -$(BINDIR)/$(BINARY_NAME).elf: $(ALL_OBJECTS) - @echo - @echo $(MSG_LINKING) Target $@ - @mkdir -p $(@D) -ifdef SHOW_DETAILS - $(CXX) $(LDFLAGS) $(LINK_INCLUDES) -o $@ $^ $(LINK_LIBRARIES) -else - @$(CXX) $(LDFLAGS) $(LINK_INCLUDES) -o $@ $^ $(LINK_LIBRARIES) -endif -ifeq ($(BUILD_FOLDER), mission) -# With Link Time Optimization, section size is not available - $(SIZE) $@ -else - $(SIZE) $^ $@ -endif - -$(BINDIR)/$(BINARY_NAME).hex: $(BINDIR)/$(BINARY_NAME).elf - @echo - @echo $(MSG_BINARY) - @mkdir -p $(@D) - $(HEXCOPY) $< $@ - -# Build new objects for changed dependencies. -$(OBJDIR)/%.o: %.cpp -$(OBJDIR)/%.o: %.cpp $(DEPENDDIR)/%.d | $(DEPENDDIR) - @echo - @echo $(MSG_COMPILING) $< - @mkdir -p $(@D) -ifdef SHOW_DETAILS - $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $< -else - @$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $< -endif - -$(OBJDIR)/%.o: %.c -$(OBJDIR)/%.o: %.c $(DEPENDDIR)/%.d | $(DEPENDDIR) - @echo - @echo $(MSG_COMPILING) $< - @mkdir -p $(@D) -ifdef SHOW_DETAILS - $(CC) $(CXXFLAGS) $(CFLAGS) -c -o $@ $< -else - @$(CC) $(CXXFLAGS) $(CFLAGS) -c -o $@ $< -endif - -#------------------------------------------------------------------------------- -# Dependency Handling -#------------------------------------------------------------------------------- - -# Dependency Handling according to following guide: -# http://make.mad-scientist.net/papers/advanced-auto-dependency-generation/ -$(DEPENDDIR): - @mkdir -p $(@D) -DEPENDENCY_RELATIVE = $(CSRC:.c=.d) $(CXXSRC:.cpp=.d) -# This is the list of all dependencies -DEPFILES = $(addprefix $(DEPENDDIR)/, $(DEPENDENCY_RELATIVE)) -# Create subdirectories for dependencies -$(DEPFILES): - @mkdir -p $(@D) -# Include all dependencies -include $(wildcard $(DEPFILES)) - -# .PHONY tells make that these targets aren't files -.PHONY: clean release debug all hardclean cleanbin diff --git a/unittest/user/testcfg/TestsConfig.h b/unittest/user/testcfg/TestsConfig.h deleted file mode 100644 index cd967fa7..00000000 --- a/unittest/user/testcfg/TestsConfig.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef FSFW_UNITTEST_CONFIG_TESTSCONFIG_H_ -#define FSFW_UNITTEST_CONFIG_TESTSCONFIG_H_ - - -#define CUSTOM_UNITTEST_RUNNER 0 - - -#endif /* FSFW_UNITTEST_CONFIG_TESTSCONFIG_H_ */ diff --git a/unittest/user/testcfg/cdatapool/dataPoolInit.cpp b/unittest/user/testcfg/cdatapool/dataPoolInit.cpp deleted file mode 100644 index ad2dc4ef..00000000 --- a/unittest/user/testcfg/cdatapool/dataPoolInit.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "dataPoolInit.h" - -void datapool::dataPoolInit(std::map * poolMap) { - -} diff --git a/unittest/user/testcfg/cdatapool/dataPoolInit.h b/unittest/user/testcfg/cdatapool/dataPoolInit.h deleted file mode 100644 index 9425d767..00000000 --- a/unittest/user/testcfg/cdatapool/dataPoolInit.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef HOSTED_CONFIG_CDATAPOOL_DATAPOOLINIT_H_ -#define HOSTED_CONFIG_CDATAPOOL_DATAPOOLINIT_H_ - -#include -#include -#include -#include - - -namespace datapool { - void dataPoolInit(std::map * poolMap); - - enum datapoolvariables { - NO_PARAMETER = 0, - }; -} -#endif /* CONFIG_CDATAPOOL_DATAPOOLINIT_H_ */ diff --git a/unittest/user/testcfg/pollingsequence/PollingSequenceFactory.cpp b/unittest/user/testcfg/pollingsequence/PollingSequenceFactory.cpp deleted file mode 100644 index b7f1fb3e..00000000 --- a/unittest/user/testcfg/pollingsequence/PollingSequenceFactory.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "PollingSequenceFactory.h" - -#include -#include -#include - -ReturnValue_t pst::pollingSequenceInitDefault( - FixedTimeslotTaskIF *thisSequence) { - /* Length of a communication cycle */ - uint32_t length = thisSequence->getPeriodMs(); - - /* Add polling sequence table here */ - - if (thisSequence->checkSequence() == HasReturnvaluesIF::RETURN_OK) { - return HasReturnvaluesIF::RETURN_OK; - } - else { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "pst::pollingSequenceInitDefault: Sequence invalid!" - << std::endl; -#endif - return HasReturnvaluesIF::RETURN_FAILED; - } -} - diff --git a/unittest/user/testcfg/testcfg.mk b/unittest/user/testcfg/testcfg.mk deleted file mode 100644 index fca2f732..00000000 --- a/unittest/user/testcfg/testcfg.mk +++ /dev/null @@ -1,8 +0,0 @@ -CXXSRC += $(wildcard $(CURRENTPATH)/cdatapool/*.cpp) -CXXSRC += $(wildcard $(CURRENTPATH)/ipc/*.cpp) -CXXSRC += $(wildcard $(CURRENTPATH)/objects/*.cpp) -CXXSRC += $(wildcard $(CURRENTPATH)/pollingsequence/*.cpp) -CXXSRC += $(wildcard $(CURRENTPATH)/events/*.cpp) -CXXSRC += $(wildcard $(CURRENTPATH)/*.cpp) - -INCLUDES += $(CURRENTPATH) diff --git a/unittest/user/unittest/CMakeLists.txt b/unittest/user/unittest/CMakeLists.txt deleted file mode 100644 index ad6d4787..00000000 --- a/unittest/user/unittest/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -add_subdirectory(core) diff --git a/unittest/user/unittest/core/CMakeLists.txt b/unittest/user/unittest/core/CMakeLists.txt deleted file mode 100644 index 0989926c..00000000 --- a/unittest/user/unittest/core/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -target_sources(${TARGET_NAME} PRIVATE - CatchDefinitions.cpp - CatchFactory.cpp - CatchRunner.cpp - CatchSetup.cpp - printChar.cpp -) - -if(CUSTOM_UNITTEST_RUNNER) - target_sources(${TARGET_NAME} PRIVATE - CatchRunner.cpp - ) -endif() \ No newline at end of file diff --git a/unittest/user/unittest/core/CatchFactory.h b/unittest/user/unittest/core/CatchFactory.h deleted file mode 100644 index f06e7ae5..00000000 --- a/unittest/user/unittest/core/CatchFactory.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef FSFW_CATCHFACTORY_H_ -#define FSFW_CATCHFACTORY_H_ - -#include - -namespace Factory { - /** - * @brief Creates all SystemObject elements which are persistent - * during execution. - */ - void produce(); - void setStaticFrameworkObjectIds(); - -} - -#endif /* FSFW_CATCHFACTORY_H_ */ diff --git a/unittest/user/unittest/core/core.mk b/unittest/user/unittest/core/core.mk deleted file mode 100644 index 3e5626d3..00000000 --- a/unittest/user/unittest/core/core.mk +++ /dev/null @@ -1,3 +0,0 @@ -CXXSRC += $(wildcard $(CURRENTPATH)/*.cpp) - -INCLUDES += $(CURRENTPATH) \ No newline at end of file diff --git a/unittest/user/unlockRealtime.sh b/unittest/user/unlockRealtime.sh deleted file mode 100644 index b28d5490..00000000 --- a/unittest/user/unlockRealtime.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/bash -# Run this script to unlock all permissions to run the linux binaries -# and create threads - -binaries=$(find $directory -type f -name "*.elf") - -echo Unlocking real time permissions for binaries and bash console... - -# Set up the soft realtime limit to maximum (99) -# Please note that the hard limit needs to be set to 99 too -# for this to work (check with ulimit -Hr). -# If that has not been done yet, add -# hard rtprio 99 -# to /etc/security/limits.conf -# It is also necessary and recommended to add -# soft rtprio 99 -# as well. This can also be done in the command line -# but would need to be done for each session. -ulimit -Sr 99 - -for binary in ${binaries}; do - sudo setcap 'cap_sys_nice=eip' ${binary} - result=$? - if [ ${result} = 0 ];then - echo ${binary} was unlocked - fi -done - -# sudo setcap 'cap_sys_nice=eip' /bin/bash -# result=$? -# if [ ${result} = 0 ];then -# echo /bin/bash was unlocked -# fi -