Compare commits

..

1 Commits

Author SHA1 Message Date
taheran a508a02120 Branch on top of the V0.0.1 release tag. Changes made to TimeStamper,
TmPacketBase and TmPacketMinimal to suit ESBO protocol
2022-01-17 15:52:49 +01:00
1080 changed files with 22886 additions and 49326 deletions

View File

@ -1,7 +0,0 @@
---
BasedOnStyle: Google
IndentWidth: 2
---
Language: Cpp
ColumnLimit: 100
---

2
.gitignore vendored
View File

@ -2,5 +2,3 @@
.project
.settings
.metadata
/build*

175
CHANGELOG
View File

@ -1,175 +0,0 @@
# Changed from ASTP 1.1.0 to 1.2.0
## API Changes
### FSFW Architecture
- New src folder which contains all source files except the HAL, contributed code and test code
- External and internal API mostly stayed the same
- Folder names are now all smaller case: internalError was renamed to internalerror and
FreeRTOS was renamed to freertos
- Warning if optional headers are used but the modules was not added to the source files to compile
### HAL
- HAL added back into FSFW. It is tightly bound to the FSFW, and compiling it as a static library
made using it more complicated than necessary
## Bugfixes
### FreeRTOS QueueMapManager
- Fixed a bug which causes the first generated Queue ID to be invalid
## Enhancements
### FSFW Architecture
- See API changes chapter. This change will keep the internal API consistent in the future
# Changes from ASTP 1.0.0 to 1.1.0
## API Changes
### PUS
- Added PUS C support
- SUBSYSTEM_IDs added for PUS Services
- Added new Parameter which must be defined in config: fsfwconfig::FSFW_MAX_TM_PACKET_SIZE
### ObjectManager
- ObjectManager is now a singelton
### Configuration
- Additional configuration option fsfwconfig::FSFW_MAX_TM_PACKET_SIZE which
need to be specified in FSFWConfig.h
### CMake
- Changed Cmake FSFW_ADDITIONAL_INC_PATH to FSFW_ADDITIONAL_INC_PATHS
## Bugfixes
- timemanager/TimeStamperIF.h: Timestamp config was not used correctly, leading to different timestamp sizes than configured in fsfwconfig::FSFW_MISSION_TIMESTAMP_SIZE
- TCP server fixes
## Enhancements
### FreeRTOS Queue Handles
- Fixed an internal issue how FreeRTOS MessageQueues were handled
### Linux OSAL
- Better printf error messages
### CMake
- Check for C++11 as mininimum required Version
### Debug Output
- Changed Warning color to magenta, which is well readable on both dark and light mode IDEs
# Changes from ASTP 0.0.1 to 1.0.0
### Host OSAL
- Bugfix in MessageQueue, which caused the sender not to be set properly
### FreeRTOS OSAL
- vRequestContextSwitchFromISR is declared extern "C" so it can be defined in
a C file without issues
### PUS Services
- It is now possible to change the message queue depth for the telecommand verification service (PUS1)
- The same is possible for the event reporting service (PUS5)
- PUS Health Service added, which allows to command and retrieve health via PUS packets
### EnhancedControllerBase
- New base class for a controller which also implements HasActionsIF and HasLocalDataPoolIF
### Local Pool
- Interface of LocalPools has changed. LocalPool is not a template anymore. Instead the size and
bucket number of the pools per page and the number of pages are passed to the ctor instead of
two ctor arguments and a template parameter
### Parameter Service
- The API of the parameter service has been changed to prevent inconsistencies
between documentation and actual code and to clarify usage.
- The parameter ID now consists of:
1. Domain ID (1 byte)
2. Unique Identifier (1 byte)
3. Linear Index (2 bytes)
The linear index can be used for arrays as well as matrices.
The parameter load command now explicitely expects the ECSS PTC and PFC
information as well as the rows and column number. Rows and column will
default to one, which is equivalent to one scalar parameter (the most
important use-case)
### File System Interface
- A new interfaces specifies the functions for a software object which exposes the file system of
a given hardware to use message based file handling (e.g. PUS commanding)
### Internal Error Reporter
- The new internal error reporter uses the local data pools. The pool IDs for
the exisiting three error values and the new error set will be hardcoded for
now, the the constructor for the internal error reporter just takes an object
ID for now.
### Device Handler Base
- There is an additional `PERFORM_OPERATION` step for the device handler base. It is important
that DHB users adapt their polling sequence tables to perform this step. This steps allows for
a clear distinction between operation and communication steps
- setNormalDatapoolEntriesInvalid is not an abstract method and a default implementation was provided
- getTransitionDelayMs is now an abstract method
### DeviceHandlerIF
- Typo for UNKNOWN_DEVICE_REPLY
### Events
- makeEvent function: Now takes three input parameters instead of two and
allows setting a unique ID. Event.cpp source file removed, functions now
defined in header directly. Namespaces renamed. Functions declared `constexpr`
now
### Commanding Service Base
- CSB uses the new fsfwconfig::FSFW_CSB_FIFO_DEPTH variable to determine the FIFO depth for each
CSB instance. This variable has to be set in the FSFWConfig.h file
### Service Interface
- Proper printf support contained in ServiceInterfacePrinter.h
- CPP ostream support now optional (can reduce executable size by 150 - 250 kB)
- Amalagated header which determines automatically which service interface to use depending on FSFWConfig.h configuration.
Users can just use #include <fsfw/serviceinterface/ServiceInterface.h>
- If CPP streams are excluded, sif:: calls won't work anymore and need to be replaced by their printf counterparts.
For the fsfw, this can be done by checking the processor define FSFW_CPP_OSTREAM_ENABLED from FSFWConfig.h.
For mission code, developers need to replace sif:: calls by the printf counterparts, but only if the CPP stream are excluded.
If this is not the case, everything should work as usual.
### ActionHelper and ActionMessage
- ActionHelper finish function and ActionMessage::setCompletionReply now expects explicit
information whether to report a success or failure message instead of deriving it implicitely
from returnvalue
### PUS Parameter Service 20
Added PUS parameter service 20 (only custom subservices available).

View File

@ -1,351 +0,0 @@
cmake_minimum_required(VERSION 3.13)
set(FSFW_VERSION 2)
set(FSFW_SUBVERSION 0)
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})
option(FSFW_GENERATE_SECTIONS
"Generate function and data sections. Required to remove unused code" ON
)
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_DOCS "Build documentation with Sphinx and Doxygen" OFF)
if(FSFW_BUILD_UNITTESTS)
option(FSFW_TESTS_GEN_COV "Generate coverage data for unittests" ON)
endif()
option(FSFW_WARNING_SHADOW_LOCAL_GCC "Enable -Wshadow=local warning in GCC" ON)
# Options to exclude parts of the FSFW from compilation.
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)
# Optional sources
option(FSFW_ADD_PUS "Compile with PUS sources" ON)
option(FSFW_ADD_MONITORING "Compile with monitoring components" ON)
option(FSFW_ADD_RMAP "Compile with RMAP" OFF)
option(FSFW_ADD_DATALINKLAYER "Compile with Data Link Layer" OFF)
option(FSFW_ADD_COORDINATES "Compile with coordinate components" OFF)
option(FSFW_ADD_TMSTORAGE "Compile with tm storage components" OFF)
# Contrib sources
option(FSFW_ADD_SGP4_PROPAGATOR "Add SGP4 propagator code" OFF)
set(LIB_FSFW_NAME fsfw)
set(FSFW_TEST_TGT fsfw-tests)
set(FSFW_DUMMY_TGT fsfw-dummy)
project(${LIB_FSFW_NAME})
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)
# Not installed, so use FetchContent to download and provide Catch2
if(NOT Catch2_FOUND)
include(FetchContent)
FetchContent_Declare(
Catch2
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
GIT_TAG v3.0.0-preview3
)
FetchContent_MakeAvailable(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)
project(${FSFW_TEST_TGT} CXX C)
add_executable(${FSFW_TEST_TGT})
if(FSFW_TESTS_GEN_COV)
message(STATUS "Generating coverage data for the library")
message(STATUS "Targets linking against ${LIB_FSFW_NAME} "
"will be compiled with coverage data as well"
)
include(FetchContent)
FetchContent_Declare(
cmake-modules
GIT_REPOSITORY https://github.com/bilke/cmake-modules.git
)
FetchContent_MakeAvailable(cmake-modules)
set(CMAKE_BUILD_TYPE "Debug")
list(APPEND CMAKE_MODULE_PATH ${cmake-modules_SOURCE_DIR})
include(CodeCoverage)
endif()
endif()
set(FSFW_CORE_INC_PATH "inc")
set_property(CACHE FSFW_OSAL PROPERTY STRINGS host linux rtems freertos)
# Configure Files
target_include_directories(${LIB_FSFW_NAME} PRIVATE
${CMAKE_CURRENT_BINARY_DIR}
)
target_include_directories(${LIB_FSFW_NAME} INTERFACE
${CMAKE_CURRENT_BINARY_DIR}
)
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
elseif(${CMAKE_CXX_STANDARD} LESS 11)
message(FATAL_ERROR "Compiling the FSFW requires a minimum of C++11 support")
endif()
# Backwards comptability
if(OS_FSFW AND NOT FSFW_OSAL)
message(WARNING "Please pass the FSFW OSAL as FSFW_OSAL instead of OS_FSFW")
set(FSFW_OSAL OS_FSFW)
endif()
if(NOT FSFW_OSAL)
message(STATUS "No OS for FSFW via FSFW_OSAL set. Assuming host OS")
# Assume host OS and autodetermine from OS_FSFW
if(UNIX)
set(FSFW_OSAL "linux"
CACHE STRING
"OS abstraction layer used in the FSFW"
)
elseif(WIN32)
set(FSFW_OSAL "host"
CACHE STRING "OS abstraction layer used in the FSFW"
)
endif()
endif()
set(FSFW_OSAL_DEFINITION FSFW_OSAL_HOST)
if(FSFW_OSAL MATCHES host)
set(FSFW_OS_NAME "Host")
set(FSFW_OSAL_HOST ON)
elseif(FSFW_OSAL MATCHES linux)
set(FSFW_OS_NAME "Linux")
set(FSFW_OSAL_LINUX ON)
elseif(FSFW_OSAL MATCHES freertos)
set(FSFW_OS_NAME "FreeRTOS")
set(FSFW_OSAL_FREERTOS ON)
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
${LIB_OS_NAME}
)
elseif(FSFW_OSAL STREQUAL rtems)
set(FSFW_OS_NAME "RTEMS")
set(FSFW_OSAL_RTEMS ON)
else()
message(WARNING
"Invalid operating system for FSFW specified! Setting to host.."
)
set(FSFW_OS_NAME "Host")
set(OS_FSFW "host")
endif()
if(FSFW_BUILD_UNITTESTS OR FSFW_BUILD_DOCS)
configure_file(src/fsfw/FSFW.h.in fsfw/FSFW.h)
configure_file(src/fsfw/FSFWVersion.h.in fsfw/FSFWVersion.h)
else()
configure_file(src/fsfw/FSFW.h.in FSFW.h)
configure_file(src/fsfw/FSFWVersion.h.in FSFWVersion.h)
endif()
message(STATUS "Compiling FSFW for the ${FSFW_OS_NAME} operating system.")
add_subdirectory(src)
add_subdirectory(tests)
if(FSFW_ADD_HAL)
add_subdirectory(hal)
endif()
add_subdirectory(contrib)
if(FSFW_BUILD_DOCS)
add_subdirectory(docs)
endif()
if(FSFW_BUILD_UNITTESTS)
if(FSFW_TESTS_GEN_COV)
if(CMAKE_COMPILER_IS_GNUCXX)
include(CodeCoverage)
# Remove quotes.
separate_arguments(COVERAGE_COMPILER_FLAGS
NATIVE_COMMAND "${COVERAGE_COMPILER_FLAGS}"
)
# Add compile options manually, we don't want coverage for Catch2
target_compile_options(${FSFW_TEST_TGT} PRIVATE
"${COVERAGE_COMPILER_FLAGS}"
)
target_compile_options(${LIB_FSFW_NAME} PRIVATE
"${COVERAGE_COMPILER_FLAGS}"
)
# Exclude directories here
if(WIN32)
set(GCOVR_ADDITIONAL_ARGS
"--exclude-throw-branches"
"--exclude-unreachable-branches"
)
set(COVERAGE_EXCLUDES
"/c/msys64/mingw64/*"
)
elseif(UNIX)
set(COVERAGE_EXCLUDES
"/usr/include/*" "/usr/bin/*" "Catch2/*"
"/usr/local/include/*" "*/fsfw_tests/*"
"*/catch2-src/*"
)
endif()
target_link_options(${FSFW_TEST_TGT} PRIVATE
-fprofile-arcs
-ftest-coverage
)
target_link_options(${LIB_FSFW_NAME} PRIVATE
-fprofile-arcs
-ftest-coverage
)
# Need to specify this as an interface, otherwise there will the compile issues
target_link_options(${LIB_FSFW_NAME} INTERFACE
-fprofile-arcs
-ftest-coverage
)
if(WIN32)
setup_target_for_coverage_gcovr_html(
NAME ${FSFW_TEST_TGT}_coverage
EXECUTABLE ${FSFW_TEST_TGT}
DEPENDENCIES ${FSFW_TEST_TGT}
)
else()
setup_target_for_coverage_lcov(
NAME ${FSFW_TEST_TGT}_coverage
EXECUTABLE ${FSFW_TEST_TGT}
DEPENDENCIES ${FSFW_TEST_TGT}
)
endif()
endif()
endif()
target_link_libraries(${FSFW_TEST_TGT} PRIVATE Catch2::Catch2 ${LIB_FSFW_NAME})
endif()
# The project CMakeLists file has to set the FSFW_CONFIG_PATH and add it.
# If this is not given, we include the default configuration and emit a warning.
if(NOT FSFW_CONFIG_PATH)
set(DEF_CONF_PATH misc/defaultcfg/fsfwconfig)
if(NOT FSFW_BUILD_DOCS)
message(WARNING "Flight Software Framework configuration path not set!")
message(WARNING "Setting default configuration from ${DEF_CONF_PATH} ..")
endif()
add_subdirectory(${DEF_CONF_PATH})
set(FSFW_CONFIG_PATH ${DEF_CONF_PATH})
endif()
# FSFW might be part of a possibly complicated folder structure, so we
# extract the absolute path of the fsfwconfig folder.
if(IS_ABSOLUTE ${FSFW_CONFIG_PATH})
set(FSFW_CONFIG_PATH_ABSOLUTE ${FSFW_CONFIG_PATH})
else()
get_filename_component(FSFW_CONFIG_PATH_ABSOLUTE
${FSFW_CONFIG_PATH} REALPATH BASE_DIR ${CMAKE_SOURCE_DIR}
)
endif()
foreach(INCLUDE_PATH ${FSFW_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_ADD_INC_PATHS_ABS ${CURR_ABS_INC_PATH})
endforeach()
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
if(NOT DEFINED FSFW_WARNING_FLAGS)
set(FSFW_WARNING_FLAGS
-Wall
-Wextra
-Wimplicit-fallthrough=1
-Wno-unused-parameter
-Wno-psabi
)
endif()
if(FSFW_GENERATE_SECTIONS)
target_compile_options(${LIB_FSFW_NAME} PRIVATE
"-ffunction-sections"
"-fdata-sections"
)
endif()
if(FSFW_REMOVE_UNUSED_CODE)
target_link_options(${LIB_FSFW_NAME} PRIVATE
"Wl,--gc-sections"
)
endif()
if(FSFW_WARNING_SHADOW_LOCAL_GCC)
list(APPEND WARNING_FLAGS "-Wshadow=local")
endif()
endif()
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
set(COMPILER_FLAGS "/permissive-")
endif()
# Required include paths to compile the FSFW
target_include_directories(${LIB_FSFW_NAME} INTERFACE
${CMAKE_SOURCE_DIR}
${FSFW_CONFIG_PATH_ABSOLUTE}
${FSFW_CORE_INC_PATH}
${FSFW_ADD_INC_PATHS_ABS}
)
# Includes path required to compile FSFW itself as well
# We assume that the fsfwconfig folder uses include relative to the project
# root here!
target_include_directories(${LIB_FSFW_NAME} PRIVATE
${CMAKE_SOURCE_DIR}
${FSFW_CONFIG_PATH_ABSOLUTE}
${FSFW_CORE_INC_PATH}
${FSFW_ADD_INC_PATHS_ABS}
)
target_compile_options(${LIB_FSFW_NAME} PRIVATE
${FSFW_WARNING_FLAGS}
${COMPILER_FLAGS}
)
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
${FSFW_ADDITIONAL_LINK_LIBS}
)
string(CONCAT POST_BUILD_COMMENT
"######################################################################\n"
"Built FSFW v${FSFW_VERSION}.${FSFW_SUBVERSION}.${FSFW_REVISION}, "
"Target OSAL: ${FSFW_OS_NAME}\n"
"######################################################################\n"
)
add_custom_command(
TARGET ${LIB_FSFW_NAME}
POST_BUILD
COMMENT ${POST_BUILD_COMMENT}
)

12
FSFWVersion.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef FSFW_DEFAULTCFG_VERSION_H_
#define FSFW_DEFAULTCFG_VERSION_H_
const char* const FSFW_VERSION_NAME = "ASTP";
#define FSFW_VERSION 0
#define FSFW_SUBVERSION 0
#define FSFW_REVISION 1
#endif /* FSFW_DEFAULTCFG_VERSION_H_ */

213
README.md
View File

@ -1,5 +1,4 @@
![FSFW Logo](misc/logo/FSFW_Logo_V3_bw.png)
![FSFW Logo](logo/FSFW_Logo_V3_bw.png)
# Flight Software Framework (FSFW)
The Flight Software Framework is a C++ Object Oriented Framework for unmanned,
@ -9,120 +8,152 @@ The initial version of the Flight Software Framework was developed during
the Flying Laptop Project by the University of Stuttgart in cooperation
with Airbus Defence and Space GmbH.
## Quick facts
## Intended Use
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 recommended hardware is a microprocessor with more than 2 MB of RAM and 1 MB of non-volatile Memory.
For reference, current Applications use a Cobham Gaisler UT699 (LEON3FT), a ISISPACE IOBC or a Zynq-7020 SoC.
Currently, the FSFW provides the following OSALs:
- Linux
- Host
- FreeRTOS
- RTEMS
## Structure
The recommended hardware is a microprocessor with more than 1 MB of RAM and 1 MB of non-volatile
memory. For reference, current applications use a Cobham Gaisler UT699 (LEON3FT), a
ISISPACE IOBC or a Zynq-7020 SoC. The `fsfw` was also successfully run on the
STM32H743ZI-Nucleo board and on a Raspberry Pi and is currently running on the active
satellite mission Flying Laptop.
The general structure is driven by the usage of interfaces provided by objects. The FSFW uses C++11 as baseline. The intention behind this is that this C++ Standard should be widely available, even with older compilers.
The FSFW uses dynamic allocation during the initialization but provides static containers during runtime.
This simplifies the instantiation of objects and allows the usage of some standard containers.
Dynamic Allocation after initialization is discouraged and different solutions are provided in the FSFW to achieve that.
The fsfw uses Run-time type information.
Exceptions are not allowed.
## Getting started
### Failure Handling
The [Hosted FSFW example](https://egit.irs.uni-stuttgart.de/fsfw/fsfw-example-hosted) provides a
good starting point and a demo to see the FSFW capabilities.
It is recommended to get started by building and playing around with the demo application.
There are also other examples provided for all OSALs using the popular embedded platforms
Raspberry Pi, Beagle Bone Black and STM32H7.
Functions should return a defined ReturnValue_t to signal to the caller that something is gone wrong.
Returnvalues must be unique. For this the function HasReturnvaluesIF::makeReturnCode or the Macro MAKE_RETURN can be used.
The CLASS_ID is a unique id for that type of object. See returnvalues/FwClassIds.
Generally, the FSFW is included in a project by providing
a configuration folder, building the static library and linking against it.
There are some functions like `printChar` which are different depending on the target architecture
and need to be implemented by the mission developer.
### OSAL
The FSFW provides operation system abstraction layers for Linux, FreeRTOS and RTEMS. A independent OSAL called "host" is currently not finished. This aims to be running on windows as well.
The OSAL provides periodic tasks, message queues, clocks and Semaphores as well as Mutexes.
A template configuration folder was provided and can be copied into the project root to have
a starting point. The [configuration section](docs/README-config.md#top) provides more specific
information about the possible options.
### Core Components
## Adding the library
Clock:
* This is a class of static functions that can be used at anytime
* Leap Seconds must be set if any time conversions from UTC to other times is used
The following steps show how to add and use FSFW components. It is still recommended to
try out the example mentioned above to get started, but the following steps show how to
add and link against the FSFW library in general.
ObjectManager (must be created):
1. Add this repository as a submodule
* The component which handles all references. All SystemObjects register at this component.
* Any SystemObject needs to have a unique ObjectId. Those can be managed like objects::framework_objects.
* A reference to an object can be get by calling the following function. T must be the specific Interface you want to call.
A nullptr check of the returning Pointer must be done. This function is based on Run-time type information.
```sh
git submodule add https://egit.irs.uni-stuttgart.de/fsfw/fsfw.git fsfw
```
``` c++
template <typename T> T* ObjectManagerIF::get( object_id_t id )
2. Add the following directive inside the uppermost `CMakeLists.txt` file of your project
```
* A typical way to create all objects on startup is a handing a static produce function to the ObjectManager on creation.
By calling objectManager->initialize() the produce function will be called and all SystemObjects will be initialized afterwards.
```cmake
add_subdirectory(fsfw)
```
Event Manager:
3. Make sure to provide a configuration folder and supply the path to that folder with
the `FSFW_CONFIG_PATH` CMake variable from the uppermost `CMakeLists.txt` file.
It is also necessary to provide the `printChar` function. You can find an example
implementation for a hosted build
[here](https://egit.irs.uni-stuttgart.de/fsfw/fsfw-example-hosted/src/branch/master/bsp_hosted/utility/printChar.c).
* Component which allows routing of events
* Other objects can subscribe to specific events, ranges of events or all events of an object.
* Subscriptions can be done during runtime but should be done during initialization
* Amounts of allowed subscriptions must be configured by setting this parameters:
4. Link against the FSFW library
```cmake
target_link_libraries(<YourProjectName> PRIVATE fsfw)
```
5. It should now be possible use the FSFW as a static library from the user code.
## Building the unittests
The FSFW also has unittests which use the [Catch2 library](https://github.com/catchorg/Catch2).
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.
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`.
You can use the following commands inside the `fsfw` folder to set up the build system
```sh
mkdir build-Unittest && cd build-Unittest
cmake -DFSFW_BUILD_UNITTESTS=ON -DFSFW_OSAL=host ..
``` c++
namespace fsfwconfig {
//! Configure the allocated pool sizes for the event manager.
static constexpr size_t FSFW_EVENTMGMR_MATCHTREE_NODES = 240;
static constexpr size_t FSFW_EVENTMGMT_EVENTIDMATCHERS = 120;
static constexpr size_t FSFW_EVENTMGMR_RANGEMATCHERS = 120;
}
```
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,
the following command can be used inside the build directory after the build system was set up
Health Table:
```sh
cmake --build . -- fsfw-tests_coverage -j
```
* A component which holds every health state
* Provides a thread safe way to access all health states without the need of message exchanges
The `coverage.py` script located in the `script` folder can also be used to do this conveniently.
Stores
## Formatting the sources
* The message based communication can only exchange a few bytes of information inside the message itself. Therefore, additional information can be exchanged with Stores. With this, only the store address must be exchanged in the message.
* Internally, the FSFW uses an IPC Store to exchange data between processes. For incoming TCs a TC Store is used. For outgoing TM a TM store is used.
* All of them should use the Thread Safe Class storagemanager/PoolManager
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.
Tasks
## Index
[1. High-level overview](docs/README-highlevel.md#top) <br>
[2. Core components](docs/README-core.md#top) <br>
[3. Configuration](docs/README-config.md#top) <br>
[4. OSAL overview](docs/README-osal.md#top) <br>
[5. PUS services](docs/README-pus.md#top) <br>
[6. Device Handler overview](docs/README-devicehandlers.md#top) <br>
[7. Controller overview](docs/README-controllers.md#top) <br>
[8. Local Data Pools](docs/README-localpools.md#top) <br>
There are two different types of tasks:
* The PeriodicTask just executes objects that are of type ExecutableObjectIF in the order of the insertion to the Tasks.
* FixedTimeslotTask executes a list of calls in the order of the given list. This is intended for DeviceHandlers, where polling should be in a defined order. An example can be found in defaultcfg/fsfwconfig/pollingSequence
### Static Ids in the framework
Some parts of the framework use a static routing address for communication.
An example setup of ids can be found in the example config in "defaultcft/fsfwconfig/objects/Factory::setStaticFrameworkObjectIds()".
### Events
Events are tied to objects. EventIds can be generated by calling the Macro MAKE_EVENT. This works analog to the returnvalues.
Every object that needs own EventIds has to get a unique SUBSYSTEM_ID.
Every SystemObject can call triggerEvent from the parent class.
Therefore, event messages contain the specific EventId and the objectId of the object that has triggered.
### Internal Communication
Components communicate mostly over Message through Queues.
Those queues are created by calling the singleton QueueFactory::instance()->create().
### External Communication
The external communication with the mission control system is mostly up to the user implementation.
The FSFW provides PUS Services which can be used to but don't need to be used.
The services can be seen as a conversion from a TC to a message based communication and back.
#### CCSDS Frames, CCSDS Space Packets and PUS
If the communication is based on CCSDS Frames and Space Packets, several classes can be used to distributed the packets to the corresponding services. Those can be found in tcdistribution.
If Space Packets are used, a timestamper must be created.
An example can be found in the timemanager folder, this uses CCSDSTime::CDS_short.
#### DeviceHandling
DeviceHandlers are a core component of the FSFW.
The idea is, to have a software counterpart of every physical device to provide a simple mode, health and commanding interface.
By separating the underlying Communication Interface with DeviceCommunicationIF, a DH can be tested on different hardware.
The DH has mechanisms to monitor the communication with the physical device which allow for FDIR reaction.
A standard FDIR component for the DH will be created automatically but can be overwritten by the user.
#### Modes, Health
The two interfaces HasModesIF and HasHealthIF provide access for commanding and monitoring of components.
On-board Mode Management is implement in hierarchy system.
DeviceHandlers and Controllers are the lowest part of the hierarchy.
The next layer are Assemblies. Those assemblies act as a component which handle redundancies of handlers.
Assemblies share a common core with the next level which are the Subsystems.
Those Assemblies are intended to act as auto-generated components from a database which describes the subsystem modes.
The definitions contain transition and target tables which contain the DH, Assembly and Controller Modes to be commanded.
Transition tables contain as many steps as needed to reach the mode from any other mode, e.g. a switch into any higher AOCS mode might first turn on the sensors, than the actuators and the controller as last component.
The target table is used to describe the state that is checked continuously by the subsystem.
All of this allows System Modes to be generated as Subsystem object as well from the same database.
This System contains list of subsystem modes in the transition and target tables.
Therefore, it allows a modular system to create system modes and easy commanding of those, because only the highest components must be commanded.
The health state represents if the component is able to perform its tasks.
This can be used to signal the system to avoid using this component instead of a redundant one.
The on-board FDIR uses the health state for isolation and recovery.
## Example config
A example config can be found in defaultcfg/fsfwconfig.
## Unit Tests
Unit Tests are provided in the unittest folder. Those use the catch2 framework but do not include catch2 itself.
See README.md in the unittest Folder.

162
action/ActionHelper.cpp Normal file
View File

@ -0,0 +1,162 @@
#include "ActionHelper.h"
#include "HasActionsIF.h"
#include "../ipc/MessageQueueSenderIF.h"
#include "../objectmanager/ObjectManagerIF.h"
ActionHelper::ActionHelper(HasActionsIF* setOwner,
MessageQueueIF* useThisQueue) :
owner(setOwner), queueToUse(useThisQueue) {
}
ActionHelper::~ActionHelper() {
}
ReturnValue_t ActionHelper::handleActionMessage(CommandMessage* command) {
if (command->getCommand() == ActionMessage::EXECUTE_ACTION) {
ActionId_t currentAction = ActionMessage::getActionId(command);
prepareExecution(command->getSender(), currentAction,
ActionMessage::getStoreId(command));
return HasReturnvaluesIF::RETURN_OK;
} else {
return CommandMessage::UNKNOWN_COMMAND;
}
}
ReturnValue_t ActionHelper::initialize(MessageQueueIF* queueToUse_) {
ipcStore = objectManager->get<StorageManagerIF>(objects::IPC_STORE);
if (ipcStore == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
if(queueToUse_ != nullptr) {
setQueueToUse(queueToUse_);
}
return HasReturnvaluesIF::RETURN_OK;
}
void ActionHelper::step(uint8_t step, MessageQueueId_t reportTo,
ActionId_t commandId, ReturnValue_t result) {
CommandMessage reply;
ActionMessage::setStepReply(&reply, commandId, step + STEP_OFFSET, result);
queueToUse->sendMessage(reportTo, &reply);
}
void ActionHelper::finish(MessageQueueId_t reportTo, ActionId_t commandId,
ReturnValue_t result) {
CommandMessage reply;
ActionMessage::setCompletionReply(&reply, commandId, result);
queueToUse->sendMessage(reportTo, &reply);
}
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;
size_t size = 0;
ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size);
if (result != HasReturnvaluesIF::RETURN_OK) {
CommandMessage reply;
ActionMessage::setStepReply(&reply, actionId, 0, result);
queueToUse->sendMessage(commandedBy, &reply);
return;
}
result = owner->executeAction(actionId, commandedBy, dataPtr, size);
ipcStore->deleteData(dataAddress);
if(result == HasActionsIF::EXECUTION_FINISHED) {
CommandMessage reply;
ActionMessage::setCompletionReply(&reply, actionId, result);
queueToUse->sendMessage(commandedBy, &reply);
}
if (result != HasReturnvaluesIF::RETURN_OK) {
CommandMessage reply;
ActionMessage::setStepReply(&reply, actionId, 0, result);
queueToUse->sendMessage(commandedBy, &reply);
return;
}
}
ReturnValue_t ActionHelper::reportData(MessageQueueId_t reportTo,
ActionId_t replyId, SerializeIF* data, bool hideSender) {
CommandMessage reply;
store_address_t storeAddress;
uint8_t *dataPtr;
size_t maxSize = data->getSerializedSize();
if (maxSize == 0) {
//No error, there's simply nothing to report.
return HasReturnvaluesIF::RETURN_OK;
}
size_t size = 0;
ReturnValue_t result = ipcStore->getFreeElement(&storeAddress, maxSize,
&dataPtr);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
result = data->serialize(&dataPtr, &size, maxSize,
SerializeIF::Endianness::BIG);
if (result != HasReturnvaluesIF::RETURN_OK) {
ipcStore->deleteData(storeAddress);
return result;
}
// We don't need to report the objectId, as we receive REQUESTED data
// before the completion success message.
// True aperiodic replies need to be reported with
// another dedicated message.
ActionMessage::setDataReply(&reply, replyId, storeAddress);
// If the sender needs to be hidden, for example to handle packet
// as unrequested reply, this will be done here.
if (hideSender) {
result = MessageQueueSenderIF::sendMessage(reportTo, &reply);
}
else {
result = queueToUse->sendMessage(reportTo, &reply);
}
if (result != HasReturnvaluesIF::RETURN_OK){
ipcStore->deleteData(storeAddress);
}
return result;
}
void ActionHelper::resetHelper() {
}
ReturnValue_t ActionHelper::reportData(MessageQueueId_t reportTo,
ActionId_t replyId, const uint8_t *data, size_t dataSize,
bool hideSender) {
CommandMessage reply;
store_address_t storeAddress;
ReturnValue_t result = ipcStore->addData(&storeAddress, data, dataSize);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
if (result != HasReturnvaluesIF::RETURN_OK) {
ipcStore->deleteData(storeAddress);
return result;
}
// We don't need to report the objectId, as we receive REQUESTED data
// before the completion success message.
// True aperiodic replies need to be reported with
// another dedicated message.
ActionMessage::setDataReply(&reply, replyId, storeAddress);
// If the sender needs to be hidden, for example to handle packet
// as unrequested reply, this will be done here.
if (hideSender) {
result = MessageQueueSenderIF::sendMessage(reportTo, &reply);
}
else {
result = queueToUse->sendMessage(reportTo, &reply);
}
if (result != HasReturnvaluesIF::RETURN_OK){
ipcStore->deleteData(storeAddress);
}
return result;
}

125
action/ActionHelper.h Normal file
View File

@ -0,0 +1,125 @@
#ifndef FSFW_ACTION_ACTIONHELPER_H_
#define FSFW_ACTION_ACTIONHELPER_H_
#include "ActionMessage.h"
#include "../serialize/SerializeIF.h"
#include "../ipc/MessageQueueIF.h"
/**
* @brief Action Helper is a helper class which handles action messages
*
* Components which use the HasActionIF this helper can be used to handle
* the action messages.
* It does handle step messages as well as other answers to action calls.
* It uses the executeAction function of its owner as callback.
* The call of the initialize function is mandatory and needs a
* valid MessageQueueIF pointer!
*/
class HasActionsIF;
class ActionHelper {
public:
/**
* Constructor of the action helper
* @param setOwner Pointer to the owner of the interface
* @param useThisQueue messageQueue to be used, can be set during
* initialize function as well.
*/
ActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue);
virtual ~ActionHelper();
/**
* Function to be called from the owner with a new command message
*
* If the message is a valid action message the helper will use the
* executeAction function from HasActionsIF.
* If the message is invalid or the callback fails a message reply will be
* send to the sender of the message automatically.
*
* @param command Pointer to a command message received by the owner
* @return HasReturnvaluesIF::RETURN_OK if the message is a action message,
* CommandMessage::UNKNOW_COMMAND if this message ID is unkown
*/
ReturnValue_t handleActionMessage(CommandMessage* command);
/**
* Helper initialize function. Must be called before use of any other
* helper function
* @param queueToUse_ Pointer to the messageQueue to be used, optional
* if queue was set in constructor
* @return Returns RETURN_OK if successful
*/
ReturnValue_t initialize(MessageQueueIF* queueToUse_ = nullptr);
/**
* Function to be called from the owner to send a step message.
* Success or failure will be determined by the result value.
*
* @param step Number of steps already done
* @param reportTo The messageQueueId to report the step message to
* @param commandId ID of the executed command
* @param result Result of the execution
*/
void step(uint8_t step, MessageQueueId_t reportTo,
ActionId_t commandId,
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK);
/**
* Function to be called by the owner to send a action completion message
*
* @param reportTo MessageQueueId_t to report the action completion message to
* @param commandId ID of the executed command
* @param result Result of the execution
*/
void finish(MessageQueueId_t reportTo, ActionId_t commandId,
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK);
/**
* Function to be called by the owner if an action does report data.
* Takes a SerializeIF* pointer and serializes it into the IPC store.
* @param reportTo MessageQueueId_t to report the action completion
* message to
* @param replyId ID of the executed command
* @param data Pointer to the data
* @return Returns RETURN_OK if successful, otherwise failure code
*/
ReturnValue_t reportData(MessageQueueId_t reportTo, ActionId_t replyId,
SerializeIF* data, bool hideSender = false);
/**
* Function to be called by the owner if an action does report data.
* Takes the raw data and writes it into the IPC store.
* @param reportTo MessageQueueId_t to report the action completion
* message to
* @param replyId ID of the executed command
* @param data Pointer to the data
* @return Returns RETURN_OK if successful, otherwise failure code
*/
ReturnValue_t reportData(MessageQueueId_t reportTo, ActionId_t replyId,
const uint8_t* data, size_t dataSize, bool hideSender = false);
/**
* Function to setup the MessageQueueIF* of the helper. Can be used to
* set the MessageQueueIF* if message queue is unavailable at construction
* and initialize but must be setup before first call of other functions.
* @param queue Queue to be used by the helper
*/
void setQueueToUse(MessageQueueIF *queue);
protected:
//!< Increase of value of this per step
static const uint8_t STEP_OFFSET = 1;
HasActionsIF* owner;//!< Pointer to the owner
//! Queue to be used as response sender, has to be set in ctor or with
//! setQueueToUse
MessageQueueIF* queueToUse;
//! Pointer to an IPC Store, initialized during construction or
StorageManagerIF* ipcStore = nullptr;
/**
* Internal function called by handleActionMessage
* @param commandedBy MessageQueueID of Commander
* @param actionId ID of action to be done
* @param dataAddress Address of additional data in IPC Store
*/
virtual void prepareExecution(MessageQueueId_t commandedBy,
ActionId_t actionId, store_address_t dataAddress);
/**
* @brief Default implementation is empty.
*/
virtual void resetHelper();
};
#endif /* FSFW_ACTION_ACTIONHELPER_H_ */

79
action/ActionMessage.cpp Normal file
View File

@ -0,0 +1,79 @@
#include "ActionMessage.h"
#include "../objectmanager/ObjectManagerIF.h"
#include "../storagemanager/StorageManagerIF.h"
ActionMessage::ActionMessage() {
}
ActionMessage::~ActionMessage() {
}
void ActionMessage::setCommand(CommandMessage* message, ActionId_t fid,
store_address_t parameters) {
message->setCommand(EXECUTE_ACTION);
message->setParameter(fid);
message->setParameter2(parameters.raw);
}
ActionId_t ActionMessage::getActionId(const CommandMessage* message) {
return ActionId_t(message->getParameter());
}
store_address_t ActionMessage::getStoreId(const CommandMessage* message) {
store_address_t temp;
temp.raw = message->getParameter2();
return temp;
}
void ActionMessage::setStepReply(CommandMessage* message, ActionId_t fid, uint8_t step,
ReturnValue_t result) {
if (result == HasReturnvaluesIF::RETURN_OK) {
message->setCommand(STEP_SUCCESS);
} else {
message->setCommand(STEP_FAILED);
}
message->setParameter(fid);
message->setParameter2((step << 16) + result);
}
uint8_t ActionMessage::getStep(const CommandMessage* message) {
return uint8_t((message->getParameter2() >> 16) & 0xFF);
}
ReturnValue_t ActionMessage::getReturnCode(const CommandMessage* message) {
return message->getParameter2() & 0xFFFF;
}
void ActionMessage::setDataReply(CommandMessage* message, ActionId_t actionId,
store_address_t data) {
message->setCommand(DATA_REPLY);
message->setParameter(actionId);
message->setParameter2(data.raw);
}
void ActionMessage::setCompletionReply(CommandMessage* message,
ActionId_t fid, ReturnValue_t result) {
if (result == HasReturnvaluesIF::RETURN_OK) {
message->setCommand(COMPLETION_SUCCESS);
} else {
message->setCommand(COMPLETION_FAILED);
}
message->setParameter(fid);
message->setParameter2(result);
}
void ActionMessage::clear(CommandMessage* message) {
switch(message->getCommand()) {
case EXECUTE_ACTION:
case DATA_REPLY: {
StorageManagerIF *ipcStore = objectManager->get<StorageManagerIF>(
objects::IPC_STORE);
if (ipcStore != NULL) {
ipcStore->deleteData(getStoreId(message));
}
break;
}
default:
break;
}
}

36
action/ActionMessage.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef FSFW_ACTION_ACTIONMESSAGE_H_
#define FSFW_ACTION_ACTIONMESSAGE_H_
#include "../ipc/CommandMessage.h"
#include "../objectmanager/ObjectManagerIF.h"
#include "../storagemanager/StorageManagerIF.h"
typedef uint32_t ActionId_t;
class ActionMessage {
private:
ActionMessage();
public:
static const uint8_t MESSAGE_ID = messagetypes::ACTION;
static const Command_t EXECUTE_ACTION = MAKE_COMMAND_ID(1);
static const Command_t STEP_SUCCESS = MAKE_COMMAND_ID(2);
static const Command_t STEP_FAILED = MAKE_COMMAND_ID(3);
static const Command_t DATA_REPLY = MAKE_COMMAND_ID(4);
static const Command_t COMPLETION_SUCCESS = MAKE_COMMAND_ID(5);
static const Command_t COMPLETION_FAILED = MAKE_COMMAND_ID(6);
virtual ~ActionMessage();
static void setCommand(CommandMessage* message, ActionId_t fid,
store_address_t parameters);
static ActionId_t getActionId(const CommandMessage* message );
static store_address_t getStoreId(const CommandMessage* message );
static void setStepReply(CommandMessage* message, ActionId_t fid,
uint8_t step, ReturnValue_t result = HasReturnvaluesIF::RETURN_OK);
static uint8_t getStep(const CommandMessage* message );
static ReturnValue_t getReturnCode(const CommandMessage* message );
static void setDataReply(CommandMessage* message, ActionId_t actionId,
store_address_t data);
static void setCompletionReply(CommandMessage* message, ActionId_t fid,
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK);
static void clear(CommandMessage* message);
};
#endif /* FSFW_ACTION_ACTIONMESSAGE_H_ */

View File

@ -0,0 +1,127 @@
#include "ActionMessage.h"
#include "CommandActionHelper.h"
#include "CommandsActionsIF.h"
#include "HasActionsIF.h"
#include "../objectmanager/ObjectManagerIF.h"
CommandActionHelper::CommandActionHelper(CommandsActionsIF *setOwner) :
owner(setOwner), queueToUse(NULL), ipcStore(
NULL), commandCount(0), lastTarget(0) {
}
CommandActionHelper::~CommandActionHelper() {
}
ReturnValue_t CommandActionHelper::commandAction(object_id_t commandTo,
ActionId_t actionId, SerializeIF *data) {
HasActionsIF *receiver = objectManager->get<HasActionsIF>(commandTo);
if (receiver == NULL) {
return CommandsActionsIF::OBJECT_HAS_NO_FUNCTIONS;
}
store_address_t storeId;
uint8_t *storePointer;
size_t maxSize = data->getSerializedSize();
ReturnValue_t result = ipcStore->getFreeElement(&storeId, maxSize,
&storePointer);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
size_t size = 0;
result = data->serialize(&storePointer, &size, maxSize,
SerializeIF::Endianness::BIG);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
return sendCommand(receiver->getCommandQueue(), actionId, storeId);
}
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->get<HasActionsIF>(commandTo);
if (receiver == NULL) {
return CommandsActionsIF::OBJECT_HAS_NO_FUNCTIONS;
}
store_address_t storeId;
ReturnValue_t result = ipcStore->addData(&storeId, data, size);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
return sendCommand(receiver->getCommandQueue(), actionId, storeId);
}
ReturnValue_t CommandActionHelper::sendCommand(MessageQueueId_t queueId,
ActionId_t actionId, store_address_t storeId) {
CommandMessage command;
ActionMessage::setCommand(&command, actionId, storeId);
ReturnValue_t result = queueToUse->sendMessage(queueId, &command);
if (result != HasReturnvaluesIF::RETURN_OK) {
ipcStore->deleteData(storeId);
}
lastTarget = queueId;
commandCount++;
return result;
}
ReturnValue_t CommandActionHelper::initialize() {
ipcStore = objectManager->get<StorageManagerIF>(objects::IPC_STORE);
if (ipcStore == NULL) {
return HasReturnvaluesIF::RETURN_FAILED;
}
queueToUse = owner->getCommandQueuePtr();
if (queueToUse == NULL) {
return HasReturnvaluesIF::RETURN_FAILED;
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t CommandActionHelper::handleReply(CommandMessage *reply) {
if (reply->getSender() != lastTarget) {
return HasReturnvaluesIF::RETURN_FAILED;
}
switch (reply->getCommand()) {
case ActionMessage::COMPLETION_SUCCESS:
commandCount--;
owner->completionSuccessfulReceived(ActionMessage::getActionId(reply));
return HasReturnvaluesIF::RETURN_OK;
case ActionMessage::COMPLETION_FAILED:
commandCount--;
owner->completionFailedReceived(ActionMessage::getActionId(reply),
ActionMessage::getReturnCode(reply));
return HasReturnvaluesIF::RETURN_OK;
case ActionMessage::STEP_SUCCESS:
owner->stepSuccessfulReceived(ActionMessage::getActionId(reply),
ActionMessage::getStep(reply));
return HasReturnvaluesIF::RETURN_OK;
case ActionMessage::STEP_FAILED:
commandCount--;
owner->stepFailedReceived(ActionMessage::getActionId(reply),
ActionMessage::getStep(reply),
ActionMessage::getReturnCode(reply));
return HasReturnvaluesIF::RETURN_OK;
case ActionMessage::DATA_REPLY:
extractDataForOwner(ActionMessage::getActionId(reply),
ActionMessage::getStoreId(reply));
return HasReturnvaluesIF::RETURN_OK;
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
}
uint8_t CommandActionHelper::getCommandCount() const {
return commandCount;
}
void CommandActionHelper::extractDataForOwner(ActionId_t actionId, store_address_t storeId) {
const uint8_t * data = NULL;
size_t size = 0;
ReturnValue_t result = ipcStore->getData(storeId, &data, &size);
if (result != HasReturnvaluesIF::RETURN_OK) {
return;
}
owner->dataReceived(actionId, data, size);
ipcStore->deleteData(storeId);
}

View File

@ -0,0 +1,36 @@
#ifndef COMMANDACTIONHELPER_H_
#define COMMANDACTIONHELPER_H_
#include "ActionMessage.h"
#include "../objectmanager/ObjectManagerIF.h"
#include "../returnvalues/HasReturnvaluesIF.h"
#include "../serialize/SerializeIF.h"
#include "../storagemanager/StorageManagerIF.h"
#include "../ipc/MessageQueueIF.h"
class CommandsActionsIF;
class CommandActionHelper {
friend class CommandsActionsIF;
public:
CommandActionHelper(CommandsActionsIF* owner);
virtual ~CommandActionHelper();
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);
uint8_t getCommandCount() const;
private:
CommandsActionsIF* owner;
MessageQueueIF* queueToUse;
StorageManagerIF* ipcStore;
uint8_t commandCount;
MessageQueueId_t lastTarget;
void extractDataForOwner(ActionId_t actionId, store_address_t storeId);
ReturnValue_t sendCommand(MessageQueueId_t queueId, ActionId_t actionId,
store_address_t storeId);
};
#endif /* COMMANDACTIONHELPER_H_ */

View File

@ -0,0 +1,37 @@
#ifndef FSFW_ACTION_COMMANDSACTIONSIF_H_
#define FSFW_ACTION_COMMANDSACTIONSIF_H_
#include "CommandActionHelper.h"
#include "../returnvalues/HasReturnvaluesIF.h"
#include "../ipc/MessageQueueIF.h"
/**
* Interface to separate commanding actions of other objects.
* In next iteration, IF should be shortened to three calls:
* - dataReceived(data)
* - successReceived(id, step)
* - failureReceived(id, step, cause)
* or even
* - replyReceived(id, step, cause) (if cause == OK, it's a success).
*/
class CommandsActionsIF {
friend class CommandActionHelper;
public:
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 MessageQueueIF* getCommandQueuePtr() = 0;
protected:
virtual void stepSuccessfulReceived(ActionId_t actionId, uint8_t step) = 0;
virtual void stepFailedReceived(ActionId_t actionId, uint8_t step,
ReturnValue_t returnCode) = 0;
virtual void dataReceived(ActionId_t actionId, const uint8_t* data,
uint32_t size) = 0;
virtual void completionSuccessfulReceived(ActionId_t actionId) = 0;
virtual void completionFailedReceived(ActionId_t actionId,
ReturnValue_t returnCode) = 0;
};
#endif /* FSFW_ACTION_COMMANDSACTIONSIF_H_ */

View File

@ -35,28 +35,28 @@
*/
class HasActionsIF {
public:
static const uint8_t INTERFACE_ID = CLASS_ID::HAS_ACTIONS_IF;
static const ReturnValue_t IS_BUSY = MAKE_RETURN_CODE(1);
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() { }
/**
* Function to get the MessageQueueId_t of the implementing object
* @return MessageQueueId_t of the object
*/
virtual MessageQueueId_t getCommandQueue() const = 0;
/**
* Execute or initialize the execution of a certain function.
* The ActionHelpers will execute this function and behave differently
* depending on the returnvalue.
*
* @return
* -@c EXECUTION_FINISHED Finish reply will be generated
* -@c Not RETURN_OK Step failure reply will be generated
*/
virtual ReturnValue_t executeAction(ActionId_t actionId,
MessageQueueId_t commandedBy, const uint8_t* data, size_t size) = 0;
static const uint8_t INTERFACE_ID = CLASS_ID::HAS_ACTIONS_IF;
static const ReturnValue_t IS_BUSY = MAKE_RETURN_CODE(1);
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() { }
/**
* Function to get the MessageQueueId_t of the implementing object
* @return MessageQueueId_t of the object
*/
virtual MessageQueueId_t getCommandQueue() const = 0;
/**
* Execute or initialize the execution of a certain function.
* The ActionHelpers will execute this function and behave differently
* depending on the returnvalue.
*
* @return
* -@c EXECUTION_FINISHED Finish reply will be generated
* -@c Not RETURN_OK Step failure reply will be generated
*/
virtual ReturnValue_t executeAction(ActionId_t actionId,
MessageQueueId_t commandedBy, const uint8_t* data, size_t size) = 0;
};

View File

@ -0,0 +1,75 @@
#include "HasActionsIF.h"
#include "SimpleActionHelper.h"
SimpleActionHelper::SimpleActionHelper(HasActionsIF* setOwner,
MessageQueueIF* useThisQueue) :
ActionHelper(setOwner, useThisQueue), isExecuting(false) {
}
SimpleActionHelper::~SimpleActionHelper() {
}
void SimpleActionHelper::step(ReturnValue_t result) {
// STEP_OFFESET is subtracted to compensate for adding offset in base
// method, which is not necessary here.
ActionHelper::step(stepCount - STEP_OFFSET, lastCommander, lastAction,
result);
if (result != HasReturnvaluesIF::RETURN_OK) {
resetHelper();
}
}
void SimpleActionHelper::finish(ReturnValue_t result) {
ActionHelper::finish(lastCommander, lastAction, result);
resetHelper();
}
ReturnValue_t SimpleActionHelper::reportData(SerializeIF* data) {
return ActionHelper::reportData(lastCommander, lastAction, data);
}
void SimpleActionHelper::resetHelper() {
stepCount = 0;
isExecuting = false;
lastAction = 0;
lastCommander = 0;
}
void SimpleActionHelper::prepareExecution(MessageQueueId_t commandedBy,
ActionId_t actionId, store_address_t dataAddress) {
CommandMessage reply;
if (isExecuting) {
ipcStore->deleteData(dataAddress);
ActionMessage::setStepReply(&reply, actionId, 0,
HasActionsIF::IS_BUSY);
queueToUse->sendMessage(commandedBy, &reply);
}
const uint8_t* dataPtr = NULL;
size_t size = 0;
ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size);
if (result != HasReturnvaluesIF::RETURN_OK) {
ActionMessage::setStepReply(&reply, actionId, 0, result);
queueToUse->sendMessage(commandedBy, &reply);
return;
}
lastCommander = commandedBy;
lastAction = actionId;
result = owner->executeAction(actionId, commandedBy, dataPtr, size);
ipcStore->deleteData(dataAddress);
switch (result) {
case HasReturnvaluesIF::RETURN_OK:
isExecuting = true;
stepCount++;
break;
case HasActionsIF::EXECUTION_FINISHED:
ActionMessage::setCompletionReply(&reply, actionId,
HasReturnvaluesIF::RETURN_OK);
queueToUse->sendMessage(commandedBy, &reply);
break;
default:
ActionMessage::setStepReply(&reply, actionId, 0, result);
queueToUse->sendMessage(commandedBy, &reply);
break;
}
}

View File

@ -0,0 +1,30 @@
#ifndef FSFW_ACTION_SIMPLEACTIONHELPER_H_
#define FSFW_ACTION_SIMPLEACTIONHELPER_H_
#include "ActionHelper.h"
/**
* @brief This is an action helper which is only able to service one action
* at a time but remembers last commander and last action which
* simplifies usage
*/
class SimpleActionHelper: public ActionHelper {
public:
SimpleActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue);
virtual ~SimpleActionHelper();
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();
private:
bool isExecuting;
MessageQueueId_t lastCommander = MessageQueueIF::NO_QUEUE;
ActionId_t lastAction = 0;
uint8_t stepCount = 0;
};
#endif /* SIMPLEACTIONHELPER_H_ */

View File

@ -1,8 +0,0 @@
FROM ubuntu:focal
RUN apt-get update
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

View File

@ -1,72 +0,0 @@
pipeline {
agent any
environment {
BUILDDIR = 'build-unittests'
}
stages {
stage('Create Docker') {
agent {
dockerfile {
dir 'automation'
additionalBuildArgs '--no-cache'
reuseNode true
}
}
steps {
sh 'rm -rf $BUILDDIR'
}
}
stage('Configure') {
agent {
dockerfile {
dir 'automation'
reuseNode true
}
}
steps {
dir(BUILDDIR) {
sh 'cmake -DFSFW_OSAL=host -DFSFW_BUILD_UNITTESTS=ON ..'
}
}
}
stage('Build') {
agent {
dockerfile {
dir 'automation'
reuseNode true
}
}
steps {
dir(BUILDDIR) {
sh 'cmake --build . -j'
}
}
}
stage('Unittests') {
agent {
dockerfile {
dir 'automation'
reuseNode true
}
}
steps {
dir(BUILDDIR) {
sh 'cmake --build . -- fsfw-tests_coverage -j'
}
}
}
stage('Valgrind') {
agent {
dockerfile {
dir 'automation'
reuseNode true
}
}
steps {
dir(BUILDDIR) {
sh 'valgrind --leak-check=full --error-exitcode=1 ./fsfw-tests'
}
}
}
}
}

View File

@ -1,13 +0,0 @@
# Look for an executable called sphinx-build
find_program(SPHINX_EXECUTABLE
NAMES sphinx-build
DOC "Path to sphinx-build executable")
include(FindPackageHandleStandardArgs)
# Handle standard arguments to find_package like REQUIRED and QUIET
find_package_handle_standard_args(
Sphinx
"Failed to find sphinx-build executable"
SPHINX_EXECUTABLE
)

253
container/ArrayList.h Normal file
View File

@ -0,0 +1,253 @@
#ifndef FSFW_CONTAINER_ARRAYLIST_H_
#define FSFW_CONTAINER_ARRAYLIST_H_
#include "../returnvalues/HasReturnvaluesIF.h"
#include "../serialize/SerializeAdapter.h"
#include "../serialize/SerializeIF.h"
/**
* @brief A List that stores its values in an array.
* @details
* The underlying storage is an array that can be allocated by the class
* itself or supplied via ctor.
*
* @ingroup container
*/
template<typename T, typename count_t = uint8_t>
class ArrayList {
template<typename U, typename count> friend class SerialArrayListAdapter;
public:
static const uint8_t INTERFACE_ID = CLASS_ID::ARRAY_LIST;
static const ReturnValue_t FULL = MAKE_RETURN_CODE(0x01);
/**
* This is the allocating constructor.
* It allocates an array of the specified size.
* @param maxSize
*/
ArrayList(count_t maxSize) :
size(0), maxSize_(maxSize), allocated(true) {
entries = new T[maxSize];
}
/**
* This is the non-allocating constructor
*
* It expects a pointer to an array of a certain size and initializes
* itself to it.
*
* @param storage the array to use as backend
* @param maxSize size of storage
* @param size size of data already present in storage
*/
ArrayList(T *storage, count_t maxSize, count_t size = 0) :
size(size), entries(storage), maxSize_(maxSize), allocated(false) {
}
/**
* Copying is forbiden by declaring copy ctor and copy assignment deleted
* It is too ambigous in this case.
* (Allocate a new backend? Use the same? What to do in an modifying call?)
*/
ArrayList(const ArrayList& other) = delete;
const ArrayList& operator=(const ArrayList& other) = delete;
/**
* Number of Elements stored in this List
*/
count_t size;
/**
* Destructor, if the allocating constructor was used, it deletes the array.
*/
virtual ~ArrayList() {
if (allocated) {
delete[] entries;
}
}
/**
* An Iterator to go trough an ArrayList
*
* It stores a pointer to an element and increments the
* pointer when incremented itself.
*/
class Iterator {
public:
/**
* Empty ctor, points to NULL
*/
Iterator(): value(0) {}
/**
* Initializes the Iterator to point to an element
*
* @param initialize
*/
Iterator(T *initialize) {
value = initialize;
}
/**
* The current element the iterator points to
*/
T *value;
Iterator& operator++() {
value++;
return *this;
}
Iterator operator++(int) {
Iterator tmp(*this);
operator++();
return tmp;
}
Iterator& operator--() {
value--;
return *this;
}
Iterator operator--(int) {
Iterator tmp(*this);
operator--();
return tmp;
}
T& operator*() {
return *value;
}
const T& operator*() const {
return *value;
}
T *operator->() {
return value;
}
const T *operator->() const {
return value;
}
};
friend bool operator==(const ArrayList::Iterator& lhs,
const ArrayList::Iterator& rhs) {
return (lhs.value == rhs.value);
}
friend bool operator!=(const ArrayList::Iterator& lhs,
const ArrayList::Iterator& rhs) {
return not (lhs.value == rhs.value);
}
/**
* Iterator pointing to the first stored elmement
*
* @return Iterator to the first element
*/
Iterator begin() const {
return Iterator(&entries[0]);
}
/**
* returns an Iterator pointing to the element after the last stored entry
*
* @return Iterator to the element after the last entry
*/
Iterator end() const {
return Iterator(&entries[size]);
}
T & operator[](count_t i) const {
return entries[i];
}
/**
* The first element
*
* @return pointer to the first stored element
*/
T *front() {
return entries;
}
/**
* The last element
*
* does not return a valid pointer if called on an empty list.
*
* @return pointer to the last stored element
*/
T *back() {
return &entries[size - 1];
//Alternative solution
//return const_cast<T*>(static_cast<const T*>(*this).back());
}
const T* back() const{
return &entries[size-1];
}
/**
* The maximum number of elements this List can contain
*
* @return maximum number of elements
*/
size_t maxSize() const {
return this->maxSize_;
}
/**
* Insert a new element into the list.
*
* The new element is inserted after the last stored element.
*
* @param entry
* @return
* -@c FULL if the List is full
* -@c RETURN_OK else
*/
ReturnValue_t insert(T entry) {
if (size >= maxSize_) {
return FULL;
}
entries[size] = entry;
++size;
return HasReturnvaluesIF::RETURN_OK;
}
/**
* clear the List
*
* This does not actually clear all entries, it only sets the size to 0.
*/
void clear() {
size = 0;
}
count_t remaining() {
return (maxSize_ - size);
}
protected:
/**
* pointer to the array in which the entries are stored
*/
T *entries;
/**
* remembering the maximum size
*/
size_t maxSize_;
/**
* true if the array was allocated and needs to be deleted in the destructor.
*/
bool allocated;
};
#endif /* FSFW_CONTAINER_ARRAYLIST_H_ */

153
container/BinaryTree.h Normal file
View File

@ -0,0 +1,153 @@
#ifndef FRAMEWORK_CONTAINER_BINARYTREE_H_
#define FRAMEWORK_CONTAINER_BINARYTREE_H_
#include <stddef.h>
#include <stdint.h>
#include <map>
template<typename Tp>
class BinaryNode {
public:
BinaryNode(Tp* setValue) :
value(setValue), left(NULL), right(NULL), parent(NULL) {
}
Tp *value;
BinaryNode* left;
BinaryNode* right;
BinaryNode* parent;
};
template<typename Tp>
class ExplicitNodeIterator {
public:
typedef ExplicitNodeIterator<Tp> _Self;
typedef BinaryNode<Tp> _Node;
typedef Tp value_type;
typedef Tp* pointer;
typedef Tp& reference;
ExplicitNodeIterator() :
element(NULL) {
}
ExplicitNodeIterator(_Node* node) :
element(node) {
}
BinaryNode<Tp>* element;
_Self up() {
return _Self(element->parent);
}
_Self left() {
if (element != NULL) {
return _Self(element->left);
} else {
return _Self(NULL);
}
}
_Self right() {
if (element != NULL) {
return _Self(element->right);
} else {
return _Self(NULL);
}
}
bool operator==(const _Self& __x) const {
return element == __x.element;
}
bool operator!=(const _Self& __x) const {
return element != __x.element;
}
pointer
operator->() const {
if (element != NULL) {
return element->value;
} else {
return NULL;
}
}
pointer operator*() const {
return this->operator->();
}
};
/**
* Pretty rudimentary version of a simple binary tree (not a binary search tree!).
*/
template<typename Tp>
class BinaryTree {
public:
typedef ExplicitNodeIterator<Tp> iterator;
typedef BinaryNode<Tp> Node;
typedef std::pair<iterator, iterator> children;
BinaryTree() :
rootNode(NULL) {
}
BinaryTree(Node* rootNode) :
rootNode(rootNode) {
}
iterator begin() const {
return iterator(rootNode);
}
static iterator end() {
return iterator(NULL);
}
iterator insert(bool insertLeft, iterator parentNode, Node* newNode ) {
newNode->parent = parentNode.element;
if (parentNode.element != NULL) {
if (insertLeft) {
parentNode.element->left = newNode;
} else {
parentNode.element->right = newNode;
}
} else {
//Insert first element.
rootNode = newNode;
}
return iterator(newNode);
}
//No recursion to children. Needs to be done externally.
children erase(iterator node) {
if (node.element == rootNode) {
//We're root node
rootNode = NULL;
} else {
//Delete parent's reference
if (node.up().left() == node) {
node.up().element->left = NULL;
} else {
node.up().element->right = NULL;
}
}
return children(node.element->left, node.element->right);
}
static uint32_t countLeft(iterator start) {
if (start == end()) {
return 0;
}
//We also count the start node itself.
uint32_t count = 1;
while (start.left() != end()) {
count++;
start = start.left();
}
return count;
}
static uint32_t countRight(iterator start) {
if (start == end()) {
return 0;
}
//We also count the start node itself.
uint32_t count = 1;
while (start.right() != end()) {
count++;
start = start.right();
}
return count;
}
protected:
Node* rootNode;
};
#endif /* FRAMEWORK_CONTAINER_BINARYTREE_H_ */

55
container/DynamicFIFO.h Normal file
View File

@ -0,0 +1,55 @@
#ifndef FSFW_CONTAINER_DYNAMICFIFO_H_
#define FSFW_CONTAINER_DYNAMICFIFO_H_
#include "FIFOBase.h"
#include <vector>
/**
* @brief Simple First-In-First-Out data structure. The maximum size
* can be set in the constructor.
* @details
* The maximum capacity can be determined at run-time, so this container
* performs dynamic memory allocation!
* The public interface of FIFOBase exposes the user interface for the FIFO.
* @tparam T Entry Type
* @tparam capacity Maximum capacity
*/
template<typename T>
class DynamicFIFO: public FIFOBase<T> {
public:
DynamicFIFO(size_t maxCapacity): FIFOBase<T>(nullptr, maxCapacity),
fifoVector(maxCapacity) {
// trying to pass the pointer of the uninitialized vector
// to the FIFOBase constructor directly lead to a super evil bug.
// So we do it like this now.
this->setContainer(fifoVector.data());
};
/**
* @brief Custom copy constructor which prevents setting the
* underlying pointer wrong. This function allocates memory!
* @details This is a very heavy operation so try to avoid this!
*
*/
DynamicFIFO(const DynamicFIFO& other): FIFOBase<T>(other),
fifoVector(other.maxCapacity) {
this->fifoVector = other.fifoVector;
this->setContainer(fifoVector.data());
}
/**
* @brief Custom assignment operator
* @details This is a very heavy operation so try to avoid this!
* @param other DyamicFIFO to copy from
*/
DynamicFIFO& operator=(const DynamicFIFO& other){
FIFOBase<T>::operator=(other);
this->fifoVector = other.fifoVector;
this->setContainer(fifoVector.data());
return *this;
}
private:
std::vector<T> fifoVector;
};
#endif /* FSFW_CONTAINER_DYNAMICFIFO_H_ */

47
container/FIFO.h Normal file
View File

@ -0,0 +1,47 @@
#ifndef FSFW_CONTAINER_FIFO_H_
#define FSFW_CONTAINER_FIFO_H_
#include "FIFOBase.h"
#include <array>
/**
* @brief Simple First-In-First-Out data structure with size fixed at
* compile time
* @details
* Performs no dynamic memory allocation.
* The public interface of FIFOBase exposes the user interface for the FIFO.
* @tparam T Entry Type
* @tparam capacity Maximum capacity
*/
template<typename T, size_t capacity>
class FIFO: public FIFOBase<T> {
public:
FIFO(): FIFOBase<T>(nullptr, capacity) {
this->setContainer(fifoArray.data());
};
/**
* @brief Custom copy constructor to set pointer correctly.
* @param other
*/
FIFO(const FIFO& other): FIFOBase<T>(other) {
this->fifoArray = other.fifoArray;
this->setContainer(fifoArray.data());
}
/**
* @brief Custom assignment operator
* @param other
*/
FIFO& operator=(const FIFO& other){
FIFOBase<T>::operator=(other);
this->fifoArray = other.fifoArray;
this->setContainer(fifoArray.data());
return *this;
}
private:
std::array<T, capacity> fifoArray;
};
#endif /* FSFW_CONTAINER_FIFO_H_ */

79
container/FIFOBase.h Normal file
View File

@ -0,0 +1,79 @@
#ifndef FSFW_CONTAINER_FIFOBASE_H_
#define FSFW_CONTAINER_FIFOBASE_H_
#include "../returnvalues/HasReturnvaluesIF.h"
#include <cstddef>
#include <cstring>
template <typename T>
class FIFOBase {
public:
static const uint8_t INTERFACE_ID = CLASS_ID::FIFO_CLASS;
static const ReturnValue_t FULL = MAKE_RETURN_CODE(1);
static const ReturnValue_t EMPTY = MAKE_RETURN_CODE(2);
/** Default ctor, takes pointer to first entry of underlying container
* and maximum capacity */
FIFOBase(T* values, const size_t maxCapacity);
/**
* Insert value into FIFO
* @param value
* @return RETURN_OK on success, FULL if full
*/
ReturnValue_t insert(T value);
/**
* Retrieve item from FIFO. This removes the item from the FIFO.
* @param value Must point to a valid T
* @return RETURN_OK on success, EMPTY if empty and FAILED if nullptr check failed
*/
ReturnValue_t retrieve(T *value);
/**
* Retrieve item from FIFO without removing it from FIFO.
* @param value Must point to a valid T
* @return RETURN_OK on success, EMPTY if empty and FAILED if nullptr check failed
*/
ReturnValue_t peek(T * value);
/**
* Remove item from FIFO.
* @return RETURN_OK on success, EMPTY if empty
*/
ReturnValue_t pop();
/***
* Check if FIFO is empty
* @return True if empty, False if not
*/
bool empty();
/***
* Check if FIFO is Full
* @return True if full, False if not
*/
bool full();
/***
* Current used size (elements) used
* @return size_t in elements
*/
size_t size();
/***
* Get maximal capacity of fifo
* @return size_t with max capacity of this fifo
*/
size_t getMaxCapacity() const;
protected:
void setContainer(T* data);
size_t maxCapacity = 0;
T* values;
size_t readIndex = 0;
size_t writeIndex = 0;
size_t currentSize = 0;
size_t next(size_t current);
};
#include "FIFOBase.tpp"
#endif /* FSFW_CONTAINER_FIFOBASE_H_ */

93
container/FIFOBase.tpp Normal file
View File

@ -0,0 +1,93 @@
#ifndef FSFW_CONTAINER_FIFOBASE_TPP_
#define FSFW_CONTAINER_FIFOBASE_TPP_
#ifndef FSFW_CONTAINER_FIFOBASE_H_
#error Include FIFOBase.h before FIFOBase.tpp!
#endif
template<typename T>
inline FIFOBase<T>::FIFOBase(T* values, const size_t maxCapacity):
maxCapacity(maxCapacity), values(values){};
template<typename T>
inline ReturnValue_t FIFOBase<T>::insert(T value) {
if (full()) {
return FULL;
} else {
values[writeIndex] = value;
writeIndex = next(writeIndex);
++currentSize;
return HasReturnvaluesIF::RETURN_OK;
}
};
template<typename T>
inline ReturnValue_t FIFOBase<T>::retrieve(T* value) {
if (empty()) {
return EMPTY;
} else {
if (value == nullptr){
return HasReturnvaluesIF::RETURN_FAILED;
}
*value = values[readIndex];
readIndex = next(readIndex);
--currentSize;
return HasReturnvaluesIF::RETURN_OK;
}
};
template<typename T>
inline ReturnValue_t FIFOBase<T>::peek(T* value) {
if(empty()) {
return EMPTY;
} else {
if (value == nullptr){
return HasReturnvaluesIF::RETURN_FAILED;
}
*value = values[readIndex];
return HasReturnvaluesIF::RETURN_OK;
}
};
template<typename T>
inline ReturnValue_t FIFOBase<T>::pop() {
T value;
return this->retrieve(&value);
};
template<typename T>
inline bool FIFOBase<T>::empty() {
return (currentSize == 0);
};
template<typename T>
inline bool FIFOBase<T>::full() {
return (currentSize == maxCapacity);
}
template<typename T>
inline size_t FIFOBase<T>::size() {
return currentSize;
}
template<typename T>
inline size_t FIFOBase<T>::next(size_t current) {
++current;
if (current == maxCapacity) {
current = 0;
}
return current;
}
template<typename T>
inline size_t FIFOBase<T>::getMaxCapacity() const {
return maxCapacity;
}
template<typename T>
inline void FIFOBase<T>::setContainer(T *data) {
this->values = data;
}
#endif

View File

@ -0,0 +1,38 @@
#ifndef FIXEDARRAYLIST_H_
#define FIXEDARRAYLIST_H_
#include "ArrayList.h"
#include <cmath>
/**
* \ingroup container
*/
template<typename T, size_t MAX_SIZE, typename count_t = uint8_t>
class FixedArrayList: public ArrayList<T, count_t> {
static_assert(MAX_SIZE <= (pow(2,sizeof(count_t)*8)-1), "count_t is not large enough to hold MAX_SIZE");
private:
T data[MAX_SIZE];
public:
FixedArrayList() :
ArrayList<T, count_t>(data, MAX_SIZE) {
}
FixedArrayList(const FixedArrayList& other) :
ArrayList<T, count_t>(data, MAX_SIZE) {
memcpy(this->data, other.data, sizeof(this->data));
this->entries = data;
this->size = other.size;
}
FixedArrayList& operator=(FixedArrayList other) {
memcpy(this->data, other.data, sizeof(this->data));
this->entries = data;
this->size = other.size;
return *this;
}
virtual ~FixedArrayList() {
}
};
#endif /* FIXEDARRAYLIST_H_ */

230
container/FixedMap.h Normal file
View File

@ -0,0 +1,230 @@
#ifndef FSFW_CONTAINER_FIXEDMAP_H_
#define FSFW_CONTAINER_FIXEDMAP_H_
#include "ArrayList.h"
#include "../returnvalues/HasReturnvaluesIF.h"
#include <utility>
#include <type_traits>
/**
* @brief Map implementation for maps with a pre-defined size.
* @details
* Can be initialized with desired maximum size.
* Iterator is used to access <key,value> pair and iterate through map entries.
* Complexity O(n).
* @warning Iterators return a non-const key_t in the pair.
* @warning A User is not allowed to change the key, otherwise the map is corrupted.
* @ingroup container
*/
template<typename key_t, typename T>
class FixedMap: public SerializeIF {
static_assert (std::is_trivially_copyable<T>::value or
std::is_base_of<SerializeIF, T>::value,
"Types used in FixedMap must either be trivial copy-able or a "
"derived class from SerializeIF to be serialize-able");
public:
static const uint8_t INTERFACE_ID = CLASS_ID::FIXED_MAP;
static const ReturnValue_t KEY_ALREADY_EXISTS = MAKE_RETURN_CODE(0x01);
static const ReturnValue_t MAP_FULL = MAKE_RETURN_CODE(0x02);
static const ReturnValue_t KEY_DOES_NOT_EXIST = MAKE_RETURN_CODE(0x03);
private:
static const key_t EMPTY_SLOT = -1;
ArrayList<std::pair<key_t, T>, uint32_t> theMap;
uint32_t _size;
uint32_t findIndex(key_t key) const {
if (_size == 0) {
return 1;
}
uint32_t i = 0;
for (i = 0; i < _size; ++i) {
if (theMap[i].first == key) {
return i;
}
}
return i;
}
public:
FixedMap(uint32_t maxSize) :
theMap(maxSize), _size(0) {
}
class Iterator: public ArrayList<std::pair<key_t, T>, uint32_t>::Iterator {
public:
Iterator() :
ArrayList<std::pair<key_t, T>, uint32_t>::Iterator() {
}
Iterator(std::pair<key_t, T> *pair) :
ArrayList<std::pair<key_t, T>, uint32_t>::Iterator(pair) {
}
};
friend bool operator==(const typename FixedMap::Iterator& lhs,
const typename FixedMap::Iterator& rhs) {
return (lhs.value == rhs.value);
}
friend bool operator!=(const typename FixedMap::Iterator& lhs,
const typename FixedMap::Iterator& rhs) {
return not (lhs.value == rhs.value);
}
Iterator begin() const {
return Iterator(&theMap[0]);
}
Iterator end() const {
return Iterator(&theMap[_size]);
}
uint32_t size() const {
return _size;
}
ReturnValue_t insert(key_t key, T value, Iterator *storedValue = nullptr) {
if (exists(key) == HasReturnvaluesIF::RETURN_OK) {
return KEY_ALREADY_EXISTS;
}
if (_size == theMap.maxSize()) {
return MAP_FULL;
}
theMap[_size].first = key;
theMap[_size].second = value;
if (storedValue != nullptr) {
*storedValue = Iterator(&theMap[_size]);
}
++_size;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t insert(std::pair<key_t, T> pair) {
return insert(pair.first, pair.second);
}
ReturnValue_t exists(key_t key) const {
ReturnValue_t result = KEY_DOES_NOT_EXIST;
if (findIndex(key) < _size) {
result = HasReturnvaluesIF::RETURN_OK;
}
return result;
}
ReturnValue_t erase(Iterator *iter) {
uint32_t i;
if ((i = findIndex((*iter).value->first)) >= _size) {
return KEY_DOES_NOT_EXIST;
}
theMap[i] = theMap[_size - 1];
--_size;
--((*iter).value);
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t erase(key_t key) {
uint32_t i;
if ((i = findIndex(key)) >= _size) {
return KEY_DOES_NOT_EXIST;
}
theMap[i] = theMap[_size - 1];
--_size;
return HasReturnvaluesIF::RETURN_OK;
}
T *findValue(key_t key) const {
return &theMap[findIndex(key)].second;
}
Iterator find(key_t key) const {
ReturnValue_t result = exists(key);
if (result != HasReturnvaluesIF::RETURN_OK) {
return end();
}
return Iterator(&theMap[findIndex(key)]);
}
ReturnValue_t find(key_t key, T **value) const {
ReturnValue_t result = exists(key);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
*value = &theMap[findIndex(key)].second;
return HasReturnvaluesIF::RETURN_OK;
}
bool empty() {
if(_size == 0) {
return true;
}
else {
return false;
}
}
bool full() {
if(_size >= theMap.maxSize()) {
return true;
}
else {
return false;
}
}
void clear() {
_size = 0;
}
uint32_t maxSize() const {
return theMap.maxSize();
}
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size,
size_t maxSize, Endianness streamEndianness) const {
ReturnValue_t result = SerializeAdapter::serialize(&this->_size,
buffer, size, maxSize, streamEndianness);
uint32_t i = 0;
while ((result == HasReturnvaluesIF::RETURN_OK) && (i < this->_size)) {
result = SerializeAdapter::serialize(&theMap[i].first, buffer,
size, maxSize, streamEndianness);
result = SerializeAdapter::serialize(&theMap[i].second, buffer, size,
maxSize, streamEndianness);
++i;
}
return result;
}
virtual size_t getSerializedSize() const {
uint32_t printSize = sizeof(_size);
uint32_t i = 0;
for (i = 0; i < _size; ++i) {
printSize += SerializeAdapter::getSerializedSize(
&theMap[i].first);
printSize += SerializeAdapter::getSerializedSize(&theMap[i].second);
}
return printSize;
}
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
Endianness streamEndianness) {
ReturnValue_t result = SerializeAdapter::deSerialize(&this->_size,
buffer, size, streamEndianness);
if (this->_size > theMap.maxSize()) {
return SerializeIF::TOO_MANY_ELEMENTS;
}
uint32_t i = 0;
while ((result == HasReturnvaluesIF::RETURN_OK) && (i < this->_size)) {
result = SerializeAdapter::deSerialize(&theMap[i].first, buffer,
size, streamEndianness);
result = SerializeAdapter::deSerialize(&theMap[i].second, buffer, size,
streamEndianness);
++i;
}
return result;
}
};
#endif /* FSFW_CONTAINER_FIXEDMAP_H_ */

View File

@ -0,0 +1,206 @@
#ifndef FSFW_CONTAINER_FIXEDORDEREDMULTIMAP_H_
#define FSFW_CONTAINER_FIXEDORDEREDMULTIMAP_H_
#include "ArrayList.h"
#include <cstring>
/**
* @brief An associative container which allows multiple entries of the same key.
* @details
* Same keys are ordered by KEY_COMPARE function which is std::less<key_t> > by default.
*
* It uses the ArrayList, so technically this is not a real map, it is an array of pairs
* of type key_t, T. It is ordered by key_t as FixedMap but allows same keys. Thus it has a linear
* complexity O(n). As long as the number of entries remains low, this
* should not be an issue.
* The number of insertion and deletion operation should be minimized
* as those incur extensive memory move operations (the underlying container
* is not node based).
*
* Its of fixed size so no allocations are performed after the construction.
*
* The maximum size is given as first parameter of the constructor.
*
* It provides an iterator to do list iterations.
*
* The type T must have a copy constructor if it is not trivial copy-able.
*
* @warning Iterators return a non-const key_t in the pair.
* @warning A User is not allowed to change the key, otherwise the map is corrupted.
*
* \ingroup container
*/
template<typename key_t, typename T, typename KEY_COMPARE = std::less<key_t>>
class FixedOrderedMultimap {
public:
static const uint8_t INTERFACE_ID = CLASS_ID::FIXED_MULTIMAP;
static const ReturnValue_t MAP_FULL = MAKE_RETURN_CODE(0x01);
static const ReturnValue_t KEY_DOES_NOT_EXIST = MAKE_RETURN_CODE(0x02);
/***
* Constructor which needs a size_t for the maximum allowed size
*
* Can not be resized during runtime
*
* Allocates memory at construction
* @param maxSize size_t of Maximum allowed size
*/
FixedOrderedMultimap(size_t maxSize):theMap(maxSize), _size(0){
}
/***
* Virtual destructor frees Memory by deleting its member
*/
virtual ~FixedOrderedMultimap() {
}
/***
* Special iterator for FixedOrderedMultimap
*/
class Iterator: public ArrayList<std::pair<key_t, T>, size_t>::Iterator {
public:
Iterator() :
ArrayList<std::pair<key_t, T>, size_t>::Iterator() {
}
Iterator(std::pair<key_t, T> *pair) :
ArrayList<std::pair<key_t, T>, size_t>::Iterator(pair) {
}
};
/***
* Returns an iterator pointing to the first element
* @return Iterator pointing to first element
*/
Iterator begin() const {
return Iterator(&theMap[0]);
}
/**
* Returns an iterator pointing to one element past the end
* @return Iterator pointing to one element past the end
*/
Iterator end() const {
return Iterator(&theMap[_size]);
}
/***
* Returns the current size of the map (not maximum size!)
* @return Current size
*/
size_t size() const{
return _size;
}
/**
* Clears the map, does not deallocate any memory
*/
void clear(){
_size = 0;
}
/**
* Returns the maximum size of the map
* @return Maximum size of the map
*/
size_t maxSize() const{
return theMap.maxSize();
}
/***
* Used to insert a key and value separately.
*
* @param[in] key Key of the new element
* @param[in] value Value of the new element
* @param[in/out] (optional) storedValue On success this points to the new value, otherwise a nullptr
* @return RETURN_OK if insert was successful, MAP_FULL if no space is available
*/
ReturnValue_t insert(key_t key, T value, Iterator *storedValue = nullptr);
/***
* Used to insert new pair instead of single values
*
* @param pair Pair to be inserted
* @return RETURN_OK if insert was successful, MAP_FULL if no space is available
*/
ReturnValue_t insert(std::pair<key_t, T> pair);
/***
* Can be used to check if a certain key is in the map
* @param key Key to be checked
* @return RETURN_OK if the key exists KEY_DOES_NOT_EXIST otherwise
*/
ReturnValue_t exists(key_t key) const;
/***
* Used to delete the element in the iterator
*
* The iterator will point to the element before or begin(),
* but never to one element in front of the map.
*
* @warning The iterator needs to be valid and dereferenceable
* @param[in/out] iter Pointer to iterator to the element that needs to be ereased
* @return RETURN_OK if erased, KEY_DOES_NOT_EXIST if the there is no element like this
*/
ReturnValue_t erase(Iterator *iter);
/***
* Used to erase by key
* @param key Key to be erased
* @return RETURN_OK if erased, KEY_DOES_NOT_EXIST if the there is no element like this
*/
ReturnValue_t erase(key_t key);
/***
* Find returns the first appearance of the key
*
* If the key does not exist, it points to end()
*
* @param key Key to search for
* @return Iterator pointing to the first entry of key
*/
Iterator find(key_t key) const{
ReturnValue_t result = exists(key);
if (result != HasReturnvaluesIF::RETURN_OK) {
return end();
}
return Iterator(&theMap[findFirstIndex(key)]);
};
/***
* Finds first entry of the given key and returns a
* pointer to the value
*
* @param key Key to search for
* @param value Found value
* @return RETURN_OK if it points to the value,
* KEY_DOES_NOT_EXIST if the key is not in the map
*/
ReturnValue_t find(key_t key, T **value) const;
friend bool operator==(const typename FixedOrderedMultimap::Iterator& lhs,
const typename FixedOrderedMultimap::Iterator& rhs) {
return (lhs.value == rhs.value);
}
friend bool operator!=(const typename FixedOrderedMultimap::Iterator& lhs,
const typename FixedOrderedMultimap::Iterator& rhs) {
return not (lhs.value == rhs.value);
}
private:
typedef KEY_COMPARE compare;
compare myComp;
ArrayList<std::pair<key_t, T>, size_t> theMap;
size_t _size;
size_t findFirstIndex(key_t key, size_t startAt = 0) const;
size_t findNicePlace(key_t key) const;
void removeFromPosition(size_t position);
};
#include "FixedOrderedMultimap.tpp"
#endif /* FSFW_CONTAINER_FIXEDORDEREDMULTIMAP_H_ */

View File

@ -0,0 +1,109 @@
#ifndef FRAMEWORK_CONTAINER_FIXEDORDEREDMULTIMAP_TPP_
#define FRAMEWORK_CONTAINER_FIXEDORDEREDMULTIMAP_TPP_
template<typename key_t, typename T, typename KEY_COMPARE>
inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::insert(key_t key, T value, Iterator *storedValue) {
if (_size == theMap.maxSize()) {
return MAP_FULL;
}
size_t position = findNicePlace(key);
memmove(static_cast<void*>(&theMap[position + 1]),static_cast<void*>(&theMap[position]),
(_size - position) * sizeof(std::pair<key_t,T>));
theMap[position].first = key;
theMap[position].second = value;
++_size;
if (storedValue != nullptr) {
*storedValue = Iterator(&theMap[position]);
}
return HasReturnvaluesIF::RETURN_OK;
}
template<typename key_t, typename T, typename KEY_COMPARE>
inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::insert(std::pair<key_t, T> pair) {
return insert(pair.first, pair.second);
}
template<typename key_t, typename T, typename KEY_COMPARE>
inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::exists(key_t key) const {
ReturnValue_t result = KEY_DOES_NOT_EXIST;
if (findFirstIndex(key) < _size) {
result = HasReturnvaluesIF::RETURN_OK;
}
return result;
}
template<typename key_t, typename T, typename KEY_COMPARE>
inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::erase(Iterator *iter) {
size_t i;
if ((i = findFirstIndex((*iter).value->first)) >= _size) {
return KEY_DOES_NOT_EXIST;
}
removeFromPosition(i);
if (*iter != begin()) {
(*iter)--;
} else {
*iter = begin();
}
return HasReturnvaluesIF::RETURN_OK;
}
template<typename key_t, typename T, typename KEY_COMPARE>
inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::erase(key_t key) {
size_t i;
if ((i = findFirstIndex(key)) >= _size) {
return KEY_DOES_NOT_EXIST;
}
do {
removeFromPosition(i);
i = findFirstIndex(key, i);
} while (i < _size);
return HasReturnvaluesIF::RETURN_OK;
}
template<typename key_t, typename T, typename KEY_COMPARE>
inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::find(key_t key, T **value) const {
ReturnValue_t result = exists(key);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
*value = &theMap[findFirstIndex(key)].second;
return HasReturnvaluesIF::RETURN_OK;
}
template<typename key_t, typename T, typename KEY_COMPARE>
inline size_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::findFirstIndex(key_t key, size_t startAt) const {
if (startAt >= _size) {
return startAt + 1;
}
size_t i = startAt;
for (i = startAt; i < _size; ++i) {
if (theMap[i].first == key) {
return i;
}
}
return i;
}
template<typename key_t, typename T, typename KEY_COMPARE>
inline size_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::findNicePlace(key_t key) const {
size_t i = 0;
for (i = 0; i < _size; ++i) {
if (myComp(key, theMap[i].first)) {
return i;
}
}
return i;
}
template<typename key_t, typename T, typename KEY_COMPARE>
inline void FixedOrderedMultimap<key_t, T, KEY_COMPARE>::removeFromPosition(size_t position) {
if (_size <= position) {
return;
}
memmove(static_cast<void*>(&theMap[position]), static_cast<void*>(&theMap[position + 1]),
(_size - position - 1) * sizeof(std::pair<key_t,T>));
--_size;
}
#endif /* FRAMEWORK_CONTAINER_FIXEDORDEREDMULTIMAP_TPP_ */

View File

@ -0,0 +1,90 @@
#ifndef FRAMEWORK_CONTAINER_HYBRIDITERATOR_H_
#define FRAMEWORK_CONTAINER_HYBRIDITERATOR_H_
#include "ArrayList.h"
#include "SinglyLinkedList.h"
template<typename T, typename count_t = uint8_t>
class HybridIterator: public LinkedElement<T>::Iterator,
public ArrayList<T, count_t>::Iterator {
public:
HybridIterator() {}
HybridIterator(typename LinkedElement<T>::Iterator *iter) :
LinkedElement<T>::Iterator(*iter), value(iter->value),
linked(true) {
}
HybridIterator(LinkedElement<T> *start) :
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 = NULL;
}
}
HybridIterator(T *firstElement, T *lastElement) :
ArrayList<T, count_t>::Iterator(firstElement), value(firstElement),
linked(false), end(++lastElement) {
if (value == end) {
value = NULL;
}
}
HybridIterator& operator++() {
if (linked) {
LinkedElement<T>::Iterator::operator++();
if (LinkedElement<T>::Iterator::value != nullptr) {
value = LinkedElement<T>::Iterator::value->value;
} else {
value = nullptr;
}
} else {
ArrayList<T, count_t>::Iterator::operator++();
value = ArrayList<T, count_t>::Iterator::value;
if (value == end) {
value = nullptr;
}
}
return *this;
}
HybridIterator operator++(int) {
HybridIterator tmp(*this);
operator++();
return tmp;
}
bool operator==(const HybridIterator& other) const {
return value == other.value;
}
bool operator!=(const HybridIterator& other) const {
return !(*this == other);
}
T operator*() {
return *value;
}
T *operator->() {
return value;
}
T* value = nullptr;
private:
bool linked = false;
T *end = nullptr;
};
#endif /* FRAMEWORK_CONTAINER_HYBRIDITERATOR_H_ */

View File

@ -0,0 +1,700 @@
#ifndef FRAMEWORK_CONTAINER_INDEXEDRINGMEMORY_H_
#define FRAMEWORK_CONTAINER_INDEXEDRINGMEMORY_H_
#include "ArrayList.h"
#include "../globalfunctions/CRC.h"
#include "../serviceinterface/ServiceInterfaceStream.h"
#include "../returnvalues/HasReturnvaluesIF.h"
#include "../serialize/SerialArrayListAdapter.h"
#include <cmath>
template<typename T>
class Index: public SerializeIF{
/**
* Index is the Type used for the list of indices. The template parameter is the type which describes the index, it needs to be a child of SerializeIF to be able to make it persistent
*/
static_assert(std::is_base_of<SerializeIF,T>::value,"Wrong Type for Index, Type must implement SerializeIF");
public:
Index():blockStartAddress(0),size(0),storedPackets(0){}
Index(uint32_t startAddress):blockStartAddress(startAddress),size(0),storedPackets(0){
}
void setBlockStartAddress(uint32_t newAddress){
this->blockStartAddress = newAddress;
}
uint32_t getBlockStartAddress() const {
return blockStartAddress;
}
const T* getIndexType() const {
return &indexType;
}
T* modifyIndexType(){
return &indexType;
}
/**
* Updates the index Type. Uses = operator
* @param indexType Type to copy from
*/
void setIndexType(T* indexType) {
this->indexType = *indexType;
}
uint32_t getSize() const {
return size;
}
void setSize(uint32_t size) {
this->size = size;
}
void addSize(uint32_t size){
this->size += size;
}
void setStoredPackets(uint32_t newStoredPackets){
this->storedPackets = newStoredPackets;
}
void addStoredPackets(uint32_t packets){
this->storedPackets += packets;
}
uint32_t getStoredPackets() const{
return this->storedPackets;
}
ReturnValue_t serialize(uint8_t** buffer, size_t* size,
size_t maxSize, Endianness streamEndianness) const {
ReturnValue_t result = SerializeAdapter::serialize(&blockStartAddress,buffer,size,maxSize,streamEndianness);
if(result != HasReturnvaluesIF::RETURN_OK){
return result;
}
result = indexType.serialize(buffer,size,maxSize,streamEndianness);
if(result != HasReturnvaluesIF::RETURN_OK){
return result;
}
result = SerializeAdapter::serialize(&this->size,buffer,size,maxSize,streamEndianness);
if(result != HasReturnvaluesIF::RETURN_OK){
return result;
}
result = SerializeAdapter::serialize(&this->storedPackets,buffer,size,maxSize,streamEndianness);
return result;
}
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
Endianness streamEndianness){
ReturnValue_t result = SerializeAdapter::deSerialize(&blockStartAddress,buffer,size,streamEndianness);
if(result != HasReturnvaluesIF::RETURN_OK){
return result;
}
result = indexType.deSerialize(buffer,size,streamEndianness);
if(result != HasReturnvaluesIF::RETURN_OK){
return result;
}
result = SerializeAdapter::deSerialize(&this->size,buffer,size,streamEndianness);
if(result != HasReturnvaluesIF::RETURN_OK){
return result;
}
result = SerializeAdapter::deSerialize(&this->storedPackets,buffer,size,streamEndianness);
if(result != HasReturnvaluesIF::RETURN_OK){
return result;
}
return result;
}
size_t getSerializedSize() const {
uint32_t size = SerializeAdapter::getSerializedSize(&blockStartAddress);
size += indexType.getSerializedSize();
size += SerializeAdapter::getSerializedSize(&this->size);
size += SerializeAdapter::getSerializedSize(&this->storedPackets);
return size;
}
bool operator==(const Index<T>& other){
return ((blockStartAddress == other.getBlockStartAddress()) && (size==other.getSize())) && (indexType == *(other.getIndexType()));
}
private:
uint32_t blockStartAddress;
uint32_t size;
uint32_t storedPackets;
T indexType;
};
template<typename T>
class IndexedRingMemoryArray: public SerializeIF, public ArrayList<Index<T>, uint32_t>{
/**
* Indexed Ring Memory Array is a class for a ring memory with indices. It assumes that the newest data comes in last
* It uses the currentWriteBlock as pointer to the current writing position
* The currentReadBlock must be set manually
*/
public:
IndexedRingMemoryArray(uint32_t startAddress, uint32_t size, uint32_t bytesPerBlock, SerializeIF* additionalInfo,
bool overwriteOld) :ArrayList<Index<T>,uint32_t>(NULL,(uint32_t)10,(uint32_t)0),totalSize(size),indexAddress(startAddress),currentReadSize(0),currentReadBlockSizeCached(0),lastBlockToReadSize(0), additionalInfo(additionalInfo),overwriteOld(overwriteOld){
//Calculate the maximum number of indices needed for this blocksize
uint32_t maxNrOfIndices = floor(static_cast<double>(size)/static_cast<double>(bytesPerBlock));
//Calculate the Size needeed for the index itself
uint32_t serializedSize = 0;
if(additionalInfo!=NULL){
serializedSize += additionalInfo->getSerializedSize();
}
//Size of current iterator type
Index<T> tempIndex;
serializedSize += tempIndex.getSerializedSize();
//Add Size of Array
serializedSize += sizeof(uint32_t); //size of array
serializedSize += (tempIndex.getSerializedSize() * maxNrOfIndices); //size of elements
serializedSize += sizeof(uint16_t); //size of crc
//Calculate new size after index
if(serializedSize > totalSize){
error << "IndexedRingMemory: Store is too small for index" << std::endl;
}
uint32_t useableSize = totalSize - serializedSize;
//Update the totalSize for calculations
totalSize = useableSize;
//True StartAddress
uint32_t trueStartAddress = indexAddress + serializedSize;
//Calculate True number of Blocks and reset size of true Number of Blocks
uint32_t trueNumberOfBlocks = floor(static_cast<double>(totalSize) / static_cast<double>(bytesPerBlock));
//allocate memory now
this->entries = new Index<T>[trueNumberOfBlocks];
this->size = trueNumberOfBlocks;
this->maxSize_ = trueNumberOfBlocks;
this->allocated = true;
//Check trueNumberOfBlocks
if(trueNumberOfBlocks<1){
error << "IndexedRingMemory: Invalid Number of Blocks: " << trueNumberOfBlocks;
}
//Fill address into index
uint32_t address = trueStartAddress;
for (typename IndexedRingMemoryArray<T>::Iterator it = this->begin();it!=this->end();++it) {
it->setBlockStartAddress(address);
it->setSize(0);
it->setStoredPackets(0);
address += bytesPerBlock;
}
//Initialize iterators
currentWriteBlock = this->begin();
currentReadBlock = this->begin();
lastBlockToRead = this->begin();
//Check last blockSize
uint32_t lastBlockSize = (trueStartAddress + useableSize) - (this->back()->getBlockStartAddress());
if((lastBlockSize<bytesPerBlock) && (this->size > 1)){
//remove the last Block so the second last block has more size
this->size -= 1;
debug << "IndexedRingMemory: Last Block is smaller than bytesPerBlock, removed last block" << std::endl;
}
}
/**
* Resets the whole index, the iterators and executes the given reset function on every index type
* @param typeResetFnc static reset function which accepts a pointer to the index Type
*/
void reset(void (*typeResetFnc)(T*)){
currentReadBlock = this->begin();
currentWriteBlock = this->begin();
lastBlockToRead = this->begin();
currentReadSize = 0;
currentReadBlockSizeCached = 0;
lastBlockToReadSize = 0;
for(typename IndexedRingMemoryArray<T>::Iterator it = this->begin();it!=this->end();++it){
it->setSize(0);
it->setStoredPackets(0);
(*typeResetFnc)(it->modifyIndexType());
}
}
void resetBlock(typename IndexedRingMemoryArray<T>::Iterator it,void (*typeResetFnc)(T*)){
it->setSize(0);
it->setStoredPackets(0);
(*typeResetFnc)(it->modifyIndexType());
}
/*
* Reading
*/
void setCurrentReadBlock(typename IndexedRingMemoryArray<T>::Iterator it){
currentReadBlock = it;
currentReadBlockSizeCached = it->getSize();
}
void resetRead(){
currentReadBlock = this->begin();
currentReadSize = 0;
currentReadBlockSizeCached = this->begin()->getSize();
lastBlockToRead = currentWriteBlock;
lastBlockToReadSize = currentWriteBlock->getSize();
}
/**
* Sets the last block to read to this iterator.
* Can be used to dump until block x
* @param it The iterator for the last read block
*/
void setLastBlockToRead(typename IndexedRingMemoryArray<T>::Iterator it){
lastBlockToRead = it;
lastBlockToReadSize = it->getSize();
}
/**
* Set the read pointer to the first written Block, which is the first non empty block in front of the write block
* Can be the currentWriteBlock as well
*/
void readOldest(){
resetRead();
currentReadBlock = getNextNonEmptyBlock();
currentReadBlockSizeCached = currentReadBlock->getSize();
}
/**
* Sets the current read iterator to the next Block and resets the current read size
* The current size of the block will be cached to avoid race condition between write and read
* If the end of the ring is reached the read pointer will be set to the begin
*/
void readNext(){
currentReadSize = 0;
if((this->size != 0) && (currentReadBlock.value ==this->back())){
currentReadBlock = this->begin();
}else{
currentReadBlock++;
}
currentReadBlockSizeCached = currentReadBlock->getSize();
}
/**
* Returns the address which is currently read from
* @return Address to read from
*/
uint32_t getCurrentReadAddress() const {
return getAddressOfCurrentReadBlock() + currentReadSize;
}
/**
* Adds readSize to the current size and checks if the read has no more data left and advances the read block
* @param readSize The size that was read
* @return Returns true if the read can go on
*/
bool addReadSize(uint32_t readSize) {
if(currentReadBlock == lastBlockToRead){
//The current read block is the last to read
if((currentReadSize+readSize)<lastBlockToReadSize){
//the block has more data -> return true
currentReadSize += readSize;
return true;
}else{
//Reached end of read -> return false
currentReadSize = lastBlockToReadSize;
return false;
}
}else{
//We are not in the last Block
if((currentReadSize + readSize)<currentReadBlockSizeCached){
//The current Block has more data
currentReadSize += readSize;
return true;
}else{
//The current block is written completely
readNext();
if(currentReadBlockSizeCached==0){
//Next block is empty
typename IndexedRingMemoryArray<T>::Iterator it(currentReadBlock);
//Search if any block between this and the last block is not empty
for(;it!=lastBlockToRead;++it){
if(it == this->end()){
//This is the end, next block is the begin
it = this->begin();
if(it == lastBlockToRead){
//Break if the begin is the lastBlockToRead
break;
}
}
if(it->getSize()!=0){
//This is a non empty block. Go on reading with this block
currentReadBlock = it;
currentReadBlockSizeCached = it->getSize();
return true;
}
}
//reached lastBlockToRead and every block was empty, check if the last block is also empty
if(lastBlockToReadSize!=0){
//go on with last Block
currentReadBlock = lastBlockToRead;
currentReadBlockSizeCached = lastBlockToReadSize;
return true;
}
//There is no non empty block left
return false;
}
//Size is larger than 0
return true;
}
}
}
uint32_t getRemainigSizeOfCurrentReadBlock() const{
if(currentReadBlock == lastBlockToRead){
return (lastBlockToReadSize - currentReadSize);
}else{
return (currentReadBlockSizeCached - currentReadSize);
}
}
uint32_t getAddressOfCurrentReadBlock() const {
return currentReadBlock->getBlockStartAddress();
}
/**
* Gets the next non empty Block after the current write block,
* @return Returns the iterator to the block. If there is non, the current write block is returned
*/
typename IndexedRingMemoryArray<T>::Iterator getNextNonEmptyBlock() const {
for(typename IndexedRingMemoryArray<T>::Iterator it = getNextWrite();it!=currentWriteBlock;++it){
if(it == this->end()){
it = this->begin();
if(it == currentWriteBlock){
break;
}
}
if(it->getSize()!=0){
return it;
}
}
return currentWriteBlock;
}
/**
* Returns a copy of the oldest Index type
* @return Type of Index
*/
T* getOldest(){
return (getNextNonEmptyBlock()->modifyIndexType());
}
/*
* Writing
*/
uint32_t getAddressOfCurrentWriteBlock() const{
return currentWriteBlock->getBlockStartAddress();
}
uint32_t getSizeOfCurrentWriteBlock() const{
return currentWriteBlock->getSize();
}
uint32_t getCurrentWriteAddress() const{
return getAddressOfCurrentWriteBlock() + getSizeOfCurrentWriteBlock();
}
void clearCurrentWriteBlock(){
currentWriteBlock->setSize(0);
currentWriteBlock->setStoredPackets(0);
}
void addCurrentWriteBlock(uint32_t size, uint32_t storedPackets){
currentWriteBlock->addSize(size);
currentWriteBlock->addStoredPackets(storedPackets);
}
T* modifyCurrentWriteBlockIndexType(){
return currentWriteBlock->modifyIndexType();
}
void updatePreviousWriteSize(uint32_t size, uint32_t storedPackets){
typename IndexedRingMemoryArray<T>::Iterator it = getPreviousBlock(currentWriteBlock);
it->addSize(size);
it->addStoredPackets(storedPackets);
}
/**
* Checks if the block has enough space for sizeToWrite
* @param sizeToWrite The data to be written in the Block
* @return Returns true if size to write is smaller the remaining size of the block
*/
bool hasCurrentWriteBlockEnoughSpace(uint32_t sizeToWrite){
typename IndexedRingMemoryArray<T>::Iterator next = getNextWrite();
uint32_t addressOfNextBlock = next->getBlockStartAddress();
uint32_t availableSize = ((addressOfNextBlock+totalSize) - (getAddressOfCurrentWriteBlock()+getSizeOfCurrentWriteBlock()))%totalSize;
return (sizeToWrite < availableSize);
}
/**
* Checks if the store is full if overwrite old is false
* @return Returns true if it is writeable and false if not
*/
bool isNextBlockWritable(){
//First check if this is the end of the list
typename IndexedRingMemoryArray<T>::Iterator next;
next = getNextWrite();
if((next->getSize()!=0) && (!overwriteOld)){
return false;
}
return true;
}
/**
* Updates current write Block Index Type
* @param infoOfNewBlock
*/
void updateCurrentBlock(T* infoOfNewBlock){
currentWriteBlock->setIndexType(infoOfNewBlock);
}
/**
* Succeed to next block, returns FAILED if overwrite is false and the store is full
* @return
*/
ReturnValue_t writeNext(){
//Check Next Block
if(!isNextBlockWritable()){
//The Index is full and does not overwrite old
return HasReturnvaluesIF::RETURN_FAILED;
}
//Next block can be written, update Metadata
currentWriteBlock = getNextWrite();
currentWriteBlock->setSize(0);
currentWriteBlock->setStoredPackets(0);
return HasReturnvaluesIF::RETURN_OK;
}
/**
* Serializes the Index and calculates the CRC.
* Parameters according to HasSerializeIF
* @param buffer
* @param size
* @param maxSize
* @param streamEndianness
* @return
*/
ReturnValue_t serialize(uint8_t** buffer, size_t* size,
size_t maxSize, Endianness streamEndianness) const{
uint8_t* crcBuffer = *buffer;
uint32_t oldSize = *size;
if(additionalInfo!=NULL){
additionalInfo->serialize(buffer,size,maxSize,streamEndianness);
}
ReturnValue_t result = currentWriteBlock->serialize(buffer,size,maxSize,streamEndianness);
if(result != HasReturnvaluesIF::RETURN_OK){
return result;
}
result = SerializeAdapter::serialize(&this->size,buffer,size,maxSize,streamEndianness);
if(result != HasReturnvaluesIF::RETURN_OK){
return result;
}
uint32_t i = 0;
while ((result == HasReturnvaluesIF::RETURN_OK) && (i < this->size)) {
result = SerializeAdapter::serialize(&this->entries[i], buffer, size,
maxSize, streamEndianness);
++i;
}
if(result != HasReturnvaluesIF::RETURN_OK){
return result;
}
uint16_t crc = Calculate_CRC(crcBuffer,(*size-oldSize));
result = SerializeAdapter::serialize(&crc,buffer,size,maxSize,streamEndianness);
return result;
}
/**
* Get the serialized Size of the index
* @return The serialized size of the index
*/
size_t getSerializedSize() const {
uint32_t size = 0;
if(additionalInfo!=NULL){
size += additionalInfo->getSerializedSize();
}
size += currentWriteBlock->getSerializedSize();
size += SerializeAdapter::getSerializedSize(&this->size);
size += (this->entries[0].getSerializedSize()) * this->size;
uint16_t crc = 0;
size += SerializeAdapter::getSerializedSize(&crc);
return size;
}
/**
* DeSerialize the Indexed Ring from a buffer, deSerializes the current write iterator
* CRC Has to be checked before!
* @param buffer
* @param size
* @param streamEndianness
* @return
*/
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
Endianness streamEndianness){
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
if(additionalInfo!=NULL){
result = additionalInfo->deSerialize(buffer,size,streamEndianness);
}
if(result != HasReturnvaluesIF::RETURN_OK){
return result;
}
Index<T> tempIndex;
result = tempIndex.deSerialize(buffer,size,streamEndianness);
if(result != HasReturnvaluesIF::RETURN_OK){
return result;
}
uint32_t tempSize = 0;
result = SerializeAdapter::deSerialize(&tempSize,buffer,size,streamEndianness);
if(result != HasReturnvaluesIF::RETURN_OK){
return result;
}
if(this->size != tempSize){
return HasReturnvaluesIF::RETURN_FAILED;
}
uint32_t i = 0;
while ((result == HasReturnvaluesIF::RETURN_OK) && (i < this->size)) {
result = SerializeAdapter::deSerialize(
&this->entries[i], buffer, size,
streamEndianness);
++i;
}
if(result != HasReturnvaluesIF::RETURN_OK){
return result;
}
typename IndexedRingMemoryArray<T>::Iterator cmp(&tempIndex);
for(typename IndexedRingMemoryArray<T>::Iterator it= this->begin();it!=this->end();++it){
if(*(cmp.value) == *(it.value)){
currentWriteBlock = it;
return HasReturnvaluesIF::RETURN_OK;
}
}
//Reached if current write block iterator is not found
return HasReturnvaluesIF::RETURN_FAILED;
}
uint32_t getIndexAddress() const {
return indexAddress;
}
/*
* Statistics
*/
uint32_t getStoredPackets() const {
uint32_t size = 0;
for(typename IndexedRingMemoryArray<T>::Iterator it= this->begin();it!=this->end();++it){
size += it->getStoredPackets();
}
return size;
}
uint32_t getTotalSize() const {
return totalSize;
}
uint32_t getCurrentSize() const{
uint32_t size = 0;
for(typename IndexedRingMemoryArray<T>::Iterator it= this->begin();it!=this->end();++it){
size += it->getSize();
}
return size;
}
bool isEmpty() const{
return getCurrentSize()==0;
}
double getPercentageFilled() const{
uint32_t filledSize = 0;
for(typename IndexedRingMemoryArray<T>::Iterator it= this->begin();it!=this->end();++it){
filledSize += it->getSize();
}
return (double)filledSize/(double)this->totalSize;
}
typename IndexedRingMemoryArray<T>::Iterator getCurrentWriteBlock() const{
return currentWriteBlock;
}
/**
* Get the next block of the currentWriteBlock.
* Returns the first one if currentWriteBlock is the last one
* @return Iterator pointing to the next block after currentWriteBlock
*/
typename IndexedRingMemoryArray<T>::Iterator getNextWrite() const{
typename IndexedRingMemoryArray<T>::Iterator next(currentWriteBlock);
if((this->size != 0) && (currentWriteBlock.value == this->back())){
next = this->begin();
}else{
++next;
}
return next;
}
/**
* Get the block in front of the Iterator
* Returns the last block if it is the first block
* @param it iterator which you want the previous block from
* @return pointing to the block before it
*/
typename IndexedRingMemoryArray<T>::Iterator getPreviousBlock(typename IndexedRingMemoryArray<T>::Iterator it) {
if(this->begin() == it){
typename IndexedRingMemoryArray<T>::Iterator next((this->back()));
return next;
}
typename IndexedRingMemoryArray<T>::Iterator next(it);
--next;
return next;
}
private:
//The total size used by the blocks (without index)
uint32_t totalSize;
//The address of the index
const uint32_t indexAddress;
//The iterators for writing and reading
typename IndexedRingMemoryArray<T>::Iterator currentWriteBlock;
typename IndexedRingMemoryArray<T>::Iterator currentReadBlock;
//How much of the current read block is read already
uint32_t currentReadSize;
//Cached Size of current read block
uint32_t currentReadBlockSizeCached;
//Last block of current write (should be write block)
typename IndexedRingMemoryArray<T>::Iterator lastBlockToRead;
//current size of last Block to read
uint32_t lastBlockToReadSize;
//Additional Info to be serialized with the index
SerializeIF* additionalInfo;
//Does it overwrite old blocks?
const bool overwriteOld;
};
#endif /* FRAMEWORK_CONTAINER_INDEXEDRINGMEMORY_H_ */

View File

@ -0,0 +1,71 @@
#ifndef FRAMEWORK_CONTAINER_PLACEMENTFACTORY_H_
#define FRAMEWORK_CONTAINER_PLACEMENTFACTORY_H_
#include "../storagemanager/StorageManagerIF.h"
#include <utility>
/**
* The Placement Factory is used to create objects at runtime in a specific pool.
* In general, this should be avoided and it should only be used if you know what you are doing.
* You are not allowed to use this container with a type that allocates memory internally like ArrayList.
*
* Also, you have to check the returned pointer in generate against nullptr!
*
* A backend of Type StorageManagerIF must be given as a place to store the new objects.
* Therefore ThreadSafety is only provided by your StorageManager Implementation.
*
* Objects must be destroyed by the user with "destroy"! Otherwise the pool will not be cleared.
*
* The concept is based on the placement new operator.
*
* @warning Do not use with any Type that allocates memory internally!
* @ingroup container
*/
class PlacementFactory {
public:
PlacementFactory(StorageManagerIF* backend) :
dataBackend(backend) {
}
/***
* Generates an object of type T in the backend storage.
*
* @warning Do not use with any Type that allocates memory internally!
*
* @tparam T Type of Object
* @param args Constructor Arguments to be passed
* @return A pointer to the new object or a nullptr in case of failure
*/
template<typename T, typename ... Args>
T* generate(Args&&... args) {
store_address_t tempId;
uint8_t* pData = nullptr;
ReturnValue_t result = dataBackend->getFreeElement(&tempId, sizeof(T),
&pData);
if (result != HasReturnvaluesIF::RETURN_OK) {
return nullptr;
}
T* temp = new (pData) T(std::forward<Args>(args)...);
return temp;
}
/***
* Function to destroy the object allocated with generate and free space in backend.
* This must be called by the user.
*
* @param thisElement Element to be destroyed
* @return RETURN_OK if the element was destroyed, different errors on failure
*/
template<typename T>
ReturnValue_t destroy(T* thisElement) {
if (thisElement == nullptr){
return HasReturnvaluesIF::RETURN_FAILED;
}
//Need to call destructor first, in case something was allocated by the object (shouldn't do that, however).
thisElement->~T();
uint8_t* pointer = (uint8_t*) (thisElement);
return dataBackend->deleteData(pointer, sizeof(T));
}
private:
StorageManagerIF* dataBackend;
};
#endif /* FRAMEWORK_CONTAINER_PLACEMENTFACTORY_H_ */

113
container/RingBufferBase.h Normal file
View File

@ -0,0 +1,113 @@
#ifndef FSFW_CONTAINER_RINGBUFFERBASE_H_
#define FSFW_CONTAINER_RINGBUFFERBASE_H_
#include "../returnvalues/HasReturnvaluesIF.h"
#include <cstddef>
template<uint8_t N_READ_PTRS = 1>
class RingBufferBase {
public:
RingBufferBase(size_t startAddress, const size_t size, bool overwriteOld) :
start(startAddress), write(startAddress), size(size),
overwriteOld(overwriteOld) {
for (uint8_t count = 0; count < N_READ_PTRS; count++) {
read[count] = startAddress;
}
}
virtual ~RingBufferBase() {}
bool isFull(uint8_t n = 0) {
return (availableWriteSpace(n) == 0);
}
bool isEmpty(uint8_t n = 0) {
return (getAvailableReadData(n) == 0);
}
size_t getAvailableReadData(uint8_t n = 0) const {
return ((write + size) - read[n]) % size;
}
size_t availableWriteSpace(uint8_t n = 0) const {
//One less to avoid ambiguous full/empty problem.
return (((read[n] + size) - write - 1) % size);
}
bool overwritesOld() const {
return overwriteOld;
}
size_t getMaxSize() const {
return size - 1;
}
void clear() {
write = start;
for (uint8_t count = 0; count < N_READ_PTRS; count++) {
read[count] = start;
}
}
size_t writeTillWrap() {
return (start + size) - write;
}
size_t readTillWrap(uint8_t n = 0) {
return (start + size) - read[n];
}
size_t getStart() const {
return start;
}
protected:
const size_t start;
size_t write;
size_t read[N_READ_PTRS];
const size_t size;
const bool overwriteOld;
void incrementWrite(uint32_t amount) {
write = ((write + amount - start) % size) + start;
}
void incrementRead(uint32_t amount, uint8_t n = 0) {
read[n] = ((read[n] + amount - start) % size) + start;
}
ReturnValue_t readData(uint32_t amount, uint8_t n = 0) {
if (getAvailableReadData(n) >= amount) {
incrementRead(amount, n);
return HasReturnvaluesIF::RETURN_OK;
} else {
return HasReturnvaluesIF::RETURN_FAILED;
}
}
ReturnValue_t writeData(uint32_t amount) {
if (availableWriteSpace() >= amount or overwriteOld) {
incrementWrite(amount);
return HasReturnvaluesIF::RETURN_OK;
} else {
return HasReturnvaluesIF::RETURN_FAILED;
}
}
size_t getRead(uint8_t n = 0) const {
return read[n];
}
void setRead(uint32_t read, uint8_t n = 0) {
if (read >= start && read < (start+size)) {
this->read[n] = read;
}
}
uint32_t getWrite() const {
return write;
}
void setWrite(uint32_t write) {
this->write = write;
}
};
#endif /* FSFW_CONTAINER_RINGBUFFERBASE_H_ */

View File

@ -0,0 +1,55 @@
#include "SharedRingBuffer.h"
#include "../ipc/MutexFactory.h"
#include "../ipc/MutexHelper.h"
SharedRingBuffer::SharedRingBuffer(object_id_t objectId, const size_t size,
bool overwriteOld, size_t maxExcessBytes):
SystemObject(objectId), SimpleRingBuffer(size, overwriteOld,
maxExcessBytes) {
mutex = MutexFactory::instance()->createMutex();
}
SharedRingBuffer::SharedRingBuffer(object_id_t objectId, uint8_t *buffer,
const size_t size, bool overwriteOld, size_t maxExcessBytes):
SystemObject(objectId), SimpleRingBuffer(buffer, size, overwriteOld,
maxExcessBytes) {
mutex = MutexFactory::instance()->createMutex();
}
void SharedRingBuffer::setToUseReceiveSizeFIFO(size_t fifoDepth) {
this->fifoDepth = fifoDepth;
}
ReturnValue_t SharedRingBuffer::lockRingBufferMutex(
MutexIF::TimeoutType timeoutType, dur_millis_t timeout) {
return mutex->lockMutex(timeoutType, timeout);
}
ReturnValue_t SharedRingBuffer::unlockRingBufferMutex() {
return mutex->unlockMutex();
}
MutexIF* SharedRingBuffer::getMutexHandle() const {
return mutex;
}
ReturnValue_t SharedRingBuffer::initialize() {
if(fifoDepth > 0) {
receiveSizesFIFO = new DynamicFIFO<size_t>(fifoDepth);
}
return SystemObject::initialize();
}
DynamicFIFO<size_t>* SharedRingBuffer::getReceiveSizesFIFO() {
if(receiveSizesFIFO == nullptr) {
// Configuration error.
sif::warning << "SharedRingBuffer::getReceiveSizesFIFO: Ring buffer"
<< " was not configured to have sizes FIFO, returning nullptr!"
<< std::endl;
}
return receiveSizesFIFO;
}

View File

@ -0,0 +1,92 @@
#ifndef FSFW_CONTAINER_SHAREDRINGBUFFER_H_
#define FSFW_CONTAINER_SHAREDRINGBUFFER_H_
#include "SimpleRingBuffer.h"
#include "DynamicFIFO.h"
#include "../ipc/MutexIF.h"
#include "../objectmanager/SystemObject.h"
#include "../timemanager/Clock.h"
/**
* @brief Ring buffer which can be shared among multiple objects
* @details
* This class offers a mutex to perform thread-safe operation on the ring
* buffer. It is still up to the developer to actually perform the lock
* and unlock operations.
*/
class SharedRingBuffer: public SystemObject,
public SimpleRingBuffer {
public:
/**
* This constructor allocates a new internal buffer with the supplied size.
* @param size
* @param overwriteOld
* If the ring buffer is overflowing at a write operartion, the oldest data
* will be overwritten.
*/
SharedRingBuffer(object_id_t objectId, const size_t size,
bool overwriteOld, size_t maxExcessBytes);
/**
* @brief This function can be used to add an optional FIFO to the class
* @details
* This FIFO will be allocated in the initialize function (and will
* have a fixed maximum size after that). It can be used to store
* values like packet sizes, for example for a shared ring buffer
* used by producer/consumer tasks.
*/
void setToUseReceiveSizeFIFO(size_t fifoDepth);
/**
* This constructor takes an external buffer with the specified size.
* @param buffer
* @param size
* @param overwriteOld
* If the ring buffer is overflowing at a write operartion, the oldest data
* will be overwritten.
*/
SharedRingBuffer(object_id_t objectId, uint8_t* buffer, const size_t size,
bool overwriteOld, size_t maxExcessBytes);
/**
* Unless a read-only constant value is read, all operations on the
* shared ring buffer should be protected by calling this function.
* @param timeoutType
* @param timeout
* @return
*/
virtual ReturnValue_t lockRingBufferMutex(MutexIF::TimeoutType timeoutType,
dur_millis_t timeout);
/**
* Any locked mutex also has to be unlocked, otherwise, access to the
* shared ring buffer will be blocked.
* @return
*/
virtual ReturnValue_t unlockRingBufferMutex();
/**
* The mutex handle can be accessed directly, for example to perform
* the lock with the #MutexHelper for a RAII compliant lock operation.
* @return
*/
MutexIF* getMutexHandle() const;
ReturnValue_t initialize() override;
/**
* If the shared ring buffer was configured to have a sizes FIFO, a handle
* to that FIFO can be retrieved with this function.
* Do not forget to protect access with a lock if required!
* @return
*/
DynamicFIFO<size_t>* getReceiveSizesFIFO();
private:
MutexIF* mutex = nullptr;
size_t fifoDepth = 0;
DynamicFIFO<size_t>* receiveSizesFIFO = nullptr;
};
#endif /* FSFW_CONTAINER_SHAREDRINGBUFFER_H_ */

View File

@ -0,0 +1,131 @@
#include "SimpleRingBuffer.h"
#include <cstring>
SimpleRingBuffer::SimpleRingBuffer(const size_t size, bool overwriteOld,
size_t maxExcessBytes) :
RingBufferBase<>(0, size, overwriteOld),
maxExcessBytes(maxExcessBytes) {
if(maxExcessBytes > size) {
this->maxExcessBytes = size;
}
else {
this->maxExcessBytes = maxExcessBytes;
}
buffer = new uint8_t[size + maxExcessBytes];
}
SimpleRingBuffer::SimpleRingBuffer(uint8_t *buffer, const size_t size,
bool overwriteOld, size_t maxExcessBytes):
RingBufferBase<>(0, size, overwriteOld), buffer(buffer) {
if(maxExcessBytes > size) {
this->maxExcessBytes = size;
}
else {
this->maxExcessBytes = maxExcessBytes;
}
}
SimpleRingBuffer::~SimpleRingBuffer() {
delete[] buffer;
}
ReturnValue_t SimpleRingBuffer::getFreeElement(uint8_t **writePointer,
size_t amount) {
if (availableWriteSpace() >= amount or overwriteOld) {
size_t amountTillWrap = writeTillWrap();
if (amountTillWrap < amount) {
if((amount - amountTillWrap + excessBytes) > maxExcessBytes) {
return HasReturnvaluesIF::RETURN_FAILED;
}
excessBytes = amount - amountTillWrap;
}
*writePointer = &buffer[write];
return HasReturnvaluesIF::RETURN_OK;
}
else {
return HasReturnvaluesIF::RETURN_FAILED;
}
}
void SimpleRingBuffer::confirmBytesWritten(size_t amount) {
if(getExcessBytes() > 0) {
moveExcessBytesToStart();
}
incrementWrite(amount);
}
ReturnValue_t SimpleRingBuffer::writeData(const uint8_t* data,
size_t amount) {
if (availableWriteSpace() >= amount or overwriteOld) {
size_t amountTillWrap = writeTillWrap();
if (amountTillWrap >= amount) {
// remaining size in buffer is sufficient to fit full amount.
memcpy(&buffer[write], data, amount);
}
else {
memcpy(&buffer[write], data, amountTillWrap);
memcpy(buffer, data + amountTillWrap, amount - amountTillWrap);
}
incrementWrite(amount);
return HasReturnvaluesIF::RETURN_OK;
} else {
return HasReturnvaluesIF::RETURN_FAILED;
}
}
ReturnValue_t SimpleRingBuffer::readData(uint8_t* data, size_t amount,
bool incrementReadPtr, bool readRemaining, size_t* trueAmount) {
size_t availableData = getAvailableReadData(READ_PTR);
size_t amountTillWrap = readTillWrap(READ_PTR);
if (availableData < amount) {
if (readRemaining) {
// more data available than amount specified.
amount = availableData;
} else {
return HasReturnvaluesIF::RETURN_FAILED;
}
}
if (trueAmount != nullptr) {
*trueAmount = amount;
}
if (amountTillWrap >= amount) {
memcpy(data, &buffer[read[READ_PTR]], amount);
} else {
memcpy(data, &buffer[read[READ_PTR]], amountTillWrap);
memcpy(data + amountTillWrap, buffer, amount - amountTillWrap);
}
if(incrementReadPtr) {
deleteData(amount, readRemaining);
}
return HasReturnvaluesIF::RETURN_OK;
}
size_t SimpleRingBuffer::getExcessBytes() const {
return excessBytes;
}
void SimpleRingBuffer::moveExcessBytesToStart() {
if(excessBytes > 0) {
std::memcpy(buffer, &buffer[size], excessBytes);
excessBytes = 0;
}
}
ReturnValue_t SimpleRingBuffer::deleteData(size_t amount,
bool deleteRemaining, size_t* trueAmount) {
size_t availableData = getAvailableReadData(READ_PTR);
if (availableData < amount) {
if (deleteRemaining) {
amount = availableData;
} else {
return HasReturnvaluesIF::RETURN_FAILED;
}
}
if (trueAmount != nullptr) {
*trueAmount = amount;
}
incrementRead(amount, READ_PTR);
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -0,0 +1,129 @@
#ifndef FSFW_CONTAINER_SIMPLERINGBUFFER_H_
#define FSFW_CONTAINER_SIMPLERINGBUFFER_H_
#include "RingBufferBase.h"
#include <cstddef>
/**
* @brief Circular buffer implementation, useful for buffering
* into data streams.
* @details
* Note that the deleteData() has to be called to increment the read pointer.
* This class allocated dynamically, so
* @ingroup containers
*/
class SimpleRingBuffer: public RingBufferBase<> {
public:
/**
* This constructor allocates a new internal buffer with the supplied size.
*
* @param size
* @param overwriteOld If the ring buffer is overflowing at a write
* operation, the oldest data will be overwritten.
* @param maxExcessBytes These additional bytes will be allocated in addtion
* to the specified size to accomodate contiguous write operations
* with getFreeElement.
*
*/
SimpleRingBuffer(const size_t size, bool overwriteOld,
size_t maxExcessBytes = 0);
/**
* This constructor takes an external buffer with the specified size.
* @param buffer
* @param size
* @param overwriteOld
* If the ring buffer is overflowing at a write operartion, the oldest data
* will be overwritten.
* @param maxExcessBytes
* If the buffer can accomodate additional bytes for contigous write
* operations with getFreeElement, this is the maximum allowed additional
* size
*/
SimpleRingBuffer(uint8_t* buffer, const size_t size, bool overwriteOld,
size_t maxExcessBytes = 0);
virtual ~SimpleRingBuffer();
/**
* Write to circular buffer and increment write pointer by amount.
* @param data
* @param amount
* @return -@c RETURN_OK if write operation was successfull
* -@c RETURN_FAILED if
*/
ReturnValue_t writeData(const uint8_t* data, size_t amount);
/**
* Returns a pointer to a free element. If the remaining buffer is
* not large enough, the data will be written past the actual size
* and the amount of excess bytes will be cached. This function
* does not increment the write pointer!
* @param writePointer Pointer to a pointer which can be used to write
* contiguous blocks into the ring buffer
* @param amount
* @return
*/
ReturnValue_t getFreeElement(uint8_t** writePointer, size_t amount);
/**
* This increments the write pointer and also copies the excess bytes
* to the beginning. It should be called if the write operation
* conducted after calling getFreeElement() was performed.
* @return
*/
void confirmBytesWritten(size_t amount);
virtual size_t getExcessBytes() const;
/**
* Helper functions which moves any excess bytes to the start
* of the ring buffer.
* @return
*/
virtual void moveExcessBytesToStart();
/**
* Read from circular buffer at read pointer.
* @param data
* @param amount
* @param incrementReadPtr
* If this is set to true, the read pointer will be incremented.
* If readRemaining is set to true, the read pointer will be incremented
* accordingly.
* @param readRemaining
* If this is set to true, the data will be read even if the amount
* specified exceeds the read data available.
* @param trueAmount [out]
* If readRemaining was set to true, the true amount read will be assigned
* to the passed value.
* @return
* - @c RETURN_OK if data was read successfully
* - @c RETURN_FAILED if not enough data was available and readRemaining
* was set to false.
*/
ReturnValue_t readData(uint8_t* data, size_t amount,
bool incrementReadPtr = false, bool readRemaining = false,
size_t* trueAmount = nullptr);
/**
* Delete data by incrementing read pointer.
* @param amount
* @param deleteRemaining
* If the amount specified is larger than the remaing size to read and this
* is set to true, the remaining amount will be deleted as well
* @param trueAmount [out]
* If deleteRemaining was set to true, the amount deleted will be assigned
* to the passed value.
* @return
*/
ReturnValue_t deleteData(size_t amount, bool deleteRemaining = false,
size_t* trueAmount = nullptr);
private:
static const uint8_t READ_PTR = 0;
uint8_t* buffer = nullptr;
size_t maxExcessBytes;
size_t excessBytes = 0;
};
#endif /* FSFW_CONTAINER_SIMPLERINGBUFFER_H_ */

View File

@ -0,0 +1,154 @@
#ifndef FRAMEWORK_CONTAINER_SINGLYLINKEDLIST_H_
#define FRAMEWORK_CONTAINER_SINGLYLINKEDLIST_H_
#include <cstddef>
#include <cstdint>
/**
* @brief Linked list data structure,
* each entry has a pointer to the next entry (singly)
* @ingroup container
*/
template<typename T>
class LinkedElement {
public:
T *value;
class Iterator {
public:
LinkedElement<T> *value = nullptr;
Iterator() {}
Iterator(LinkedElement<T> *element) :
value(element) {
}
Iterator& operator++() {
value = value->getNext();
return *this;
}
Iterator operator++(int) {
Iterator tmp(*this);
operator++();
return tmp;
}
bool operator==(Iterator other) {
return value == other.value;
}
bool operator!=(Iterator other) {
return !(*this == other);
}
T *operator->() {
return value->value;
}
};
LinkedElement(T* setElement, LinkedElement<T>* setNext = nullptr):
value(setElement), next(setNext) {}
virtual ~LinkedElement(){}
virtual LinkedElement* getNext() const {
return next;
}
virtual void setNext(LinkedElement* next) {
this->next = next;
}
virtual void setEnd() {
this->next = nullptr;
}
LinkedElement* begin() {
return this;
}
LinkedElement* end() {
return nullptr;
}
private:
LinkedElement *next;
};
template<typename T>
class SinglyLinkedList {
public:
using ElementIterator = typename LinkedElement<T>::Iterator;
SinglyLinkedList() {}
SinglyLinkedList(ElementIterator start) :
start(start.value) {}
SinglyLinkedList(LinkedElement<T>* startElement) :
start(startElement) {}
ElementIterator begin() const {
return ElementIterator::Iterator(start);
}
/** Returns iterator to nulltr */
ElementIterator end() const {
return ElementIterator::Iterator();
}
/**
* Returns last element in singly linked list.
* @return
*/
ElementIterator back() const {
LinkedElement<T> *element = start;
while (element->getNext() != nullptr) {
element = element->getNext();
}
return ElementIterator::Iterator(element);
}
size_t getSize() const {
size_t size = 0;
LinkedElement<T> *element = start;
while (element != nullptr) {
size++;
element = element->getNext();
}
return size;
}
void setStart(LinkedElement<T>* firstElement) {
start = firstElement;
}
void setNext(LinkedElement<T>* currentElement,
LinkedElement<T>* nextElement) {
currentElement->setNext(nextElement);
}
void setLast(LinkedElement<T>* lastElement) {
lastElement->setEnd();
}
void insertElement(LinkedElement<T>* element, size_t position) {
LinkedElement<T> *currentElement = start;
for(size_t count = 0; count < position; count++) {
if(currentElement == nullptr) {
return;
}
currentElement = currentElement->getNext();
}
LinkedElement<T>* elementAfterCurrent = currentElement->next;
currentElement->setNext(element);
if(elementAfterCurrent != nullptr) {
element->setNext(elementAfterCurrent);
}
}
void insertBack(LinkedElement<T>* lastElement) {
back().value->setNext(lastElement);
}
protected:
LinkedElement<T> *start = nullptr;
};
#endif /* SINGLYLINKEDLIST_H_ */

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_contrib)

View File

@ -1,11 +0,0 @@
if(FSFW_ADD_SGP4_PROPAGATOR)
target_sources(${LIB_FSFW_NAME} PRIVATE
sgp4/sgp4unit.cpp
)
target_include_directories(${LIB_FSFW_NAME} PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/sgp4
)
target_include_directories(${LIB_FSFW_NAME} INTERFACE
${CMAKE_CURRENT_SOURCE_DIR}/sgp4
)
endif()

View File

@ -0,0 +1,137 @@
#include "../subsystem/SubsystemBase.h"
#include "ControllerBase.h"
#include "../subsystem/SubsystemBase.h"
#include "../ipc/QueueFactory.h"
#include "../action/HasActionsIF.h"
ControllerBase::ControllerBase(uint32_t setObjectId, uint32_t parentId,
size_t commandQueueDepth) :
SystemObject(setObjectId), parentId(parentId), mode(MODE_OFF), submode(
SUBMODE_NONE), commandQueue(NULL), modeHelper(
this), healthHelper(this, setObjectId),hkSwitcher(this),executingTask(NULL) {
commandQueue = QueueFactory::instance()->createMessageQueue(commandQueueDepth);
}
ControllerBase::~ControllerBase() {
QueueFactory::instance()->deleteMessageQueue(commandQueue);
}
ReturnValue_t ControllerBase::initialize() {
ReturnValue_t result = SystemObject::initialize();
if (result != RETURN_OK) {
return result;
}
MessageQueueId_t parentQueue = 0;
if (parentId != 0) {
SubsystemBase *parent = objectManager->get<SubsystemBase>(parentId);
if (parent == NULL) {
return RETURN_FAILED;
}
parentQueue = parent->getCommandQueue();
parent->registerChild(getObjectId());
}
result = healthHelper.initialize(parentQueue);
if (result != RETURN_OK) {
return result;
}
result = modeHelper.initialize(parentQueue);
if (result != RETURN_OK) {
return result;
}
result = hkSwitcher.initialize();
if (result != RETURN_OK) {
return result;
}
return RETURN_OK;
}
MessageQueueId_t ControllerBase::getCommandQueue() const {
return commandQueue->getId();
}
void ControllerBase::handleQueue() {
CommandMessage message;
ReturnValue_t result;
for (result = commandQueue->receiveMessage(&message); result == RETURN_OK;
result = commandQueue->receiveMessage(&message)) {
result = modeHelper.handleModeCommand(&message);
if (result == RETURN_OK) {
continue;
}
result = healthHelper.handleHealthCommand(&message);
if (result == RETURN_OK) {
continue;
}
result = handleCommandMessage(&message);
if (result == RETURN_OK) {
continue;
}
message.setToUnknownCommand();
commandQueue->reply(&message);
}
}
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;
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::setToExternalControl() {
healthHelper.setHealth(EXTERNAL_CONTROL);
}
void ControllerBase::announceMode(bool recursive) {
triggerEvent(MODE_INFO, mode, submode);
}
ReturnValue_t ControllerBase::performOperation(uint8_t opCode) {
handleQueue();
hkSwitcher.performOperation();
performControlOperation();
return RETURN_OK;
}
void ControllerBase::modeChanged(Mode_t mode, Submode_t submode) {
return;
}
ReturnValue_t ControllerBase::setHealth(HealthState health) {
switch (health) {
case HEALTHY:
case EXTERNAL_CONTROL:
healthHelper.setHealth(health);
return RETURN_OK;
default:
return INVALID_HEALTH_STATE;
}
}
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) {
}

View File

@ -0,0 +1,79 @@
#ifndef CONTROLLERBASE_H_
#define CONTROLLERBASE_H_
#include "../health/HasHealthIF.h"
#include "../health/HealthHelper.h"
#include "../modes/HasModesIF.h"
#include "../modes/ModeHelper.h"
#include "../objectmanager/SystemObject.h"
#include "../tasks/ExecutableObjectIF.h"
#include "../datapool/HkSwitchHelper.h"
class ControllerBase: public HasModesIF,
public HasHealthIF,
public ExecutableObjectIF,
public SystemObject,
public HasReturnvaluesIF {
public:
static const Mode_t MODE_NORMAL = 2;
ControllerBase(uint32_t setObjectId, uint32_t parentId,
size_t commandQueueDepth = 3);
virtual ~ControllerBase();
ReturnValue_t initialize();
virtual MessageQueueId_t getCommandQueue() const;
virtual ReturnValue_t performOperation(uint8_t opCode);
virtual ReturnValue_t setHealth(HealthState health);
virtual HasHealthIF::HealthState getHealth();
/**
* Implementation of ExecutableObjectIF function
*
* Used to setup the reference of the task, that executes this component
* @param task_ Pointer to the taskIF of this task
*/
virtual void setTaskIF(PeriodicTaskIF* task_);
protected:
const uint32_t parentId;
Mode_t mode;
Submode_t submode;
MessageQueueIF* commandQueue;
ModeHelper modeHelper;
HealthHelper healthHelper;
HkSwitchHelper hkSwitcher;
/**
* Pointer to the task which executes this component, is invalid before setTaskIF was called.
*/
PeriodicTaskIF* executingTask;
void handleQueue();
virtual ReturnValue_t handleCommandMessage(CommandMessage *message) = 0;
virtual void performControlOperation() = 0;
virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
uint32_t *msToReachTheMode) = 0;
virtual void modeChanged(Mode_t mode, Submode_t submode);
virtual void startTransition(Mode_t mode, Submode_t submode);
virtual void getMode(Mode_t *mode, Submode_t *submode);
virtual void setToExternalControl();
virtual void announceMode(bool recursive);
virtual void changeHK(Mode_t mode, Submode_t submode, bool enable);
};
#endif /* CONTROLLERBASE_H_ */

View File

@ -1,9 +1,8 @@
#include "fsfw/coordinates/CoordinateTransformations.h"
#include "fsfw/globalfunctions/constants.h"
#include "fsfw/globalfunctions/math/MatrixOperations.h"
#include "fsfw/globalfunctions/math/VectorOperations.h"
#include <cstddef>
#include "CoordinateTransformations.h"
#include "../globalfunctions/constants.h"
#include "../globalfunctions/math/MatrixOperations.h"
#include "../globalfunctions/math/VectorOperations.h"
#include <stddef.h>
#include <cmath>
@ -18,13 +17,11 @@ void CoordinateTransformations::velocityEcfToEci(const double* ecfVelocity,
ecfToEci(ecfVelocity, eciVelocity, ecfPosition, timeUTC);
}
void CoordinateTransformations::positionEciToEcf(const double* eciCoordinates,
double* ecfCoordinates,timeval *timeUTC){
void CoordinateTransformations::positionEciToEcf(const double* eciCoordinates, double* ecfCoordinates,timeval *timeUTC){
eciToEcf(eciCoordinates,ecfCoordinates,NULL,timeUTC);
};
void CoordinateTransformations::velocityEciToEcf(const double* eciVelocity,
const double* eciPosition, double* ecfVelocity,timeval* timeUTC){
void CoordinateTransformations::velocityEciToEcf(const double* eciVelocity,const double* eciPosition, double* ecfVelocity,timeval* timeUTC){
eciToEcf(eciVelocity,ecfVelocity,eciPosition,timeUTC);
}

View File

@ -1,8 +1,7 @@
#ifndef COORDINATETRANSFORMATIONS_H_
#define COORDINATETRANSFORMATIONS_H_
#include "coordinatesConf.h"
#include "fsfw/timemanager/Clock.h"
#include "../timemanager/Clock.h"
#include <cstring>
class CoordinateTransformations {

View File

@ -1,14 +1,13 @@
#ifndef FRAMEWORK_COORDINATES_JGM3MODEL_H_
#define FRAMEWORK_COORDINATES_JGM3MODEL_H_
#include "coordinatesConf.h"
#include <stdint.h>
#include "CoordinateTransformations.h"
#include "fsfw/globalfunctions/math/VectorOperations.h"
#include "fsfw/globalfunctions/timevalOperations.h"
#include "fsfw/globalfunctions/constants.h"
#include "../globalfunctions/math/VectorOperations.h"
#include "../globalfunctions/timevalOperations.h"
#include "../globalfunctions/constants.h"
#include <memory.h>
#include <cstdint>
template<uint8_t DEGREE,uint8_t ORDER>
class Jgm3Model {

View File

@ -1,13 +1,10 @@
#include "fsfw/coordinates/CoordinateTransformations.h"
#include "fsfw/coordinates/Sgp4Propagator.h"
#include "fsfw/globalfunctions/constants.h"
#include "fsfw/globalfunctions/math/MatrixOperations.h"
#include "fsfw/globalfunctions/math/VectorOperations.h"
#include "fsfw/globalfunctions/timevalOperations.h"
#include "CoordinateTransformations.h"
#include "Sgp4Propagator.h"
#include "../globalfunctions/constants.h"
#include "../globalfunctions/math/MatrixOperations.h"
#include "../globalfunctions/math/VectorOperations.h"
#include "../globalfunctions/timevalOperations.h"
#include <cstring>
Sgp4Propagator::Sgp4Propagator() :
initialized(false), epoch({0, 0}), whichconst(wgs84) {

View File

@ -1,14 +1,9 @@
#ifndef SGP4PROPAGATOR_H_
#define SGP4PROPAGATOR_H_
#include "coordinatesConf.h"
#include "fsfw/platform.h"
#ifndef PLATFORM_WIN
#include <sys/time.h>
#endif
#include "fsfw_contrib/sgp4/sgp4unit.h"
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
#include "../contrib/sgp4/sgp4unit.h"
#include "../returnvalues/HasReturnvaluesIF.h"
class Sgp4Propagator {
public:

View File

@ -8,7 +8,6 @@
#ifndef BCFRAME_H_
#define BCFRAME_H_
#include "dllConf.h"
#include "CCSDSReturnValuesIF.h"
/**

View File

@ -8,8 +8,7 @@
#ifndef CCSDSRETURNVALUESIF_H_
#define CCSDSRETURNVALUESIF_H_
#include "dllConf.h"
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
#include "../returnvalues/HasReturnvaluesIF.h"
/**
* This is a helper class to collect special return values that come up during CCSDS Handling.
* @ingroup ccsds_handling

View File

@ -1,5 +1,14 @@
#include "fsfw/datalinklayer/Clcw.h"
#include "fsfw/serviceinterface/ServiceInterface.h"
/**
* @file Clcw.cpp
* @brief This file defines the Clcw class.
* @date 17.04.2013
* @author baetz
*/
#include "Clcw.h"
#include "../serviceinterface/ServiceInterfaceStream.h"
Clcw::Clcw() {
content.raw = 0;
@ -46,9 +55,7 @@ void Clcw::setBitLock(bool bitLock) {
}
void Clcw::print() {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "Clcw::print: Clcw is: " << std::hex << getAsWhole() << std::dec << std::endl;
#endif
}
void Clcw::setWhole(uint32_t rawClcw) {

View File

@ -1,9 +1,14 @@
/**
* @file Clcw.h
* @brief This file defines the Clcw class.
* @date 17.04.2013
* @author baetz
*/
#ifndef CLCW_H_
#define CLCW_H_
#include "dllConf.h"
#include "ClcwIF.h"
/**
* Small helper method to handle the Clcw values.
* It has a content struct that manages the register and can be set externally.

View File

@ -1,6 +1,6 @@
#include "fsfw/datalinklayer/DataLinkLayer.h"
#include "fsfw/globalfunctions/CRC.h"
#include "fsfw/serviceinterface/ServiceInterface.h"
#include "DataLinkLayer.h"
#include "../globalfunctions/CRC.h"
#include "../serviceinterface/ServiceInterfaceStream.h"
DataLinkLayer::DataLinkLayer(uint8_t* set_frame_buffer, ClcwIF* setClcw,
uint8_t set_start_sequence_length, uint16_t set_scid) :
@ -98,10 +98,8 @@ ReturnValue_t DataLinkLayer::processFrame(uint16_t length) {
receivedDataLength = length;
ReturnValue_t status = allFramesReception();
if (status != RETURN_OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "DataLinkLayer::processFrame: frame reception failed. "
"Error code: " << std::hex << status << std::dec << std::endl;
#endif
// currentFrame.print();
return status;
} else {
@ -126,9 +124,7 @@ ReturnValue_t DataLinkLayer::initialize() {
if ( virtualChannels.begin() != virtualChannels.end() ) {
clcw->setVirtualChannel( virtualChannels.begin()->second->getChannelId() );
} else {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "DataLinkLayer::initialize: No VC assigned to this DLL instance! " << std::endl;
#endif
return RETURN_FAILED;
}

View File

@ -1,13 +1,11 @@
#ifndef DATALINKLAYER_H_
#define DATALINKLAYER_H_
#include "dllConf.h"
#include "CCSDSReturnValuesIF.h"
#include "ClcwIF.h"
#include "TcTransferFrame.h"
#include "VirtualChannelReceptionIF.h"
#include "fsfw/events/Event.h"
#include "../events/Event.h"
#include <map>
@ -21,18 +19,12 @@ class VirtualChannelReception;
class DataLinkLayer : public CCSDSReturnValuesIF {
public:
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::SYSTEM_1;
//! [EXPORT] : [COMMENT] A RF available signal was detected. P1: raw RFA state, P2: 0
static const Event RF_AVAILABLE = MAKE_EVENT(0, severity::INFO);
//! [EXPORT] : [COMMENT] A previously found RF available signal was lost.
//! P1: raw RFA state, P2: 0
static const Event RF_LOST = MAKE_EVENT(1, severity::INFO);
//! [EXPORT] : [COMMENT] A Bit Lock signal. Was detected. P1: raw BLO state, P2: 0
static const Event BIT_LOCK = MAKE_EVENT(2, severity::INFO);
//! [EXPORT] : [COMMENT] A previously found Bit Lock signal was lost. P1: raw BLO state, P2: 0
static const Event BIT_LOCK_LOST = MAKE_EVENT(3, severity::INFO);
// static const Event RF_CHAIN_LOST = MAKE_EVENT(4, severity::INFO); //!< The CCSDS Board detected that either bit lock or RF available or both are lost. No parameters.
//! [EXPORT] : [COMMENT] The CCSDS Board could not interpret a TC
static const Event FRAME_PROCESSING_FAILED = MAKE_EVENT(5, severity::LOW);
static const Event RF_AVAILABLE = MAKE_EVENT(0, SEVERITY::INFO); //!< A RF available signal was detected. P1: raw RFA state, P2: 0
static const Event RF_LOST = MAKE_EVENT(1, SEVERITY::INFO); //!< A previously found RF available signal was lost. P1: raw RFA state, P2: 0
static const Event BIT_LOCK = MAKE_EVENT(2, SEVERITY::INFO); //!< A Bit Lock signal. Was detected. P1: raw BLO state, P2: 0
static const Event BIT_LOCK_LOST = MAKE_EVENT(3, SEVERITY::INFO); //!< A previously found Bit Lock signal was lost. P1: raw BLO state, P2: 0
// static const Event RF_CHAIN_LOST = MAKE_EVENT(4, SEVERITY::INFO); //!< The CCSDS Board detected that either bit lock or RF available or both are lost. No parameters.
static const Event FRAME_PROCESSING_FAILED = MAKE_EVENT(5, SEVERITY::LOW); //!< The CCSDS Board could not interpret a TC
/**
* The Constructor sets the passed parameters and nothing else.
* @param set_frame_buffer The buffer in which incoming frame candidates are stored.

View File

@ -8,9 +8,7 @@
#ifndef FARM1STATEIF_H_
#define FARM1STATEIF_H_
#include "dllConf.h"
#include "CCSDSReturnValuesIF.h"
class VirtualChannelReception;
class TcTransferFrame;
class ClcwIF;

View File

@ -1,8 +1,16 @@
#include "fsfw/datalinklayer/ClcwIF.h"
#include "fsfw/datalinklayer/Farm1StateLockout.h"
#include "fsfw/datalinklayer/TcTransferFrame.h"
#include "fsfw/datalinklayer/VirtualChannelReception.h"
/**
* @file Farm1StateLockout.cpp
* @brief This file defines the Farm1StateLockout class.
* @date 24.04.2013
* @author baetz
*/
#include "ClcwIF.h"
#include "Farm1StateLockout.h"
#include "TcTransferFrame.h"
#include "VirtualChannelReception.h"
Farm1StateLockout::Farm1StateLockout(VirtualChannelReception* setMyVC) : myVC(setMyVC) {
}

View File

@ -1,7 +1,13 @@
/**
* @file Farm1StateLockout.h
* @brief This file defines the Farm1StateLockout class.
* @date 24.04.2013
* @author baetz
*/
#ifndef FARM1STATELOCKOUT_H_
#define FARM1STATELOCKOUT_H_
#include "dllConf.h"
#include "Farm1StateIF.h"
/**

View File

@ -1,7 +1,17 @@
#include "fsfw/datalinklayer/ClcwIF.h"
#include "fsfw/datalinklayer/Farm1StateOpen.h"
#include "fsfw/datalinklayer/TcTransferFrame.h"
#include "fsfw/datalinklayer/VirtualChannelReception.h"
/**
* @file Farm1StateOpen.cpp
* @brief This file defines the Farm1StateOpen class.
* @date 24.04.2013
* @author baetz
*/
#include "ClcwIF.h"
#include "Farm1StateOpen.h"
#include "TcTransferFrame.h"
#include "VirtualChannelReception.h"
Farm1StateOpen::Farm1StateOpen(VirtualChannelReception* setMyVC) : myVC(setMyVC) {
}

View File

@ -8,7 +8,6 @@
#ifndef FARM1STATEOPEN_H_
#define FARM1STATEOPEN_H_
#include "dllConf.h"
#include "Farm1StateIF.h"
/**

View File

@ -1,7 +1,15 @@
#include "fsfw/datalinklayer/ClcwIF.h"
#include "fsfw/datalinklayer/Farm1StateWait.h"
#include "fsfw/datalinklayer/TcTransferFrame.h"
#include "fsfw/datalinklayer/VirtualChannelReception.h"
/**
* @file Farm1StateWait.cpp
* @brief This file defines the Farm1StateWait class.
* @date 24.04.2013
* @author baetz
*/
#include "ClcwIF.h"
#include "Farm1StateWait.h"
#include "TcTransferFrame.h"
#include "VirtualChannelReception.h"
Farm1StateWait::Farm1StateWait(VirtualChannelReception* setMyVC) : myVC(setMyVC) {
}

View File

@ -8,7 +8,6 @@
#ifndef FARM1STATEWAIT_H_
#define FARM1STATEWAIT_H_
#include "dllConf.h"
#include "Farm1StateIF.h"
/**

View File

@ -1,21 +1,25 @@
#include "fsfw/datalinklayer/MapPacketExtraction.h"
/**
* @file MapPacketExtraction.cpp
* @brief This file defines the MapPacketExtraction class.
* @date 26.03.2013
* @author baetz
*/
#include "fsfw/ipc/QueueFactory.h"
#include "fsfw/serviceinterface/ServiceInterface.h"
#include "fsfw/storagemanager/StorageManagerIF.h"
#include "fsfw/tmtcpacket/SpacePacketBase.h"
#include "fsfw/tmtcservices/AcceptsTelecommandsIF.h"
#include "fsfw/tmtcservices/TmTcMessage.h"
#include "fsfw/objectmanager/ObjectManager.h"
#include <cstring>
#include "MapPacketExtraction.h"
#include "../ipc/QueueFactory.h"
#include "../serviceinterface/ServiceInterfaceStream.h"
#include "../storagemanager/StorageManagerIF.h"
#include "../tmtcpacket/SpacePacketBase.h"
#include "../tmtcservices/AcceptsTelecommandsIF.h"
#include "../tmtcservices/TmTcMessage.h"
#include <string.h>
MapPacketExtraction::MapPacketExtraction(uint8_t setMapId,
object_id_t setPacketDestination) :
lastSegmentationFlag(NO_SEGMENTATION), mapId(setMapId),
bufferPosition(packetBuffer), packetDestination(setPacketDestination),
tcQueueId(MessageQueueIF::NO_QUEUE) {
std::memset(packetBuffer, 0, sizeof(packetBuffer));
lastSegmentationFlag(NO_SEGMENTATION), mapId(setMapId), packetLength(0), bufferPosition(
packetBuffer), packetDestination(setPacketDestination), packetStore(
NULL), tcQueueId(MessageQueueIF::NO_QUEUE) {
memset(packetBuffer, 0, sizeof(packetBuffer));
}
ReturnValue_t MapPacketExtraction::extractPackets(TcTransferFrame* frame) {
@ -32,11 +36,9 @@ ReturnValue_t MapPacketExtraction::extractPackets(TcTransferFrame* frame) {
bufferPosition = &packetBuffer[packetLength];
status = RETURN_OK;
} else {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error
<< "MapPacketExtraction::extractPackets. Packet too large! Size: "
<< packetLength << std::endl;
#endif
clearBuffers();
status = CONTENT_TOO_LARGE;
}
@ -56,30 +58,24 @@ ReturnValue_t MapPacketExtraction::extractPackets(TcTransferFrame* frame) {
}
status = RETURN_OK;
} else {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error
<< "MapPacketExtraction::extractPackets. Packet too large! Size: "
<< packetLength << std::endl;
#endif
clearBuffers();
status = CONTENT_TOO_LARGE;
}
} else {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error
<< "MapPacketExtraction::extractPackets. Illegal segment! Last flag: "
<< (int) lastSegmentationFlag << std::endl;
#endif
clearBuffers();
status = ILLEGAL_SEGMENTATION_FLAG;
}
break;
default:
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error
<< "MapPacketExtraction::extractPackets. Illegal segmentationFlag: "
<< (int) segmentationFlag << std::endl;
#endif
clearBuffers();
status = DATA_CORRUPTED;
break;
@ -134,9 +130,9 @@ void MapPacketExtraction::clearBuffers() {
}
ReturnValue_t MapPacketExtraction::initialize() {
packetStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TC_STORE);
AcceptsTelecommandsIF* distributor = ObjectManager::instance()->
get<AcceptsTelecommandsIF>(packetDestination);
packetStore = objectManager->get<StorageManagerIF>(objects::TC_STORE);
AcceptsTelecommandsIF* distributor = objectManager->get<
AcceptsTelecommandsIF>(packetDestination);
if ((packetStore != NULL) && (distributor != NULL)) {
tcQueueId = distributor->getRequestQueue();
return RETURN_OK;
@ -146,14 +142,10 @@ ReturnValue_t MapPacketExtraction::initialize() {
}
void MapPacketExtraction::printPacketBuffer(void) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "DLL: packet_buffer contains: " << std::endl;
#endif
for (uint32_t i = 0; i < this->packetLength; ++i) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "packet_buffer[" << std::dec << i << "]: 0x" << std::hex
<< (uint16_t) this->packetBuffer[i] << std::endl;
#endif
}
}

View File

@ -1,11 +1,17 @@
#ifndef FSFW_DATALINKLAYER_MAPPACKETEXTRACTION_H_
#define FSFW_DATALINKLAYER_MAPPACKETEXTRACTION_H_
/**
* @file MapPacketExtraction.h
* @brief This file defines the MapPacketExtraction class.
* @date 26.03.2013
* @author baetz
*/
#ifndef MAPPACKETEXTRACTION_H_
#define MAPPACKETEXTRACTION_H_
#include "dllConf.h"
#include "MapPacketExtractionIF.h"
#include "fsfw/objectmanager/ObjectManagerIF.h"
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
#include "fsfw/ipc/MessageQueueSenderIF.h"
#include "../objectmanager/ObjectManagerIF.h"
#include "../returnvalues/HasReturnvaluesIF.h"
#include "../ipc/MessageQueueSenderIF.h"
class StorageManagerIF;
@ -14,19 +20,17 @@ class StorageManagerIF;
* The class implements the full MAP Packet Extraction functionality as described in the CCSDS
* TC Space Data Link Protocol. It internally stores incomplete segmented packets until they are
* fully received. All found packets are forwarded to a single distribution entity.
* @author B. Baetz
*/
class MapPacketExtraction: public MapPacketExtractionIF {
private:
static const uint32_t MAX_PACKET_SIZE = 4096;
uint8_t lastSegmentationFlag; //!< The segmentation flag of the last received frame.
uint8_t mapId; //!< MAP ID of this MAP Channel.
uint32_t packetLength = 0; //!< Complete length of the current Space Packet.
uint32_t packetLength; //!< Complete length of the current Space Packet.
uint8_t* bufferPosition; //!< Position to write to in the internal Packet buffer.
uint8_t packetBuffer[MAX_PACKET_SIZE]; //!< The internal Space Packet Buffer.
object_id_t packetDestination;
//!< Pointer to the store where full TC packets are stored.
StorageManagerIF* packetStore = nullptr;
StorageManagerIF* packetStore; //!< Pointer to the store where full TC packets are stored.
MessageQueueId_t tcQueueId; //!< QueueId to send found packets to the distributor.
/**
* Debug method to print the packet Buffer's content.
@ -71,4 +75,4 @@ public:
uint8_t getMapId() const;
};
#endif /* FSFW_DATALINKLAYER_MAPPACKETEXTRACTION_H_ */
#endif /* MAPPACKETEXTRACTION_H_ */

View File

@ -8,7 +8,6 @@
#ifndef MAPPACKETEXTRACTIONIF_H_
#define MAPPACKETEXTRACTIONIF_H_
#include "dllConf.h"
#include "CCSDSReturnValuesIF.h"
#include "TcTransferFrame.h"

View File

@ -1,8 +1,17 @@
#include "fsfw/datalinklayer/TcTransferFrame.h"
#include "fsfw/serviceinterface/ServiceInterface.h"
/**
* @file TcTransferFrame.cpp
* @brief This file defines the TcTransferFrame class.
* @date 27.04.2013
* @author baetz
*/
#include "TcTransferFrame.h"
#include "../serviceinterface/ServiceInterfaceStream.h"
TcTransferFrame::TcTransferFrame() {
frame = nullptr;
frame = NULL;
}
TcTransferFrame::TcTransferFrame(uint8_t* setData) {
@ -78,25 +87,16 @@ uint8_t* TcTransferFrame::getFullDataField() {
}
void TcTransferFrame::print() {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "Raw Frame: " << std::hex << std::endl;
for (uint16_t count = 0; count < this->getFullSize(); count++ ) {
sif::debug << (uint16_t)this->getFullFrame()[count] << " ";
}
sif::debug << std::dec << std::endl;
sif::debug << "Frame Header:" << std::endl;
sif::debug << "Version Number: " << std::hex
<< (uint16_t)this->getVersionNumber() << std::endl;
sif::debug << "Bypass Flag set?| Ctrl Cmd Flag set?: "
<< (uint16_t)this->bypassFlagSet() << " | "
<< (uint16_t)this->controlCommandFlagSet() << std::endl;
sif::debug << "SCID : " << this->getSpacecraftId() << std::endl;
sif::debug << "VCID : " << (uint16_t)this->getVirtualChannelId()
<< std::endl;
sif::debug << "Frame length: " << std::dec << this->getFrameLength()
<< std::endl;
sif::debug << "Sequence Number: " << (uint16_t)this->getSequenceNumber()
<< std::endl;
#endif
// debug << "Frame Header:" << std::endl;
// debug << "Version Number: " << std::hex << (uint16_t)this->current_frame.getVersionNumber() << std::endl;
// debug << "Bypass Flag set?| Ctrl Cmd Flag set?: " << (uint16_t)this->current_frame.bypassFlagSet() << " | " << (uint16_t)this->current_frame.controlCommandFlagSet() << std::endl;
// debug << "SCID : " << this->current_frame.getSpacecraftId() << std::endl;
// debug << "VCID : " << (uint16_t)this->current_frame.getVirtualChannelId() << std::endl;
// debug << "Frame length: " << std::dec << this->current_frame.getFrameLength() << std::endl;
// debug << "Sequence Number: " << (uint16_t)this->current_frame.getSequenceNumber() << std::endl;
}

View File

@ -1,10 +1,8 @@
#ifndef TCTRANSFERFRAME_H_
#define TCTRANSFERFRAME_H_
#include "dllConf.h"
#include <cstdint>
#include <cstddef>
#include <stdint.h>
#include <stddef.h>
/**
* The TcTransferFrame class simplifies handling of such Frames.

View File

@ -1,8 +1,14 @@
#include "fsfw/datalinklayer/TcTransferFrameLocal.h"
#include "fsfw/globalfunctions/CRC.h"
#include "fsfw/serviceinterface/ServiceInterface.h"
/**
* @file TcTransferFrameLocal.cpp
* @brief This file defines the TcTransferFrameLocal class.
* @date 27.04.2013
* @author baetz
*/
#include <cstring>
#include "TcTransferFrameLocal.h"
#include "../globalfunctions/CRC.h"
#include "../serviceinterface/ServiceInterfaceStream.h"
#include <string.h>
TcTransferFrameLocal::TcTransferFrameLocal(bool bypass, bool controlCommand, uint16_t scid,
uint8_t vcId, uint8_t sequenceNumber, uint8_t setSegmentHeader, uint8_t* data, uint16_t dataSize, uint16_t forceCrc) {
@ -31,9 +37,7 @@ TcTransferFrameLocal::TcTransferFrameLocal(bool bypass, bool controlCommand, uin
this->getFullFrame()[getFullSize()-2] = (crc & 0xFF00) >> 8;
this->getFullFrame()[getFullSize()-1] = (crc & 0x00FF);
} else {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "TcTransferFrameLocal: dataSize too large: " << dataSize << std::endl;
#endif
sif::debug << "TcTransferFrameLocal: dataSize too large: " << dataSize << std::endl;
}
} else {
//No data in frame

View File

@ -8,7 +8,6 @@
#ifndef TCTRANSFERFRAMELOCAL_H_
#define TCTRANSFERFRAMELOCAL_H_
#include "dllConf.h"
#include "TcTransferFrame.h"
/**

View File

@ -5,9 +5,9 @@
* @author baetz
*/
#include "fsfw/datalinklayer/BCFrame.h"
#include "fsfw/datalinklayer/VirtualChannelReception.h"
#include "fsfw/serviceinterface/ServiceInterface.h"
#include "BCFrame.h"
#include "VirtualChannelReception.h"
#include "../serviceinterface/ServiceInterfaceStream.h"
VirtualChannelReception::VirtualChannelReception(uint8_t setChannelId,
uint8_t setSlidingWindowWidth) :
@ -102,10 +102,8 @@ uint8_t VirtualChannelReception::getChannelId() const {
ReturnValue_t VirtualChannelReception::initialize() {
ReturnValue_t returnValue = RETURN_FAILED;
if ((slidingWindowWidth > 254) || (slidingWindowWidth % 2 != 0)) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "VirtualChannelReception::initialize: Illegal sliding window width: "
<< (int) slidingWindowWidth << std::endl;
#endif
return RETURN_FAILED;
}
for (mapChannelIterator iterator = mapChannels.begin(); iterator != mapChannels.end();

View File

@ -8,7 +8,6 @@
#ifndef VIRTUALCHANNELRECEPTION_H_
#define VIRTUALCHANNELRECEPTION_H_
#include "dllConf.h"
#include "CCSDSReturnValuesIF.h"
#include "Clcw.h"
#include "Farm1StateIF.h"
@ -17,7 +16,6 @@
#include "Farm1StateWait.h"
#include "MapPacketExtractionIF.h"
#include "VirtualChannelReceptionIF.h"
#include <map>
/**
* Implementation of a TC Virtual Channel.

View File

@ -8,10 +8,9 @@
#ifndef VIRTUALCHANNELRECEPTIONIF_H_
#define VIRTUALCHANNELRECEPTIONIF_H_
#include "dllConf.h"
#include "ClcwIF.h"
#include "TcTransferFrame.h"
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
#include "../returnvalues/HasReturnvaluesIF.h"
/**
* This is the interface for Virtual Channel reception classes.

View File

@ -0,0 +1,14 @@
#include "ControllerSet.h"
ControllerSet::ControllerSet() {
}
ControllerSet::~ControllerSet() {
}
void ControllerSet::setInvalid() {
read();
setToDefault();
commit(PoolVariableIF::INVALID);
}

15
datapool/ControllerSet.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef CONTROLLERSET_H_
#define CONTROLLERSET_H_
#include "DataSet.h"
class ControllerSet :public DataSet {
public:
ControllerSet();
virtual ~ControllerSet();
virtual void setToDefault() = 0;
void setInvalid();
};
#endif /* CONTROLLERSET_H_ */

131
datapool/DataPool.cpp Normal file
View File

@ -0,0 +1,131 @@
#include "DataPool.h"
#include "../serviceinterface/ServiceInterfaceStream.h"
#include "../ipc/MutexFactory.h"
DataPool::DataPool( void ( *initFunction )( std::map<uint32_t, PoolEntryIF*>* pool_map ) ) {
mutex = MutexFactory::instance()->createMutex();
if (initFunction != NULL ) {
initFunction( &this->data_pool );
}
}
DataPool::~DataPool() {
MutexFactory::instance()->deleteMutex(mutex);
for ( std::map<uint32_t, PoolEntryIF*>::iterator it = this->data_pool.begin(); it != this->data_pool.end(); ++it ) {
delete it->second;
}
}
//The function checks PID, type and array length before returning a copy of the PoolEntry. In failure case, it returns a temp-Entry with size 0 and NULL-ptr.
template <typename T> PoolEntry<T>* DataPool::getData( uint32_t data_pool_id, uint8_t sizeOrPosition ) {
std::map<uint32_t, PoolEntryIF*>::iterator it = this->data_pool.find( data_pool_id );
if ( it != this->data_pool.end() ) {
PoolEntry<T>* entry = dynamic_cast< PoolEntry<T>* >( it->second );
if (entry != NULL ) {
if ( sizeOrPosition <= entry->length ) {
return entry;
}
}
}
return NULL;
}
PoolEntryIF* DataPool::getRawData( uint32_t data_pool_id ) {
std::map<uint32_t, PoolEntryIF*>::iterator it = this->data_pool.find( data_pool_id );
if ( it != this->data_pool.end() ) {
return it->second;
} else {
return NULL;
}
}
//uint8_t DataPool::getRawData( uint32_t data_pool_id, uint8_t* address, uint16_t* size, uint32_t maxSize ) {
// std::map<uint32_t, PoolEntryIF*>::iterator it = this->data_pool.find( data_pool_id );
// if ( it != this->data_pool.end() ) {
// if ( it->second->getByteSize() <= maxSize ) {
// *size = it->second->getByteSize();
// memcpy( address, it->second->getRawData(), *size );
// return DP_SUCCESSFUL;
// }
// }
// *size = 0;
// return DP_FAILURE;
//}
ReturnValue_t DataPool::freeDataPoolLock() {
ReturnValue_t status = mutex->unlockMutex();
if ( status != RETURN_OK ) {
sif::error << "DataPool::DataPool: unlock of mutex failed with error code: " << status << std::endl;
}
return status;
}
ReturnValue_t DataPool::lockDataPool() {
ReturnValue_t status = mutex->lockMutex(MutexIF::BLOCKING);
if ( status != RETURN_OK ) {
sif::error << "DataPool::DataPool: lock of mutex failed with error code: " << status << std::endl;
}
return status;
}
void DataPool::print() {
sif::debug << "DataPool contains: " << std::endl;
std::map<uint32_t, PoolEntryIF*>::iterator dataPoolIt;
dataPoolIt = this->data_pool.begin();
while( dataPoolIt != this->data_pool.end() ) {
sif::debug << std::hex << dataPoolIt->first << std::dec << " |";
dataPoolIt->second->print();
dataPoolIt++;
}
}
template PoolEntry<uint8_t>* DataPool::getData<uint8_t>( uint32_t data_pool_id, uint8_t size );
template PoolEntry<uint16_t>* DataPool::getData<uint16_t>( uint32_t data_pool_id, uint8_t size );
template PoolEntry<uint32_t>* DataPool::getData<uint32_t>( uint32_t data_pool_id, uint8_t size );
template PoolEntry<uint64_t>* DataPool::getData<uint64_t>(uint32_t data_pool_id,
uint8_t size);
template PoolEntry<int8_t>* DataPool::getData<int8_t>( uint32_t data_pool_id, uint8_t size );
template PoolEntry<int16_t>* DataPool::getData<int16_t>( uint32_t data_pool_id, uint8_t size );
template PoolEntry<int32_t>* DataPool::getData<int32_t>( uint32_t data_pool_id, uint8_t size );
template PoolEntry<float>* DataPool::getData<float>( uint32_t data_pool_id, uint8_t size );
template PoolEntry<double>* DataPool::getData<double>(uint32_t data_pool_id,
uint8_t size);
uint32_t DataPool::PIDToDataPoolId(uint32_t parameter_id) {
return (parameter_id >> 8) & 0x00FFFFFF;
}
uint8_t DataPool::PIDToArrayIndex(uint32_t parameter_id) {
return (parameter_id & 0x000000FF);
}
uint32_t DataPool::poolIdAndPositionToPid(uint32_t poolId, uint8_t index) {
return (poolId << 8) + index;
}
//SHOULDDO: Do we need a mutex lock here... I don't think so, as we only check static const values of elements in a list that do not change.
//there is no guarantee in the standard, but it seems to me that the implementation is safe -UM
ReturnValue_t DataPool::getType(uint32_t parameter_id, Type* type) {
std::map<uint32_t, PoolEntryIF*>::iterator it = this->data_pool.find( PIDToDataPoolId(parameter_id));
if ( it != this->data_pool.end() ) {
*type = it->second->getType();
return RETURN_OK;
} else {
*type = Type::UNKNOWN_TYPE;
return RETURN_FAILED;
}
}
bool DataPool::exists(uint32_t parameterId) {
uint32_t poolId = PIDToDataPoolId(parameterId);
uint32_t index = PIDToArrayIndex(parameterId);
std::map<uint32_t, PoolEntryIF*>::iterator it = this->data_pool.find( poolId );
if (it != data_pool.end()) {
if (it->second->getSize() >= index) {
return true;
}
}
return false;
}

135
datapool/DataPool.h Normal file
View File

@ -0,0 +1,135 @@
/**
* \file DataPool.h
*
* \date 10/17/2012
* \author Bastian Baetz
*
* \brief This file contains the definition of the DataPool class and (temporarily)
* the "extern" definition of the global dataPool instance.
*/
#ifndef DATAPOOL_H_
#define DATAPOOL_H_
#include "PoolEntry.h"
#include "../globalfunctions/Type.h"
#include "../ipc/MutexIF.h"
#include <map>
/**
* \defgroup data_pool Data Pool
* This is the group, where all classes associated with Data Pool Handling belong to.
* This includes classes to access Data Pool variables.
*/
#define DP_SUCCESSFUL 0
#define DP_FAILURE 1
/**
* \brief This class represents the OBSW global data-pool.
*
* \details All variables are registered and space is allocated in an initialization
* function, which is passed do the constructor.
* Space for the variables is allocated on the heap (with a new call).
* The data is found by a data pool id, which uniquely represents a variable.
* Data pool variables should be used with a blackboard logic in mind,
* which means read data is valid (if flagged so), but not necessarily up-to-date.
* Variables are either single values or arrays.
* \ingroup data_pool
*/
class DataPool : public HasReturnvaluesIF {
private:
/**
* \brief This is the actual data pool itself.
* \details It is represented by a map
* with the data pool id as index and a pointer to a single PoolEntry as value.
*/
std::map<uint32_t, PoolEntryIF*> data_pool;
public:
/**
* \brief The mutex is created in the constructor and makes access mutual exclusive.
* \details Locking and unlocking the pool is only done by the DataSet class.
*/
MutexIF* mutex;
/**
* \brief In the classes constructor, the passed initialization function is called.
* \details To enable filling the pool,
* a pointer to the map is passed, allowing direct access to the pool's content.
* On runtime, adding or removing variables is forbidden.
*/
DataPool( void ( *initFunction )( std::map<uint32_t, PoolEntryIF*>* pool_map ) );
/**
* \brief The destructor iterates through the data_pool map and calls all Entries destructors to clean up the heap.
*/
~DataPool();
/**
* \brief This is the default call to access the pool.
* \details A pointer to the PoolEntry object is returned.
* The call checks data pool id, type and array size. Returns NULL in case of failure.
* \param data_pool_id The data pool id to search.
* \param sizeOrPosition The array size (not byte size!) of the pool entry, or the position the user wants to read.
* If smaller than the entry size, everything's ok.
*/
template <typename T> PoolEntry<T>* getData( uint32_t data_pool_id, uint8_t sizeOrPosition );
/**
* \brief An alternative call to get a data pool entry in case the type is not implicitly known
* (i.e. in Housekeeping Telemetry).
* \details It returns a basic interface and does NOT perform
* a size check. The caller has to assure he does not copy too much data.
* Returns NULL in case the entry is not found.
* \param data_pool_id The data pool id to search.
*/
PoolEntryIF* getRawData( uint32_t data_pool_id );
/**
* \brief This is a small helper function to facilitate locking the global data pool.
* \details It fetches the pool's mutex id and tries to acquire the mutex.
*/
ReturnValue_t lockDataPool();
/**
* \brief This is a small helper function to facilitate unlocking the global data pool.
* \details It fetches the pool's mutex id and tries to free the mutex.
*/
ReturnValue_t freeDataPoolLock();
/**
* \brief The print call is a simple debug method.
* \details It prints the current content of the data pool.
* It iterates through the data_pool map and calls each entry's print() method.
*/
void print();
/**
* Extracts the data pool id from a SCOS 2000 PID.
* @param parameter_id The passed Parameter ID.
* @return The data pool id as used within the OBSW.
*/
static uint32_t PIDToDataPoolId( uint32_t parameter_id );
/**
* Extracts an array index out of a SCOS 2000 PID.
* @param parameter_id The passed Parameter ID.
* @return The index of the corresponding data pool entry.
*/
static uint8_t PIDToArrayIndex( uint32_t parameter_id );
/**
* Retransforms a data pool id and an array index to a SCOS 2000 PID.
*/
static uint32_t poolIdAndPositionToPid( uint32_t poolId, uint8_t index );
/**
* Method to return the type of a pool variable.
* @param parameter_id A parameterID (not pool id) of a DP member.
* @param type Returns the type or TYPE::UNKNOWN_TYPE
* @return RETURN_OK if parameter exists, RETURN_FAILED else.
*/
ReturnValue_t getType( uint32_t parameter_id, Type* type );
/**
* Method to check if a PID exists.
* Does not lock, as there's no possibility to alter the list that is checked during run-time.
* @param parameterId The PID (not pool id!) of a parameter.
* @return true if exists, false else.
*/
bool exists(uint32_t parameterId);
};
//We assume someone globally instantiates a DataPool.
extern DataPool dataPool;
#endif /* DATAPOOL_H_ */

300
datapool/DataPoolAdmin.cpp Normal file
View File

@ -0,0 +1,300 @@
#include "DataPool.h"
#include "DataPoolAdmin.h"
#include "DataSet.h"
#include "PoolRawAccess.h"
#include "../ipc/CommandMessage.h"
#include "../ipc/QueueFactory.h"
#include "../parameters/ParameterMessage.h"
DataPoolAdmin::DataPoolAdmin(object_id_t objectId) :
SystemObject(objectId), storage(NULL), commandQueue(NULL), memoryHelper(
this, NULL), actionHelper(this, NULL) {
commandQueue = QueueFactory::instance()->createMessageQueue();
}
DataPoolAdmin::~DataPoolAdmin() {
QueueFactory::instance()->deleteMessageQueue(commandQueue);
}
ReturnValue_t DataPoolAdmin::performOperation(uint8_t opCode) {
handleCommand();
return RETURN_OK;
}
MessageQueueId_t DataPoolAdmin::getCommandQueue() const {
return commandQueue->getId();
}
ReturnValue_t DataPoolAdmin::executeAction(ActionId_t actionId,
MessageQueueId_t commandedBy, const uint8_t* data, size_t size) {
if (actionId != SET_VALIDITY) {
return INVALID_ACTION_ID;
}
if (size != 5) {
return INVALID_PARAMETERS;
}
uint32_t address = (data[0] << 24) | (data[1] << 16) | (data[2] << 8)
| data[3];
uint8_t valid = data[4];
uint32_t poolId = ::dataPool.PIDToDataPoolId(address);
DataSet mySet;
PoolRawAccess variable(poolId, 0, &mySet, PoolVariableIF::VAR_READ_WRITE);
ReturnValue_t status = mySet.read();
if (status != RETURN_OK) {
return INVALID_ADDRESS;
}
if (valid != 0) {
variable.setValid(PoolVariableIF::VALID);
} else {
variable.setValid(PoolVariableIF::INVALID);
}
mySet.commit();
return EXECUTION_FINISHED;
}
ReturnValue_t DataPoolAdmin::getParameter(uint8_t domainId,
uint16_t parameterId, ParameterWrapper* parameterWrapper,
const ParameterWrapper* newValues, uint16_t startAtIndex) {
return HasReturnvaluesIF::RETURN_FAILED;
}
void DataPoolAdmin::handleCommand() {
CommandMessage command;
ReturnValue_t result = commandQueue->receiveMessage(&command);
if (result != RETURN_OK) {
return;
}
result = actionHelper.handleActionMessage(&command);
if (result == HasReturnvaluesIF::RETURN_OK) {
return;
}
result = handleParameterCommand(&command);
if (result == HasReturnvaluesIF::RETURN_OK) {
return;
}
result = memoryHelper.handleMemoryCommand(&command);
if (result != RETURN_OK) {
command.setToUnknownCommand();
commandQueue->reply(&command);
}
}
ReturnValue_t DataPoolAdmin::handleMemoryLoad(uint32_t address,
const uint8_t* data, size_t size, uint8_t** dataPointer) {
uint32_t poolId = ::dataPool.PIDToDataPoolId(address);
uint8_t arrayIndex = ::dataPool.PIDToArrayIndex(address);
DataSet testSet;
PoolRawAccess varToGetSize(poolId, arrayIndex, &testSet,
PoolVariableIF::VAR_READ);
ReturnValue_t status = testSet.read();
if (status != RETURN_OK) {
return INVALID_ADDRESS;
}
uint8_t typeSize = varToGetSize.getSizeOfType();
if (size % typeSize != 0) {
return INVALID_SIZE;
}
if (size > varToGetSize.getSizeTillEnd()) {
return INVALID_SIZE;
}
const uint8_t* readPosition = data;
for (; size > 0; size -= typeSize) {
DataSet rawSet;
PoolRawAccess variable(poolId, arrayIndex, &rawSet,
PoolVariableIF::VAR_READ_WRITE);
status = rawSet.read();
if (status == RETURN_OK) {
status = variable.setEntryFromBigEndian(readPosition, typeSize);
if (status == RETURN_OK) {
status = rawSet.commit();
}
}
arrayIndex += 1;
readPosition += typeSize;
}
return ACTIVITY_COMPLETED;
}
ReturnValue_t DataPoolAdmin::handleMemoryDump(uint32_t address, size_t size,
uint8_t** dataPointer, uint8_t* copyHere) {
uint32_t poolId = ::dataPool.PIDToDataPoolId(address);
uint8_t arrayIndex = ::dataPool.PIDToArrayIndex(address);
DataSet testSet;
PoolRawAccess varToGetSize(poolId, arrayIndex, &testSet,
PoolVariableIF::VAR_READ);
ReturnValue_t status = testSet.read();
if (status != RETURN_OK) {
return INVALID_ADDRESS;
}
uint8_t typeSize = varToGetSize.getSizeOfType();
if (size > varToGetSize.getSizeTillEnd()) {
return INVALID_SIZE;
}
uint8_t* ptrToCopy = copyHere;
for (; size > 0; size -= typeSize) {
DataSet rawSet;
PoolRawAccess variable(poolId, arrayIndex, &rawSet,
PoolVariableIF::VAR_READ);
status = rawSet.read();
if (status == RETURN_OK) {
size_t temp = 0;
status = variable.getEntryEndianSafe(ptrToCopy, &temp, size);
if (status != RETURN_OK) {
return RETURN_FAILED;
}
} else {
//Error reading parameter.
}
arrayIndex += 1;
ptrToCopy += typeSize;
}
return ACTIVITY_COMPLETED;
}
ReturnValue_t DataPoolAdmin::initialize() {
ReturnValue_t result = SystemObject::initialize();
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
result = memoryHelper.initialize(commandQueue);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
storage = objectManager->get<StorageManagerIF>(objects::IPC_STORE);
if (storage == NULL) {
return HasReturnvaluesIF::RETURN_FAILED;
}
result = actionHelper.initialize(commandQueue);
return result;
}
//mostly identical to ParameterHelper::handleParameterMessage()
ReturnValue_t DataPoolAdmin::handleParameterCommand(CommandMessage* command) {
ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED;
switch (command->getCommand()) {
case ParameterMessage::CMD_PARAMETER_DUMP: {
uint8_t domain = HasParametersIF::getDomain(
ParameterMessage::getParameterId(command));
uint16_t parameterId = HasParametersIF::getMatrixId(
ParameterMessage::getParameterId(command));
DataPoolParameterWrapper wrapper;
result = wrapper.set(domain, parameterId);
if (result == HasReturnvaluesIF::RETURN_OK) {
result = sendParameter(command->getSender(),
ParameterMessage::getParameterId(command), &wrapper);
}
}
break;
case ParameterMessage::CMD_PARAMETER_LOAD: {
uint8_t domain = HasParametersIF::getDomain(
ParameterMessage::getParameterId(command));
uint16_t parameterId = HasParametersIF::getMatrixId(
ParameterMessage::getParameterId(command));
uint8_t index = HasParametersIF::getIndex(
ParameterMessage::getParameterId(command));
const uint8_t *storedStream;
size_t storedStreamSize;
result = storage->getData(ParameterMessage::getStoreId(command),
&storedStream, &storedStreamSize);
if (result != HasReturnvaluesIF::RETURN_OK) {
break;
}
ParameterWrapper streamWrapper;
result = streamWrapper.set(storedStream, storedStreamSize);
if (result != HasReturnvaluesIF::RETURN_OK) {
storage->deleteData(ParameterMessage::getStoreId(command));
break;
}
DataPoolParameterWrapper poolWrapper;
result = poolWrapper.set(domain, parameterId);
if (result != HasReturnvaluesIF::RETURN_OK) {
storage->deleteData(ParameterMessage::getStoreId(command));
break;
}
result = poolWrapper.copyFrom(&streamWrapper, index);
storage->deleteData(ParameterMessage::getStoreId(command));
if (result == HasReturnvaluesIF::RETURN_OK) {
result = sendParameter(command->getSender(),
ParameterMessage::getParameterId(command), &poolWrapper);
}
}
break;
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
if (result != HasReturnvaluesIF::RETURN_OK) {
rejectCommand(command->getSender(), result, command->getCommand());
}
return HasReturnvaluesIF::RETURN_OK;
}
//identical to ParameterHelper::sendParameter()
ReturnValue_t DataPoolAdmin::sendParameter(MessageQueueId_t to, uint32_t id,
const DataPoolParameterWrapper* wrapper) {
size_t serializedSize = wrapper->getSerializedSize();
uint8_t *storeElement;
store_address_t address;
ReturnValue_t result = storage->getFreeElement(&address, serializedSize,
&storeElement);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
size_t storeElementSize = 0;
result = wrapper->serialize(&storeElement, &storeElementSize,
serializedSize, SerializeIF::Endianness::BIG);
if (result != HasReturnvaluesIF::RETURN_OK) {
storage->deleteData(address);
return result;
}
CommandMessage reply;
ParameterMessage::setParameterDumpReply(&reply, id, address);
commandQueue->sendMessage(to, &reply);
return HasReturnvaluesIF::RETURN_OK;
}
//identical to ParameterHelper::rejectCommand()
void DataPoolAdmin::rejectCommand(MessageQueueId_t to, ReturnValue_t reason,
Command_t initialCommand) {
CommandMessage reply;
reply.setReplyRejected(reason, initialCommand);
commandQueue->sendMessage(to, &reply);
}

58
datapool/DataPoolAdmin.h Normal file
View File

@ -0,0 +1,58 @@
#ifndef DATAPOOLADMIN_H_
#define DATAPOOLADMIN_H_
#include "../memory/MemoryHelper.h"
#include "../action/HasActionsIF.h"
#include "../action/SimpleActionHelper.h"
#include "../objectmanager/SystemObject.h"
#include "../returnvalues/HasReturnvaluesIF.h"
#include "../tasks/ExecutableObjectIF.h"
#include "../parameters/ReceivesParameterMessagesIF.h"
#include "DataPoolParameterWrapper.h"
#include "../ipc/MessageQueueIF.h"
class DataPoolAdmin: public HasActionsIF,
public ExecutableObjectIF,
public AcceptsMemoryMessagesIF,
public HasReturnvaluesIF,
public ReceivesParameterMessagesIF,
public SystemObject {
public:
static const ActionId_t SET_VALIDITY = 1;
DataPoolAdmin(object_id_t objectId);
~DataPoolAdmin();
ReturnValue_t performOperation(uint8_t opCode);
MessageQueueId_t getCommandQueue() const;
ReturnValue_t handleMemoryLoad(uint32_t address, const uint8_t* data,
size_t size, uint8_t** dataPointer);
ReturnValue_t handleMemoryDump(uint32_t address, size_t size,
uint8_t** dataPointer, uint8_t* copyHere);
ReturnValue_t executeAction(ActionId_t actionId,
MessageQueueId_t commandedBy, const uint8_t* data, size_t size);
//not implemented as ParameterHelper is no used
ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId,
ParameterWrapper *parameterWrapper,
const ParameterWrapper *newValues, uint16_t startAtIndex);
ReturnValue_t initialize();
private:
StorageManagerIF *storage;
MessageQueueIF* commandQueue;
MemoryHelper memoryHelper;
SimpleActionHelper actionHelper;
void handleCommand();
ReturnValue_t handleParameterCommand(CommandMessage *command);
ReturnValue_t sendParameter(MessageQueueId_t to, uint32_t id,
const DataPoolParameterWrapper* wrapper);
void rejectCommand(MessageQueueId_t to, ReturnValue_t reason,
Command_t initialCommand);
};
#endif /* DATAPOOLADMIN_H_ */

View File

@ -0,0 +1,181 @@
#include "DataPoolParameterWrapper.h"
//for returncodes
#include "../parameters/HasParametersIF.h"
#include "DataSet.h"
#include "PoolRawAccess.h"
DataPoolParameterWrapper::DataPoolParameterWrapper() :
type(Type::UNKNOWN_TYPE), rows(0), columns(0), poolId(
PoolVariableIF::NO_PARAMETER) {
}
DataPoolParameterWrapper::~DataPoolParameterWrapper() {
}
ReturnValue_t DataPoolParameterWrapper::set(uint8_t domainId,
uint16_t parameterId) {
poolId = (domainId << 16) + parameterId;
DataSet mySet;
PoolRawAccess raw(poolId, 0, &mySet, PoolVariableIF::VAR_READ);
ReturnValue_t status = mySet.read();
if (status != HasReturnvaluesIF::RETURN_OK) {
//should only fail for invalid pool id
return HasParametersIF::INVALID_MATRIX_ID;
}
type = raw.getType();
rows = raw.getArraySize();
columns = 1;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t DataPoolParameterWrapper::serialize(uint8_t** buffer,
size_t* size, size_t maxSize, Endianness streamEndianness) const {
ReturnValue_t result;
result = SerializeAdapter::serialize(&type, buffer, size, maxSize,
streamEndianness);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
result = SerializeAdapter::serialize(&columns, buffer, size,
maxSize, streamEndianness);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
result = SerializeAdapter::serialize(&rows, buffer, size, maxSize,
streamEndianness);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
for (uint8_t index = 0; index < rows; index++){
DataSet mySet;
PoolRawAccess raw(poolId, index, &mySet,PoolVariableIF::VAR_READ);
mySet.read();
result = raw.serialize(buffer,size,maxSize,streamEndianness);
if (result != HasReturnvaluesIF::RETURN_OK){
return result;
}
}
return HasReturnvaluesIF::RETURN_OK;
}
//same as ParameterWrapper
size_t DataPoolParameterWrapper::getSerializedSize() const {
size_t serializedSize = 0;
serializedSize += type.getSerializedSize();
serializedSize += sizeof(rows);
serializedSize += sizeof(columns);
serializedSize += rows * columns * type.getSize();
return serializedSize;
}
ReturnValue_t DataPoolParameterWrapper::deSerialize(const uint8_t** buffer,
size_t* size, Endianness streamEndianness) {
return HasReturnvaluesIF::RETURN_FAILED;
}
template<typename T>
ReturnValue_t DataPoolParameterWrapper::deSerializeData(uint8_t startingRow,
uint8_t startingColumn, const void* from, uint8_t fromRows) {
//treat from as a continuous Stream as we copy all of it
const uint8_t *fromAsStream = (const uint8_t *) from;
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
for (uint8_t fromRow = 0; fromRow < fromRows; fromRow++) {
DataSet mySet;
PoolRawAccess raw(poolId, startingRow + fromRow, &mySet,
PoolVariableIF::VAR_READ_WRITE);
mySet.read();
result = raw.setEntryFromBigEndian(fromAsStream, sizeof(T));
fromAsStream += sizeof(T);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
mySet.commit();
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t DataPoolParameterWrapper::copyFrom(const ParameterWrapper* from,
uint16_t startWritingAtIndex) {
if (poolId == PoolVariableIF::NO_PARAMETER) {
return ParameterWrapper::NOT_SET;
}
if (type != from->type) {
return ParameterWrapper::DATATYPE_MISSMATCH;
}
//check if from fits into this
uint8_t startingRow = startWritingAtIndex / columns;
uint8_t startingColumn = startWritingAtIndex % columns;
if ((from->rows > (rows - startingRow))
|| (from->columns > (columns - startingColumn))) {
return ParameterWrapper::TOO_BIG;
}
ReturnValue_t result;
//copy data
if (from->pointsToStream) {
switch (type) {
case Type::UINT8_T:
result = deSerializeData<uint8_t>(startingRow, startingColumn,
from->readonlyData, from->rows);
break;
case Type::INT8_T:
result = deSerializeData<int8_t>(startingRow, startingColumn,
from->readonlyData, from->rows);
break;
case Type::UINT16_T:
result = deSerializeData<uint16_t>(startingRow, startingColumn,
from->readonlyData, from->rows);
break;
case Type::INT16_T:
result = deSerializeData<int16_t>(startingRow, startingColumn,
from->readonlyData, from->rows);
break;
case Type::UINT32_T:
result = deSerializeData<uint32_t>(startingRow, startingColumn,
from->readonlyData, from->rows);
break;
case Type::INT32_T:
result = deSerializeData<int32_t>(startingRow, startingColumn,
from->readonlyData, from->rows);
break;
case Type::FLOAT:
result = deSerializeData<float>(startingRow, startingColumn,
from->readonlyData, from->rows);
break;
case Type::DOUBLE:
result = deSerializeData<double>(startingRow, startingColumn,
from->readonlyData, from->rows);
break;
default:
result = ParameterWrapper::UNKNOW_DATATYPE;
break;
}
} else {
//not supported
return HasReturnvaluesIF::RETURN_FAILED;
}
return result;
}

View File

@ -0,0 +1,38 @@
#ifndef DATAPOOLPARAMETERWRAPPER_H_
#define DATAPOOLPARAMETERWRAPPER_H_
#include "../globalfunctions/Type.h"
#include "../parameters/ParameterWrapper.h"
class DataPoolParameterWrapper: public SerializeIF {
public:
DataPoolParameterWrapper();
virtual ~DataPoolParameterWrapper();
ReturnValue_t set(uint8_t domainId, uint16_t parameterId);
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size,
size_t maxSize, Endianness streamEndianness) const override;
virtual size_t getSerializedSize() const override;
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
Endianness streamEndianness) override;
ReturnValue_t copyFrom(const ParameterWrapper *from,
uint16_t startWritingAtIndex);
private:
Type type;
uint8_t rows;
uint8_t columns;
uint32_t poolId;
template<typename T>
ReturnValue_t deSerializeData(uint8_t startingRow, uint8_t startingColumn,
const void *from, uint8_t fromRows);
};
#endif /* DATAPOOLPARAMETERWRAPPER_H_ */

150
datapool/DataSet.cpp Normal file
View File

@ -0,0 +1,150 @@
#include "DataSet.h"
#include "../serviceinterface/ServiceInterfaceStream.h"
DataSet::DataSet() :
fill_count(0), state(DATA_SET_UNINITIALISED) {
for (unsigned count = 0; count < DATA_SET_MAX_SIZE; count++) {
registeredVariables[count] = NULL;
}
}
DataSet::~DataSet() {
//Don't do anything with your variables, they are dead already! (Destructor is already called)
}
ReturnValue_t DataSet::read() {
ReturnValue_t result = RETURN_OK;
if (state == DATA_SET_UNINITIALISED) {
lockDataPool();
for (uint16_t count = 0; count < fill_count; count++) {
if (registeredVariables[count]->getReadWriteMode()
!= PoolVariableIF::VAR_WRITE
&& registeredVariables[count]->getDataPoolId()
!= PoolVariableIF::NO_PARAMETER) {
ReturnValue_t status = registeredVariables[count]->read();
if (status != RETURN_OK) {
result = INVALID_PARAMETER_DEFINITION;
break;
}
}
}
state = DATA_SET_WAS_READ;
freeDataPoolLock();
} else {
sif::error << "DataSet::read(): Call made in wrong position." << std::endl;
result = SET_WAS_ALREADY_READ;
}
return result;
}
ReturnValue_t DataSet::commit(uint8_t valid) {
setValid(valid);
return commit();
}
ReturnValue_t DataSet::commit() {
if (state == DATA_SET_WAS_READ) {
lockDataPool();
for (uint16_t count = 0; count < fill_count; count++) {
if (registeredVariables[count]->getReadWriteMode()
!= PoolVariableIF::VAR_READ
&& registeredVariables[count]->getDataPoolId()
!= PoolVariableIF::NO_PARAMETER) {
registeredVariables[count]->commit();
}
}
state = DATA_SET_UNINITIALISED;
freeDataPoolLock();
return RETURN_OK;
} else {
ReturnValue_t result = RETURN_OK;
lockDataPool();
for (uint16_t count = 0; count < fill_count; count++) {
if (registeredVariables[count]->getReadWriteMode()
== PoolVariableIF::VAR_WRITE
&& registeredVariables[count]->getDataPoolId()
!= PoolVariableIF::NO_PARAMETER) {
registeredVariables[count]->commit();
} else if (registeredVariables[count]->getDataPoolId()
!= PoolVariableIF::NO_PARAMETER) {
if (result != COMMITING_WITHOUT_READING) {
sif::error <<
"DataSet::commit(): commit-without-read "
"call made with non write-only variable." << std::endl;
result = COMMITING_WITHOUT_READING;
}
}
}
state = DATA_SET_UNINITIALISED;
freeDataPoolLock();
return result;
}
}
void DataSet::registerVariable(PoolVariableIF* variable) {
if (state == DATA_SET_UNINITIALISED) {
if (variable != NULL) {
if (fill_count < DATA_SET_MAX_SIZE) {
registeredVariables[fill_count] = variable;
fill_count++;
return;
}
}
}
sif::error
<< "DataSet::registerVariable: failed. Either NULL, or set is full, or call made in wrong position."
<< std::endl;
return;
}
uint8_t DataSet::freeDataPoolLock() {
return ::dataPool.freeDataPoolLock();
}
uint8_t DataSet::lockDataPool() {
return ::dataPool.lockDataPool();
}
ReturnValue_t DataSet::serialize(uint8_t** buffer, size_t* size,
size_t maxSize, Endianness streamEndianness) const {
ReturnValue_t result = RETURN_FAILED;
for (uint16_t count = 0; count < fill_count; count++) {
result = registeredVariables[count]->serialize(buffer, size, maxSize,
streamEndianness);
if (result != RETURN_OK) {
return result;
}
}
return result;
}
size_t DataSet::getSerializedSize() const {
size_t size = 0;
for (uint16_t count = 0; count < fill_count; count++) {
size += registeredVariables[count]->getSerializedSize();
}
return size;
}
void DataSet::setValid(uint8_t valid) {
for (uint16_t count = 0; count < fill_count; count++) {
if (registeredVariables[count]->getReadWriteMode()
!= PoolVariableIF::VAR_READ) {
registeredVariables[count]->setValid(valid);
}
}
}
ReturnValue_t DataSet::deSerialize(const uint8_t** buffer, size_t* size,
Endianness streamEndianness) {
ReturnValue_t result = RETURN_FAILED;
for (uint16_t count = 0; count < fill_count; count++) {
result = registeredVariables[count]->deSerialize(buffer, size,
streamEndianness);
if (result != RETURN_OK) {
return result;
}
}
return result;
}

159
datapool/DataSet.h Normal file
View File

@ -0,0 +1,159 @@
/*
* \file DataSet.h
*
* \brief This file contains the DataSet class and a small structure called DataSetContent.
*
* \date 10/17/2012
*
* \author Bastian Baetz
*
*/
#ifndef DATASET_H_
#define DATASET_H_
#include "DataPool.h"
#include "DataSetIF.h"
#include "PoolRawAccess.h"
#include "PoolVariable.h"
#include "PoolVarList.h"
#include "PoolVector.h"
#include "../serialize/SerializeAdapter.h"
/**
* \brief The DataSet class manages a set of locally checked out variables.
*
* \details This class manages a list, where a set of local variables (or pool variables) are
* registered. They are checked-out (i.e. their values are looked up and copied)
* with the read call. After the user finishes working with the pool variables,
* he can write back all variable values to the pool with the commit call.
* The data set manages locking and freeing the data pool, to ensure that all values
* are read and written back at once.
* An internal state manages usage of this class. Variables may only be registered before
* the read call is made, and the commit call only after the read call.
* If pool variables are writable and not committed until destruction of the set, the
* DataSet class automatically sets the valid flag in the data pool to invalid (without)
* changing the variable's value.
*
* \ingroup data_pool
*/
class DataSet: public DataSetIF, public HasReturnvaluesIF, public SerializeIF {
private:
//SHOULDDO we could use a linked list of datapool variables
static const uint8_t DATA_SET_MAX_SIZE = 63; //!< This definition sets the maximum number of variables to register in one DataSet.
/**
* \brief This array represents all pool variables registered in this set.
* \details It has a maximum size of DATA_SET_MAX_SIZE.
*/
PoolVariableIF* registeredVariables[DATA_SET_MAX_SIZE];
/**
* \brief The fill_count attribute ensures that the variables register in the correct array
* position and that the maximum number of variables is not exceeded.
*/
uint16_t fill_count;
/**
* States of the seet.
*/
enum States {
DATA_SET_UNINITIALISED, //!< DATA_SET_UNINITIALISED
DATA_SET_WAS_READ //!< DATA_SET_WAS_READ
};
/**
* \brief state manages the internal state of the data set, which is important e.g. for the
* behavior on destruction.
*/
States state;
/**
* \brief This is a small helper function to facilitate locking the global data pool.
* \details It makes use of the lockDataPool method offered by the DataPool class.
*/
uint8_t lockDataPool();
/**
* \brief This is a small helper function to facilitate unlocking the global data pool.
* \details It makes use of the freeDataPoolLock method offered by the DataPool class.
*/
uint8_t freeDataPoolLock();
public:
static const uint8_t INTERFACE_ID = CLASS_ID::DATA_SET_CLASS;
static const ReturnValue_t INVALID_PARAMETER_DEFINITION =
MAKE_RETURN_CODE( 0x01 );
static const ReturnValue_t SET_WAS_ALREADY_READ = MAKE_RETURN_CODE( 0x02 );
static const ReturnValue_t COMMITING_WITHOUT_READING =
MAKE_RETURN_CODE(0x03);
/**
* \brief The constructor simply sets the fill_count to zero and sets the state to "uninitialized".
*/
DataSet();
/**
* \brief The destructor automatically manages writing the valid information of variables.
* \details In case the data set was read out, but not committed (indicated by state),
* the destructor parses all variables that are still registered to the set.
* For each, the valid flag in the data pool is set to "invalid".
*/
~DataSet();
/**
* \brief The read call initializes reading out all registered variables.
* \details It iterates through the list of registered variables and calls all read()
* functions of the registered pool variables (which read out their values from the
* data pool) which are not write-only. In case of an error (e.g. a wrong data type,
* or an invalid data pool id), the operation is aborted and
* \c INVALID_PARAMETER_DEFINITION returned.
* The data pool is locked during the whole read operation and freed afterwards.
* The state changes to "was written" after this operation.
* \return - \c RETURN_OK if all variables were read successfully.
* - \c INVALID_PARAMETER_DEFINITION if PID, size or type of the
* requested variable is invalid.
* - \c SET_WAS_ALREADY_READ if read() is called twice without calling
* commit() in between
*/
ReturnValue_t read();
/**
* \brief The commit call initializes writing back the registered variables.
* \details It iterates through the list of registered variables and calls
* the commit() method of the remaining registered variables (which write back
* their values to the pool).
* The data pool is locked during the whole commit operation and freed afterwards.
* The state changes to "was committed" after this operation.
* If the set does contain at least one variable which is not write-only commit()
* can only be called after read(). If the set only contains variables which are
* write only, commit() can be called without a preceding read() call.
* \return - \c RETURN_OK if all variables were read successfully.
* - \c COMMITING_WITHOUT_READING if set was not read yet and contains non write-only
* variables
*/
ReturnValue_t commit(void);
/**
* Variant of method above which sets validity of all elements of the set.
* @param valid Validity information from PoolVariableIF.
* \return - \c RETURN_OK if all variables were read successfully.
* - \c COMMITING_WITHOUT_READING if set was not read yet and contains non write-only
* variables
*/
ReturnValue_t commit(uint8_t valid);
/**
* \brief This operation is used to register the local variables in the set.
* \details It copies all required information to the currently
* free space in the registeredVariables list.
*/
void registerVariable(PoolVariableIF* variable);
/**
* Set the valid information of all variables contained in the set which are not readonly
*
* @param valid Validity information from PoolVariableIF.
*/
void setValid(uint8_t valid);
ReturnValue_t serialize(uint8_t** buffer, size_t* size,
size_t maxSize, Endianness streamEndianness) const override;
size_t getSerializedSize() const override;
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
Endianness streamEndianness) override;
};
#endif /* DATASET_H_ */

39
datapool/DataSetIF.h Normal file
View File

@ -0,0 +1,39 @@
/**
* \file DataSetIF.h
*
* \brief This file contains the small interface to access the DataSet class.
*
* \date 10/23/2012
*
* \author Bastian Baetz
*
*/
#ifndef DATASETIF_H_
#define DATASETIF_H_
class PoolVariableIF;
/**
* \brief This class defines a small interface to register on a DataSet.
*
* \details Currently, the only purpose of this interface is to provide a method for locally
* checked-out variables to register on a data set. Still, it may become useful for
* other purposes as well.
*
* \ingroup data_pool
*/
class DataSetIF {
public:
/**
* \brief This is an empty virtual destructor, as it is proposed for C++ interfaces.
*/
virtual ~DataSetIF() {}
/**
* \brief This operation provides a method to register local data pool variables
* to register in a data set by passing itself to this DataSet operation.
*/
virtual void registerVariable( PoolVariableIF* variable ) = 0;
};
#endif /* DATASETIF_H_ */

View File

@ -1,5 +1,6 @@
#include "fsfw/datapool/HkSwitchHelper.h"
#include "fsfw/ipc/QueueFactory.h"
#include "HkSwitchHelper.h"
//#include <mission/tmtcservices/HKService_03.h>
#include "../ipc/QueueFactory.h"
HkSwitchHelper::HkSwitchHelper(EventReportingProxyIF* eventProxy) :
commandActionHelper(this), eventProxy(eventProxy) {
@ -7,7 +8,7 @@ HkSwitchHelper::HkSwitchHelper(EventReportingProxyIF* eventProxy) :
}
HkSwitchHelper::~HkSwitchHelper() {
QueueFactory::instance()->deleteMessageQueue(actionQueue);
// TODO Auto-generated destructor stub
}
ReturnValue_t HkSwitchHelper::initialize() {
@ -21,14 +22,14 @@ ReturnValue_t HkSwitchHelper::initialize() {
}
ReturnValue_t HkSwitchHelper::performOperation(uint8_t operationCode) {
CommandMessage command;
while (actionQueue->receiveMessage(&command) == HasReturnvaluesIF::RETURN_OK) {
ReturnValue_t result = commandActionHelper.handleReply(&command);
CommandMessage message;
while (actionQueue->receiveMessage(&message) == HasReturnvaluesIF::RETURN_OK) {
ReturnValue_t result = commandActionHelper.handleReply(&message);
if (result == HasReturnvaluesIF::RETURN_OK) {
continue;
}
command.setToUnknownCommand();
actionQueue->reply(&command);
message.setToUnknownCommand();
actionQueue->reply(&message);
}
return HasReturnvaluesIF::RETURN_OK;

View File

@ -1,9 +1,9 @@
#ifndef FRAMEWORK_DATAPOOL_HKSWITCHHELPER_H_
#define FRAMEWORK_DATAPOOL_HKSWITCHHELPER_H_
#include "fsfw/tasks/ExecutableObjectIF.h"
#include "fsfw/action/CommandsActionsIF.h"
#include "fsfw/events/EventReportingProxyIF.h"
#include "../tasks/ExecutableObjectIF.h"
#include "../action/CommandsActionsIF.h"
#include "../events/EventReportingProxyIF.h"
//TODO this class violations separation between mission and framework
//but it is only a transitional solution until the Datapool is
@ -13,7 +13,7 @@ class HkSwitchHelper: public ExecutableObjectIF, public CommandsActionsIF {
public:
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::HK;
static const Event SWITCHING_TM_FAILED = MAKE_EVENT(1, severity::LOW); //!< Commanding the HK Service failed, p1: error code, p2 action: 0 disable / 1 enable
static const Event SWITCHING_TM_FAILED = MAKE_EVENT(1, SEVERITY::LOW); //!< Commanding the HK Service failed, p1: error code, p2 action: 0 disable / 1 enable
HkSwitchHelper(EventReportingProxyIF *eventProxy);
virtual ~HkSwitchHelper();

147
datapool/PIDReader.h Normal file
View File

@ -0,0 +1,147 @@
#ifndef PIDREADER_H_
#define PIDREADER_H_
#include "DataPool.h"
#include "DataSetIF.h"
#include "PoolEntry.h"
#include "PoolVariableIF.h"
#include "../serialize/SerializeAdapter.h"
#include "../serviceinterface/ServiceInterfaceStream.h"
template<typename U, uint8_t n_var> class PIDReaderList;
template<typename T>
class PIDReader: public PoolVariableIF {
template<typename U, uint8_t n_var> friend class PIDReaderList;
protected:
uint32_t parameterId;
uint8_t valid;
ReturnValue_t read() {
uint8_t arrayIndex = DataPool::PIDToArrayIndex(parameterId);
PoolEntry<T> *read_out = ::dataPool.getData<T>(
DataPool::PIDToDataPoolId(parameterId), arrayIndex);
if (read_out != NULL) {
valid = read_out->valid;
value = read_out->address[arrayIndex];
return HasReturnvaluesIF::RETURN_OK;
} else {
value = 0;
valid = false;
sif::error << "PIDReader: read of PID 0x" << std::hex << parameterId
<< std::dec << " failed." << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
}
/**
* Never commit, is read-only.
* Reason is the possibility to access a single DP vector element, but if we commit,
* we set validity of the whole vector.
*/
ReturnValue_t commit() {
return HasReturnvaluesIF::RETURN_FAILED;
}
/**
* Empty ctor for List initialization
*/
PIDReader() :
parameterId(PoolVariableIF::NO_PARAMETER), valid(
PoolVariableIF::INVALID), value(0) {
}
public:
/**
* \brief This is the local copy of the data pool entry.
*/
T value;
/**
* \brief In the constructor, the variable can register itself in a DataSet (if not NULL is
* passed).
* \details It DOES NOT fetch the current value from the data pool, but sets the value
* attribute to default (0). The value is fetched within the read() operation.
* \param set_id This is the id in the global data pool this instance of the access class
* corresponds to.
* \param dataSet The data set in which the variable shall register itself. If NULL,
* the variable is not registered.
* \param setWritable If this flag is set to true, changes in the value attribute can be
* written back to the data pool, otherwise not.
*/
PIDReader(uint32_t setParameterId, DataSetIF *dataSet) :
parameterId(setParameterId), valid(PoolVariableIF::INVALID), value(
0) {
if (dataSet != NULL) {
dataSet->registerVariable(this);
}
}
/**
* Copy ctor to copy classes containing Pool Variables.
*/
PIDReader(const PIDReader &rhs) :
parameterId(rhs.parameterId), valid(rhs.valid), value(rhs.value) {
}
/**
* \brief The classes destructor is empty.
*/
~PIDReader() {
}
/**
* \brief This operation returns the data pool id of the variable.
*/
uint32_t getDataPoolId() const {
return DataPool::PIDToDataPoolId(parameterId);
}
uint32_t getParameterId() const {
return parameterId;
}
/**
* This method returns if the variable is write-only, read-write or read-only.
*/
ReadWriteMode_t getReadWriteMode() const {
return VAR_READ;
}
/**
* \brief With this call, the valid information of the variable is returned.
*/
bool isValid() const {
if (valid)
return true;
else
return false;
}
uint8_t getValid() {
return valid;
}
void setValid(uint8_t valid) {
this->valid = valid;
}
operator T() {
return value;
}
PIDReader<T>& operator=(T newValue) {
value = newValue;
return *this;
}
virtual ReturnValue_t serialize(uint8_t **buffer, size_t *size,
size_t maxSize, Endianness streamEndianness) const override {
return SerializeAdapter::serialize(&value, buffer, size, maxSize,
streamEndianness);
}
virtual size_t getSerializedSize() const override {
return SerializeAdapter::getSerializedSize(&value);
}
virtual ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size,
Endianness streamEndianness) override {
return SerializeAdapter::deSerialize(&value, buffer, size,
streamEndianness);
}
};
#endif /* PIDREADER_H_ */

27
datapool/PIDReaderList.h Normal file
View File

@ -0,0 +1,27 @@
#ifndef FRAMEWORK_DATAPOOL_PIDREADERLIST_H_
#define FRAMEWORK_DATAPOOL_PIDREADERLIST_H_
#include "PIDReader.h"
#include "PoolVariableIF.h"
template <class T, uint8_t n_var>
class PIDReaderList {
private:
PIDReader<T> variables[n_var];
public:
PIDReaderList( const uint32_t setPid[n_var], DataSetIF* dataSet) {
//I really should have a look at the new init list c++ syntax.
if (dataSet == NULL) {
return;
}
for (uint8_t count = 0; count < n_var; count++) {
variables[count].parameterId = setPid[count];
dataSet->registerVariable(&variables[count]);
}
}
PIDReader<T> &operator [](int i) { return variables[i]; }
};
#endif /* FRAMEWORK_DATAPOOL_PIDREADERLIST_H_ */

View File

@ -1,25 +1,28 @@
#include "fsfw/datapool/PoolEntry.h"
#include "fsfw/serviceinterface/ServiceInterface.h"
#include "fsfw/globalfunctions/arrayprinter.h"
#include "PoolEntry.h"
#include "../serviceinterface/ServiceInterfaceStream.h"
#include "../globalfunctions/arrayprinter.h"
#include <cstring>
#include <algorithm>
template <typename T>
PoolEntry<T>::PoolEntry(std::initializer_list<T> initValue, bool setValid ):
length(static_cast<uint8_t>(initValue.size())), valid(setValid) {
PoolEntry<T>::PoolEntry(std::initializer_list<T> initValue, uint8_t setLength,
bool setValid ) : length(setLength), valid(setValid) {
this->address = new T[this->length];
if(initValue.size() == 0) {
std::memset(this->address, 0, this->getByteSize());
}
else if (initValue.size() != setLength){
sif::warning << "PoolEntry: setLength is not equal to initializer list"
"length! Performing zero initialization with given setLength"
<< std::endl;
std::memset(this->address, 0, this->getByteSize());
}
else {
std::copy(initValue.begin(), initValue.end(), this->address);
}
}
template <typename T>
PoolEntry<T>::PoolEntry(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];
if (initValue != nullptr) {
@ -63,26 +66,10 @@ bool PoolEntry<T>::getValid() {
template <typename T>
void PoolEntry<T>::print() {
const char* validString = nullptr;
if(valid) {
validString = "Valid";
}
else {
validString = "Invalid";
}
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "PoolEntry information." << std::endl;
sif::info << "PoolEntry validity: " << validString << std::endl;
#else
sif::printInfo("PoolEntry information.\n");
sif::printInfo("PoolEntry validity: %s\n", validString);
#endif
arrayprinter::print(reinterpret_cast<uint8_t*>(address), getByteSize());
}
template<typename T>
inline T* PoolEntry<T>::getDataPtr() {
return this->address;
sif::debug << "Pool Entry Validity: " <<
(this->valid? " (valid) " : " (invalid) ") << std::endl;
arrayprinter::print(reinterpret_cast<uint8_t*>(address), length);
sif::debug << std::dec << std::endl;
}
template<typename T>
@ -93,10 +80,8 @@ Type PoolEntry<T>::getType() {
template class PoolEntry<uint8_t>;
template class PoolEntry<uint16_t>;
template class PoolEntry<uint32_t>;
template class PoolEntry<uint64_t>;
template class PoolEntry<int8_t>;
template class PoolEntry<int16_t>;
template class PoolEntry<int32_t>;
template class PoolEntry<int64_t>;
template class PoolEntry<float>;
template class PoolEntry<double>;

View File

@ -1,5 +1,5 @@
#ifndef FSFW_DATAPOOL_POOLENTRY_H_
#define FSFW_DATAPOOL_POOLENTRY_H_
#ifndef FRAMEWORK_DATAPOOL_POOLENTRY_H_
#define FRAMEWORK_DATAPOOL_POOLENTRY_H_
#include "PoolEntryIF.h"
@ -35,22 +35,24 @@ public:
"uint8_t");
/**
* @brief In the classe's constructor, space is allocated on the heap and
* potential initialization values are copied to that space.
* potential init values are copied to that space.
* @details
* Not passing any arguments will initialize an non-array pool entry
* with an initial invalid state and the value 0.
* Please note that if an initializer list is passed, the length of the
* initializer list needs to be correct for vector entries because
* required allocated space will be deduced from the initializer list length
* and the pool entry type.
* (setLength = 1) with an initial invalid state.
* Please note that if an initializer list is passed, the correct
* corresponding length should be passed too, otherwise a zero
* initialization will be performed with the given setLength.
* @param initValue
* Initializer list with values to initialize with, for example {0, 0} to
* initialize the a pool entry of a vector with two entries to 0.
* Initializer list with values to initialize with, for example {0,0} to
* initialize the two entries to zero.
* @param setLength
* Defines the array length of this entry. Should be equal to the
* intializer list length.
* @param setValid
* Sets the initialization flag. It is invalid by default.
*/
PoolEntry(std::initializer_list<T> initValue = {0}, bool setValid = false);
PoolEntry(std::initializer_list<T> initValue = {}, uint8_t setLength = 1,
bool setValid = false);
/**
* @brief In the classe's constructor, space is allocated on the heap and
* potential init values are copied to that space.
@ -64,9 +66,9 @@ public:
*/
PoolEntry(T* initValue, uint8_t setLength = 1, bool setValid = false);
//! Explicitely deleted copy ctor, copying is not allowed.
//! Explicitely deleted copy ctor, copying is not allowed!
PoolEntry(const PoolEntry&) = delete;
//! Explicitely deleted copy assignment, copying is not allowed.
//! Explicitely deleted copy assignment, copying is not allowed!
PoolEntry& operator=(const PoolEntry&) = delete;
/**
@ -80,16 +82,21 @@ public:
~PoolEntry();
/**
* Return typed pointer to start of data.
* @return
* @brief This is the address pointing to the allocated memory.
*/
T* getDataPtr();
T* address;
/**
* @brief This attribute stores the length information.
*/
uint8_t length;
/**
* @brief Here, the validity information for a variable is stored.
* Every entry (single variable or vector) has one valid flag.
*/
uint8_t valid;
/**
* @brief getSize returns the array size of the entry.
* @details
* For non-array pool entries return type size, for vector entries
* return type size times the number of entries.
* @details A single parameter has size 1.
*/
uint8_t getSize();
/**
@ -116,22 +123,8 @@ public:
* information to the screen. It prints all array entries in a row.
*/
void print();
Type getType();
private:
/**
* @brief This attribute stores the length information.
*/
uint8_t length;
/**
* @brief Here, the validity information for a variable is stored.
* Every entry (single variable or vector) has one valid flag.
*/
uint8_t valid;
/**
* @brief This is the address pointing to the allocated memory.
*/
T* address;
Type getType();
};
#endif /* FSFW_DATAPOOL_POOLENTRY_H_ */
#endif /* POOLENTRY_H_ */

View File

@ -1,5 +1,5 @@
#ifndef FSFW_DATAPOOL_POOLENTRYIF_H_
#define FSFW_DATAPOOL_POOLENTRYIF_H_
#ifndef FRAMEWORK_DATAPOOL_POOLENTRYIF_H_
#define FRAMEWORK_DATAPOOL_POOLENTRYIF_H_
#include "../globalfunctions/Type.h"
#include <cstdint>
@ -60,4 +60,4 @@ public:
virtual Type getType() = 0;
};
#endif /* FSFW_DATAPOOL_POOLENTRYIF_H_ */
#endif /* POOLENTRYIF_H_ */

187
datapool/PoolRawAccess.cpp Normal file
View File

@ -0,0 +1,187 @@
#include "DataPool.h"
#include "PoolEntryIF.h"
#include "PoolRawAccess.h"
#include "../serviceinterface/ServiceInterfaceStream.h"
#include "../serialize/EndianConverter.h"
#include <cstring>
PoolRawAccess::PoolRawAccess(uint32_t set_id, uint8_t setArrayEntry,
DataSetIF *data_set, ReadWriteMode_t setReadWriteMode) :
dataPoolId(set_id), arrayEntry(setArrayEntry), valid(false), type(
Type::UNKNOWN_TYPE), typeSize(0), arraySize(0), sizeTillEnd(0), readWriteMode(
setReadWriteMode) {
memset(value, 0, sizeof(value));
if (data_set != NULL) {
data_set->registerVariable(this);
}
}
PoolRawAccess::~PoolRawAccess() {
}
ReturnValue_t PoolRawAccess::read() {
PoolEntryIF *read_out = ::dataPool.getRawData(dataPoolId);
if (read_out != NULL) {
valid = read_out->getValid();
if (read_out->getSize() > arrayEntry) {
arraySize = read_out->getSize();
typeSize = read_out->getByteSize() / read_out->getSize();
type = read_out->getType();
if (typeSize <= sizeof(value)) {
uint16_t arrayPosition = arrayEntry * typeSize;
sizeTillEnd = read_out->getByteSize() - arrayPosition;
uint8_t *ptr =
&((uint8_t*) read_out->getRawData())[arrayPosition];
memcpy(value, ptr, typeSize);
return HasReturnvaluesIF::RETURN_OK;
} else {
//Error value type too large.
}
} else {
//Error index requested too large
}
} else {
//Error entry does not exist.
}
sif::error << "PoolRawAccess: read of DP Variable 0x" << std::hex
<< dataPoolId << std::dec << " failed." << std::endl;
valid = INVALID;
typeSize = 0;
sizeTillEnd = 0;
memset(value, 0, sizeof(value));
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t PoolRawAccess::commit() {
PoolEntryIF *write_back = ::dataPool.getRawData(dataPoolId);
if ((write_back != NULL) && (readWriteMode != VAR_READ)) {
write_back->setValid(valid);
uint8_t array_position = arrayEntry * typeSize;
uint8_t *ptr = &((uint8_t*) write_back->getRawData())[array_position];
memcpy(ptr, value, typeSize);
return HasReturnvaluesIF::RETURN_OK;
} else {
return HasReturnvaluesIF::RETURN_FAILED;
}
}
uint8_t* PoolRawAccess::getEntry() {
return value;
}
ReturnValue_t PoolRawAccess::getEntryEndianSafe(uint8_t *buffer,
size_t *writtenBytes, size_t maxSize) {
uint8_t *data_ptr = getEntry();
// debug << "PoolRawAccess::getEntry: Array position: " << index * size_of_type << " Size of T: " << (int)size_of_type << " ByteSize: " << byte_size << " Position: " << *size << std::endl;
if (typeSize == 0) {
return DATA_POOL_ACCESS_FAILED;
}
if (typeSize > maxSize) {
return INCORRECT_SIZE;
}
EndianConverter::convertBigEndian(buffer, data_ptr, typeSize);
*writtenBytes = typeSize;
return HasReturnvaluesIF::RETURN_OK;
}
Type PoolRawAccess::getType() {
return type;
}
size_t PoolRawAccess::getSizeOfType() {
return typeSize;
}
size_t PoolRawAccess::getArraySize() {
return arraySize;
}
uint32_t PoolRawAccess::getDataPoolId() const {
return dataPoolId;
}
PoolVariableIF::ReadWriteMode_t PoolRawAccess::getReadWriteMode() const {
return readWriteMode;
}
ReturnValue_t PoolRawAccess::setEntryFromBigEndian(const uint8_t *buffer,
size_t setSize) {
if (typeSize == setSize) {
EndianConverter::convertBigEndian(value, buffer, typeSize);
return HasReturnvaluesIF::RETURN_OK;
} else {
sif::error
<< "PoolRawAccess::setEntryFromBigEndian: Illegal sizes: Internal"
<< (uint32_t) typeSize << ", Requested: " << setSize
<< std::endl;
return INCORRECT_SIZE;
}
}
bool PoolRawAccess::isValid() const {
if (valid != INVALID)
return true;
else
return false;
}
void PoolRawAccess::setValid(uint8_t valid) {
this->valid = valid;
}
size_t PoolRawAccess::getSizeTillEnd() const {
return sizeTillEnd;
}
ReturnValue_t PoolRawAccess::serialize(uint8_t **buffer, size_t *size,
size_t maxSize, Endianness streamEndianness) const {
if (typeSize + *size <= maxSize) {
switch (streamEndianness) {
case (Endianness::BIG):
EndianConverter::convertBigEndian(*buffer, value, typeSize);
break;
case (Endianness::LITTLE):
EndianConverter::convertLittleEndian(*buffer, value, typeSize);
break;
default:
case (Endianness::MACHINE):
memcpy(*buffer, value, typeSize);
break;
}
*size += typeSize;
(*buffer) += typeSize;
return HasReturnvaluesIF::RETURN_OK;
} else {
return SerializeIF::BUFFER_TOO_SHORT;
}
}
size_t PoolRawAccess::getSerializedSize() const {
return typeSize;
}
ReturnValue_t PoolRawAccess::deSerialize(const uint8_t **buffer, size_t *size,
Endianness streamEndianness) {
if (*size >= typeSize) {
switch (streamEndianness) {
case (Endianness::BIG):
EndianConverter::convertBigEndian(value, *buffer, typeSize);
break;
case (Endianness::LITTLE):
EndianConverter::convertLittleEndian(value, *buffer, typeSize);
break;
default:
case (Endianness::MACHINE):
memcpy(value, *buffer, typeSize);
break;
}
*size -= typeSize;
*buffer += typeSize;
return HasReturnvaluesIF::RETURN_OK;
} else {
return SerializeIF::STREAM_TOO_SHORT;
}
}

152
datapool/PoolRawAccess.h Normal file
View File

@ -0,0 +1,152 @@
#ifndef POOLRAWACCESS_H_
#define POOLRAWACCESS_H_
#include "DataSetIF.h"
#include "PoolVariableIF.h"
/**
* This class allows accessing Data Pool variables as raw bytes.
* This is necessary to have an access method for HK data, as the PID's alone do not
* provide a type information.
* \ingroup data_pool
*/
class PoolRawAccess: public PoolVariableIF {
private:
/**
* \brief To access the correct data pool entry on read and commit calls, the data pool id
* is stored.
*/
uint32_t dataPoolId;
/**
* \brief The array entry that is fetched from the data pool.
*/
uint8_t arrayEntry;
/**
* \brief The valid information as it was stored in the data pool is copied to this attribute.
*/
uint8_t valid;
/**
* \brief This value contains the type of the data pool entry.
*/
Type type;
/**
* \brief This value contains the size of the data pool entry in bytes.
*/
size_t typeSize;
/**
* The size of the DP array (single values return 1)
*/
size_t arraySize;
/**
* The size (in bytes) from the selected entry till the end of this DataPool variable.
*/
size_t sizeTillEnd;
/**
* \brief The information whether the class is read-write or read-only is stored here.
*/
ReadWriteMode_t readWriteMode;
static const uint8_t RAW_MAX_SIZE = sizeof(double);
protected:
/**
* \brief This is a call to read the value from the global data pool.
* \details When executed, this operation tries to fetch the pool entry with matching
* data pool id from the global data pool and copies the value and the valid
* information to its local attributes. In case of a failure (wrong type or
* pool id not found), the variable is set to zero and invalid.
* The operation does NOT provide any mutual exclusive protection by itself.
*/
ReturnValue_t read();
/**
* \brief The commit call writes back the variable's value to the data pool.
* \details It checks type and size, as well as if the variable is writable. If so,
* the value is copied and the valid flag is automatically set to "valid".
* The operation does NOT provide any mutual exclusive protection by itself.
*
*/
ReturnValue_t commit();
public:
static const uint8_t INTERFACE_ID = CLASS_ID::POOL_RAW_ACCESS_CLASS;
static const ReturnValue_t INCORRECT_SIZE = MAKE_RETURN_CODE(0x01);
static const ReturnValue_t DATA_POOL_ACCESS_FAILED = MAKE_RETURN_CODE(0x02);
uint8_t value[RAW_MAX_SIZE];
PoolRawAccess(uint32_t data_pool_id, uint8_t arrayEntry,
DataSetIF *data_set, ReadWriteMode_t setReadWriteMode =
PoolVariableIF::VAR_READ);
/**
* \brief The classes destructor is empty. If commit() was not called, the local value is
* discarded and not written back to the data pool.
*/
~PoolRawAccess();
/**
* \brief This operation returns a pointer to the entry fetched.
* \details This means, it does not return a pointer to byte "index", but to the start byte of
* array entry "index". Example: If the original data pool array consists of an double
* array of size four, getEntry(1) returns &(this->value[8]).
*/
uint8_t* getEntry();
/**
* \brief This operation returns the fetched entry from the data pool and
* flips the bytes, if necessary.
* \details It makes use of the getEntry call of this function, but additionally flips the
* bytes to big endian, which is the default for external communication (as House-
* keeping telemetry). To achieve this, the data is copied directly to the passed
* buffer, if it fits in the given maxSize.
* \param buffer A pointer to a buffer to write to
* \param writtenBytes The number of bytes written is returned with this value.
* \param maxSize The maximum size that the function may write to buffer.
* \return - \c RETURN_OK if entry could be acquired
* - \c RETURN_FAILED else.
*/
ReturnValue_t getEntryEndianSafe(uint8_t *buffer, size_t *size,
size_t maxSize);
/**
* With this method, the content can be set from a big endian buffer safely.
* @param buffer Pointer to the data to set
* @param size Size of the data to write. Must fit this->size.
* @return - \c RETURN_OK on success
* - \c RETURN_FAILED on failure
*/
ReturnValue_t setEntryFromBigEndian(const uint8_t *buffer,
size_t setSize);
/**
* \brief This operation returns the type of the entry currently stored.
*/
Type getType();
/**
* \brief This operation returns the size of the entry currently stored.
*/
size_t getSizeOfType();
/**
*
* @return the size of the datapool array
*/
size_t getArraySize();
/**
* \brief This operation returns the data pool id of the variable.
*/
uint32_t getDataPoolId() const;
/**
* This method returns if the variable is read-write or read-only.
*/
ReadWriteMode_t getReadWriteMode() const;
/**
* \brief With this call, the valid information of the variable is returned.
*/
bool isValid() const;
void setValid(uint8_t valid);
/**
* Getter for the remaining size.
*/
size_t getSizeTillEnd() const;
ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize,
Endianness streamEndianness) const override;
size_t getSerializedSize() const override;
ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size,
Endianness streamEndianness) override;
};
#endif /* POOLRAWACCESS_H_ */

28
datapool/PoolVarList.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef POOLVARLIST_H_
#define POOLVARLIST_H_
#include "PoolVariable.h"
#include "PoolVariableIF.h"
template <class T, uint8_t n_var>
class PoolVarList {
private:
PoolVariable<T> variables[n_var];
public:
PoolVarList( const uint32_t set_id[n_var], DataSetIF* dataSet, PoolVariableIF::ReadWriteMode_t setReadWriteMode ) {
//I really should have a look at the new init list c++ syntax.
if (dataSet == NULL) {
return;
}
for (uint8_t count = 0; count < n_var; count++) {
variables[count].dataPoolId = set_id[count];
variables[count].readWriteMode = setReadWriteMode;
dataSet->registerVariable(&variables[count]);
}
}
PoolVariable<T> &operator [](int i) { return variables[i]; }
};
#endif /* POOLVARLIST_H_ */

295
datapool/PoolVariable.h Normal file
View File

@ -0,0 +1,295 @@
/*
* \file PoolVariable.h
*
* \brief This file contains the PoolVariable class, which locally represents a non-array data pool variable.
*
* \date 10/17/2012
*
* \author Bastian Baetz
*/
#ifndef POOLVARIABLE_H_
#define POOLVARIABLE_H_
#include "DataSetIF.h"
#include "PoolEntry.h"
#include "PoolVariableIF.h"
#include "../serialize/SerializeAdapter.h"
#include "../serviceinterface/ServiceInterfaceStream.h"
template<typename T, uint8_t n_var> class PoolVarList;
/**
* \brief This is the access class for non-array data pool entries.
*
* \details To ensure safe usage of the data pool, operation is not done directly on the data pool
* entries, but on local copies. This class provides simple type-safe access to single
* data pool entries (i.e. entries with length = 1).
* The class can be instantiated as read-write and read only.
* It provides a commit-and-roll-back semantic, which means that the variable's value in
* the data pool is not changed until the commit call is executed.
* \tparam T The template parameter sets the type of the variable. Currently, all plain data types
* are supported, but in principle any type is possible.
* \ingroup data_pool
*/
template<typename T>
class PoolVariable: public PoolVariableIF {
template<typename U, uint8_t n_var> friend class PoolVarList;
protected:
/**
* \brief To access the correct data pool entry on read and commit calls, the data pool id
* is stored.
*/
uint32_t dataPoolId;
/**
* \brief The valid information as it was stored in the data pool is copied to this attribute.
*/
uint8_t valid;
/**
* \brief The information whether the class is read-write or read-only is stored here.
*/
ReadWriteMode_t readWriteMode;
/**
* \brief This is a call to read the value from the global data pool.
* \details When executed, this operation tries to fetch the pool entry with matching
* data pool id from the global data pool and copies the value and the valid
* information to its local attributes. In case of a failure (wrong type or
* pool id not found), the variable is set to zero and invalid.
* The operation does NOT provide any mutual exclusive protection by itself.
*/
ReturnValue_t read() {
PoolEntry<T> *read_out = ::dataPool.getData < T > (dataPoolId, 1);
if (read_out != NULL) {
valid = read_out->valid;
value = *(read_out->address);
return HasReturnvaluesIF::RETURN_OK;
} else {
value = 0;
valid = false;
sif::error << "PoolVariable: read of DP Variable 0x" << std::hex
<< dataPoolId << std::dec << " failed." << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
}
/**
* \brief The commit call writes back the variable's value to the data pool.
* \details It checks type and size, as well as if the variable is writable. If so,
* the value is copied and the valid flag is automatically set to "valid".
* The operation does NOT provide any mutual exclusive protection by itself.
*
*/
ReturnValue_t commit() {
PoolEntry<T> *write_back = ::dataPool.getData < T > (dataPoolId, 1);
if ((write_back != NULL) && (readWriteMode != VAR_READ)) {
write_back->valid = valid;
*(write_back->address) = value;
return HasReturnvaluesIF::RETURN_OK;
} else {
return HasReturnvaluesIF::RETURN_FAILED;
}
}
/**
* Empty ctor for List initialization
*/
PoolVariable() :
dataPoolId(PoolVariableIF::NO_PARAMETER), valid(
PoolVariableIF::INVALID), readWriteMode(VAR_READ), value(0) {
}
public:
/**
* \brief This is the local copy of the data pool entry.
* \details The user can work on this attribute
* just like he would on a simple local variable.
*/
T value;
/**
* \brief In the constructor, the variable can register itself in a DataSet (if not NULL is
* passed).
* \details It DOES NOT fetch the current value from the data pool, but sets the value
* attribute to default (0). The value is fetched within the read() operation.
* \param set_id This is the id in the global data pool this instance of the access class
* corresponds to.
* \param dataSet The data set in which the variable shall register itself. If NULL,
* the variable is not registered.
* \param setWritable If this flag is set to true, changes in the value attribute can be
* written back to the data pool, otherwise not.
*/
PoolVariable(uint32_t set_id, DataSetIF *dataSet,
ReadWriteMode_t setReadWriteMode) :
dataPoolId(set_id), valid(PoolVariableIF::INVALID), readWriteMode(
setReadWriteMode), value(0) {
if (dataSet != NULL) {
dataSet->registerVariable(this);
}
}
/**
* Copy ctor to copy classes containing Pool Variables.
*/
PoolVariable(const PoolVariable &rhs) :
dataPoolId(rhs.dataPoolId), valid(rhs.valid), readWriteMode(
rhs.readWriteMode), value(rhs.value) {
}
/**
* \brief The classes destructor is empty.
* \details If commit() was not called, the local value is
* discarded and not written back to the data pool.
*/
~PoolVariable() {
}
/**
* \brief This operation returns the data pool id of the variable.
*/
uint32_t getDataPoolId() const {
return dataPoolId;
}
/**
* This operation sets the data pool id of the variable.
* The method is necessary to set id's of data pool member variables with bad initialization.
*/
void setDataPoolId(uint32_t poolId) {
dataPoolId = poolId;
}
/**
* This method returns if the variable is write-only, read-write or read-only.
*/
ReadWriteMode_t getReadWriteMode() const {
return readWriteMode;
}
/**
* \brief With this call, the valid information of the variable is returned.
*/
bool isValid() const {
if (valid)
return true;
else
return false;
}
uint8_t getValid() {
return valid;
}
void setValid(uint8_t valid) {
this->valid = valid;
}
operator T() {
return value;
}
operator T() const {
return value;
}
PoolVariable<T>& operator=(T newValue) {
value = newValue;
return *this;
}
PoolVariable<T>& operator=(PoolVariable<T> newPoolVariable) {
value = newPoolVariable.value;
return *this;
}
virtual ReturnValue_t serialize(uint8_t **buffer, size_t *size,
size_t maxSize, Endianness streamEndianness) const override {
return SerializeAdapter::serialize<T>(&value, buffer, size, maxSize,
streamEndianness);
}
virtual size_t getSerializedSize() const override {
return SerializeAdapter::getSerializedSize(&value);
}
virtual ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size,
Endianness streamEndianness) override {
return SerializeAdapter::deSerialize(&value, buffer, size, streamEndianness);
}
};
typedef PoolVariable<uint8_t> db_uint8_t;
typedef PoolVariable<uint16_t> db_uint16_t;
typedef PoolVariable<uint32_t> db_uint32_t;
typedef PoolVariable<int8_t> db_int8_t;
typedef PoolVariable<int16_t> db_int16_t;
typedef PoolVariable<int32_t> db_int32_t;
typedef PoolVariable<uint8_t> db_bool_t;
typedef PoolVariable<float> db_float_t;
typedef PoolVariable<double> db_double_t;
//Alternative (but I thing this is not as useful: code duplication, differences too small):
//template <typename T>
//class PoolReader : public PoolVariableIF {
//private:
// uint32_t parameter_id;
// uint8_t valid;
//public:
// T value;
// PoolReader( uint32_t set_id, DataSetIF* set ) : parameter_id(set_id), valid(false), value(0) {
// set->registerVariable( this );
// }
//
// ~PoolReader() {};
//
// uint8_t commit() {
// return HasReturnvaluesIF::RETURN_OK;
// }
//
// uint8_t read() {
// PoolEntry<T>* read_out = ::dataPool.getData<T>( parameter_id, 1 );
// if ( read_out != NULL ) {
// valid = read_out->valid;
// value = *(read_out->address);
// return HasReturnvaluesIF::RETURN_OK;
// } else {
// value = 0;
// valid = false;
// return CHECKOUT_FAILED;
// }
// }
// uint32_t getParameterId() { return parameter_id; }
// bool isWritable() { return false; };
// bool isValid() { if (valid) return true; else return false; }
//};
//
//template <typename T>
//class PoolWriter : public PoolVariableIF {
//private:
// uint32_t parameter_id;
//public:
// T value;
// PoolWriter( uint32_t set_id, DataSetIF* set ) : parameter_id(set_id), value(0) {
// set->registerVariable( this );
// }
//
// ~PoolWriter() {};
//
// uint8_t commit() {
// PoolEntry<T>* write_back = ::dataPool.getData<T>( parameter_id, 1 );
// if ( write_back != NULL ) {
// write_back->valid = true;
// *(write_back->address) = value;
// return HasReturnvaluesIF::RETURN_OK;
// } else {
// return CHECKOUT_FAILED;
// }
// }
// uint8_t read() {
// PoolEntry<T>* read_out = ::dataPool.getData<T>( parameter_id, 1 );
// if ( read_out != NULL ) {
// value = *(read_out->address);
// return HasReturnvaluesIF::RETURN_OK;
// } else {
// value = 0;
// return CHECKOUT_FAILED;
// }
// }
// uint32_t getParameterId() { return parameter_id; }
// bool isWritable() { return true; };
// bool isValid() { return false; }
//};
#endif /* POOLVARIABLE_H_ */

71
datapool/PoolVariableIF.h Normal file
View File

@ -0,0 +1,71 @@
/*
* \file PoolVariableIF.h
*
* \brief This file contains the interface definition for pool variables.
*
* \date 10/17/2012
*
* \author Bastian Baetz
*/
#ifndef POOLVARIABLEIF_H_
#define POOLVARIABLEIF_H_
#include "../returnvalues/HasReturnvaluesIF.h"
#include "../serialize/SerializeIF.h"
/**
* \brief This interface is used to control local data pool variable representations.
*
* \details To securely handle data pool variables, all pool entries are locally managed by
* data pool variable access classes, which are called pool variables. To ensure a
* common state of a set of variables needed in a function, these local pool variables
* again are managed by other classes, e.g. the DataSet. This interface provides unified
* access to local pool variables for such manager classes.
* \ingroup data_pool
*/
class PoolVariableIF : public SerializeIF {
friend class DataSet;
protected:
/**
* \brief The commit call shall write back a newly calculated local value to the data pool.
*/
virtual ReturnValue_t commit() = 0;
/**
* \brief The read call shall read the value of this parameter from the data pool and store
* the content locally.
*/
virtual ReturnValue_t read() = 0;
public:
static const uint8_t VALID = 1;
static const uint8_t INVALID = 0;
static const uint32_t NO_PARAMETER = 0;
enum ReadWriteMode_t {
VAR_READ, VAR_WRITE, VAR_READ_WRITE
};
/**
* \brief This is an empty virtual destructor, as it is proposed for C++ interfaces.
*/
virtual ~PoolVariableIF() {
}
/**
* \brief This method returns if the variable is write-only, read-write or read-only.
*/
virtual ReadWriteMode_t getReadWriteMode() const = 0;
/**
* \brief This operation shall return the data pool id of the variable.
*/
virtual uint32_t getDataPoolId() const = 0;
/**
* \brief With this call, the valid information of the variable is returned.
*/
virtual bool isValid() const = 0;
/**
* \brief With this call, the valid information of the variable is set.
*/
virtual void setValid(uint8_t validity) = 0;
};
#endif /* POOLVARIABLEIF_H_ */

233
datapool/PoolVector.h Normal file
View File

@ -0,0 +1,233 @@
/*
* \file PoolVector.h
*
* \brief This file contains the PoolVector class, the header only class to handle data pool vectors.
*
* \date 10/23/2012
*
* \author Bastian Baetz
*/
#ifndef POOLVECTOR_H_
#define POOLVECTOR_H_
#include "DataSetIF.h"
#include "PoolEntry.h"
#include "PoolVariableIF.h"
#include "../serialize/SerializeAdapter.h"
#include "../serviceinterface/ServiceInterfaceStream.h"
/**
* \brief This is the access class for array-type data pool entries.
*
* \details To ensure safe usage of the data pool, operation is not done directly on the data pool
* entries, but on local copies. This class provides simple type- and length-safe access
* to vector-style data pool entries (i.e. entries with length > 1).
* The class can be instantiated as read-write and read only.
* It provides a commit-and-roll-back semantic, which means that no array entry in
* the data pool is changed until the commit call is executed.
* There are two template parameters:
* \tparam T This template parameter specifies the data type of an array entry. Currently, all
* plain data types are supported, but in principle any type is possible.
* \tparam vector_size This template parameter specifies the vector size of this entry.
* Using a template parameter for this is not perfect, but avoids dynamic memory allocation.
* \ingroup data_pool
*/
template<typename T, uint16_t vector_size>
class PoolVector: public PoolVariableIF {
private:
/**
* \brief To access the correct data pool entry on read and commit calls, the data pool id
* is stored.
*/
uint32_t dataPoolId;
/**
* \brief The valid information as it was stored in the data pool is copied to this attribute.
*/
uint8_t valid;
/**
* \brief The information whether the class is read-write or read-only is stored here.
*/
ReadWriteMode_t readWriteMode;
protected:
/**
* \brief This is a call to read the array's values from the global data pool.
* \details When executed, this operation tries to fetch the pool entry with matching
* data pool id from the global data pool and copies all array values and the valid
* information to its local attributes. In case of a failure (wrong type, size or
* pool id not found), the variable is set to zero and invalid.
* The operation does NOT provide any mutual exclusive protection by itself.
*/
ReturnValue_t read() {
PoolEntry<T>* read_out = ::dataPool.getData<T>(this->dataPoolId,
vector_size);
if (read_out != NULL) {
this->valid = read_out->valid;
memcpy(this->value, read_out->address, read_out->getByteSize());
return HasReturnvaluesIF::RETURN_OK;
} else {
memset(this->value, 0, vector_size * sizeof(T));
sif::error << "PoolVector: read of DP Variable 0x" << std::hex
<< dataPoolId << std::dec << " failed." << std::endl;
this->valid = INVALID;
return HasReturnvaluesIF::RETURN_FAILED;
}
}
/**
* \brief The commit call copies the array values back to the data pool.
* \details It checks type and size, as well as if the variable is writable. If so,
* the value is copied and the valid flag is automatically set to "valid".
* The operation does NOT provide any mutual exclusive protection by itself.
*
*/
ReturnValue_t commit() {
PoolEntry<T>* write_back = ::dataPool.getData<T>(this->dataPoolId,
vector_size);
if ((write_back != NULL) && (this->readWriteMode != VAR_READ)) {
write_back->valid = valid;
memcpy(write_back->address, this->value, write_back->getByteSize());
return HasReturnvaluesIF::RETURN_OK;
} else {
return HasReturnvaluesIF::RETURN_FAILED;
}
}
public:
/**
* \brief This is the local copy of the data pool entry.
* \detials The user can work on this attribute
* just like he would on a local array of this type.
*/
T value[vector_size];
/**
* \brief In the constructor, the variable can register itself in a DataSet (if not NULL is
* passed).
* \details It DOES NOT fetch the current value from the data pool, but sets the value
* attribute to default (0). The value is fetched within the read() operation.
* \param set_id This is the id in the global data pool this instance of the access class
* corresponds to.
* \param dataSet The data set in which the variable shall register itself. If NULL,
* the variable is not registered.
* \param setWritable If this flag is set to true, changes in the value attribute can be
* written back to the data pool, otherwise not.
*/
PoolVector(uint32_t set_id, DataSetIF* set,
ReadWriteMode_t setReadWriteMode) :
dataPoolId(set_id), valid(false), readWriteMode(setReadWriteMode) {
memset(this->value, 0, vector_size * sizeof(T));
if (set != NULL) {
set->registerVariable(this);
}
}
/**
* Copy ctor to copy classes containing Pool Variables.
*/
// PoolVector(const PoolVector& rhs) {
// PoolVector<T, vector_size> temp(rhs.dataPoolId, rhs.)
// memcpy(value, rhs.value, sizeof(T)*vector_size);
// }
/**
* \brief The classes destructor is empty.
* \details If commit() was not called, the local value is
* discarded and not written back to the data pool.
*/
~PoolVector() {
}
;
/**
* \brief The operation returns the number of array entries in this variable.
*/
uint8_t getSize() {
return vector_size;
}
/**
* \brief This operation returns the data pool id of the variable.
*/
uint32_t getDataPoolId() const {
return dataPoolId;
}
/**
* This operation sets the data pool id of the variable.
* The method is necessary to set id's of data pool member variables with bad initialization.
*/
void setDataPoolId(uint32_t poolId) {
dataPoolId = poolId;
}
/**
* This method returns if the variable is write-only, read-write or read-only.
*/
ReadWriteMode_t getReadWriteMode() const {
return readWriteMode;
}
;
/**
* \brief With this call, the valid information of the variable is returned.
*/
bool isValid() const {
if (valid != INVALID)
return true;
else
return false;
}
void setValid(uint8_t valid) {
this->valid = valid;
}
uint8_t getValid() {
return valid;
}
T &operator [](int i) {
return value[i];
}
const T &operator [](int i) const {
return value[i];
}
PoolVector<T, vector_size> &operator=(
PoolVector<T, vector_size> newPoolVector) {
for (uint16_t i = 0; i < vector_size; i++) {
this->value[i] = newPoolVector.value[i];
}
return *this;
}
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size,
size_t maxSize, Endianness streamEndianness) const {
uint16_t i;
ReturnValue_t result;
for (i = 0; i < vector_size; i++) {
result = SerializeAdapter::serialize(&(value[i]), buffer, size,
maxSize, streamEndianness);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
}
return result;
}
virtual size_t getSerializedSize() const {
return vector_size * SerializeAdapter::getSerializedSize(value);
}
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
Endianness streamEndianness) {
uint16_t i;
ReturnValue_t result;
for (i = 0; i < vector_size; i++) {
result = SerializeAdapter::deSerialize(&(value[i]), buffer, size,
streamEndianness);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
}
return result;
}
};
#endif /* POOLVECTOR_H_ */

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