Compare commits
64 Commits
9f7b9be800
...
docker_d2
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 | |||
17771c0497 | |||
c05184e1c4 | |||
![]() |
b2252bdc0b | ||
![]() |
6c1db8473b | ||
1a530633ca | |||
8037e8074b | |||
d07e0e5576 | |||
5525466b52 | |||
c2a89bf709 | |||
8dd0b2608d | |||
05495077ec | |||
8ff9eadf30 | |||
082c86ea18 | |||
2800d6f28c | |||
b4effe7a46 | |||
e6e71436c2 | |||
a887f852c8 | |||
0b3255e463 | |||
631a531212 | |||
665d8cd479 | |||
10398855a9 | |||
d0fec93dc3 | |||
59ab54b2fb | |||
7095999bd2 | |||
7ffb4107d2 | |||
9ce59d3c75 |
20
CHANGELOG.md
20
CHANGELOG.md
@@ -24,6 +24,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
- `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
|
||||
|
||||
@@ -37,6 +47,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
- 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]
|
||||
|
||||
|
@@ -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,7 +65,7 @@ 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 QUIET)
|
||||
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")
|
||||
@@ -57,11 +74,12 @@ if(FSFW_BUILD_UNITTESTS)
|
||||
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()
|
||||
|
||||
@@ -89,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)
|
||||
@@ -350,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}
|
||||
)
|
||||
|
||||
|
45
README.md
45
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
|
||||
@@ -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
|
||||
|
2
automation/Jenkinsfile
vendored
2
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') {
|
||||
|
@@ -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`.
|
||||
|
@@ -1,9 +1,9 @@
|
||||
#include "MgmLIS3MDLHandler.h"
|
||||
|
||||
#include "fsfw/datapool/PoolReadGuard.h"
|
||||
|
||||
#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),
|
||||
|
@@ -1,27 +0,0 @@
|
||||
#ifndef FSFW_HAL_SRC_FSFW_HAL_LINUX_GPIO_GPIO_H_
|
||||
#define FSFW_HAL_SRC_FSFW_HAL_LINUX_GPIO_GPIO_H_
|
||||
|
||||
#include "fsfw_hal/common/gpio/GpioIF.h"
|
||||
#include "fsfw_hal/common/gpio/gpioDefinitions.h"
|
||||
|
||||
/**
|
||||
* @brief Additional abstraction layer for handling GPIOs.
|
||||
*
|
||||
* @author J. Meier
|
||||
*/
|
||||
class Gpio {
|
||||
public:
|
||||
Gpio(gpioId_t gpioId, GpioIF* gpioIF) : gpioId(gpioId), gpioIF(gpioIF) {
|
||||
if (gpioIF == nullptr) {
|
||||
sif::error << "Gpio::Gpio: Invalid GpioIF" << std::endl;
|
||||
}
|
||||
}
|
||||
ReturnValue_t pullHigh() { return gpioIF->pullHigh(gpioId); }
|
||||
ReturnValue_t pullLow() { return gpioIF->pullLow(gpioId); }
|
||||
|
||||
private:
|
||||
gpioId_t gpioId = gpio::NO_GPIO;
|
||||
GpioIF* gpioIF = nullptr;
|
||||
};
|
||||
|
||||
#endif /* FSFW_HAL_SRC_FSFW_HAL_LINUX_GPIO_GPIO_H_ */
|
@@ -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,
|
||||
|
@@ -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();
|
||||
|
@@ -2,8 +2,8 @@
|
||||
|
||||
#include <fsfw/serviceinterface.h>
|
||||
|
||||
UartCookie::UartCookie(object_id_t handlerId, std::string deviceFile, UartBaudRate baudrate,
|
||||
size_t maxReplyLen, UartModes uartMode)
|
||||
UartCookie::UartCookie(object_id_t handlerId, std::string deviceFile, UartModes uartMode,
|
||||
UartBaudRate baudrate, size_t maxReplyLen)
|
||||
: handlerId(handlerId),
|
||||
deviceFile(deviceFile),
|
||||
uartMode(uartMode),
|
||||
|
@@ -69,8 +69,8 @@ class UartCookie : public CookieIF {
|
||||
* 8 databits (number of bits transfered with one uart frame)
|
||||
* One stop bit
|
||||
*/
|
||||
UartCookie(object_id_t handlerId, std::string deviceFile, UartBaudRate baudrate,
|
||||
size_t maxReplyLen, UartModes uartMode = UartModes::NON_CANONICAL);
|
||||
UartCookie(object_id_t handlerId, std::string deviceFile, UartModes uartMode,
|
||||
UartBaudRate baudrate, size_t maxReplyLen);
|
||||
|
||||
virtual ~UartCookie();
|
||||
|
||||
|
@@ -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) {}
|
||||
|
@@ -16,8 +16,8 @@ class CommandActionHelper {
|
||||
public:
|
||||
CommandActionHelper(CommandsActionsIF* owner);
|
||||
virtual ~CommandActionHelper();
|
||||
ReturnValue_t commandAction(object_id_t commandTo, ActionId_t actionId,
|
||||
const uint8_t* data = nullptr, uint32_t size = 0);
|
||||
ReturnValue_t commandAction(object_id_t commandTo, ActionId_t actionId, const uint8_t* data,
|
||||
uint32_t size);
|
||||
ReturnValue_t commandAction(object_id_t commandTo, ActionId_t actionId, SerializeIF* data);
|
||||
ReturnValue_t initialize();
|
||||
ReturnValue_t handleReply(CommandMessage* reply);
|
||||
|
@@ -12,9 +12,7 @@ object_id_t CFDPHandler::packetDestination = 0;
|
||||
|
||||
CFDPHandler::CFDPHandler(object_id_t setObjectId, CFDPDistributor* dist)
|
||||
: SystemObject(setObjectId) {
|
||||
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
|
||||
requestQueue = QueueFactory::instance()->createMessageQueue(
|
||||
CFDP_HANDLER_MAX_RECEPTION, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||
requestQueue = QueueFactory::instance()->createMessageQueue(CFDP_HANDLER_MAX_RECEPTION);
|
||||
distributor = dist;
|
||||
}
|
||||
|
||||
|
@@ -10,24 +10,16 @@ class HybridIterator : public LinkedElement<T>::Iterator, public ArrayList<T, co
|
||||
HybridIterator() {}
|
||||
|
||||
HybridIterator(typename LinkedElement<T>::Iterator *iter)
|
||||
: LinkedElement<T>::Iterator(*iter), value(iter->value), linked(true) {
|
||||
if(iter != nullptr) {
|
||||
value = iter->value;
|
||||
}
|
||||
}
|
||||
: LinkedElement<T>::Iterator(*iter), value(iter->value), linked(true) {}
|
||||
|
||||
HybridIterator(LinkedElement<T> *start)
|
||||
: LinkedElement<T>::Iterator(start), linked(true) {
|
||||
if(start != nullptr) {
|
||||
value = start->value;
|
||||
}
|
||||
}
|
||||
: LinkedElement<T>::Iterator(start), value(start->value), linked(true) {}
|
||||
|
||||
HybridIterator(typename ArrayList<T, count_t>::Iterator start,
|
||||
typename ArrayList<T, count_t>::Iterator end)
|
||||
: ArrayList<T, count_t>::Iterator(start), value(start.value), linked(false), end(end.value) {
|
||||
if (value == this->end) {
|
||||
value = nullptr;
|
||||
value = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -13,9 +13,7 @@ ControllerBase::ControllerBase(object_id_t setObjectId, object_id_t parentId,
|
||||
submode(SUBMODE_NONE),
|
||||
modeHelper(this),
|
||||
healthHelper(this, setObjectId) {
|
||||
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(
|
||||
commandQueueDepth, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(commandQueueDepth);
|
||||
}
|
||||
|
||||
ControllerBase::~ControllerBase() { QueueFactory::instance()->deleteMessageQueue(commandQueue); }
|
||||
|
@@ -1,4 +1,4 @@
|
||||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
||||
PoolDataSetBase.cpp
|
||||
PoolEntry.cpp
|
||||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
||||
PoolDataSetBase.cpp
|
||||
PoolEntry.cpp
|
||||
)
|
@@ -7,26 +7,24 @@
|
||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||
|
||||
template <typename T>
|
||||
PoolEntry<T>::PoolEntry(uint8_t len, bool setValid): length(len), valid(setValid) {
|
||||
this->address = new T[this->length]();
|
||||
std::memset(this->address, 0, this->getByteSize());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
PoolEntry<T>::PoolEntry(std::initializer_list<T> initValues, bool setValid)
|
||||
: length(static_cast<uint8_t>(initValues.size())), valid(setValid) {
|
||||
this->address = new T[this->length]();
|
||||
if (initValues.size() > 0) {
|
||||
std::copy(initValues.begin(), initValues.end(), this->address);
|
||||
PoolEntry<T>::PoolEntry(std::initializer_list<T> initValue, bool setValid)
|
||||
: length(static_cast<uint8_t>(initValue.size())), valid(setValid) {
|
||||
this->address = new T[this->length];
|
||||
if (initValue.size() == 0) {
|
||||
std::memset(this->address, 0, this->getByteSize());
|
||||
} else {
|
||||
std::copy(initValue.begin(), initValue.end(), this->address);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
PoolEntry<T>::PoolEntry(const T* initValue, uint8_t setLength, bool setValid)
|
||||
PoolEntry<T>::PoolEntry(T* initValue, uint8_t setLength, bool setValid)
|
||||
: length(setLength), valid(setValid) {
|
||||
this->address = new T[this->length]();
|
||||
this->address = new T[this->length];
|
||||
if (initValue != nullptr) {
|
||||
std::memcpy(this->address, initValue, this->getByteSize());
|
||||
} else {
|
||||
std::memset(this->address, 0, this->getByteSize());
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -33,9 +33,6 @@ class PoolEntry : public PoolEntryIF {
|
||||
"instead! The ECSS standard defines a boolean as a one bit "
|
||||
"field. Therefore it is preferred to store a boolean as an "
|
||||
"uint8_t");
|
||||
|
||||
PoolEntry(uint8_t len = 1, bool setValid = false);
|
||||
|
||||
/**
|
||||
* @brief In the classe's constructor, space is allocated on the heap and
|
||||
* potential initialization values are copied to that space.
|
||||
@@ -52,7 +49,7 @@ class PoolEntry : public PoolEntryIF {
|
||||
* @param setValid
|
||||
* Sets the initialization flag. It is invalid by default.
|
||||
*/
|
||||
PoolEntry(std::initializer_list<T> initValue, bool setValid = false);
|
||||
PoolEntry(std::initializer_list<T> initValue = {0}, bool setValid = false);
|
||||
|
||||
/**
|
||||
* @brief In the classe's constructor, space is allocated on the heap and
|
||||
@@ -65,7 +62,7 @@ class PoolEntry : public PoolEntryIF {
|
||||
* @param setValid
|
||||
* Sets the initialization flag. It is invalid by default.
|
||||
*/
|
||||
PoolEntry(const T* initValue, uint8_t setLength = 1, bool setValid = false);
|
||||
PoolEntry(T* initValue, uint8_t setLength = 1, bool setValid = false);
|
||||
|
||||
//! Explicitely deleted copy ctor, copying is not allowed.
|
||||
PoolEntry(const PoolEntry&) = delete;
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -162,7 +162,6 @@ class LocalPoolDataSetBase : public PoolDataSetBase, public MarkChangedIF {
|
||||
object_id_t getCreatorObjectId();
|
||||
|
||||
bool getReportingEnabled() const;
|
||||
void setReportingEnabled(bool enabled);
|
||||
|
||||
/**
|
||||
* Returns the current periodic HK generation interval this set
|
||||
@@ -190,6 +189,7 @@ class LocalPoolDataSetBase : public PoolDataSetBase, public MarkChangedIF {
|
||||
* Used for periodic generation.
|
||||
*/
|
||||
bool reportingEnabled = false;
|
||||
void setReportingEnabled(bool enabled);
|
||||
|
||||
void initializePeriodicHelper(float collectionInterval, dur_millis_t minimumPeriodicInterval,
|
||||
uint8_t nonDiagIntervalFactor = 5);
|
||||
|
@@ -26,7 +26,11 @@ void AssemblyBase::performChildOperation() {
|
||||
|
||||
void AssemblyBase::startTransition(Mode_t mode, Submode_t submode) {
|
||||
doStartTransition(mode, submode);
|
||||
triggerModeHelperEvents(mode, submode);
|
||||
if (modeHelper.isForced()) {
|
||||
triggerEvent(FORCING_MODE, mode, submode);
|
||||
} else {
|
||||
triggerEvent(CHANGING_MODE, mode, submode);
|
||||
}
|
||||
}
|
||||
|
||||
void AssemblyBase::doStartTransition(Mode_t mode, Submode_t submode) {
|
||||
@@ -73,10 +77,9 @@ bool AssemblyBase::handleChildrenChangedHealth() {
|
||||
}
|
||||
HealthState healthState = healthHelper.healthTable->getHealth(iter->first);
|
||||
if (healthState == HasHealthIF::NEEDS_RECOVERY) {
|
||||
triggerEvent(TRYING_RECOVERY, iter->first, 0);
|
||||
triggerEvent(TRYING_RECOVERY);
|
||||
recoveryState = RECOVERY_STARTED;
|
||||
recoveringDevice = iter;
|
||||
// The user needs to take care of commanding the children off in commandChildren
|
||||
doStartTransition(targetMode, targetSubmode);
|
||||
} else {
|
||||
triggerEvent(CHILD_CHANGED_HEALTH);
|
||||
@@ -225,9 +228,6 @@ ReturnValue_t AssemblyBase::handleHealthReply(CommandMessage* message) {
|
||||
bool AssemblyBase::checkAndHandleRecovery() {
|
||||
switch (recoveryState) {
|
||||
case RECOVERY_STARTED:
|
||||
// The recovery was already start in #handleChildrenChangedHealth and we just need
|
||||
// to wait for an off time period.
|
||||
// TODO: make time period configurable
|
||||
recoveryState = RECOVERY_WAIT;
|
||||
recoveryOffTimer.resetTimer();
|
||||
return true;
|
||||
@@ -266,11 +266,3 @@ void AssemblyBase::overwriteDeviceHealth(object_id_t objectId, HasHealthIF::Heal
|
||||
modeHelper.setForced(true);
|
||||
sendHealthCommand(childrenMap[objectId].commandQueue, EXTERNAL_CONTROL);
|
||||
}
|
||||
|
||||
void AssemblyBase::triggerModeHelperEvents(Mode_t mode, Submode_t submode) {
|
||||
if (modeHelper.isForced()) {
|
||||
triggerEvent(FORCING_MODE, mode, submode);
|
||||
} else {
|
||||
triggerEvent(CHANGING_MODE, mode, submode);
|
||||
}
|
||||
}
|
||||
|
@@ -12,8 +12,7 @@
|
||||
* Documentation: Dissertation Baetz p.156, 157.
|
||||
*
|
||||
* This class reduces the complexity of controller components which would
|
||||
* otherwise be needed for the handling of redundant devices. However, it can also be used to
|
||||
* manage the mode keeping and recovery of non-redundant devices
|
||||
* otherwise be needed for the handling of redundant devices.
|
||||
*
|
||||
* The template class monitors mode and health state of its children
|
||||
* and checks availability of devices on every detected change.
|
||||
@@ -27,9 +26,11 @@
|
||||
*
|
||||
* Important:
|
||||
*
|
||||
* The implementation must call #registerChild for all commanded children during initialization.
|
||||
* The implementation must call registerChild(object_id_t child)
|
||||
* for all commanded children during initialization.
|
||||
* The implementation must call the initialization function of the base class.
|
||||
* (This will call the function in SubsystemBase)
|
||||
*
|
||||
*/
|
||||
class AssemblyBase : public SubsystemBase {
|
||||
public:
|
||||
@@ -46,14 +47,13 @@ class AssemblyBase : public SubsystemBase {
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Command children to reach [mode,submode] combination. Can be done by setting
|
||||
* #commandsOutstanding correctly, or using #executeTable. In case of an FDIR recovery,
|
||||
* the user needs to ensure that the target devices are healthy. If a device is not healthy,
|
||||
* a recovery might be on-going and the device needs to be commanded to off first.
|
||||
* Command children to reach [mode,submode] combination
|
||||
* Can be done by setting #commandsOutstanding correctly,
|
||||
* or using executeTable()
|
||||
* @param mode
|
||||
* @param submode
|
||||
* @return
|
||||
* - @c RETURN_OK if OK
|
||||
* - @c RETURN_OK if ok
|
||||
* - @c NEED_SECOND_STEP if children need to be commanded again
|
||||
*/
|
||||
virtual ReturnValue_t commandChildren(Mode_t mode, Submode_t submode) = 0;
|
||||
@@ -120,19 +120,8 @@ class AssemblyBase : public SubsystemBase {
|
||||
|
||||
virtual ReturnValue_t handleHealthReply(CommandMessage *message);
|
||||
|
||||
/**
|
||||
* @brief Default periodic handler
|
||||
* @details
|
||||
* This is the default periodic handler which will be called by the SubsystemBase
|
||||
* performOperation. It performs the child transitions or reacts to changed health/mode states
|
||||
* of children objects
|
||||
*/
|
||||
virtual void performChildOperation() override;
|
||||
virtual void performChildOperation();
|
||||
|
||||
/**
|
||||
* This function handles changed mode or health states of children
|
||||
* @return
|
||||
*/
|
||||
bool handleChildrenChanged();
|
||||
|
||||
/**
|
||||
@@ -145,37 +134,12 @@ class AssemblyBase : public SubsystemBase {
|
||||
|
||||
bool handleChildrenChangedHealth();
|
||||
|
||||
/**
|
||||
* Core transition handler. The default implementation will only do something if
|
||||
* #commandsOutstanding is smaller or equal to zero, which means that all mode commands
|
||||
* from the #doPerformTransition call were executed successfully.
|
||||
*
|
||||
* Unless a second step was requested, the function will then use #checkChildrenState to
|
||||
* determine whether the target mode was reached.
|
||||
*
|
||||
* There is some special handling for certain (internal) modes:
|
||||
* - A second step is necessary. #commandChildren will be performed again
|
||||
* - The device health was overwritten. #commandChildren will be called
|
||||
* - A recovery is ongoing. #checkAndHandleRecovery will be called.
|
||||
*/
|
||||
virtual void handleChildrenTransition();
|
||||
|
||||
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, uint32_t *msToReachTheMode);
|
||||
|
||||
/**
|
||||
* Calls #doStartTransition and triggers an informative event as well that the mode will
|
||||
* change
|
||||
* @param mode
|
||||
* @param submode
|
||||
*/
|
||||
virtual void startTransition(Mode_t mode, Submode_t submode);
|
||||
|
||||
/**
|
||||
* This function starts the transition by setting the internal #targetSubmode and #targetMode
|
||||
* variables and then calling the #commandChildren function.
|
||||
* @param mode
|
||||
* @param submode
|
||||
*/
|
||||
virtual void doStartTransition(Mode_t mode, Submode_t submode);
|
||||
|
||||
virtual bool isInTransition();
|
||||
@@ -196,7 +160,7 @@ class AssemblyBase : public SubsystemBase {
|
||||
* Manages recovery of a device
|
||||
* @return true if recovery is still ongoing, false else.
|
||||
*/
|
||||
virtual bool checkAndHandleRecovery();
|
||||
bool checkAndHandleRecovery();
|
||||
|
||||
/**
|
||||
* Helper method to overwrite health state of one of the children.
|
||||
@@ -204,8 +168,6 @@ class AssemblyBase : public SubsystemBase {
|
||||
* @param objectId Must be a registered child.
|
||||
*/
|
||||
void overwriteDeviceHealth(object_id_t objectId, HasHealthIF::HealthState oldHealth);
|
||||
|
||||
void triggerModeHelperEvents(Mode_t mode, Submode_t submode);
|
||||
};
|
||||
|
||||
#endif /* FSFW_DEVICEHANDLERS_ASSEMBLYBASE_H_ */
|
||||
|
@@ -39,9 +39,8 @@ DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, object_id_t device
|
||||
childTransitionDelay(5000),
|
||||
transitionSourceMode(_MODE_POWER_DOWN),
|
||||
transitionSourceSubMode(SUBMODE_NONE) {
|
||||
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(
|
||||
cmdQueueSize, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||
cmdQueueSize, MessageQueueMessage::MAX_MESSAGE_SIZE);
|
||||
insertInCommandMap(RAW_COMMAND_ID);
|
||||
cookieInfo.state = COOKIE_UNUSED;
|
||||
cookieInfo.pendingCommand = deviceCommandMap.end();
|
||||
@@ -49,6 +48,9 @@ DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, object_id_t device
|
||||
printWarningOrError(sif::OutputTypes::OUT_ERROR, "DeviceHandlerBase",
|
||||
HasReturnvaluesIF::RETURN_FAILED, "Invalid cookie");
|
||||
}
|
||||
if (this->fdirInstance == nullptr) {
|
||||
this->fdirInstance = new DeviceHandlerFailureIsolation(setObjectId, defaultFdirParentId);
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceHandlerBase::setHkDestination(object_id_t hkDestination) {
|
||||
@@ -124,18 +126,6 @@ ReturnValue_t DeviceHandlerBase::initialize() {
|
||||
if (result != RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
if (this->fdirInstance == nullptr) {
|
||||
this->fdirInstance =
|
||||
new DeviceHandlerFailureIsolation(this->getObjectId(), defaultFdirParentId);
|
||||
}
|
||||
|
||||
if (this->parent != objects::NO_OBJECT) {
|
||||
HasModesIF* modeIF = ObjectManager::instance()->get<HasModesIF>(this->parent);
|
||||
HasHealthIF* healthIF = ObjectManager::instance()->get<HasHealthIF>(this->parent);
|
||||
if (modeIF != nullptr and healthIF != nullptr) {
|
||||
setParentQueue(modeIF->getCommandQueue());
|
||||
}
|
||||
}
|
||||
|
||||
communicationInterface =
|
||||
ObjectManager::instance()->get<DeviceCommunicationIF>(deviceCommunicationId);
|
||||
@@ -362,12 +352,14 @@ void DeviceHandlerBase::doStateMachine() {
|
||||
}
|
||||
} break;
|
||||
case _MODE_WAIT_OFF: {
|
||||
uint32_t currentUptime;
|
||||
Clock::getUptime(¤tUptime);
|
||||
|
||||
if (powerSwitcher == nullptr) {
|
||||
setMode(MODE_OFF);
|
||||
break;
|
||||
}
|
||||
uint32_t currentUptime;
|
||||
Clock::getUptime(¤tUptime);
|
||||
|
||||
if (currentUptime - timeoutStart >= powerSwitcher->getSwitchDelayMs()) {
|
||||
triggerEvent(MODE_TRANSITION_FAILED, PowerSwitchIF::SWITCH_TIMEOUT, 0);
|
||||
setMode(MODE_ERROR_ON);
|
||||
@@ -1407,8 +1399,6 @@ void DeviceHandlerBase::setTaskIF(PeriodicTaskIF* task) { executingTask = task;
|
||||
void DeviceHandlerBase::debugInterface(uint8_t positionTracker, object_id_t objectId,
|
||||
uint32_t parameter) {}
|
||||
|
||||
Submode_t DeviceHandlerBase::getInitialSubmode() { return SUBMODE_NONE; }
|
||||
|
||||
void DeviceHandlerBase::performOperationHook() {}
|
||||
|
||||
ReturnValue_t DeviceHandlerBase::initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
|
||||
@@ -1431,7 +1421,7 @@ ReturnValue_t DeviceHandlerBase::initializeAfterTaskCreation() {
|
||||
this->poolManager.initializeAfterTaskCreation();
|
||||
|
||||
if (setStartupImmediately) {
|
||||
startTransition(MODE_ON, getInitialSubmode());
|
||||
startTransition(MODE_ON, SUBMODE_NONE);
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
@@ -1515,11 +1505,3 @@ MessageQueueId_t DeviceHandlerBase::getCommanderQueueId(DeviceCommandId_t replyI
|
||||
}
|
||||
return commandIter->second.sendReplyTo;
|
||||
}
|
||||
|
||||
void DeviceHandlerBase::setCustomFdir(FailureIsolationBase* fdir) { this->fdirInstance = fdir; }
|
||||
|
||||
void DeviceHandlerBase::setParent(object_id_t parent) { this->parent = parent; }
|
||||
|
||||
void DeviceHandlerBase::setPowerSwitcher(PowerSwitchIF* switcher) {
|
||||
this->powerSwitcher = switcher;
|
||||
}
|
||||
|
@@ -103,9 +103,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
DeviceHandlerBase(object_id_t setObjectId, object_id_t deviceCommunication, CookieIF *comCookie,
|
||||
FailureIsolationBase *fdirInstance = nullptr, size_t cmdQueueSize = 20);
|
||||
|
||||
void setCustomFdir(FailureIsolationBase *fdir);
|
||||
void setParent(object_id_t parent);
|
||||
void setPowerSwitcher(PowerSwitchIF *switcher);
|
||||
void setHkDestination(object_id_t hkDestination);
|
||||
|
||||
/**
|
||||
@@ -652,12 +649,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
virtual void debugInterface(uint8_t positionTracker = 0, object_id_t objectId = 0,
|
||||
uint32_t parameter = 0);
|
||||
|
||||
/**
|
||||
* @brief Can be overwritten by a child to specify the initial submode when device has been set
|
||||
* to startup immediately.
|
||||
*/
|
||||
virtual Submode_t getInitialSubmode();
|
||||
|
||||
protected:
|
||||
static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_BASE;
|
||||
|
||||
@@ -831,7 +822,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
/** Pointer to the used FDIR instance. If not provided by child,
|
||||
* default class is instantiated. */
|
||||
FailureIsolationBase *fdirInstance;
|
||||
object_id_t parent = objects::NO_OBJECT;
|
||||
|
||||
//! To correctly delete the default instance.
|
||||
bool defaultFDIRUsed;
|
||||
|
@@ -29,7 +29,6 @@ ReturnValue_t DeviceHandlerFailureIsolation::eventReceived(EventMessage* event)
|
||||
switch (event->getEvent()) {
|
||||
case HasModesIF::MODE_TRANSITION_FAILED:
|
||||
case HasModesIF::OBJECT_IN_INVALID_MODE:
|
||||
case DeviceHandlerIF::DEVICE_WANTS_HARD_REBOOT:
|
||||
// We'll try a recovery as long as defined in MAX_REBOOT.
|
||||
// Might cause some AssemblyBase cycles, so keep number low.
|
||||
handleRecovery(event->getEvent());
|
||||
|
@@ -109,7 +109,6 @@ class DeviceHandlerIF {
|
||||
static const Event INVALID_DEVICE_COMMAND = MAKE_EVENT(8, severity::LOW);
|
||||
static const Event MONITORING_LIMIT_EXCEEDED = MAKE_EVENT(9, severity::LOW);
|
||||
static const Event MONITORING_AMBIGUOUS = MAKE_EVENT(10, severity::HIGH);
|
||||
static const Event DEVICE_WANTS_HARD_REBOOT = MAKE_EVENT(11, severity::HIGH);
|
||||
|
||||
static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_IF;
|
||||
|
||||
|
@@ -8,9 +8,7 @@ HealthDevice::HealthDevice(object_id_t setObjectId, MessageQueueId_t parentQueue
|
||||
parentQueue(parentQueue),
|
||||
commandQueue(),
|
||||
healthHelper(this, setObjectId) {
|
||||
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(
|
||||
3, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(3);
|
||||
}
|
||||
|
||||
HealthDevice::~HealthDevice() { QueueFactory::instance()->deleteMessageQueue(commandQueue); }
|
||||
|
@@ -18,9 +18,8 @@ const LocalPool::LocalPoolConfig EventManager::poolConfig = {
|
||||
EventManager::EventManager(object_id_t setObjectId)
|
||||
: SystemObject(setObjectId), factoryBackend(0, poolConfig, false, true) {
|
||||
mutex = MutexFactory::instance()->createMutex();
|
||||
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
|
||||
eventReportQueue = QueueFactory::instance()->createMessageQueue(
|
||||
MAX_EVENTS_PER_CYCLE, EventMessage::EVENT_MESSAGE_SIZE, &mqArgs);
|
||||
eventReportQueue = QueueFactory::instance()->createMessageQueue(MAX_EVENTS_PER_CYCLE,
|
||||
EventMessage::EVENT_MESSAGE_SIZE);
|
||||
}
|
||||
|
||||
EventManager::~EventManager() {
|
||||
@@ -47,20 +46,9 @@ ReturnValue_t EventManager::performOperation(uint8_t opCode) {
|
||||
|
||||
void EventManager::notifyListeners(EventMessage* message) {
|
||||
lockMutex();
|
||||
for (auto& listener : listenerList) {
|
||||
if (listener.second.match(message)) {
|
||||
ReturnValue_t result =
|
||||
MessageQueueSenderIF::sendMessage(listener.first, message, message->getSender());
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << std::hex << "EventManager::notifyListeners: MSG to 0x" << std::setfill('0')
|
||||
<< std::setw(8) << listener.first << " failed with result 0x" << std::setw(4)
|
||||
<< result << std::setfill(' ') << std::endl;
|
||||
#else
|
||||
sif::printError("Sending message to listener 0x%08x failed with result %04x\n",
|
||||
listener.first, result);
|
||||
#endif
|
||||
}
|
||||
for (auto iter = listenerList.begin(); iter != listenerList.end(); ++iter) {
|
||||
if (iter->second.match(message)) {
|
||||
MessageQueueSenderIF::sendMessage(iter->first, message, message->getSender());
|
||||
}
|
||||
}
|
||||
unlockMutex();
|
||||
@@ -201,19 +189,4 @@ void EventManager::printUtility(sif::OutputTypes printType, EventMessage* messag
|
||||
}
|
||||
}
|
||||
|
||||
void EventManager::printListeners() {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::info << "Event manager listener MQ IDs:" << std::setfill('0') << std::hex << std::endl;
|
||||
for (auto& listener : listenerList) {
|
||||
sif::info << "0x" << std::setw(8) << listener.first << std::endl;
|
||||
}
|
||||
sif::info << std::dec << std::setfill(' ');
|
||||
#else
|
||||
sif::printInfo("Event manager listener MQ IDs:\n");
|
||||
for (auto& listener : listenerList) {
|
||||
sif::printInfo("0x%08x\n", listener.first);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* FSFW_OBJ_EVENT_TRANSLATION == 1 */
|
||||
|
@@ -42,7 +42,6 @@ class EventManager : public EventManagerIF, public ExecutableObjectIF, public Sy
|
||||
object_id_t reporterFrom = 0, object_id_t reporterTo = 0,
|
||||
bool reporterInverted = false);
|
||||
ReturnValue_t performOperation(uint8_t opCode);
|
||||
void printListeners();
|
||||
|
||||
protected:
|
||||
MessageQueueIF* eventReportQueue = nullptr;
|
||||
|
@@ -9,9 +9,8 @@
|
||||
FailureIsolationBase::FailureIsolationBase(object_id_t owner, object_id_t parent,
|
||||
uint8_t messageDepth, uint8_t parameterDomainBase)
|
||||
: ownerId(owner), faultTreeParent(parent), parameterDomainBase(parameterDomainBase) {
|
||||
auto mqArgs = MqArgs(owner, static_cast<void*>(this));
|
||||
eventQueue = QueueFactory::instance()->createMessageQueue(
|
||||
messageDepth, EventMessage::EVENT_MESSAGE_SIZE, &mqArgs);
|
||||
eventQueue =
|
||||
QueueFactory::instance()->createMessageQueue(messageDepth, EventMessage::EVENT_MESSAGE_SIZE);
|
||||
}
|
||||
|
||||
FailureIsolationBase::~FailureIsolationBase() {
|
||||
@@ -52,12 +51,11 @@ ReturnValue_t FailureIsolationBase::initialize() {
|
||||
ObjectManager::instance()->get<ConfirmsFailuresIF>(faultTreeParent);
|
||||
if (parentIF == nullptr) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "FailureIsolationBase::intialize: Parent object "
|
||||
<< "invalid" << std::endl;
|
||||
sif::error << "Make sure it implements ConfirmsFailuresIF" << std::endl;
|
||||
#else
|
||||
sif::printError("FailureIsolationBase::intialize: Parent object invalid\n");
|
||||
sif::printError("Make sure it implements ConfirmsFailuresIF\n");
|
||||
sif::error << "FailureIsolationBase::intialize: Parent object"
|
||||
<< "invalid." << std::endl;
|
||||
#endif
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "Make sure it implements ConfirmsFailuresIF." << std::endl;
|
||||
#endif
|
||||
return ObjectManagerIF::CHILD_INIT_FAILED;
|
||||
return RETURN_FAILED;
|
||||
|
@@ -14,12 +14,13 @@ class FailureIsolationBase : public HasReturnvaluesIF,
|
||||
public HasParametersIF {
|
||||
public:
|
||||
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::FDIR_1;
|
||||
//! FDIR has an internal state, which changed from par2 (oldState) to par1 (newState).
|
||||
static const Event FDIR_CHANGED_STATE = MAKE_EVENT(1, severity::INFO);
|
||||
//! FDIR tries to restart device. Par1: event that caused recovery.
|
||||
static const Event FDIR_STARTS_RECOVERY = MAKE_EVENT(2, severity::MEDIUM);
|
||||
//! FDIR turns off device. Par1: event that caused recovery.
|
||||
static const Event FDIR_TURNS_OFF_DEVICE = MAKE_EVENT(3, severity::MEDIUM);
|
||||
static const Event FDIR_CHANGED_STATE =
|
||||
MAKE_EVENT(1, severity::INFO); //!< FDIR has an internal state, which changed from par2
|
||||
//!< (oldState) to par1 (newState).
|
||||
static const Event FDIR_STARTS_RECOVERY = MAKE_EVENT(
|
||||
2, severity::MEDIUM); //!< FDIR tries to restart device. Par1: event that caused recovery.
|
||||
static const Event FDIR_TURNS_OFF_DEVICE = MAKE_EVENT(
|
||||
3, severity::MEDIUM); //!< FDIR turns off device. Par1: event that caused recovery.
|
||||
|
||||
FailureIsolationBase(object_id_t owner, object_id_t parent = objects::NO_OBJECT,
|
||||
uint8_t messageDepth = 10, uint8_t parameterDomainBase = 0xF0);
|
||||
|
@@ -1,13 +1,13 @@
|
||||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
||||
arrayprinter.cpp
|
||||
AsciiConverter.cpp
|
||||
CRC.cpp
|
||||
DleEncoder.cpp
|
||||
DleParser.cpp
|
||||
PeriodicOperationDivider.cpp
|
||||
timevalOperations.cpp
|
||||
Type.cpp
|
||||
bitutility.cpp
|
||||
target_sources(${LIB_FSFW_NAME}
|
||||
PRIVATE
|
||||
arrayprinter.cpp
|
||||
AsciiConverter.cpp
|
||||
CRC.cpp
|
||||
DleEncoder.cpp
|
||||
PeriodicOperationDivider.cpp
|
||||
timevalOperations.cpp
|
||||
Type.cpp
|
||||
bitutility.cpp
|
||||
)
|
||||
|
||||
add_subdirectory(math)
|
||||
|
@@ -1,231 +0,0 @@
|
||||
#include "DleParser.h"
|
||||
|
||||
#include <fsfw/globalfunctions/DleEncoder.h>
|
||||
#include <fsfw/serviceinterface/ServiceInterface.h>
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
DleParser::DleParser(SimpleRingBuffer& decodeRingBuf, DleEncoder& decoder, BufPair encodedBuf,
|
||||
BufPair decodedBuf, UserHandler handler, void* args)
|
||||
: decodeRingBuf(decodeRingBuf),
|
||||
decoder(decoder),
|
||||
encodedBuf(encodedBuf),
|
||||
decodedBuf(decodedBuf),
|
||||
handler(handler),
|
||||
ctx(args) {
|
||||
if (handler == nullptr) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "DleParser::DleParser: Invalid user handler" << std::endl;
|
||||
#else
|
||||
sif::printError("DleParser::DleParser: Invalid user handler\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t DleParser::passData(uint8_t* data, size_t len) {
|
||||
if (data == nullptr or len == 0 or handler == nullptr) {
|
||||
return RETURN_FAILED;
|
||||
}
|
||||
size_t copyIntoRingBufFromHere = 0;
|
||||
size_t copyAmount = len;
|
||||
size_t startIdx = 0;
|
||||
ReturnValue_t result = RETURN_OK;
|
||||
bool startFoundInThisPacket = false;
|
||||
for (size_t idx = 0; idx < len; idx++) {
|
||||
if (data[idx] == DleEncoder::STX_CHAR) {
|
||||
if (not startFound and not startFoundInThisPacket) {
|
||||
startIdx = idx;
|
||||
copyIntoRingBufFromHere = idx;
|
||||
copyAmount = len - idx;
|
||||
} else {
|
||||
// Maybe print warning, should not happen
|
||||
decodeRingBuf.clear();
|
||||
ErrorInfo info;
|
||||
info.len = idx;
|
||||
prepareErrorContext(ErrorTypes::CONSECUTIVE_STX_CHARS, info);
|
||||
handler(ctx);
|
||||
copyIntoRingBufFromHere = idx;
|
||||
copyAmount = len - idx;
|
||||
}
|
||||
startFound = true;
|
||||
startFoundInThisPacket = true;
|
||||
} else if (data[idx] == DleEncoder::ETX_CHAR) {
|
||||
if (startFoundInThisPacket) {
|
||||
size_t readLen = 0;
|
||||
size_t decodedLen = 0;
|
||||
result = decoder.decode(data + startIdx, idx + 1 - startIdx, &readLen, decodedBuf.first,
|
||||
decodedBuf.second, &decodedLen);
|
||||
if (result == HasReturnvaluesIF::RETURN_OK) {
|
||||
ctx.setType(ContextType::PACKET_FOUND);
|
||||
ctx.decodedPacket.first = decodedBuf.first;
|
||||
ctx.decodedPacket.second = decodedLen;
|
||||
this->handler(ctx);
|
||||
} else if (result == DleEncoder::STREAM_TOO_SHORT) {
|
||||
ErrorInfo info;
|
||||
info.res = result;
|
||||
prepareErrorContext(ErrorTypes::DECODING_BUF_TOO_SMALL, info);
|
||||
handler(ctx);
|
||||
} else {
|
||||
ErrorInfo info;
|
||||
info.res = result;
|
||||
prepareErrorContext(ErrorTypes::DECODING_BUF_TOO_SMALL, info);
|
||||
handler(ctx);
|
||||
}
|
||||
decodeRingBuf.clear();
|
||||
if ((idx + 1) < len) {
|
||||
copyIntoRingBufFromHere = idx + 1;
|
||||
copyAmount = len - idx - 1;
|
||||
} else {
|
||||
copyAmount = 0;
|
||||
}
|
||||
} else if (startFound) {
|
||||
// ETX found but STX was found in another mini packet. Reconstruct the full packet
|
||||
// to decode it
|
||||
result = decodeRingBuf.writeData(data, idx + 1);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
ErrorInfo info;
|
||||
info.res = result;
|
||||
prepareErrorContext(ErrorTypes::RING_BUF_ERROR, info);
|
||||
handler(ctx);
|
||||
}
|
||||
size_t fullEncodedLen = decodeRingBuf.getAvailableReadData();
|
||||
if (fullEncodedLen > encodedBuf.second) {
|
||||
ErrorInfo info;
|
||||
info.len = fullEncodedLen;
|
||||
prepareErrorContext(ErrorTypes::ENCODED_BUF_TOO_SMALL, info);
|
||||
handler(ctx);
|
||||
decodeRingBuf.clear();
|
||||
} else {
|
||||
size_t decodedLen = 0;
|
||||
size_t readLen = 0;
|
||||
decodeRingBuf.readData(encodedBuf.first, fullEncodedLen, true);
|
||||
result = decoder.decode(encodedBuf.first, fullEncodedLen, &readLen, decodedBuf.first,
|
||||
decodedBuf.second, &decodedLen);
|
||||
if (result == HasReturnvaluesIF::RETURN_OK) {
|
||||
if (this->handler != nullptr) {
|
||||
ctx.setType(ContextType::PACKET_FOUND);
|
||||
ctx.decodedPacket.first = decodedBuf.first;
|
||||
ctx.decodedPacket.second = decodedLen;
|
||||
this->handler(ctx);
|
||||
}
|
||||
} else if (result == DleEncoder::STREAM_TOO_SHORT) {
|
||||
ErrorInfo info;
|
||||
info.res = result;
|
||||
prepareErrorContext(ErrorTypes::DECODING_BUF_TOO_SMALL, info);
|
||||
handler(ctx);
|
||||
} else {
|
||||
ErrorInfo info;
|
||||
info.res = result;
|
||||
prepareErrorContext(ErrorTypes::DECODE_ERROR, info);
|
||||
handler(ctx);
|
||||
}
|
||||
decodeRingBuf.clear();
|
||||
startFound = false;
|
||||
startFoundInThisPacket = false;
|
||||
if ((idx + 1) < len) {
|
||||
copyIntoRingBufFromHere = idx + 1;
|
||||
copyAmount = len - idx - 1;
|
||||
} else {
|
||||
copyAmount = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// End data without preceeding STX
|
||||
ErrorInfo info;
|
||||
info.len = idx + 1;
|
||||
prepareErrorContext(ErrorTypes::CONSECUTIVE_ETX_CHARS, info);
|
||||
handler(ctx);
|
||||
decodeRingBuf.clear();
|
||||
if ((idx + 1) < len) {
|
||||
copyIntoRingBufFromHere = idx + 1;
|
||||
copyAmount = len - idx - 1;
|
||||
} else {
|
||||
copyAmount = 0;
|
||||
}
|
||||
}
|
||||
startFoundInThisPacket = false;
|
||||
startFound = false;
|
||||
}
|
||||
}
|
||||
if (copyAmount > 0) {
|
||||
result = decodeRingBuf.writeData(data + copyIntoRingBufFromHere, copyAmount);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
ErrorInfo info;
|
||||
info.res = result;
|
||||
prepareErrorContext(ErrorTypes::RING_BUF_ERROR, info);
|
||||
handler(ctx);
|
||||
}
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
void DleParser::defaultFoundPacketHandler(uint8_t* packet, size_t len, void* args) {
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::info << "DleParserBase::handleFoundPacket: Detected DLE packet with " << len << " bytes"
|
||||
<< std::endl;
|
||||
#else
|
||||
sif::printInfo("DleParserBase::handleFoundPacket: Detected DLE packet with %d bytes\n", len);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void DleParser::defaultErrorHandler(ErrorTypes err, ErrorInfo ctx) {
|
||||
switch (err) {
|
||||
case (ErrorTypes::NONE): {
|
||||
errorPrinter("No error");
|
||||
break;
|
||||
}
|
||||
case (ErrorTypes::DECODE_ERROR): {
|
||||
errorPrinter("Decode Error");
|
||||
break;
|
||||
}
|
||||
case (ErrorTypes::RING_BUF_ERROR): {
|
||||
errorPrinter("Ring Buffer Error");
|
||||
break;
|
||||
}
|
||||
case (ErrorTypes::ENCODED_BUF_TOO_SMALL):
|
||||
case (ErrorTypes::DECODING_BUF_TOO_SMALL): {
|
||||
char opt[64];
|
||||
snprintf(opt, sizeof(opt), ": Too small for packet with length %d", ctx.len);
|
||||
if (err == ErrorTypes::ENCODED_BUF_TOO_SMALL) {
|
||||
errorPrinter("Encoded buf too small", opt);
|
||||
} else {
|
||||
errorPrinter("Decoding buf too small", opt);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case (ErrorTypes::CONSECUTIVE_STX_CHARS): {
|
||||
errorPrinter("Consecutive STX chars detected");
|
||||
break;
|
||||
}
|
||||
case (ErrorTypes::CONSECUTIVE_ETX_CHARS): {
|
||||
errorPrinter("Consecutive ETX chars detected");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DleParser::errorPrinter(const char* str, const char* opt) {
|
||||
if (opt == nullptr) {
|
||||
opt = "";
|
||||
}
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::info << "DleParserBase::handleParseError: " << str << opt << std::endl;
|
||||
#else
|
||||
sif::printInfo("DleParserBase::handleParseError: %s%s\n", str, opt);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void DleParser::prepareErrorContext(ErrorTypes err, ErrorInfo info) {
|
||||
ctx.setType(ContextType::ERROR);
|
||||
ctx.error.first = err;
|
||||
ctx.error.second = info;
|
||||
}
|
||||
|
||||
void DleParser::reset() {
|
||||
startFound = false;
|
||||
decodeRingBuf.clear();
|
||||
}
|
@@ -1,127 +0,0 @@
|
||||
#ifndef MISSION_DEVICES_DLEPARSER_H_
|
||||
#define MISSION_DEVICES_DLEPARSER_H_
|
||||
|
||||
#include <fsfw/container/SimpleRingBuffer.h>
|
||||
#include <fsfw/globalfunctions/DleEncoder.h>
|
||||
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
|
||||
/**
|
||||
* @brief This base helper class can be used to extract DLE encoded packets from a data stream
|
||||
* @details
|
||||
* The core API of the parser takes received packets which can contains DLE packets. The parser
|
||||
* can deal with DLE packets split across multiple packets. It does so by using a dedicated
|
||||
* decoding ring buffer. The user can process received packets and detect errors by
|
||||
* overriding two provided virtual methods. This also allows detecting multiple DLE packets
|
||||
* inside one passed packet.
|
||||
*/
|
||||
class DleParser : public HasReturnvaluesIF {
|
||||
public:
|
||||
using BufPair = std::pair<uint8_t*, size_t>;
|
||||
|
||||
enum class ContextType { PACKET_FOUND, ERROR };
|
||||
|
||||
enum class ErrorTypes {
|
||||
NONE,
|
||||
ENCODED_BUF_TOO_SMALL,
|
||||
DECODING_BUF_TOO_SMALL,
|
||||
DECODE_ERROR,
|
||||
RING_BUF_ERROR,
|
||||
CONSECUTIVE_STX_CHARS,
|
||||
CONSECUTIVE_ETX_CHARS
|
||||
};
|
||||
|
||||
union ErrorInfo {
|
||||
size_t len;
|
||||
ReturnValue_t res;
|
||||
};
|
||||
|
||||
using ErrorPair = std::pair<ErrorTypes, ErrorInfo>;
|
||||
|
||||
struct Context {
|
||||
public:
|
||||
Context(void* args) : userArgs(args) { setType(ContextType::PACKET_FOUND); }
|
||||
|
||||
void setType(ContextType type) {
|
||||
if (type == ContextType::PACKET_FOUND) {
|
||||
error.first = ErrorTypes::NONE;
|
||||
error.second.len = 0;
|
||||
} else {
|
||||
decodedPacket.first = nullptr;
|
||||
decodedPacket.second = 0;
|
||||
}
|
||||
}
|
||||
|
||||
ContextType getType() const { return type; }
|
||||
|
||||
BufPair decodedPacket = {};
|
||||
ErrorPair error;
|
||||
void* userArgs;
|
||||
|
||||
private:
|
||||
ContextType type;
|
||||
};
|
||||
|
||||
using UserHandler = void (*)(const Context& ctx);
|
||||
|
||||
/**
|
||||
* Base class constructor
|
||||
* @param decodeRingBuf Ring buffer used to store multiple packets to allow detecting DLE packets
|
||||
* split across multiple packets
|
||||
* @param decoder Decoder instance
|
||||
* @param encodedBuf Buffer used to store encoded packets. It has to be large enough to hold
|
||||
* the largest expected encoded DLE packet size
|
||||
* @param decodedBuf Buffer used to store decoded packets. It has to be large enough to hold the
|
||||
* largest expected decoded DLE packet size
|
||||
* @param handler Function which will be called on a found packet
|
||||
* @param args Arbitrary user argument
|
||||
*/
|
||||
DleParser(SimpleRingBuffer& decodeRingBuf, DleEncoder& decoder, BufPair encodedBuf,
|
||||
BufPair decodedBuf, UserHandler handler, void* args);
|
||||
|
||||
/**
|
||||
* This function allows to pass new data into the parser. It then scans for DLE packets
|
||||
* automatically and inserts (part of) the packet into a ring buffer if necessary.
|
||||
* @param data
|
||||
* @param len
|
||||
* @return
|
||||
*/
|
||||
ReturnValue_t passData(uint8_t* data, size_t len);
|
||||
|
||||
/**
|
||||
* Example found packet handler
|
||||
* function call
|
||||
* @param packet Decoded packet
|
||||
* @param len Length of detected packet
|
||||
*/
|
||||
void defaultFoundPacketHandler(uint8_t* packet, size_t len, void* args);
|
||||
/**
|
||||
* Will be called if an error occured in the #passData call
|
||||
* @param err
|
||||
* @param ctx Context information depending on the error type
|
||||
* - For buffer length errors, will be set to the detected packet length which is too large
|
||||
* - For decode or ring buffer errors, will be set to the result returned from the failed call
|
||||
*/
|
||||
static void defaultErrorHandler(ErrorTypes err, ErrorInfo ctx);
|
||||
|
||||
static void errorPrinter(const char* str, const char* opt = nullptr);
|
||||
|
||||
void prepareErrorContext(ErrorTypes err, ErrorInfo ctx);
|
||||
/**
|
||||
* Resets the parser by resetting the internal states and clearing the decoding ring buffer
|
||||
*/
|
||||
void reset();
|
||||
|
||||
private:
|
||||
SimpleRingBuffer& decodeRingBuf;
|
||||
DleEncoder& decoder;
|
||||
BufPair encodedBuf;
|
||||
BufPair decodedBuf;
|
||||
UserHandler handler = nullptr;
|
||||
Context ctx;
|
||||
bool startFound = false;
|
||||
};
|
||||
|
||||
#endif /* MISSION_DEVICES_DLEPARSER_H_ */
|
@@ -179,9 +179,6 @@ class MatchTree : public SerializeableMatcherIF<T>, public BinaryTree<Serializea
|
||||
virtual ReturnValue_t cleanUpElement(iterator position) { return HasReturnvaluesIF::RETURN_OK; }
|
||||
|
||||
bool matchSubtree(iterator iter, T number) {
|
||||
if(iter == nullptr) {
|
||||
return false;
|
||||
}
|
||||
bool isMatch = iter->match(number);
|
||||
if (isMatch) {
|
||||
if (iter.left() == this->end()) {
|
||||
|
@@ -23,15 +23,19 @@ class HasHealthIF {
|
||||
static const Event HEALTH_INFO = MAKE_EVENT(6, severity::INFO);
|
||||
static const Event CHILD_CHANGED_HEALTH = MAKE_EVENT(7, severity::INFO);
|
||||
static const Event CHILD_PROBLEMS = MAKE_EVENT(8, severity::LOW);
|
||||
//! Assembly overwrites health information of children to keep satellite alive.
|
||||
static const Event OVERWRITING_HEALTH = MAKE_EVENT(9, severity::LOW);
|
||||
//! Someone starts a recovery of a component (typically power-cycle). No parameters.
|
||||
static const Event TRYING_RECOVERY = MAKE_EVENT(10, severity::MEDIUM);
|
||||
//! Recovery is ongoing. Comes twice during recovery.
|
||||
//! P1: 0 for the first, 1 for the second event. P2: 0
|
||||
static const Event RECOVERY_STEP = MAKE_EVENT(11, severity::MEDIUM);
|
||||
//! Recovery was completed. Not necessarily successful. No parameters.
|
||||
static const Event RECOVERY_DONE = MAKE_EVENT(12, severity::MEDIUM);
|
||||
static const Event OVERWRITING_HEALTH =
|
||||
MAKE_EVENT(9, severity::LOW); //!< Assembly overwrites health information of children to keep
|
||||
//!< satellite alive.
|
||||
static const Event TRYING_RECOVERY =
|
||||
MAKE_EVENT(10, severity::MEDIUM); //!< Someone starts a recovery of a component (typically
|
||||
//!< power-cycle). No parameters.
|
||||
static const Event RECOVERY_STEP =
|
||||
MAKE_EVENT(11, severity::MEDIUM); //!< Recovery is ongoing. Comes twice during recovery. P1:
|
||||
//!< 0 for the first, 1 for the second event. P2: 0
|
||||
static const Event RECOVERY_DONE = MAKE_EVENT(
|
||||
12,
|
||||
severity::MEDIUM); //!< Recovery was completed. Not necessarily successful. No parameters.
|
||||
|
||||
virtual ~HasHealthIF() {}
|
||||
|
||||
virtual MessageQueueId_t getCommandQueue() const = 0;
|
||||
|
@@ -7,13 +7,11 @@
|
||||
|
||||
InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId, uint32_t messageQueueDepth)
|
||||
: SystemObject(setObjectId),
|
||||
commandQueue(QueueFactory::instance()->createMessageQueue(messageQueueDepth)),
|
||||
poolManager(this, commandQueue),
|
||||
internalErrorSid(setObjectId, InternalErrorDataset::ERROR_SET_ID),
|
||||
internalErrorDataset(this) {
|
||||
mutex = MutexFactory::instance()->createMutex();
|
||||
auto mqArgs = MqArgs(setObjectId, static_cast<void *>(this));
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(
|
||||
messageQueueDepth, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||
}
|
||||
|
||||
InternalErrorReporter::~InternalErrorReporter() { MutexFactory::instance()->deleteMutex(mutex); }
|
||||
@@ -38,14 +36,15 @@ ReturnValue_t InternalErrorReporter::performOperation(uint8_t opCode) {
|
||||
if ((newQueueHits > 0) or (newTmHits > 0) or (newStoreHits > 0)) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::debug << "InternalErrorReporter::performOperation: Errors "
|
||||
<< "occured: Queue | TM | Store : " << newQueueHits << " | " << newTmHits << " | "
|
||||
<< newStoreHits << std::endl;
|
||||
<< "occured!" << std::endl;
|
||||
sif::debug << "Queue errors: " << newQueueHits << std::endl;
|
||||
sif::debug << "TM errors: " << newTmHits << std::endl;
|
||||
sif::debug << "Store errors: " << newStoreHits << std::endl;
|
||||
#else
|
||||
sif::printDebug(
|
||||
"InternalErrorReporter::performOperation: Errors occured: Queue | TM | Store: %lu | %lu "
|
||||
"| %lu\n",
|
||||
static_cast<unsigned int>(newQueueHits), static_cast<unsigned int>(newTmHits),
|
||||
static_cast<unsigned int>(newStoreHits));
|
||||
sif::printDebug("InternalErrorReporter::performOperation: Errors occured!\n");
|
||||
sif::printDebug("Queue errors: %lu\n", static_cast<unsigned int>(newQueueHits));
|
||||
sif::printDebug("TM errors: %lu\n", static_cast<unsigned int>(newTmHits));
|
||||
sif::printDebug("Store errors: %lu\n", static_cast<unsigned int>(newStoreHits));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@@ -1,9 +1,9 @@
|
||||
#include "MessageQueueBase.h"
|
||||
|
||||
MessageQueueBase::MessageQueueBase(MessageQueueId_t id, MessageQueueId_t defaultDest,
|
||||
MqArgs* args): id(id) {
|
||||
MessageQueueBase::MessageQueueBase(MessageQueueId_t id, MessageQueueId_t defaultDest, MqArgs* args)
|
||||
: id(id) {
|
||||
this->defaultDest = defaultDest;
|
||||
if(args != nullptr) {
|
||||
if (args != nullptr) {
|
||||
this->args = *args;
|
||||
}
|
||||
}
|
||||
@@ -23,35 +23,25 @@ ReturnValue_t MessageQueueBase::reply(MessageQueueMessageIF* message) {
|
||||
}
|
||||
|
||||
ReturnValue_t MessageQueueBase::receiveMessage(MessageQueueMessageIF* message,
|
||||
MessageQueueId_t* receivedFrom) {
|
||||
MessageQueueId_t* receivedFrom) {
|
||||
ReturnValue_t status = this->receiveMessage(message);
|
||||
*receivedFrom = this->last;
|
||||
return status;
|
||||
}
|
||||
|
||||
MessageQueueId_t MessageQueueBase::getLastPartner() const {
|
||||
return last;
|
||||
}
|
||||
MessageQueueId_t MessageQueueBase::getLastPartner() const { return last; }
|
||||
|
||||
MessageQueueId_t MessageQueueBase::getId() const {
|
||||
return id;
|
||||
}
|
||||
MessageQueueId_t MessageQueueBase::getId() const { return id; }
|
||||
|
||||
MqArgs& MessageQueueBase::getMqArgs() {
|
||||
return args;
|
||||
}
|
||||
MqArgs& MessageQueueBase::getMqArgs() { return args; }
|
||||
|
||||
void MessageQueueBase::setDefaultDestination(MessageQueueId_t defaultDestination) {
|
||||
this->defaultDest = defaultDestination;
|
||||
}
|
||||
|
||||
MessageQueueId_t MessageQueueBase::getDefaultDestination() const {
|
||||
return defaultDest;
|
||||
}
|
||||
MessageQueueId_t MessageQueueBase::getDefaultDestination() const { return defaultDest; }
|
||||
|
||||
bool MessageQueueBase::isDefaultDestinationSet() const {
|
||||
return (defaultDest != NO_QUEUE);
|
||||
}
|
||||
bool MessageQueueBase::isDefaultDestinationSet() const { return (defaultDest != NO_QUEUE); }
|
||||
|
||||
ReturnValue_t MessageQueueBase::sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
||||
bool ignoreFault) {
|
||||
|
@@ -1,11 +1,11 @@
|
||||
#ifndef FSFW_SRC_FSFW_IPC_MESSAGEQUEUEBASE_H_
|
||||
#define FSFW_SRC_FSFW_IPC_MESSAGEQUEUEBASE_H_
|
||||
|
||||
#include <fsfw/ipc/definitions.h>
|
||||
#include <fsfw/ipc/MessageQueueIF.h>
|
||||
#include <fsfw/ipc/definitions.h>
|
||||
|
||||
class MessageQueueBase: public MessageQueueIF {
|
||||
public:
|
||||
class MessageQueueBase : public MessageQueueIF {
|
||||
public:
|
||||
MessageQueueBase(MessageQueueId_t id, MessageQueueId_t defaultDest, MqArgs* mqArgs);
|
||||
virtual ~MessageQueueBase();
|
||||
|
||||
@@ -17,25 +17,24 @@ public:
|
||||
virtual MessageQueueId_t getDefaultDestination() const override;
|
||||
virtual bool isDefaultDestinationSet() const override;
|
||||
virtual ReturnValue_t sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
||||
bool ignoreFault) override;
|
||||
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;
|
||||
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:
|
||||
|
||||
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_ */
|
||||
|
@@ -2,6 +2,7 @@
|
||||
#define FSFW_IPC_MESSAGEQUEUEIF_H_
|
||||
|
||||
#include <fsfw/ipc/definitions.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "../returnvalues/HasReturnvaluesIF.h"
|
||||
@@ -45,7 +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.
|
||||
|
@@ -19,33 +19,32 @@ class HasModesIF {
|
||||
static const ReturnValue_t INVALID_SUBMODE = MAKE_RETURN_CODE(0x04);
|
||||
|
||||
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::SYSTEM_MANAGER;
|
||||
//! An object announces changing the mode. p1: target mode. p2: target submode
|
||||
static const Event CHANGING_MODE = MAKE_EVENT(0, severity::INFO);
|
||||
//! An Object announces its mode; parameter1 is mode, parameter2 is submode
|
||||
static const Event MODE_INFO = MAKE_EVENT(1, severity::INFO);
|
||||
static const Event CHANGING_MODE =
|
||||
MAKE_EVENT(0, severity::INFO); //!< An object announces changing the mode. p1: target mode.
|
||||
//!< p2: target submode
|
||||
static const Event MODE_INFO = MAKE_EVENT(
|
||||
1,
|
||||
severity::INFO); //!< An Object announces its mode; parameter1 is mode, parameter2 is submode
|
||||
static const Event FALLBACK_FAILED = MAKE_EVENT(2, severity::HIGH);
|
||||
static const Event MODE_TRANSITION_FAILED = MAKE_EVENT(3, severity::LOW);
|
||||
static const Event CANT_KEEP_MODE = MAKE_EVENT(4, severity::HIGH);
|
||||
//! Indicates a bug or configuration failure: Object is in a mode it should never be in.
|
||||
static const Event OBJECT_IN_INVALID_MODE = MAKE_EVENT(5, severity::LOW);
|
||||
//! The mode is changed, but for some reason, the change is forced, i.e. EXTERNAL_CONTROL ignored.
|
||||
//! p1: target mode. p2: target submode
|
||||
static const Event FORCING_MODE = MAKE_EVENT(6, severity::MEDIUM);
|
||||
//! A mode command was rejected by the called object. Par1: called object id, Par2: return code.
|
||||
static const Event MODE_CMD_REJECTED = MAKE_EVENT(7, severity::LOW);
|
||||
static const Event OBJECT_IN_INVALID_MODE =
|
||||
MAKE_EVENT(5, severity::LOW); //!< Indicates a bug or configuration failure: Object is in a
|
||||
//!< mode it should never be in.
|
||||
static const Event FORCING_MODE = MAKE_EVENT(
|
||||
6, severity::MEDIUM); //!< The mode is changed, but for some reason, the change is forced,
|
||||
//!< i.e. EXTERNAL_CONTROL ignored. p1: target mode. p2: target submode
|
||||
static const Event MODE_CMD_REJECTED =
|
||||
MAKE_EVENT(7, severity::LOW); //!< A mode command was rejected by the called object. Par1:
|
||||
//!< called object id, Par2: return code.
|
||||
|
||||
//! The device is powered and ready to perform operations. In this mode, no commands are
|
||||
//! sent by the device handler itself, but direct commands van be commanded and will be
|
||||
//! interpreted
|
||||
static constexpr Mode_t MODE_ON = 1;
|
||||
//! The device is powered off. The only command accepted in this mode is a mode change to on.
|
||||
static constexpr Mode_t MODE_OFF = 0;
|
||||
|
||||
static constexpr Mode_t MODE_INVALID = -1;
|
||||
static constexpr Mode_t MODE_UNDEFINED = -2;
|
||||
|
||||
//! To avoid checks against magic number "0".
|
||||
static const Submode_t SUBMODE_NONE = 0;
|
||||
static const Mode_t MODE_ON =
|
||||
1; //!< The device is powered and ready to perform operations. In this mode, no commands are
|
||||
//!< sent by the device handler itself, but direct commands van be commanded and will be
|
||||
//!< interpreted
|
||||
static const Mode_t MODE_OFF = 0; //!< The device is powered off. The only command accepted in
|
||||
//!< this mode is a mode change to on.
|
||||
static const Submode_t SUBMODE_NONE = 0; //!< To avoid checks against magic number "0".
|
||||
|
||||
virtual ~HasModesIF() {}
|
||||
virtual MessageQueueId_t getCommandQueue() const = 0;
|
||||
|
@@ -95,16 +95,13 @@ void ObjectManager::initialize() {
|
||||
for (auto const& it : objectList) {
|
||||
result = it.second->initialize();
|
||||
if (result != RETURN_OK) {
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
object_id_t var = it.first;
|
||||
sif::error << "ObjectManager::initialize: Object 0x" << std::hex << std::setw(8)
|
||||
<< std::setfill('0') << it.first << " failed to initialize with code 0x" << result
|
||||
<< std::dec << std::setfill(' ') << std::endl;
|
||||
#else
|
||||
sif::printError(
|
||||
"ObjectManager::initialize: Object 0x%08x failed to initialize with code 0x%04x\n", var,
|
||||
it.first);
|
||||
#endif
|
||||
<< std::setfill('0') << var
|
||||
<< " failed to "
|
||||
"initialize with code 0x"
|
||||
<< result << std::dec << std::setfill(' ') << std::endl;
|
||||
#endif
|
||||
errorCount++;
|
||||
}
|
||||
|
@@ -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) {
|
||||
|
@@ -2,6 +2,7 @@
|
||||
#define FSFW_OSAL_FREERTOS_MESSAGEQUEUE_H_
|
||||
|
||||
#include <fsfw/ipc/MessageQueueBase.h>
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "TaskManagement.h"
|
||||
#include "fsfw/internalerror/InternalErrorReporterIF.h"
|
||||
|
@@ -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;
|
||||
|
@@ -1,17 +1,17 @@
|
||||
#ifndef FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_
|
||||
#define FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_
|
||||
|
||||
#include "fsfw/ipc/MessageQueueBase.h"
|
||||
#include <memory>
|
||||
#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"
|
||||
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
|
||||
/**
|
||||
* @brief This class manages sending and receiving of
|
||||
* message queue messages.
|
||||
|
@@ -1,5 +1,4 @@
|
||||
#include "fsfw/timemanager/Clock.h"
|
||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||
|
||||
#include <linux/sysinfo.h>
|
||||
#include <sys/sysinfo.h>
|
||||
@@ -8,12 +7,9 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <cstring>
|
||||
|
||||
uint16_t Clock::leapSeconds = 0;
|
||||
MutexIF* Clock::timeMutex = NULL;
|
||||
|
||||
void handleClockError(const char* func);
|
||||
#include "fsfw/ipc/MutexGuard.h"
|
||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||
|
||||
uint32_t Clock::getTicksPerSecond(void) {
|
||||
uint32_t ticks = sysconf(_SC_CLK_TCK);
|
||||
@@ -29,7 +25,7 @@ ReturnValue_t Clock::setClock(const TimeOfDay_t* time) {
|
||||
|
||||
int status = clock_settime(CLOCK_REALTIME, &timeUnix);
|
||||
if (status != 0) {
|
||||
handleClockError("setClock");
|
||||
// TODO errno
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
@@ -41,7 +37,7 @@ ReturnValue_t Clock::setClock(const timeval* time) {
|
||||
timeUnix.tv_nsec = (__syscall_slong_t)time->tv_usec * 1000;
|
||||
int status = clock_settime(CLOCK_REALTIME, &timeUnix);
|
||||
if (status != 0) {
|
||||
handleClockError("setClock");
|
||||
// TODO errno
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
@@ -51,7 +47,6 @@ ReturnValue_t Clock::getClock_timeval(timeval* time) {
|
||||
timespec timeUnix;
|
||||
int status = clock_gettime(CLOCK_REALTIME, &timeUnix);
|
||||
if (status != 0) {
|
||||
handleClockError("getClock_timeval");
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
time->tv_sec = timeUnix.tv_sec;
|
||||
@@ -120,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;
|
||||
@@ -154,15 +155,3 @@ ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) {
|
||||
*JD2000 = (time.tv_sec - 946728000. + time.tv_usec / 1000000.) / 24. / 3600.;
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
|
||||
void handleClockError(const char* func) {
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "Clock::" << func << ": Failed with code " << errno << ": " << strerror(errno)
|
||||
<< std::endl;
|
||||
#else
|
||||
sif::printWarning("Clock::%s: Failed with code %d: %s\n", func, errno, strerror(errno));
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
@@ -61,8 +61,7 @@ class MessageQueue : public 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;
|
||||
MessageQueueId_t sentFrom, bool ignoreFault = false) override;
|
||||
|
||||
protected:
|
||||
/**
|
||||
|
@@ -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);
|
||||
|
@@ -2,6 +2,7 @@
|
||||
#define FSFW_OSAL_RTEMS_MESSAGEQUEUE_H_
|
||||
|
||||
#include <fsfw/ipc/MessageQueueBase.h>
|
||||
|
||||
#include "RtemsBasic.h"
|
||||
#include "fsfw/internalerror/InternalErrorReporterIF.h"
|
||||
#include "fsfw/ipc/MessageQueueIF.h"
|
||||
@@ -52,8 +53,8 @@ class MessageQueue : public MessageQueueBase {
|
||||
// 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;
|
||||
MessageQueueId_t sentFrom = NO_QUEUE,
|
||||
bool ignoreFault = false) override;
|
||||
|
||||
private:
|
||||
/**
|
||||
|
@@ -59,14 +59,13 @@ 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;
|
||||
|
||||
ReturnValue_t addComponent(ExecutableObjectIF *object) override;
|
||||
|
||||
uint32_t getPeriodMs() const override;
|
||||
|
||||
|
@@ -66,7 +66,7 @@ class HasParametersIF {
|
||||
* @param newValues
|
||||
* @param startAtIndex Linear index, runs left to right, top to bottom for
|
||||
* matrix indexes.
|
||||
* @return RETURN_OK if parameter is valid and a set function of the parameter wrapper was called.
|
||||
* @return
|
||||
*/
|
||||
virtual ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueIdentifier,
|
||||
ParameterWrapper *parameterWrapper,
|
||||
|
@@ -211,13 +211,9 @@ ReturnValue_t ParameterWrapper::copyFrom(const ParameterWrapper *from,
|
||||
if (data == nullptr) {
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "ParameterWrapper::copyFrom: Called on read-only variable or "
|
||||
"data pointer not set"
|
||||
<< std::endl;
|
||||
sif::warning << "ParameterWrapper::copyFrom: Called on read-only variable!" << std::endl;
|
||||
#else
|
||||
sif::printWarning(
|
||||
"ParameterWrapper::copyFrom: Called on read-only variable "
|
||||
"or data pointer not set\n");
|
||||
sif::printWarning("ParameterWrapper::copyFrom: Called on read-only variable!\n");
|
||||
#endif
|
||||
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
||||
return READONLY;
|
||||
@@ -226,9 +222,9 @@ ReturnValue_t ParameterWrapper::copyFrom(const ParameterWrapper *from,
|
||||
if (from->readonlyData == nullptr) {
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "ParameterWrapper::copyFrom: Source not set" << std::endl;
|
||||
sif::warning << "ParameterWrapper::copyFrom: Source not set!" << std::endl;
|
||||
#else
|
||||
sif::printWarning("ParameterWrapper::copyFrom: Source not set\n");
|
||||
sif::printWarning("ParameterWrapper::copyFrom: Source not set!\n");
|
||||
#endif
|
||||
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
||||
return SOURCE_NOT_SET;
|
||||
@@ -237,9 +233,9 @@ ReturnValue_t ParameterWrapper::copyFrom(const ParameterWrapper *from,
|
||||
if (type != from->type) {
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "ParameterWrapper::copyFrom: Datatype missmatch" << std::endl;
|
||||
sif::warning << "ParameterWrapper::copyFrom: Datatype missmatch!" << std::endl;
|
||||
#else
|
||||
sif::printWarning("ParameterWrapper::copyFrom: Datatype missmatch\n");
|
||||
sif::printWarning("ParameterWrapper::copyFrom: Datatype missmatch!\n");
|
||||
#endif
|
||||
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
||||
return DATATYPE_MISSMATCH;
|
||||
@@ -249,9 +245,9 @@ ReturnValue_t ParameterWrapper::copyFrom(const ParameterWrapper *from,
|
||||
if (rows == 0 or columns == 0) {
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "ParameterWrapper::copyFrom: Columns or rows zero" << std::endl;
|
||||
sif::warning << "ParameterWrapper::copyFrom: Columns or rows zero!" << std::endl;
|
||||
#else
|
||||
sif::printWarning("ParameterWrapper::copyFrom: Columns or rows zero\n");
|
||||
sif::printWarning("ParameterWrapper::copyFrom: Columns or rows zero!\n");
|
||||
#endif
|
||||
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
||||
return COLUMN_OR_ROWS_ZERO;
|
||||
|
@@ -1,8 +1,7 @@
|
||||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
||||
Fuse.cpp
|
||||
PowerComponent.cpp
|
||||
PowerSensor.cpp
|
||||
PowerSwitcher.cpp
|
||||
DummyPowerSwitcher.cpp
|
||||
PowerSwitcherComponent.cpp
|
||||
target_sources(${LIB_FSFW_NAME}
|
||||
PRIVATE
|
||||
Fuse.cpp
|
||||
PowerComponent.cpp
|
||||
PowerSensor.cpp
|
||||
PowerSwitcher.cpp
|
||||
)
|
@@ -1,46 +0,0 @@
|
||||
#include "DummyPowerSwitcher.h"
|
||||
|
||||
DummyPowerSwitcher::DummyPowerSwitcher(object_id_t objectId, size_t numberOfSwitches,
|
||||
size_t numberOfFuses, uint32_t switchDelayMs)
|
||||
: SystemObject(objectId),
|
||||
switcherList(numberOfSwitches),
|
||||
fuseList(numberOfFuses),
|
||||
switchDelayMs(switchDelayMs) {}
|
||||
|
||||
void DummyPowerSwitcher::setInitialSwitcherList(std::vector<ReturnValue_t> switcherList) {
|
||||
this->switcherList = switcherList;
|
||||
}
|
||||
|
||||
void DummyPowerSwitcher::setInitialFusesList(std::vector<ReturnValue_t> fuseList) {
|
||||
this->fuseList = fuseList;
|
||||
}
|
||||
|
||||
ReturnValue_t DummyPowerSwitcher::sendSwitchCommand(power::Switch_t switchNr, ReturnValue_t onOff) {
|
||||
if (switchNr < switcherList.capacity()) {
|
||||
switcherList[switchNr] = onOff;
|
||||
}
|
||||
return RETURN_FAILED;
|
||||
}
|
||||
|
||||
ReturnValue_t DummyPowerSwitcher::sendFuseOnCommand(uint8_t fuseNr) {
|
||||
if (fuseNr < fuseList.capacity()) {
|
||||
fuseList[fuseNr] = FUSE_ON;
|
||||
}
|
||||
return RETURN_FAILED;
|
||||
}
|
||||
|
||||
ReturnValue_t DummyPowerSwitcher::getSwitchState(power::Switch_t switchNr) const {
|
||||
if (switchNr < switcherList.capacity()) {
|
||||
return switcherList[switchNr];
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
|
||||
ReturnValue_t DummyPowerSwitcher::getFuseState(uint8_t fuseNr) const {
|
||||
if (fuseNr < fuseList.capacity()) {
|
||||
return fuseList[fuseNr];
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
|
||||
uint32_t DummyPowerSwitcher::getSwitchDelayMs(void) const { return switchDelayMs; }
|
@@ -1,31 +0,0 @@
|
||||
#ifndef FSFW_SRC_FSFW_POWER_DUMMYPOWERSWITCHER_H_
|
||||
#define FSFW_SRC_FSFW_POWER_DUMMYPOWERSWITCHER_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
|
||||
#include "PowerSwitchIF.h"
|
||||
#include "definitions.h"
|
||||
#include "fsfw/objectmanager/SystemObject.h"
|
||||
|
||||
class DummyPowerSwitcher : public SystemObject, public PowerSwitchIF {
|
||||
public:
|
||||
DummyPowerSwitcher(object_id_t objectId, size_t numberOfSwitches, size_t numberOfFuses,
|
||||
uint32_t switchDelayMs = 5000);
|
||||
|
||||
void setInitialSwitcherList(std::vector<ReturnValue_t> switcherList);
|
||||
void setInitialFusesList(std::vector<ReturnValue_t> switcherList);
|
||||
|
||||
virtual ReturnValue_t sendSwitchCommand(power::Switch_t switchNr, ReturnValue_t onOff) override;
|
||||
virtual ReturnValue_t sendFuseOnCommand(uint8_t fuseNr) override;
|
||||
virtual ReturnValue_t getSwitchState(power::Switch_t switchNr) const override;
|
||||
virtual ReturnValue_t getFuseState(uint8_t fuseNr) const override;
|
||||
virtual uint32_t getSwitchDelayMs(void) const override;
|
||||
|
||||
private:
|
||||
std::vector<ReturnValue_t> switcherList;
|
||||
std::vector<ReturnValue_t> fuseList;
|
||||
uint32_t switchDelayMs = 5000;
|
||||
};
|
||||
|
||||
#endif /* FSFW_SRC_FSFW_POWER_DUMMYPOWERSWITCHER_H_ */
|
@@ -34,14 +34,14 @@ class Fuse : public SystemObject,
|
||||
};
|
||||
|
||||
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PCDU_1;
|
||||
//! PSS detected that current on a fuse is totally out of bounds.
|
||||
static const Event FUSE_CURRENT_HIGH = MAKE_EVENT(1, severity::LOW);
|
||||
//! PSS detected a fuse that went off.
|
||||
static const Event FUSE_WENT_OFF = MAKE_EVENT(2, severity::LOW);
|
||||
//! PSS detected a fuse that violates its limits.
|
||||
static const Event POWER_ABOVE_HIGH_LIMIT = MAKE_EVENT(4, severity::LOW);
|
||||
//! PSS detected a fuse that violates its limits.
|
||||
static const Event POWER_BELOW_LOW_LIMIT = MAKE_EVENT(5, severity::LOW);
|
||||
static const Event FUSE_CURRENT_HIGH = MAKE_EVENT(
|
||||
1, severity::LOW); //!< PSS detected that current on a fuse is totally out of bounds.
|
||||
static const Event FUSE_WENT_OFF =
|
||||
MAKE_EVENT(2, severity::LOW); //!< PSS detected a fuse that went off.
|
||||
static const Event POWER_ABOVE_HIGH_LIMIT =
|
||||
MAKE_EVENT(4, severity::LOW); //!< PSS detected a fuse that violates its limits.
|
||||
static const Event POWER_BELOW_LOW_LIMIT =
|
||||
MAKE_EVENT(5, severity::LOW); //!< PSS detected a fuse that violates its limits.
|
||||
|
||||
typedef std::list<PowerComponentIF *> DeviceList;
|
||||
Fuse(object_id_t fuseObjectId, uint8_t fuseId, sid_t variableSet, VariableIds ids,
|
||||
|
@@ -15,9 +15,7 @@ PowerSensor::PowerSensor(object_id_t objectId, sid_t setId, VariableIds ids, Def
|
||||
limits.currentMin, limits.currentMax, events.currentLow, events.currentHigh),
|
||||
voltageLimit(objectId, MODULE_ID_VOLTAGE, ids.pidVoltage, confirmationCount,
|
||||
limits.voltageMin, limits.voltageMax, events.voltageLow, events.voltageHigh) {
|
||||
auto mqArgs = MqArgs(objectId, static_cast<void*>(this));
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(
|
||||
3, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue();
|
||||
}
|
||||
|
||||
PowerSensor::~PowerSensor() { QueueFactory::instance()->deleteMessageQueue(commandQueue); }
|
||||
|
@@ -3,7 +3,6 @@
|
||||
|
||||
#include "../events/Event.h"
|
||||
#include "../returnvalues/HasReturnvaluesIF.h"
|
||||
#include "definitions.h"
|
||||
/**
|
||||
*
|
||||
* @brief This interface defines a connection to a device that is capable of
|
||||
@@ -38,11 +37,11 @@ class PowerSwitchIF : public HasReturnvaluesIF {
|
||||
* @param switchNr
|
||||
* @param onOff on == @c SWITCH_ON; off != @c SWITCH_ON
|
||||
*/
|
||||
virtual ReturnValue_t sendSwitchCommand(power::Switch_t switchNr, ReturnValue_t onOff) = 0;
|
||||
virtual void sendSwitchCommand(uint8_t switchNr, ReturnValue_t onOff) const = 0;
|
||||
/**
|
||||
* Sends a command to the Power Unit to enable a certain fuse.
|
||||
*/
|
||||
virtual ReturnValue_t sendFuseOnCommand(uint8_t fuseNr) = 0;
|
||||
virtual void sendFuseOnCommand(uint8_t fuseNr) const = 0;
|
||||
|
||||
/**
|
||||
* get the state of the Switches.
|
||||
@@ -52,7 +51,7 @@ class PowerSwitchIF : public HasReturnvaluesIF {
|
||||
* - @c SWITCH_OFF if the specified switch is off.
|
||||
* - @c RETURN_FAILED if an error occured
|
||||
*/
|
||||
virtual ReturnValue_t getSwitchState(power::Switch_t switchNr) const = 0;
|
||||
virtual ReturnValue_t getSwitchState(uint8_t switchNr) const = 0;
|
||||
/**
|
||||
* get state of a fuse.
|
||||
* @param fuseNr
|
||||
|
@@ -1,12 +1,19 @@
|
||||
#include "fsfw/power/PowerSwitcher.h"
|
||||
|
||||
#include "definitions.h"
|
||||
#include "fsfw/objectmanager/ObjectManager.h"
|
||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||
|
||||
PowerSwitcher::PowerSwitcher(PowerSwitchIF* switcher, power::Switch_t setSwitch1,
|
||||
power::Switch_t setSwitch2, PowerSwitcher::State_t setStartState)
|
||||
: power(switcher), state(setStartState), firstSwitch(setSwitch1), secondSwitch(setSwitch2) {}
|
||||
PowerSwitcher::PowerSwitcher(uint8_t setSwitch1, uint8_t setSwitch2,
|
||||
PowerSwitcher::State_t setStartState)
|
||||
: state(setStartState), firstSwitch(setSwitch1), secondSwitch(setSwitch2) {}
|
||||
|
||||
ReturnValue_t PowerSwitcher::initialize(object_id_t powerSwitchId) {
|
||||
power = ObjectManager::instance()->get<PowerSwitchIF>(powerSwitchId);
|
||||
if (power == nullptr) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t PowerSwitcher::getStateOfSwitches() {
|
||||
SwitchReturn_t result = howManySwitches();
|
||||
@@ -45,37 +52,18 @@ void PowerSwitcher::commandSwitches(ReturnValue_t onOff) {
|
||||
return;
|
||||
}
|
||||
|
||||
void PowerSwitcher::turnOn(bool checkCurrentState) {
|
||||
if (checkCurrentState) {
|
||||
if (getStateOfSwitches() == PowerSwitchIF::SWITCH_ON) {
|
||||
state = SWITCH_IS_ON;
|
||||
return;
|
||||
}
|
||||
}
|
||||
void PowerSwitcher::turnOn() {
|
||||
commandSwitches(PowerSwitchIF::SWITCH_ON);
|
||||
state = WAIT_ON;
|
||||
}
|
||||
|
||||
void PowerSwitcher::turnOff(bool checkCurrentState) {
|
||||
if (checkCurrentState) {
|
||||
if (getStateOfSwitches() == PowerSwitchIF::SWITCH_OFF) {
|
||||
state = SWITCH_IS_OFF;
|
||||
return;
|
||||
}
|
||||
}
|
||||
void PowerSwitcher::turnOff() {
|
||||
commandSwitches(PowerSwitchIF::SWITCH_OFF);
|
||||
state = WAIT_OFF;
|
||||
}
|
||||
|
||||
bool PowerSwitcher::active() {
|
||||
if (state == WAIT_OFF or state == WAIT_ON) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
PowerSwitcher::SwitchReturn_t PowerSwitcher::howManySwitches() {
|
||||
if (secondSwitch == power::NO_SWITCH) {
|
||||
if (secondSwitch == NO_SWITCH) {
|
||||
return ONE_SWITCH;
|
||||
} else {
|
||||
return TWO_SWITCHES;
|
||||
|
@@ -14,28 +14,28 @@ class PowerSwitcher : public HasReturnvaluesIF {
|
||||
SWITCH_IS_OFF,
|
||||
SWITCH_IS_ON,
|
||||
};
|
||||
|
||||
State_t state;
|
||||
static const uint8_t INTERFACE_ID = CLASS_ID::POWER_SWITCHER;
|
||||
static const ReturnValue_t IN_POWER_TRANSITION = MAKE_RETURN_CODE(1);
|
||||
static const ReturnValue_t SWITCH_STATE_MISMATCH = MAKE_RETURN_CODE(2);
|
||||
PowerSwitcher(PowerSwitchIF* switcher, uint8_t setSwitch1, uint8_t setSwitch2 = power::NO_SWITCH,
|
||||
PowerSwitcher(uint8_t setSwitch1, uint8_t setSwitch2 = NO_SWITCH,
|
||||
State_t setStartState = SWITCH_IS_OFF);
|
||||
void turnOn(bool checkCurrentState = true);
|
||||
void turnOff(bool checkCurrentState = true);
|
||||
bool active();
|
||||
ReturnValue_t initialize(object_id_t powerSwitchId);
|
||||
void turnOn();
|
||||
void turnOff();
|
||||
void doStateMachine();
|
||||
State_t getState();
|
||||
ReturnValue_t checkSwitchState();
|
||||
uint32_t getSwitchDelay();
|
||||
power::Switch_t getFirstSwitch() const;
|
||||
power::Switch_t getSecondSwitch() const;
|
||||
uint8_t getFirstSwitch() const;
|
||||
uint8_t getSecondSwitch() const;
|
||||
|
||||
private:
|
||||
uint8_t firstSwitch;
|
||||
uint8_t secondSwitch;
|
||||
PowerSwitchIF* power = nullptr;
|
||||
State_t state;
|
||||
power::Switch_t firstSwitch = power::NO_SWITCH;
|
||||
power::Switch_t secondSwitch = power::NO_SWITCH;
|
||||
|
||||
static const uint8_t NO_SWITCH = 0xFF;
|
||||
enum SwitchReturn_t { ONE_SWITCH = 1, TWO_SWITCHES = 2 };
|
||||
ReturnValue_t getStateOfSwitches();
|
||||
void commandSwitches(ReturnValue_t onOff);
|
||||
|
@@ -1,108 +0,0 @@
|
||||
#include "PowerSwitcherComponent.h"
|
||||
|
||||
#include <fsfw/ipc/QueueFactory.h>
|
||||
#include <fsfw/power/PowerSwitchIF.h>
|
||||
|
||||
PowerSwitcherComponent::PowerSwitcherComponent(object_id_t objectId, PowerSwitchIF* pwrSwitcher, power::Switch_t pwrSwitch)
|
||||
: SystemObject(objectId), switcher(pwrSwitcher, pwrSwitch), modeHelper(this),
|
||||
healthHelper(this, objectId) {
|
||||
queue = QueueFactory::instance()->createMessageQueue();
|
||||
}
|
||||
|
||||
ReturnValue_t PowerSwitcherComponent::performOperation(uint8_t opCode) {
|
||||
ReturnValue_t result;
|
||||
CommandMessage command;
|
||||
|
||||
for (result = queue->receiveMessage(&command); result == RETURN_OK;
|
||||
result = queue->receiveMessage(&command)) {
|
||||
result = healthHelper.handleHealthCommand(&command);
|
||||
if (result == RETURN_OK) {
|
||||
continue;
|
||||
}
|
||||
|
||||
result = modeHelper.handleModeCommand(&command);
|
||||
if (result == RETURN_OK) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if(switcher.active()) {
|
||||
switcher.doStateMachine();
|
||||
auto currState = switcher.getState();
|
||||
if (currState == PowerSwitcher::SWITCH_IS_OFF) {
|
||||
setMode(MODE_OFF, 0);
|
||||
} else if(currState == PowerSwitcher::SWITCH_IS_ON) {
|
||||
setMode(MODE_ON, 0);
|
||||
}
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t PowerSwitcherComponent::initialize() {
|
||||
ReturnValue_t result = modeHelper.initialize();
|
||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
result = healthHelper.initialize();
|
||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
return SystemObject::initialize();
|
||||
}
|
||||
|
||||
MessageQueueId_t PowerSwitcherComponent::getCommandQueue() const {
|
||||
return queue->getId();
|
||||
}
|
||||
|
||||
void PowerSwitcherComponent::getMode(Mode_t *mode, Submode_t *submode) {
|
||||
*mode = this->mode;
|
||||
*submode = this->submode;
|
||||
}
|
||||
|
||||
ReturnValue_t PowerSwitcherComponent::setHealth(HealthState health) {
|
||||
healthHelper.setHealth(health);
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t PowerSwitcherComponent::checkModeCommand(Mode_t mode, Submode_t submode,
|
||||
uint32_t *msToReachTheMode) {
|
||||
*msToReachTheMode = 5000;
|
||||
if(mode != MODE_ON and mode != MODE_OFF) {
|
||||
return TRANS_NOT_ALLOWED;
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
void PowerSwitcherComponent::startTransition(Mode_t mode, Submode_t submode) {
|
||||
if(mode == MODE_OFF) {
|
||||
switcher.turnOff(true);
|
||||
switcher.doStateMachine();
|
||||
if(switcher.getState() == PowerSwitcher::SWITCH_IS_OFF) {
|
||||
setMode(MODE_OFF, 0);
|
||||
}
|
||||
} else if (mode == MODE_ON) {
|
||||
switcher.turnOn(true);
|
||||
switcher.doStateMachine();
|
||||
if(switcher.getState() == PowerSwitcher::SWITCH_IS_ON) {
|
||||
setMode(MODE_ON, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PowerSwitcherComponent::setToExternalControl() {
|
||||
healthHelper.setHealth(HasHealthIF::EXTERNAL_CONTROL);
|
||||
}
|
||||
|
||||
void PowerSwitcherComponent::announceMode(bool recursive) {
|
||||
triggerEvent(MODE_INFO, mode, submode);
|
||||
}
|
||||
|
||||
void PowerSwitcherComponent::setMode(Mode_t newMode, Submode_t newSubmode) {
|
||||
this->mode = newMode;
|
||||
this->submode = newSubmode;
|
||||
modeHelper.modeChanged(mode, submode);
|
||||
announceMode(false);
|
||||
}
|
||||
|
||||
HasHealthIF::HealthState PowerSwitcherComponent::getHealth() {
|
||||
return healthHelper.getHealth();
|
||||
}
|
@@ -1,64 +0,0 @@
|
||||
#ifndef _FSFW_POWER_POWERSWITCHERCOMPONENT_H_
|
||||
#define _FSFW_POWER_POWERSWITCHERCOMPONENT_H_
|
||||
|
||||
#include <fsfw/health/HasHealthIF.h>
|
||||
#include <fsfw/health/HealthHelper.h>
|
||||
#include <fsfw/modes/HasModesIF.h>
|
||||
#include <fsfw/modes/ModeHelper.h>
|
||||
#include <fsfw/objectmanager/SystemObject.h>
|
||||
#include <fsfw/power/definitions.h>
|
||||
#include <fsfw/power/PowerSwitcher.h>
|
||||
#include <fsfw/tasks/ExecutableObjectIF.h>
|
||||
|
||||
class PowerSwitchIF;
|
||||
|
||||
/**
|
||||
* @brief Allows to create an power switch object with its own mode and health
|
||||
* @details
|
||||
* This basic component allows to create an object which is solely responsible for managing a
|
||||
* switch. It also has a mode and a health by implementing the respective interface components
|
||||
* which allows integrating this component into a system mode tree.
|
||||
*
|
||||
* Commanding this component to MODE_OFF will cause the switcher to turn the switch off while
|
||||
* commanding in to MODE_ON will cause the switcher to turn the switch on.
|
||||
*/
|
||||
class PowerSwitcherComponent:
|
||||
public SystemObject,
|
||||
public HasReturnvaluesIF,
|
||||
public ExecutableObjectIF,
|
||||
public HasModesIF,
|
||||
public HasHealthIF {
|
||||
public:
|
||||
PowerSwitcherComponent(object_id_t objectId, PowerSwitchIF* pwrSwitcher,
|
||||
power::Switch_t pwrSwitch);
|
||||
|
||||
private:
|
||||
|
||||
MessageQueueIF* queue = nullptr;
|
||||
PowerSwitcher switcher;
|
||||
|
||||
Mode_t mode = MODE_OFF;
|
||||
Submode_t submode = 0;
|
||||
|
||||
ModeHelper modeHelper;
|
||||
HealthHelper healthHelper;
|
||||
|
||||
void setMode(Mode_t newMode, Submode_t newSubmode);
|
||||
|
||||
virtual ReturnValue_t performOperation(uint8_t opCode) override;
|
||||
|
||||
ReturnValue_t initialize() override;
|
||||
|
||||
MessageQueueId_t getCommandQueue() const override;
|
||||
void getMode(Mode_t *mode, Submode_t *submode) override;
|
||||
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
|
||||
uint32_t *msToReachTheMode) override;
|
||||
void startTransition(Mode_t mode, Submode_t submode) override;
|
||||
void setToExternalControl() override;
|
||||
void announceMode(bool recursive) override;
|
||||
|
||||
ReturnValue_t setHealth(HealthState health) override;
|
||||
HasHealthIF::HealthState getHealth() override;
|
||||
};
|
||||
|
||||
#endif /* _FSFW_POWER_POWERSWITCHERCOMPONENT_H_ */
|
@@ -1,13 +0,0 @@
|
||||
#ifndef FSFW_SRC_FSFW_POWER_DEFINITIONS_H_
|
||||
#define FSFW_SRC_FSFW_POWER_DEFINITIONS_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace power {
|
||||
|
||||
using Switch_t = uint8_t;
|
||||
static constexpr Switch_t NO_SWITCH = 0xFF;
|
||||
|
||||
} // namespace power
|
||||
|
||||
#endif /* FSFW_SRC_FSFW_POWER_DEFINITIONS_H_ */
|
@@ -16,9 +16,7 @@ Service1TelecommandVerification::Service1TelecommandVerification(object_id_t obj
|
||||
apid(apid),
|
||||
serviceId(serviceId),
|
||||
targetDestination(targetDestination) {
|
||||
auto mqArgs = MqArgs(objectId, static_cast<void*>(this));
|
||||
tmQueue = QueueFactory::instance()->createMessageQueue(
|
||||
messageQueueDepth, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||
tmQueue = QueueFactory::instance()->createMessageQueue(messageQueueDepth);
|
||||
}
|
||||
|
||||
Service1TelecommandVerification::~Service1TelecommandVerification() {
|
||||
|
@@ -214,11 +214,11 @@ ReturnValue_t Service3Housekeeping::handleReply(const CommandMessage* reply,
|
||||
default:
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "Service3Housekeeping::handleReply: Invalid reply with "
|
||||
<< "reply command " << command << std::endl;
|
||||
<< "reply command " << command << "!" << std::endl;
|
||||
#else
|
||||
sif::printWarning(
|
||||
"Service3Housekeeping::handleReply: Invalid reply with "
|
||||
"reply command %hu\n",
|
||||
"reply command %hu!\n",
|
||||
command);
|
||||
#endif
|
||||
return CommandingServiceBase::INVALID_REPLY;
|
||||
|
@@ -12,9 +12,7 @@ Service5EventReporting::Service5EventReporting(object_id_t objectId, uint16_t ap
|
||||
uint32_t messageQueueDepth)
|
||||
: PusServiceBase(objectId, apid, serviceId),
|
||||
maxNumberReportsPerCycle(maxNumberReportsPerCycle) {
|
||||
auto mqArgs = MqArgs(objectId, static_cast<void*>(this));
|
||||
eventQueue = QueueFactory::instance()->createMessageQueue(
|
||||
messageQueueDepth, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||
eventQueue = QueueFactory::instance()->createMessageQueue(messageQueueDepth);
|
||||
}
|
||||
|
||||
Service5EventReporting::~Service5EventReporting() {
|
||||
@@ -38,6 +36,9 @@ ReturnValue_t Service5EventReporting::performService() {
|
||||
}
|
||||
}
|
||||
}
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "Service5EventReporting::generateEventReport: Too many events" << std::endl;
|
||||
#endif
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
@@ -86,7 +87,7 @@ ReturnValue_t Service5EventReporting::handleRequest(uint8_t subservice) {
|
||||
// to be registered to the event manager to listen for events.
|
||||
ReturnValue_t Service5EventReporting::initialize() {
|
||||
EventManagerIF* manager = ObjectManager::instance()->get<EventManagerIF>(objects::EVENT_MANAGER);
|
||||
if (manager == nullptr) {
|
||||
if (manager == NULL) {
|
||||
return RETURN_FAILED;
|
||||
}
|
||||
// register Service 5 as listener for events
|
||||
|
@@ -41,7 +41,7 @@
|
||||
class Service5EventReporting : public PusServiceBase {
|
||||
public:
|
||||
Service5EventReporting(object_id_t objectId, uint16_t apid, uint8_t serviceId,
|
||||
size_t maxNumberReportsPerCycle, uint32_t messageQueueDepth);
|
||||
size_t maxNumberReportsPerCycle = 10, uint32_t messageQueueDepth = 10);
|
||||
virtual ~Service5EventReporting();
|
||||
|
||||
/***
|
||||
|
@@ -6,10 +6,10 @@
|
||||
class Service9TimeManagement : public PusServiceBase {
|
||||
public:
|
||||
static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PUS_SERVICE_9;
|
||||
//!< Clock has been set. P1: New Uptime. P2: Old Uptime
|
||||
static constexpr Event CLOCK_SET = MAKE_EVENT(0, severity::INFO);
|
||||
//!< Clock could not be set. P1: Returncode.
|
||||
static constexpr Event CLOCK_SET_FAILURE = MAKE_EVENT(1, severity::LOW);
|
||||
static constexpr Event CLOCK_SET =
|
||||
MAKE_EVENT(0, severity::INFO); //!< Clock has been set. P1: New Uptime. P2: Old Uptime
|
||||
static constexpr Event CLOCK_SET_FAILURE =
|
||||
MAKE_EVENT(1, severity::LOW); //!< Clock could not be set. P1: Returncode.
|
||||
|
||||
static constexpr uint8_t CLASS_ID = CLASS_ID::PUS_SERVICE_9;
|
||||
|
||||
|
@@ -30,11 +30,11 @@ ReturnValue_t Subsystem::checkSequence(HybridIterator<ModeListEntry> iter,
|
||||
return FALLBACK_SEQUENCE_DOES_NOT_EXIST;
|
||||
}
|
||||
|
||||
if (iter.value ==nullptr) {
|
||||
if (iter.value == NULL) {
|
||||
return NO_TARGET_TABLE;
|
||||
}
|
||||
|
||||
for (; iter.value != nullptr; ++iter) {
|
||||
for (; iter.value != NULL; ++iter) {
|
||||
if (!existsModeTable(iter->getTableId())) {
|
||||
return TABLE_DOES_NOT_EXIST;
|
||||
} else {
|
||||
@@ -66,18 +66,13 @@ HybridIterator<ModeListEntry> Subsystem::getCurrentTable() {
|
||||
void Subsystem::performChildOperation() {
|
||||
if (isInTransition) {
|
||||
if (commandsOutstanding <= 0) { // all children of the current table were commanded and replied
|
||||
if (currentSequenceIterator.value == nullptr) { // we're through with this sequence
|
||||
if (currentSequenceIterator.value == NULL) { // we're through with this sequence
|
||||
if (checkStateAgainstTable(currentTargetTable, targetSubmode) == RETURN_OK) {
|
||||
setMode(targetMode, targetSubmode);
|
||||
isInTransition = false;
|
||||
return;
|
||||
} else {
|
||||
Mode_t tableId = 0;
|
||||
auto seq = getSequence(targetMode);
|
||||
if(seq.value != nullptr) {
|
||||
tableId = seq->getTableId();
|
||||
}
|
||||
transitionFailed(TARGET_TABLE_NOT_REACHED, tableId);
|
||||
transitionFailed(TARGET_TABLE_NOT_REACHED, getSequence(targetMode)->getTableId());
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -253,13 +248,10 @@ ReturnValue_t Subsystem::handleCommandMessage(CommandMessage *message) {
|
||||
case ModeSequenceMessage::READ_TABLE: {
|
||||
ReturnValue_t result;
|
||||
Mode_t table = ModeSequenceMessage::getSequenceId(message);
|
||||
EntryPointer *entry = nullptr;
|
||||
EntryPointer *entry = NULL;
|
||||
result = modeTables.find(table, &entry);
|
||||
if (result != RETURN_OK or entry == nullptr) {
|
||||
if (result != RETURN_OK) {
|
||||
replyToCommand(result, 0);
|
||||
if(entry == nullptr) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
SerializeIF *elements[2];
|
||||
|
@@ -1,7 +1,7 @@
|
||||
#ifndef FSFW_SUBSYSTEM_SUBSYSTEM_H_
|
||||
#define FSFW_SUBSYSTEM_SUBSYSTEM_H_
|
||||
|
||||
#include "fsfw/FSFW.h"
|
||||
#include <FSFWConfig.h>
|
||||
|
||||
#include "../container/FixedArrayList.h"
|
||||
#include "../container/FixedMap.h"
|
||||
@@ -12,12 +12,8 @@
|
||||
#include "modes/ModeDefinitions.h"
|
||||
|
||||
/**
|
||||
* @brief This class extends the SubsystemBase to perform the management of mode tables
|
||||
* and mode sequences
|
||||
* @brief TODO: documentation missing
|
||||
* @details
|
||||
* This class is able to use mode tables and sequences to command all its children into the
|
||||
* right mode. Fallback sequences can be used to handle failed transitions or have a fallback
|
||||
* in case a component can't keep its current mode.
|
||||
*/
|
||||
class Subsystem : public SubsystemBase, public HasModeSequenceIF {
|
||||
public:
|
||||
|
@@ -8,13 +8,11 @@ SubsystemBase::SubsystemBase(object_id_t setObjectId, object_id_t parent, Mode_t
|
||||
uint16_t commandQueueDepth)
|
||||
: SystemObject(setObjectId),
|
||||
mode(initialMode),
|
||||
commandQueue(QueueFactory::instance()->createMessageQueue(commandQueueDepth,
|
||||
CommandMessage::MAX_MESSAGE_SIZE)),
|
||||
healthHelper(this, setObjectId),
|
||||
modeHelper(this),
|
||||
parentId(parent) {
|
||||
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(
|
||||
commandQueueDepth, CommandMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||
}
|
||||
parentId(parent) {}
|
||||
|
||||
SubsystemBase::~SubsystemBase() { QueueFactory::instance()->deleteMessageQueue(commandQueue); }
|
||||
|
||||
@@ -33,9 +31,8 @@ ReturnValue_t SubsystemBase::registerChild(object_id_t objectId) {
|
||||
info.mode = MODE_OFF;
|
||||
}
|
||||
} else {
|
||||
// intentional to force an initial command during system startup
|
||||
info.commandQueue = child->getCommandQueue();
|
||||
info.mode = HasModesIF::MODE_UNDEFINED;
|
||||
info.mode = -1; // intentional to force an initial command during system startup
|
||||
}
|
||||
|
||||
info.submode = SUBMODE_NONE;
|
||||
|
@@ -15,14 +15,7 @@
|
||||
|
||||
/**
|
||||
* @defgroup subsystems Subsystem Objects
|
||||
* All Subsystem and Assemblies can derive from this class. It contains helper classes to
|
||||
* perform mode and health handling, which allows OBSW developers to build a mode tree for
|
||||
* the whole satellite.
|
||||
*
|
||||
* Aside from setting up a mode tree and being able to executing mode tables, this class does not
|
||||
* provide an implementation on what to do with the features. To build a mode tree, helper classes
|
||||
* like the #AssemblyBase or the #Subsystem class extend and use the functionality of the base
|
||||
* class.
|
||||
* Contains all Subsystem and Assemblies
|
||||
*/
|
||||
class SubsystemBase : public SystemObject,
|
||||
public HasModesIF,
|
||||
@@ -103,7 +96,6 @@ class SubsystemBase : public SystemObject,
|
||||
Submode_t targetSubmode);
|
||||
|
||||
/**
|
||||
* This function takes care of sending all according mode commands specified inside a mode table.
|
||||
* We need to know the target Submode, as children are able to inherit the submode
|
||||
* Still, we have a default for all child implementations which do not use submode inheritance
|
||||
*/
|
||||
@@ -131,11 +123,11 @@ class SubsystemBase : public SystemObject,
|
||||
virtual void performChildOperation() = 0;
|
||||
|
||||
virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
|
||||
uint32_t *msToReachTheMode) override = 0;
|
||||
uint32_t *msToReachTheMode) = 0;
|
||||
|
||||
virtual void startTransition(Mode_t mode, Submode_t submode) override = 0;
|
||||
virtual void startTransition(Mode_t mode, Submode_t submode) = 0;
|
||||
|
||||
virtual void getMode(Mode_t *mode, Submode_t *submode) override;
|
||||
virtual void getMode(Mode_t *mode, Submode_t *submode);
|
||||
|
||||
virtual void setToExternalControl();
|
||||
|
||||
|
@@ -5,9 +5,7 @@
|
||||
#include "fsfw/tmtcservices/TmTcMessage.h"
|
||||
|
||||
TcDistributor::TcDistributor(object_id_t objectId) : SystemObject(objectId) {
|
||||
auto mqArgs = MqArgs(objectId);
|
||||
tcQueue = QueueFactory::instance()->createMessageQueue(
|
||||
DISTRIBUTER_MAX_PACKETS, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||
tcQueue = QueueFactory::instance()->createMessageQueue(DISTRIBUTER_MAX_PACKETS);
|
||||
}
|
||||
|
||||
TcDistributor::~TcDistributor() { QueueFactory::instance()->deleteMessageQueue(tcQueue); }
|
||||
|
@@ -4,13 +4,14 @@
|
||||
|
||||
AbstractTemperatureSensor::AbstractTemperatureSensor(object_id_t setObjectid,
|
||||
ThermalModuleIF *thermalModule)
|
||||
: SystemObject(setObjectid), healthHelper(this, setObjectid), parameterHelper(this) {
|
||||
if (thermalModule != nullptr) {
|
||||
: SystemObject(setObjectid),
|
||||
commandQueue(NULL),
|
||||
healthHelper(this, setObjectid),
|
||||
parameterHelper(this) {
|
||||
if (thermalModule != NULL) {
|
||||
thermalModule->registerSensor(this);
|
||||
}
|
||||
auto mqArgs = MqArgs(setObjectid, static_cast<void *>(this));
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(
|
||||
3, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue();
|
||||
}
|
||||
|
||||
AbstractTemperatureSensor::~AbstractTemperatureSensor() {
|
||||
|
@@ -51,7 +51,7 @@ class AbstractTemperatureSensor : public HasHealthIF,
|
||||
HasHealthIF::HealthState getHealth();
|
||||
|
||||
protected:
|
||||
MessageQueueIF* commandQueue = nullptr;
|
||||
MessageQueueIF* commandQueue;
|
||||
HealthHelper healthHelper;
|
||||
ParameterHelper parameterHelper;
|
||||
|
||||
|
@@ -12,9 +12,7 @@ Heater::Heater(uint32_t objectId, uint8_t switch0, uint8_t switch1)
|
||||
switch1(switch1),
|
||||
heaterOnCountdown(10800000) /*about two orbits*/,
|
||||
parameterHelper(this) {
|
||||
auto mqArgs = MqArgs(objectId, static_cast<void*>(this));
|
||||
eventQueue = QueueFactory::instance()->createMessageQueue(
|
||||
3, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||
eventQueue = QueueFactory::instance()->createMessageQueue();
|
||||
}
|
||||
|
||||
Heater::~Heater() { QueueFactory::instance()->deleteMessageQueue(eventQueue); }
|
||||
|
@@ -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,
|
||||
@@ -489,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;
|
||||
@@ -583,7 +578,7 @@ ReturnValue_t CCSDSTime::convertFromCDS(Clock::TimeOfDay_t* to, const CCSDSTime:
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
return CCSDSTime::convertTimevalToTimeOfDay(to, &tempTimeval);
|
||||
return Clock::convertTimevalToTimeOfDay(&tempTimeval, to);
|
||||
}
|
||||
|
||||
ReturnValue_t CCSDSTime::convertFromCUC(timeval* to, uint8_t pField, const uint8_t* from,
|
||||
|
@@ -223,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_ */
|
||||
|
@@ -173,6 +173,7 @@ class Clock {
|
||||
|
||||
static MutexIF *timeMutex;
|
||||
static uint16_t leapSeconds;
|
||||
static bool leapSecondsSet;
|
||||
};
|
||||
|
||||
#endif /* FSFW_TIMEMANAGER_CLOCK_H_ */
|
||||
|
@@ -3,6 +3,10 @@
|
||||
#include "fsfw/ipc/MutexGuard.h"
|
||||
#include "fsfw/timemanager/Clock.h"
|
||||
|
||||
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);
|
||||
@@ -29,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) {
|
||||
if (not leapSecondsSet) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
if (checkOrCreateClockMutex() != HasReturnvaluesIF::RETURN_OK) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
MutexGuard helper(timeMutex);
|
||||
@@ -46,6 +54,16 @@ ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) {
|
||||
|
||||
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;
|
||||
|
@@ -33,47 +33,50 @@ class TmStoreBackendIF : public HasParametersIF {
|
||||
static const ReturnValue_t INVALID_REQUEST = MAKE_RETURN_CODE(15);
|
||||
|
||||
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::MEMORY;
|
||||
//! Initiating sending data to store failed. Low, par1:
|
||||
//! returnCode, par2: integer (debug info)
|
||||
static const Event STORE_SEND_WRITE_FAILED = MAKE_EVENT(0, severity::LOW);
|
||||
//! Data was sent, but writing failed. Low, par1: returnCode, par2: 0
|
||||
static const Event STORE_WRITE_FAILED = MAKE_EVENT(1, severity::LOW);
|
||||
//! Initiating reading data from store failed. Low, par1: returnCode, par2: 0
|
||||
static const Event STORE_SEND_READ_FAILED = MAKE_EVENT(2, severity::LOW);
|
||||
//! Data was requested, but access failed. Low, par1: returnCode, par2: 0
|
||||
static const Event STORE_READ_FAILED = MAKE_EVENT(3, severity::LOW);
|
||||
//! An unexpected TM packet or data message occurred. Low, par1: 0, par2: integer (debug info)
|
||||
static const Event UNEXPECTED_MSG = MAKE_EVENT(4, severity::LOW);
|
||||
//! Storing data failed. May simply be a full store. Low, par1: returnCode,
|
||||
//! par2: integer (sequence count of failed packet).
|
||||
static const Event STORING_FAILED = MAKE_EVENT(5, severity::LOW);
|
||||
//! Dumping retrieved data failed. Low, par1: returnCode,
|
||||
//! par2: integer (sequence count of failed packet).
|
||||
static const Event TM_DUMP_FAILED = MAKE_EVENT(6, severity::LOW);
|
||||
//! Corrupted init data or read error. Low, par1: returnCode, par2: integer (debug info)
|
||||
//! Store was not initialized. Starts empty. Info, parameters both zero.
|
||||
static const Event STORE_INIT_FAILED = MAKE_EVENT(7, severity::LOW);
|
||||
//! Data was read out, but it is inconsistent. Low par1:
|
||||
//! Memory address of corruption, par2: integer (debug info)
|
||||
static const Event STORE_INIT_EMPTY = MAKE_EVENT(8, severity::INFO);
|
||||
|
||||
static const Event STORE_CONTENT_CORRUPTED = MAKE_EVENT(9, severity::LOW);
|
||||
//! Info event indicating the store will be initialized, either at boot or after IOB switch.
|
||||
//! Info. pars: 0
|
||||
static const Event STORE_INITIALIZE = MAKE_EVENT(10, severity::INFO);
|
||||
//! Info event indicating the store was successfully initialized, either at boot or after
|
||||
//! IOB switch. Info. pars: 0
|
||||
static const Event INIT_DONE = MAKE_EVENT(11, severity::INFO);
|
||||
//! Info event indicating that dumping finished successfully.
|
||||
//! par1: Number of dumped packets. par2: APID/SSC (16bits each)
|
||||
static const Event DUMP_FINISHED = MAKE_EVENT(12, severity::INFO);
|
||||
//! Info event indicating that deletion finished successfully.
|
||||
//! par1:Number of deleted packets. par2: APID/SSC (16bits each)
|
||||
static const Event DELETION_FINISHED = MAKE_EVENT(13, severity::INFO);
|
||||
//! Info event indicating that something went wrong during deletion. pars: 0
|
||||
static const Event DELETION_FAILED = MAKE_EVENT(14, severity::LOW);
|
||||
//! Info that the a auto catalog report failed
|
||||
static const Event AUTO_CATALOGS_SENDING_FAILED = MAKE_EVENT(15, severity::INFO);
|
||||
static const Event STORE_SEND_WRITE_FAILED =
|
||||
MAKE_EVENT(0, severity::LOW); //!< Initiating sending data to store failed. Low, par1:
|
||||
//!< returnCode, par2: integer (debug info)
|
||||
static const Event STORE_WRITE_FAILED = MAKE_EVENT(
|
||||
1, severity::LOW); //!< Data was sent, but writing failed. Low, par1: returnCode, par2: 0
|
||||
static const Event STORE_SEND_READ_FAILED =
|
||||
MAKE_EVENT(2, severity::LOW); //!< Initiating reading data from store failed. Low, par1:
|
||||
//!< returnCode, par2: 0
|
||||
static const Event STORE_READ_FAILED = MAKE_EVENT(
|
||||
3, severity::LOW); //!< Data was requested, but access failed. Low, par1: returnCode, par2: 0
|
||||
static const Event UNEXPECTED_MSG =
|
||||
MAKE_EVENT(4, severity::LOW); //!< An unexpected TM packet or data message occurred. Low,
|
||||
//!< par1: 0, par2: integer (debug info)
|
||||
static const Event STORING_FAILED = MAKE_EVENT(
|
||||
5, severity::LOW); //!< Storing data failed. May simply be a full store. Low, par1:
|
||||
//!< returnCode, par2: integer (sequence count of failed packet).
|
||||
static const Event TM_DUMP_FAILED =
|
||||
MAKE_EVENT(6, severity::LOW); //!< Dumping retrieved data failed. Low, par1: returnCode,
|
||||
//!< par2: integer (sequence count of failed packet).
|
||||
static const Event STORE_INIT_FAILED =
|
||||
MAKE_EVENT(7, severity::LOW); //!< Corrupted init data or read error. Low, par1: returnCode,
|
||||
//!< par2: integer (debug info)
|
||||
static const Event STORE_INIT_EMPTY = MAKE_EVENT(
|
||||
8, severity::INFO); //!< Store was not initialized. Starts empty. Info, parameters both zero.
|
||||
static const Event STORE_CONTENT_CORRUPTED =
|
||||
MAKE_EVENT(9, severity::LOW); //!< Data was read out, but it is inconsistent. Low par1:
|
||||
//!< Memory address of corruption, par2: integer (debug info)
|
||||
static const Event STORE_INITIALIZE =
|
||||
MAKE_EVENT(10, severity::INFO); //!< Info event indicating the store will be initialized,
|
||||
//!< either at boot or after IOB switch. Info. pars: 0
|
||||
static const Event INIT_DONE = MAKE_EVENT(
|
||||
11, severity::INFO); //!< Info event indicating the store was successfully initialized,
|
||||
//!< either at boot or after IOB switch. Info. pars: 0
|
||||
static const Event DUMP_FINISHED = MAKE_EVENT(
|
||||
12, severity::INFO); //!< Info event indicating that dumping finished successfully. par1:
|
||||
//!< Number of dumped packets. par2: APID/SSC (16bits each)
|
||||
static const Event DELETION_FINISHED = MAKE_EVENT(
|
||||
13, severity::INFO); //!< Info event indicating that deletion finished successfully. par1:
|
||||
//!< Number of deleted packets. par2: APID/SSC (16bits each)
|
||||
static const Event DELETION_FAILED = MAKE_EVENT(
|
||||
14,
|
||||
severity::LOW); //!< Info event indicating that something went wrong during deletion. pars: 0
|
||||
static const Event AUTO_CATALOGS_SENDING_FAILED =
|
||||
MAKE_EVENT(15, severity::INFO); //!< Info that the a auto catalog report failed
|
||||
|
||||
virtual ~TmStoreBackendIF() {}
|
||||
|
||||
|
@@ -25,7 +25,7 @@ class SpacePacket : public SpacePacketBase {
|
||||
* @param apid Sets the packet's APID field. The default value describes an idle packet.
|
||||
* @param sequenceCount ets the packet's Source Sequence Count field.
|
||||
*/
|
||||
SpacePacket(uint16_t packetDataLength = 0, bool isTelecommand = false,
|
||||
SpacePacket(uint16_t packetDataLength, bool isTelecommand = false,
|
||||
uint16_t apid = APID_IDLE_PACKET, uint16_t sequenceCount = 0);
|
||||
/**
|
||||
* The class's default destructor.
|
||||
|
@@ -20,10 +20,8 @@ CommandingServiceBase::CommandingServiceBase(object_id_t setObjectId, uint16_t a
|
||||
service(service),
|
||||
timeoutSeconds(commandTimeoutSeconds),
|
||||
commandMap(numberOfParallelCommands) {
|
||||
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
|
||||
size_t mqSz = MessageQueueMessage::MAX_MESSAGE_SIZE;
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(queueDepth, mqSz, &mqArgs);
|
||||
requestQueue = QueueFactory::instance()->createMessageQueue(queueDepth, mqSz, &mqArgs);
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(queueDepth);
|
||||
requestQueue = QueueFactory::instance()->createMessageQueue(queueDepth);
|
||||
}
|
||||
|
||||
void CommandingServiceBase::setPacketSource(object_id_t packetSource) {
|
||||
|
@@ -13,9 +13,7 @@ object_id_t PusServiceBase::packetDestination = 0;
|
||||
|
||||
PusServiceBase::PusServiceBase(object_id_t setObjectId, uint16_t setApid, uint8_t setServiceId)
|
||||
: SystemObject(setObjectId), apid(setApid), serviceId(setServiceId) {
|
||||
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
|
||||
requestQueue = QueueFactory::instance()->createMessageQueue(
|
||||
PUS_SERVICE_MAX_RECEPTION, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||
requestQueue = QueueFactory::instance()->createMessageQueue(PUS_SERVICE_MAX_RECEPTION);
|
||||
}
|
||||
|
||||
PusServiceBase::~PusServiceBase() { QueueFactory::instance()->deleteMessageQueue(requestQueue); }
|
||||
|
@@ -19,19 +19,6 @@ class SourceSequenceCounter {
|
||||
void reset(uint16_t toValue = 0) {
|
||||
sequenceCount = toValue % (SpacePacketBase::LIMIT_SEQUENCE_COUNT);
|
||||
}
|
||||
SourceSequenceCounter& operator++(int) {
|
||||
this->increment();
|
||||
return *this;
|
||||
}
|
||||
SourceSequenceCounter& operator--(int) {
|
||||
this->decrement();
|
||||
return *this;
|
||||
}
|
||||
SourceSequenceCounter& operator=(const uint16_t& newCount) {
|
||||
sequenceCount = newCount;
|
||||
return *this;
|
||||
}
|
||||
operator uint16_t() { return this->get(); }
|
||||
};
|
||||
|
||||
#endif /* FSFW_TMTCSERVICES_SOURCESEQUENCECOUNTER_H_ */
|
||||
|
@@ -15,9 +15,7 @@ TmTcBridge::TmTcBridge(object_id_t objectId, object_id_t tcDestination, object_i
|
||||
tcDestination(tcDestination)
|
||||
|
||||
{
|
||||
auto mqArgs = MqArgs(objectId, static_cast<void*>(this));
|
||||
tmTcReceptionQueue = QueueFactory::instance()->createMessageQueue(
|
||||
TMTC_RECEPTION_QUEUE_DEPTH, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||
tmTcReceptionQueue = QueueFactory::instance()->createMessageQueue(TMTC_RECEPTION_QUEUE_DEPTH);
|
||||
}
|
||||
|
||||
TmTcBridge::~TmTcBridge() { QueueFactory::instance()->deleteMessageQueue(tmTcReceptionQueue); }
|
||||
@@ -174,18 +172,15 @@ ReturnValue_t TmTcBridge::storeDownlinkData(TmTcMessage* message) {
|
||||
}
|
||||
|
||||
if (tmFifo->full()) {
|
||||
if (warningSwitch) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "TmTcBridge::storeDownlinkData: TM downlink max. number "
|
||||
"of stored packet IDs reached!"
|
||||
<< std::endl;
|
||||
sif::warning << "TmTcBridge::storeDownlinkData: TM downlink max. number "
|
||||
"of stored packet IDs reached!"
|
||||
<< std::endl;
|
||||
#else
|
||||
sif::printWarning(
|
||||
"TmTcBridge::storeDownlinkData: TM downlink max. number "
|
||||
"of stored packet IDs reached!\n");
|
||||
sif::printWarning(
|
||||
"TmTcBridge::storeDownlinkData: TM downlink max. number "
|
||||
"of stored packet IDs reached!\n");
|
||||
#endif
|
||||
warningSwitch = true;
|
||||
}
|
||||
if (overwriteOld) {
|
||||
tmFifo->retrieve(&storeId);
|
||||
tmStore->deleteData(storeId);
|
||||
|
@@ -72,8 +72,6 @@ class TmTcBridge : public AcceptsTelemetryIF,
|
||||
virtual uint16_t getIdentifier() override;
|
||||
virtual MessageQueueId_t getRequestQueue() override;
|
||||
|
||||
bool warningSwitch = true;
|
||||
|
||||
protected:
|
||||
//! Cached for initialize function.
|
||||
object_id_t tmStoreId = objects::NO_OBJECT;
|
||||
|
@@ -3,4 +3,5 @@ target_sources(${FSFW_TEST_TGT} PRIVATE
|
||||
testOpDivider.cpp
|
||||
testBitutil.cpp
|
||||
testCRC.cpp
|
||||
testTimevalOperations.cpp
|
||||
)
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
@@ -73,7 +73,7 @@ TEST_CASE("Command Executor", "[cmd-exec]") {
|
||||
REQUIRE(result != CommandExecutor::COMMAND_ERROR);
|
||||
// This ensures that the tests do not block indefinitely
|
||||
usleep(500);
|
||||
REQUIRE(limitIdx < 50000);
|
||||
REQUIRE(limitIdx < 500);
|
||||
}
|
||||
limitIdx = 0;
|
||||
CHECK(bytesHaveBeenRead == true);
|
||||
|
@@ -4,8 +4,8 @@
|
||||
#include <cstring>
|
||||
#include <queue>
|
||||
|
||||
#include "fsfw/ipc/MessageQueueBase.h"
|
||||
#include "fsfw/ipc/CommandMessage.h"
|
||||
#include "fsfw/ipc/MessageQueueBase.h"
|
||||
#include "fsfw/ipc/MessageQueueIF.h"
|
||||
#include "fsfw/ipc/MessageQueueMessage.h"
|
||||
#include "fsfw_tests/unit/CatchDefinitions.h"
|
||||
@@ -13,7 +13,7 @@
|
||||
class MessageQueueMockBase : public MessageQueueBase {
|
||||
public:
|
||||
MessageQueueMockBase()
|
||||
: MessageQueueBase(MessageQueueIF::NO_QUEUE, MessageQueueIF::NO_QUEUE, nullptr) {}
|
||||
: MessageQueueBase(MessageQueueIF::NO_QUEUE, MessageQueueIF::NO_QUEUE, nullptr) {}
|
||||
|
||||
uint8_t messageSentCounter = 0;
|
||||
bool messageSent = false;
|
||||
|
@@ -1,4 +1,5 @@
|
||||
target_sources(${FSFW_TEST_TGT} PRIVATE
|
||||
TestMessageQueue.cpp
|
||||
TestSemaphore.cpp
|
||||
TestClock.cpp
|
||||
)
|
||||
|
86
tests/src/fsfw_tests/unit/osal/TestClock.cpp
Normal file
86
tests/src/fsfw_tests/unit/osal/TestClock.cpp
Normal file
@@ -0,0 +1,86 @@
|
||||
#include <fsfw/globalfunctions/timevalOperations.h>
|
||||
#include <fsfw/timemanager/Clock.h>
|
||||
|
||||
#include <array>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include "fsfw_tests/unit/CatchDefinitions.h"
|
||||
|
||||
TEST_CASE("OSAL::Clock Test", "[OSAL::Clock Test]") {
|
||||
SECTION("Test getClock") {
|
||||
timeval time;
|
||||
ReturnValue_t result = Clock::getClock_timeval(&time);
|
||||
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
|
||||
Clock::TimeOfDay_t timeOfDay;
|
||||
result = Clock::getDateAndTime(&timeOfDay);
|
||||
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
|
||||
timeval timeOfDayAsTimeval;
|
||||
result = Clock::convertTimeOfDayToTimeval(&timeOfDay, &timeOfDayAsTimeval);
|
||||
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
|
||||
// We require timeOfDayAsTimeval to be larger than time as it
|
||||
// was request a few ns later
|
||||
double difference = timevalOperations::toDouble(timeOfDayAsTimeval - time);
|
||||
CHECK(difference >= 0.0);
|
||||
CHECK(difference <= 0.005);
|
||||
|
||||
// Conversion in the other direction
|
||||
Clock::TimeOfDay_t timevalAsTimeOfDay;
|
||||
result = Clock::convertTimevalToTimeOfDay(&time, &timevalAsTimeOfDay);
|
||||
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
|
||||
CHECK(timevalAsTimeOfDay.year <= timeOfDay.year);
|
||||
// TODO We should write TimeOfDay operators!
|
||||
}
|
||||
SECTION("Leap seconds") {
|
||||
uint16_t leapSeconds = 0;
|
||||
ReturnValue_t result = Clock::getLeapSeconds(&leapSeconds);
|
||||
REQUIRE(result == HasReturnvaluesIF::RETURN_FAILED);
|
||||
REQUIRE(leapSeconds == 0);
|
||||
result = Clock::setLeapSeconds(18);
|
||||
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
|
||||
result = Clock::getLeapSeconds(&leapSeconds);
|
||||
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
|
||||
REQUIRE(leapSeconds == 18);
|
||||
}
|
||||
SECTION("usec Test") {
|
||||
timeval timeAsTimeval;
|
||||
ReturnValue_t result = Clock::getClock_timeval(&timeAsTimeval);
|
||||
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
|
||||
uint64_t timeAsUsec = 0;
|
||||
result = Clock::getClock_usecs(&timeAsUsec);
|
||||
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
|
||||
double timeAsUsecDouble = static_cast<double>(timeAsUsec) / 1000000.0;
|
||||
timeval timeAsUsecTimeval = timevalOperations::toTimeval(timeAsUsecDouble);
|
||||
double difference = timevalOperations::toDouble(timeAsUsecTimeval - timeAsTimeval);
|
||||
// We accept 5 ms difference
|
||||
CHECK(difference >= 0.0);
|
||||
CHECK(difference <= 0.005);
|
||||
uint64_t timevalAsUint64 = static_cast<uint64_t>(timeAsTimeval.tv_sec) * 1000000ull +
|
||||
static_cast<uint64_t>(timeAsTimeval.tv_usec);
|
||||
CHECK((timeAsUsec - timevalAsUint64) >= 0);
|
||||
CHECK((timeAsUsec - timevalAsUint64) <= (5 * 1000));
|
||||
}
|
||||
SECTION("Test j2000") {
|
||||
double j2000;
|
||||
timeval time;
|
||||
time.tv_sec = 1648208539;
|
||||
time.tv_usec = 0;
|
||||
ReturnValue_t result = Clock::convertTimevalToJD2000(time, &j2000);
|
||||
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
|
||||
double correctJ2000 = 2459663.98772 - 2451545.0;
|
||||
CHECK(j2000 == Catch::Approx(correctJ2000).margin(1.2 * 1e-8));
|
||||
}
|
||||
SECTION("Convert to TT") {
|
||||
timeval utcTime;
|
||||
utcTime.tv_sec = 1648208539;
|
||||
utcTime.tv_usec = 999000;
|
||||
timeval tt;
|
||||
ReturnValue_t result = Clock::setLeapSeconds(27);
|
||||
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
|
||||
result = Clock::convertUTCToTT(utcTime, &tt);
|
||||
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
|
||||
CHECK(tt.tv_usec == 183000);
|
||||
// The plus 1 is a own forced overflow of usecs
|
||||
CHECK(tt.tv_sec == (1648208539 + 27 + 10 + 32 + 1));
|
||||
}
|
||||
}
|
@@ -81,7 +81,8 @@ TEST_CASE("CCSDSTime Tests", "[TestCCSDSTime]") {
|
||||
std::string timeAscii = "2022-12-31T23:59:59.123Z";
|
||||
Clock::TimeOfDay_t timeTo;
|
||||
const uint8_t* timeChar = reinterpret_cast<const uint8_t*>(timeAscii.c_str());
|
||||
CCSDSTime::convertFromASCII(&timeTo, timeChar, timeAscii.length());
|
||||
auto result = CCSDSTime::convertFromASCII(&timeTo, timeChar, timeAscii.length());
|
||||
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
|
||||
REQUIRE(timeTo.year == 2022);
|
||||
REQUIRE(timeTo.month == 12);
|
||||
REQUIRE(timeTo.day == 31);
|
||||
@@ -89,6 +90,19 @@ TEST_CASE("CCSDSTime Tests", "[TestCCSDSTime]") {
|
||||
REQUIRE(timeTo.minute == 59);
|
||||
REQUIRE(timeTo.second == 59);
|
||||
REQUIRE(timeTo.usecond == Catch::Approx(123000));
|
||||
|
||||
std::string timeAscii2 = "2022-365T23:59:59.123Z";
|
||||
const uint8_t* timeChar2 = reinterpret_cast<const uint8_t*>(timeAscii2.c_str());
|
||||
Clock::TimeOfDay_t timeTo2;
|
||||
result = CCSDSTime::convertFromCcsds(&timeTo2, timeChar2, timeAscii2.length());
|
||||
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
|
||||
REQUIRE(timeTo2.year == 2022);
|
||||
REQUIRE(timeTo2.month == 12);
|
||||
REQUIRE(timeTo2.day == 31);
|
||||
REQUIRE(timeTo2.hour == 23);
|
||||
REQUIRE(timeTo2.minute == 59);
|
||||
REQUIRE(timeTo2.second == 59);
|
||||
REQUIRE(timeTo2.usecond == Catch::Approx(123000));
|
||||
}
|
||||
|
||||
SECTION("CDS Conversions") {
|
||||
@@ -119,6 +133,7 @@ TEST_CASE("CCSDSTime Tests", "[TestCCSDSTime]") {
|
||||
CHECK(cdsTime.msDay_h == 0xE0);
|
||||
CHECK(cdsTime.msDay_l == 0xC5);
|
||||
CHECK(cdsTime.msDay_ll == 0xC3);
|
||||
CHECK(cdsTime.pField == CCSDSTime::P_FIELD_CDS_SHORT);
|
||||
|
||||
// Conversion back to timeval
|
||||
timeval timeReturnAsTimeval;
|
||||
@@ -128,5 +143,56 @@ TEST_CASE("CCSDSTime Tests", "[TestCCSDSTime]") {
|
||||
timeval difference = timeAsTimeval - timeReturnAsTimeval;
|
||||
CHECK(difference.tv_usec == 456);
|
||||
CHECK(difference.tv_sec == 0);
|
||||
|
||||
Clock::TimeOfDay_t timeReturnAsTimeOfDay;
|
||||
result = CCSDSTime::convertFromCDS(&timeReturnAsTimeOfDay, &cdsTime);
|
||||
CHECK(result == HasReturnvaluesIF::RETURN_OK);
|
||||
CHECK(timeReturnAsTimeOfDay.year == 2020);
|
||||
CHECK(timeReturnAsTimeOfDay.month == 2);
|
||||
CHECK(timeReturnAsTimeOfDay.day == 29);
|
||||
CHECK(timeReturnAsTimeOfDay.hour == 13);
|
||||
CHECK(timeReturnAsTimeOfDay.minute == 24);
|
||||
CHECK(timeReturnAsTimeOfDay.second == 45);
|
||||
// micro seconds precision is lost
|
||||
CHECK(timeReturnAsTimeOfDay.usecond == 123000);
|
||||
|
||||
Clock::TimeOfDay_t timeReturnAsTodFromBuffer;
|
||||
const uint8_t* buffer = reinterpret_cast<const uint8_t*>(&cdsTime);
|
||||
result = CCSDSTime::convertFromCDS(&timeReturnAsTodFromBuffer, buffer, sizeof(cdsTime));
|
||||
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
|
||||
CHECK(timeReturnAsTodFromBuffer.year == time.year);
|
||||
CHECK(timeReturnAsTodFromBuffer.month == time.month);
|
||||
CHECK(timeReturnAsTodFromBuffer.day == time.day);
|
||||
CHECK(timeReturnAsTodFromBuffer.hour == time.hour);
|
||||
CHECK(timeReturnAsTodFromBuffer.minute == time.minute);
|
||||
CHECK(timeReturnAsTodFromBuffer.second == time.second);
|
||||
CHECK(timeReturnAsTodFromBuffer.usecond == 123000);
|
||||
|
||||
Clock::TimeOfDay_t todFromCCSDS;
|
||||
result = CCSDSTime::convertFromCcsds(&todFromCCSDS, buffer, sizeof(cdsTime));
|
||||
CHECK(result == HasReturnvaluesIF::RETURN_OK);
|
||||
CHECK(todFromCCSDS.year == time.year);
|
||||
CHECK(todFromCCSDS.month == time.month);
|
||||
CHECK(todFromCCSDS.day == time.day);
|
||||
CHECK(todFromCCSDS.hour == time.hour);
|
||||
CHECK(todFromCCSDS.minute == time.minute);
|
||||
CHECK(todFromCCSDS.second == time.second);
|
||||
CHECK(todFromCCSDS.usecond == 123000);
|
||||
}
|
||||
SECTION("CCSDS Failures") {
|
||||
Clock::TimeOfDay_t time;
|
||||
time.year = 2020;
|
||||
time.month = 12;
|
||||
time.day = 32;
|
||||
time.hour = 13;
|
||||
time.minute = 24;
|
||||
time.second = 45;
|
||||
time.usecond = 123456;
|
||||
CCSDSTime::Ccs_mseconds to;
|
||||
auto result = CCSDSTime::convertToCcsds(&to, &time);
|
||||
REQUIRE(result == CCSDSTime::INVALID_TIME_FORMAT);
|
||||
CCSDSTime::Ccs_seconds to2;
|
||||
result = CCSDSTime::convertToCcsds(&to2, &time);
|
||||
REQUIRE(result == CCSDSTime::INVALID_TIME_FORMAT);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user