Compare commits
192 Commits
Author | SHA1 | Date | |
---|---|---|---|
70f0a72f1b | |||
b5d890eedd | |||
50b1b48678 | |||
0e0dbc74aa | |||
8c34051d8b | |||
b00d83cb1a | |||
17e609c3a5 | |||
64f0166b64 | |||
c80f06fbcb | |||
e796f82203 | |||
5b7ca8c13c | |||
031739ef51 | |||
b8516b15cb | |||
ac5a54b5da | |||
29015b340b | |||
64274acbeb | |||
ff98c42514 | |||
126ac52975 | |||
70d3197212 | |||
dd90980520 | |||
352ab43c1f | |||
97e98eae24 | |||
5ac88f2b15 | |||
b03a6684f9 | |||
7c2e50b665 | |||
c04ca704d2 | |||
6aa54fe1d4 | |||
c55925959b | |||
4f0669c574 | |||
f0d996ffd2 | |||
f4d05c2c9c | |||
d1151ca707 | |||
82f46992f6 | |||
c0f80680ef | |||
7761b66fe2 | |||
acc4c8d975 | |||
fe739aa81a | |||
afe006e234 | |||
95f018a0b0 | |||
8c2105ae0a | |||
ed2c2af4a0 | |||
17771c0497 | |||
82df132e7d | |||
a02619e5a2 | |||
a011e70665 | |||
c05184e1c4 | |||
b2252bdc0b | |||
7e61ce1ed2 | |||
fcb6437388 | |||
6c1db8473b | |||
1a530633ca | |||
8037e8074b | |||
d07e0e5576 | |||
5525466b52 | |||
c2a89bf709 | |||
8dd0b2608d | |||
05495077ec | |||
8ff9eadf30 | |||
082c86ea18 | |||
2800d6f28c | |||
b4effe7a46 | |||
e6e71436c2 | |||
4be45adae6 | |||
a887f852c8 | |||
0d7d2203d2 | |||
cde184f428 | |||
0b3255e463 | |||
df3794dfd8 | |||
d02d5c351d | |||
631a531212 | |||
febecd4b30 | |||
964e311d8b | |||
d43caa8296 | |||
916ed3f56a | |||
665d8cd479 | |||
10398855a9 | |||
d0fec93dc3 | |||
59ab54b2fb | |||
7095999bd2 | |||
7ffb4107d2 | |||
d9d9a28ef8 | |||
d95582b81b | |||
c60aa68d00 | |||
9ce59d3c75 | |||
a0dfdfab2c | |||
3e17011087 | |||
f441505476 | |||
7c64797f03 | |||
e08bdd3e35 | |||
d2dd16aef3 | |||
b7a617dab3 | |||
bc95e7c886 | |||
fca43b3d34 | |||
48c5c3fbd5 | |||
b694aea100 | |||
6998626ad4 | |||
24ad858b64 | |||
288d453978 | |||
522cbc7f3d | |||
ce5bcc5897 | |||
97c93afeff | |||
8704b9ab06 | |||
5a1585bd00 | |||
5d6de90859 | |||
378c6c8006 | |||
f4922a8686 | |||
0bdcb40609 | |||
e684680d60 | |||
aa5d1042f0 | |||
14ac852b7e | |||
6b1a81ee92 | |||
3779b44813 | |||
949549178a | |||
7daa9812ff | |||
ca508bfe61 | |||
345a799031 | |||
445d5dd6f0 | |||
238baa8597 | |||
7932afc315 | |||
d1e3dc4d49 | |||
77e5fba7fd | |||
ca70c8c614 | |||
14620fdd72 | |||
89c1878622 | |||
d6856fc54a | |||
e5a9cab34e | |||
a4f97a7ba7 | |||
8b1af232c3 | |||
983fa346b3 | |||
32f420c4f0 | |||
41a82e923c | |||
5ddac36314 | |||
d06eecf9b0 | |||
5912ddd2a2 | |||
7db11588b4 | |||
c88b931ef1 | |||
10ffa2f44a | |||
dbe31dd339 | |||
14b44f8bb2 | |||
117747970d | |||
c6540650e2 | |||
f659f13759 | |||
95078e1103 | |||
8920255565 | |||
2d12618c96 | |||
68ca6fd122 | |||
33e9592659 | |||
19d217e3b9 | |||
af286d3bc6 | |||
20928732ec | |||
a8426750f2 | |||
2635f39344 | |||
89327463e3 | |||
cf45eca100 | |||
c0fa365f8f | |||
9d9f19781d | |||
f4520ea346 | |||
bbacdc5cac | |||
a6c0f3fef5 | |||
0e8328fca3 | |||
1ef3dae72e | |||
32381a7872 | |||
09815f5cce | |||
f6357b4531 | |||
a10e5c6ed4 | |||
d6d13eec95 | |||
457bc6609e | |||
e75155c329 | |||
d4e48006f2 | |||
d6508e23b6 | |||
2cb254a556 | |||
f99f5ed730 | |||
5f7e384442 | |||
56d0c8c616 | |||
5ff0f8ea10 | |||
fdc8a3d4f7 | |||
e5e85bcff9 | |||
4862edfdb5 | |||
a50b52df51 | |||
eac7e6db07 | |||
0c4835bfb5 | |||
aebd4817b8 | |||
9c2ceb4a9f | |||
68ace0b74a | |||
d119479c0a | |||
6739890d53 | |||
90b8ad1e6d | |||
025f79fcb4 | |||
6fb64f9ada | |||
2f1b923009 | |||
45ea09291a | |||
b7f3eff742 |
50
CHANGELOG.md
50
CHANGELOG.md
@ -8,6 +8,56 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
# [unreleased]
|
||||
|
||||
# [v5.0.0]
|
||||
|
||||
## Changes
|
||||
|
||||
- HAL Linux SPI: Set the Clock Default State when setting new SPI speed
|
||||
and mode
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/573
|
||||
- GPIO HAL: `Direction`, `GpioOperation` and `Levels` are enum classes now, which prevents
|
||||
name clashes with Windows defines.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/572
|
||||
- New CMake option `FSFW_HAL_LINUX_ADD_LIBGPIOD` to specifically exclude `gpiod` code.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/572
|
||||
- HAL Devicehandlers: Periodic printout is run-time configurable now
|
||||
- `oneShotAction` flag in the `TestTask` class is not static anymore
|
||||
- HAL Linux Uart: Baudrate and bits per word are enums now, avoiding misconfigurations
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/585
|
||||
- IPC Message Queue Handling: Allow passing an optional `MqArgs` argument into the MessageQueue
|
||||
creation call. It allows passing context information and an arbitrary user argument into
|
||||
the message queue. Also streamlined and simplified `MessageQueue` implementation for all OSALs
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/583
|
||||
- Clock:
|
||||
- `timeval` to `TimeOfDay_t`
|
||||
- Added Mutex for gmtime calls: (compare http://www.opengate.at/blog/2020/01/timeless/)
|
||||
- Moved the statics used by Clock in ClockCommon.cpp to this file
|
||||
- Better check for leap seconds
|
||||
- Added Unittests for Clock (only getter)
|
||||
|
||||
## Removed
|
||||
|
||||
- Removed the `HkSwitchHelper`. This module should not be needed anymore, now that the local
|
||||
datapools have been implemented.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/557
|
||||
|
||||
## Additions
|
||||
|
||||
- Linux HAL: Add wiretapping option for I2C. Enabled with `FSFW_HAL_I2C_WIRETAPPING` defined to 1
|
||||
- Dedicated Version class and constant `fsfw::FSFW_VERSION` containing version information
|
||||
inside `fsfw/version.h`
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/559
|
||||
- Added ETL dependency and improved library dependency management
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/592
|
||||
|
||||
## Fixed
|
||||
|
||||
- Small bugfix in STM32 HAL for SPI
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/599
|
||||
- HAL GPIO: Improved error checking in `LinuxLibgpioIF::configureGpios(...)`. If a GPIO
|
||||
configuration fails, the function will exit prematurely with a dedicated error code
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/602
|
||||
|
||||
# [v4.0.0]
|
||||
|
||||
## Additions
|
||||
|
@ -7,6 +7,23 @@ 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})
|
||||
|
||||
set(FSFW_ETL_LIB_MAJOR_VERSION 20 CACHE STRING
|
||||
"ETL library major version requirement"
|
||||
)
|
||||
set(FSFW_ETL_LIB_VERSION ${FSFW_ETL_LIB_MAJOR_VERSION}.27.3 CACHE STRING
|
||||
"ETL library exact version requirement"
|
||||
)
|
||||
set(FSFW_ETL_LINK_TARGET etl::etl)
|
||||
|
||||
set(FSFW_CATCH2_LIB_MAJOR_VERSION 3 CACHE STRING
|
||||
"Catch2 library major version requirement"
|
||||
)
|
||||
set(FSFW_CATCH2_LIB_VERSION v${FSFW_CATCH2_LIB_MAJOR_VERSION}.0.0-preview5 CACHE STRING
|
||||
"Catch2 library exact version requirement"
|
||||
)
|
||||
|
||||
set(FSFW_ETL_LIB_NAME etl)
|
||||
|
||||
option(FSFW_GENERATE_SECTIONS
|
||||
"Generate function and data sections. Required to remove unused code" ON
|
||||
)
|
||||
@ -48,19 +65,21 @@ add_library(${LIB_FSFW_NAME})
|
||||
if(FSFW_BUILD_UNITTESTS)
|
||||
message(STATUS "Building the FSFW unittests in addition to the static library")
|
||||
# Check whether the user has already installed Catch2 first
|
||||
find_package(Catch2 3)
|
||||
find_package(Catch2 ${FSFW_CATCH2_LIB_MAJOR_VERSION})
|
||||
# Not installed, so use FetchContent to download and provide Catch2
|
||||
if(NOT Catch2_FOUND)
|
||||
message(STATUS "Catch2 installation not found. Downloading Catch2 library with FetchContent")
|
||||
include(FetchContent)
|
||||
|
||||
FetchContent_Declare(
|
||||
Catch2
|
||||
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
|
||||
GIT_TAG v3.0.0-preview4
|
||||
GIT_TAG ${FSFW_CATCH2_LIB_VERSION}
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(Catch2)
|
||||
#fixes regression -preview4, to be confirmed in later releases
|
||||
# fixes regression -preview4, to be confirmed in later releases
|
||||
# Related GitHub issue: https://github.com/catchorg/Catch2/issues/2417
|
||||
set_target_properties(Catch2 PROPERTIES DEBUG_POSTFIX "")
|
||||
endif()
|
||||
|
||||
@ -88,6 +107,28 @@ if(FSFW_BUILD_UNITTESTS)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
message(STATUS "Finding and/or providing ETL library")
|
||||
|
||||
# Check whether the user has already installed ETL first
|
||||
find_package(${FSFW_ETL_LIB_NAME} ${FSFW_ETL_LIB_MAJOR_VERSION} QUIET)
|
||||
# Not installed, so use FetchContent to download and provide etl
|
||||
if(NOT ${FSFW_ETL_LIB_NAME}_FOUND)
|
||||
message(STATUS
|
||||
"No ETL installation was found with find_package. Installing and providing "
|
||||
"etl with FindPackage"
|
||||
)
|
||||
include(FetchContent)
|
||||
|
||||
FetchContent_Declare(
|
||||
${FSFW_ETL_LIB_NAME}
|
||||
GIT_REPOSITORY https://github.com/ETLCPP/etl
|
||||
GIT_TAG ${FSFW_ETL_LIB_VERSION}
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(${FSFW_ETL_LIB_NAME})
|
||||
add_library(${FSFW_ETL_LINK_TARGET} ALIAS ${FSFW_ETL_LIB_NAME})
|
||||
endif()
|
||||
|
||||
set(FSFW_CORE_INC_PATH "inc")
|
||||
|
||||
set_property(CACHE FSFW_OSAL PROPERTY STRINGS host linux rtems freertos)
|
||||
@ -281,6 +322,24 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
-Wimplicit-fallthrough=1
|
||||
-Wno-unused-parameter
|
||||
-Wno-psabi
|
||||
-Wduplicated-cond # check for duplicate conditions
|
||||
-Wduplicated-branches # check for duplicate branches
|
||||
-Wlogical-op # Search for bitwise operations instead of logical
|
||||
-Wnull-dereference # Search for NULL dereference
|
||||
-Wundef # Warn if undefind marcos are used
|
||||
-Wformat=2 # Format string problem detection
|
||||
-Wformat-overflow=2 # Formatting issues in printf
|
||||
-Wformat-truncation=2 # Formatting issues in printf
|
||||
-Wformat-security # Search for dangerous printf operations
|
||||
-Wstrict-overflow=3 # Warn if integer overflows might happen
|
||||
-Warray-bounds=2 # Some array bounds violations will be found
|
||||
-Wshift-overflow=2 # Search for bit left shift overflows (<c++14)
|
||||
-Wcast-qual # Warn if the constness is cast away
|
||||
-Wstringop-overflow=4
|
||||
# -Wstack-protector # Emits a few false positives for low level access
|
||||
# -Wconversion # Creates many false positives
|
||||
# -Warith-conversion # Use with Wconversion to find more implicit conversions
|
||||
# -fanalyzer # Should be used to look through problems
|
||||
)
|
||||
endif()
|
||||
|
||||
@ -331,6 +390,7 @@ target_compile_options(${LIB_FSFW_NAME} PRIVATE
|
||||
)
|
||||
|
||||
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
|
||||
${FSFW_ETL_LINK_TARGET}
|
||||
${FSFW_ADDITIONAL_LINK_LIBS}
|
||||
)
|
||||
|
||||
|
51
README.md
51
README.md
@ -11,9 +11,15 @@ 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 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.
|
||||
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:
|
||||
|
||||
@ -45,6 +51,28 @@ A template configuration folder was provided and can be copied into the project
|
||||
a starting point. The [configuration section](docs/README-config.md#top) provides more specific
|
||||
information about the possible options.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
The Embedded Template Library (etl) is a dependency of the FSFW which is automatically
|
||||
installed and provided by the build system unless the correction version was installed.
|
||||
The current recommended version can be found inside the fsfw `CMakeLists.txt` file or by using
|
||||
`ccmake` and looking up the `FSFW_ETL_LIB_MAJOR_VERSION` variable.
|
||||
|
||||
You can install the ETL library like this. On Linux, it might be necessary to add `sudo` before
|
||||
the install call:
|
||||
|
||||
```cpp
|
||||
git clone https://github.com/ETLCPP/etl
|
||||
cd etl
|
||||
git checkout <currentRecommendedVersion>
|
||||
mkdir build && cd build
|
||||
cmake ..
|
||||
cmake --install .
|
||||
```
|
||||
|
||||
It is recommended to install `20.27.2` or newer for the package version handling of
|
||||
ETL to work.
|
||||
|
||||
## Adding the library
|
||||
|
||||
The following steps show how to add and use FSFW components. It is still recommended to
|
||||
@ -71,9 +99,9 @@ add and link against the FSFW library in general.
|
||||
|
||||
4. Link against the FSFW library
|
||||
|
||||
```cmake
|
||||
target_link_libraries(<YourProjectName> PRIVATE fsfw)
|
||||
```
|
||||
```cmake
|
||||
target_link_libraries(${YourProjectName} PRIVATE fsfw)
|
||||
```
|
||||
|
||||
5. It should now be possible use the FSFW as a static library from the user code.
|
||||
|
||||
@ -83,6 +111,19 @@ The FSFW also has unittests which use the [Catch2 library](https://github.com/ca
|
||||
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.
|
||||
|
||||
You can install the Catch2 library, which prevents the build system to avoid re-downloading
|
||||
the dependency if the unit tests are completely rebuilt. The current recommended version
|
||||
can be found inside the fsfw `CMakeLists.txt` file or by using `ccmake` and looking up
|
||||
the `FSFW_CATCH2_LIB_VERSION` variable.
|
||||
|
||||
```sh
|
||||
git clone https://github.com/catchorg/Catch2.git
|
||||
cd Catch2
|
||||
git checkout <currentRecommendedVersion>
|
||||
cmake -Bbuild -H. -DBUILD_TESTING=OFF
|
||||
sudo cmake --build build/ --target install
|
||||
```
|
||||
|
||||
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`.
|
||||
|
@ -6,3 +6,9 @@ RUN apt-get --yes upgrade
|
||||
#tzdata is a dependency, won't install otherwise
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
RUN apt-get --yes install gcc g++ cmake make lcov git valgrind nano iputils-ping
|
||||
|
||||
RUN git clone https://github.com/catchorg/Catch2.git && \
|
||||
cd Catch2 && \
|
||||
git checkout v3.0.0-preview5 && \
|
||||
cmake -Bbuild -H. -DBUILD_TESTING=OFF && \
|
||||
cmake --build build/ --target install
|
||||
|
6
automation/Jenkinsfile
vendored
6
automation/Jenkinsfile
vendored
@ -3,7 +3,7 @@ pipeline {
|
||||
BUILDDIR = 'build-tests'
|
||||
}
|
||||
agent {
|
||||
docker { image 'fsfw-ci:d1'}
|
||||
docker { image 'fsfw-ci:d2'}
|
||||
}
|
||||
stages {
|
||||
stage('Clean') {
|
||||
@ -21,14 +21,14 @@ pipeline {
|
||||
stage('Build') {
|
||||
steps {
|
||||
dir(BUILDDIR) {
|
||||
sh 'cmake --build . -j'
|
||||
sh 'cmake --build . -j4'
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Unittests') {
|
||||
steps {
|
||||
dir(BUILDDIR) {
|
||||
sh 'cmake --build . -- fsfw-tests_coverage -j'
|
||||
sh 'cmake --build . -- fsfw-tests_coverage -j4'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,29 @@ A template configuration folder was provided and can be copied into the project
|
||||
a starting point. The [configuration section](docs/README-config.md#top) provides more specific
|
||||
information about the possible options.
|
||||
|
||||
Prerequisites
|
||||
-------------------
|
||||
|
||||
The Embedded Template Library (etl) is a dependency of the FSFW which is automatically
|
||||
installed and provided by the build system unless the correction version was installed.
|
||||
The current recommended version can be found inside the fsfw ``CMakeLists.txt`` file or by using
|
||||
``ccmake`` and looking up the ``FSFW_ETL_LIB_MAJOR_VERSION`` variable.
|
||||
|
||||
You can install the ETL library like this. On Linux, it might be necessary to add ``sudo`` before
|
||||
the install call:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
git clone https://github.com/ETLCPP/etl
|
||||
cd etl
|
||||
git checkout <currentRecommendedVersion>
|
||||
mkdir build && cd build
|
||||
cmake ..
|
||||
cmake --install .
|
||||
|
||||
It is recommended to install ``20.27.2`` or newer for the package version handling of
|
||||
ETL to work.
|
||||
|
||||
Adding the library
|
||||
-------------------
|
||||
|
||||
@ -60,6 +83,20 @@ 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.
|
||||
|
||||
You can install the Catch2 library, which prevents the build system to avoid re-downloading
|
||||
the dependency if the unit tests are completely rebuilt. The current recommended version
|
||||
can be found inside the fsfw ``CMakeLists.txt`` file or by using ``ccmake`` and looking up
|
||||
the ``FSFW_CATCH2_LIB_VERSION`` variable.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
git clone https://github.com/catchorg/Catch2.git
|
||||
cd Catch2
|
||||
git checkout <currentRecommendedVersion>
|
||||
cmake -Bbuild -H. -DBUILD_TESTING=OFF
|
||||
sudo cmake --build build/ --target install
|
||||
|
||||
|
||||
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`.
|
||||
|
@ -9,6 +9,7 @@ option(FSFW_HAL_ADD_LINUX "Add the Linux HAL to the sources. Requires gpiod libr
|
||||
# Linux. The only exception from this is the gpiod library which requires a dedicated installation,
|
||||
# but CMake is able to determine whether this library is installed with find_library.
|
||||
option(FSFW_HAL_LINUX_ADD_PERIPHERAL_DRIVERS "Add peripheral drivers for embedded Linux" ON)
|
||||
option(FSFW_HAL_LINUX_ADD_LIBGPIOD "Target implements libgpiod" ON)
|
||||
|
||||
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)
|
||||
|
@ -9,11 +9,11 @@ using gpioId_t = uint16_t;
|
||||
|
||||
namespace gpio {
|
||||
|
||||
enum Levels : uint8_t { LOW = 0, HIGH = 1, NONE = 99 };
|
||||
enum class Levels : int { LOW = 0, HIGH = 1, NONE = 99 };
|
||||
|
||||
enum Direction : uint8_t { IN = 0, OUT = 1 };
|
||||
enum class Direction : int { IN = 0, OUT = 1 };
|
||||
|
||||
enum GpioOperation { READ, WRITE };
|
||||
enum class GpioOperation { READ, WRITE };
|
||||
|
||||
enum class GpioTypes {
|
||||
NONE,
|
||||
@ -80,7 +80,7 @@ class GpiodRegularByChip : public GpiodRegularBase {
|
||||
public:
|
||||
GpiodRegularByChip()
|
||||
: GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_CHIP, std::string(), gpio::Direction::IN,
|
||||
gpio::LOW, 0) {}
|
||||
gpio::Levels::LOW, 0) {}
|
||||
|
||||
GpiodRegularByChip(std::string chipname_, int lineNum_, std::string consumer_,
|
||||
gpio::Direction direction_, gpio::Levels initValue_)
|
||||
@ -90,7 +90,7 @@ class GpiodRegularByChip : public GpiodRegularBase {
|
||||
|
||||
GpiodRegularByChip(std::string chipname_, int lineNum_, std::string consumer_)
|
||||
: GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_CHIP, consumer_, gpio::Direction::IN,
|
||||
gpio::LOW, lineNum_),
|
||||
gpio::Levels::LOW, lineNum_),
|
||||
chipname(chipname_) {}
|
||||
|
||||
std::string chipname;
|
||||
@ -106,7 +106,7 @@ class GpiodRegularByLabel : public GpiodRegularBase {
|
||||
|
||||
GpiodRegularByLabel(std::string label_, int lineNum_, std::string consumer_)
|
||||
: GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_LABEL, consumer_, gpio::Direction::IN,
|
||||
gpio::LOW, lineNum_),
|
||||
gpio::Levels::LOW, lineNum_),
|
||||
label(label_) {}
|
||||
|
||||
std::string label;
|
||||
@ -127,7 +127,7 @@ class GpiodRegularByLineName : public GpiodRegularBase {
|
||||
|
||||
GpiodRegularByLineName(std::string lineName_, std::string consumer_)
|
||||
: GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME, consumer_, gpio::Direction::IN,
|
||||
gpio::LOW),
|
||||
gpio::Levels::LOW),
|
||||
lineName(lineName_) {}
|
||||
|
||||
std::string lineName;
|
||||
|
@ -8,11 +8,7 @@ GyroHandlerL3GD20H::GyroHandlerL3GD20H(object_id_t objectId, object_id_t deviceC
|
||||
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
|
||||
}
|
||||
dataset(this) {}
|
||||
|
||||
GyroHandlerL3GD20H::~GyroHandlerL3GD20H() {}
|
||||
|
||||
@ -193,22 +189,22 @@ ReturnValue_t GyroHandlerL3GD20H::interpretDeviceReply(DeviceCommandId_t id,
|
||||
|
||||
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 (periodicPrintout) {
|
||||
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;
|
||||
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);
|
||||
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) {
|
||||
@ -272,3 +268,8 @@ void GyroHandlerL3GD20H::setAbsoluteLimits(float limitX, float limitY, float lim
|
||||
this->absLimitY = limitY;
|
||||
this->absLimitZ = limitZ;
|
||||
}
|
||||
|
||||
void GyroHandlerL3GD20H::enablePeriodicPrintouts(bool enable, uint8_t divider) {
|
||||
periodicPrintout = enable;
|
||||
debugDivider.setDivider(divider);
|
||||
}
|
||||
|
@ -5,7 +5,6 @@
|
||||
#include <fsfw/globalfunctions/PeriodicOperationDivider.h>
|
||||
|
||||
#include "devicedefinitions/GyroL3GD20Definitions.h"
|
||||
#include "fsfw/FSFW.h"
|
||||
|
||||
/**
|
||||
* @brief Device Handler for the L3GD20H gyroscope sensor
|
||||
@ -22,6 +21,8 @@ class GyroHandlerL3GD20H : public DeviceHandlerBase {
|
||||
uint32_t transitionDelayMs);
|
||||
virtual ~GyroHandlerL3GD20H();
|
||||
|
||||
void enablePeriodicPrintouts(bool enable, uint8_t divider);
|
||||
|
||||
/**
|
||||
* 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
|
||||
@ -80,9 +81,8 @@ class GyroHandlerL3GD20H : public DeviceHandlerBase {
|
||||
// Set default value
|
||||
float sensitivity = L3GD20H::SENSITIVITY_00;
|
||||
|
||||
#if FSFW_HAL_L3GD20_GYRO_DEBUG == 1
|
||||
PeriodicOperationDivider *debugDivider = nullptr;
|
||||
#endif
|
||||
bool periodicPrintout = false;
|
||||
PeriodicOperationDivider debugDivider = PeriodicOperationDivider(3);
|
||||
};
|
||||
|
||||
#endif /* MISSION_DEVICES_GYROL3GD20HANDLER_H_ */
|
||||
|
@ -1,20 +1,14 @@
|
||||
#include "MgmLIS3MDLHandler.h"
|
||||
|
||||
#include "fsfw/datapool/PoolReadGuard.h"
|
||||
#if FSFW_HAL_LIS3MDL_MGM_DEBUG == 1
|
||||
#include "fsfw/globalfunctions/PeriodicOperationDivider.h"
|
||||
#endif
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "fsfw/datapool/PoolReadGuard.h"
|
||||
|
||||
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;
|
||||
@ -264,7 +258,7 @@ ReturnValue_t MgmLIS3MDLHandler::interpretDeviceReply(DeviceCommandId_t id, cons
|
||||
int16_t mgmMeasurementRawZ =
|
||||
packet[MGMLIS3MDL::Z_HIGHBYTE_IDX] << 8 | packet[MGMLIS3MDL::Z_LOWBYTE_IDX];
|
||||
|
||||
/* Target value in microtesla */
|
||||
// Target value in microtesla
|
||||
float mgmX = static_cast<float>(mgmMeasurementRawX) * sensitivityFactor *
|
||||
MGMLIS3MDL::GAUSS_TO_MICROTESLA_FACTOR;
|
||||
float mgmY = static_cast<float>(mgmMeasurementRawY) * sensitivityFactor *
|
||||
@ -272,23 +266,24 @@ ReturnValue_t MgmLIS3MDLHandler::interpretDeviceReply(DeviceCommandId_t id, cons
|
||||
float mgmZ = static_cast<float>(mgmMeasurementRawZ) * sensitivityFactor *
|
||||
MGMLIS3MDL::GAUSS_TO_MICROTESLA_FACTOR;
|
||||
|
||||
#if FSFW_HAL_LIS3MDL_MGM_DEBUG == 1
|
||||
if (debugDivider->checkAndIncrement()) {
|
||||
if (periodicPrintout) {
|
||||
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;
|
||||
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);
|
||||
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) {
|
||||
@ -318,15 +313,16 @@ ReturnValue_t MgmLIS3MDLHandler::interpretDeviceReply(DeviceCommandId_t id, cons
|
||||
case MGMLIS3MDL::READ_TEMPERATURE: {
|
||||
int16_t tempValueRaw = packet[2] << 8 | packet[1];
|
||||
float tempValue = 25.0 + ((static_cast<float>(tempValueRaw)) / 8.0);
|
||||
#if FSFW_HAL_LIS3MDL_MGM_DEBUG == 1
|
||||
if (debugDivider->check()) {
|
||||
if (periodicPrintout) {
|
||||
if (debugDivider.check()) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::info << "MGMHandlerLIS3: Temperature: " << tempValue << " C" << std::endl;
|
||||
sif::info << "MGMHandlerLIS3: Temperature: " << tempValue << " C" << std::endl;
|
||||
#else
|
||||
sif::printInfo("MGMHandlerLIS3: Temperature: %f C\n");
|
||||
sif::printInfo("MGMHandlerLIS3: Temperature: %f C\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ReturnValue_t result = dataset.read();
|
||||
if (result == HasReturnvaluesIF::RETURN_OK) {
|
||||
dataset.temperature = tempValue;
|
||||
@ -462,7 +458,9 @@ ReturnValue_t MgmLIS3MDLHandler::prepareCtrlRegisterWrite() {
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
void MgmLIS3MDLHandler::doTransition(Mode_t modeFrom, Submode_t subModeFrom) {}
|
||||
void MgmLIS3MDLHandler::doTransition(Mode_t modeFrom, Submode_t subModeFrom) {
|
||||
DeviceHandlerBase::doTransition(modeFrom, subModeFrom);
|
||||
}
|
||||
|
||||
uint32_t MgmLIS3MDLHandler::getTransitionDelayMs(Mode_t from, Mode_t to) { return transitionDelay; }
|
||||
|
||||
@ -482,3 +480,8 @@ void MgmLIS3MDLHandler::setAbsoluteLimits(float xLimit, float yLimit, float zLim
|
||||
this->absLimitY = yLimit;
|
||||
this->absLimitZ = zLimit;
|
||||
}
|
||||
|
||||
void MgmLIS3MDLHandler::enablePeriodicPrintouts(bool enable, uint8_t divider) {
|
||||
periodicPrintout = enable;
|
||||
debugDivider.setDivider(divider);
|
||||
}
|
||||
|
@ -3,8 +3,8 @@
|
||||
|
||||
#include "devicedefinitions/MgmLIS3HandlerDefs.h"
|
||||
#include "events/subsystemIdRanges.h"
|
||||
#include "fsfw/FSFW.h"
|
||||
#include "fsfw/devicehandlers/DeviceHandlerBase.h"
|
||||
#include "fsfw/globalfunctions/PeriodicOperationDivider.h"
|
||||
|
||||
class PeriodicOperationDivider;
|
||||
|
||||
@ -30,6 +30,7 @@ class MgmLIS3MDLHandler : public DeviceHandlerBase {
|
||||
uint32_t transitionDelay);
|
||||
virtual ~MgmLIS3MDLHandler();
|
||||
|
||||
void enablePeriodicPrintouts(bool enable, uint8_t divider);
|
||||
/**
|
||||
* 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
|
||||
@ -167,9 +168,8 @@ class MgmLIS3MDLHandler : public DeviceHandlerBase {
|
||||
*/
|
||||
ReturnValue_t prepareCtrlRegisterWrite();
|
||||
|
||||
#if FSFW_HAL_LIS3MDL_MGM_DEBUG == 1
|
||||
PeriodicOperationDivider *debugDivider;
|
||||
#endif
|
||||
bool periodicPrintout = false;
|
||||
PeriodicOperationDivider debugDivider = PeriodicOperationDivider(3);
|
||||
};
|
||||
|
||||
#endif /* MISSION_DEVICES_MGMLIS3MDLHANDLER_H_ */
|
||||
|
@ -10,11 +10,7 @@ MgmRM3100Handler::MgmRM3100Handler(object_id_t objectId, object_id_t deviceCommu
|
||||
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
|
||||
}
|
||||
transitionDelay(transitionDelay) {}
|
||||
|
||||
MgmRM3100Handler::~MgmRM3100Handler() {}
|
||||
|
||||
@ -337,23 +333,23 @@ ReturnValue_t MgmRM3100Handler::handleDataReadout(const uint8_t *packet) {
|
||||
float fieldStrengthY = fieldStrengthRawY * scaleFactorX;
|
||||
float fieldStrengthZ = fieldStrengthRawZ * scaleFactorX;
|
||||
|
||||
#if FSFW_HAL_RM3100_MGM_DEBUG == 1
|
||||
if (debugDivider->checkAndIncrement()) {
|
||||
if (periodicPrintout) {
|
||||
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;
|
||||
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);
|
||||
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);
|
||||
@ -365,3 +361,8 @@ ReturnValue_t MgmRM3100Handler::handleDataReadout(const uint8_t *packet) {
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
void MgmRM3100Handler::enablePeriodicPrintouts(bool enable, uint8_t divider) {
|
||||
periodicPrintout = enable;
|
||||
debugDivider.setDivider(divider);
|
||||
}
|
||||
|
@ -2,12 +2,8 @@
|
||||
#define MISSION_DEVICES_MGMRM3100HANDLER_H_
|
||||
|
||||
#include "devicedefinitions/MgmRM3100HandlerDefs.h"
|
||||
#include "fsfw/FSFW.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
|
||||
@ -33,6 +29,7 @@ class MgmRM3100Handler : public DeviceHandlerBase {
|
||||
uint32_t transitionDelay);
|
||||
virtual ~MgmRM3100Handler();
|
||||
|
||||
void enablePeriodicPrintouts(bool enable, uint8_t divider);
|
||||
/**
|
||||
* Configure device handler to go to normal mode after startup immediately
|
||||
* @param enable
|
||||
@ -98,9 +95,9 @@ class MgmRM3100Handler : public DeviceHandlerBase {
|
||||
size_t commandDataLen);
|
||||
|
||||
ReturnValue_t handleDataReadout(const uint8_t *packet);
|
||||
#if FSFW_HAL_RM3100_MGM_DEBUG == 1
|
||||
PeriodicOperationDivider *debugDivider;
|
||||
#endif
|
||||
|
||||
bool periodicPrintout = false;
|
||||
PeriodicOperationDivider debugDivider = PeriodicOperationDivider(3);
|
||||
};
|
||||
|
||||
#endif /* MISSION_DEVICEHANDLING_MGMRM3100HANDLER_H_ */
|
||||
|
@ -9,7 +9,9 @@ target_sources(${LIB_FSFW_NAME} PRIVATE
|
||||
)
|
||||
|
||||
if(FSFW_HAL_LINUX_ADD_PERIPHERAL_DRIVERS)
|
||||
if(FSFW_HAL_LINUX_ADD_LIBGPIOD)
|
||||
add_subdirectory(gpio)
|
||||
endif()
|
||||
add_subdirectory(spi)
|
||||
add_subdirectory(i2c)
|
||||
add_subdirectory(uart)
|
||||
|
@ -44,6 +44,7 @@ ReturnValue_t LinuxLibgpioIF::addGpios(GpioCookie* gpioCookie) {
|
||||
}
|
||||
|
||||
ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) {
|
||||
ReturnValue_t result = RETURN_OK;
|
||||
for (auto& gpioConfig : mapToAdd) {
|
||||
auto& gpioType = gpioConfig.second->gpioType;
|
||||
switch (gpioType) {
|
||||
@ -55,7 +56,7 @@ ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) {
|
||||
if (regularGpio == nullptr) {
|
||||
return GPIO_INVALID_INSTANCE;
|
||||
}
|
||||
configureGpioByChip(gpioConfig.first, *regularGpio);
|
||||
result = configureGpioByChip(gpioConfig.first, *regularGpio);
|
||||
break;
|
||||
}
|
||||
case (gpio::GpioTypes::GPIO_REGULAR_BY_LABEL): {
|
||||
@ -63,7 +64,7 @@ ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) {
|
||||
if (regularGpio == nullptr) {
|
||||
return GPIO_INVALID_INSTANCE;
|
||||
}
|
||||
configureGpioByLabel(gpioConfig.first, *regularGpio);
|
||||
result = configureGpioByLabel(gpioConfig.first, *regularGpio);
|
||||
break;
|
||||
}
|
||||
case (gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME): {
|
||||
@ -71,7 +72,7 @@ ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) {
|
||||
if (regularGpio == nullptr) {
|
||||
return GPIO_INVALID_INSTANCE;
|
||||
}
|
||||
configureGpioByLineName(gpioConfig.first, *regularGpio);
|
||||
result = configureGpioByLineName(gpioConfig.first, *regularGpio);
|
||||
break;
|
||||
}
|
||||
case (gpio::GpioTypes::CALLBACK): {
|
||||
@ -83,8 +84,11 @@ ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) {
|
||||
gpioCallback->initValue, gpioCallback->callbackArgs);
|
||||
}
|
||||
}
|
||||
if (result != RETURN_OK) {
|
||||
return GPIO_INIT_FAILED;
|
||||
}
|
||||
}
|
||||
return RETURN_OK;
|
||||
return result;
|
||||
}
|
||||
|
||||
ReturnValue_t LinuxLibgpioIF::configureGpioByLabel(gpioId_t gpioId,
|
||||
@ -161,11 +165,12 @@ ReturnValue_t LinuxLibgpioIF::configureRegularGpio(gpioId_t gpioId, struct gpiod
|
||||
consumer = regularGpio.consumer;
|
||||
/* Configure direction and add a description to the GPIO */
|
||||
switch (direction) {
|
||||
case (gpio::OUT): {
|
||||
result = gpiod_line_request_output(lineHandle, consumer.c_str(), regularGpio.initValue);
|
||||
case (gpio::Direction::OUT): {
|
||||
result = gpiod_line_request_output(lineHandle, consumer.c_str(),
|
||||
static_cast<int>(regularGpio.initValue));
|
||||
break;
|
||||
}
|
||||
case (gpio::IN): {
|
||||
case (gpio::Direction::IN): {
|
||||
result = gpiod_line_request_input(lineHandle, consumer.c_str());
|
||||
break;
|
||||
}
|
||||
@ -211,7 +216,7 @@ ReturnValue_t LinuxLibgpioIF::pullHigh(gpioId_t gpioId) {
|
||||
if (regularGpio == nullptr) {
|
||||
return GPIO_TYPE_FAILURE;
|
||||
}
|
||||
return driveGpio(gpioId, *regularGpio, gpio::HIGH);
|
||||
return driveGpio(gpioId, *regularGpio, gpio::Levels::HIGH);
|
||||
} else {
|
||||
auto gpioCallback = dynamic_cast<GpioCallback*>(gpioMapIter->second);
|
||||
if (gpioCallback->callback == nullptr) {
|
||||
@ -243,7 +248,7 @@ ReturnValue_t LinuxLibgpioIF::pullLow(gpioId_t gpioId) {
|
||||
if (regularGpio == nullptr) {
|
||||
return GPIO_TYPE_FAILURE;
|
||||
}
|
||||
return driveGpio(gpioId, *regularGpio, gpio::LOW);
|
||||
return driveGpio(gpioId, *regularGpio, gpio::Levels::LOW);
|
||||
} else {
|
||||
auto gpioCallback = dynamic_cast<GpioCallback*>(gpioMapIter->second);
|
||||
if (gpioCallback->callback == nullptr) {
|
||||
@ -258,11 +263,11 @@ ReturnValue_t LinuxLibgpioIF::pullLow(gpioId_t gpioId) {
|
||||
|
||||
ReturnValue_t LinuxLibgpioIF::driveGpio(gpioId_t gpioId, GpiodRegularBase& regularGpio,
|
||||
gpio::Levels logicLevel) {
|
||||
int result = gpiod_line_set_value(regularGpio.lineHandle, logicLevel);
|
||||
int result = gpiod_line_set_value(regularGpio.lineHandle, static_cast<int>(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;
|
||||
<< " to logic level " << static_cast<int>(logicLevel) << std::endl;
|
||||
#else
|
||||
sif::printWarning(
|
||||
"LinuxLibgpioIF::driveGpio: Failed to pull GPIO with ID %d to "
|
||||
|
@ -29,6 +29,8 @@ class LinuxLibgpioIF : public GpioIF, public SystemObject {
|
||||
HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 4);
|
||||
static constexpr ReturnValue_t GPIO_DUPLICATE_DETECTED =
|
||||
HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 5);
|
||||
static constexpr ReturnValue_t GPIO_INIT_FAILED =
|
||||
HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 6);
|
||||
|
||||
LinuxLibgpioIF(object_id_t objectId);
|
||||
virtual ~LinuxLibgpioIF();
|
||||
|
@ -1,4 +1,13 @@
|
||||
#include "fsfw_hal/linux/i2c/I2cComIF.h"
|
||||
#include "I2cComIF.h"
|
||||
|
||||
#include "fsfw/FSFW.h"
|
||||
#include "fsfw/serviceinterface.h"
|
||||
#include "fsfw_hal/linux/UnixFileGuard.h"
|
||||
#include "fsfw_hal/linux/utility.h"
|
||||
|
||||
#if FSFW_HAL_I2C_WIRETAPPING == 1
|
||||
#include "fsfw/globalfunctions/arrayprinter.h"
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
@ -8,11 +17,6 @@
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "fsfw/FSFW.h"
|
||||
#include "fsfw/serviceinterface.h"
|
||||
#include "fsfw_hal/linux/UnixFileGuard.h"
|
||||
#include "fsfw_hal/linux/utility.h"
|
||||
|
||||
I2cComIF::I2cComIF(object_id_t objectId) : SystemObject(objectId) {}
|
||||
|
||||
I2cComIF::~I2cComIF() {}
|
||||
@ -112,6 +116,11 @@ ReturnValue_t I2cComIF::sendMessage(CookieIF* cookie, const uint8_t* sendData, s
|
||||
#endif
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
|
||||
#if FSFW_HAL_I2C_WIRETAPPING == 1
|
||||
sif::info << "Sent I2C data to bus " << deviceFile << ":" << std::endl;
|
||||
arrayprinter::print(sendData, sendLen);
|
||||
#endif
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
@ -176,6 +185,11 @@ ReturnValue_t I2cComIF::requestReceiveMessage(CookieIF* cookie, size_t requestLe
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
|
||||
#if FSFW_HAL_I2C_WIRETAPPING == 1
|
||||
sif::info << "I2C read bytes from bus " << deviceFile << ":" << std::endl;
|
||||
arrayprinter::print(replyBuffer, requestLen);
|
||||
#endif
|
||||
|
||||
i2cDeviceMapIter->second.replyLen = requestLen;
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
ReturnValue_t gpio::createRpiGpioConfig(GpioCookie* cookie, gpioId_t gpioId, int bcmPin,
|
||||
std::string consumer, gpio::Direction direction,
|
||||
int initValue) {
|
||||
gpio::Levels initValue) {
|
||||
if (cookie == nullptr) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
|
@ -21,7 +21,8 @@ namespace gpio {
|
||||
* @return
|
||||
*/
|
||||
ReturnValue_t createRpiGpioConfig(GpioCookie* cookie, gpioId_t gpioId, int bcmPin,
|
||||
std::string consumer, gpio::Direction direction, int initValue);
|
||||
std::string consumer, gpio::Direction direction,
|
||||
gpio::Levels initValue);
|
||||
} // namespace gpio
|
||||
|
||||
#endif /* BSP_RPI_GPIO_GPIORPI_H_ */
|
||||
|
@ -401,4 +401,12 @@ void SpiComIF::setSpiSpeedAndMode(int spiFd, spi::SpiModes mode, uint32_t speed)
|
||||
if (retval != 0) {
|
||||
utility::handleIoctlError("SpiComIF::setSpiSpeedAndMode: Setting SPI speed failed");
|
||||
}
|
||||
// This updates the SPI clock default polarity. Only setting the mode does not update
|
||||
// the line state, which can be an issue on mode switches because the clock line will
|
||||
// switch the state after the chip select is pulled low
|
||||
clockUpdateTransfer.len = 0;
|
||||
retval = ioctl(spiFd, SPI_IOC_MESSAGE(1), &clockUpdateTransfer);
|
||||
if (retval != 0) {
|
||||
utility::handleIoctlError("SpiComIF::setSpiSpeedAndMode: Updating SPI default clock failed");
|
||||
}
|
||||
}
|
||||
|
@ -74,6 +74,7 @@ class SpiComIF : public DeviceCommunicationIF, public SystemObject {
|
||||
MutexIF* spiMutex = nullptr;
|
||||
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING;
|
||||
uint32_t timeoutMs = 20;
|
||||
spi_ioc_transfer clockUpdateTransfer = {};
|
||||
|
||||
using SpiDeviceMap = std::unordered_map<address_t, SpiInstance>;
|
||||
using SpiDeviceMapIter = SpiDeviceMap::iterator;
|
||||
|
@ -148,16 +148,16 @@ void UartComIF::setDatasizeOptions(struct termios* options, UartCookie* uartCook
|
||||
/* Clear size bits */
|
||||
options->c_cflag &= ~CSIZE;
|
||||
switch (uartCookie->getBitsPerWord()) {
|
||||
case 5:
|
||||
case BitsPerWord::BITS_5:
|
||||
options->c_cflag |= CS5;
|
||||
break;
|
||||
case 6:
|
||||
case BitsPerWord::BITS_6:
|
||||
options->c_cflag |= CS6;
|
||||
break;
|
||||
case 7:
|
||||
case BitsPerWord::BITS_7:
|
||||
options->c_cflag |= CS7;
|
||||
break;
|
||||
case 8:
|
||||
case BitsPerWord::BITS_8:
|
||||
options->c_cflag |= CS8;
|
||||
break;
|
||||
default:
|
||||
@ -193,82 +193,126 @@ void UartComIF::setFixedOptions(struct termios* options) {
|
||||
|
||||
void UartComIF::configureBaudrate(struct termios* options, UartCookie* uartCookie) {
|
||||
switch (uartCookie->getBaudrate()) {
|
||||
case 50:
|
||||
case UartBaudRate::RATE_50:
|
||||
cfsetispeed(options, B50);
|
||||
cfsetospeed(options, B50);
|
||||
break;
|
||||
case 75:
|
||||
case UartBaudRate::RATE_75:
|
||||
cfsetispeed(options, B75);
|
||||
cfsetospeed(options, B75);
|
||||
break;
|
||||
case 110:
|
||||
case UartBaudRate::RATE_110:
|
||||
cfsetispeed(options, B110);
|
||||
cfsetospeed(options, B110);
|
||||
break;
|
||||
case 134:
|
||||
case UartBaudRate::RATE_134:
|
||||
cfsetispeed(options, B134);
|
||||
cfsetospeed(options, B134);
|
||||
break;
|
||||
case 150:
|
||||
case UartBaudRate::RATE_150:
|
||||
cfsetispeed(options, B150);
|
||||
cfsetospeed(options, B150);
|
||||
break;
|
||||
case 200:
|
||||
case UartBaudRate::RATE_200:
|
||||
cfsetispeed(options, B200);
|
||||
cfsetospeed(options, B200);
|
||||
break;
|
||||
case 300:
|
||||
case UartBaudRate::RATE_300:
|
||||
cfsetispeed(options, B300);
|
||||
cfsetospeed(options, B300);
|
||||
break;
|
||||
case 600:
|
||||
case UartBaudRate::RATE_600:
|
||||
cfsetispeed(options, B600);
|
||||
cfsetospeed(options, B600);
|
||||
break;
|
||||
case 1200:
|
||||
case UartBaudRate::RATE_1200:
|
||||
cfsetispeed(options, B1200);
|
||||
cfsetospeed(options, B1200);
|
||||
break;
|
||||
case 1800:
|
||||
case UartBaudRate::RATE_1800:
|
||||
cfsetispeed(options, B1800);
|
||||
cfsetospeed(options, B1800);
|
||||
break;
|
||||
case 2400:
|
||||
case UartBaudRate::RATE_2400:
|
||||
cfsetispeed(options, B2400);
|
||||
cfsetospeed(options, B2400);
|
||||
break;
|
||||
case 4800:
|
||||
case UartBaudRate::RATE_4800:
|
||||
cfsetispeed(options, B4800);
|
||||
cfsetospeed(options, B4800);
|
||||
break;
|
||||
case 9600:
|
||||
case UartBaudRate::RATE_9600:
|
||||
cfsetispeed(options, B9600);
|
||||
cfsetospeed(options, B9600);
|
||||
break;
|
||||
case 19200:
|
||||
case UartBaudRate::RATE_19200:
|
||||
cfsetispeed(options, B19200);
|
||||
cfsetospeed(options, B19200);
|
||||
break;
|
||||
case 38400:
|
||||
case UartBaudRate::RATE_38400:
|
||||
cfsetispeed(options, B38400);
|
||||
cfsetospeed(options, B38400);
|
||||
break;
|
||||
case 57600:
|
||||
case UartBaudRate::RATE_57600:
|
||||
cfsetispeed(options, B57600);
|
||||
cfsetospeed(options, B57600);
|
||||
break;
|
||||
case 115200:
|
||||
case UartBaudRate::RATE_115200:
|
||||
cfsetispeed(options, B115200);
|
||||
cfsetospeed(options, B115200);
|
||||
break;
|
||||
case 230400:
|
||||
case UartBaudRate::RATE_230400:
|
||||
cfsetispeed(options, B230400);
|
||||
cfsetospeed(options, B230400);
|
||||
break;
|
||||
case 460800:
|
||||
case UartBaudRate::RATE_460800:
|
||||
cfsetispeed(options, B460800);
|
||||
cfsetospeed(options, B460800);
|
||||
break;
|
||||
case UartBaudRate::RATE_500000:
|
||||
cfsetispeed(options, B500000);
|
||||
cfsetospeed(options, B500000);
|
||||
break;
|
||||
case UartBaudRate::RATE_576000:
|
||||
cfsetispeed(options, B576000);
|
||||
cfsetospeed(options, B576000);
|
||||
break;
|
||||
case UartBaudRate::RATE_921600:
|
||||
cfsetispeed(options, B921600);
|
||||
cfsetospeed(options, B921600);
|
||||
break;
|
||||
case UartBaudRate::RATE_1000000:
|
||||
cfsetispeed(options, B1000000);
|
||||
cfsetospeed(options, B1000000);
|
||||
break;
|
||||
case UartBaudRate::RATE_1152000:
|
||||
cfsetispeed(options, B1152000);
|
||||
cfsetospeed(options, B1152000);
|
||||
break;
|
||||
case UartBaudRate::RATE_1500000:
|
||||
cfsetispeed(options, B1500000);
|
||||
cfsetospeed(options, B1500000);
|
||||
break;
|
||||
case UartBaudRate::RATE_2000000:
|
||||
cfsetispeed(options, B2000000);
|
||||
cfsetospeed(options, B2000000);
|
||||
break;
|
||||
case UartBaudRate::RATE_2500000:
|
||||
cfsetispeed(options, B2500000);
|
||||
cfsetospeed(options, B2500000);
|
||||
break;
|
||||
case UartBaudRate::RATE_3000000:
|
||||
cfsetispeed(options, B3000000);
|
||||
cfsetospeed(options, B3000000);
|
||||
break;
|
||||
case UartBaudRate::RATE_3500000:
|
||||
cfsetispeed(options, B3500000);
|
||||
cfsetospeed(options, B3500000);
|
||||
break;
|
||||
case UartBaudRate::RATE_4000000:
|
||||
cfsetispeed(options, B4000000);
|
||||
cfsetospeed(options, B4000000);
|
||||
break;
|
||||
default:
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "UartComIF::configureBaudrate: Baudrate not supported" << std::endl;
|
||||
@ -427,7 +471,7 @@ ReturnValue_t UartComIF::handleNoncanonicalRead(UartCookie& uartCookie, UartDevi
|
||||
auto bufferPtr = iter->second.replyBuffer.data();
|
||||
// Size check to prevent buffer overflow
|
||||
if (requestLen > uartCookie.getMaxReplyLen()) {
|
||||
#if OBSW_VERBOSE_LEVEL >= 1
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "UartComIF::requestReceiveMessage: Next read would cause overflow!"
|
||||
<< std::endl;
|
||||
|
@ -1,9 +1,9 @@
|
||||
#include "fsfw_hal/linux/uart/UartCookie.h"
|
||||
#include "UartCookie.h"
|
||||
|
||||
#include <fsfw/serviceinterface.h>
|
||||
|
||||
UartCookie::UartCookie(object_id_t handlerId, std::string deviceFile, UartModes uartMode,
|
||||
uint32_t baudrate, size_t maxReplyLen)
|
||||
UartBaudRate baudrate, size_t maxReplyLen)
|
||||
: handlerId(handlerId),
|
||||
deviceFile(deviceFile),
|
||||
uartMode(uartMode),
|
||||
@ -12,7 +12,7 @@ UartCookie::UartCookie(object_id_t handlerId, std::string deviceFile, UartModes
|
||||
|
||||
UartCookie::~UartCookie() {}
|
||||
|
||||
uint32_t UartCookie::getBaudrate() const { return baudrate; }
|
||||
UartBaudRate UartCookie::getBaudrate() const { return baudrate; }
|
||||
|
||||
size_t UartCookie::getMaxReplyLen() const { return maxReplyLen; }
|
||||
|
||||
@ -24,23 +24,9 @@ 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:
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::debug << "UartCookie::setBitsPerWord: Invalid bits per word specified" << std::endl;
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
bitsPerWord = bitsPerWord_;
|
||||
}
|
||||
void UartCookie::setBitsPerWord(BitsPerWord bitsPerWord_) { bitsPerWord = bitsPerWord_; }
|
||||
|
||||
uint8_t UartCookie::getBitsPerWord() const { return bitsPerWord; }
|
||||
BitsPerWord UartCookie::getBitsPerWord() const { return bitsPerWord; }
|
||||
|
||||
StopBits UartCookie::getStopBits() const { return stopBits; }
|
||||
|
||||
|
@ -12,6 +12,41 @@ enum class StopBits { ONE_STOP_BIT, TWO_STOP_BITS };
|
||||
|
||||
enum class UartModes { CANONICAL, NON_CANONICAL };
|
||||
|
||||
enum class BitsPerWord { BITS_5, BITS_6, BITS_7, BITS_8 };
|
||||
|
||||
enum class UartBaudRate {
|
||||
RATE_50,
|
||||
RATE_75,
|
||||
RATE_110,
|
||||
RATE_134,
|
||||
RATE_150,
|
||||
RATE_200,
|
||||
RATE_300,
|
||||
RATE_600,
|
||||
RATE_1200,
|
||||
RATE_1800,
|
||||
RATE_2400,
|
||||
RATE_4800,
|
||||
RATE_9600,
|
||||
RATE_19200,
|
||||
RATE_38400,
|
||||
RATE_57600,
|
||||
RATE_115200,
|
||||
RATE_230400,
|
||||
RATE_460800,
|
||||
RATE_500000,
|
||||
RATE_576000,
|
||||
RATE_921600,
|
||||
RATE_1000000,
|
||||
RATE_1152000,
|
||||
RATE_1500000,
|
||||
RATE_2000000,
|
||||
RATE_2500000,
|
||||
RATE_3000000,
|
||||
RATE_3500000,
|
||||
RATE_4000000
|
||||
};
|
||||
|
||||
/**
|
||||
* @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
|
||||
@ -27,25 +62,23 @@ class UartCookie : public CookieIF {
|
||||
* @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 baudrate The baudrate to use for input and output.
|
||||
* @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);
|
||||
UartCookie(object_id_t handlerId, std::string deviceFile, UartModes uartMode,
|
||||
UartBaudRate baudrate, size_t maxReplyLen);
|
||||
|
||||
virtual ~UartCookie();
|
||||
|
||||
uint32_t getBaudrate() const;
|
||||
UartBaudRate getBaudrate() const;
|
||||
size_t getMaxReplyLen() const;
|
||||
std::string getDeviceFile() const;
|
||||
Parity getParity() const;
|
||||
uint8_t getBitsPerWord() const;
|
||||
BitsPerWord getBitsPerWord() const;
|
||||
StopBits getStopBits() const;
|
||||
UartModes getUartMode() const;
|
||||
object_id_t getHandlerId() const;
|
||||
@ -76,7 +109,7 @@ class UartCookie : public CookieIF {
|
||||
/**
|
||||
* Function two set number of bits per UART frame.
|
||||
*/
|
||||
void setBitsPerWord(uint8_t bitsPerWord_);
|
||||
void setBitsPerWord(BitsPerWord bitsPerWord_);
|
||||
|
||||
/**
|
||||
* Function to specify the number of stopbits.
|
||||
@ -97,10 +130,10 @@ class UartCookie : public CookieIF {
|
||||
std::string deviceFile;
|
||||
const UartModes uartMode;
|
||||
bool flushInput = false;
|
||||
uint32_t baudrate;
|
||||
UartBaudRate baudrate;
|
||||
size_t maxReplyLen = 0;
|
||||
Parity parity = Parity::NONE;
|
||||
uint8_t bitsPerWord = 8;
|
||||
BitsPerWord bitsPerWord = BitsPerWord::BITS_8;
|
||||
uint8_t readCycles = 1;
|
||||
StopBits stopBits = StopBits::ONE_STOP_BIT;
|
||||
bool replySizeFixed = true;
|
||||
|
@ -21,7 +21,7 @@ using mspCb = void (*)(void);
|
||||
namespace spi {
|
||||
|
||||
struct MspCfgBase {
|
||||
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) {}
|
||||
|
@ -97,11 +97,11 @@ def handle_docs_type(args, build_dir_list: list):
|
||||
build_directory = determine_build_dir(build_dir_list)
|
||||
os.chdir(build_directory)
|
||||
if args.build:
|
||||
os.system("cmake --build . -j")
|
||||
cmd_runner("cmake --build . -j")
|
||||
if args.open:
|
||||
if not os.path.isfile("docs/sphinx/index.html"):
|
||||
# try again..
|
||||
os.system("cmake --build . -j")
|
||||
cmd_runner("cmake --build . -j")
|
||||
if not os.path.isfile("docs/sphinx/index.html"):
|
||||
print(
|
||||
"No Sphinx documentation file detected. "
|
||||
@ -143,25 +143,21 @@ def handle_tests_type(args, build_dir_list: list):
|
||||
if which("valgrind") is None:
|
||||
print("Please install valgrind first")
|
||||
sys.exit(1)
|
||||
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")
|
||||
cmd_runner("valgrind --leak-check=full ./fsfw-tests")
|
||||
os.chdir("..")
|
||||
|
||||
|
||||
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 ..")
|
||||
cmd_runner("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 ..")
|
||||
cmd_runner("cmake -DFSFW_OSAL=host -DFSFW_BUILD_DOCS=ON ..")
|
||||
os.chdir("..")
|
||||
|
||||
|
||||
@ -184,7 +180,7 @@ def check_for_cmake_build_dir(build_dir_list: list) -> list:
|
||||
def perform_lcov_operation(directory: str, chdir: bool):
|
||||
if chdir:
|
||||
os.chdir(directory)
|
||||
os.system("cmake --build . -- fsfw-tests_coverage -j")
|
||||
cmd_runner("cmake --build . -- fsfw-tests_coverage -j")
|
||||
|
||||
|
||||
def determine_build_dir(build_dir_list: List[str]):
|
||||
@ -206,5 +202,10 @@ def determine_build_dir(build_dir_list: List[str]):
|
||||
return build_directory
|
||||
|
||||
|
||||
def cmd_runner(cmd: str):
|
||||
print(f"Executing command: {cmd}")
|
||||
os.system(cmd)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
@ -1,3 +1,7 @@
|
||||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
||||
version.cpp
|
||||
)
|
||||
|
||||
# Core
|
||||
|
||||
add_subdirectory(action)
|
||||
|
@ -30,6 +30,10 @@
|
||||
#define FSFW_VERBOSE_LEVEL 1
|
||||
#endif /* FSFW_VERBOSE_LEVEL */
|
||||
|
||||
#ifndef FSFW_DISABLE_PRINTOUT
|
||||
#define FSFW_DISABLE_PRINTOUT 0
|
||||
#endif
|
||||
|
||||
#ifndef FSFW_USE_REALTIME_FOR_LINUX
|
||||
#define FSFW_USE_REALTIME_FOR_LINUX 0
|
||||
#endif /* FSFW_USE_REALTIME_FOR_LINUX */
|
||||
@ -57,16 +61,9 @@
|
||||
#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 */
|
||||
// Can be used for low-level debugging of the I2C bus
|
||||
#ifndef FSFW_HAL_I2C_WIRETAPPING
|
||||
#define FSFW_HAL_I2C_WIRETAPPING 0
|
||||
#endif
|
||||
|
||||
#endif /* FSFW_FSFW_H_ */
|
||||
|
@ -2,8 +2,8 @@
|
||||
#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@
|
||||
#define FSFW_VERSION_MAJOR @FSFW_VERSION@
|
||||
#define FSFW_VERSION_MINOR @FSFW_SUBVERSION@
|
||||
#define FSFW_VERSION_REVISION @FSFW_REVISION@
|
||||
|
||||
#endif /* FSFW_VERSION_H_ */
|
||||
|
@ -6,10 +6,13 @@
|
||||
#include <fsfw/cfdp/tlv/Tlv.h>
|
||||
#include <fsfw/cfdp/tlv/TlvIF.h>
|
||||
#include <fsfw/serialize/SerializeIF.h>
|
||||
#include <fsfw/serviceinterface/ServiceInterface.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#include "fsfw/FSFW.h"
|
||||
|
||||
namespace cfdp {
|
||||
|
||||
enum FilestoreActionCode {
|
||||
|
@ -1,7 +1,6 @@
|
||||
#ifndef FSFW_CONTROLLER_CONTROLLERBASE_H_
|
||||
#define FSFW_CONTROLLER_CONTROLLERBASE_H_
|
||||
|
||||
#include "fsfw/datapool/HkSwitchHelper.h"
|
||||
#include "fsfw/health/HasHealthIF.h"
|
||||
#include "fsfw/health/HealthHelper.h"
|
||||
#include "fsfw/modes/HasModesIF.h"
|
||||
|
@ -1,6 +1,4 @@
|
||||
target_sources(${LIB_FSFW_NAME}
|
||||
PRIVATE
|
||||
HkSwitchHelper.cpp
|
||||
PoolDataSetBase.cpp
|
||||
PoolEntry.cpp
|
||||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
||||
PoolDataSetBase.cpp
|
||||
PoolEntry.cpp
|
||||
)
|
@ -1,67 +0,0 @@
|
||||
#include "fsfw/datapool/HkSwitchHelper.h"
|
||||
|
||||
#include "fsfw/ipc/QueueFactory.h"
|
||||
|
||||
HkSwitchHelper::HkSwitchHelper(EventReportingProxyIF* eventProxy)
|
||||
: commandActionHelper(this), eventProxy(eventProxy) {
|
||||
actionQueue = QueueFactory::instance()->createMessageQueue();
|
||||
}
|
||||
|
||||
HkSwitchHelper::~HkSwitchHelper() { QueueFactory::instance()->deleteMessageQueue(actionQueue); }
|
||||
|
||||
ReturnValue_t HkSwitchHelper::initialize() {
|
||||
ReturnValue_t result = commandActionHelper.initialize();
|
||||
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ReturnValue_t HkSwitchHelper::performOperation(uint8_t operationCode) {
|
||||
CommandMessage command;
|
||||
while (actionQueue->receiveMessage(&command) == HasReturnvaluesIF::RETURN_OK) {
|
||||
ReturnValue_t result = commandActionHelper.handleReply(&command);
|
||||
if (result == HasReturnvaluesIF::RETURN_OK) {
|
||||
continue;
|
||||
}
|
||||
command.setToUnknownCommand();
|
||||
actionQueue->reply(&command);
|
||||
}
|
||||
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
void HkSwitchHelper::stepSuccessfulReceived(ActionId_t actionId, uint8_t step) {}
|
||||
|
||||
void HkSwitchHelper::stepFailedReceived(ActionId_t actionId, uint8_t step,
|
||||
ReturnValue_t returnCode) {
|
||||
eventProxy->forwardEvent(SWITCHING_TM_FAILED, returnCode, actionId);
|
||||
}
|
||||
|
||||
void HkSwitchHelper::dataReceived(ActionId_t actionId, const uint8_t* data, uint32_t size) {}
|
||||
|
||||
void HkSwitchHelper::completionSuccessfulReceived(ActionId_t actionId) {}
|
||||
|
||||
void HkSwitchHelper::completionFailedReceived(ActionId_t actionId, ReturnValue_t returnCode) {
|
||||
eventProxy->forwardEvent(SWITCHING_TM_FAILED, returnCode, actionId);
|
||||
}
|
||||
|
||||
ReturnValue_t HkSwitchHelper::switchHK(SerializeIF* sids, bool enable) {
|
||||
// ActionId_t action = HKService::DISABLE_HK;
|
||||
// if (enable) {
|
||||
// action = HKService::ENABLE_HK;
|
||||
// }
|
||||
//
|
||||
// ReturnValue_t result = commandActionHelper.commandAction(
|
||||
// objects::PUS_HK_SERVICE, action, sids);
|
||||
//
|
||||
// if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
// eventProxy->forwardEvent(SWITCHING_TM_FAILED, result);
|
||||
// }
|
||||
// return result;
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
MessageQueueIF* HkSwitchHelper::getCommandQueuePtr() { return actionQueue; }
|
@ -1,44 +0,0 @@
|
||||
#ifndef FRAMEWORK_DATAPOOL_HKSWITCHHELPER_H_
|
||||
#define FRAMEWORK_DATAPOOL_HKSWITCHHELPER_H_
|
||||
|
||||
#include "fsfw/action/CommandsActionsIF.h"
|
||||
#include "fsfw/events/EventReportingProxyIF.h"
|
||||
#include "fsfw/tasks/ExecutableObjectIF.h"
|
||||
|
||||
// TODO this class violations separation between mission and framework
|
||||
// but it is only a transitional solution until the Datapool is
|
||||
// implemented decentrally
|
||||
|
||||
class HkSwitchHelper : public ExecutableObjectIF, public CommandsActionsIF {
|
||||
public:
|
||||
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::HK;
|
||||
static const Event SWITCHING_TM_FAILED =
|
||||
MAKE_EVENT(1, severity::LOW); //!< Commanding the HK Service failed, p1: error code, p2
|
||||
//!< action: 0 disable / 1 enable
|
||||
|
||||
HkSwitchHelper(EventReportingProxyIF* eventProxy);
|
||||
virtual ~HkSwitchHelper();
|
||||
|
||||
ReturnValue_t initialize();
|
||||
|
||||
virtual ReturnValue_t performOperation(uint8_t operationCode = 0);
|
||||
|
||||
ReturnValue_t switchHK(SerializeIF* sids, bool enable);
|
||||
|
||||
virtual void setTaskIF(PeriodicTaskIF* task_){};
|
||||
|
||||
protected:
|
||||
virtual void stepSuccessfulReceived(ActionId_t actionId, uint8_t step);
|
||||
virtual void stepFailedReceived(ActionId_t actionId, uint8_t step, ReturnValue_t returnCode);
|
||||
virtual void dataReceived(ActionId_t actionId, const uint8_t* data, uint32_t size);
|
||||
virtual void completionSuccessfulReceived(ActionId_t actionId);
|
||||
virtual void completionFailedReceived(ActionId_t actionId, ReturnValue_t returnCode);
|
||||
virtual MessageQueueIF* getCommandQueuePtr();
|
||||
|
||||
private:
|
||||
CommandActionHelper commandActionHelper;
|
||||
MessageQueueIF* actionQueue;
|
||||
EventReportingProxyIF* eventProxy;
|
||||
};
|
||||
|
||||
#endif /* FRAMEWORK_DATAPOOL_HKSWITCHHELPER_H_ */
|
@ -84,8 +84,8 @@ ReturnValue_t LocalDataPoolManager::initializeHousekeepingPoolEntriesOnce() {
|
||||
return result;
|
||||
}
|
||||
|
||||
printWarningOrError(sif::OutputTypes::OUT_WARNING, "initialize", HasReturnvaluesIF::RETURN_FAILED,
|
||||
"The map should only be initialized once");
|
||||
printWarningOrError(sif::OutputTypes::OUT_WARNING, "initializeHousekeepingPoolEntriesOnce",
|
||||
HasReturnvaluesIF::RETURN_FAILED, "The map should only be initialized once");
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
@ -787,6 +787,10 @@ ReturnValue_t LocalDataPoolManager::generateSetStructurePacket(sid_t sid, bool i
|
||||
// Serialize set packet into store.
|
||||
size_t size = 0;
|
||||
result = setPacket.serialize(&storePtr, &size, expectedSize, SerializeIF::Endianness::BIG);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
ipcStore->deleteData(storeId);
|
||||
return result;
|
||||
}
|
||||
if (expectedSize != size) {
|
||||
printWarningOrError(sif::OutputTypes::OUT_WARNING, "generateSetStructurePacket",
|
||||
HasReturnvaluesIF::RETURN_FAILED,
|
||||
@ -801,7 +805,10 @@ ReturnValue_t LocalDataPoolManager::generateSetStructurePacket(sid_t sid, bool i
|
||||
HousekeepingMessage::setHkStuctureReportReply(&reply, sid, storeId);
|
||||
}
|
||||
|
||||
hkQueue->reply(&reply);
|
||||
result = hkQueue->reply(&reply);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
ipcStore->deleteData(storeId);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -47,13 +47,14 @@ LocalPoolObjectBase::LocalPoolObjectBase(object_id_t poolOwner, lp_id_t poolId,
|
||||
HasLocalDataPoolIF* hkOwner = ObjectManager::instance()->get<HasLocalDataPoolIF>(poolOwner);
|
||||
if (hkOwner == nullptr) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "LocalPoolVariable: The supplied pool owner did not implement the correct "
|
||||
"interface HasLocalDataPoolIF!"
|
||||
<< std::endl;
|
||||
sif::error << "LocalPoolVariable: The supplied pool owner 0x" << std::hex << poolOwner
|
||||
<< std::dec << " did not implement the correct interface "
|
||||
<< "HasLocalDataPoolIF" << std::endl;
|
||||
#else
|
||||
sif::printError(
|
||||
"LocalPoolVariable: The supplied pool owner did not implement the correct "
|
||||
"interface HasLocalDataPoolIF!\n");
|
||||
"LocalPoolVariable: The supplied pool owner 0x%08x did not implement the correct "
|
||||
"interface HasLocalDataPoolIF\n",
|
||||
poolOwner);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ class StaticLocalDataSet : public LocalPoolDataSetBase {
|
||||
}
|
||||
|
||||
private:
|
||||
std::array<PoolVariableIF*, NUM_VARIABLES> poolVarList;
|
||||
std::array<PoolVariableIF*, NUM_VARIABLES> poolVarList = {};
|
||||
};
|
||||
|
||||
#endif /* FSFW_DATAPOOLLOCAL_STATICLOCALDATASET_H_ */
|
||||
|
@ -410,7 +410,7 @@ ReturnValue_t DeviceHandlerBase::insertInCommandAndReplyMap(
|
||||
DeviceCommandId_t deviceCommand, uint16_t maxDelayCycles, LocalPoolDataSetBase* replyDataSet,
|
||||
size_t replyLen, bool periodic, bool hasDifferentReplyId, DeviceCommandId_t replyId) {
|
||||
// No need to check, as we may try to insert multiple times.
|
||||
insertInCommandMap(deviceCommand);
|
||||
insertInCommandMap(deviceCommand, hasDifferentReplyId, replyId);
|
||||
if (hasDifferentReplyId) {
|
||||
return insertInReplyMap(replyId, maxDelayCycles, replyDataSet, replyLen, periodic);
|
||||
} else {
|
||||
@ -437,11 +437,15 @@ ReturnValue_t DeviceHandlerBase::insertInReplyMap(DeviceCommandId_t replyId,
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t DeviceHandlerBase::insertInCommandMap(DeviceCommandId_t deviceCommand) {
|
||||
ReturnValue_t DeviceHandlerBase::insertInCommandMap(DeviceCommandId_t deviceCommand,
|
||||
bool useAlternativeReply,
|
||||
DeviceCommandId_t alternativeReplyId) {
|
||||
DeviceCommandInfo info;
|
||||
info.expectedReplies = 0;
|
||||
info.isExecuting = false;
|
||||
info.sendReplyTo = NO_COMMANDER;
|
||||
info.useAlternativeReplyId = alternativeReplyId;
|
||||
info.alternativeReplyId = alternativeReplyId;
|
||||
auto resultPair = deviceCommandMap.emplace(deviceCommand, info);
|
||||
if (resultPair.second) {
|
||||
return RETURN_OK;
|
||||
@ -451,12 +455,20 @@ ReturnValue_t DeviceHandlerBase::insertInCommandMap(DeviceCommandId_t deviceComm
|
||||
}
|
||||
|
||||
size_t DeviceHandlerBase::getNextReplyLength(DeviceCommandId_t commandId) {
|
||||
DeviceReplyIter iter = deviceReplyMap.find(commandId);
|
||||
if (iter != deviceReplyMap.end()) {
|
||||
return iter->second.replyLen;
|
||||
DeviceCommandId_t replyId = NO_COMMAND_ID;
|
||||
DeviceCommandMap::iterator command = cookieInfo.pendingCommand;
|
||||
if (command->second.useAlternativeReplyId) {
|
||||
replyId = command->second.alternativeReplyId;
|
||||
} else {
|
||||
return 0;
|
||||
replyId = commandId;
|
||||
}
|
||||
DeviceReplyIter iter = deviceReplyMap.find(replyId);
|
||||
if (iter != deviceReplyMap.end()) {
|
||||
if (iter->second.delayCycles != 0) {
|
||||
return iter->second.replyLen;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ReturnValue_t DeviceHandlerBase::updateReplyMapEntry(DeviceCommandId_t deviceReply,
|
||||
@ -651,7 +663,9 @@ void DeviceHandlerBase::doGetWrite() {
|
||||
|
||||
// We need to distinguish here, because a raw command never expects a reply.
|
||||
//(Could be done in eRIRM, but then child implementations need to be careful.
|
||||
result = enableReplyInReplyMap(cookieInfo.pendingCommand);
|
||||
DeviceCommandMap::iterator command = cookieInfo.pendingCommand;
|
||||
result = enableReplyInReplyMap(command, 1, command->second.useAlternativeReplyId,
|
||||
command->second.alternativeReplyId);
|
||||
} else {
|
||||
// always generate a failure event, so that FDIR knows what's up
|
||||
triggerEvent(DEVICE_SENDING_COMMAND_FAILED, result, cookieInfo.pendingCommand->first);
|
||||
@ -824,7 +838,7 @@ void DeviceHandlerBase::handleReply(const uint8_t* receivedData, DeviceCommandId
|
||||
}
|
||||
|
||||
ReturnValue_t DeviceHandlerBase::getStorageData(store_address_t storageAddress, uint8_t** data,
|
||||
uint32_t* len) {
|
||||
size_t* len) {
|
||||
size_t lenTmp;
|
||||
|
||||
if (IPCStore == nullptr) {
|
||||
|
@ -478,7 +478,9 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
* @return - @c RETURN_OK when the command was successfully inserted,
|
||||
* - @c RETURN_FAILED else.
|
||||
*/
|
||||
ReturnValue_t insertInCommandMap(DeviceCommandId_t deviceCommand);
|
||||
ReturnValue_t insertInCommandMap(DeviceCommandId_t deviceCommand,
|
||||
bool useAlternativeReply = false,
|
||||
DeviceCommandId_t alternativeReplyId = 0);
|
||||
|
||||
/**
|
||||
* Enables a periodic reply for a given command. It sets to delay cycles to the specified
|
||||
@ -673,7 +675,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
//! Pointer to the raw packet that will be sent.
|
||||
uint8_t *rawPacket = nullptr;
|
||||
//! Size of the #rawPacket.
|
||||
uint32_t rawPacketLen = 0;
|
||||
size_t rawPacketLen = 0;
|
||||
|
||||
/**
|
||||
* The mode the device handler is currently in.
|
||||
@ -751,6 +753,8 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
//! if this is != NO_COMMANDER, DHB was commanded externally and shall
|
||||
//! report everything to commander.
|
||||
MessageQueueId_t sendReplyTo;
|
||||
bool useAlternativeReplyId;
|
||||
DeviceCommandId_t alternativeReplyId;
|
||||
};
|
||||
using DeviceCommandMap = std::map<DeviceCommandId_t, DeviceCommandInfo>;
|
||||
/**
|
||||
@ -1250,7 +1254,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
* - @c RETURN_FAILED IPCStore is nullptr
|
||||
* - the return value from the IPCStore if it was not @c RETURN_OK
|
||||
*/
|
||||
ReturnValue_t getStorageData(store_address_t storageAddress, uint8_t **data, uint32_t *len);
|
||||
ReturnValue_t getStorageData(store_address_t storageAddress, uint8_t **data, size_t *len);
|
||||
|
||||
/**
|
||||
* @param modeTo either @c MODE_ON, MODE_NORMAL or MODE_RAW, nothing else!
|
||||
|
@ -7,8 +7,14 @@
|
||||
// could be moved to more suitable location
|
||||
#include <events/subsystemIdRanges.h>
|
||||
|
||||
typedef uint16_t EventId_t;
|
||||
typedef uint8_t EventSeverity_t;
|
||||
using EventId_t = uint16_t;
|
||||
using EventSeverity_t = uint8_t;
|
||||
using UniqueEventId_t = uint8_t;
|
||||
|
||||
namespace severity {
|
||||
enum Severity : EventSeverity_t { INFO = 1, LOW = 2, MEDIUM = 3, HIGH = 4 };
|
||||
|
||||
} // namespace severity
|
||||
|
||||
#define MAKE_EVENT(id, severity) (((severity) << 16) + (SUBSYSTEM_ID * 100) + (id))
|
||||
|
||||
@ -20,18 +26,11 @@ constexpr EventId_t getEventId(Event event) { return (event & 0xFFFF); }
|
||||
|
||||
constexpr EventSeverity_t getSeverity(Event event) { return ((event >> 16) & 0xFF); }
|
||||
|
||||
constexpr Event makeEvent(uint8_t subsystemId, uint8_t uniqueEventId,
|
||||
constexpr Event makeEvent(uint8_t subsystemId, UniqueEventId_t uniqueEventId,
|
||||
EventSeverity_t eventSeverity) {
|
||||
return (eventSeverity << 16) + (subsystemId * 100) + uniqueEventId;
|
||||
}
|
||||
|
||||
} // namespace event
|
||||
|
||||
namespace severity {
|
||||
static constexpr EventSeverity_t INFO = 1;
|
||||
static constexpr EventSeverity_t LOW = 2;
|
||||
static constexpr EventSeverity_t MEDIUM = 3;
|
||||
static constexpr EventSeverity_t HIGH = 4;
|
||||
} // namespace severity
|
||||
|
||||
#endif /* EVENTOBJECT_EVENT_H_ */
|
||||
|
@ -28,7 +28,7 @@ const uint16_t CRC::crc16ccitt_table[256] = {
|
||||
|
||||
// CRC implementation
|
||||
uint16_t CRC::crc16ccitt(uint8_t const input[], uint32_t length, uint16_t startingCrc) {
|
||||
uint8_t *data = (uint8_t *)input;
|
||||
const uint8_t *data = static_cast<const uint8_t *>(input);
|
||||
unsigned int tbl_idx;
|
||||
|
||||
while (length--) {
|
||||
@ -39,88 +39,4 @@ uint16_t CRC::crc16ccitt(uint8_t const input[], uint32_t length, uint16_t starti
|
||||
}
|
||||
return startingCrc & 0xffff;
|
||||
|
||||
// The part below is not used!
|
||||
// bool temr[16];
|
||||
// bool xor_out[16];
|
||||
// bool r[16];
|
||||
// bool d[8];
|
||||
// uint16_t crc_value = 0;
|
||||
//
|
||||
//
|
||||
// for (int i=0; i<16 ;i++) {
|
||||
// temr[i] = false;
|
||||
// xor_out[i] = false;
|
||||
// }
|
||||
//
|
||||
//
|
||||
// for (int i=0; i<16 ;i++)
|
||||
// r[i] = true; // initialize with 0xFFFF
|
||||
//
|
||||
//
|
||||
//
|
||||
// for (int j=0; j<length ;j++)
|
||||
// {
|
||||
//
|
||||
// for (int i=0; i<8 ;i++)
|
||||
// if ((input[j] & 1<<i) == 1<<i)
|
||||
// d[7-i]=true; // reverse input data
|
||||
// else
|
||||
// d[7-i]=false; // reverse input data
|
||||
//
|
||||
//
|
||||
//
|
||||
// temr[0] = d[4] ^ d[0];
|
||||
// temr[1] = d[5] ^ d[1];
|
||||
// temr[2] = d[6] ^ d[2];
|
||||
// temr[3] = d[7] ^ d[3];
|
||||
// temr[4] = r[12] ^ r[8];
|
||||
// temr[5] = r[13] ^ r[9];
|
||||
// temr[6] = r[14] ^ r[10];
|
||||
// temr[7] = r[15] ^ r[11];
|
||||
// temr[8] = d[4] ^ r[12];
|
||||
// temr[9] = d[5] ^ r[13];
|
||||
// temr[10] = d[6] ^ r[14];
|
||||
// temr[11] = d[7] ^ r[15];
|
||||
// temr[12] = temr[0] ^ temr[4];
|
||||
// temr[13] = temr[1] ^ temr[5];
|
||||
// temr[14] = temr[2] ^ temr[6];
|
||||
// temr[15] = temr[3] ^ temr[7];
|
||||
//
|
||||
//
|
||||
// xor_out[0] = temr[12];
|
||||
// xor_out[1] = temr[13];
|
||||
// xor_out[2] = temr[14];
|
||||
// xor_out[3] = temr[15];
|
||||
// xor_out[4] = temr[8];
|
||||
// xor_out[5] = temr[9] ^ temr[12];
|
||||
// xor_out[6] = temr[10] ^ temr[13];
|
||||
// xor_out[7] = temr[11] ^ temr[14];
|
||||
// xor_out[8] = temr[15] ^ r[0];
|
||||
// xor_out[9] = temr[8] ^ r[1];
|
||||
// xor_out[10] = temr[9] ^ r[2];
|
||||
// xor_out[11] = temr[10] ^ r[3];
|
||||
// xor_out[12] = temr[11] ^ temr[12] ^ r[4];
|
||||
// xor_out[13] = temr[13] ^ r[5];
|
||||
// xor_out[14] = temr[14] ^ r[6];
|
||||
// xor_out[15] = temr[15] ^ r[7];
|
||||
//
|
||||
// for (int i=0; i<16 ;i++)
|
||||
// {
|
||||
// r[i]= xor_out[i] ;
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//
|
||||
//
|
||||
//
|
||||
// for (int i=0; i<16 ;i++)
|
||||
// {
|
||||
// if (xor_out[i] == true)
|
||||
// crc_value = crc_value + pow(2,(15 -i)); // reverse CrC result before
|
||||
//Final XOR
|
||||
// }
|
||||
//
|
||||
// crc_value = 0;// for debug mode
|
||||
// return (crc_value);
|
||||
|
||||
} /* Calculate_CRC() */
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "fsfw/globalfunctions/arrayprinter.h"
|
||||
|
||||
#include <bitset>
|
||||
#include <cmath>
|
||||
|
||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||
|
||||
@ -68,7 +69,7 @@ void arrayprinter::printHex(const uint8_t *data, size_t size, size_t maxCharPerL
|
||||
currentPos += snprintf(printBuffer + currentPos, 6, "%02x", data[i]);
|
||||
if (i < size - 1) {
|
||||
currentPos += sprintf(printBuffer + currentPos, ",");
|
||||
if (i > 0 and (i + 1) % maxCharPerLine == 0) {
|
||||
if ((i + 1) % maxCharPerLine == 0) {
|
||||
currentPos += sprintf(printBuffer + currentPos, "\n");
|
||||
}
|
||||
}
|
||||
@ -97,20 +98,21 @@ void arrayprinter::printDec(const uint8_t *data, size_t size, size_t maxCharPerL
|
||||
}
|
||||
std::cout << "]" << std::endl;
|
||||
#else
|
||||
// General format: 32, 243, -12 so it is number of chars times 5
|
||||
// General format: 32,243,-12 so it is number of chars times 4
|
||||
// plus line break plus small safety margin.
|
||||
char printBuffer[(size + 1) * 5 + 1] = {};
|
||||
uint16_t expectedLines = ceil((double)size / maxCharPerLine);
|
||||
char printBuffer[size * 4 + 1 + expectedLines] = {};
|
||||
size_t currentPos = 0;
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
// To avoid buffer overflows.
|
||||
if (sizeof(printBuffer) - currentPos <= 5) {
|
||||
if (sizeof(printBuffer) - currentPos <= 4) {
|
||||
break;
|
||||
}
|
||||
|
||||
currentPos += snprintf(printBuffer + currentPos, 3, "%d", data[i]);
|
||||
currentPos += snprintf(printBuffer + currentPos, 4, "%d", data[i]);
|
||||
if (i < size - 1) {
|
||||
currentPos += sprintf(printBuffer + currentPos, ",");
|
||||
if (i > 0 and (i + 1) % maxCharPerLine == 0) {
|
||||
if ((i + 1) % maxCharPerLine == 0) {
|
||||
currentPos += sprintf(printBuffer + currentPos, "\n");
|
||||
}
|
||||
}
|
||||
|
@ -57,6 +57,9 @@ ReturnValue_t InternalErrorReporter::performOperation(uint8_t opCode) {
|
||||
internalErrorDataset.storeHits.value += newStoreHits;
|
||||
internalErrorDataset.tmHits.value += newTmHits;
|
||||
internalErrorDataset.setValidity(true, true);
|
||||
if ((newQueueHits != 0) or (newStoreHits != 0) or (newTmHits != 0)) {
|
||||
internalErrorDataset.setChanged(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -77,14 +80,6 @@ uint32_t InternalErrorReporter::getAndResetQueueHits() {
|
||||
return value;
|
||||
}
|
||||
|
||||
uint32_t InternalErrorReporter::getQueueHits() {
|
||||
uint32_t value;
|
||||
mutex->lockMutex(timeoutType, timeoutMs);
|
||||
value = queueHits;
|
||||
mutex->unlockMutex();
|
||||
return value;
|
||||
}
|
||||
|
||||
void InternalErrorReporter::incrementQueueHits() {
|
||||
mutex->lockMutex(timeoutType, timeoutMs);
|
||||
queueHits++;
|
||||
@ -100,14 +95,6 @@ uint32_t InternalErrorReporter::getAndResetTmHits() {
|
||||
return value;
|
||||
}
|
||||
|
||||
uint32_t InternalErrorReporter::getTmHits() {
|
||||
uint32_t value;
|
||||
mutex->lockMutex(timeoutType, timeoutMs);
|
||||
value = tmHits;
|
||||
mutex->unlockMutex();
|
||||
return value;
|
||||
}
|
||||
|
||||
void InternalErrorReporter::incrementTmHits() {
|
||||
mutex->lockMutex(timeoutType, timeoutMs);
|
||||
tmHits++;
|
||||
@ -125,14 +112,6 @@ uint32_t InternalErrorReporter::getAndResetStoreHits() {
|
||||
return value;
|
||||
}
|
||||
|
||||
uint32_t InternalErrorReporter::getStoreHits() {
|
||||
uint32_t value;
|
||||
mutex->lockMutex(timeoutType, timeoutMs);
|
||||
value = storeHits;
|
||||
mutex->unlockMutex();
|
||||
return value;
|
||||
}
|
||||
|
||||
void InternalErrorReporter::incrementStoreHits() {
|
||||
mutex->lockMutex(timeoutType, timeoutMs);
|
||||
storeHits++;
|
||||
|
@ -46,11 +46,11 @@ class InternalErrorReporter : public SystemObject,
|
||||
virtual ReturnValue_t initializeAfterTaskCreation() override;
|
||||
virtual ReturnValue_t performOperation(uint8_t opCode) override;
|
||||
|
||||
virtual void queueMessageNotSent();
|
||||
virtual void queueMessageNotSent() override;
|
||||
|
||||
virtual void lostTm();
|
||||
virtual void lostTm() override;
|
||||
|
||||
virtual void storeFull();
|
||||
virtual void storeFull() override;
|
||||
|
||||
virtual void setTaskIF(PeriodicTaskIF* task) override;
|
||||
|
||||
@ -74,15 +74,12 @@ class InternalErrorReporter : public SystemObject,
|
||||
uint32_t storeHits = 0;
|
||||
|
||||
uint32_t getAndResetQueueHits();
|
||||
uint32_t getQueueHits();
|
||||
void incrementQueueHits();
|
||||
|
||||
uint32_t getAndResetTmHits();
|
||||
uint32_t getTmHits();
|
||||
void incrementTmHits();
|
||||
|
||||
uint32_t getAndResetStoreHits();
|
||||
uint32_t getStoreHits();
|
||||
void incrementStoreHits();
|
||||
};
|
||||
|
||||
|
@ -1,22 +1,34 @@
|
||||
#ifndef INTERNALERRORREPORTERIF_H_
|
||||
#define INTERNALERRORREPORTERIF_H_
|
||||
|
||||
/**
|
||||
* @brief Interface which is used to report internal errors like full message queues or stores.
|
||||
* @details
|
||||
* This interface smust be used for the InteralErrorReporter object.
|
||||
* It should be used to indicate that there was a Problem with Queues or Stores.
|
||||
*
|
||||
* It can be used to report missing Telemetry which could not be sent due to a internal problem.
|
||||
*
|
||||
*/
|
||||
class InternalErrorReporterIF {
|
||||
public:
|
||||
virtual ~InternalErrorReporterIF() {}
|
||||
|
||||
/**
|
||||
* Thread safe
|
||||
* @brief Function to be called if a message queue could not be sent.
|
||||
* @details OSAL Implementations should call this function to indicate that
|
||||
* a message was lost.
|
||||
*
|
||||
* Implementations are required to be Thread safe
|
||||
*/
|
||||
virtual void queueMessageNotSent() = 0;
|
||||
|
||||
/**
|
||||
* Thread safe
|
||||
* @brief Function to be called if Telemetry could not be sent
|
||||
* @details Implementations must be Thread safe
|
||||
*/
|
||||
virtual void lostTm() = 0;
|
||||
|
||||
/**
|
||||
* Thread safe
|
||||
* @brief Function to be called if a onboard storage is full
|
||||
* @details Implementations must be Thread safe
|
||||
*/
|
||||
virtual void storeFull() = 0;
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
target_sources(${LIB_FSFW_NAME}
|
||||
PRIVATE
|
||||
CommandMessage.cpp
|
||||
CommandMessageCleaner.cpp
|
||||
MessageQueueMessage.cpp
|
||||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
||||
CommandMessage.cpp
|
||||
CommandMessageCleaner.cpp
|
||||
MessageQueueMessage.cpp
|
||||
MessageQueueBase.cpp
|
||||
)
|
54
src/fsfw/ipc/MessageQueueBase.cpp
Normal file
54
src/fsfw/ipc/MessageQueueBase.cpp
Normal file
@ -0,0 +1,54 @@
|
||||
#include "MessageQueueBase.h"
|
||||
|
||||
MessageQueueBase::MessageQueueBase(MessageQueueId_t id, MessageQueueId_t defaultDest, MqArgs* args)
|
||||
: id(id) {
|
||||
this->defaultDest = defaultDest;
|
||||
if (args != nullptr) {
|
||||
this->args = *args;
|
||||
}
|
||||
}
|
||||
|
||||
MessageQueueBase::~MessageQueueBase() {}
|
||||
|
||||
ReturnValue_t MessageQueueBase::sendToDefault(MessageQueueMessageIF* message) {
|
||||
return sendToDefaultFrom(message, this->getId(), false);
|
||||
}
|
||||
|
||||
ReturnValue_t MessageQueueBase::reply(MessageQueueMessageIF* message) {
|
||||
if (this->last != MessageQueueIF::NO_QUEUE) {
|
||||
return sendMessageFrom(this->last, message, this->getId());
|
||||
} else {
|
||||
return NO_REPLY_PARTNER;
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t MessageQueueBase::receiveMessage(MessageQueueMessageIF* message,
|
||||
MessageQueueId_t* receivedFrom) {
|
||||
ReturnValue_t status = this->receiveMessage(message);
|
||||
*receivedFrom = this->last;
|
||||
return status;
|
||||
}
|
||||
|
||||
MessageQueueId_t MessageQueueBase::getLastPartner() const { return last; }
|
||||
|
||||
MessageQueueId_t MessageQueueBase::getId() const { return id; }
|
||||
|
||||
MqArgs& MessageQueueBase::getMqArgs() { return args; }
|
||||
|
||||
void MessageQueueBase::setDefaultDestination(MessageQueueId_t defaultDestination) {
|
||||
this->defaultDest = defaultDestination;
|
||||
}
|
||||
|
||||
MessageQueueId_t MessageQueueBase::getDefaultDestination() const { return defaultDest; }
|
||||
|
||||
bool MessageQueueBase::isDefaultDestinationSet() const { return (defaultDest != NO_QUEUE); }
|
||||
|
||||
ReturnValue_t MessageQueueBase::sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
||||
bool ignoreFault) {
|
||||
return sendMessageFrom(sendTo, message, this->getId(), false);
|
||||
}
|
||||
|
||||
ReturnValue_t MessageQueueBase::sendToDefaultFrom(MessageQueueMessageIF* message,
|
||||
MessageQueueId_t sentFrom, bool ignoreFault) {
|
||||
return sendMessageFrom(defaultDest, message, sentFrom, ignoreFault);
|
||||
}
|
40
src/fsfw/ipc/MessageQueueBase.h
Normal file
40
src/fsfw/ipc/MessageQueueBase.h
Normal file
@ -0,0 +1,40 @@
|
||||
#ifndef FSFW_SRC_FSFW_IPC_MESSAGEQUEUEBASE_H_
|
||||
#define FSFW_SRC_FSFW_IPC_MESSAGEQUEUEBASE_H_
|
||||
|
||||
#include <fsfw/ipc/MessageQueueIF.h>
|
||||
#include <fsfw/ipc/definitions.h>
|
||||
|
||||
class MessageQueueBase : public MessageQueueIF {
|
||||
public:
|
||||
MessageQueueBase(MessageQueueId_t id, MessageQueueId_t defaultDest, MqArgs* mqArgs);
|
||||
virtual ~MessageQueueBase();
|
||||
|
||||
// Default implementations for MessageQueueIF where possible
|
||||
virtual MessageQueueId_t getLastPartner() const override;
|
||||
virtual MessageQueueId_t getId() const override;
|
||||
virtual MqArgs& getMqArgs() override;
|
||||
virtual void setDefaultDestination(MessageQueueId_t defaultDestination) override;
|
||||
virtual MessageQueueId_t getDefaultDestination() const override;
|
||||
virtual bool isDefaultDestinationSet() const override;
|
||||
virtual ReturnValue_t sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
||||
bool ignoreFault) override;
|
||||
virtual ReturnValue_t sendToDefault(MessageQueueMessageIF* message) override;
|
||||
virtual ReturnValue_t reply(MessageQueueMessageIF* message) override;
|
||||
virtual ReturnValue_t receiveMessage(MessageQueueMessageIF* message,
|
||||
MessageQueueId_t* receivedFrom) override;
|
||||
virtual ReturnValue_t sendToDefaultFrom(MessageQueueMessageIF* message, MessageQueueId_t sentFrom,
|
||||
bool ignoreFault = false) override;
|
||||
|
||||
// OSAL specific, forward the abstract function
|
||||
virtual ReturnValue_t receiveMessage(MessageQueueMessageIF* message) = 0;
|
||||
virtual ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
||||
MessageQueueId_t sentFrom, bool ignoreFault = false) = 0;
|
||||
|
||||
protected:
|
||||
MessageQueueId_t id = MessageQueueIF::NO_QUEUE;
|
||||
MessageQueueId_t last = MessageQueueIF::NO_QUEUE;
|
||||
MessageQueueId_t defaultDest = MessageQueueIF::NO_QUEUE;
|
||||
MqArgs args = {};
|
||||
};
|
||||
|
||||
#endif /* FSFW_SRC_FSFW_IPC_MESSAGEQUEUEBASE_H_ */
|
@ -1,6 +1,8 @@
|
||||
#ifndef FSFW_IPC_MESSAGEQUEUEIF_H_
|
||||
#define FSFW_IPC_MESSAGEQUEUEIF_H_
|
||||
|
||||
#include <fsfw/ipc/definitions.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "../returnvalues/HasReturnvaluesIF.h"
|
||||
@ -44,8 +46,8 @@ class MessageQueueIF {
|
||||
virtual ReturnValue_t reply(MessageQueueMessageIF* message) = 0;
|
||||
|
||||
/**
|
||||
* @brief This function reads available messages from the message queue
|
||||
* and returns the sender.
|
||||
* @brief This function reads available messages from the message queue and returns the
|
||||
* sender.
|
||||
* @details
|
||||
* It works identically to the other receiveMessage call, but in addition
|
||||
* returns the sender's queue id.
|
||||
@ -78,19 +80,16 @@ class MessageQueueIF {
|
||||
*/
|
||||
virtual ReturnValue_t flush(uint32_t* count) = 0;
|
||||
/**
|
||||
* @brief This method returns the message queue
|
||||
* id of the last communication partner.
|
||||
* @brief This method returns the message queue ID of the last communication partner.
|
||||
*/
|
||||
virtual MessageQueueId_t getLastPartner() const = 0;
|
||||
/**
|
||||
* @brief This method returns the message queue
|
||||
* id of this class's message queue.
|
||||
* @brief This method returns the message queue ID of this class's message queue.
|
||||
*/
|
||||
virtual MessageQueueId_t getId() const = 0;
|
||||
|
||||
/**
|
||||
* @brief With the sendMessage call, a queue message
|
||||
* is sent to a receiving queue.
|
||||
* @brief With the sendMessage call, a queue message is sent to a receiving queue.
|
||||
* @details
|
||||
* This method takes the message provided, adds the sentFrom information
|
||||
* and passes it on to the destination provided with an operating system
|
||||
@ -129,8 +128,7 @@ class MessageQueueIF {
|
||||
bool ignoreFault = false) = 0;
|
||||
|
||||
/**
|
||||
* @brief The sendToDefaultFrom method sends a queue message
|
||||
* to the default destination.
|
||||
* @brief The sendToDefaultFrom method sends a queue message to the default destination.
|
||||
* @details
|
||||
* In all other aspects, it works identical to the sendMessage method.
|
||||
* @param message
|
||||
@ -164,6 +162,8 @@ class MessageQueueIF {
|
||||
virtual MessageQueueId_t getDefaultDestination() const = 0;
|
||||
|
||||
virtual bool isDefaultDestinationSet() const = 0;
|
||||
|
||||
virtual MqArgs& getMqArgs() = 0;
|
||||
};
|
||||
|
||||
#endif /* FSFW_IPC_MESSAGEQUEUEIF_H_ */
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
#include "MessageQueueIF.h"
|
||||
#include "MessageQueueMessage.h"
|
||||
#include "definitions.h"
|
||||
|
||||
/**
|
||||
* Creates message queues.
|
||||
@ -22,7 +23,8 @@ class QueueFactory {
|
||||
static QueueFactory* instance();
|
||||
|
||||
MessageQueueIF* createMessageQueue(uint32_t messageDepth = 3,
|
||||
size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE);
|
||||
size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE,
|
||||
MqArgs* args = nullptr);
|
||||
|
||||
void deleteMessageQueue(MessageQueueIF* queue);
|
||||
|
||||
|
14
src/fsfw/ipc/definitions.h
Normal file
14
src/fsfw/ipc/definitions.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef FSFW_SRC_FSFW_IPC_DEFINITIONS_H_
|
||||
#define FSFW_SRC_FSFW_IPC_DEFINITIONS_H_
|
||||
|
||||
#include <fsfw/objectmanager/SystemObjectIF.h>
|
||||
#include <fsfw/objectmanager/frameworkObjects.h>
|
||||
|
||||
struct MqArgs {
|
||||
MqArgs(){};
|
||||
MqArgs(object_id_t objectId, void* args = nullptr) : objectId(objectId), args(args) {}
|
||||
object_id_t objectId = objects::NO_OBJECT;
|
||||
void* args = nullptr;
|
||||
};
|
||||
|
||||
#endif /* FSFW_SRC_FSFW_IPC_DEFINITIONS_H_ */
|
@ -11,9 +11,6 @@
|
||||
// TODO sanitize input?
|
||||
// TODO much of this code can be reused for tick-only systems
|
||||
|
||||
uint16_t Clock::leapSeconds = 0;
|
||||
MutexIF* Clock::timeMutex = nullptr;
|
||||
|
||||
uint32_t Clock::getTicksPerSecond(void) { return 1000; }
|
||||
|
||||
ReturnValue_t Clock::setClock(const TimeOfDay_t* time) {
|
||||
|
@ -4,8 +4,9 @@
|
||||
#include "fsfw/osal/freertos/QueueMapManager.h"
|
||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||
|
||||
MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize)
|
||||
: maxMessageSize(maxMessageSize) {
|
||||
MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize, MqArgs* args)
|
||||
: MessageQueueBase(MessageQueueIF::NO_QUEUE, MessageQueueIF::NO_QUEUE, args),
|
||||
maxMessageSize(maxMessageSize) {
|
||||
handle = xQueueCreate(messageDepth, maxMessageSize);
|
||||
if (handle == nullptr) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
@ -15,10 +16,10 @@ MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize)
|
||||
#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);
|
||||
sif::printError("Specified Maximum Message Size: %d\n", maxMessageSize);
|
||||
#endif
|
||||
}
|
||||
QueueMapManager::instance()->addMessageQueue(handle, &queueId);
|
||||
QueueMapManager::instance()->addMessageQueue(handle, &id);
|
||||
}
|
||||
|
||||
MessageQueue::~MessageQueue() {
|
||||
@ -29,28 +30,6 @@ MessageQueue::~MessageQueue() {
|
||||
|
||||
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);
|
||||
@ -72,27 +51,16 @@ ReturnValue_t MessageQueue::handleSendResult(BaseType_t result, bool ignoreFault
|
||||
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<void*>(message->getBuffer()), 0);
|
||||
if (result == pdPASS) {
|
||||
this->lastPartner = message->getSender();
|
||||
this->last = 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
|
||||
@ -100,17 +68,6 @@ ReturnValue_t MessageQueue::flush(uint32_t* count) {
|
||||
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,
|
||||
|
@ -1,12 +1,15 @@
|
||||
#ifndef FSFW_OSAL_FREERTOS_MESSAGEQUEUE_H_
|
||||
#define FSFW_OSAL_FREERTOS_MESSAGEQUEUE_H_
|
||||
|
||||
#include <fsfw/ipc/MessageQueueBase.h>
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "TaskManagement.h"
|
||||
#include "fsfw/internalerror/InternalErrorReporterIF.h"
|
||||
#include "fsfw/ipc/MessageQueueIF.h"
|
||||
#include "fsfw/ipc/MessageQueueMessage.h"
|
||||
#include "fsfw/ipc/MessageQueueMessageIF.h"
|
||||
#include "fsfw/ipc/definitions.h"
|
||||
#include "queue.h"
|
||||
|
||||
/**
|
||||
@ -32,7 +35,7 @@
|
||||
* @ingroup osal
|
||||
* @ingroup message_queue
|
||||
*/
|
||||
class MessageQueue : public MessageQueueIF {
|
||||
class MessageQueue : public MessageQueueBase {
|
||||
friend class MessageQueueSenderIF;
|
||||
|
||||
public:
|
||||
@ -53,7 +56,8 @@ class MessageQueue : public MessageQueueIF {
|
||||
* This should be left default.
|
||||
*/
|
||||
MessageQueue(size_t messageDepth = 3,
|
||||
size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE);
|
||||
size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE,
|
||||
MqArgs* args = nullptr);
|
||||
|
||||
/** Copying message queues forbidden */
|
||||
MessageQueue(const MessageQueue&) = delete;
|
||||
@ -73,40 +77,15 @@ class MessageQueue : public MessageQueueIF {
|
||||
*/
|
||||
void switchSystemContext(CallContext callContext);
|
||||
|
||||
/** MessageQueueIF implementation */
|
||||
ReturnValue_t sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
||||
bool ignoreFault = false) override;
|
||||
QueueHandle_t getNativeQueueHandle();
|
||||
|
||||
ReturnValue_t sendToDefault(MessageQueueMessageIF* message) override;
|
||||
|
||||
ReturnValue_t reply(MessageQueueMessageIF* message) override;
|
||||
// Implement non-generic MessageQueueIF functions not handled by MessageQueueBase
|
||||
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
|
||||
@ -136,12 +115,8 @@ class MessageQueue : public MessageQueueIF {
|
||||
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;
|
||||
|
@ -97,7 +97,11 @@ void PeriodicTask::taskFunctionality() {
|
||||
|
||||
ReturnValue_t PeriodicTask::addComponent(object_id_t object) {
|
||||
ExecutableObjectIF* newObject = ObjectManager::instance()->get<ExecutableObjectIF>(object);
|
||||
if (newObject == nullptr) {
|
||||
return addComponent(newObject);
|
||||
}
|
||||
|
||||
ReturnValue_t PeriodicTask::addComponent(ExecutableObjectIF* object) {
|
||||
if (object == nullptr) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "PeriodicTask::addComponent: Invalid object. Make sure"
|
||||
"it implement ExecutableObjectIF"
|
||||
@ -105,8 +109,8 @@ ReturnValue_t PeriodicTask::addComponent(object_id_t object) {
|
||||
#endif
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
objectList.push_back(newObject);
|
||||
newObject->setTaskIF(this);
|
||||
objectList.push_back(object);
|
||||
object->setTaskIF(this);
|
||||
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
@ -63,6 +63,16 @@ class PeriodicTask : public PeriodicTaskIF, public FreeRTOSTaskIF {
|
||||
*/
|
||||
ReturnValue_t addComponent(object_id_t object) override;
|
||||
|
||||
/**
|
||||
* Adds an object to the list of objects to be executed.
|
||||
* The objects are executed in the order added.
|
||||
* @param object Id of the object to add.
|
||||
* @return
|
||||
* -@c RETURN_OK on success
|
||||
* -@c RETURN_FAILED if the object could not be added.
|
||||
*/
|
||||
ReturnValue_t addComponent(ExecutableObjectIF* object) override;
|
||||
|
||||
uint32_t getPeriodMs() const override;
|
||||
|
||||
ReturnValue_t sleepFor(uint32_t ms) override;
|
||||
|
@ -22,8 +22,9 @@ QueueFactory::QueueFactory() {}
|
||||
|
||||
QueueFactory::~QueueFactory() {}
|
||||
|
||||
MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, size_t maxMessageSize) {
|
||||
return new MessageQueue(messageDepth, maxMessageSize);
|
||||
MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, size_t maxMessageSize,
|
||||
MqArgs* args) {
|
||||
return new MessageQueue(messageDepth, maxMessageSize, args);
|
||||
}
|
||||
|
||||
void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) { delete queue; }
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include "fsfw/ipc/MutexGuard.h"
|
||||
#include "fsfw/platform.h"
|
||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||
|
||||
@ -11,9 +12,6 @@
|
||||
#include <fstream>
|
||||
#endif
|
||||
|
||||
uint16_t Clock::leapSeconds = 0;
|
||||
MutexIF* Clock::timeMutex = NULL;
|
||||
|
||||
using SystemClock = std::chrono::system_clock;
|
||||
|
||||
uint32_t Clock::getTicksPerSecond(void) {
|
||||
@ -127,6 +125,13 @@ ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) {
|
||||
auto seconds = std::chrono::time_point_cast<std::chrono::seconds>(now);
|
||||
auto fraction = now - seconds;
|
||||
time_t tt = SystemClock::to_time_t(now);
|
||||
ReturnValue_t result = checkOrCreateClockMutex();
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
MutexGuard helper(timeMutex);
|
||||
// gmtime writes its output in a global buffer which is not Thread Safe
|
||||
// Therefore we have to use a Mutex here
|
||||
struct tm* timeInfo;
|
||||
timeInfo = gmtime(&tt);
|
||||
time->year = timeInfo->tm_year + 1900;
|
||||
@ -150,17 +155,14 @@ ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from, timeval*
|
||||
time_tm.tm_hour = from->hour;
|
||||
time_tm.tm_min = from->minute;
|
||||
time_tm.tm_sec = from->second;
|
||||
time_tm.tm_isdst = 0;
|
||||
|
||||
time_t seconds = mktime(&time_tm);
|
||||
time_t seconds = timegm(&time_tm);
|
||||
|
||||
to->tv_sec = seconds;
|
||||
to->tv_usec = from->usecond;
|
||||
// Fails in 2038..
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "Clock::convertTimeBla: not implemented yet" << std::endl;
|
||||
#endif
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) {
|
||||
|
@ -8,10 +8,12 @@
|
||||
#include "fsfw/osal/host/QueueMapManager.h"
|
||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||
|
||||
MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize)
|
||||
: messageSize(maxMessageSize), messageDepth(messageDepth) {
|
||||
MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize, MqArgs* args)
|
||||
: MessageQueueBase(MessageQueueIF::NO_QUEUE, MessageQueueIF::NO_QUEUE, args),
|
||||
messageSize(maxMessageSize),
|
||||
messageDepth(messageDepth) {
|
||||
queueLock = MutexFactory::instance()->createMutex();
|
||||
auto result = QueueMapManager::instance()->addMessageQueue(this, &mqId);
|
||||
auto result = QueueMapManager::instance()->addMessageQueue(this, &id);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "MessageQueue::MessageQueue: Could not be created" << std::endl;
|
||||
@ -23,42 +25,11 @@ MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize)
|
||||
|
||||
MessageQueue::~MessageQueue() { MutexFactory::instance()->deleteMutex(queueLock); }
|
||||
|
||||
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 MessageQueueIF::NO_REPLY_PARTNER;
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
||||
MessageQueueId_t sentFrom, bool ignoreFault) {
|
||||
return sendMessageFromMessageQueue(sendTo, message, sentFrom, ignoreFault);
|
||||
}
|
||||
|
||||
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) {
|
||||
if (messageQueue.empty()) {
|
||||
return MessageQueueIF::EMPTY;
|
||||
@ -68,12 +39,10 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
|
||||
message->getBuffer());
|
||||
messageQueue.pop();
|
||||
// The last partner is the first uint32_t field in the message
|
||||
this->lastPartner = message->getSender();
|
||||
this->last = message->getSender();
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
MessageQueueId_t MessageQueue::getLastPartner() const { return lastPartner; }
|
||||
|
||||
ReturnValue_t MessageQueue::flush(uint32_t* count) {
|
||||
*count = messageQueue.size();
|
||||
// Clears the queue.
|
||||
@ -81,17 +50,6 @@ ReturnValue_t MessageQueue::flush(uint32_t* count) {
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
MessageQueueId_t MessageQueue::getId() const { return mqId; }
|
||||
|
||||
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,
|
||||
@ -125,6 +83,13 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
|
||||
memcpy(targetQueue->messageQueue.back().data(), message->getBuffer(),
|
||||
message->getMaximumMessageSize());
|
||||
} else {
|
||||
if (not ignoreFault) {
|
||||
InternalErrorReporterIF* internalErrorReporter =
|
||||
ObjectManager::instance()->get<InternalErrorReporterIF>(objects::INTERNAL_ERROR_REPORTER);
|
||||
if (internalErrorReporter != nullptr) {
|
||||
internalErrorReporter->queueMessageNotSent();
|
||||
}
|
||||
}
|
||||
return MessageQueueIF::FULL;
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
|
@ -5,9 +5,11 @@
|
||||
#include <queue>
|
||||
|
||||
#include "fsfw/internalerror/InternalErrorReporterIF.h"
|
||||
#include "fsfw/ipc/MessageQueueBase.h"
|
||||
#include "fsfw/ipc/MessageQueueIF.h"
|
||||
#include "fsfw/ipc/MessageQueueMessage.h"
|
||||
#include "fsfw/ipc/MutexIF.h"
|
||||
#include "fsfw/ipc/definitions.h"
|
||||
#include "fsfw/timemanager/Clock.h"
|
||||
|
||||
/**
|
||||
@ -33,7 +35,7 @@
|
||||
* @ingroup osal
|
||||
* @ingroup message_queue
|
||||
*/
|
||||
class MessageQueue : public MessageQueueIF {
|
||||
class MessageQueue : public MessageQueueBase {
|
||||
friend class MessageQueueSenderIF;
|
||||
|
||||
public:
|
||||
@ -54,7 +56,8 @@ class MessageQueue : public MessageQueueIF {
|
||||
* This should be left default.
|
||||
*/
|
||||
MessageQueue(size_t messageDepth = 3,
|
||||
size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE);
|
||||
size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE,
|
||||
MqArgs* args = nullptr);
|
||||
|
||||
/** Copying message queues forbidden */
|
||||
MessageQueue(const MessageQueue&) = delete;
|
||||
@ -67,121 +70,12 @@ class MessageQueue : public MessageQueueIF {
|
||||
*/
|
||||
virtual ~MessageQueue();
|
||||
|
||||
/**
|
||||
* @brief This operation sends a message to the given destination.
|
||||
* @details It directly uses the sendMessage call of the MessageQueueSender
|
||||
* parent, but passes its queue id as "sentFrom" parameter.
|
||||
* @param sendTo This parameter specifies the message queue id of the
|
||||
* destination message queue.
|
||||
* @param message A pointer to a previously created message, which is sent.
|
||||
* @param ignoreFault If set to true, the internal software fault counter
|
||||
* is not incremented if queue is full.
|
||||
*/
|
||||
ReturnValue_t sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
||||
bool ignoreFault = false) override;
|
||||
/**
|
||||
* @brief This operation sends a message to the default destination.
|
||||
* @details As in the sendMessage method, this function uses the
|
||||
* sendToDefault call of the MessageQueueSender parent class and adds its
|
||||
* queue id as "sentFrom" information.
|
||||
* @param message A pointer to a previously created message, which is sent.
|
||||
*/
|
||||
ReturnValue_t sendToDefault(MessageQueueMessageIF* message) override;
|
||||
/**
|
||||
* @brief This operation sends a message to the last communication partner.
|
||||
* @details This operation simplifies answering an incoming message by using
|
||||
* the stored lastPartner information as destination. If there was no
|
||||
* message received yet (i.e. lastPartner is zero), an error code is returned.
|
||||
* @param message A pointer to a previously created message, which is sent.
|
||||
*/
|
||||
ReturnValue_t reply(MessageQueueMessageIF* message) override;
|
||||
|
||||
/**
|
||||
* @brief With the sendMessage call, a queue message is sent to a
|
||||
* receiving queue.
|
||||
* @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.
|
||||
*/
|
||||
// Implement non-generic MessageQueueIF functions not handled by MessageQueueBase
|
||||
virtual ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
||||
MessageQueueId_t sentFrom = NO_QUEUE,
|
||||
bool ignoreFault = false) override;
|
||||
|
||||
/**
|
||||
* @brief The sendToDefault method sends a queue message to the default
|
||||
* destination.
|
||||
* @details
|
||||
* In all other aspects, it works identical to the sendMessage method.
|
||||
* @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.
|
||||
*/
|
||||
virtual ReturnValue_t sendToDefaultFrom(MessageQueueMessageIF* message,
|
||||
MessageQueueId_t sentFrom = NO_QUEUE,
|
||||
bool ignoreFault = false) override;
|
||||
|
||||
/**
|
||||
* @brief This function reads available messages from the message queue
|
||||
* and returns the sender.
|
||||
* @details
|
||||
* It works identically to the other receiveMessage call, but in addition
|
||||
* returns the sender's queue id.
|
||||
* @param message A pointer to a message in which the received data is stored.
|
||||
* @param receivedFrom A pointer to a queue id in which the sender's id is stored.
|
||||
*/
|
||||
ReturnValue_t receiveMessage(MessageQueueMessageIF* message,
|
||||
MessageQueueId_t* receivedFrom) override;
|
||||
|
||||
/**
|
||||
* @brief This function reads available messages from the message queue.
|
||||
* @details
|
||||
* If data is available it is stored in the passed message pointer.
|
||||
* The message's original content is overwritten and the sendFrom
|
||||
* information is stored in the lastPartner attribute. Else, the lastPartner
|
||||
* information remains untouched, the message's content is cleared and the
|
||||
* function returns immediately.
|
||||
* @param message A pointer to a message in which the received data is stored.
|
||||
*/
|
||||
ReturnValue_t receiveMessage(MessageQueueMessageIF* message) override;
|
||||
/**
|
||||
* Deletes all pending messages in the queue.
|
||||
* @param count The number of flushed messages.
|
||||
* @return RETURN_OK on success.
|
||||
*/
|
||||
ReturnValue_t flush(uint32_t* count) override;
|
||||
/**
|
||||
* @brief This method returns the message queue id of the last
|
||||
* communication partner.
|
||||
*/
|
||||
MessageQueueId_t getLastPartner() const override;
|
||||
/**
|
||||
* @brief This method returns the message queue id of this class's
|
||||
* message queue.
|
||||
*/
|
||||
MessageQueueId_t getId() const override;
|
||||
|
||||
/**
|
||||
* @brief This method is a simple setter for the default destination.
|
||||
*/
|
||||
void setDefaultDestination(MessageQueueId_t defaultDestination) override;
|
||||
/**
|
||||
* @brief This method is a simple getter for the default destination.
|
||||
*/
|
||||
MessageQueueId_t getDefaultDestination() const override;
|
||||
|
||||
bool isDefaultDestinationSet() const override;
|
||||
|
||||
ReturnValue_t lockQueue(MutexIF::TimeoutType timeoutType, dur_millis_t lockTimeout);
|
||||
ReturnValue_t unlockQueue();
|
||||
@ -211,23 +105,14 @@ class MessageQueue : public MessageQueueIF {
|
||||
MessageQueueId_t sentFrom = NO_QUEUE,
|
||||
bool ignoreFault = false);
|
||||
|
||||
// static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault);
|
||||
|
||||
private:
|
||||
std::queue<std::vector<uint8_t>> messageQueue;
|
||||
/**
|
||||
* @brief The class stores the queue id it got assigned.
|
||||
* If initialization fails, the queue id is set to zero.
|
||||
*/
|
||||
MessageQueueId_t mqId = MessageQueueIF::NO_QUEUE;
|
||||
size_t messageSize = 0;
|
||||
size_t messageDepth = 0;
|
||||
|
||||
MutexIF* queueLock;
|
||||
|
||||
bool defaultDestinationSet = false;
|
||||
MessageQueueId_t defaultDestination = MessageQueueIF::NO_QUEUE;
|
||||
MessageQueueId_t lastPartner = MessageQueueIF::NO_QUEUE;
|
||||
};
|
||||
|
||||
#endif /* FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_ */
|
||||
|
@ -102,11 +102,15 @@ void PeriodicTask::taskFunctionality() {
|
||||
|
||||
ReturnValue_t PeriodicTask::addComponent(object_id_t object) {
|
||||
ExecutableObjectIF* newObject = ObjectManager::instance()->get<ExecutableObjectIF>(object);
|
||||
if (newObject == nullptr) {
|
||||
return addComponent(newObject);
|
||||
}
|
||||
|
||||
ReturnValue_t PeriodicTask::addComponent(ExecutableObjectIF* object) {
|
||||
if (object == nullptr) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
newObject->setTaskIF(this);
|
||||
objectList.push_back(newObject);
|
||||
object->setTaskIF(this);
|
||||
objectList.push_back(object);
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
|
@ -59,6 +59,16 @@ class PeriodicTask : public PeriodicTaskIF {
|
||||
*/
|
||||
ReturnValue_t addComponent(object_id_t object);
|
||||
|
||||
/**
|
||||
* Adds an object to the list of objects to be executed.
|
||||
* The objects are executed in the order added.
|
||||
* @param object pointer to the object to add.
|
||||
* @return
|
||||
* -@c RETURN_OK on success
|
||||
* -@c RETURN_FAILED if the object could not be added.
|
||||
*/
|
||||
ReturnValue_t addComponent(ExecutableObjectIF* object);
|
||||
|
||||
uint32_t getPeriodMs() const;
|
||||
|
||||
ReturnValue_t sleepFor(uint32_t ms);
|
||||
|
@ -27,12 +27,13 @@ QueueFactory::QueueFactory() {}
|
||||
|
||||
QueueFactory::~QueueFactory() {}
|
||||
|
||||
MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, size_t maxMessageSize) {
|
||||
MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, size_t maxMessageSize,
|
||||
MqArgs* args) {
|
||||
// A thread-safe queue can be implemented by using a combination
|
||||
// of std::queue and std::mutex. This uses dynamic memory allocation
|
||||
// which could be alleviated by using a custom allocator, external library
|
||||
// (etl::queue) or simply using std::queue, we're on a host machine anyway.
|
||||
return new MessageQueue(messageDepth, maxMessageSize);
|
||||
return new MessageQueue(messageDepth, maxMessageSize, args);
|
||||
}
|
||||
|
||||
void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) { delete queue; }
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "fsfw/osal/linux/BinarySemaphore.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <cstring>
|
||||
|
@ -1,29 +1,29 @@
|
||||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
||||
Clock.cpp
|
||||
BinarySemaphore.cpp
|
||||
CountingSemaphore.cpp
|
||||
FixedTimeslotTask.cpp
|
||||
InternalErrorCodes.cpp
|
||||
MessageQueue.cpp
|
||||
Mutex.cpp
|
||||
MutexFactory.cpp
|
||||
PeriodicPosixTask.cpp
|
||||
PosixThread.cpp
|
||||
QueueFactory.cpp
|
||||
SemaphoreFactory.cpp
|
||||
TaskFactory.cpp
|
||||
tcpipHelpers.cpp
|
||||
unixUtility.cpp
|
||||
BinarySemaphore.cpp
|
||||
CountingSemaphore.cpp
|
||||
FixedTimeslotTask.cpp
|
||||
InternalErrorCodes.cpp
|
||||
MessageQueue.cpp
|
||||
Mutex.cpp
|
||||
MutexFactory.cpp
|
||||
PeriodicPosixTask.cpp
|
||||
PosixThread.cpp
|
||||
QueueFactory.cpp
|
||||
SemaphoreFactory.cpp
|
||||
TaskFactory.cpp
|
||||
tcpipHelpers.cpp
|
||||
unixUtility.cpp
|
||||
)
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
rt
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
rt
|
||||
)
|
||||
|
||||
target_link_libraries(${LIB_FSFW_NAME} INTERFACE
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
)
|
||||
|
||||
|
@ -8,11 +8,9 @@
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include "fsfw/ipc/MutexGuard.h"
|
||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||
|
||||
uint16_t Clock::leapSeconds = 0;
|
||||
MutexIF* Clock::timeMutex = NULL;
|
||||
|
||||
uint32_t Clock::getTicksPerSecond(void) {
|
||||
uint32_t ticks = sysconf(_SC_CLK_TCK);
|
||||
return ticks;
|
||||
@ -117,7 +115,13 @@ ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) {
|
||||
// TODO errno
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
|
||||
ReturnValue_t result = checkOrCreateClockMutex();
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
MutexGuard helper(timeMutex);
|
||||
// gmtime writes its output in a global buffer which is not Thread Safe
|
||||
// Therefore we have to use a Mutex here
|
||||
struct tm* timeInfo;
|
||||
timeInfo = gmtime(&timeUnix.tv_sec);
|
||||
time->year = timeInfo->tm_year + 1900;
|
||||
@ -140,8 +144,9 @@ ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from, timeval*
|
||||
fromTm.tm_hour = from->hour;
|
||||
fromTm.tm_min = from->minute;
|
||||
fromTm.tm_sec = from->second;
|
||||
fromTm.tm_isdst = 0;
|
||||
|
||||
to->tv_sec = mktime(&fromTm);
|
||||
to->tv_sec = timegm(&fromTm);
|
||||
to->tv_usec = from->usecond;
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
@ -11,13 +11,10 @@
|
||||
#include "fsfw/osal/linux/unixUtility.h"
|
||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||
|
||||
MessageQueue::MessageQueue(uint32_t messageDepth, size_t maxMessageSize)
|
||||
: id(MessageQueueIF::NO_QUEUE),
|
||||
lastPartner(MessageQueueIF::NO_QUEUE),
|
||||
defaultDestination(MessageQueueIF::NO_QUEUE),
|
||||
MessageQueue::MessageQueue(uint32_t messageDepth, size_t maxMessageSize, MqArgs* args)
|
||||
: MessageQueueBase(MessageQueueIF::NO_QUEUE, MessageQueueIF::NO_QUEUE, args),
|
||||
maxMessageSize(maxMessageSize) {
|
||||
mq_attr attributes;
|
||||
this->id = 0;
|
||||
// Set attributes
|
||||
attributes.mq_curmsgs = 0;
|
||||
attributes.mq_maxmsg = messageDepth;
|
||||
@ -50,30 +47,6 @@ MessageQueue::~MessageQueue() {
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
@ -96,7 +69,7 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
|
||||
int status = mq_receive(id, reinterpret_cast<char*>(message->getBuffer()),
|
||||
message->getMaximumMessageSize(), &messagePriority);
|
||||
if (status > 0) {
|
||||
this->lastPartner = message->getSender();
|
||||
this->last = message->getSender();
|
||||
// Check size of incoming message.
|
||||
if (message->getMessageSize() < message->getMinimumMessageSize()) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
@ -164,8 +137,6 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
|
||||
}
|
||||
}
|
||||
|
||||
MessageQueueId_t MessageQueue::getLastPartner() const { return this->lastPartner; }
|
||||
|
||||
ReturnValue_t MessageQueue::flush(uint32_t* count) {
|
||||
mq_attr attrib;
|
||||
int status = mq_getattr(id, &attrib);
|
||||
@ -212,26 +183,11 @@ ReturnValue_t MessageQueue::flush(uint32_t* count) {
|
||||
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,
|
||||
@ -240,9 +196,9 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
|
||||
bool ignoreFault) {
|
||||
if (message == nullptr) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "MessageQueue::sendMessageFromMessageQueue: Message is nullptr!" << std::endl;
|
||||
sif::error << "MessageQueue::sendMessageFromMessageQueue: Message is nullptr" << std::endl;
|
||||
#else
|
||||
sif::printError("MessageQueue::sendMessageFromMessageQueue: Message is nullptr!\n");
|
||||
sif::printError("MessageQueue::sendMessageFromMessageQueue: Message is nullptr\n");
|
||||
#endif
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
@ -256,7 +212,7 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
|
||||
if (!ignoreFault) {
|
||||
InternalErrorReporterIF* internalErrorReporter =
|
||||
ObjectManager::instance()->get<InternalErrorReporterIF>(objects::INTERNAL_ERROR_REPORTER);
|
||||
if (internalErrorReporter != NULL) {
|
||||
if (internalErrorReporter != nullptr) {
|
||||
internalErrorReporter->queueMessageNotSent();
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,13 @@
|
||||
#ifndef FSFW_OSAL_LINUX_MESSAGEQUEUE_H_
|
||||
#define FSFW_OSAL_LINUX_MESSAGEQUEUE_H_
|
||||
|
||||
#include <fsfw/ipc/MessageQueueBase.h>
|
||||
#include <mqueue.h>
|
||||
|
||||
#include "fsfw/internalerror/InternalErrorReporterIF.h"
|
||||
#include "fsfw/ipc/MessageQueueIF.h"
|
||||
#include "fsfw/ipc/MessageQueueMessage.h"
|
||||
#include "fsfw/ipc/definitions.h"
|
||||
/**
|
||||
* @brief This class manages sending and receiving of message queue messages.
|
||||
*
|
||||
@ -25,7 +27,7 @@
|
||||
* makes use of the operating system calls provided.
|
||||
* @ingroup message_queue
|
||||
*/
|
||||
class MessageQueue : public MessageQueueIF {
|
||||
class MessageQueue : public MessageQueueBase {
|
||||
friend class MessageQueueSenderIF;
|
||||
|
||||
public:
|
||||
@ -42,104 +44,24 @@ class MessageQueue : public MessageQueueIF {
|
||||
* This should be left default.
|
||||
*/
|
||||
MessageQueue(uint32_t messageDepth = 3,
|
||||
size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE);
|
||||
size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE,
|
||||
MqArgs* args = nullptr);
|
||||
|
||||
/** 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();
|
||||
/**
|
||||
* @brief This operation sends a message to the given destination.
|
||||
* @details It directly uses the sendMessage call of the MessageQueueSender parent, but passes
|
||||
* its queue id as "sentFrom" parameter.
|
||||
* @param sendTo This parameter specifies the message queue id of the destination message
|
||||
* queue.
|
||||
* @param message A pointer to a previously created message, which is sent.
|
||||
* @param ignoreFault If set to true, the internal software fault counter is not incremented if
|
||||
* queue is full.
|
||||
*/
|
||||
virtual ReturnValue_t sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
||||
bool ignoreFault = false);
|
||||
/**
|
||||
* @brief This operation sends a message to the default destination.
|
||||
* @details As in the sendMessage method, this function uses the sendToDefault call of the
|
||||
* MessageQueueSender parent class and adds its queue id as "sentFrom"
|
||||
* information.
|
||||
* @param message A pointer to a previously created message, which is sent.
|
||||
*/
|
||||
virtual ReturnValue_t sendToDefault(MessageQueueMessageIF* message);
|
||||
/**
|
||||
* @brief This operation sends a message to the last communication partner.
|
||||
* @details This operation simplifies answering an incoming message by using the stored
|
||||
* lastParnter information as destination. If there was no message received yet
|
||||
* (i.e. lastPartner is zero), an error code is returned.
|
||||
* @param message A pointer to a previously created message, which is sent.
|
||||
*/
|
||||
ReturnValue_t reply(MessageQueueMessageIF* message);
|
||||
|
||||
/**
|
||||
* @brief This function reads available messages from the message queue and returns the
|
||||
* sender.
|
||||
* @details It works identically to the other receiveMessage call, but in addition returns the
|
||||
* sender's queue id.
|
||||
* @param message A pointer to a message in which the received data is stored.
|
||||
* @param receivedFrom A pointer to a queue id in which the sender's id is stored.
|
||||
*/
|
||||
ReturnValue_t receiveMessage(MessageQueueMessageIF* message, MessageQueueId_t* receivedFrom);
|
||||
|
||||
/**
|
||||
* @brief This function reads available messages from the message queue.
|
||||
* @details If data is available it is stored in the passed message pointer. The message's
|
||||
* original content is overwritten and the sendFrom information is stored in
|
||||
* the lastPartner attribute. Else, the lastPartner information remains untouched, the message's
|
||||
* content is cleared and the function returns immediately.
|
||||
* @param message A pointer to a message in which the received data is stored.
|
||||
*/
|
||||
ReturnValue_t receiveMessage(MessageQueueMessageIF* message);
|
||||
/**
|
||||
* Deletes all pending messages in the queue.
|
||||
* @param count The number of flushed messages.
|
||||
* @return RETURN_OK on success.
|
||||
*/
|
||||
ReturnValue_t flush(uint32_t* count);
|
||||
/**
|
||||
* @brief This method returns the message queue id of the last communication partner.
|
||||
*/
|
||||
MessageQueueId_t getLastPartner() const;
|
||||
/**
|
||||
* @brief This method returns the message queue id of this class's message queue.
|
||||
*/
|
||||
MessageQueueId_t getId() const;
|
||||
/**
|
||||
* \brief With the sendMessage call, a queue message is sent to a receiving queue.
|
||||
* \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.
|
||||
*/
|
||||
virtual ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
||||
MessageQueueId_t sentFrom, bool ignoreFault = false);
|
||||
/**
|
||||
* \brief The sendToDefault method sends a queue message to the default destination.
|
||||
* \details In all other aspects, it works identical to the sendMessage method.
|
||||
* \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.
|
||||
*/
|
||||
virtual ReturnValue_t sendToDefaultFrom(MessageQueueMessageIF* message,
|
||||
MessageQueueId_t sentFrom = NO_QUEUE,
|
||||
bool ignoreFault = false);
|
||||
/**
|
||||
* \brief This method is a simple setter for the default destination.
|
||||
*/
|
||||
void setDefaultDestination(MessageQueueId_t defaultDestination);
|
||||
/**
|
||||
* \brief This method is a simple getter for the default destination.
|
||||
*/
|
||||
MessageQueueId_t getDefaultDestination() const;
|
||||
|
||||
bool isDefaultDestinationSet() const;
|
||||
// Implement non-generic MessageQueueIF functions not handled by MessageQueueBase
|
||||
ReturnValue_t receiveMessage(MessageQueueMessageIF* message) override;
|
||||
ReturnValue_t flush(uint32_t* count) override;
|
||||
ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
||||
MessageQueueId_t sentFrom, bool ignoreFault = false) override;
|
||||
|
||||
protected:
|
||||
/**
|
||||
@ -158,31 +80,10 @@ class MessageQueue : public MessageQueueIF {
|
||||
bool ignoreFault = false);
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief The class stores the queue id it got assigned from the operating system in this
|
||||
* attribute. If initialization fails, the queue id is set to zero.
|
||||
*/
|
||||
MessageQueueId_t id;
|
||||
/**
|
||||
* @brief In this attribute, the queue id of the last communication partner is stored
|
||||
* to allow for replying.
|
||||
*/
|
||||
MessageQueueId_t lastPartner;
|
||||
/**
|
||||
* @brief The message queue's name -a user specific information for the operating system- is
|
||||
* generated automatically with the help of this static counter.
|
||||
*/
|
||||
/**
|
||||
* \brief This attribute stores a default destination to send messages to.
|
||||
* \details It is stored to simplify sending to always-the-same receiver. The attribute may
|
||||
* be set in the constructor or by a setter call to setDefaultDestination.
|
||||
*/
|
||||
MessageQueueId_t defaultDestination;
|
||||
|
||||
/**
|
||||
* The name of the message queue, stored for unlinking
|
||||
*/
|
||||
char name[16];
|
||||
char name[16] = {};
|
||||
|
||||
static uint16_t queueCounter;
|
||||
const size_t maxMessageSize;
|
||||
|
@ -28,7 +28,11 @@ void* PeriodicPosixTask::taskEntryPoint(void* arg) {
|
||||
|
||||
ReturnValue_t PeriodicPosixTask::addComponent(object_id_t object) {
|
||||
ExecutableObjectIF* newObject = ObjectManager::instance()->get<ExecutableObjectIF>(object);
|
||||
if (newObject == nullptr) {
|
||||
return addComponent(newObject);
|
||||
}
|
||||
|
||||
ReturnValue_t PeriodicPosixTask::addComponent(ExecutableObjectIF* object) {
|
||||
if (object == nullptr) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "PeriodicTask::addComponent: Invalid object. Make sure"
|
||||
<< " it implements ExecutableObjectIF!" << std::endl;
|
||||
@ -39,8 +43,8 @@ ReturnValue_t PeriodicPosixTask::addComponent(object_id_t object) {
|
||||
#endif
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
objectList.push_back(newObject);
|
||||
newObject->setTaskIF(this);
|
||||
objectList.push_back(object);
|
||||
object->setTaskIF(this);
|
||||
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
@ -42,6 +42,14 @@ class PeriodicPosixTask : public PosixThread, public PeriodicTaskIF {
|
||||
*/
|
||||
ReturnValue_t addComponent(object_id_t object) override;
|
||||
|
||||
/**
|
||||
* Adds an object to the list of objects to be executed.
|
||||
* The objects are executed in the order added.
|
||||
* @param object pointer to the object to add.
|
||||
* @return RETURN_OK on success, RETURN_FAILED if the object could not be added.
|
||||
*/
|
||||
ReturnValue_t addComponent(ExecutableObjectIF* object) override;
|
||||
|
||||
uint32_t getPeriodMs() const override;
|
||||
|
||||
ReturnValue_t sleepFor(uint32_t ms) override;
|
||||
@ -65,9 +73,10 @@ 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);
|
||||
/**
|
||||
|
@ -28,8 +28,9 @@ QueueFactory::QueueFactory() {}
|
||||
|
||||
QueueFactory::~QueueFactory() {}
|
||||
|
||||
MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, size_t maxMessageSize) {
|
||||
return new MessageQueue(messageDepth, maxMessageSize);
|
||||
MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, size_t maxMessageSize,
|
||||
MqArgs* args) {
|
||||
return new MessageQueue(messageDepth, maxMessageSize, args);
|
||||
}
|
||||
|
||||
void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) { delete queue; }
|
||||
|
@ -6,9 +6,6 @@
|
||||
#include "fsfw/ipc/MutexGuard.h"
|
||||
#include "fsfw/osal/rtems/RtemsBasic.h"
|
||||
|
||||
uint16_t Clock::leapSeconds = 0;
|
||||
MutexIF* Clock::timeMutex = nullptr;
|
||||
|
||||
uint32_t Clock::getTicksPerSecond(void) {
|
||||
rtems_interval ticks_per_second = rtems_clock_get_ticks_per_second();
|
||||
return static_cast<uint32_t>(ticks_per_second);
|
||||
|
@ -6,8 +6,9 @@
|
||||
#include "fsfw/osal/rtems/RtemsBasic.h"
|
||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||
|
||||
MessageQueue::MessageQueue(size_t message_depth, size_t max_message_size)
|
||||
: id(0), lastPartner(0), defaultDestination(NO_QUEUE), internalErrorReporter(nullptr) {
|
||||
MessageQueue::MessageQueue(size_t message_depth, size_t max_message_size, MqArgs* args)
|
||||
: MessageQueueBase(MessageQueueIF::NO_QUEUE, MessageQueueIF::NO_QUEUE, args),
|
||||
internalErrorReporter(nullptr) {
|
||||
rtems_name name = ('Q' << 24) + (queueCounter++ << 8);
|
||||
rtems_status_code status =
|
||||
rtems_message_queue_create(name, message_depth, max_message_size, 0, &(this->id));
|
||||
@ -16,43 +17,19 @@ MessageQueue::MessageQueue(size_t message_depth, size_t max_message_size)
|
||||
sif::error << "MessageQueue::MessageQueue: Creating Queue " << std::hex << name << std::dec
|
||||
<< " failed with status:" << (uint32_t)status << std::endl;
|
||||
#endif
|
||||
this->id = 0;
|
||||
this->id = MessageQueueIF::NO_QUEUE;
|
||||
}
|
||||
}
|
||||
|
||||
MessageQueue::~MessageQueue() { rtems_message_queue_delete(id); }
|
||||
|
||||
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::reply(MessageQueueMessageIF* message) {
|
||||
if (this->lastPartner != 0) {
|
||||
return sendMessage(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) {
|
||||
size_t size = 0;
|
||||
rtems_status_code status =
|
||||
rtems_message_queue_receive(id, message->getBuffer(), &size, RTEMS_NO_WAIT, 1);
|
||||
if (status == RTEMS_SUCCESSFUL) {
|
||||
message->setMessageSize(size);
|
||||
this->lastPartner = message->getSender();
|
||||
this->last = message->getSender();
|
||||
// Check size of incoming message.
|
||||
if (message->getMessageSize() < message->getMinimumMessageSize()) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
@ -65,19 +42,11 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
|
||||
return convertReturnCode(status);
|
||||
}
|
||||
|
||||
MessageQueueId_t MessageQueue::getLastPartner() const { return this->lastPartner; }
|
||||
|
||||
ReturnValue_t MessageQueue::flush(uint32_t* count) {
|
||||
rtems_status_code status = rtems_message_queue_flush(id, count);
|
||||
return convertReturnCode(status);
|
||||
}
|
||||
|
||||
MessageQueueId_t MessageQueue::getId() const { return this->id; }
|
||||
|
||||
void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) {
|
||||
this->defaultDestination = defaultDestination;
|
||||
}
|
||||
|
||||
ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
||||
MessageQueueId_t sentFrom, bool ignoreFault) {
|
||||
message->setSender(sentFrom);
|
||||
@ -103,15 +72,6 @@ ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, MessageQueu
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessageIF* message,
|
||||
MessageQueueId_t sentFrom, bool ignoreFault) {
|
||||
return sendMessageFrom(defaultDestination, message, sentFrom, ignoreFault);
|
||||
}
|
||||
|
||||
MessageQueueId_t MessageQueue::getDefaultDestination() const { return this->defaultDestination; }
|
||||
|
||||
bool MessageQueue::isDefaultDestinationSet() const { return (defaultDestination != NO_QUEUE); }
|
||||
|
||||
ReturnValue_t MessageQueue::convertReturnCode(rtems_status_code inValue) {
|
||||
switch (inValue) {
|
||||
case RTEMS_SUCCESSFUL:
|
||||
|
@ -1,10 +1,13 @@
|
||||
#ifndef FSFW_OSAL_RTEMS_MESSAGEQUEUE_H_
|
||||
#define FSFW_OSAL_RTEMS_MESSAGEQUEUE_H_
|
||||
|
||||
#include <fsfw/ipc/MessageQueueBase.h>
|
||||
|
||||
#include "RtemsBasic.h"
|
||||
#include "fsfw/internalerror/InternalErrorReporterIF.h"
|
||||
#include "fsfw/ipc/MessageQueueIF.h"
|
||||
#include "fsfw/ipc/MessageQueueMessage.h"
|
||||
#include "fsfw/ipc/definitions.h"
|
||||
|
||||
/**
|
||||
* @brief This class manages sending and receiving of message queue messages.
|
||||
@ -19,7 +22,7 @@
|
||||
*as well as sending and receiving messages, the class makes use of the operating system calls
|
||||
*provided. \ingroup message_queue
|
||||
*/
|
||||
class MessageQueue : public MessageQueueIF {
|
||||
class MessageQueue : public MessageQueueBase {
|
||||
public:
|
||||
/**
|
||||
* @brief The constructor initializes and configures the message queue.
|
||||
@ -34,131 +37,26 @@ class MessageQueue : public MessageQueueIF {
|
||||
* This should be left default.
|
||||
*/
|
||||
MessageQueue(size_t message_depth = 3,
|
||||
size_t max_message_size = MessageQueueMessage::MAX_MESSAGE_SIZE);
|
||||
size_t max_message_size = MessageQueueMessage::MAX_MESSAGE_SIZE,
|
||||
MqArgs* args = nullptr);
|
||||
|
||||
/** 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();
|
||||
/**
|
||||
* @brief This operation sends a message to the given destination.
|
||||
* @details It directly uses the sendMessage call of the MessageQueueSender parent, but passes
|
||||
* its queue id as "sentFrom" parameter.
|
||||
* @param sendTo This parameter specifies the message queue id of the destination message
|
||||
* queue.
|
||||
* @param message A pointer to a previously created message, which is sent.
|
||||
* @param ignoreFault If set to true, the internal software fault counter is not incremented if
|
||||
* queue is full.
|
||||
*/
|
||||
ReturnValue_t sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
||||
bool ignoreFault = false);
|
||||
/**
|
||||
* @brief This operation sends a message to the default destination.
|
||||
* @details As in the sendMessage method, this function uses the sendToDefault call of the
|
||||
* MessageQueueSender parent class and adds its queue id as "sentFrom"
|
||||
* information.
|
||||
* @param message A pointer to a previously created message, which is sent.
|
||||
*/
|
||||
ReturnValue_t sendToDefault(MessageQueueMessageIF* message);
|
||||
/**
|
||||
* @brief This operation sends a message to the last communication partner.
|
||||
* @details This operation simplifies answering an incoming message by using the stored
|
||||
* lastParnter information as destination. If there was no message received yet
|
||||
* (i.e. lastPartner is zero), an error code is returned.
|
||||
* @param message A pointer to a previously created message, which is sent.
|
||||
*/
|
||||
ReturnValue_t reply(MessageQueueMessageIF* message);
|
||||
|
||||
/**
|
||||
* @brief This function reads available messages from the message queue and returns the
|
||||
* sender.
|
||||
* @details It works identically to the other receiveMessage call, but in addition returns the
|
||||
* sender's queue id.
|
||||
* @param message A pointer to a message in which the received data is stored.
|
||||
* @param receivedFrom A pointer to a queue id in which the sender's id is stored.
|
||||
*/
|
||||
ReturnValue_t receiveMessage(MessageQueueMessageIF* message, MessageQueueId_t* receivedFrom);
|
||||
|
||||
/**
|
||||
* @brief This function reads available messages from the message queue.
|
||||
* @details If data is available it is stored in the passed message pointer. The message's
|
||||
* original content is overwritten and the sendFrom information is stored in
|
||||
* the lastPartner attribute. Else, the lastPartner information remains untouched, the message's
|
||||
* content is cleared and the function returns immediately.
|
||||
* @param message A pointer to a message in which the received data is stored.
|
||||
*/
|
||||
ReturnValue_t receiveMessage(MessageQueueMessageIF* message);
|
||||
/**
|
||||
* Deletes all pending messages in the queue.
|
||||
* @param count The number of flushed messages.
|
||||
* @return RETURN_OK on success.
|
||||
*/
|
||||
ReturnValue_t flush(uint32_t* count);
|
||||
/**
|
||||
* @brief This method returns the message queue id of the last communication partner.
|
||||
*/
|
||||
MessageQueueId_t getLastPartner() const;
|
||||
/**
|
||||
* @brief This method returns the message queue id of this class's message queue.
|
||||
*/
|
||||
MessageQueueId_t getId() const;
|
||||
/**
|
||||
* \brief With the sendMessage call, a queue message is sent to a receiving queue.
|
||||
* \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.
|
||||
*/
|
||||
virtual ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
||||
MessageQueueId_t sentFrom = NO_QUEUE,
|
||||
bool ignoreFault = false);
|
||||
/**
|
||||
* \brief The sendToDefault method sends a queue message to the default destination.
|
||||
* \details In all other aspects, it works identical to the sendMessage method.
|
||||
* \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.
|
||||
*/
|
||||
virtual ReturnValue_t sendToDefaultFrom(MessageQueueMessageIF* message,
|
||||
MessageQueueId_t sentFrom = NO_QUEUE,
|
||||
bool ignoreFault = false);
|
||||
/**
|
||||
* \brief This method is a simple setter for the default destination.
|
||||
*/
|
||||
void setDefaultDestination(MessageQueueId_t defaultDestination);
|
||||
/**
|
||||
* \brief This method is a simple getter for the default destination.
|
||||
*/
|
||||
MessageQueueId_t getDefaultDestination() const;
|
||||
|
||||
bool isDefaultDestinationSet() const;
|
||||
// Implement non-generic MessageQueueIF functions not handled by MessageQueueBase
|
||||
ReturnValue_t flush(uint32_t* count) override;
|
||||
ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
||||
MessageQueueId_t sentFrom = NO_QUEUE,
|
||||
bool ignoreFault = false) override;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief The class stores the queue id it got assigned from the operating system in this
|
||||
* attribute. If initialization fails, the queue id is set to zero.
|
||||
*/
|
||||
MessageQueueId_t id;
|
||||
/**
|
||||
* @brief In this attribute, the queue id of the last communication partner is stored
|
||||
* to allow for replying.
|
||||
*/
|
||||
MessageQueueId_t lastPartner;
|
||||
/**
|
||||
* @brief The message queue's name -a user specific information for the operating system- is
|
||||
* generated automatically with the help of this static counter.
|
||||
*/
|
||||
/**
|
||||
* \brief This attribute stores a default destination to send messages to.
|
||||
* \details It is stored to simplify sending to always-the-same receiver. The attribute may
|
||||
* be set in the constructor or by a setter call to setDefaultDestination.
|
||||
*/
|
||||
MessageQueueId_t defaultDestination;
|
||||
|
||||
/**
|
||||
* \brief This attribute stores a reference to the internal error reporter for reporting full
|
||||
* queues. \details In the event of a full destination queue, the reporter will be notified. The
|
||||
|
@ -68,11 +68,15 @@ void PeriodicTask::taskFunctionality() {
|
||||
|
||||
ReturnValue_t PeriodicTask::addComponent(object_id_t object) {
|
||||
ExecutableObjectIF* newObject = ObjectManager::instance()->get<ExecutableObjectIF>(object);
|
||||
if (newObject == nullptr) {
|
||||
return addComponent(newObject);
|
||||
}
|
||||
|
||||
ReturnValue_t PeriodicTask::addComponent(ExecutableObjectIF* object) {
|
||||
if (object == nullptr) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
objectList.push_back(newObject);
|
||||
newObject->setTaskIF(this);
|
||||
objectList.push_back(object);
|
||||
object->setTaskIF(this);
|
||||
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
@ -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
|
||||
*/
|
||||
@ -59,6 +59,14 @@ class PeriodicTask : public RTEMSTaskBase, public PeriodicTaskIF {
|
||||
*/
|
||||
ReturnValue_t addComponent(object_id_t object) override;
|
||||
|
||||
/**
|
||||
* Adds an object to the list of objects to be executed.
|
||||
* The objects are executed in the order added.
|
||||
* @param object pointer to the object to add.
|
||||
* @return RETURN_OK on success, RETURN_FAILED if the object could not be added.
|
||||
*/
|
||||
ReturnValue_t addComponent(ExecutableObjectIF *object) override;
|
||||
|
||||
uint32_t getPeriodMs() const override;
|
||||
|
||||
ReturnValue_t sleepFor(uint32_t ms) override;
|
||||
|
@ -49,8 +49,9 @@ QueueFactory::QueueFactory() {}
|
||||
|
||||
QueueFactory::~QueueFactory() {}
|
||||
|
||||
MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, size_t maxMessageSize) {
|
||||
return new MessageQueue(messageDepth, maxMessageSize);
|
||||
MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, size_t maxMessageSize,
|
||||
MqArgs* args) {
|
||||
return new MessageQueue(messageDepth, maxMessageSize, args);
|
||||
}
|
||||
|
||||
void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) { delete queue; }
|
||||
|
@ -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);
|
||||
|
@ -75,11 +75,11 @@ 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
|
||||
* 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 command) command was not sent
|
||||
* - @c COMMAND_CHANNEL_DEACTIVATED the channel has no port set
|
||||
* - @c NOT_SUPPORTED if you dont feel like
|
||||
* implementing something...
|
||||
@ -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)
|
||||
|
@ -1,6 +1,8 @@
|
||||
#ifndef FSFW_SERVICEINTERFACE_SERVICEINTERFACEPRINTER
|
||||
#define FSFW_SERVICEINTERFACE_SERVICEINTERFACEPRINTER
|
||||
|
||||
#include "fsfw/FSFW.h"
|
||||
|
||||
#if FSFW_DISABLE_PRINTOUT == 0
|
||||
#include <cstdio>
|
||||
#endif
|
||||
|
@ -110,7 +110,7 @@ ReturnValue_t LocalPool::modifyData(store_address_t storeId, uint8_t** packetPtr
|
||||
}
|
||||
|
||||
ReturnValue_t LocalPool::deleteData(store_address_t storeId) {
|
||||
#if FSFW_VERBOSE_PRINTOUT == 2
|
||||
#if FSFW_VERBOSE_LEVEL >= 2
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::debug << "Delete: Pool: " << std::dec << storeId.poolIndex
|
||||
<< " Index: " << storeId.packetIndex << std::endl;
|
||||
@ -148,7 +148,7 @@ ReturnValue_t LocalPool::deleteData(uint8_t* ptr, size_t size, store_address_t*
|
||||
// element of an object.
|
||||
localId.packetIndex = deltaAddress / elementSizes[n];
|
||||
result = deleteData(localId);
|
||||
#if FSFW_VERBOSE_PRINTOUT == 2
|
||||
#if FSFW_VERBOSE_LEVEL >= 2
|
||||
if (deltaAddress % elementSizes[n] != 0) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "LocalPool::deleteData: Address not aligned!" << std::endl;
|
||||
@ -219,7 +219,7 @@ ReturnValue_t LocalPool::reserveSpace(const size_t size, store_address_t* storeI
|
||||
status = findEmpty(storeId->poolIndex, &storeId->packetIndex);
|
||||
}
|
||||
if (status == RETURN_OK) {
|
||||
#if FSFW_VERBOSE_PRINTOUT == 2
|
||||
#if FSFW_VERBOSE_LEVEL >= 2
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::debug << "Reserve: Pool: " << std::dec << storeId->poolIndex
|
||||
<< " Index: " << storeId->packetIndex << std::endl;
|
||||
@ -257,7 +257,7 @@ void LocalPool::setToSpillToHigherPools(bool enable) { this->spillsToHigherPools
|
||||
ReturnValue_t LocalPool::getSubPoolIndex(size_t packetSize, uint16_t* subpoolIndex,
|
||||
uint16_t startAtIndex) {
|
||||
for (uint16_t n = startAtIndex; n < NUMBER_OF_SUBPOOLS; n++) {
|
||||
#if FSFW_VERBOSE_PRINTOUT == 2
|
||||
#if FSFW_VERBOSE_LEVEL >= 2
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::debug << "LocalPool " << getObjectId() << "::getPoolIndex: Pool: " << n
|
||||
<< ", Element Size: " << elementSizes[n] << std::endl;
|
||||
|
@ -17,7 +17,7 @@ ReturnValue_t PoolManager::reserveSpace(const size_t size, store_address_t* addr
|
||||
}
|
||||
|
||||
ReturnValue_t PoolManager::deleteData(store_address_t storeId) {
|
||||
#if FSFW_VERBOSE_PRINTOUT == 2
|
||||
#if FSFW_VERBOSE_LEVEL >= 2
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::debug << "PoolManager( " << translateObject(getObjectId()) << " )::deleteData from store "
|
||||
<< storeId.poolIndex << ". id is " << storeId.packetIndex << std::endl;
|
||||
|
@ -26,21 +26,25 @@ class PeriodicTaskIF {
|
||||
virtual ReturnValue_t startTask() = 0;
|
||||
|
||||
/**
|
||||
* Add a component (object) to a periodic task. The pointer to the
|
||||
* task can be set optionally
|
||||
* Add a component (object) to a periodic task.
|
||||
* @param object
|
||||
* Add an object to the task. The most important case is to add an
|
||||
* executable object with a function which will be called regularly
|
||||
* (see ExecutableObjectIF)
|
||||
* @param setTaskIF
|
||||
* Can be used to specify whether the task object pointer is passed
|
||||
* to the component.
|
||||
* Add an object to the task. The object needs to implement ExecutableObjectIF
|
||||
* @return
|
||||
*/
|
||||
virtual ReturnValue_t addComponent(object_id_t object) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add an object to a periodic task.
|
||||
* @param object
|
||||
* Add an object to the task.
|
||||
* @return
|
||||
*/
|
||||
virtual ReturnValue_t addComponent(ExecutableObjectIF* object) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
};
|
||||
|
||||
virtual ReturnValue_t sleepFor(uint32_t ms) = 0;
|
||||
|
||||
virtual uint32_t getPeriodMs() const = 0;
|
||||
|
@ -91,7 +91,7 @@ ReturnValue_t CCSDSTime::convertFromCDS(Clock::TimeOfDay_t* to, const uint8_t* f
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
return convertTimevalToTimeOfDay(to, &time);
|
||||
return Clock::convertTimevalToTimeOfDay(&time, to);
|
||||
}
|
||||
|
||||
ReturnValue_t CCSDSTime::convertFromCCS(Clock::TimeOfDay_t* to, const uint8_t* from,
|
||||
@ -109,8 +109,8 @@ ReturnValue_t CCSDSTime::convertFromCCS(Clock::TimeOfDay_t* to, const uint8_t* f
|
||||
if (result != RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
Ccs_mseconds* temp = (Ccs_mseconds*)from;
|
||||
// At this point we made sure that this is a valid ccs time
|
||||
const Ccs_mseconds* temp = reinterpret_cast<const Ccs_mseconds*>(from);
|
||||
|
||||
to->year = (temp->yearMSB << 8) + temp->yearLSB;
|
||||
to->hour = temp->hour;
|
||||
@ -118,16 +118,19 @@ ReturnValue_t CCSDSTime::convertFromCCS(Clock::TimeOfDay_t* to, const uint8_t* f
|
||||
to->second = temp->second;
|
||||
|
||||
if (temp->pField & (1 << 3)) { // day of year variation
|
||||
uint16_t tempDay = (temp->month << 8) + temp->day;
|
||||
result = convertDaysOfYear(tempDay, to->year, &(temp->month), &(temp->day));
|
||||
uint16_t tempDayOfYear = (temp->month << 8) + temp->day;
|
||||
uint8_t tempDay = 0;
|
||||
uint8_t tempMonth = 0;
|
||||
result = convertDaysOfYear(tempDayOfYear, to->year, &tempMonth, &tempDay);
|
||||
if (result != RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
to->month = tempMonth;
|
||||
to->day = tempDay;
|
||||
} else {
|
||||
to->month = temp->month;
|
||||
to->day = temp->day;
|
||||
}
|
||||
|
||||
to->month = temp->month;
|
||||
to->day = temp->day;
|
||||
|
||||
to->usecond = 0;
|
||||
if (subsecondsLength > 0) {
|
||||
*foundLength += 1;
|
||||
@ -162,7 +165,7 @@ ReturnValue_t CCSDSTime::convertFromASCII(Clock::TimeOfDay_t* to, const uint8_t*
|
||||
uint16_t hour;
|
||||
uint16_t minute;
|
||||
float second;
|
||||
int count = sscanf((char*)from,
|
||||
int count = sscanf((const char*)from,
|
||||
"%4" SCNu16 "-%2" SCNu16 "-%2" SCNu16
|
||||
"T%"
|
||||
"2" SCNu16 ":%2" SCNu16 ":%fZ",
|
||||
@ -179,7 +182,7 @@ ReturnValue_t CCSDSTime::convertFromASCII(Clock::TimeOfDay_t* to, const uint8_t*
|
||||
}
|
||||
|
||||
// try Code B (yyyy-ddd)
|
||||
count = sscanf((char*)from,
|
||||
count = sscanf((const char*)from,
|
||||
"%4" SCNu16 "-%3" SCNu16 "T%2" SCNu16
|
||||
":%"
|
||||
"2" SCNu16 ":%fZ",
|
||||
@ -211,7 +214,7 @@ ReturnValue_t CCSDSTime::convertFromASCII(Clock::TimeOfDay_t* to, const uint8_t*
|
||||
float second;
|
||||
// try Code A (yyyy-mm-dd)
|
||||
int count =
|
||||
sscanf((char*)from, "%4" SCNu16 "-%2" SCNu8 "-%2" SCNu16 "T%2" SCNu8 ":%2" SCNu8 ":%fZ",
|
||||
sscanf((const char*)from, "%4" SCNu16 "-%2" SCNu8 "-%2" SCNu16 "T%2" SCNu8 ":%2" SCNu8 ":%fZ",
|
||||
&year, &month, &day, &hour, &minute, &second);
|
||||
if (count == 6) {
|
||||
to->year = year;
|
||||
@ -225,8 +228,8 @@ ReturnValue_t CCSDSTime::convertFromASCII(Clock::TimeOfDay_t* to, const uint8_t*
|
||||
}
|
||||
|
||||
// try Code B (yyyy-ddd)
|
||||
count = sscanf((char*)from, "%4" SCNu16 "-%3" SCNu16 "T%2" SCNu8 ":%2" SCNu8 ":%fZ", &year, &day,
|
||||
&hour, &minute, &second);
|
||||
count = sscanf((const char*)from, "%4" SCNu16 "-%3" SCNu16 "T%2" SCNu8 ":%2" SCNu8 ":%fZ", &year,
|
||||
&day, &hour, &minute, &second);
|
||||
if (count == 5) {
|
||||
uint8_t tempDay;
|
||||
ReturnValue_t result = CCSDSTime::convertDaysOfYear(day, year, &month, &tempDay);
|
||||
@ -248,7 +251,7 @@ ReturnValue_t CCSDSTime::convertFromASCII(Clock::TimeOfDay_t* to, const uint8_t*
|
||||
}
|
||||
|
||||
ReturnValue_t CCSDSTime::checkCcs(const uint8_t* time, uint8_t length) {
|
||||
Ccs_mseconds* time_struct = (Ccs_mseconds*)time;
|
||||
const Ccs_mseconds* time_struct = reinterpret_cast<const Ccs_mseconds*>(time);
|
||||
|
||||
uint8_t additionalBytes = time_struct->pField & 0b111;
|
||||
if ((additionalBytes == 0b111) || (length < (additionalBytes + 8))) {
|
||||
@ -278,7 +281,7 @@ ReturnValue_t CCSDSTime::checkCcs(const uint8_t* time, uint8_t length) {
|
||||
return INVALID_TIME_FORMAT;
|
||||
}
|
||||
|
||||
uint8_t* additionalByte = &time_struct->secondEminus2;
|
||||
const uint8_t* additionalByte = &time_struct->secondEminus2;
|
||||
|
||||
for (; additionalBytes != 0; additionalBytes--) {
|
||||
if (*additionalByte++ > 99) {
|
||||
@ -486,11 +489,6 @@ ReturnValue_t CCSDSTime::checkTimeOfDay(const Clock::TimeOfDay_t* time) {
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t CCSDSTime::convertTimevalToTimeOfDay(Clock::TimeOfDay_t* to, timeval* from) {
|
||||
// This is rather tricky. Implement only if needed. Also, if so, move to OSAL.
|
||||
return UNSUPPORTED_TIME_FORMAT;
|
||||
}
|
||||
|
||||
ReturnValue_t CCSDSTime::convertFromCDS(timeval* to, const uint8_t* from, size_t* foundLength,
|
||||
size_t maxLength) {
|
||||
uint8_t pField = *from;
|
||||
@ -554,6 +552,35 @@ ReturnValue_t CCSDSTime::convertFromCDS(timeval* to, const uint8_t* from, size_t
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t CCSDSTime::convertFromCDS(timeval* to, const CCSDSTime::CDS_short* from) {
|
||||
if (to == nullptr or from == nullptr) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
uint16_t days = (from->dayMSB << 8) + from->dayLSB;
|
||||
if (days <= DAYS_CCSDS_TO_UNIX_EPOCH) {
|
||||
return INVALID_TIME_FORMAT;
|
||||
}
|
||||
days -= DAYS_CCSDS_TO_UNIX_EPOCH;
|
||||
to->tv_sec = days * SECONDS_PER_DAY;
|
||||
uint32_t msDay =
|
||||
(from->msDay_hh << 24) + (from->msDay_h << 16) + (from->msDay_l << 8) + from->msDay_ll;
|
||||
to->tv_sec += (msDay / 1000);
|
||||
to->tv_usec = (msDay % 1000) * 1000;
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t CCSDSTime::convertFromCDS(Clock::TimeOfDay_t* to, const CCSDSTime::CDS_short* from) {
|
||||
if (to == nullptr or from == nullptr) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
timeval tempTimeval;
|
||||
ReturnValue_t result = convertFromCDS(&tempTimeval, from);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
return Clock::convertTimevalToTimeOfDay(&tempTimeval, to);
|
||||
}
|
||||
|
||||
ReturnValue_t CCSDSTime::convertFromCUC(timeval* to, uint8_t pField, const uint8_t* from,
|
||||
size_t* foundLength, size_t maxLength) {
|
||||
uint32_t secs = 0;
|
||||
|
@ -180,6 +180,8 @@ class CCSDSTime : public HasReturnvaluesIF {
|
||||
|
||||
static ReturnValue_t convertFromCDS(timeval *to, uint8_t const *from, size_t *foundLength,
|
||||
size_t maxLength);
|
||||
static ReturnValue_t convertFromCDS(timeval *to, const CCSDSTime::CDS_short *from);
|
||||
static ReturnValue_t convertFromCDS(Clock::TimeOfDay_t *to, const CCSDSTime::CDS_short *from);
|
||||
|
||||
static ReturnValue_t convertFromCCS(Clock::TimeOfDay_t *to, uint8_t const *from,
|
||||
size_t *foundLength, size_t maxLength);
|
||||
@ -221,7 +223,6 @@ class CCSDSTime : public HasReturnvaluesIF {
|
||||
uint8_t *day);
|
||||
|
||||
static bool isLeapYear(uint32_t year);
|
||||
static ReturnValue_t convertTimevalToTimeOfDay(Clock::TimeOfDay_t *to, timeval *from);
|
||||
};
|
||||
|
||||
#endif /* FSFW_TIMEMANAGER_CCSDSTIME_H_ */
|
||||
|
@ -99,6 +99,13 @@ class Clock {
|
||||
*/
|
||||
static ReturnValue_t getDateAndTime(TimeOfDay_t *time);
|
||||
|
||||
/**
|
||||
* Convert to time of day struct given the POSIX timeval struct
|
||||
* @param from
|
||||
* @param to
|
||||
* @return
|
||||
*/
|
||||
static ReturnValue_t convertTimevalToTimeOfDay(const timeval *from, TimeOfDay_t *to);
|
||||
/**
|
||||
* Converts a time of day struct to POSIX seconds.
|
||||
* @param time The time of day as input
|
||||
@ -166,6 +173,7 @@ class Clock {
|
||||
|
||||
static MutexIF *timeMutex;
|
||||
static uint16_t leapSeconds;
|
||||
static bool leapSecondsSet;
|
||||
};
|
||||
|
||||
#endif /* FSFW_TIMEMANAGER_CLOCK_H_ */
|
||||
|
@ -1,7 +1,13 @@
|
||||
#include <ctime>
|
||||
|
||||
#include "fsfw/ipc/MutexGuard.h"
|
||||
#include "fsfw/timemanager/Clock.h"
|
||||
|
||||
ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval *tt) {
|
||||
uint16_t Clock::leapSeconds = 0;
|
||||
MutexIF* Clock::timeMutex = nullptr;
|
||||
bool Clock::leapSecondsSet = false;
|
||||
|
||||
ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) {
|
||||
uint16_t leapSeconds;
|
||||
ReturnValue_t result = getLeapSeconds(&leapSeconds);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
@ -27,12 +33,16 @@ ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) {
|
||||
MutexGuard helper(timeMutex);
|
||||
|
||||
leapSeconds = leapSeconds_;
|
||||
leapSecondsSet = true;
|
||||
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t Clock::getLeapSeconds(uint16_t *leapSeconds_) {
|
||||
if (timeMutex == nullptr) {
|
||||
ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) {
|
||||
if (not leapSecondsSet) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
if (checkOrCreateClockMutex() != HasReturnvaluesIF::RETURN_OK) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
MutexGuard helper(timeMutex);
|
||||
@ -42,9 +52,32 @@ ReturnValue_t Clock::getLeapSeconds(uint16_t *leapSeconds_) {
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t Clock::convertTimevalToTimeOfDay(const timeval* from, TimeOfDay_t* to) {
|
||||
struct tm* timeInfo;
|
||||
// According to https://en.cppreference.com/w/c/chrono/gmtime, the implementation of gmtime_s
|
||||
// in the Windows CRT is incompatible with the C standard but this should not be an issue for
|
||||
// this implementation
|
||||
ReturnValue_t result = checkOrCreateClockMutex();
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
MutexGuard helper(timeMutex);
|
||||
// gmtime writes its output in a global buffer which is not Thread Safe
|
||||
// Therefore we have to use a Mutex here
|
||||
timeInfo = gmtime(&from->tv_sec);
|
||||
to->year = timeInfo->tm_year + 1900;
|
||||
to->month = timeInfo->tm_mon + 1;
|
||||
to->day = timeInfo->tm_mday;
|
||||
to->hour = timeInfo->tm_hour;
|
||||
to->minute = timeInfo->tm_min;
|
||||
to->second = timeInfo->tm_sec;
|
||||
to->usecond = from->tv_usec;
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t Clock::checkOrCreateClockMutex() {
|
||||
if (timeMutex == nullptr) {
|
||||
MutexFactory *mutexFactory = MutexFactory::instance();
|
||||
MutexFactory* mutexFactory = MutexFactory::instance();
|
||||
if (mutexFactory == nullptr) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
#include "fsfw/timemanager/Countdown.h"
|
||||
|
||||
Countdown::Countdown(uint32_t initialTimeout) : timeout(initialTimeout) {}
|
||||
Countdown::Countdown(uint32_t initialTimeout) : timeout(initialTimeout) {
|
||||
setTimeout(initialTimeout);
|
||||
}
|
||||
|
||||
Countdown::~Countdown() {}
|
||||
|
||||
|
23
src/fsfw/version.cpp
Normal file
23
src/fsfw/version.cpp
Normal file
@ -0,0 +1,23 @@
|
||||
#include "version.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#include "fsfw/FSFWVersion.h"
|
||||
|
||||
#ifdef major
|
||||
#undef major
|
||||
#endif
|
||||
|
||||
#ifdef minor
|
||||
#undef minor
|
||||
#endif
|
||||
|
||||
const fsfw::Version fsfw::FSFW_VERSION = {FSFW_VERSION_MAJOR, FSFW_VERSION_MINOR,
|
||||
FSFW_VERSION_REVISION};
|
||||
|
||||
fsfw::Version::Version(uint32_t major, uint32_t minor, uint32_t revision)
|
||||
: major(major), minor(minor), revision(revision) {}
|
||||
|
||||
void fsfw::Version::getVersion(char* str, size_t maxLen) const {
|
||||
snprintf(str, maxLen, "%d.%d.%d", major, minor, revision);
|
||||
}
|
64
src/fsfw/version.h
Normal file
64
src/fsfw/version.h
Normal file
@ -0,0 +1,64 @@
|
||||
#ifndef FSFW_SRC_FSFW_VERSION_H_
|
||||
#define FSFW_SRC_FSFW_VERSION_H_
|
||||
|
||||
#include "fsfw/FSFW.h"
|
||||
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
#include <iostream>
|
||||
#endif
|
||||
#include <cstdint>
|
||||
|
||||
namespace fsfw {
|
||||
|
||||
class Version {
|
||||
public:
|
||||
Version(uint32_t major, uint32_t minor, uint32_t revision);
|
||||
uint32_t major = 0;
|
||||
uint32_t minor = 0;
|
||||
uint32_t revision = 0;
|
||||
|
||||
friend bool operator==(const Version& v1, const Version& v2) {
|
||||
return (v1.major == v2.major and v1.minor == v2.minor and v1.revision == v2.revision);
|
||||
}
|
||||
|
||||
friend bool operator!=(const Version& v1, const Version& v2) { return not(v1 == v2); }
|
||||
|
||||
friend bool operator<(const Version& v1, const Version& v2) {
|
||||
return ((v1.major < v2.major) or (v1.major == v2.major and v1.minor < v2.minor) or
|
||||
(v1.major == v2.major and v1.minor == v2.minor and v1.revision < v2.revision));
|
||||
}
|
||||
|
||||
friend bool operator>(const Version& v1, const Version& v2) {
|
||||
return not(v1 < v2) and not(v1 == v2);
|
||||
}
|
||||
|
||||
friend bool operator<=(const Version& v1, const Version& v2) { return ((v1 == v2) or (v1 < v2)); }
|
||||
|
||||
friend bool operator>=(const Version& v1, const Version& v2) { return ((v1 == v2) or (v1 > v2)); }
|
||||
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
/**
|
||||
* Print format to given ostream using format "major.minor.revision"
|
||||
* @param os
|
||||
* @param v
|
||||
* @return
|
||||
*/
|
||||
friend std::ostream& operator<<(std::ostream& os, const Version& v) {
|
||||
os << v.major << "." << v.minor << "." << v.revision;
|
||||
return os;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Get version as format "major.minor.revision"
|
||||
* @param str
|
||||
* @param maxLen
|
||||
*/
|
||||
void getVersion(char* str, size_t maxLen) const;
|
||||
};
|
||||
|
||||
extern const fsfw::Version FSFW_VERSION;
|
||||
|
||||
} // namespace fsfw
|
||||
|
||||
#endif /* FSFW_SRC_FSFW_VERSION_H_ */
|
@ -208,7 +208,7 @@ ReturnValue_t TestDevice::buildNormalModeCommand(DeviceCommandId_t deviceCommand
|
||||
const uint8_t* commandData,
|
||||
size_t commandDataLen) {
|
||||
if (fullInfoPrintout) {
|
||||
#if OBSW_VERBOSE_LEVEL >= 3
|
||||
#if FSFW_VERBOSE_LEVEL >= 3
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::info << "TestDevice::buildTestCommand1: Building normal command" << std::endl;
|
||||
#else
|
||||
@ -351,7 +351,7 @@ ReturnValue_t TestDevice::scanForReply(const uint8_t* start, size_t len, DeviceC
|
||||
switch (pendingCmd) {
|
||||
case (TEST_NORMAL_MODE_CMD): {
|
||||
if (fullInfoPrintout) {
|
||||
#if OBSW_VERBOSE_LEVEL >= 3
|
||||
#if FSFW_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;
|
||||
@ -678,7 +678,6 @@ ReturnValue_t TestDevice::getParameter(uint8_t domainId, uint8_t uniqueId,
|
||||
int32_t newValue = 0;
|
||||
ReturnValue_t result = newValues->getElement<int32_t>(&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 "
|
||||
@ -688,7 +687,6 @@ ReturnValue_t TestDevice::getParameter(uint8_t domainId, uint8_t uniqueId,
|
||||
sif::printInfo("TestDevice%d::getParameter: Setting parameter 1 to new value %lu\n",
|
||||
deviceIdx, static_cast<unsigned long>(newValue));
|
||||
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
||||
#endif /* OBSW_DEVICE_HANDLER_PRINTOUT == 1 */
|
||||
}
|
||||
}
|
||||
parameterWrapper->set(testParameter1);
|
||||
@ -702,7 +700,6 @@ ReturnValue_t TestDevice::getParameter(uint8_t domainId, uint8_t uniqueId,
|
||||
newValues->getElement<float>(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 "
|
||||
@ -715,7 +712,6 @@ ReturnValue_t TestDevice::getParameter(uint8_t domainId, uint8_t uniqueId,
|
||||
"[%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;
|
||||
|
@ -3,7 +3,6 @@
|
||||
#include <fsfw/objectmanager/ObjectManager.h>
|
||||
#include <fsfw/serviceinterface/ServiceInterface.h>
|
||||
|
||||
bool TestTask::oneShotAction = true;
|
||||
MutexIF* TestTask::testLock = nullptr;
|
||||
|
||||
TestTask::TestTask(object_id_t objectId) : SystemObject(objectId), testMode(testModes::A) {
|
||||
|
@ -29,7 +29,7 @@ class TestTask : public SystemObject, public ExecutableObjectIF, public HasRetur
|
||||
bool testFlag = false;
|
||||
|
||||
private:
|
||||
static bool oneShotAction;
|
||||
bool oneShotAction = true;
|
||||
static MutexIF* testLock;
|
||||
StorageManagerIF* IPCStore;
|
||||
};
|
||||
|
@ -2,14 +2,13 @@ target_sources(${FSFW_TEST_TGT} PRIVATE
|
||||
CatchDefinitions.cpp
|
||||
CatchFactory.cpp
|
||||
printChar.cpp
|
||||
version.cpp
|
||||
)
|
||||
|
||||
# if(FSFW_CUSTOM_UNITTEST_RUNNER)
|
||||
target_sources(${FSFW_TEST_TGT} PRIVATE
|
||||
CatchRunner.cpp
|
||||
CatchSetup.cpp
|
||||
)
|
||||
# endif()
|
||||
target_sources(${FSFW_TEST_TGT} PRIVATE
|
||||
CatchRunner.cpp
|
||||
CatchSetup.cpp
|
||||
)
|
||||
|
||||
add_subdirectory(testcfg)
|
||||
add_subdirectory(action)
|
||||
@ -23,3 +22,4 @@ add_subdirectory(timemanager)
|
||||
add_subdirectory(tmtcpacket)
|
||||
add_subdirectory(cfdp)
|
||||
add_subdirectory(hal)
|
||||
add_subdirectory(internalerror)
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include <fsfw/datapool/PoolReadGuard.h>
|
||||
#include <fsfw/datapoollocal/HasLocalDataPoolIF.h>
|
||||
#include <fsfw/datapoollocal/StaticLocalDataSet.h>
|
||||
#include <fsfw/globalfunctions/timevalOperations.h>
|
||||
#include <fsfw/housekeeping/HousekeepingSnapshot.h>
|
||||
#include <fsfw/ipc/CommandMessageCleaner.h>
|
||||
#include <fsfw/objectmanager/ObjectManager.h>
|
||||
@ -20,8 +21,10 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") {
|
||||
REQUIRE(poolOwner->initializeHkManager() == retval::CATCH_OK);
|
||||
REQUIRE(poolOwner->initializeHkManagerAfterTaskCreation() == retval::CATCH_OK);
|
||||
|
||||
MessageQueueMockBase* mqMock = poolOwner->getMockQueueHandle();
|
||||
REQUIRE(mqMock != nullptr);
|
||||
MessageQueueMockBase* poolOwnerMock = poolOwner->getMockQueueHandle();
|
||||
REQUIRE(poolOwnerMock != nullptr);
|
||||
|
||||
// MessageQueueIF* hkCommander = QueueFactory::instance()->createMessageQueue();
|
||||
CommandMessage messageSent;
|
||||
uint8_t messagesSent = 0;
|
||||
|
||||
@ -40,9 +43,9 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") {
|
||||
poolOwner->dataset.setChanged(true);
|
||||
/* Now the update message should be generated. */
|
||||
REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK);
|
||||
REQUIRE(mqMock->wasMessageSent() == true);
|
||||
REQUIRE(poolOwnerMock->wasMessageSent() == true);
|
||||
|
||||
REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK);
|
||||
REQUIRE(poolOwnerMock->receiveMessage(&messageSent) == retval::CATCH_OK);
|
||||
CHECK(messageSent.getCommand() ==
|
||||
static_cast<int>(HousekeepingMessage::UPDATE_NOTIFICATION_SET));
|
||||
|
||||
@ -52,9 +55,9 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") {
|
||||
poolOwner->dataset.setChanged(true);
|
||||
REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK);
|
||||
|
||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
||||
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||
CHECK(messagesSent == 1);
|
||||
REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK);
|
||||
REQUIRE(poolOwnerMock->receiveMessage(&messageSent) == retval::CATCH_OK);
|
||||
CHECK(messageSent.getCommand() ==
|
||||
static_cast<int>(HousekeepingMessage::UPDATE_NOTIFICATION_SET));
|
||||
|
||||
@ -62,15 +65,15 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") {
|
||||
REQUIRE(poolOwner->subscribeWrapperSetUpdateHk() == retval::CATCH_OK);
|
||||
poolOwner->dataset.setChanged(true);
|
||||
REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK);
|
||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
||||
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||
CHECK(messagesSent == 2);
|
||||
/* first message sent should be the update notification, considering
|
||||
the internal list is a vector checked in insertion order. */
|
||||
REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK);
|
||||
REQUIRE(poolOwnerMock->receiveMessage(&messageSent) == retval::CATCH_OK);
|
||||
CHECK(messageSent.getCommand() ==
|
||||
static_cast<int>(HousekeepingMessage::UPDATE_NOTIFICATION_SET));
|
||||
|
||||
REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK);
|
||||
REQUIRE(poolOwnerMock->receiveMessage(&messageSent) == retval::CATCH_OK);
|
||||
CHECK(messageSent.getCommand() == static_cast<int>(HousekeepingMessage::HK_REPORT));
|
||||
/* Clear message to avoid memory leak, our mock won't do it for us (yet) */
|
||||
CommandMessageCleaner::clearCommandMessage(&messageSent);
|
||||
@ -93,16 +96,14 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") {
|
||||
poolOwner->dataset.setChanged(true);
|
||||
|
||||
/* Store current time, we are going to check the (approximate) time equality later */
|
||||
CCSDSTime::CDS_short timeCdsNow;
|
||||
timeval now;
|
||||
Clock::getClock_timeval(&now);
|
||||
CCSDSTime::convertToCcsds(&timeCdsNow, &now);
|
||||
|
||||
/* Trigger generation of snapshot */
|
||||
REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK);
|
||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
||||
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||
CHECK(messagesSent == 1);
|
||||
REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK);
|
||||
REQUIRE(poolOwnerMock->receiveMessage(&messageSent) == retval::CATCH_OK);
|
||||
/* Check that snapshot was generated */
|
||||
CHECK(messageSent.getCommand() == static_cast<int>(HousekeepingMessage::UPDATE_SNAPSHOT_SET));
|
||||
/* Now we deserialize the snapshot into a new dataset instance */
|
||||
@ -131,13 +132,11 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") {
|
||||
CHECK(newSet.localPoolUint16Vec.value[2] == 42932);
|
||||
|
||||
/* Now we check that both times are equal */
|
||||
CHECK(cdsShort.pField == timeCdsNow.pField);
|
||||
CHECK(cdsShort.dayLSB == Catch::Approx(timeCdsNow.dayLSB).margin(1));
|
||||
CHECK(cdsShort.dayMSB == Catch::Approx(timeCdsNow.dayMSB).margin(1));
|
||||
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(5));
|
||||
timeval timeFromHK;
|
||||
auto result = CCSDSTime::convertFromCDS(&timeFromHK, &cdsShort);
|
||||
CHECK(result == HasReturnvaluesIF::RETURN_OK);
|
||||
timeval difference = timeFromHK - now;
|
||||
CHECK(timevalOperations::toDouble(difference) < 1.0);
|
||||
}
|
||||
|
||||
SECTION("VariableSnapshotTest") {
|
||||
@ -158,22 +157,19 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") {
|
||||
}
|
||||
|
||||
poolVar->setChanged(true);
|
||||
|
||||
/* Store current time, we are going to check the (approximate) time equality later */
|
||||
CCSDSTime::CDS_short timeCdsNow;
|
||||
timeval now;
|
||||
Clock::getClock_timeval(&now);
|
||||
CCSDSTime::convertToCcsds(&timeCdsNow, &now);
|
||||
|
||||
REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK);
|
||||
|
||||
/* Check update snapshot was sent. */
|
||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
||||
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||
CHECK(messagesSent == 1);
|
||||
|
||||
/* Should have been reset. */
|
||||
CHECK(poolVar->hasChanged() == false);
|
||||
REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK);
|
||||
REQUIRE(poolOwnerMock->receiveMessage(&messageSent) == retval::CATCH_OK);
|
||||
CHECK(messageSent.getCommand() ==
|
||||
static_cast<int>(HousekeepingMessage::UPDATE_SNAPSHOT_VARIABLE));
|
||||
/* Now we deserialize the snapshot into a new dataset instance */
|
||||
@ -193,13 +189,11 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") {
|
||||
CHECK(varCopy.value == 25);
|
||||
|
||||
/* Now we check that both times are equal */
|
||||
CHECK(cdsShort.pField == timeCdsNow.pField);
|
||||
CHECK(cdsShort.dayLSB == Catch::Approx(timeCdsNow.dayLSB).margin(1));
|
||||
CHECK(cdsShort.dayMSB == Catch::Approx(timeCdsNow.dayMSB).margin(1));
|
||||
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(5));
|
||||
timeval timeFromHK;
|
||||
auto result = CCSDSTime::convertFromCDS(&timeFromHK, &cdsShort);
|
||||
CHECK(result == HasReturnvaluesIF::RETURN_OK);
|
||||
timeval difference = timeFromHK - now;
|
||||
CHECK(timevalOperations::toDouble(difference) < 1.0);
|
||||
}
|
||||
|
||||
SECTION("VariableNotificationTest") {
|
||||
@ -217,11 +211,11 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") {
|
||||
REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK);
|
||||
|
||||
/* Check update notification was sent. */
|
||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
||||
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||
CHECK(messagesSent == 1);
|
||||
/* Should have been reset. */
|
||||
CHECK(poolVar->hasChanged() == false);
|
||||
REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK);
|
||||
REQUIRE(poolOwnerMock->receiveMessage(&messageSent) == retval::CATCH_OK);
|
||||
CHECK(messageSent.getCommand() ==
|
||||
static_cast<int>(HousekeepingMessage::UPDATE_NOTIFICATION_VARIABLE));
|
||||
/* Now subscribe for the dataset update (HK and update) again with subscription interface */
|
||||
@ -233,26 +227,26 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") {
|
||||
poolOwner->dataset.setChanged(true);
|
||||
REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK);
|
||||
/* Now two messages should be sent. */
|
||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
||||
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||
CHECK(messagesSent == 2);
|
||||
mqMock->clearMessages(true);
|
||||
poolOwnerMock->clearMessages(true);
|
||||
|
||||
poolOwner->dataset.setChanged(true);
|
||||
poolVar->setChanged(true);
|
||||
REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK);
|
||||
/* Now three messages should be sent. */
|
||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
||||
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||
CHECK(messagesSent == 3);
|
||||
REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK);
|
||||
REQUIRE(poolOwnerMock->receiveMessage(&messageSent) == retval::CATCH_OK);
|
||||
CHECK(messageSent.getCommand() ==
|
||||
static_cast<int>(HousekeepingMessage::UPDATE_NOTIFICATION_VARIABLE));
|
||||
REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK);
|
||||
REQUIRE(poolOwnerMock->receiveMessage(&messageSent) == retval::CATCH_OK);
|
||||
CHECK(messageSent.getCommand() ==
|
||||
static_cast<int>(HousekeepingMessage::UPDATE_NOTIFICATION_SET));
|
||||
REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK);
|
||||
REQUIRE(poolOwnerMock->receiveMessage(&messageSent) == retval::CATCH_OK);
|
||||
CHECK(messageSent.getCommand() == static_cast<int>(HousekeepingMessage::HK_REPORT));
|
||||
CommandMessageCleaner::clearCommandMessage(&messageSent);
|
||||
REQUIRE(mqMock->receiveMessage(&messageSent) == static_cast<int>(MessageQueueIF::EMPTY));
|
||||
REQUIRE(poolOwnerMock->receiveMessage(&messageSent) == static_cast<int>(MessageQueueIF::EMPTY));
|
||||
}
|
||||
|
||||
SECTION("PeriodicHKAndMessaging") {
|
||||
@ -263,38 +257,38 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") {
|
||||
REQUIRE(poolOwner->subscribePeriodicHk(true) == retval::CATCH_OK);
|
||||
REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK);
|
||||
/* Now HK packet should be sent as message immediately. */
|
||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
||||
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||
CHECK(messagesSent == 1);
|
||||
CHECK(mqMock->popMessage() == retval::CATCH_OK);
|
||||
CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
|
||||
|
||||
LocalPoolDataSetBase* setHandle = poolOwner->getDataSetHandle(lpool::testSid);
|
||||
REQUIRE(setHandle != nullptr);
|
||||
CHECK(poolOwner->poolManager.generateHousekeepingPacket(lpool::testSid, setHandle, false) ==
|
||||
retval::CATCH_OK);
|
||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
||||
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||
CHECK(messagesSent == 1);
|
||||
CHECK(mqMock->popMessage() == retval::CATCH_OK);
|
||||
CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
|
||||
|
||||
CHECK(setHandle->getReportingEnabled() == true);
|
||||
CommandMessage hkCmd;
|
||||
HousekeepingMessage::setToggleReportingCommand(&hkCmd, lpool::testSid, false, false);
|
||||
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK);
|
||||
CHECK(setHandle->getReportingEnabled() == false);
|
||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
||||
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||
CHECK(messagesSent == 1);
|
||||
CHECK(mqMock->popMessage() == retval::CATCH_OK);
|
||||
CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
|
||||
|
||||
HousekeepingMessage::setToggleReportingCommand(&hkCmd, lpool::testSid, true, false);
|
||||
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK);
|
||||
CHECK(setHandle->getReportingEnabled() == true);
|
||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
||||
CHECK(mqMock->popMessage() == retval::CATCH_OK);
|
||||
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||
CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
|
||||
|
||||
HousekeepingMessage::setToggleReportingCommand(&hkCmd, lpool::testSid, false, false);
|
||||
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK);
|
||||
CHECK(setHandle->getReportingEnabled() == false);
|
||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
||||
CHECK(mqMock->popMessage() == retval::CATCH_OK);
|
||||
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||
CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
|
||||
|
||||
HousekeepingMessage::setCollectionIntervalModificationCommand(&hkCmd, lpool::testSid, 0.4,
|
||||
false);
|
||||
@ -302,23 +296,23 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") {
|
||||
/* For non-diagnostics and a specified minimum frequency of 0.2 seconds, the
|
||||
resulting collection interval should be 1.0 second */
|
||||
CHECK(poolOwner->dataset.getCollectionInterval() == 1.0);
|
||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
||||
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||
CHECK(messagesSent == 1);
|
||||
CHECK(mqMock->popMessage() == retval::CATCH_OK);
|
||||
CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
|
||||
|
||||
HousekeepingMessage::setStructureReportingCommand(&hkCmd, lpool::testSid, false);
|
||||
REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK);
|
||||
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK);
|
||||
/* Now HK packet should be sent as message. */
|
||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
||||
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||
CHECK(messagesSent == 1);
|
||||
CHECK(mqMock->popMessage() == retval::CATCH_OK);
|
||||
CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
|
||||
|
||||
HousekeepingMessage::setOneShotReportCommand(&hkCmd, lpool::testSid, false);
|
||||
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK);
|
||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
||||
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||
CHECK(messagesSent == 1);
|
||||
CHECK(mqMock->popMessage() == retval::CATCH_OK);
|
||||
CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
|
||||
|
||||
HousekeepingMessage::setUpdateNotificationSetCommand(&hkCmd, lpool::testSid);
|
||||
sid_t sidToCheck;
|
||||
@ -334,62 +328,62 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") {
|
||||
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) ==
|
||||
static_cast<int>(LocalDataPoolManager::WRONG_HK_PACKET_TYPE));
|
||||
/* We still expect a failure message being sent */
|
||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
||||
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||
CHECK(messagesSent == 1);
|
||||
CHECK(mqMock->popMessage() == retval::CATCH_OK);
|
||||
CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
|
||||
|
||||
HousekeepingMessage::setCollectionIntervalModificationCommand(&hkCmd, lpool::testSid, 0.4,
|
||||
false);
|
||||
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) ==
|
||||
static_cast<int>(LocalDataPoolManager::WRONG_HK_PACKET_TYPE));
|
||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
||||
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||
CHECK(messagesSent == 1);
|
||||
CHECK(mqMock->popMessage() == retval::CATCH_OK);
|
||||
CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
|
||||
|
||||
HousekeepingMessage::setStructureReportingCommand(&hkCmd, lpool::testSid, false);
|
||||
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) ==
|
||||
static_cast<int>(LocalDataPoolManager::WRONG_HK_PACKET_TYPE));
|
||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
||||
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||
CHECK(messagesSent == 1);
|
||||
CHECK(mqMock->popMessage() == retval::CATCH_OK);
|
||||
CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
|
||||
|
||||
HousekeepingMessage::setStructureReportingCommand(&hkCmd, lpool::testSid, true);
|
||||
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK);
|
||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
||||
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||
CHECK(messagesSent == 1);
|
||||
CHECK(mqMock->popMessage() == retval::CATCH_OK);
|
||||
CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
|
||||
|
||||
HousekeepingMessage::setCollectionIntervalModificationCommand(&hkCmd, lpool::testSid, 0.4,
|
||||
true);
|
||||
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK);
|
||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
||||
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||
CHECK(messagesSent == 1);
|
||||
CHECK(mqMock->popMessage() == retval::CATCH_OK);
|
||||
CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
|
||||
|
||||
HousekeepingMessage::setToggleReportingCommand(&hkCmd, lpool::testSid, true, true);
|
||||
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK);
|
||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
||||
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||
CHECK(messagesSent == 1);
|
||||
CHECK(mqMock->popMessage() == retval::CATCH_OK);
|
||||
CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
|
||||
|
||||
HousekeepingMessage::setToggleReportingCommand(&hkCmd, lpool::testSid, false, true);
|
||||
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK);
|
||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
||||
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||
CHECK(messagesSent == 1);
|
||||
CHECK(mqMock->popMessage() == retval::CATCH_OK);
|
||||
CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
|
||||
|
||||
HousekeepingMessage::setOneShotReportCommand(&hkCmd, lpool::testSid, false);
|
||||
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) ==
|
||||
static_cast<int>(LocalDataPoolManager::WRONG_HK_PACKET_TYPE));
|
||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
||||
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||
CHECK(messagesSent == 1);
|
||||
CHECK(mqMock->popMessage() == retval::CATCH_OK);
|
||||
CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
|
||||
|
||||
HousekeepingMessage::setOneShotReportCommand(&hkCmd, lpool::testSid, true);
|
||||
CHECK(poolOwner->poolManager.handleHousekeepingMessage(&hkCmd) == retval::CATCH_OK);
|
||||
REQUIRE(mqMock->wasMessageSent(&messagesSent) == true);
|
||||
REQUIRE(poolOwnerMock->wasMessageSent(&messagesSent) == true);
|
||||
CHECK(messagesSent == 1);
|
||||
CHECK(mqMock->popMessage() == retval::CATCH_OK);
|
||||
CHECK(poolOwnerMock->popMessage() == retval::CATCH_OK);
|
||||
|
||||
HousekeepingMessage::setUpdateNotificationVariableCommand(&hkCmd, lpool::uint8VarGpid);
|
||||
gp_id_t gpidToCheck;
|
||||
@ -415,5 +409,5 @@ TEST_CASE("LocalPoolManagerTest", "[LocManTest]") {
|
||||
/* we need to reset the subscription list because the pool owner
|
||||
is a global object. */
|
||||
CHECK(poolOwner->reset() == retval::CATCH_OK);
|
||||
mqMock->clearMessages(true);
|
||||
poolOwnerMock->clearMessages(true);
|
||||
}
|
||||
|
@ -2,4 +2,6 @@ target_sources(${FSFW_TEST_TGT} PRIVATE
|
||||
testDleEncoder.cpp
|
||||
testOpDivider.cpp
|
||||
testBitutil.cpp
|
||||
testCRC.cpp
|
||||
testTimevalOperations.cpp
|
||||
)
|
||||
|
14
tests/src/fsfw_tests/unit/globalfunctions/testCRC.cpp
Normal file
14
tests/src/fsfw_tests/unit/globalfunctions/testCRC.cpp
Normal file
@ -0,0 +1,14 @@
|
||||
#include <array>
|
||||
|
||||
#include "catch2/catch_test_macros.hpp"
|
||||
#include "fsfw/globalfunctions/CRC.h"
|
||||
#include "fsfw_tests/unit/CatchDefinitions.h"
|
||||
|
||||
TEST_CASE("CRC", "[CRC]") {
|
||||
std::array<uint8_t, 10> testData = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
uint16_t crc = CRC::crc16ccitt(testData.data(), 10);
|
||||
REQUIRE(crc == 49729);
|
||||
for (uint8_t index = 0; index < testData.size(); index++) {
|
||||
REQUIRE(testData[index] == index);
|
||||
}
|
||||
}
|
@ -0,0 +1,124 @@
|
||||
#include <fsfw/globalfunctions/timevalOperations.h>
|
||||
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include "fsfw_tests/unit/CatchDefinitions.h"
|
||||
|
||||
TEST_CASE("TimevalTest", "[timevalOperations]") {
|
||||
SECTION("Comparison") {
|
||||
timeval t1;
|
||||
t1.tv_sec = 1648227422;
|
||||
t1.tv_usec = 123456;
|
||||
timeval t2;
|
||||
t2.tv_sec = 1648227422;
|
||||
t2.tv_usec = 123456;
|
||||
REQUIRE(t1 == t2);
|
||||
REQUIRE(t2 == t1);
|
||||
REQUIRE_FALSE(t1 != t2);
|
||||
REQUIRE_FALSE(t2 != t1);
|
||||
REQUIRE(t1 <= t2);
|
||||
REQUIRE(t2 <= t1);
|
||||
REQUIRE(t1 >= t2);
|
||||
REQUIRE(t2 >= t1);
|
||||
REQUIRE_FALSE(t1 < t2);
|
||||
REQUIRE_FALSE(t2 < t1);
|
||||
REQUIRE_FALSE(t1 > t2);
|
||||
REQUIRE_FALSE(t2 > t1);
|
||||
|
||||
timeval t3;
|
||||
t3.tv_sec = 1648227422;
|
||||
t3.tv_usec = 123457;
|
||||
REQUIRE_FALSE(t1 == t3);
|
||||
REQUIRE(t1 != t3);
|
||||
REQUIRE(t1 <= t3);
|
||||
REQUIRE_FALSE(t3 <= t1);
|
||||
REQUIRE_FALSE(t1 >= t3);
|
||||
REQUIRE(t3 >= t1);
|
||||
REQUIRE(t1 < t3);
|
||||
REQUIRE_FALSE(t3 < t1);
|
||||
REQUIRE_FALSE(t1 > t3);
|
||||
REQUIRE(t3 > t1);
|
||||
|
||||
timeval t4;
|
||||
t4.tv_sec = 1648227423;
|
||||
t4.tv_usec = 123456;
|
||||
REQUIRE_FALSE(t1 == t4);
|
||||
REQUIRE(t1 != t4);
|
||||
REQUIRE(t1 <= t4);
|
||||
REQUIRE_FALSE(t4 <= t1);
|
||||
REQUIRE_FALSE(t1 >= t4);
|
||||
REQUIRE(t4 >= t1);
|
||||
REQUIRE(t1 < t4);
|
||||
REQUIRE_FALSE(t4 < t1);
|
||||
REQUIRE_FALSE(t1 > t4);
|
||||
REQUIRE(t4 > t1);
|
||||
}
|
||||
SECTION("Operators") {
|
||||
timeval t1;
|
||||
t1.tv_sec = 1648227422;
|
||||
t1.tv_usec = 123456;
|
||||
timeval t2;
|
||||
t2.tv_sec = 1648227422;
|
||||
t2.tv_usec = 123456;
|
||||
timeval t3 = t1 - t2;
|
||||
REQUIRE(t3.tv_sec == 0);
|
||||
REQUIRE(t3.tv_usec == 0);
|
||||
timeval t4 = t1 - t3;
|
||||
REQUIRE(t4.tv_sec == 1648227422);
|
||||
REQUIRE(t4.tv_usec == 123456);
|
||||
timeval t5 = t3 - t1;
|
||||
REQUIRE(t5.tv_sec == -1648227422);
|
||||
REQUIRE(t5.tv_usec == -123456);
|
||||
|
||||
timeval t6;
|
||||
t6.tv_sec = 1648227400;
|
||||
t6.tv_usec = 999999;
|
||||
|
||||
timeval t7 = t6 + t1;
|
||||
REQUIRE(t7.tv_sec == (1648227422ull + 1648227400ull + 1ull));
|
||||
REQUIRE(t7.tv_usec == 123455);
|
||||
|
||||
timeval t8 = t1 - t6;
|
||||
REQUIRE(t8.tv_sec == 1648227422 - 1648227400 - 1);
|
||||
REQUIRE(t8.tv_usec == 123457);
|
||||
|
||||
double scalar = 2;
|
||||
timeval t9 = t1 * scalar;
|
||||
REQUIRE(t9.tv_sec == 3296454844);
|
||||
REQUIRE(t9.tv_usec == 246912);
|
||||
timeval t10 = scalar * t1;
|
||||
REQUIRE(t10.tv_sec == 3296454844);
|
||||
REQUIRE(t10.tv_usec == 246912);
|
||||
timeval t11 = t6 * scalar;
|
||||
REQUIRE(t11.tv_sec == (3296454800 + 1));
|
||||
REQUIRE(t11.tv_usec == 999998);
|
||||
|
||||
timeval t12 = t1 / scalar;
|
||||
REQUIRE(t12.tv_sec == 824113711);
|
||||
REQUIRE(t12.tv_usec == 61728);
|
||||
|
||||
timeval t13 = t6 / scalar;
|
||||
REQUIRE(t13.tv_sec == 824113700);
|
||||
// Rounding issue
|
||||
REQUIRE(t13.tv_usec == 499999);
|
||||
|
||||
double scalar2 = t9 / t1;
|
||||
REQUIRE(scalar2 == Catch::Approx(2.0));
|
||||
double scalar3 = t1 / t6;
|
||||
REQUIRE(scalar3 == Catch::Approx(1.000000013));
|
||||
double scalar4 = t3 / t1;
|
||||
REQUIRE(scalar4 == Catch::Approx(0));
|
||||
double scalar5 = t12 / t1;
|
||||
REQUIRE(scalar5 == Catch::Approx(0.5));
|
||||
}
|
||||
|
||||
SECTION("timevalOperations::toTimeval") {
|
||||
double seconds = 1648227422.123456;
|
||||
timeval t1 = timevalOperations::toTimeval(seconds);
|
||||
REQUIRE(t1.tv_sec == 1648227422);
|
||||
// Allow 1 usec rounding tolerance
|
||||
REQUIRE(t1.tv_usec >= 123455);
|
||||
REQUIRE(t1.tv_usec <= 123457);
|
||||
}
|
||||
}
|
3
tests/src/fsfw_tests/unit/internalerror/CMakeLists.txt
Normal file
3
tests/src/fsfw_tests/unit/internalerror/CMakeLists.txt
Normal file
@ -0,0 +1,3 @@
|
||||
target_sources(${FSFW_TEST_TGT} PRIVATE
|
||||
TestInternalErrorReporter.cpp
|
||||
)
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user