Merge commit 'd9759581' into mohr/introspection

This commit is contained in:
Ulrich Mohr 2022-08-18 12:20:20 +02:00
commit 31f59f915c
302 changed files with 1337 additions and 480 deletions

View File

@ -8,7 +8,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
# [unreleased]
# [v5.0.0]
## Added
- Add new `UnsignedByteField` class
# [v5.0.0] 25.07.2022
## Changes
@ -19,16 +23,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Bump C++ required version to C++17. Every project which uses the FSFW and every modern
compiler supports it
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/622
- HAL Linux SPI: Set the Clock Default State when setting new SPI speed
and mode
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/573
- GPIO HAL: `Direction`, `GpioOperation` and `Levels` are enum classes now, which prevents
name clashes with Windows defines.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/572
- New CMake option `FSFW_HAL_LINUX_ADD_LIBGPIOD` to specifically exclude `gpiod` code.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/572
- HAL Devicehandlers: Periodic printout is run-time configurable now
- `oneShotAction` flag in the `TestTask` class is not static anymore
- `SimpleRingBuffer::writeData` now checks if the amount is larger than the total size of the
Buffer and rejects such writeData calls with `HasReturnvaluesIF::RETURN_FAILED`
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/586
- Major update for version handling, using `git describe` to fetch version information with git.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/601
- Add helper functions provided by [`cmake-modules`](https://github.com/bilke/cmake-modules)
@ -46,6 +47,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
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
- Internal API change: Moved the `fsfw_hal` to the `src` folder and integration and internal
tests part of `fsfw_tests` to `src`. Unittests are now in a dedicated folder called `unittests`
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/653
### Task Module Refactoring
@ -120,6 +124,8 @@ https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/593
## Additions
- New constructor for PoolEntry which allows to simply specify the length of the pool entry.
This is also the new default constructor for scalar value with 0 as an initial value
- Added options for CI/CD builds: `FSFW_CICD_BUILD`. This allows the source code to know
whether it is running in CI/CD
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/623

View File

@ -13,7 +13,7 @@ list(APPEND CMAKE_MODULE_PATH
# Version file handling #
# ##############################################################################
set(FSFW_VERSION_IF_GIT_FAILS 4)
set(FSFW_VERSION_IF_GIT_FAILS 5)
set(FSFW_SUBVERSION_IF_GIT_FAILS 0)
set(FSFW_REVISION_IF_GIT_FAILS 0)
@ -67,6 +67,7 @@ endif()
set(FSFW_SOURCES_DIR "${CMAKE_SOURCE_DIR}/src/fsfw")
set(FSFW_ETL_LIB_NAME etl)
set(FSFW_ETL_LINK_TARGET etl::etl)
set(FSFW_ETL_LIB_MAJOR_VERSION
20
CACHE STRING "ETL library major version requirement")
@ -103,11 +104,11 @@ if(FSFW_GENERATE_SECTIONS)
option(FSFW_REMOVE_UNUSED_CODE "Remove unused code" ON)
endif()
option(FSFW_BUILD_UNITTESTS
"Build unittest binary in addition to static library" OFF)
option(FSFW_BUILD_TESTS "Build unittest binary in addition to static library"
OFF)
option(FSFW_CICD_BUILD "Build for CI/CD. This can disable problematic test" OFF)
option(FSFW_BUILD_DOCS "Build documentation with Sphinx and Doxygen" OFF)
if(FSFW_BUILD_UNITTESTS)
if(FSFW_BUILD_TESTS)
option(FSFW_TESTS_GEN_COV "Generate coverage data for unittests" ON)
endif()
@ -117,6 +118,12 @@ option(FSFW_ADD_INTERNAL_TESTS "Add internal unit tests" ON)
option(FSFW_ADD_UNITTESTS "Add regular unittests. Requires Catch2" OFF)
option(FSFW_ADD_HAL "Add Hardware Abstraction Layer" ON)
if(UNIX)
option(FSFW_HAL_LINUX_ADD_PERIPHERAL_DRIVERS "Add Linux peripheral drivers"
OFF)
option(FSFW_HAL_LINUX_ADD_LIBGPIOD "Attempt to add Linux GPIOD drivers" OFF)
endif()
# Optional sources
option(FSFW_ADD_PUS "Compile with PUS sources" ON)
option(FSFW_ADD_MONITORING "Compile with monitoring components" ON)
@ -139,7 +146,7 @@ if(IPO_SUPPORTED AND FSFW_ENABLE_IPO)
TRUE)
endif()
if(FSFW_BUILD_UNITTESTS)
if(FSFW_BUILD_TESTS)
message(
STATUS
"${MSG_PREFIX} Building the FSFW unittests in addition to the static library"
@ -162,10 +169,9 @@ if(FSFW_BUILD_UNITTESTS)
list(APPEND FSFW_FETCH_CONTENT_TARGETS Catch2)
endif()
set(FSFW_CONFIG_PATH tests/src/fsfw_tests/unit/testcfg)
configure_file(tests/src/fsfw_tests/unit/testcfg/FSFWConfig.h.in FSFWConfig.h)
configure_file(tests/src/fsfw_tests/unit/testcfg/TestsConfig.h.in
tests/TestsConfig.h)
set(FSFW_CONFIG_PATH unittests/testcfg)
configure_file(unittests/testcfg/FSFWConfig.h.in FSFWConfig.h)
configure_file(unittests/testcfg/TestsConfig.h.in tests/TestsConfig.h)
project(${FSFW_TEST_TGT} CXX C)
add_executable(${FSFW_TEST_TGT})
@ -284,16 +290,15 @@ message(
)
add_subdirectory(src)
add_subdirectory(tests)
if(FSFW_ADD_HAL)
add_subdirectory(hal)
endif()
add_subdirectory(contrib)
if(FSFW_BUILD_TESTS)
add_subdirectory(unittests)
endif()
if(FSFW_BUILD_DOCS)
add_subdirectory(docs)
endif()
if(FSFW_BUILD_UNITTESTS)
if(FSFW_BUILD_TESTS)
if(FSFW_TESTS_GEN_COV)
if(CMAKE_COMPILER_IS_GNUCXX)
include(CodeCoverage)
@ -450,8 +455,8 @@ target_include_directories(
target_compile_options(${LIB_FSFW_NAME} PRIVATE ${FSFW_WARNING_FLAGS}
${COMPILER_FLAGS})
target_link_libraries(${LIB_FSFW_NAME} PRIVATE ${FSFW_ETL_LINK_TARGET}
${FSFW_ADDITIONAL_LINK_LIBS})
target_link_libraries(${LIB_FSFW_NAME} PRIVATE ${FSFW_ADDITIONAL_LINK_LIBS})
target_link_libraries(${LIB_FSFW_NAME} PUBLIC ${FSFW_ETL_LINK_TARGET})
string(
CONCAT

View File

@ -132,14 +132,14 @@ You can use the following commands inside the `fsfw` folder to set up the build
```sh
mkdir build-tests && cd build-tests
cmake -DFSFW_BUILD_UNITTESTS=ON -DFSFW_OSAL=host -DCMAKE_BUILD_TYPE=Debug ..
cmake -DFSFW_BUILD_TESTS=ON -DFSFW_OSAL=host -DCMAKE_BUILD_TYPE=Debug ..
```
You can also use `-DFSFW_OSAL=linux` on Linux systems.
Coverage data in HTML format can be generated using the `CodeCoverage`
[CMake module](https://github.com/bilke/cmake-modules/tree/master).
To build the unittests, run them and then generare the coverage data in this format,
To build the unittests, run them and then generate the coverage data in this format,
the following command can be used inside the build directory after the build system was set up
```sh
@ -188,7 +188,10 @@ and open the documentation conveniently. Try `helper.py -h for more information.
The formatting is done by the `clang-format` tool. The configuration is contained within the
`.clang-format` file in the repository root. As long as `clang-format` is installed, you
can run the `apply-clang-format.sh` helper script to format all source files consistently.
can run the `auto-format.sh` helper script to format all source files consistently. Furthermore cmake-format is required to format CMake files which can be installed with:
````sh
sudo pip install cmakelang
````
## Index

View File

@ -12,3 +12,9 @@ RUN git clone https://github.com/catchorg/Catch2.git && \
git checkout v3.0.0-preview5 && \
cmake -Bbuild -H. -DBUILD_TESTING=OFF && \
cmake --build build/ --target install
RUN git clone https://github.com/ETLCPP/etl.git && \
cd etl && \
git checkout 20.28.0 && \
cmake -B build . && \
cmake --install build/

View File

@ -3,7 +3,7 @@ pipeline {
BUILDDIR = 'build-tests'
}
agent {
docker { image 'fsfw-ci:d2'}
docker { image 'fsfw-ci:d3'}
}
stages {
stage('Clean') {
@ -14,7 +14,7 @@ pipeline {
stage('Configure') {
steps {
dir(BUILDDIR) {
sh 'cmake -DFSFW_OSAL=host -DFSFW_BUILD_UNITTESTS=ON -DFSFW_CICD_BUILD=ON ..'
sh 'cmake -DFSFW_OSAL=host -DFSFW_BUILD_TESTS=ON -DFSFW_CICD_BUILD=ON ..'
}
}
}

View File

@ -106,7 +106,7 @@ You can use the following commands inside the ``fsfw`` folder to set up the buil
.. code-block:: console
mkdir build-tests && cd build-tests
cmake -DFSFW_BUILD_UNITTESTS=ON -DFSFW_OSAL=host ..
cmake -DFSFW_BUILD_TESTS=ON -DFSFW_OSAL=host ..
You can also use ``-DFSFW_OSAL=linux`` on Linux systems.

View File

@ -1,48 +0,0 @@
cmake_minimum_required(VERSION 3.13)
# Can also be changed by upper CMakeLists.txt file
find_library(LIB_FSFW_NAME fsfw REQUIRED)
option(FSFW_HAL_ADD_LINUX "Add the Linux HAL to the sources. Requires gpiod library" OFF)
# On by default for now because I did not have an issue including and compiling those files
# and libraries on a Desktop Linux system and the primary target of the FSFW is still embedded
# Linux. The only exception from this is the gpiod library which requires a dedicated installation,
# but CMake is able to determine whether this library is installed with find_library.
option(FSFW_HAL_LINUX_ADD_PERIPHERAL_DRIVERS "Add peripheral drivers for embedded Linux" ON)
option(FSFW_HAL_LINUX_ADD_LIBGPIOD "Target implements libgpiod" ON)
option(FSFW_HAL_ADD_RASPBERRY_PI "Add Raspberry Pi specific code to the sources" OFF)
option(FSFW_HAL_ADD_STM32H7 "Add the STM32H7 HAL to the sources" OFF)
option(FSFW_HAL_WARNING_SHADOW_LOCAL_GCC "Enable -Wshadow=local warning in GCC" ON)
set(LINUX_HAL_PATH_NAME linux)
set(STM32H7_PATH_NAME stm32h7)
add_subdirectory(src)
foreach(INCLUDE_PATH ${FSFW_HAL_ADDITIONAL_INC_PATHS})
if(IS_ABSOLUTE ${INCLUDE_PATH})
set(CURR_ABS_INC_PATH "${INCLUDE_PATH}")
else()
get_filename_component(CURR_ABS_INC_PATH
${INCLUDE_PATH} REALPATH BASE_DIR ${CMAKE_SOURCE_DIR})
endif()
if(CMAKE_VERBOSE)
message(STATUS "FSFW include path: ${CURR_ABS_INC_PATH}")
endif()
list(APPEND FSFW_HAL_ADD_INC_PATHS_ABS ${CURR_ABS_INC_PATH})
endforeach()
target_include_directories(${LIB_FSFW_NAME} PRIVATE
${FSFW_HAL_ADD_INC_PATHS_ABS}
)
target_compile_definitions(${LIB_FSFW_NAME} PRIVATE
${FSFW_HAL_DEFINES}
)
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
${FSFW_HAL_LINK_LIBS}
)

View File

@ -1,9 +0,0 @@
target_include_directories(${LIB_FSFW_NAME} PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
)
target_include_directories(${LIB_FSFW_NAME} INTERFACE
${CMAKE_CURRENT_SOURCE_DIR}
)
add_subdirectory(fsfw_hal)

View File

@ -1,3 +0,0 @@
target_sources(${LIB_FSFW_NAME} PRIVATE
GpioCookie.cpp
)

View File

@ -1,5 +0,0 @@
target_sources(${LIB_FSFW_NAME} PRIVATE
GyroL3GD20Handler.cpp
MgmRM3100Handler.cpp
MgmLIS3MDLHandler.cpp
)

View File

@ -1,25 +0,0 @@
if(FSFW_HAL_ADD_RASPBERRY_PI)
add_subdirectory(rpi)
endif()
target_sources(${LIB_FSFW_NAME} PRIVATE
UnixFileGuard.cpp
CommandExecutor.cpp
utility.cpp
)
if(FSFW_HAL_LINUX_ADD_PERIPHERAL_DRIVERS)
if(FSFW_HAL_LINUX_ADD_LIBGPIOD)
add_subdirectory(gpio)
endif()
add_subdirectory(uart)
# Adding those does not really make sense on Apple systems which
# are generally host systems. It won't even compile as the headers
# are missing
if(NOT APPLE)
add_subdirectory(i2c)
add_subdirectory(spi)
endif()
endif()
add_subdirectory(uio)

View File

@ -1,16 +0,0 @@
# This abstraction layer requires the gpiod library. You can install this library
# with "sudo apt-get install -y libgpiod-dev". If you are cross-compiling, you need
# to install the package before syncing the sysroot to your host computer.
find_library(LIB_GPIO gpiod)
if(${LIB_GPIO} MATCHES LIB_GPIO-NOTFOUND)
message(STATUS "gpiod library not found, not linking against it")
else()
target_sources(${LIB_FSFW_NAME} PRIVATE
LinuxLibgpioIF.cpp
)
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
${LIB_GPIO}
)
endif()

View File

@ -1,8 +0,0 @@
target_sources(${LIB_FSFW_NAME} PUBLIC
I2cComIF.cpp
I2cCookie.cpp
)

View File

@ -1,3 +0,0 @@
target_sources(${LIB_FSFW_NAME} PRIVATE
GpioRPi.cpp
)

View File

@ -1,8 +0,0 @@
target_sources(${LIB_FSFW_NAME} PUBLIC
SpiComIF.cpp
SpiCookie.cpp
)

View File

@ -1,4 +0,0 @@
target_sources(${LIB_FSFW_NAME} PUBLIC
UartComIF.cpp
UartCookie.cpp
)

View File

@ -1,3 +0,0 @@
target_sources(${LIB_FSFW_NAME} PUBLIC
UioMapper.cpp
)

View File

@ -1,3 +0,0 @@
target_sources(${LIB_FSFW_NAME} PRIVATE
GyroL3GD20H.cpp
)

View File

@ -1,3 +0,0 @@
target_sources(${LIB_FSFW_NAME} PRIVATE
gpio.cpp
)

View File

@ -1,2 +0,0 @@
target_sources(${LIB_FSFW_NAME} PRIVATE
)

View File

@ -1,9 +0,0 @@
target_sources(${LIB_FSFW_NAME} PRIVATE
spiCore.cpp
spiDefinitions.cpp
spiInterrupts.cpp
mspInit.cpp
SpiCookie.cpp
SpiComIF.cpp
stm32h743zi.cpp
)

View File

@ -1,2 +0,0 @@
target_sources(${LIB_FSFW_NAME} PRIVATE
)

View File

@ -5,8 +5,7 @@ fi
folder_list=(
"./src"
"./hal"
"./tests"
"./unittests"
)
cmake_fmt="cmake-format"

View File

@ -48,6 +48,20 @@ def main():
action="store_true",
help="Run valgrind on generated test binary",
)
parser.add_argument(
"-g",
"--generators",
default = "Ninja",
action="store",
help="CMake generators",
)
parser.add_argument(
"-w",
"--windows",
default=False,
action="store_true",
help="Run on windows",
)
args = parser.parse_args()
if args.all:
@ -115,14 +129,14 @@ def handle_tests_type(args, build_dir_list: list):
if args.create:
if os.path.exists(UNITTEST_FOLDER_NAME):
shutil.rmtree(UNITTEST_FOLDER_NAME)
create_tests_build_cfg()
create_tests_build_cfg(args)
build_directory = UNITTEST_FOLDER_NAME
elif len(build_dir_list) == 0:
print(
"No valid CMake tests build directory found. "
"Trying to set up test build system"
)
create_tests_build_cfg()
create_tests_build_cfg(args)
build_directory = UNITTEST_FOLDER_NAME
elif len(build_dir_list) == 1:
build_directory = build_dir_list[0]
@ -147,10 +161,15 @@ def handle_tests_type(args, build_dir_list: list):
os.chdir("..")
def create_tests_build_cfg():
def create_tests_build_cfg(args):
os.mkdir(UNITTEST_FOLDER_NAME)
os.chdir(UNITTEST_FOLDER_NAME)
cmd_runner("cmake -DFSFW_OSAL=host -DFSFW_BUILD_UNITTESTS=ON ..")
if args.windows:
cmake_cmd = 'cmake -G "' + args.generators + '" -DFSFW_OSAL=host -DFSFW_BUILD_TESTS=ON \
-DGCOVR_PATH="py -m gcovr" ..'
else:
cmake_cmd = 'cmake -G "' + args.generators + '" -DFSFW_OSAL=host -DFSFW_BUILD_TESTS=ON ..'
cmd_runner(cmake_cmd)
os.chdir("..")

View File

@ -4,3 +4,8 @@ target_include_directories(${LIB_FSFW_NAME}
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
add_subdirectory(fsfw)
if(FSFW_ADD_HAL)
add_subdirectory(fsfw_hal)
endif()
add_subdirectory(fsfw_tests)

View File

@ -6,7 +6,7 @@
ActionHelper::ActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue)
: owner(setOwner), queueToUse(useThisQueue) {}
ActionHelper::~ActionHelper() {}
ActionHelper::~ActionHelper() = default;
ReturnValue_t ActionHelper::handleActionMessage(CommandMessage* command) {
if (command->getCommand() == ActionMessage::EXECUTE_ACTION) {
@ -61,7 +61,7 @@ void ActionHelper::setQueueToUse(MessageQueueIF* queue) { queueToUse = queue; }
void ActionHelper::prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId,
store_address_t dataAddress) {
const uint8_t* dataPtr = NULL;
const uint8_t* dataPtr = nullptr;
size_t size = 0;
ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size);
if (result != HasReturnvaluesIF::RETURN_OK) {

View File

@ -2,10 +2,12 @@
#define FSFW_ACTION_ACTIONHELPER_H_
#include <map>
#include "../ipc/MessageQueueIF.h"
#include "../serialize/SerializeIF.h"
#include "ActionMessage.h"
#include "Action.h"
#include "ActionMessage.h"
#include "fsfw/ipc/MessageQueueIF.h"
#include "fsfw/serialize/SerializeIF.h"
/**
* @brief Action Helper is a helper class which handles action messages
*

View File

@ -2,9 +2,9 @@
#include "fsfw/objectmanager/ObjectManager.h"
#include "fsfw/storagemanager/StorageManagerIF.h"
ActionMessage::ActionMessage() {}
ActionMessage::ActionMessage() = default;
ActionMessage::~ActionMessage() {}
ActionMessage::~ActionMessage() = default;
void ActionMessage::setCommand(CommandMessage* message, ActionId_t fid,
store_address_t parameters) {
@ -64,9 +64,8 @@ void ActionMessage::clear(CommandMessage* message) {
switch (message->getCommand()) {
case EXECUTE_ACTION:
case DATA_REPLY: {
StorageManagerIF* ipcStore =
ObjectManager::instance()->get<StorageManagerIF>(objects::IPC_STORE);
if (ipcStore != NULL) {
auto* ipcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::IPC_STORE);
if (ipcStore != nullptr) {
ipcStore->deleteData(getStoreId(message));
}
break;

View File

@ -2,14 +2,14 @@
#include "fsfw/objectmanager/ObjectManager.h"
CommandActionHelper::CommandActionHelper(CommandsActionsIF *setOwner)
: owner(setOwner), queueToUse(NULL), ipcStore(NULL), commandCount(0), lastTarget(0) {}
: owner(setOwner), queueToUse(nullptr), ipcStore(nullptr), commandCount(0), lastTarget(0) {}
CommandActionHelper::~CommandActionHelper() {}
CommandActionHelper::~CommandActionHelper() = default;
ReturnValue_t CommandActionHelper::commandAction(object_id_t commandTo, ActionId_t actionId,
SerializeIF *data) {
HasActionsIF *receiver = ObjectManager::instance()->get<HasActionsIF>(commandTo);
if (receiver == NULL) {
auto *receiver = ObjectManager::instance()->get<HasActionsIF>(commandTo);
if (receiver == nullptr) {
return CommandsActionsIF::OBJECT_HAS_NO_FUNCTIONS;
}
store_address_t storeId;
@ -29,11 +29,8 @@ ReturnValue_t CommandActionHelper::commandAction(object_id_t commandTo, ActionId
ReturnValue_t CommandActionHelper::commandAction(object_id_t commandTo, ActionId_t actionId,
const uint8_t *data, uint32_t size) {
// if (commandCount != 0) {
// return CommandsFunctionsIF::ALREADY_COMMANDING;
// }
HasActionsIF *receiver = ObjectManager::instance()->get<HasActionsIF>(commandTo);
if (receiver == NULL) {
auto *receiver = ObjectManager::instance()->get<HasActionsIF>(commandTo);
if (receiver == nullptr) {
return CommandsActionsIF::OBJECT_HAS_NO_FUNCTIONS;
}
store_address_t storeId;
@ -59,12 +56,12 @@ ReturnValue_t CommandActionHelper::sendCommand(MessageQueueId_t queueId, ActionI
ReturnValue_t CommandActionHelper::initialize() {
ipcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::IPC_STORE);
if (ipcStore == NULL) {
if (ipcStore == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
queueToUse = owner->getCommandQueuePtr();
if (queueToUse == NULL) {
if (queueToUse == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
return HasReturnvaluesIF::RETURN_OK;
@ -104,7 +101,7 @@ ReturnValue_t CommandActionHelper::handleReply(CommandMessage *reply) {
uint8_t CommandActionHelper::getCommandCount() const { return commandCount; }
void CommandActionHelper::extractDataForOwner(ActionId_t actionId, store_address_t storeId) {
const uint8_t *data = NULL;
const uint8_t *data = nullptr;
size_t size = 0;
ReturnValue_t result = ipcStore->getData(storeId, &data, &size);
if (result != HasReturnvaluesIF::RETURN_OK) {

View File

@ -14,14 +14,14 @@ class CommandActionHelper {
friend class CommandsActionsIF;
public:
CommandActionHelper(CommandsActionsIF* owner);
explicit 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, SerializeIF* data);
ReturnValue_t initialize();
ReturnValue_t handleReply(CommandMessage* reply);
uint8_t getCommandCount() const;
[[nodiscard]] uint8_t getCommandCount() const;
private:
CommandsActionsIF* owner;

View File

@ -1,9 +1,9 @@
#ifndef FSFW_ACTION_COMMANDSACTIONSIF_H_
#define FSFW_ACTION_COMMANDSACTIONSIF_H_
#include "../ipc/MessageQueueIF.h"
#include "../returnvalues/HasReturnvaluesIF.h"
#include "CommandActionHelper.h"
#include "fsfw/ipc/MessageQueueIF.h"
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
/**
* Interface to separate commanding actions of other objects.
@ -21,7 +21,7 @@ class CommandsActionsIF {
static const uint8_t INTERFACE_ID = CLASS_ID::COMMANDS_ACTIONS_IF;
static const ReturnValue_t OBJECT_HAS_NO_FUNCTIONS = MAKE_RETURN_CODE(1);
static const ReturnValue_t ALREADY_COMMANDING = MAKE_RETURN_CODE(2);
virtual ~CommandsActionsIF() {}
virtual ~CommandsActionsIF() = default;
virtual MessageQueueIF* getCommandQueuePtr() = 0;
protected:

View File

@ -1,11 +1,11 @@
#ifndef FSFW_ACTION_HASACTIONSIF_H_
#define FSFW_ACTION_HASACTIONSIF_H_
#include "../ipc/MessageQueueIF.h"
#include "../returnvalues/HasReturnvaluesIF.h"
#include "ActionHelper.h"
#include "ActionMessage.h"
#include "SimpleActionHelper.h"
#include "fsfw/ipc/MessageQueueIF.h"
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
/**
* @brief
@ -40,15 +40,16 @@ class HasActionsIF {
static const ReturnValue_t INVALID_PARAMETERS = MAKE_RETURN_CODE(2);
static const ReturnValue_t EXECUTION_FINISHED = MAKE_RETURN_CODE(3);
static const ReturnValue_t INVALID_ACTION_ID = MAKE_RETURN_CODE(4);
virtual ~HasActionsIF() {}
virtual ~HasActionsIF() = default;
/**
* Function to get the MessageQueueId_t of the implementing object
* @return MessageQueueId_t of the object
*
*/
virtual MessageQueueId_t getCommandQueue() const = 0;
[[nodiscard]] virtual MessageQueueId_t getCommandQueue() const = 0;
[[nodiscard]] virtual ActionHelper* getActionHelper() = 0;
virtual ActionHelper* getActionHelper() = 0;
/**
* Execute or initialize the execution of a certain function.
* The ActionHelpers will execute this function and behave differently

View File

@ -3,7 +3,7 @@
SimpleActionHelper::SimpleActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue)
: ActionHelper(setOwner, useThisQueue), isExecuting(false) {}
SimpleActionHelper::~SimpleActionHelper() {}
SimpleActionHelper::~SimpleActionHelper() = default;
void SimpleActionHelper::step(ReturnValue_t result) {
// STEP_OFFESET is subtracted to compensate for adding offset in base
@ -38,7 +38,7 @@ void SimpleActionHelper::prepareExecution(MessageQueueId_t commandedBy, ActionId
ActionMessage::setStepReply(&reply, actionId, 0, HasActionsIF::IS_BUSY);
queueToUse->sendMessage(commandedBy, &reply);
}
const uint8_t* dataPtr = NULL;
const uint8_t* dataPtr = nullptr;
size_t size = 0;
ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size);
if (result != HasReturnvaluesIF::RETURN_OK) {

View File

@ -11,15 +11,15 @@
class SimpleActionHelper : public ActionHelper {
public:
SimpleActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue);
virtual ~SimpleActionHelper();
~SimpleActionHelper() override;
void step(ReturnValue_t result = HasReturnvaluesIF::RETURN_OK);
void finish(ReturnValue_t result = HasReturnvaluesIF::RETURN_OK);
ReturnValue_t reportData(SerializeIF* data);
protected:
void prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId,
store_address_t dataAddress);
virtual void resetHelper();
store_address_t dataAddress) override;
void resetHelper() override;
private:
bool isExecuting;
@ -28,4 +28,4 @@ class SimpleActionHelper : public ActionHelper {
uint8_t stepCount = 0;
};
#endif /* SIMPLEACTIONHELPER_H_ */
#endif /* FSFW_ACTION_SIMPLEACTIONHELPER_H_ */

View File

@ -2,6 +2,9 @@
#include <cstring>
#include "fsfw/FSFW.h"
#include "fsfw/serviceinterface.h"
SimpleRingBuffer::SimpleRingBuffer(const size_t size, bool overwriteOld, size_t maxExcessBytes)
: RingBufferBase<>(0, size, overwriteOld), maxExcessBytes(maxExcessBytes) {
if (maxExcessBytes > size) {
@ -48,6 +51,19 @@ void SimpleRingBuffer::confirmBytesWritten(size_t amount) {
}
ReturnValue_t SimpleRingBuffer::writeData(const uint8_t* data, size_t amount) {
if (data == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
if (amount > getMaxSize()) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "SimpleRingBuffer::writeData: Amount of data too large" << std::endl;
#else
sif::printError("SimpleRingBuffer::writeData: Amount of data too large\n");
#endif
#endif
return HasReturnvaluesIF::RETURN_FAILED;
}
if (availableWriteSpace() >= amount or overwriteOld) {
size_t amountTillWrap = writeTillWrap();
if (amountTillWrap >= amount) {

View File

@ -28,7 +28,7 @@ ReturnValue_t ControllerBase::initialize() {
MessageQueueId_t parentQueue = 0;
if (parentId != objects::NO_OBJECT) {
SubsystemBase* parent = ObjectManager::instance()->get<SubsystemBase>(parentId);
auto* parent = ObjectManager::instance()->get<SubsystemBase>(parentId);
if (parent == nullptr) {
return RETURN_FAILED;
}
@ -54,7 +54,7 @@ MessageQueueId_t ControllerBase::getCommandQueue() const { return commandQueue->
void ControllerBase::handleQueue() {
CommandMessage command;
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
ReturnValue_t result;
for (result = commandQueue->receiveMessage(&command); result == RETURN_OK;
result = commandQueue->receiveMessage(&command)) {
result = modeHelper.handleModeCommand(&command);
@ -75,20 +75,20 @@ void ControllerBase::handleQueue() {
}
}
void ControllerBase::startTransition(Mode_t mode, Submode_t submode) {
void ControllerBase::startTransition(Mode_t mode_, Submode_t submode_) {
changeHK(this->mode, this->submode, false);
triggerEvent(CHANGING_MODE, mode, submode);
this->mode = mode;
this->submode = submode;
mode = mode_;
submode = submode_;
modeHelper.modeChanged(mode, submode);
modeChanged(mode, submode);
announceMode(false);
changeHK(this->mode, this->submode, true);
}
void ControllerBase::getMode(Mode_t* mode, Submode_t* submode) {
*mode = this->mode;
*submode = this->submode;
void ControllerBase::getMode(Mode_t* mode_, Submode_t* submode_) {
*mode_ = this->mode;
*submode_ = this->submode;
}
void ControllerBase::setToExternalControl() { healthHelper.setHealth(EXTERNAL_CONTROL); }
@ -101,7 +101,7 @@ ReturnValue_t ControllerBase::performOperation(uint8_t opCode) {
return RETURN_OK;
}
void ControllerBase::modeChanged(Mode_t mode, Submode_t submode) { return; }
void ControllerBase::modeChanged(Mode_t mode_, Submode_t submode_) {}
ReturnValue_t ControllerBase::setHealth(HealthState health) {
switch (health) {
@ -117,6 +117,6 @@ ReturnValue_t ControllerBase::setHealth(HealthState health) {
HasHealthIF::HealthState ControllerBase::getHealth() { return healthHelper.getHealth(); }
void ControllerBase::setTaskIF(PeriodicTaskIF* task_) { executingTask = task_; }
void ControllerBase::changeHK(Mode_t mode, Submode_t submode, bool enable) {}
void ControllerBase::changeHK(Mode_t mode_, Submode_t submode_, bool enable) {}
ReturnValue_t ControllerBase::initializeAfterTaskCreation() { return HasReturnvaluesIF::RETURN_OK; }

View File

@ -24,21 +24,21 @@ class ControllerBase : public HasModesIF,
static const Mode_t MODE_NORMAL = 2;
ControllerBase(object_id_t setObjectId, object_id_t parentId, size_t commandQueueDepth = 3);
virtual ~ControllerBase();
~ControllerBase() override;
/** SystemObject override */
virtual ReturnValue_t initialize() override;
ReturnValue_t initialize() override;
virtual MessageQueueId_t getCommandQueue() const override;
[[nodiscard]] MessageQueueId_t getCommandQueue() const override;
/** HasHealthIF overrides */
virtual ReturnValue_t setHealth(HealthState health) override;
virtual HasHealthIF::HealthState getHealth() override;
ReturnValue_t setHealth(HealthState health) override;
HasHealthIF::HealthState getHealth() override;
/** ExecutableObjectIF overrides */
virtual ReturnValue_t performOperation(uint8_t opCode) override;
virtual void setTaskIF(PeriodicTaskIF *task) override;
virtual ReturnValue_t initializeAfterTaskCreation() override;
ReturnValue_t performOperation(uint8_t opCode) override;
void setTaskIF(PeriodicTaskIF *task) override;
ReturnValue_t initializeAfterTaskCreation() override;
protected:
/**
@ -54,8 +54,8 @@ class ControllerBase : public HasModesIF,
*/
virtual void performControlOperation() = 0;
virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
uint32_t *msToReachTheMode) override = 0;
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
uint32_t *msToReachTheMode) override = 0;
const object_id_t parentId;
@ -80,10 +80,10 @@ class ControllerBase : public HasModesIF,
/** Mode helpers */
virtual void modeChanged(Mode_t mode, Submode_t submode);
virtual void startTransition(Mode_t mode, Submode_t submode) override;
virtual void getMode(Mode_t *mode, Submode_t *submode) override;
virtual void setToExternalControl() override;
virtual void announceMode(bool recursive);
void startTransition(Mode_t mode, Submode_t submode) override;
void getMode(Mode_t *mode, Submode_t *submode) override;
void setToExternalControl() override;
void announceMode(bool recursive) override;
/** HK helpers */
virtual void changeHK(Mode_t mode, Submode_t submode, bool enable);
};

View File

@ -6,7 +6,7 @@ ExtendedControllerBase::ExtendedControllerBase(object_id_t objectId, object_id_t
poolManager(this, commandQueue),
actionHelper(this, commandQueue) {}
ExtendedControllerBase::~ExtendedControllerBase() {}
ExtendedControllerBase::~ExtendedControllerBase() = default;
ActionHelper *ExtendedControllerBase::getActionHelper() {
return &actionHelper;
@ -32,7 +32,7 @@ ReturnValue_t ExtendedControllerBase::handleCommandMessage(CommandMessage *messa
void ExtendedControllerBase::handleQueue() {
CommandMessage command;
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
ReturnValue_t result;
for (result = commandQueue->receiveMessage(&command); result == RETURN_OK;
result = commandQueue->receiveMessage(&command)) {
result = actionHelper.handleActionMessage(&command);

View File

@ -18,16 +18,16 @@ class ExtendedControllerBase : public ControllerBase,
public HasLocalDataPoolIF {
public:
ExtendedControllerBase(object_id_t objectId, object_id_t parentId, size_t commandQueueDepth = 3);
virtual ~ExtendedControllerBase();
~ExtendedControllerBase() override;
/* SystemObjectIF overrides */
virtual ReturnValue_t initialize() override;
ReturnValue_t initialize() override;
virtual MessageQueueId_t getCommandQueue() const override;
[[nodiscard]] MessageQueueId_t getCommandQueue() const override;
/* ExecutableObjectIF overrides */
virtual ReturnValue_t performOperation(uint8_t opCode) override;
virtual ReturnValue_t initializeAfterTaskCreation() override;
ReturnValue_t performOperation(uint8_t opCode) override;
ReturnValue_t initializeAfterTaskCreation() override;
/* HasActionsIF overrides */
ActionHelper* getActionHelper() override;
@ -43,28 +43,28 @@ class ExtendedControllerBase : public ControllerBase,
* @param message
* @return
*/
virtual ReturnValue_t handleCommandMessage(CommandMessage* message) = 0;
ReturnValue_t handleCommandMessage(CommandMessage* message) override = 0;
/**
* Periodic helper from ControllerBase, implemented by child class.
*/
virtual void performControlOperation() = 0;
void performControlOperation() override = 0;
/* Handle the four messages mentioned above */
void handleQueue() override;
/* HasLocalDatapoolIF overrides */
virtual LocalDataPoolManager* getHkManagerHandle() override;
virtual object_id_t getObjectId() const override;
virtual uint32_t getPeriodicOperationFrequency() const override;
LocalDataPoolManager* getHkManagerHandle() override;
[[nodiscard]] object_id_t getObjectId() const override;
[[nodiscard]] uint32_t getPeriodicOperationFrequency() const override;
virtual ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
LocalDataPoolManager& poolManager) override = 0;
virtual LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override = 0;
ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
LocalDataPoolManager& poolManager) override = 0;
LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override = 0;
// Mode abstract functions
virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
uint32_t* msToReachTheMode) override = 0;
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
uint32_t* msToReachTheMode) override = 0;
};
#endif /* FSFW_CONTROLLER_EXTENDEDCONTROLLERBASE_H_ */

View File

@ -700,7 +700,8 @@ void LocalDataPoolManager::performPeriodicHkGeneration(HkReceiver& receiver) {
if (result != HasReturnvaluesIF::RETURN_OK) {
/* Configuration error */
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "LocalDataPoolManager::performPeriodicHkOperation: HK generation failed." << std::endl;
sif::warning << "LocalDataPoolManager::performPeriodicHkOperation: HK generation failed."
<< std::endl;
#else
sif::printWarning("LocalDataPoolManager::performPeriodicHkOperation: HK generation failed.\n");
#endif

View File

@ -63,7 +63,9 @@ void DeviceHandlerBase::setThermalStateRequestPoolIds(lp_id_t thermalStatePoolId
}
DeviceHandlerBase::~DeviceHandlerBase() {
delete comCookie;
if (comCookie != nullptr) {
delete comCookie;
}
if (defaultFDIRUsed) {
delete fdirInstance;
}
@ -247,15 +249,14 @@ void DeviceHandlerBase::decrementDeviceReplyMap() {
for (std::pair<const DeviceCommandId_t, DeviceReplyInfo>& replyPair : deviceReplyMap) {
if (replyPair.second.countdown != nullptr && replyPair.second.active) {
if (replyPair.second.countdown->hasTimedOut()) {
resetTimeoutControlledReply(&replyPair.second);
timedOut = true;
}
}
if (replyPair.second.delayCycles != 0 && replyPair.second.countdown == nullptr) {
replyPair.second.delayCycles--;
if (replyPair.second.delayCycles == 0) {
if (replyPair.second.periodic) {
replyPair.second.delayCycles = replyPair.second.maxDelayCycles;
}
resetDelayCyclesControlledReply(&replyPair.second);
timedOut = true;
}
}
@ -263,7 +264,6 @@ void DeviceHandlerBase::decrementDeviceReplyMap() {
replyToReply(replyPair.first, replyPair.second, TIMEOUT);
missedReply(replyPair.first);
timedOut = false;
replyPair.second.active = false;
}
}
}
@ -451,9 +451,6 @@ ReturnValue_t DeviceHandlerBase::insertInReplyMap(DeviceCommandId_t replyId,
info.dataSet = dataSet;
info.command = deviceCommandMap.end();
info.countdown = countdown;
if (info.periodic) {
info.active = true;
}
auto resultPair = deviceReplyMap.emplace(replyId, info);
if (resultPair.second) {
return RETURN_OK;
@ -526,9 +523,19 @@ ReturnValue_t DeviceHandlerBase::updatePeriodicReply(bool enable, DeviceCommandI
return COMMAND_NOT_SUPPORTED;
}
if (enable) {
info->delayCycles = info->maxDelayCycles;
info->active = true;
if (info->countdown != nullptr) {
info->delayCycles = info->maxDelayCycles;
} else {
info->countdown->resetTimer();
}
} else {
info->delayCycles = 0;
info->active = false;
if (info->countdown != nullptr) {
info->delayCycles = 0;
} else {
info->countdown->timeOut();
}
}
}
return HasReturnvaluesIF::RETURN_OK;
@ -846,9 +853,9 @@ void DeviceHandlerBase::handleReply(const uint8_t* receivedData, DeviceCommandId
}
if (info->active && info->countdown != nullptr) {
disableTimeoutControlledReply(info);
resetTimeoutControlledReply(info);
} else if (info->delayCycles != 0) {
disableDelayCyclesControlledReply(info);
resetDelayCyclesControlledReply(info);
}
if (result != RETURN_OK) {
@ -867,7 +874,7 @@ void DeviceHandlerBase::handleReply(const uint8_t* receivedData, DeviceCommandId
}
}
void DeviceHandlerBase::disableTimeoutControlledReply(DeviceReplyInfo* info) {
void DeviceHandlerBase::resetTimeoutControlledReply(DeviceReplyInfo* info) {
if (info->periodic) {
info->countdown->resetTimer();
} else {
@ -876,7 +883,7 @@ void DeviceHandlerBase::disableTimeoutControlledReply(DeviceReplyInfo* info) {
}
}
void DeviceHandlerBase::disableDelayCyclesControlledReply(DeviceReplyInfo* info) {
void DeviceHandlerBase::resetDelayCyclesControlledReply(DeviceReplyInfo* info) {
if (info->periodic) {
info->delayCycles = info->maxDelayCycles;
} else {
@ -1007,6 +1014,8 @@ ReturnValue_t DeviceHandlerBase::enableReplyInReplyMap(DeviceCommandMap::iterato
}
if (iter != deviceReplyMap.end()) {
DeviceReplyInfo* info = &(iter->second);
// If a countdown has been set, the delay cycles will be ignored and the reply times out
// as soon as the countdown has expired
info->delayCycles = info->maxDelayCycles;
info->command = command;
command->second.expectedReplies = expectedReplies;
@ -1408,7 +1417,12 @@ uint8_t DeviceHandlerBase::getReplyDelayCycles(DeviceCommandId_t deviceCommand)
if (iter == deviceReplyMap.end()) {
return 0;
} else if (iter->second.countdown != nullptr) {
return 0;
// fake a useful return value for legacy code
if (iter->second.active) {
return 1;
} else {
return 0;
}
}
return iter->second.delayCycles;
}

View File

@ -471,12 +471,21 @@ class DeviceHandlerBase : public DeviceHandlerIF,
* @param maxDelayCycles The maximum number of delay cycles the reply waits
* until it times out.
* @param periodic Indicates if the command is periodic (i.e. it is sent
<<<<<<< HEAD
* by the device repeatedly without request) or not. Default is aperiodic (0).
* Please note that periodic replies are disabled by default. You can enable them with
* #updatePeriodicReply
* @param countdown Instead of using maxDelayCycles to timeout a device reply it is also possible
* to provide a pointer to a Countdown object which will signal the timeout
* when expired
=======
* by the device repeatedly without request) or not. Default is aperiodic (0).
* Please note that periodic replies are disabled by default. You can enable them with
* #updatePeriodicReply
* @param countdown Instead of using maxDelayCycles to timeout a device reply it is also possible
* to provide a pointer to a Countdown object which will signal the timeout
* when expired
>>>>>>> upstream/development
* @return - @c RETURN_OK when the command was successfully inserted,
* - @c RETURN_FAILED else.
*/
@ -1276,15 +1285,15 @@ class DeviceHandlerBase : public DeviceHandlerIF,
void doGetRead(void);
/**
* @brief Handles disabling of replies which use a timeout to detect missed replies.
* @brief Resets replies which use a timeout to detect missed replies.
*/
void disableTimeoutControlledReply(DeviceReplyInfo *info);
void resetTimeoutControlledReply(DeviceReplyInfo *info);
/**
* @brief Handles disabling of replies which use a number of maximum delay cycles to detect
* @brief Resets replies which use a number of maximum delay cycles to detect
* missed replies.
*/
void disableDelayCyclesControlledReply(DeviceReplyInfo *info);
void resetDelayCyclesControlledReply(DeviceReplyInfo *info);
/**
* Retrive data from the #IPCStore.

View File

@ -100,6 +100,11 @@ ReturnValue_t EventManager::subscribeToEventRange(MessageQueueId_t listener, Eve
return result;
}
ReturnValue_t EventManager::unsubscribeFromAllEvents(MessageQueueId_t listener,
object_id_t object) {
return unsubscribeFromEventRange(listener, 0, 0, true, object);
}
ReturnValue_t EventManager::unsubscribeFromEventRange(MessageQueueId_t listener, EventId_t idFrom,
EventId_t idTo, bool idInverted,
object_id_t reporterFrom,

View File

@ -37,6 +37,7 @@ class EventManager : public EventManagerIF, public ExecutableObjectIF, public Sy
EventId_t idTo = 0, bool idInverted = false,
object_id_t reporterFrom = 0, object_id_t reporterTo = 0,
bool reporterInverted = false);
ReturnValue_t unsubscribeFromAllEvents(MessageQueueId_t listener, object_id_t object);
ReturnValue_t unsubscribeFromEventRange(MessageQueueId_t listener, EventId_t idFrom = 0,
EventId_t idTo = 0, bool idInverted = false,
object_id_t reporterFrom = 0, object_id_t reporterTo = 0,

View File

@ -20,6 +20,7 @@ class EventManagerIF {
bool forwardAllButSelected = false) = 0;
virtual ReturnValue_t subscribeToEvent(MessageQueueId_t listener, EventId_t event) = 0;
virtual ReturnValue_t subscribeToAllEventsFrom(MessageQueueId_t listener, object_id_t object) = 0;
virtual ReturnValue_t unsubscribeFromAllEvents(MessageQueueId_t listener, object_id_t object) = 0;
virtual ReturnValue_t subscribeToEventRange(MessageQueueId_t listener, EventId_t idFrom = 0,
EventId_t idTo = 0, bool idInverted = false,
object_id_t reporterFrom = 0,

View File

@ -15,6 +15,16 @@ FailureIsolationBase::FailureIsolationBase(object_id_t owner, object_id_t parent
}
FailureIsolationBase::~FailureIsolationBase() {
EventManagerIF* manager = ObjectManager::instance()->get<EventManagerIF>(objects::EVENT_MANAGER);
if (manager == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "FailureIsolationBase::~FailureIsolationBase: Event Manager has not"
" been initialized!"
<< std::endl;
#endif
return;
}
manager->unsubscribeFromAllEvents(eventQueue->getId(), ownerId);
QueueFactory::instance()->deleteMessageQueue(eventQueue);
}

View File

@ -60,14 +60,14 @@ ReturnValue_t FaultCounter::getParameter(uint8_t domainId, uint8_t uniqueId,
return INVALID_DOMAIN_ID;
}
switch (uniqueId) {
case 0:
switch (static_cast<ParameterIds>(uniqueId)) {
case ParameterIds::FAILURE_THRESHOLD:
parameterWrapper->set(failureThreshold);
break;
case 1:
case ParameterIds::FAULT_COUNT:
parameterWrapper->set(faultCount);
break;
case 2:
case ParameterIds::TIMEOUT:
parameterWrapper->set(timer.timeout);
break;
default:

View File

@ -6,6 +6,8 @@
class FaultCounter : public HasParametersIF {
public:
enum class ParameterIds { FAILURE_THRESHOLD, FAULT_COUNT, TIMEOUT };
FaultCounter();
FaultCounter(uint32_t failureThreshold, uint32_t decrementAfterMs,
uint8_t setParameterDomain = 0);
@ -25,7 +27,8 @@ class FaultCounter : public HasParametersIF {
virtual ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueId,
ParameterWrapper *parameterWrapper,
const ParameterWrapper *newValues, uint16_t startAtIndex);
const ParameterWrapper *newValues = nullptr,
uint16_t startAtIndex = 0);
void setParameterDomain(uint8_t domain);

View File

@ -5,7 +5,7 @@
HealthHelper::HealthHelper(HasHealthIF* owner, object_id_t objectId)
: objectId(objectId), owner(owner) {}
HealthHelper::~HealthHelper() {}
HealthHelper::~HealthHelper() { healthTable->removeObject(objectId); }
ReturnValue_t HealthHelper::handleHealthCommand(CommandMessage* message) {
switch (message->getCommand()) {

View File

@ -27,6 +27,15 @@ ReturnValue_t HealthTable::registerObject(object_id_t object,
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t HealthTable::removeObject(object_id_t object) {
mapIterator = healthMap.find(object);
if (mapIterator == healthMap.end()) {
return HasReturnvaluesIF::RETURN_FAILED;
}
healthMap.erase(mapIterator);
return HasReturnvaluesIF::RETURN_OK;
}
void HealthTable::setHealth(object_id_t object, HasHealthIF::HealthState newState) {
MutexGuard(mutex, timeoutType, mutexTimeoutMs);
HealthMap::iterator iter = healthMap.find(object);

View File

@ -17,6 +17,7 @@ class HealthTable : public HealthTableIF, public SystemObject {
/** HealthTableIF overrides */
virtual ReturnValue_t registerObject(
object_id_t object, HasHealthIF::HealthState initilialState = HasHealthIF::HEALTHY) override;
ReturnValue_t removeObject(object_id_t object) override;
virtual size_t getPrintSize() override;
virtual void printAll(uint8_t* pointer, size_t maxSize) override;

View File

@ -14,6 +14,8 @@ class HealthTableIF : public ManagesHealthIF {
virtual ReturnValue_t registerObject(
object_id_t object, HasHealthIF::HealthState initilialState = HasHealthIF::HEALTHY) = 0;
virtual ReturnValue_t removeObject(object_id_t objectId) = 0;
virtual size_t getPrintSize() = 0;
virtual void printAll(uint8_t *pointer, size_t maxSize) = 0;

View File

@ -16,7 +16,7 @@
* This is the typedef for object identifiers.
* @ingroup system_objects
*/
typedef uint32_t object_id_t;
using object_id_t = uint32_t;
/**
* This interface allows a class to be included in the object manager

View File

@ -54,7 +54,7 @@ ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) {
// If the deadline was missed, the deadlineMissedFunc is called.
if (!PosixThread::delayUntil(&lastWakeTime, interval)) {
// No time left on timer -> we missed the deadline
if(dlmFunc != nullptr){
if (dlmFunc != nullptr) {
dlmFunc();
}
}

View File

@ -290,9 +290,9 @@ ReturnValue_t MessageQueue::handleOpenError(mq_attr* attributes, uint32_t messag
*/
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "MessageQueue::MessageQueue: Default MQ size " << defaultMqMaxMsg
<< " is too small for requested size " << messageDepth << std::endl;
<< " is too small for requested message depth " << messageDepth << std::endl;
sif::error << "This error can be fixed by setting the maximum "
"allowed message size higher!"
"allowed message depth higher"
<< std::endl;
#else
sif::printError(

View File

@ -249,9 +249,12 @@ void Service3Housekeeping::handleUnrequestedReply(CommandMessage* reply) {
break;
}
case (CommandMessage::REPLY_REJECTED): {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "Service3Housekeeping::handleUnrequestedReply: Unexpected reply "
"rejected with error code"
<< reply->getParameter() << std::endl;
#else
#endif
break;
}

View File

@ -1,10 +1,10 @@
#ifndef FSFW_INC_FSFW_SERIALIZE_H_
#define FSFW_INC_FSFW_SERIALIZE_H_
#include "src/core/serialize/EndianConverter.h"
#include "src/core/serialize/SerialArrayListAdapter.h"
#include "src/core/serialize/SerialBufferAdapter.h"
#include "src/core/serialize/SerialLinkedListAdapter.h"
#include "src/core/serialize/SerializeElement.h"
#include "fsfw/serialize/EndianConverter.h"
#include "fsfw/serialize/SerialArrayListAdapter.h"
#include "fsfw/serialize/SerialBufferAdapter.h"
#include "fsfw/serialize/SerialLinkedListAdapter.h"
#include "fsfw/serialize/SerializeElement.h"
#endif /* FSFW_INC_FSFW_SERIALIZE_H_ */

View File

@ -4,7 +4,7 @@
#include <cstdint>
#include <cstring>
#include "../osal/Endiness.h"
#include "fsfw/osal/Endiness.h"
/**
* Helper class to convert variables or bitstreams between machine
@ -36,7 +36,7 @@
*/
class EndianConverter {
private:
EndianConverter(){};
EndianConverter() = default;
public:
/**
@ -49,8 +49,8 @@ class EndianConverter {
#error BYTE_ORDER_SYSTEM not defined
#elif BYTE_ORDER_SYSTEM == LITTLE_ENDIAN
T tmp;
uint8_t *pointerOut = (uint8_t *)&tmp;
uint8_t *pointerIn = (uint8_t *)&in;
auto *pointerOut = reinterpret_cast<uint8_t *>(&tmp);
auto *pointerIn = reinterpret_cast<uint8_t *>(&in);
for (size_t count = 0; count < sizeof(T); count++) {
pointerOut[sizeof(T) - count - 1] = pointerIn[count];
}
@ -73,10 +73,8 @@ class EndianConverter {
for (size_t count = 0; count < size; count++) {
out[size - count - 1] = in[count];
}
return;
#elif BYTE_ORDER_SYSTEM == BIG_ENDIAN
memcpy(out, in, size);
return;
#endif
}
@ -90,8 +88,8 @@ class EndianConverter {
#error BYTE_ORDER_SYSTEM not defined
#elif BYTE_ORDER_SYSTEM == BIG_ENDIAN
T tmp;
uint8_t *pointerOut = (uint8_t *)&tmp;
uint8_t *pointerIn = (uint8_t *)&in;
auto *pointerOut = reinterpret_cast<uint8_t *>(&tmp);
auto *pointerIn = reinterpret_cast<uint8_t *>(&in);
for (size_t count = 0; count < sizeof(T); count++) {
pointerOut[sizeof(T) - count - 1] = pointerIn[count];
}
@ -113,10 +111,8 @@ class EndianConverter {
for (size_t count = 0; count < size; count++) {
out[size - count - 1] = in[count];
}
return;
#elif BYTE_ORDER_SYSTEM == LITTLE_ENDIAN
memcpy(out, in, size);
return;
#endif
}
};

View File

@ -3,7 +3,7 @@
#include <cstddef>
#include "../returnvalues/HasReturnvaluesIF.h"
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
/**
* @defgroup serialize Serialization
@ -34,7 +34,7 @@ class SerializeIF {
static const ReturnValue_t TOO_MANY_ELEMENTS =
MAKE_RETURN_CODE(3); // !< There are too many elements to be deserialized
virtual ~SerializeIF() {}
virtual ~SerializeIF() = default;
/**
* @brief
* Function to serialize the object into a buffer with maxSize. Size represents the written
@ -59,14 +59,21 @@ class SerializeIF {
* - @c RETURN_FAILED Generic error
* - @c RETURN_OK Successful serialization
*/
virtual ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize,
Endianness streamEndianness) const = 0;
[[nodiscard]] virtual ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize,
Endianness streamEndianness) const = 0;
/**
* Forwards to regular @serialize call with big (network) endianness
*/
[[nodiscard]] virtual ReturnValue_t serializeBe(uint8_t **buffer, size_t *size,
size_t maxSize) const {
return serialize(buffer, size, maxSize, SerializeIF::Endianness::NETWORK);
}
/**
* Gets the size of a object if it would be serialized in a buffer
* @return Size of serialized object
*/
virtual size_t getSerializedSize() const = 0;
[[nodiscard]] virtual size_t getSerializedSize() const = 0;
/**
* @brief
@ -90,6 +97,57 @@ class SerializeIF {
*/
virtual ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size,
Endianness streamEndianness) = 0;
/**
* Forwards to regular @deSerialize call with big (network) endianness
*/
virtual ReturnValue_t deSerializeBe(const uint8_t **buffer, size_t *size) {
return deSerialize(buffer, size, SerializeIF::Endianness::NETWORK);
}
/**
* Helper method which can be used if serialization should be performed without any additional
* pointer arithmetic on a passed buffer pointer
* @param buffer
* @param maxSize
* @param streamEndianness
* @return
*/
[[nodiscard]] virtual ReturnValue_t serialize(uint8_t *buffer, size_t &serLen, size_t maxSize,
Endianness streamEndianness) const {
size_t tmpSize = 0;
ReturnValue_t result = serialize(&buffer, &tmpSize, maxSize, streamEndianness);
serLen = tmpSize;
return result;
}
/**
* Forwards to regular @serialize call with big (network) endianness
*/
[[nodiscard]] virtual ReturnValue_t serializeBe(uint8_t *buffer, size_t &serLen,
size_t maxSize) const {
return serialize(buffer, serLen, maxSize, SerializeIF::Endianness::NETWORK);
}
/**
* Helper methods which can be used if deserialization should be performed without any additional
* pointer arithmetic on a passed buffer pointer
* @param buffer
* @param maxSize
* @param streamEndianness
* @return
*/
virtual ReturnValue_t deSerialize(const uint8_t *buffer, size_t &deserSize, size_t maxSize,
Endianness streamEndianness) {
size_t deserLen = maxSize;
ReturnValue_t result = deSerialize(&buffer, &deserLen, streamEndianness);
deserSize = maxSize - deserLen;
return result;
}
/**
* Forwards to regular @serialize call with big (network) endianness
*/
virtual ReturnValue_t deSerializeBe(const uint8_t *buffer, size_t &deserSize, size_t maxSize) {
return deSerialize(buffer, deserSize, maxSize, SerializeIF::Endianness::NETWORK);
}
};
#endif /* FSFW_SERIALIZE_SERIALIZEIF_H_ */

View File

@ -0,0 +1,52 @@
#ifndef FSFW_UTIL_UNSIGNEDBYTEFIELD_H
#define FSFW_UTIL_UNSIGNEDBYTEFIELD_H
#include "fsfw/serialize.h"
template<typename T>
class UnsignedByteField: public SerializeIF {
public:
static_assert(std::is_unsigned<T>::value);
explicit UnsignedByteField(T value): value(value) {}
[[nodiscard]] ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize,
Endianness streamEndianness) const override {
return SerializeAdapter::serialize(&value, buffer, size, maxSize, streamEndianness);
}
ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size,
Endianness streamEndianness) override {
return SerializeAdapter::deSerialize(&value, buffer, size, streamEndianness);
}
[[nodiscard]] size_t getSerializedSize() const override {
return sizeof(T);
}
[[nodiscard]] T getValue() const {
return value;
}
void setValue(T value_) {
value = value_;
}
private:
T value;
};
class U32ByteField: public UnsignedByteField<uint32_t> {
public:
explicit U32ByteField(uint32_t value): UnsignedByteField<uint32_t>(value) {}
};
class U16ByteField: public UnsignedByteField<uint16_t> {
public:
explicit U16ByteField(uint16_t value): UnsignedByteField<uint16_t>(value) {}
};
class U8ByteField: public UnsignedByteField<uint8_t> {
public:
explicit U8ByteField(uint8_t value): UnsignedByteField<uint8_t>(value) {}
};
#endif // FSFW_UTIL_UNSIGNEDBYTEFIELD_H

View File

@ -2,9 +2,9 @@ add_subdirectory(devicehandlers)
add_subdirectory(common)
if(UNIX)
add_subdirectory(linux)
add_subdirectory(linux)
endif()
if(FSFW_HAL_ADD_STM32H7)
add_subdirectory(stm32h7)
add_subdirectory(stm32h7)
endif()

View File

@ -0,0 +1 @@
target_sources(${LIB_FSFW_NAME} PRIVATE GpioCookie.cpp)

View File

@ -0,0 +1,3 @@
target_sources(
${LIB_FSFW_NAME} PRIVATE GyroL3GD20Handler.cpp MgmRM3100Handler.cpp
MgmLIS3MDLHandler.cpp)

View File

@ -286,26 +286,22 @@ ReturnValue_t MgmLIS3MDLHandler::interpretDeviceReply(DeviceCommandId_t id, cons
PoolReadGuard readHelper(&dataset);
if (readHelper.getReadResult() == HasReturnvaluesIF::RETURN_OK) {
if (std::abs(mgmX) > absLimitX or std::abs(mgmY) > absLimitY or
std::abs(mgmZ) > absLimitZ) {
dataset.fieldStrengths.setValid(false);
}
if (std::abs(mgmX) < absLimitX) {
dataset.fieldStrengthX = mgmX;
dataset.fieldStrengthX.setValid(true);
} else {
dataset.fieldStrengthX.setValid(false);
dataset.fieldStrengths[0] = mgmX;
}
if (std::abs(mgmY) < absLimitY) {
dataset.fieldStrengthY = mgmY;
dataset.fieldStrengthY.setValid(true);
} else {
dataset.fieldStrengthY.setValid(false);
dataset.fieldStrengths[1] = mgmY;
}
if (std::abs(mgmZ) < absLimitZ) {
dataset.fieldStrengthZ = mgmZ;
dataset.fieldStrengthZ.setValid(true);
} else {
dataset.fieldStrengthZ.setValid(false);
dataset.fieldStrengths[2] = mgmZ;
}
dataset.fieldStrengths.setValid(true);
}
break;
}
@ -471,10 +467,8 @@ void MgmLIS3MDLHandler::modeChanged(void) { internalState = InternalState::STATE
ReturnValue_t MgmLIS3MDLHandler::initializeLocalDataPool(localpool::DataPool &localDataPoolMap,
LocalDataPoolManager &poolManager) {
localDataPoolMap.emplace(MGMLIS3MDL::FIELD_STRENGTH_X, new PoolEntry<float>({0.0}));
localDataPoolMap.emplace(MGMLIS3MDL::FIELD_STRENGTH_Y, new PoolEntry<float>({0.0}));
localDataPoolMap.emplace(MGMLIS3MDL::FIELD_STRENGTH_Z, new PoolEntry<float>({0.0}));
localDataPoolMap.emplace(MGMLIS3MDL::TEMPERATURE_CELCIUS, new PoolEntry<float>({0.0}));
localDataPoolMap.emplace(MGMLIS3MDL::FIELD_STRENGTHS, &mgmXYZ);
localDataPoolMap.emplace(MGMLIS3MDL::TEMPERATURE_CELCIUS, &temperature);
poolManager.subscribeForPeriodicPacket(dataset.getSid(), false, 10.0, false);
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -103,6 +103,8 @@ class MgmLIS3MDLHandler : public DeviceHandlerBase {
CommunicationStep communicationStep = CommunicationStep::DATA;
bool commandExecuted = false;
PoolEntry<float> mgmXYZ = PoolEntry<float>(3);
PoolEntry<float> temperature = PoolEntry<float>();
/*------------------------------------------------------------------------*/
/* Device specific commands and variables */
/*------------------------------------------------------------------------*/

View File

@ -309,9 +309,7 @@ void MgmRM3100Handler::modeChanged(void) { internalState = InternalState::NONE;
ReturnValue_t MgmRM3100Handler::initializeLocalDataPool(localpool::DataPool &localDataPoolMap,
LocalDataPoolManager &poolManager) {
localDataPoolMap.emplace(RM3100::FIELD_STRENGTH_X, new PoolEntry<float>({0.0}));
localDataPoolMap.emplace(RM3100::FIELD_STRENGTH_Y, new PoolEntry<float>({0.0}));
localDataPoolMap.emplace(RM3100::FIELD_STRENGTH_Z, new PoolEntry<float>({0.0}));
localDataPoolMap.emplace(RM3100::FIELD_STRENGTHS, &mgmXYZ);
poolManager.subscribeForPeriodicPacket(primaryDataset.getSid(), false, 10.0, false);
return HasReturnvaluesIF::RETURN_OK;
}
@ -355,9 +353,9 @@ ReturnValue_t MgmRM3100Handler::handleDataReadout(const uint8_t *packet) {
// TODO: Sanity check on values?
PoolReadGuard readGuard(&primaryDataset);
if (readGuard.getReadResult() == HasReturnvaluesIF::RETURN_OK) {
primaryDataset.fieldStrengthX = fieldStrengthX;
primaryDataset.fieldStrengthY = fieldStrengthY;
primaryDataset.fieldStrengthZ = fieldStrengthZ;
primaryDataset.fieldStrengths[0] = fieldStrengthX;
primaryDataset.fieldStrengths[1] = fieldStrengthY;
primaryDataset.fieldStrengths[2] = fieldStrengthZ;
primaryDataset.setValidity(true, true);
}
return RETURN_OK;

View File

@ -85,6 +85,7 @@ class MgmRM3100Handler : public DeviceHandlerBase {
bool goToNormalModeAtStartup = false;
uint32_t transitionDelay;
PoolEntry<float> mgmXYZ = PoolEntry<float>(3);
ReturnValue_t handleCycleCountConfigCommand(DeviceCommandId_t deviceCommand,
const uint8_t *commandData, size_t commandDataLen);

View File

@ -139,12 +139,7 @@ static const uint8_t CTRL_REG5_DEFAULT = 0;
static const uint32_t MGM_DATA_SET_ID = READ_CONFIG_AND_DATA;
enum MgmPoolIds : lp_id_t {
FIELD_STRENGTH_X,
FIELD_STRENGTH_Y,
FIELD_STRENGTH_Z,
TEMPERATURE_CELCIUS
};
enum MgmPoolIds : lp_id_t { FIELD_STRENGTHS, TEMPERATURE_CELCIUS };
class MgmPrimaryDataset : public StaticLocalDataSet<4> {
public:
@ -152,9 +147,10 @@ class MgmPrimaryDataset : public StaticLocalDataSet<4> {
MgmPrimaryDataset(object_id_t mgmId) : StaticLocalDataSet(sid_t(mgmId, MGM_DATA_SET_ID)) {}
lp_var_t<float> fieldStrengthX = lp_var_t<float>(sid.objectId, FIELD_STRENGTH_X, this);
lp_var_t<float> fieldStrengthY = lp_var_t<float>(sid.objectId, FIELD_STRENGTH_Y, this);
lp_var_t<float> fieldStrengthZ = lp_var_t<float>(sid.objectId, FIELD_STRENGTH_Z, this);
/**
* Field strenghts in uT
*/
lp_vec_t<float, 3> fieldStrengths = lp_vec_t<float, 3>(sid.objectId, FIELD_STRENGTHS, this);
lp_var_t<float> temperature = lp_var_t<float>(sid.objectId, TEMPERATURE_CELCIUS, this);
};

View File

@ -101,11 +101,7 @@ class CycleCountCommand : public SerialLinkedListAdapter<SerializeIF> {
static constexpr uint32_t MGM_DATASET_ID = READ_DATA;
enum MgmPoolIds : lp_id_t {
FIELD_STRENGTH_X,
FIELD_STRENGTH_Y,
FIELD_STRENGTH_Z,
};
enum MgmPoolIds : lp_id_t { FIELD_STRENGTHS };
class Rm3100PrimaryDataset : public StaticLocalDataSet<3> {
public:
@ -113,10 +109,10 @@ class Rm3100PrimaryDataset : public StaticLocalDataSet<3> {
Rm3100PrimaryDataset(object_id_t mgmId) : StaticLocalDataSet(sid_t(mgmId, MGM_DATASET_ID)) {}
// Field strengths in micro Tesla.
lp_var_t<float> fieldStrengthX = lp_var_t<float>(sid.objectId, FIELD_STRENGTH_X, this);
lp_var_t<float> fieldStrengthY = lp_var_t<float>(sid.objectId, FIELD_STRENGTH_Y, this);
lp_var_t<float> fieldStrengthZ = lp_var_t<float>(sid.objectId, FIELD_STRENGTH_Z, this);
/**
* Field strenghts in uT
*/
lp_vec_t<float, 3> fieldStrengths = lp_vec_t<float, 3>(sid.objectId, FIELD_STRENGTHS, this);
};
} // namespace RM3100

View File

@ -0,0 +1,21 @@
if(FSFW_HAL_ADD_RASPBERRY_PI)
add_subdirectory(rpi)
endif()
target_sources(${LIB_FSFW_NAME} PRIVATE UnixFileGuard.cpp CommandExecutor.cpp
utility.cpp)
if(FSFW_HAL_LINUX_ADD_PERIPHERAL_DRIVERS)
if(FSFW_HAL_LINUX_ADD_LIBGPIOD)
add_subdirectory(gpio)
endif()
add_subdirectory(uart)
# Adding those does not really make sense on Apple systems which are generally
# host systems. It won't even compile as the headers are missing
if(NOT APPLE)
add_subdirectory(i2c)
add_subdirectory(spi)
endif()
endif()
add_subdirectory(uio)

View File

@ -0,0 +1,12 @@
# This abstraction layer requires the gpiod library. You can install this
# library with "sudo apt-get install -y libgpiod-dev". If you are
# cross-compiling, you need to install the package before syncing the sysroot to
# your host computer.
find_library(LIB_GPIO gpiod)
if(${LIB_GPIO} MATCHES LIB_GPIO-NOTFOUND)
message(STATUS "gpiod library not found, not linking against it")
else()
target_sources(${LIB_FSFW_NAME} PRIVATE LinuxLibgpioIF.cpp)
target_link_libraries(${LIB_FSFW_NAME} PRIVATE ${LIB_GPIO})
endif()

View File

@ -0,0 +1 @@
target_sources(${LIB_FSFW_NAME} PUBLIC I2cComIF.cpp I2cCookie.cpp)

View File

@ -0,0 +1 @@
target_sources(${LIB_FSFW_NAME} PRIVATE GpioRPi.cpp)

View File

@ -0,0 +1 @@
target_sources(${LIB_FSFW_NAME} PUBLIC SpiComIF.cpp SpiCookie.cpp)

Some files were not shown because too many files have changed in this diff Show More