diff --git a/CHANGELOG.md b/CHANGELOG.md index cda8037c..335c0f7b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/544 - doSendRead Hook PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/545 +- Dockumentation for DHB + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/551 ### HAL additions @@ -43,6 +45,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/). could lead to compile errors that `#include "fsfw/FSFW.h"` was not found. - Fix for build regression in Catch2 v3.0.0-preview4 PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/548 +- Fix in unittest which failed on CI + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/552 +- Fix in helper script + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/553 ## API Changes diff --git a/CMakeLists.txt b/CMakeLists.txt index 19fedb64..79258db2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,8 +1,8 @@ cmake_minimum_required(VERSION 3.13) -set(FSFW_VERSION 3) +set(FSFW_VERSION 4) set(FSFW_SUBVERSION 0) -set(FSFW_REVISION 1) +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}) diff --git a/README.md b/README.md index a2261c99..89a10f4b 100644 --- a/README.md +++ b/README.md @@ -107,6 +107,42 @@ cmake --build . -- fsfw-tests_coverage -j The `coverage.py` script located in the `script` folder can also be used to do this conveniently. +## Building the documentations + +The FSFW documentation is built using the tools Sphinx, doxygen and breathe based on the +instructions provided in [this blogpost](https://devblogs.microsoft.com/cppblog/clear-functional-c-documentation-with-sphinx-breathe-doxygen-cmake/). If you +want to do this locally, set up the prerequisites first. This requires a ``python3`` +installation as well. Example here is for Ubuntu. + +```sh +sudo apt-get install doxygen graphviz +``` + +And the following Python packages + +```sh +python3 -m pip install sphinx breathe +``` + +You can set up a documentation build system using the following commands + +```sh +mkdir build-docs && cd build-docs +cmake -DFSFW_BUILD_DOCS=ON -DFSFW_OSAL=host .. +``` + +Then you can generate the documentation using + +```sh +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. + ## Formatting the sources The formatting is done by the `clang-format` tool. The configuration is contained within the diff --git a/docs/devicehandlers.rst b/docs/devicehandlers.rst index 80b9e7a3..0008edb3 100644 --- a/docs/devicehandlers.rst +++ b/docs/devicehandlers.rst @@ -14,7 +14,8 @@ requirements, which are fulfilled by implementing certain interfaces: communication bus, for example SpaceWire, UART or SPI: :cpp:class:`DeviceCommunicationIF` - The handler has housekeeping data which has to be exposed to the operator and/or other software components: :cpp:class:`HasLocalDataPoolIF` -- The handler has configurable parameters +- The handler has configurable parameters: :cpp:class:`ReceivesParameterMessagesIF` which + also implements :cpp:class:`HasParametersIF` - The handler has health states, for example to indicate a broken device: :cpp:class:`HasHealthIF` - The handler has modes. For example there are the core modes `MODE_ON`, `MODE_OFF` diff --git a/docs/getting_started.rst b/docs/getting_started.rst index 069e98cd..34547211 100644 --- a/docs/getting_started.rst +++ b/docs/getting_started.rst @@ -90,8 +90,21 @@ 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 +instructions provided in `this blogpost `_. If you +want to do this locally, set up the prerequisites first. This requires a ``python3`` +installation as well. Example here is for Ubuntu. + +.. code-block:: console + + sudo apt-get install doxygen graphviz + +And the following Python packages + +.. code-block:: console + + python3 -m pip install sphinx breathe + +You can set up a documentation build system using the following commands .. code-block:: bash @@ -110,6 +123,14 @@ 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. +Formatting the source +----------------------- + +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. + + .. _`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/hal/src/fsfw_hal/linux/uio/UioMapper.cpp b/hal/src/fsfw_hal/linux/uio/UioMapper.cpp index 33c1b0f2..43ca2727 100644 --- a/hal/src/fsfw_hal/linux/uio/UioMapper.cpp +++ b/hal/src/fsfw_hal/linux/uio/UioMapper.cpp @@ -22,7 +22,7 @@ ReturnValue_t UioMapper::getMappedAdress(uint32_t** address, Permissions permiss int fd = open(uioFile.c_str(), O_RDWR); if (fd < 1) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "PtmeAxiConfig::initialize: Invalid UIO device file" << std::endl; + sif::error << "PtmeAxiConfig::initialize: Invalid UIO device file" << std::endl; #endif return HasReturnvaluesIF::RETURN_FAILED; } @@ -36,8 +36,8 @@ ReturnValue_t UioMapper::getMappedAdress(uint32_t** address, Permissions permiss if (*address == MAP_FAILED) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "UioMapper::getMappedAdress: Failed to map physical address of uio device " - << uioFile.c_str() << " and map" << static_cast(mapNum) << std::endl; + sif::error << "UioMapper::getMappedAdress: Failed to map physical address of uio device " + << uioFile.c_str() << " and map" << static_cast(mapNum) << std::endl; #endif return HasReturnvaluesIF::RETURN_FAILED; } @@ -52,7 +52,7 @@ ReturnValue_t UioMapper::getMapSize(size_t* size) { fp = fopen(namestream.str().c_str(), "r"); if (fp == nullptr) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "UioMapper::getMapSize: Failed to open file " << namestream.str() << std::endl; + sif::error << "UioMapper::getMapSize: Failed to open file " << namestream.str() << std::endl; #endif return HasReturnvaluesIF::RETURN_FAILED; } @@ -60,11 +60,12 @@ ReturnValue_t UioMapper::getMapSize(size_t* size) { int items = fscanf(fp, "%s", hexstring); if (items != 1) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "UioMapper::getMapSize: Failed with error code " << errno - << " to read size " - "string from file " - << namestream.str() << std::endl; + sif::error << "UioMapper::getMapSize: Failed with error code " << errno + << " to read size " + "string from file " + << namestream.str() << std::endl; #endif + fclose(fp); return HasReturnvaluesIF::RETURN_FAILED; } uint32_t sizeTmp = 0; @@ -74,9 +75,10 @@ ReturnValue_t UioMapper::getMapSize(size_t* size) { } if (items != 1) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "UioMapper::getMapSize: Failed with error code " << errno << "to convert " - << "size of map" << mapNum << " to integer" << std::endl; + sif::error << "UioMapper::getMapSize: Failed with error code " << errno << "to convert " + << "size of map" << mapNum << " to integer" << std::endl; #endif + fclose(fp); return HasReturnvaluesIF::RETURN_FAILED; } fclose(fp); diff --git a/scripts/helper.py b/scripts/helper.py index 4e8a62b4..68693c40 100755 --- a/scripts/helper.py +++ b/scripts/helper.py @@ -143,7 +143,10 @@ def handle_tests_type(args, build_dir_list: list): if which("valgrind") is None: print("Please install valgrind first") sys.exit(1) - os.chdir(UNITTEST_FOLDER_NAME) + if os.path.split(os.getcwd())[1] != UNITTEST_FOLDER_NAME: + # If we are in a different directory we try to switch into it but + # this might fail + os.chdir(UNITTEST_FOLDER_NAME) os.system("valgrind --leak-check=full ./fsfw-tests") os.chdir("..") diff --git a/src/fsfw/globalfunctions/CRC.cpp b/src/fsfw/globalfunctions/CRC.cpp index 033920d0..6b8140c5 100644 --- a/src/fsfw/globalfunctions/CRC.cpp +++ b/src/fsfw/globalfunctions/CRC.cpp @@ -117,7 +117,7 @@ uint16_t CRC::crc16ccitt(uint8_t const input[], uint32_t length, uint16_t starti // { // if (xor_out[i] == true) // crc_value = crc_value + pow(2,(15 -i)); // reverse CrC result before - // Final XOR + //Final XOR // } // // crc_value = 0;// for debug mode diff --git a/src/fsfw/osal/linux/PeriodicPosixTask.h b/src/fsfw/osal/linux/PeriodicPosixTask.h index 1c3a52c7..3c9a3a0d 100644 --- a/src/fsfw/osal/linux/PeriodicPosixTask.h +++ b/src/fsfw/osal/linux/PeriodicPosixTask.h @@ -65,10 +65,9 @@ class PeriodicPosixTask : public PosixThread, public PeriodicTaskIF { /** * @brief The function containing the actual functionality of the task. * @details The method sets and starts - * the task's period, then enters a loop that is repeated indefinitely. Within - * the loop, all performOperation methods of the added objects are called. Afterwards the task - * will be blocked until the next period. On missing the deadline, the deadlineMissedFunction is - * executed. + * the task's period, then enters a loop that is repeated indefinitely. Within the + * loop, all performOperation methods of the added objects are called. Afterwards the task will be + * blocked until the next period. On missing the deadline, the deadlineMissedFunction is executed. */ virtual void taskFunctionality(void); /** diff --git a/src/fsfw/osal/rtems/PeriodicTask.h b/src/fsfw/osal/rtems/PeriodicTask.h index 119329f2..ff8617fc 100644 --- a/src/fsfw/osal/rtems/PeriodicTask.h +++ b/src/fsfw/osal/rtems/PeriodicTask.h @@ -13,8 +13,8 @@ class ExecutableObjectIF; * @brief This class represents a specialized task for periodic activities of multiple objects. * * @details MultiObjectTask is an extension to ObjectTask in the way that it is able to execute - * multiple objects that implement the ExecutableObjectIF interface. The - * objects must be added prior to starting the task. + * multiple objects that implement the ExecutableObjectIF interface. The objects + * must be added prior to starting the task. * @author baetz * @ingroup task_handling */ diff --git a/src/fsfw/rmap/RMAP.h b/src/fsfw/rmap/RMAP.h index d274fb15..42ee1ac5 100644 --- a/src/fsfw/rmap/RMAP.h +++ b/src/fsfw/rmap/RMAP.h @@ -169,8 +169,8 @@ class RMAP : public HasReturnvaluesIF { * @param buffer the data to write * @param length length of data * @return - * - @c COMMAND_NULLPOINTER datalen was != 0 but data was == - * NULL in write command + * - @c COMMAND_NULLPOINTER datalen was != 0 but data was == NULL in + * write command * - return codes of RMAPChannelIF::sendCommand() */ static ReturnValue_t sendWriteCommand(RMAPCookie *cookie, const uint8_t *buffer, size_t length); @@ -205,8 +205,8 @@ class RMAP : public HasReturnvaluesIF { * @param cookie to cookie to read from * @param expLength the expected maximum length of the reply * @return - * - @c COMMAND_NULLPOINTER datalen was != 0 but data was == - * NULL in write command, or nullpointer in read command + * - @c COMMAND_NULLPOINTER datalen was != 0 but data was == NULL in + * write command, or nullpointer in read command * - return codes of RMAPChannelIF::sendCommand() */ static ReturnValue_t sendReadCommand(RMAPCookie *cookie, uint32_t expLength); diff --git a/src/fsfw/rmap/RMAPChannelIF.h b/src/fsfw/rmap/RMAPChannelIF.h index 0c937dc8..20dfd5f8 100644 --- a/src/fsfw/rmap/RMAPChannelIF.h +++ b/src/fsfw/rmap/RMAPChannelIF.h @@ -75,10 +75,10 @@ class RMAPChannelIF { * - @c RETURN_OK * - @c COMMAND_NO_DESCRIPTORS_AVAILABLE no descriptors available for sending * command; command was not sent - * - @c COMMAND_BUFFER_FULL no receiver buffer available for - * expected len; command was not sent - * - @c COMMAND_TOO_BIG the data that was to be sent was too long for - * the hw to handle (write command) or the expected len was bigger than maximal expected len (read + * - @c COMMAND_BUFFER_FULL no receiver buffer available for expected len; + * command was not sent + * - @c COMMAND_TOO_BIG the data that was to be sent was too long for the hw + * to handle (write command) or the expected len was bigger than maximal expected len (read * command) command was not sent * - @c COMMAND_CHANNEL_DEACTIVATED the channel has no port set * - @c NOT_SUPPORTED if you dont feel like @@ -97,8 +97,8 @@ class RMAPChannelIF { * - @c REPLY_NO_REPLY no reply was received * - @c REPLY_NOT_SENT command was not sent, implies no reply * - @c REPLY_NOT_YET_SENT command is still waiting to be sent - * - @c WRITE_REPLY_INTERFACE_BUSY Interface is busy (transmission - * buffer still being processed) + * - @c WRITE_REPLY_INTERFACE_BUSY Interface is busy (transmission buffer still + * being processed) * - @c WRITE_REPLY_TRANSMISSION_ERROR Interface encountered errors during last * operation, data could not be processed. (transmission error) * - @c WRITE_REPLY_INVALID_DATA Invalid data (amount / value) diff --git a/tests/src/fsfw_tests/unit/hal/testCommandExecutor.cpp b/tests/src/fsfw_tests/unit/hal/testCommandExecutor.cpp index d2a15137..3ad26876 100644 --- a/tests/src/fsfw_tests/unit/hal/testCommandExecutor.cpp +++ b/tests/src/fsfw_tests/unit/hal/testCommandExecutor.cpp @@ -45,7 +45,7 @@ TEST_CASE("Command Executor", "[cmd-exec]") { result = cmdExecutor.check(bytesHaveBeenRead); REQUIRE(result != CommandExecutor::COMMAND_ERROR); usleep(500); - REQUIRE(limitIdx < 5); + REQUIRE(limitIdx < 500); } limitIdx = 0; @@ -71,8 +71,9 @@ TEST_CASE("Command Executor", "[cmd-exec]") { limitIdx++; result = cmdExecutor.check(bytesHaveBeenRead); REQUIRE(result != CommandExecutor::COMMAND_ERROR); + // This ensures that the tests do not block indefinitely usleep(500); - REQUIRE(limitIdx < 20); + REQUIRE(limitIdx < 500); } limitIdx = 0; CHECK(bytesHaveBeenRead == true); @@ -89,7 +90,7 @@ TEST_CASE("Command Executor", "[cmd-exec]") { std::string allTheReply(reinterpret_cast(largerReadBuffer)); // I am just going to assume that this string is the same across ping implementations // of different Linux systems - REQUIRE(allTheReply.find("localhost ping statistics") != std::string::npos); + REQUIRE(allTheReply.find("PING localhost") != std::string::npos); // Now check failing command result = cmdExecutor.load("false", false, false); @@ -101,8 +102,9 @@ TEST_CASE("Command Executor", "[cmd-exec]") { limitIdx++; result = cmdExecutor.check(bytesHaveBeenRead); REQUIRE(result != CommandExecutor::COMMAND_ERROR); + // This ensures that the tests do not block indefinitely usleep(500); - REQUIRE(limitIdx < 20); + REQUIRE(limitIdx < 500); } REQUIRE(result == HasReturnvaluesIF::RETURN_FAILED); REQUIRE(cmdExecutor.getLastError() == 1);