Merge remote-tracking branch 'upstream/development' into mueller/master

This commit is contained in:
Robin Müller 2022-02-15 17:08:29 +01:00
commit 0d6d44f72f
13 changed files with 107 additions and 37 deletions

View File

@ -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 PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/544
- doSendRead Hook - doSendRead Hook
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/545 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 ### 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. could lead to compile errors that `#include "fsfw/FSFW.h"` was not found.
- Fix for build regression in Catch2 v3.0.0-preview4 - Fix for build regression in Catch2 v3.0.0-preview4
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/548 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 ## API Changes

View File

@ -1,8 +1,8 @@
cmake_minimum_required(VERSION 3.13) cmake_minimum_required(VERSION 3.13)
set(FSFW_VERSION 3) set(FSFW_VERSION 4)
set(FSFW_SUBVERSION 0) set(FSFW_SUBVERSION 0)
set(FSFW_REVISION 1) set(FSFW_REVISION 0)
# Add the cmake folder so the FindSphinx module is found # Add the cmake folder so the FindSphinx module is found
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})

View File

@ -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. 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 ## Formatting the sources
The formatting is done by the `clang-format` tool. The configuration is contained within the The formatting is done by the `clang-format` tool. The configuration is contained within the

View File

@ -14,7 +14,8 @@ requirements, which are fulfilled by implementing certain interfaces:
communication bus, for example SpaceWire, UART or SPI: :cpp:class:`DeviceCommunicationIF` 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 - The handler has housekeeping data which has to be exposed to the operator and/or other software
components: :cpp:class:`HasLocalDataPoolIF` 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: - The handler has health states, for example to indicate a broken device:
:cpp:class:`HasHealthIF` :cpp:class:`HasHealthIF`
- The handler has modes. For example there are the core modes `MODE_ON`, `MODE_OFF` - The handler has modes. For example there are the core modes `MODE_ON`, `MODE_OFF`

View File

@ -90,8 +90,21 @@ Building the documentation
---------------------------- ----------------------------
The FSFW documentation is built using the tools Sphinx, doxygen and breathe based on the 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/>`_. You can set up a instructions provided in `this blogpost <https://devblogs.microsoft.com/cppblog/clear-functional-c-documentation-with-sphinx-breathe-doxygen-cmake/>`_. If you
documentation build system using the following commands 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 .. 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 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. 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 .. _`Hosted FSFW example`: https://egit.irs.uni-stuttgart.de/fsfw/fsfw-example-hosted
.. _`Catch2 library`: https://github.com/catchorg/Catch2 .. _`Catch2 library`: https://github.com/catchorg/Catch2
.. _`Code coverage`: https://github.com/bilke/cmake-modules/tree/master .. _`Code coverage`: https://github.com/bilke/cmake-modules/tree/master

View File

@ -22,7 +22,7 @@ ReturnValue_t UioMapper::getMappedAdress(uint32_t** address, Permissions permiss
int fd = open(uioFile.c_str(), O_RDWR); int fd = open(uioFile.c_str(), O_RDWR);
if (fd < 1) { if (fd < 1) {
#if FSFW_CPP_OSTREAM_ENABLED == 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 #endif
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
@ -36,8 +36,8 @@ ReturnValue_t UioMapper::getMappedAdress(uint32_t** address, Permissions permiss
if (*address == MAP_FAILED) { if (*address == MAP_FAILED) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "UioMapper::getMappedAdress: Failed to map physical address of uio device " sif::error << "UioMapper::getMappedAdress: Failed to map physical address of uio device "
<< uioFile.c_str() << " and map" << static_cast<int>(mapNum) << std::endl; << uioFile.c_str() << " and map" << static_cast<int>(mapNum) << std::endl;
#endif #endif
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
@ -52,7 +52,7 @@ ReturnValue_t UioMapper::getMapSize(size_t* size) {
fp = fopen(namestream.str().c_str(), "r"); fp = fopen(namestream.str().c_str(), "r");
if (fp == nullptr) { if (fp == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #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 #endif
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
@ -60,11 +60,12 @@ ReturnValue_t UioMapper::getMapSize(size_t* size) {
int items = fscanf(fp, "%s", hexstring); int items = fscanf(fp, "%s", hexstring);
if (items != 1) { if (items != 1) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "UioMapper::getMapSize: Failed with error code " << errno sif::error << "UioMapper::getMapSize: Failed with error code " << errno
<< " to read size " << " to read size "
"string from file " "string from file "
<< namestream.str() << std::endl; << namestream.str() << std::endl;
#endif #endif
fclose(fp);
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
uint32_t sizeTmp = 0; uint32_t sizeTmp = 0;
@ -74,9 +75,10 @@ ReturnValue_t UioMapper::getMapSize(size_t* size) {
} }
if (items != 1) { if (items != 1) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "UioMapper::getMapSize: Failed with error code " << errno << "to convert " sif::error << "UioMapper::getMapSize: Failed with error code " << errno << "to convert "
<< "size of map" << mapNum << " to integer" << std::endl; << "size of map" << mapNum << " to integer" << std::endl;
#endif #endif
fclose(fp);
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
fclose(fp); fclose(fp);

View File

@ -143,7 +143,10 @@ def handle_tests_type(args, build_dir_list: list):
if which("valgrind") is None: if which("valgrind") is None:
print("Please install valgrind first") print("Please install valgrind first")
sys.exit(1) 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.system("valgrind --leak-check=full ./fsfw-tests")
os.chdir("..") os.chdir("..")

View File

@ -117,7 +117,7 @@ uint16_t CRC::crc16ccitt(uint8_t const input[], uint32_t length, uint16_t starti
// { // {
// if (xor_out[i] == true) // if (xor_out[i] == true)
// crc_value = crc_value + pow(2,(15 -i)); // reverse CrC result before // crc_value = crc_value + pow(2,(15 -i)); // reverse CrC result before
// Final XOR //Final XOR
// } // }
// //
// crc_value = 0;// for debug mode // crc_value = 0;// for debug mode

View File

@ -65,10 +65,9 @@ class PeriodicPosixTask : public PosixThread, public PeriodicTaskIF {
/** /**
* @brief The function containing the actual functionality of the task. * @brief The function containing the actual functionality of the task.
* @details The method sets and starts * @details The method sets and starts
* the task's period, then enters a loop that is repeated indefinitely. Within * the task's period, then enters a loop that is repeated indefinitely. Within the
* the loop, all performOperation methods of the added objects are called. Afterwards the task * loop, all performOperation methods of the added objects are called. Afterwards the task will be
* will be blocked until the next period. On missing the deadline, the deadlineMissedFunction is * blocked until the next period. On missing the deadline, the deadlineMissedFunction is executed.
* executed.
*/ */
virtual void taskFunctionality(void); virtual void taskFunctionality(void);
/** /**

View File

@ -13,8 +13,8 @@ class ExecutableObjectIF;
* @brief This class represents a specialized task for periodic activities of multiple objects. * @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 * @details MultiObjectTask is an extension to ObjectTask in the way that it is able to execute
* multiple objects that implement the ExecutableObjectIF interface. The * multiple objects that implement the ExecutableObjectIF interface. The objects
* objects must be added prior to starting the task. * must be added prior to starting the task.
* @author baetz * @author baetz
* @ingroup task_handling * @ingroup task_handling
*/ */

View File

@ -169,8 +169,8 @@ class RMAP : public HasReturnvaluesIF {
* @param buffer the data to write * @param buffer the data to write
* @param length length of data * @param length length of data
* @return * @return
* - @c COMMAND_NULLPOINTER datalen was != 0 but data was == * - @c COMMAND_NULLPOINTER datalen was != 0 but data was == NULL in
* NULL in write command * write command
* - return codes of RMAPChannelIF::sendCommand() * - return codes of RMAPChannelIF::sendCommand()
*/ */
static ReturnValue_t sendWriteCommand(RMAPCookie *cookie, const uint8_t *buffer, size_t length); 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 cookie to cookie to read from
* @param expLength the expected maximum length of the reply * @param expLength the expected maximum length of the reply
* @return * @return
* - @c COMMAND_NULLPOINTER datalen was != 0 but data was == * - @c COMMAND_NULLPOINTER datalen was != 0 but data was == NULL in
* NULL in write command, or nullpointer in read command * write command, or nullpointer in read command
* - return codes of RMAPChannelIF::sendCommand() * - return codes of RMAPChannelIF::sendCommand()
*/ */
static ReturnValue_t sendReadCommand(RMAPCookie *cookie, uint32_t expLength); static ReturnValue_t sendReadCommand(RMAPCookie *cookie, uint32_t expLength);

View File

@ -75,10 +75,10 @@ class RMAPChannelIF {
* - @c RETURN_OK * - @c RETURN_OK
* - @c COMMAND_NO_DESCRIPTORS_AVAILABLE no descriptors available for sending * - @c COMMAND_NO_DESCRIPTORS_AVAILABLE no descriptors available for sending
* command; command was not sent * command; command was not sent
* - @c COMMAND_BUFFER_FULL no receiver buffer available for * - @c COMMAND_BUFFER_FULL no receiver buffer available for expected len;
* expected len; command was not sent * command was not sent
* - @c COMMAND_TOO_BIG the data that was to be sent was too long for * - @c COMMAND_TOO_BIG the data that was to be sent was too long for the hw
* the hw to handle (write command) or the expected len was bigger than maximal expected len (read * to handle (write command) or the expected len was bigger than maximal expected len (read
* command) command was not sent * command) command was not sent
* - @c COMMAND_CHANNEL_DEACTIVATED the channel has no port set * - @c COMMAND_CHANNEL_DEACTIVATED the channel has no port set
* - @c NOT_SUPPORTED if you dont feel like * - @c NOT_SUPPORTED if you dont feel like
@ -97,8 +97,8 @@ class RMAPChannelIF {
* - @c REPLY_NO_REPLY no reply was received * - @c REPLY_NO_REPLY no reply was received
* - @c REPLY_NOT_SENT command was not sent, implies no reply * - @c REPLY_NOT_SENT command was not sent, implies no reply
* - @c REPLY_NOT_YET_SENT command is still waiting to be sent * - @c REPLY_NOT_YET_SENT command is still waiting to be sent
* - @c WRITE_REPLY_INTERFACE_BUSY Interface is busy (transmission * - @c WRITE_REPLY_INTERFACE_BUSY Interface is busy (transmission buffer still
* buffer still being processed) * being processed)
* - @c WRITE_REPLY_TRANSMISSION_ERROR Interface encountered errors during last * - @c WRITE_REPLY_TRANSMISSION_ERROR Interface encountered errors during last
* operation, data could not be processed. (transmission error) * operation, data could not be processed. (transmission error)
* - @c WRITE_REPLY_INVALID_DATA Invalid data (amount / value) * - @c WRITE_REPLY_INVALID_DATA Invalid data (amount / value)

View File

@ -45,7 +45,7 @@ TEST_CASE("Command Executor", "[cmd-exec]") {
result = cmdExecutor.check(bytesHaveBeenRead); result = cmdExecutor.check(bytesHaveBeenRead);
REQUIRE(result != CommandExecutor::COMMAND_ERROR); REQUIRE(result != CommandExecutor::COMMAND_ERROR);
usleep(500); usleep(500);
REQUIRE(limitIdx < 5); REQUIRE(limitIdx < 500);
} }
limitIdx = 0; limitIdx = 0;
@ -71,8 +71,9 @@ TEST_CASE("Command Executor", "[cmd-exec]") {
limitIdx++; limitIdx++;
result = cmdExecutor.check(bytesHaveBeenRead); result = cmdExecutor.check(bytesHaveBeenRead);
REQUIRE(result != CommandExecutor::COMMAND_ERROR); REQUIRE(result != CommandExecutor::COMMAND_ERROR);
// This ensures that the tests do not block indefinitely
usleep(500); usleep(500);
REQUIRE(limitIdx < 20); REQUIRE(limitIdx < 500);
} }
limitIdx = 0; limitIdx = 0;
CHECK(bytesHaveBeenRead == true); CHECK(bytesHaveBeenRead == true);
@ -89,7 +90,7 @@ TEST_CASE("Command Executor", "[cmd-exec]") {
std::string allTheReply(reinterpret_cast<char*>(largerReadBuffer)); std::string allTheReply(reinterpret_cast<char*>(largerReadBuffer));
// I am just going to assume that this string is the same across ping implementations // I am just going to assume that this string is the same across ping implementations
// of different Linux systems // 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 // Now check failing command
result = cmdExecutor.load("false", false, false); result = cmdExecutor.load("false", false, false);
@ -101,8 +102,9 @@ TEST_CASE("Command Executor", "[cmd-exec]") {
limitIdx++; limitIdx++;
result = cmdExecutor.check(bytesHaveBeenRead); result = cmdExecutor.check(bytesHaveBeenRead);
REQUIRE(result != CommandExecutor::COMMAND_ERROR); REQUIRE(result != CommandExecutor::COMMAND_ERROR);
// This ensures that the tests do not block indefinitely
usleep(500); usleep(500);
REQUIRE(limitIdx < 20); REQUIRE(limitIdx < 500);
} }
REQUIRE(result == HasReturnvaluesIF::RETURN_FAILED); REQUIRE(result == HasReturnvaluesIF::RETURN_FAILED);
REQUIRE(cmdExecutor.getLastError() == 1); REQUIRE(cmdExecutor.getLastError() == 1);