Merge pull request 'Apollo Sojus Test Project Version 1.0.0' (#408) from development into master

Reviewed-on: #408
This commit is contained in:
Steffen Gaisser 2021-04-27 14:20:06 +02:00
commit 2f511523cb
589 changed files with 26176 additions and 13783 deletions

98
CHANGELOG Normal file
View File

@ -0,0 +1,98 @@
## 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).

206
CMakeLists.txt Normal file
View File

@ -0,0 +1,206 @@
cmake_minimum_required(VERSION 3.13)
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_WARNING_SHADOW_LOCAL_GCC "Enable -Wshadow=local warning in GCC" ON)
# Options to exclude parts of the FSFW from compilation.
option(FSFW_USE_RMAP "Compile with RMAP" ON)
option(FSFW_USE_DATALINKLAYER "Compile with Data Link Layer" ON)
set(LIB_FSFW_NAME fsfw)
add_library(${LIB_FSFW_NAME})
set_property(CACHE OS_FSFW PROPERTY STRINGS host linux rtems freertos)
if(NOT OS_FSFW)
message(STATUS "No OS for FSFW via OS_FSFW set. Assuming host OS")
# Assume host OS and autodetermine from OS_FSFW
if(UNIX)
set(OS_FSFW "linux"
CACHE STRING
"OS abstraction layer used in the FSFW"
)
elseif(WIN32)
set(OS_FSFW "host"
CACHE STRING "OS abstraction layer used in the FSFW"
)
endif()
endif()
set(FSFW_OSAL_DEFINITION FSFW_HOST)
if(${OS_FSFW} STREQUAL host)
set(OS_FSFW_NAME "Host")
elseif(${OS_FSFW} STREQUAL linux)
set(OS_FSFW_NAME "Linux")
set(FSFW_OSAL_DEFINITION FSFW_LINUX)
elseif(${OS_FSFW} STREQUAL freertos)
set(OS_FSFW_NAME "FreeRTOS")
set(FSFW_OSAL_DEFINITION FSFW_FREERTOS)
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
${LIB_OS_NAME}
)
elseif(${OS_FSFW} STREQUAL rtems)
set(OS_FSFW_NAME "RTEMS")
set(FSFW_OSAL_DEFINITION FSFW_RTEMS)
else()
message(WARNING
"Invalid operating system for FSFW specified! Setting to host.."
)
set(OS_FSFW_NAME "Host")
set(OS_FSFW "host")
endif()
target_compile_definitions(${LIB_FSFW_NAME} PRIVATE
${FSFW_OSAL_DEFINITION}
)
target_compile_definitions(${LIB_FSFW_NAME} INTERFACE
${FSFW_OSAL_DEFINITION}
)
message(STATUS "Compiling FSFW for the ${OS_FSFW_NAME} operating system.")
add_subdirectory(action)
add_subdirectory(container)
add_subdirectory(controller)
add_subdirectory(coordinates)
if(FSFW_USE_DATALINKLAYER)
add_subdirectory(datalinklayer)
endif()
add_subdirectory(datapool)
add_subdirectory(datapoollocal)
add_subdirectory(housekeeping)
add_subdirectory(devicehandlers)
add_subdirectory(events)
add_subdirectory(fdir)
add_subdirectory(globalfunctions)
add_subdirectory(health)
add_subdirectory(internalError)
add_subdirectory(ipc)
add_subdirectory(memory)
add_subdirectory(modes)
add_subdirectory(monitoring)
add_subdirectory(objectmanager)
add_subdirectory(osal)
add_subdirectory(parameters)
add_subdirectory(power)
add_subdirectory(pus)
if(FSFW_USE_RMAP)
add_subdirectory(rmap)
endif()
add_subdirectory(serialize)
add_subdirectory(serviceinterface)
add_subdirectory(storagemanager)
add_subdirectory(subsystem)
add_subdirectory(tasks)
add_subdirectory(tcdistribution)
add_subdirectory(thermal)
add_subdirectory(timemanager)
add_subdirectory(tmstorage)
add_subdirectory(tmtcpacket)
add_subdirectory(tmtcservices)
add_subdirectory(unittest)
# 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)
message(WARNING "Flight Software Framework configuration path not set!")
message(WARNING "Setting default configuration!")
add_subdirectory(defaultcfg/fsfwconfig)
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_PATH})
if(IS_ABSOLUTE ${INCLUDE_PATH})
set(CURR_ABS_INC_PATH "${FREERTOS_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_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_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}
)

View File

@ -3,9 +3,9 @@
const char* const FSFW_VERSION_NAME = "ASTP";
#define FSFW_VERSION 0
#define FSFW_SUBVERSION 0
#define FSFW_REVISION 1
#define FSFW_VERSION 1
#define FSFW_SUBVERSION 0
#define FSFW_REVISION 0

177
README.md
View File

@ -1,4 +1,5 @@
![FSFW Logo](logo/FSFW_Logo_V3_bw.png)
# Flight Software Framework (FSFW)
The Flight Software Framework is a C++ Object Oriented Framework for unmanned,
@ -8,152 +9,40 @@ 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.
## Intended Use
## Quick facts
The framework is designed for systems, which communicate with external devices, perform control loops, receive telecommands and send telemetry, and need to maintain a high level of availability.
Therefore, a mode and health system provides control over the states of the software and the controlled devices.
In addition, a simple mechanism of event based fault detection, isolation and recovery is implemented as well.
The framework is designed for systems, which communicate with external devices, perform control loops, receive telecommands and send telemetry, and need to maintain a high level of availability. Therefore, a mode and health system provides control over the states of the software and the controlled devices. In addition, a simple mechanism of event based fault detection, isolation and recovery is implemented as well.
The 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.
The FSFW provides abstraction layers for operating systems to provide a uniform operating system abstraction layer (OSAL). Some components of this OSAL are required internally by the FSFW but is also very useful for developers to implement the same application logic on different operating systems with a uniform interface.
Currently, the FSFW provides the following OSALs:
- Linux
- Host
- FreeRTOS
- RTEMS
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.
## Getting started
The [FSFW example](https://egit.irs.uni-stuttgart.de/fsfw/fsfw_example) provides a good starting point and a demo to see the FSFW capabilities and build it with the Make or the CMake build system. It is recommended to evaluate the FSFW by building and playing around with the demo application.
Generally, the FSFW is included in a project by compiling the FSFW sources and providing
a configuration folder and adding it to the include path. There are some functions like `printChar` which are different depending on the target architecture and need to be implemented by the mission developer.
A template configuration folder was provided and can be copied into the project root to have
a starting point. The [configuration section](doc/README-config.md#top) provides more specific information about the possible options.
## Index
[1. High-level overview](doc/README-highlevel.md#top) <br>
[2. Core components](doc/README-core.md#top) <br>
[3. OSAL overview](doc/README-osal.md#top) <br>
[4. PUS services](doc/README-pus.md#top) <br>
[5. Device Handler overview](doc/README-devicehandlers.md#top) <br>
[6. Controller overview](doc/README-controllers.md#top) <br>
[7. Local Data Pools](doc/README-localpools.md#top) <br>
## Structure
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.
### Failure Handling
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.
### 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.
### Core Components
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
ObjectManager (must be created):
* 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.
``` c++
template <typename T> T* ObjectManagerIF::get( object_id_t id )
```
* 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.
Event Manager:
* 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:
``` 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;
}
```
Health Table:
* A component which holds every health state
* Provides a thread safe way to access all health states without the need of message exchanges
Stores
* 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
Tasks
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.

View File

@ -3,151 +3,119 @@
#include "../ipc/MessageQueueSenderIF.h"
#include "../objectmanager/ObjectManagerIF.h"
#include "../serviceinterface/ServiceInterface.h"
ActionHelper::ActionHelper(HasActionsIF* setOwner,
MessageQueueIF* useThisQueue) :
owner(setOwner), queueToUse(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;
}
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_);
}
ipcStore = objectManager->get<StorageManagerIF>(objects::IPC_STORE);
if (ipcStore == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
if(queueToUse_ != nullptr) {
setQueueToUse(queueToUse_);
}
return HasReturnvaluesIF::RETURN_OK;
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);
CommandMessage reply;
ActionMessage::setStepReply(&reply, commandId, step + STEP_OFFSET, result);
queueToUse->sendMessage(reportTo, &reply);
}
void ActionHelper::finish(MessageQueueId_t reportTo, ActionId_t commandId,
void ActionHelper::finish(bool success, MessageQueueId_t reportTo, ActionId_t commandId,
ReturnValue_t result) {
CommandMessage reply;
ActionMessage::setCompletionReply(&reply, commandId, result);
queueToUse->sendMessage(reportTo, &reply);
CommandMessage reply;
ActionMessage::setCompletionReply(&reply, commandId, success, result);
queueToUse->sendMessage(reportTo, &reply);
}
void ActionHelper::setQueueToUse(MessageQueueIF* queue) {
queueToUse = 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;
}
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, true, 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) {
ActionId_t replyId, SerializeIF* data, bool hideSender) {
CommandMessage reply;
store_address_t storeAddress;
ReturnValue_t result = ipcStore->addData(&storeAddress, data, dataSize);
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) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "ActionHelper::reportData: Getting free element from IPC store failed!" <<
std::endl;
#else
sif::printWarning("ActionHelper::reportData: Getting free element from IPC "
"store failed!\n");
#endif
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.
/* 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 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);
}
@ -160,3 +128,40 @@ ReturnValue_t ActionHelper::reportData(MessageQueueId_t reportTo,
}
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) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "ActionHelper::reportData: Adding data to IPC store failed!" << std::endl;
#else
sif::printWarning("ActionHelper::reportData: Adding data to IPC store failed!\n");
#endif
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;
}

View File

@ -18,68 +18,68 @@ 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);
/**
* 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);
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 success Specify whether action was completed successfully or not.
* @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(bool success, 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.
@ -91,35 +91,36 @@ public:
*/
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);
/**
* 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;
//! Increase of value of this per step
static const uint8_t STEP_OFFSET = 1;
//! Pointer to the owner
HasActionsIF* 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();
/**
* 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_ */

View File

@ -1,4 +1,6 @@
#include "ActionMessage.h"
#include "HasActionsIF.h"
#include "../objectmanager/ObjectManagerIF.h"
#include "../storagemanager/StorageManagerIF.h"
@ -9,71 +11,72 @@ 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);
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());
return ActionId_t(message->getParameter());
}
store_address_t ActionMessage::getStoreId(const CommandMessage* message) {
store_address_t temp;
temp.raw = message->getParameter2();
return temp;
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);
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);
return uint8_t((message->getParameter2() >> 16) & 0xFF);
}
ReturnValue_t ActionMessage::getReturnCode(const CommandMessage* message) {
return message->getParameter2() & 0xFFFF;
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);
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);
ActionId_t fid, bool success, ReturnValue_t result) {
if (success) {
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;
}
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;
}
}

View File

@ -4,33 +4,44 @@
#include "../ipc/CommandMessage.h"
#include "../objectmanager/ObjectManagerIF.h"
#include "../storagemanager/StorageManagerIF.h"
typedef uint32_t ActionId_t;
using ActionId_t = uint32_t;
/**
* @brief These messages are part of the action module of the FSFW.
* @details
* These messages are sent amongst objects implementing the HasActionsIF. Classes like the
* ActionHelper are able to process these messages.
*/
class ActionMessage {
private:
ActionMessage();
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);
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,
bool success, ReturnValue_t result = HasReturnvaluesIF::RETURN_OK);
static void clear(CommandMessage* message);
};
#endif /* FSFW_ACTION_ACTIONMESSAGE_H_ */

7
action/CMakeLists.txt Normal file
View File

@ -0,0 +1,7 @@
target_sources(${LIB_FSFW_NAME}
PRIVATE
ActionHelper.cpp
ActionMessage.cpp
CommandActionHelper.cpp
SimpleActionHelper.cpp
)

View File

@ -5,123 +5,123 @@
#include "../objectmanager/ObjectManagerIF.h"
CommandActionHelper::CommandActionHelper(CommandsActionsIF *setOwner) :
owner(setOwner), queueToUse(NULL), ipcStore(
NULL), commandCount(0), lastTarget(0) {
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);
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);
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;
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;
}
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;
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;
}
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;
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);
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

@ -11,26 +11,26 @@
class CommandsActionsIF;
class CommandActionHelper {
friend class CommandsActionsIF;
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;
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);
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

@ -15,22 +15,22 @@
* - replyReceived(id, step, cause) (if cause == OK, it's a success).
*/
class CommandsActionsIF {
friend class CommandActionHelper;
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;
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;
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;
};

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

@ -2,74 +2,74 @@
#include "SimpleActionHelper.h"
SimpleActionHelper::SimpleActionHelper(HasActionsIF* setOwner,
MessageQueueIF* useThisQueue) :
ActionHelper(setOwner, useThisQueue), isExecuting(false) {
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();
}
// 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();
ActionHelper::finish(lastCommander, lastAction, result);
resetHelper();
}
ReturnValue_t SimpleActionHelper::reportData(SerializeIF* data) {
return ActionHelper::reportData(lastCommander, lastAction, data);
return ActionHelper::reportData(lastCommander, lastAction, data);
}
void SimpleActionHelper::resetHelper() {
stepCount = 0;
isExecuting = false;
lastAction = 0;
lastCommander = 0;
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;
}
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,
true, HasReturnvaluesIF::RETURN_OK);
queueToUse->sendMessage(commandedBy, &reply);
break;
default:
ActionMessage::setStepReply(&reply, actionId, 0, result);
queueToUse->sendMessage(commandedBy, &reply);
break;
}
}

View File

@ -4,27 +4,27 @@
#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
* @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);
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();
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;
bool isExecuting;
MessageQueueId_t lastCommander = MessageQueueIF::NO_QUEUE;
ActionId_t lastAction = 0;
uint8_t stepCount = 0;
};
#endif /* SIMPLEACTIONHELPER_H_ */

View File

@ -6,7 +6,7 @@
#include "../serialize/SerializeIF.h"
/**
* @brief A List that stores its values in an array.
* @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.
@ -15,237 +15,237 @@
*/
template<typename T, typename count_t = uint8_t>
class ArrayList {
template<typename U, typename count> friend class SerialArrayListAdapter;
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);
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 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) {
}
/**
* 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;
/**
* 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;
/**
* 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;
}
}
/**
* 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) {}
/**
* 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;
}
/**
* Initializes the Iterator to point to an element
*
* @param initialize
*/
Iterator(T *initialize) {
value = initialize;
}
/**
* The current element the iterator points to
*/
T *value;
/**
* The current element the iterator points to
*/
T *value;
Iterator& operator++() {
value++;
return *this;
}
Iterator& operator++() {
value++;
return *this;
}
Iterator operator++(int) {
Iterator tmp(*this);
operator++();
return tmp;
}
Iterator operator++(int) {
Iterator tmp(*this);
operator++();
return tmp;
}
Iterator& operator--() {
value--;
return *this;
}
Iterator& operator--() {
value--;
return *this;
}
Iterator operator--(int) {
Iterator tmp(*this);
operator--();
return tmp;
}
Iterator operator--(int) {
Iterator tmp(*this);
operator--();
return tmp;
}
T& operator*() {
return *value;
}
T& operator*() {
return *value;
}
const T& operator*() const {
return *value;
}
const T& operator*() const {
return *value;
}
T *operator->() {
return value;
}
T *operator->() {
return value;
}
const T *operator->() const {
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 (lhs.value == rhs.value);
}
friend bool operator!=(const ArrayList::Iterator& lhs,
const ArrayList::Iterator& rhs) {
return not (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]);
}
/**
* 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]);
}
/**
* 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];
}
T & operator[](count_t i) const {
return entries[i];
}
/**
* The first element
*
* @return pointer to the first stored element
*/
T *front() {
return entries;
}
/**
* 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());
}
/**
* 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];
}
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_;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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);
}
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_;
/**
* 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;
/**
* true if the array was allocated and needs to be deleted in the destructor.
*/
bool allocated;
};

View File

@ -7,65 +7,65 @@
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;
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);
}
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);
}
}
_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;
}
}
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;
}
if (element != NULL) {
return element->value;
} else {
return NULL;
}
}
pointer operator*() const {
return this->operator->();
return this->operator->();
}
};
@ -75,77 +75,77 @@ public:
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;
}
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;
Node* rootNode;
};

5
container/CMakeLists.txt Normal file
View File

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

View File

@ -5,8 +5,8 @@
#include <vector>
/**
* @brief Simple First-In-First-Out data structure. The maximum size
* can be set in the constructor.
* @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!
@ -17,39 +17,39 @@
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());
};
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 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;
}
/**
* @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;
std::vector<T> fifoVector;
};
#endif /* FSFW_CONTAINER_DYNAMICFIFO_H_ */

View File

@ -5,8 +5,8 @@
#include <array>
/**
* @brief Simple First-In-First-Out data structure with size fixed at
* compile time
* @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.
@ -16,32 +16,32 @@
template<typename T, size_t capacity>
class FIFO: public FIFOBase<T> {
public:
FIFO(): FIFOBase<T>(nullptr, capacity) {
this->setContainer(fifoArray.data());
};
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 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;
}
/**
* @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;
std::array<T, capacity> fifoArray;
};
#endif /* FSFW_CONTAINER_FIFO_H_ */

View File

@ -8,70 +8,70 @@
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);
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);
/** 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();
/**
* 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;
/***
* 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;
void setContainer(T* data);
size_t maxCapacity = 0;
T* values;
T* values;
size_t readIndex = 0;
size_t writeIndex = 0;
size_t currentSize = 0;
size_t readIndex = 0;
size_t writeIndex = 0;
size_t currentSize = 0;
size_t next(size_t current);
size_t next(size_t current);
};
#include "FIFOBase.tpp"

View File

@ -7,87 +7,87 @@
template<typename T>
inline FIFOBase<T>::FIFOBase(T* values, const size_t maxCapacity):
maxCapacity(maxCapacity), values(values){};
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;
}
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;
}
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;
}
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);
T value;
return this->retrieve(&value);
};
template<typename T>
inline bool FIFOBase<T>::empty() {
return (currentSize == 0);
return (currentSize == 0);
};
template<typename T>
inline bool FIFOBase<T>::full() {
return (currentSize == maxCapacity);
return (currentSize == maxCapacity);
}
template<typename T>
inline size_t FIFOBase<T>::size() {
return currentSize;
return currentSize;
}
template<typename T>
inline size_t FIFOBase<T>::next(size_t current) {
++current;
if (current == maxCapacity) {
current = 0;
}
return current;
++current;
if (current == maxCapacity) {
current = 0;
}
return current;
}
template<typename T>
inline size_t FIFOBase<T>::getMaxCapacity() const {
return maxCapacity;
return maxCapacity;
}
template<typename T>
inline void FIFOBase<T>::setContainer(T *data) {
this->values = data;
this->values = data;
}
#endif

View File

@ -8,30 +8,32 @@
*/
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");
#if !defined(_MSC_VER)
static_assert(MAX_SIZE <= (std::pow(2,sizeof(count_t)*8)-1), "count_t is not large enough to hold MAX_SIZE");
#endif
private:
T data[MAX_SIZE];
T data[MAX_SIZE];
public:
FixedArrayList() :
ArrayList<T, count_t>(data, MAX_SIZE) {
}
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(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;
}
FixedArrayList& operator=(FixedArrayList other) {
memcpy(this->data, other.data, sizeof(this->data));
this->entries = data;
this->size = other.size;
return *this;
}
virtual ~FixedArrayList() {
}
virtual ~FixedArrayList() {
}
};

View File

@ -18,212 +18,212 @@
*/
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");
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);
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;
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;
}
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) {
}
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() {
}
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) {
}
};
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 (lhs.value == rhs.value);
}
friend bool operator!=(const typename FixedMap::Iterator& lhs,
const typename FixedMap::Iterator& rhs) {
return not (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 begin() const {
return Iterator(&theMap[0]);
}
Iterator end() const {
return Iterator(&theMap[_size]);
}
Iterator end() const {
return Iterator(&theMap[_size]);
}
uint32_t size() const {
return _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(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 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 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(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;
}
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;
}
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)]);
}
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;
}
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 empty() {
if(_size == 0) {
return true;
}
else {
return false;
}
}
bool full() {
if(_size >= theMap.maxSize()) {
return true;
}
else {
return false;
}
}
bool full() {
if(_size >= theMap.maxSize()) {
return true;
}
else {
return false;
}
}
void clear() {
_size = 0;
}
void clear() {
_size = 0;
}
uint32_t maxSize() const {
return theMap.maxSize();
}
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 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;
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);
}
for (i = 0; i < _size; ++i) {
printSize += SerializeAdapter::getSerializedSize(
&theMap[i].first);
printSize += SerializeAdapter::getSerializedSize(&theMap[i].second);
}
return printSize;
}
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;
}
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;
}
};

View File

@ -3,6 +3,7 @@
#include "ArrayList.h"
#include <cstring>
#include <functional>
/**
* @brief An associative container which allows multiple entries of the same key.
@ -33,172 +34,172 @@
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);
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
*/
/***
* 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() {
}
/***
* 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() {
}
/***
* 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) {
}
};
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 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 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;
}
/***
* 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;
}
/**
* 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();
}
/**
* 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 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);
/***
* 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;
/***
* 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 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);
/***
* 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)]);
};
/***
* 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;
/***
* 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 (lhs.value == rhs.value);
}
friend bool operator!=(const typename FixedOrderedMultimap::Iterator& lhs,
const typename FixedOrderedMultimap::Iterator& rhs) {
return not (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;
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 findFirstIndex(key_t key, size_t startAt = 0) const;
size_t findNicePlace(key_t key) const;
size_t findNicePlace(key_t key) const;
void removeFromPosition(size_t position);
void removeFromPosition(size_t position);
};
#include "FixedOrderedMultimap.tpp"

View File

@ -4,105 +4,105 @@
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;
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);
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;
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;
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;
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;
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;
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;
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;
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;
}

View File

@ -6,85 +6,85 @@
template<typename T, typename count_t = uint8_t>
class HybridIterator: public LinkedElement<T>::Iterator,
public ArrayList<T, count_t>::Iterator {
public ArrayList<T, count_t>::Iterator {
public:
HybridIterator() {}
HybridIterator() {}
HybridIterator(typename LinkedElement<T>::Iterator *iter) :
LinkedElement<T>::Iterator(*iter), value(iter->value),
linked(true) {
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(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(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(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;
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;
}
if (value == end) {
value = nullptr;
}
}
return *this;
}
HybridIterator operator++(int) {
HybridIterator tmp(*this);
operator++();
return tmp;
}
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 value == other.value;
}
bool operator!=(const HybridIterator& other) const {
return !(*this == other);
}
bool operator!=(const HybridIterator& other) const {
return !(*this == other);
}
T operator*() {
return *value;
}
T operator*() {
return *value;
}
T *operator->() {
return value;
}
T *operator->() {
return value;
}
T* value = nullptr;
T* value = nullptr;
private:
bool linked = false;
T *end = nullptr;
bool linked = false;
T *end = nullptr;
};
#endif /* FRAMEWORK_CONTAINER_HYBRIDITERATOR_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -22,50 +22,50 @@
*/
class PlacementFactory {
public:
PlacementFactory(StorageManagerIF* backend) :
dataBackend(backend) {
}
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));
}
/***
* 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;
StorageManagerIF* dataBackend;
};
#endif /* FRAMEWORK_CONTAINER_PLACEMENTFACTORY_H_ */

View File

@ -7,107 +7,107 @@
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;
}
}
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() {}
virtual ~RingBufferBase() {}
bool isFull(uint8_t n = 0) {
return (availableWriteSpace(n) == 0);
}
bool isEmpty(uint8_t n = 0) {
return (getAvailableReadData(n) == 0);
}
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);
}
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;
}
bool overwritesOld() const {
return overwriteOld;
}
size_t getMaxSize() const {
return size - 1;
}
size_t getMaxSize() const {
return size - 1;
}
void clear() {
write = start;
for (uint8_t count = 0; count < N_READ_PTRS; count++) {
read[count] = start;
}
}
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 writeTillWrap() {
return (start + size) - write;
}
size_t readTillWrap(uint8_t n = 0) {
return (start + size) - read[n];
}
size_t readTillWrap(uint8_t n = 0) {
return (start + size) - read[n];
}
size_t getStart() const {
return start;
}
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;
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;
}
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 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;
}
}
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];
}
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;
}
}
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;
}
uint32_t getWrite() const {
return write;
}
void setWrite(uint32_t write) {
this->write = write;
}
void setWrite(uint32_t write) {
this->write = write;
}
};
#endif /* FSFW_CONTAINER_RINGBUFFERBASE_H_ */

View File

@ -1,25 +1,28 @@
#include "SharedRingBuffer.h"
#include "../ipc/MutexFactory.h"
#include "../ipc/MutexHelper.h"
#include "../ipc/MutexGuard.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();
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();
const size_t size, bool overwriteOld, size_t maxExcessBytes):
SystemObject(objectId), SimpleRingBuffer(buffer, size, overwriteOld,
maxExcessBytes) {
mutex = MutexFactory::instance()->createMutex();
}
SharedRingBuffer::~SharedRingBuffer() {
MutexFactory::instance()->deleteMutex(mutex);
}
void SharedRingBuffer::setToUseReceiveSizeFIFO(size_t fifoDepth) {
this->fifoDepth = fifoDepth;
this->fifoDepth = fifoDepth;
}
ReturnValue_t SharedRingBuffer::lockRingBufferMutex(
@ -38,18 +41,20 @@ MutexIF* SharedRingBuffer::getMutexHandle() const {
}
ReturnValue_t SharedRingBuffer::initialize() {
if(fifoDepth > 0) {
receiveSizesFIFO = new DynamicFIFO<size_t>(fifoDepth);
}
return SystemObject::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;
if(receiveSizesFIFO == nullptr) {
// Configuration error.
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "SharedRingBuffer::getReceiveSizesFIFO: Ring buffer"
<< " was not configured to have sizes FIFO, returning nullptr!"
<< std::endl;
#endif
}
return receiveSizesFIFO;
}

View File

@ -15,76 +15,79 @@
* and unlock operations.
*/
class SharedRingBuffer: public SystemObject,
public SimpleRingBuffer {
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);
/**
* 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);
/**
* 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);
/**
* @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);
virtual~ SharedRingBuffer();
/**
* 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);
/**
* @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);
/**
* 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;
/**
* 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();
/**
* 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();
/**
* The mutex handle can be accessed directly, for example to perform
* the lock with the #MutexGuard 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;
MutexIF* mutex = nullptr;
size_t fifoDepth = 0;
DynamicFIFO<size_t>* receiveSizesFIFO = nullptr;
size_t fifoDepth = 0;
DynamicFIFO<size_t>* receiveSizesFIFO = nullptr;
};

View File

@ -2,31 +2,31 @@
#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];
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):
bool overwriteOld, size_t maxExcessBytes):
RingBufferBase<>(0, size, overwriteOld), buffer(buffer) {
if(maxExcessBytes > size) {
this->maxExcessBytes = size;
}
else {
this->maxExcessBytes = maxExcessBytes;
}
if(maxExcessBytes > size) {
this->maxExcessBytes = size;
}
else {
this->maxExcessBytes = maxExcessBytes;
}
}
SimpleRingBuffer::~SimpleRingBuffer() {
delete[] buffer;
delete[] buffer;
}
ReturnValue_t SimpleRingBuffer::getFreeElement(uint8_t **writePointer,
@ -48,58 +48,58 @@ ReturnValue_t SimpleRingBuffer::getFreeElement(uint8_t **writePointer,
}
void SimpleRingBuffer::confirmBytesWritten(size_t amount) {
if(getExcessBytes() > 0) {
moveExcessBytesToStart();
}
incrementWrite(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;
}
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);
}
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;
if(incrementReadPtr) {
deleteData(amount, readRemaining);
}
return HasReturnvaluesIF::RETURN_OK;
}
size_t SimpleRingBuffer::getExcessBytes() const {
@ -114,18 +114,18 @@ void SimpleRingBuffer::moveExcessBytesToStart() {
}
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;
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

@ -5,7 +5,7 @@
#include <cstddef>
/**
* @brief Circular buffer implementation, useful for buffering
* @brief Circular buffer implementation, useful for buffering
* into data streams.
* @details
* Note that the deleteData() has to be called to increment the read pointer.
@ -25,104 +25,104 @@ public:
* 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
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);
* @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();
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);
/**
* 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);
/**
* 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);
/**
* 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();
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);
/**
* 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);
/**
* 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;
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

@ -5,71 +5,71 @@
#include <cstdint>
/**
* @brief Linked list data structure,
* each entry has a pointer to the next entry (singly)
* @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() {}
T *value;
class Iterator {
public:
LinkedElement<T> *value = nullptr;
Iterator() {}
Iterator(LinkedElement<T> *element) :
value(element) {
}
Iterator(LinkedElement<T> *element) :
value(element) {
}
Iterator& operator++() {
value = value->getNext();
return *this;
}
Iterator& operator++() {
value = value->getNext();
return *this;
}
Iterator operator++(int) {
Iterator tmp(*this);
operator++();
return tmp;
}
Iterator operator++(int) {
Iterator tmp(*this);
operator++();
return tmp;
}
bool operator==(Iterator other) {
return value == other.value;
}
bool operator==(Iterator other) {
return value == other.value;
}
bool operator!=(Iterator other) {
return !(*this == other);
}
T *operator->() {
return value->value;
}
};
bool operator!=(Iterator other) {
return !(*this == other);
}
T *operator->() {
return value->value;
}
};
LinkedElement(T* setElement, LinkedElement<T>* setNext = nullptr):
value(setElement), next(setNext) {}
LinkedElement(T* setElement, LinkedElement<T>* setNext = nullptr):
value(setElement), next(setNext) {}
virtual ~LinkedElement(){}
virtual ~LinkedElement(){}
virtual LinkedElement* getNext() const {
return next;
}
virtual LinkedElement* getNext() const {
return next;
}
virtual void setNext(LinkedElement* next) {
this->next = next;
}
virtual void setNext(LinkedElement* next) {
this->next = next;
}
virtual void setEnd() {
this->next = nullptr;
}
virtual void setEnd() {
this->next = nullptr;
}
LinkedElement* begin() {
return this;
}
LinkedElement* end() {
return nullptr;
}
LinkedElement* begin() {
return this;
}
LinkedElement* end() {
return nullptr;
}
private:
LinkedElement *next;
LinkedElement *next;
};
template<typename T>
@ -77,52 +77,52 @@ class SinglyLinkedList {
public:
using ElementIterator = typename LinkedElement<T>::Iterator;
SinglyLinkedList() {}
SinglyLinkedList() {}
SinglyLinkedList(ElementIterator start) :
start(start.value) {}
SinglyLinkedList(ElementIterator start) :
start(start.value) {}
SinglyLinkedList(LinkedElement<T>* startElement) :
start(startElement) {}
SinglyLinkedList(LinkedElement<T>* startElement) :
start(startElement) {}
ElementIterator begin() const {
return ElementIterator::Iterator(start);
}
ElementIterator begin() const {
return ElementIterator::Iterator(start);
}
/** Returns iterator to nulltr */
ElementIterator end() const {
return ElementIterator::Iterator();
}
/** 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);
}
/**
* 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;
}
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 setNext(LinkedElement<T>* currentElement,
LinkedElement<T>* nextElement) {
currentElement->setNext(nextElement);
}
void setLast(LinkedElement<T>* lastElement) {
lastElement->setEnd();
@ -148,7 +148,7 @@ public:
}
protected:
LinkedElement<T> *start = nullptr;
LinkedElement<T> *start = nullptr;
};
#endif /* SINGLYLINKEDLIST_H_ */

View File

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

View File

@ -1,137 +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(object_id_t setObjectId, object_id_t parentId,
size_t commandQueueDepth) :
SystemObject(setObjectId), parentId(parentId), mode(MODE_OFF),
submode(SUBMODE_NONE), modeHelper(this),
healthHelper(this, setObjectId) {
commandQueue = QueueFactory::instance()->createMessageQueue(
commandQueueDepth);
}
ControllerBase::~ControllerBase() {
QueueFactory::instance()->deleteMessageQueue(commandQueue);
QueueFactory::instance()->deleteMessageQueue(commandQueue);
}
ReturnValue_t ControllerBase::initialize() {
ReturnValue_t result = SystemObject::initialize();
if (result != RETURN_OK) {
return result;
}
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();
MessageQueueId_t parentQueue = 0;
if (parentId != objects::NO_OBJECT) {
SubsystemBase *parent = objectManager->get<SubsystemBase>(parentId);
if (parent == nullptr) {
return RETURN_FAILED;
}
parentQueue = parent->getCommandQueue();
parent->registerChild(getObjectId());
}
parent->registerChild(getObjectId());
}
result = healthHelper.initialize(parentQueue);
if (result != RETURN_OK) {
return result;
}
result = healthHelper.initialize(parentQueue);
if (result != RETURN_OK) {
return result;
}
result = modeHelper.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;
return RETURN_OK;
}
MessageQueueId_t ControllerBase::getCommandQueue() const {
return commandQueue->getId();
return commandQueue->getId();
}
void ControllerBase::handleQueue() {
CommandMessage message;
ReturnValue_t result;
for (result = commandQueue->receiveMessage(&message); result == RETURN_OK;
result = commandQueue->receiveMessage(&message)) {
CommandMessage command;
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
for (result = commandQueue->receiveMessage(&command);
result == RETURN_OK;
result = commandQueue->receiveMessage(&command)) {
result = modeHelper.handleModeCommand(&message);
if (result == RETURN_OK) {
continue;
}
result = modeHelper.handleModeCommand(&command);
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);
}
result = healthHelper.handleHealthCommand(&command);
if (result == RETURN_OK) {
continue;
}
result = handleCommandMessage(&command);
if (result == RETURN_OK) {
continue;
}
command.setToUnknownCommand();
commandQueue->reply(&command);
}
}
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);
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;
*mode = this->mode;
*submode = this->submode;
}
void ControllerBase::setToExternalControl() {
healthHelper.setHealth(EXTERNAL_CONTROL);
healthHelper.setHealth(EXTERNAL_CONTROL);
}
void ControllerBase::announceMode(bool recursive) {
triggerEvent(MODE_INFO, mode, submode);
triggerEvent(MODE_INFO, mode, submode);
}
ReturnValue_t ControllerBase::performOperation(uint8_t opCode) {
handleQueue();
hkSwitcher.performOperation();
performControlOperation();
return RETURN_OK;
handleQueue();
performControlOperation();
return RETURN_OK;
}
void ControllerBase::modeChanged(Mode_t mode, Submode_t submode) {
return;
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;
}
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();
return healthHelper.getHealth();
}
void ControllerBase::setTaskIF(PeriodicTaskIF* task_){
executingTask = task_;
executingTask = task_;
}
void ControllerBase::changeHK(Mode_t mode, Submode_t submode, bool enable) {
}
ReturnValue_t ControllerBase::initializeAfterTaskCreation() {
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -1,5 +1,5 @@
#ifndef CONTROLLERBASE_H_
#define CONTROLLERBASE_H_
#ifndef FSFW_CONTROLLER_CONTROLLERBASE_H_
#define FSFW_CONTROLLER_CONTROLLERBASE_H_
#include "../health/HasHealthIF.h"
#include "../health/HealthHelper.h"
@ -7,73 +7,88 @@
#include "../modes/ModeHelper.h"
#include "../objectmanager/SystemObject.h"
#include "../tasks/ExecutableObjectIF.h"
#include "../tasks/PeriodicTaskIF.h"
#include "../datapool/HkSwitchHelper.h"
/**
* @brief Generic base class for controller classes
* @details
* Implements common interfaces for controllers, which generally have
* a mode and a health state. This avoids boilerplate code.
*/
class ControllerBase: public HasModesIF,
public HasHealthIF,
public ExecutableObjectIF,
public SystemObject,
public HasReturnvaluesIF {
public HasHealthIF,
public ExecutableObjectIF,
public SystemObject,
public HasReturnvaluesIF {
public:
static const Mode_t MODE_NORMAL = 2;
static const Mode_t MODE_NORMAL = 2;
ControllerBase(object_id_t setObjectId, object_id_t parentId,
size_t commandQueueDepth = 3);
virtual ~ControllerBase();
ControllerBase(uint32_t setObjectId, uint32_t parentId,
size_t commandQueueDepth = 3);
virtual ~ControllerBase();
/** SystemObject override */
virtual ReturnValue_t initialize() override;
ReturnValue_t initialize();
virtual MessageQueueId_t getCommandQueue() const override;
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_);
/** HasHealthIF overrides */
virtual ReturnValue_t setHealth(HealthState health) override;
virtual HasHealthIF::HealthState getHealth() override;
/** ExecutableObjectIF overrides */
virtual ReturnValue_t performOperation(uint8_t opCode) override;
virtual void setTaskIF(PeriodicTaskIF* task) override;
virtual ReturnValue_t initializeAfterTaskCreation() override;
protected:
const uint32_t parentId;
Mode_t mode;
/**
* Implemented by child class. Handle command messages which are not
* mode or health messages.
* @param message
* @return
*/
virtual ReturnValue_t handleCommandMessage(CommandMessage *message) = 0;
Submode_t submode;
/**
* Periodic helper, implemented by child class.
*/
virtual void performControlOperation() = 0;
MessageQueueIF* commandQueue;
virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
uint32_t *msToReachTheMode) = 0;
ModeHelper modeHelper;
const object_id_t parentId;
HealthHelper healthHelper;
Mode_t mode;
HkSwitchHelper hkSwitcher;
Submode_t submode;
/**
* Pointer to the task which executes this component, is invalid before setTaskIF was called.
*/
PeriodicTaskIF* executingTask;
MessageQueueIF* commandQueue = nullptr;
void handleQueue();
ModeHelper modeHelper;
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);
HealthHelper healthHelper;
/**
* Pointer to the task which executes this component,
* is invalid before setTaskIF was called.
*/
PeriodicTaskIF* executingTask = nullptr;
/** Handle mode and health messages */
virtual void handleQueue();
/** Mode helpers */
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);
/** HK helpers */
virtual void changeHK(Mode_t mode, Submode_t submode, bool enable);
};
#endif /* CONTROLLERBASE_H_ */
#endif /* FSFW_CONTROLLER_CONTROLLERBASE_H_ */

View File

@ -0,0 +1,104 @@
#include "ExtendedControllerBase.h"
ExtendedControllerBase::ExtendedControllerBase(object_id_t objectId,
object_id_t parentId, size_t commandQueueDepth):
ControllerBase(objectId, parentId, commandQueueDepth),
poolManager(this, commandQueue),
actionHelper(this, commandQueue) {
}
ExtendedControllerBase::~ExtendedControllerBase() {
}
ReturnValue_t ExtendedControllerBase::executeAction(ActionId_t actionId,
MessageQueueId_t commandedBy, const uint8_t *data, size_t size) {
/* Needs to be overriden and implemented by child class. */
return HasReturnvaluesIF::RETURN_OK;
}
object_id_t ExtendedControllerBase::getObjectId() const {
return SystemObject::getObjectId();
}
uint32_t ExtendedControllerBase::getPeriodicOperationFrequency() const {
return this->executingTask->getPeriodMs();
}
ReturnValue_t ExtendedControllerBase::handleCommandMessage(
CommandMessage *message) {
ReturnValue_t result = actionHelper.handleActionMessage(message);
if(result == HasReturnvaluesIF::RETURN_OK) {
return result;
}
return poolManager.handleHousekeepingMessage(message);
}
void ExtendedControllerBase::handleQueue() {
CommandMessage command;
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
for (result = commandQueue->receiveMessage(&command);
result == RETURN_OK;
result = commandQueue->receiveMessage(&command)) {
result = actionHelper.handleActionMessage(&command);
if (result == RETURN_OK) {
continue;
}
result = modeHelper.handleModeCommand(&command);
if (result == RETURN_OK) {
continue;
}
result = healthHelper.handleHealthCommand(&command);
if (result == RETURN_OK) {
continue;
}
result = poolManager.handleHousekeepingMessage(&command);
if (result == RETURN_OK) {
continue;
}
result = handleCommandMessage(&command);
if (result == RETURN_OK) {
continue;
}
command.setToUnknownCommand();
commandQueue->reply(&command);
}
}
ReturnValue_t ExtendedControllerBase::initialize() {
ReturnValue_t result = ControllerBase::initialize();
if(result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
result = actionHelper.initialize(commandQueue);
if(result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
return poolManager.initialize(commandQueue);
}
ReturnValue_t ExtendedControllerBase::initializeAfterTaskCreation() {
return poolManager.initializeAfterTaskCreation();
}
ReturnValue_t ExtendedControllerBase::performOperation(uint8_t opCode) {
handleQueue();
performControlOperation();
/* We do this after performing control operation because variables will be set changed
in this function. */
poolManager.performHkOperation();
return RETURN_OK;
}
MessageQueueId_t ExtendedControllerBase::getCommandQueue() const {
return commandQueue->getId();
}
LocalDataPoolManager* ExtendedControllerBase::getHkManagerHandle() {
return &poolManager;
}

View File

@ -0,0 +1,73 @@
#ifndef FSFW_CONTROLLER_EXTENDEDCONTROLLERBASE_H_
#define FSFW_CONTROLLER_EXTENDEDCONTROLLERBASE_H_
#include "ControllerBase.h"
#include "../action/HasActionsIF.h"
#include "../datapoollocal/HasLocalDataPoolIF.h"
#include "../action/ActionHelper.h"
#include "../datapoollocal/LocalDataPoolManager.h"
/**
* @brief Extendes the basic ControllerBase with the common components
* HasActionsIF for commandability and HasLocalDataPoolIF to keep
* a pool of local data pool variables.
* @details
* Default implementations required for the interfaces will be empty and have
* to be implemented by child class.
*/
class ExtendedControllerBase: public ControllerBase,
public HasActionsIF,
public HasLocalDataPoolIF {
public:
ExtendedControllerBase(object_id_t objectId, object_id_t parentId,
size_t commandQueueDepth = 3);
virtual ~ExtendedControllerBase();
/* SystemObjectIF overrides */
virtual ReturnValue_t initialize() override;
virtual MessageQueueId_t getCommandQueue() const override;
/* ExecutableObjectIF overrides */
virtual ReturnValue_t performOperation(uint8_t opCode) override;
virtual ReturnValue_t initializeAfterTaskCreation() override;
protected:
LocalDataPoolManager poolManager;
ActionHelper actionHelper;
/**
* Implemented by child class. Handle all command messages which are
* not health, mode, action or housekeeping messages.
* @param message
* @return
*/
virtual ReturnValue_t handleCommandMessage(CommandMessage *message) = 0;
/**
* Periodic helper from ControllerBase, implemented by child class.
*/
virtual void performControlOperation() = 0;
/* Handle the four messages mentioned above */
void handleQueue() override;
/* HasActionsIF overrides */
virtual ReturnValue_t executeAction(ActionId_t actionId,
MessageQueueId_t commandedBy, const uint8_t* data,
size_t size) override;
/* HasLocalDatapoolIF overrides */
virtual LocalDataPoolManager* getHkManagerHandle() override;
virtual object_id_t getObjectId() const override;
virtual uint32_t getPeriodicOperationFrequency() const override;
virtual ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
LocalDataPoolManager& poolManager) override = 0;
virtual LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override = 0;
};
#endif /* FSFW_CONTROLLER_EXTENDEDCONTROLLERBASE_H_ */

View File

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

View File

@ -1,7 +1,9 @@
#ifndef SGP4PROPAGATOR_H_
#define SGP4PROPAGATOR_H_
#ifndef WIN32
#include <sys/time.h>
#endif
#include "../contrib/sgp4/sgp4unit.h"
#include "../returnvalues/HasReturnvaluesIF.h"

View File

@ -0,0 +1,12 @@
target_sources(${LIB_FSFW_NAME}
PRIVATE
Clcw.cpp
DataLinkLayer.cpp
Farm1StateLockout.cpp
Farm1StateOpen.cpp
Farm1StateWait.cpp
MapPacketExtraction.cpp
TcTransferFrame.cpp
TcTransferFrameLocal.cpp
VirtualChannelReception.cpp
)

View File

@ -55,7 +55,9 @@ 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

@ -98,8 +98,10 @@ 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 {
@ -124,7 +126,9 @@ 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

@ -19,12 +19,12 @@ class VirtualChannelReception;
class DataLinkLayer : public CCSDSReturnValuesIF {
public:
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::SYSTEM_1;
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
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

@ -1,10 +1,3 @@
/**
* @file MapPacketExtraction.cpp
* @brief This file defines the MapPacketExtraction class.
* @date 26.03.2013
* @author baetz
*/
#include "MapPacketExtraction.h"
#include "../ipc/QueueFactory.h"
#include "../serviceinterface/ServiceInterfaceStream.h"
@ -12,14 +5,14 @@
#include "../tmtcpacket/SpacePacketBase.h"
#include "../tmtcservices/AcceptsTelecommandsIF.h"
#include "../tmtcservices/TmTcMessage.h"
#include <string.h>
#include <cstring>
MapPacketExtraction::MapPacketExtraction(uint8_t setMapId,
object_id_t setPacketDestination) :
lastSegmentationFlag(NO_SEGMENTATION), mapId(setMapId), packetLength(0), bufferPosition(
packetBuffer), packetDestination(setPacketDestination), packetStore(
NULL), tcQueueId(MessageQueueIF::NO_QUEUE) {
memset(packetBuffer, 0, sizeof(packetBuffer));
lastSegmentationFlag(NO_SEGMENTATION), mapId(setMapId),
bufferPosition(packetBuffer), packetDestination(setPacketDestination),
tcQueueId(MessageQueueIF::NO_QUEUE) {
std::memset(packetBuffer, 0, sizeof(packetBuffer));
}
ReturnValue_t MapPacketExtraction::extractPackets(TcTransferFrame* frame) {
@ -36,9 +29,11 @@ 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;
}
@ -58,24 +53,30 @@ 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;
@ -142,10 +143,14 @@ 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,12 +1,5 @@
/**
* @file MapPacketExtraction.h
* @brief This file defines the MapPacketExtraction class.
* @date 26.03.2013
* @author baetz
*/
#ifndef MAPPACKETEXTRACTION_H_
#define MAPPACKETEXTRACTION_H_
#ifndef FSFW_DATALINKLAYER_MAPPACKETEXTRACTION_H_
#define FSFW_DATALINKLAYER_MAPPACKETEXTRACTION_H_
#include "MapPacketExtractionIF.h"
#include "../objectmanager/ObjectManagerIF.h"
@ -20,17 +13,19 @@ 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; //!< Complete length of the current Space Packet.
uint32_t packetLength = 0; //!< 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;
StorageManagerIF* packetStore; //!< Pointer to the store where full TC packets are stored.
//!< Pointer to the store where full TC packets are stored.
StorageManagerIF* packetStore = nullptr;
MessageQueueId_t tcQueueId; //!< QueueId to send found packets to the distributor.
/**
* Debug method to print the packet Buffer's content.
@ -75,4 +70,4 @@ public:
uint8_t getMapId() const;
};
#endif /* MAPPACKETEXTRACTION_H_ */
#endif /* FSFW_DATALINKLAYER_MAPPACKETEXTRACTION_H_ */

View File

@ -87,16 +87,25 @@ 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;
// 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;
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
}

View File

@ -37,7 +37,9 @@ 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::debug << "TcTransferFrameLocal: dataSize too large: " << dataSize << std::endl;
#endif
}
} else {
//No data in frame

View File

@ -102,8 +102,10 @@ 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();

6
datapool/CMakeLists.txt Normal file
View File

@ -0,0 +1,6 @@
target_sources(${LIB_FSFW_NAME}
PRIVATE
HkSwitchHelper.cpp
PoolDataSetBase.cpp
PoolEntry.cpp
)

View File

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

View File

@ -1,15 +0,0 @@
#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_ */

View File

@ -1,131 +0,0 @@
#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;
}

View File

@ -1,135 +0,0 @@
/**
* \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_ */

View File

@ -1,300 +0,0 @@
#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);
}

View File

@ -1,58 +0,0 @@
#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

@ -1,181 +0,0 @@
#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

@ -1,38 +0,0 @@
#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_ */

View File

@ -1,150 +0,0 @@
#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;
}

View File

@ -1,159 +0,0 @@
/*
* \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_ */

View File

@ -1,39 +1,45 @@
/**
* \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_
#ifndef FSFW_DATAPOOL_DATASETIF_H_
#define FSFW_DATAPOOL_DATASETIF_H_
#include "../returnvalues/HasReturnvaluesIF.h"
#include "../timemanager/Clock.h"
class PoolVariableIF;
/**
* \brief This class defines a small interface to register on a DataSet.
* @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
* @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.
* @author Bastian Baetz
* @ingroup data_pool
*/
class DataSetIF {
public:
static constexpr uint8_t INTERFACE_ID = CLASS_ID::DATA_SET_CLASS;
static constexpr ReturnValue_t INVALID_PARAMETER_DEFINITION = MAKE_RETURN_CODE(1);
static constexpr ReturnValue_t SET_WAS_ALREADY_READ = MAKE_RETURN_CODE(2);
static constexpr ReturnValue_t COMMITING_WITHOUT_READING = MAKE_RETURN_CODE(3);
static constexpr ReturnValue_t DATA_SET_UNINITIALISED = MAKE_RETURN_CODE(4);
static constexpr ReturnValue_t DATA_SET_FULL = MAKE_RETURN_CODE(5);
static constexpr ReturnValue_t POOL_VAR_NULL = MAKE_RETURN_CODE(6);
/**
* \brief This is an empty virtual destructor, as it is proposed for C++ interfaces.
* @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.
* @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;
virtual ReturnValue_t registerVariable(PoolVariableIF* variable) = 0;
virtual uint16_t getFillCount() const = 0;
};
#endif /* DATASETIF_H_ */
#endif /* FSFW_DATAPOOL_DATASETIF_H_ */

View File

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

View File

@ -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();

View File

@ -1,147 +0,0 @@
#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_ */

View File

@ -1,27 +0,0 @@
#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

@ -0,0 +1,233 @@
#include "PoolDataSetBase.h"
#include "ReadCommitIFAttorney.h"
#include "../serviceinterface/ServiceInterface.h"
#include <cstring>
PoolDataSetBase::PoolDataSetBase(PoolVariableIF** registeredVariablesArray,
const size_t maxFillCount):
registeredVariables(registeredVariablesArray),
maxFillCount(maxFillCount) {}
PoolDataSetBase::~PoolDataSetBase() {}
ReturnValue_t PoolDataSetBase::registerVariable(PoolVariableIF *variable) {
if(registeredVariables == nullptr) {
/* Underlying container invalid */
return HasReturnvaluesIF::RETURN_FAILED;
}
if (state != States::STATE_SET_UNINITIALISED) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "DataSet::registerVariable: Call made in wrong position." << std::endl;
#else
sif::printError("DataSet::registerVariable: Call made in wrong position.");
#endif
return DataSetIF::DATA_SET_UNINITIALISED;
}
if (variable == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "DataSet::registerVariable: Pool variable is nullptr." << std::endl;
#else
sif::printError("DataSet::registerVariable: Pool variable is nullptr.\n");
#endif
return DataSetIF::POOL_VAR_NULL;
}
if (fillCount >= maxFillCount) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "DataSet::registerVariable: DataSet is full." << std::endl;
#else
sif::printError("DataSet::registerVariable: DataSet is full.\n");
#endif
return DataSetIF::DATA_SET_FULL;
}
registeredVariables[fillCount] = variable;
fillCount++;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t PoolDataSetBase::read(MutexIF::TimeoutType timeoutType,
uint32_t lockTimeout) {
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
ReturnValue_t error = result;
if (state == States::STATE_SET_UNINITIALISED) {
lockDataPool(timeoutType, lockTimeout);
for (uint16_t count = 0; count < fillCount; count++) {
result = readVariable(count);
if(result != RETURN_OK) {
error = result;
}
}
state = States::STATE_SET_WAS_READ;
unlockDataPool();
}
else {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "PoolDataSetBase::read: Call made in wrong position. Don't forget to "
"commit member datasets!" << std::endl;
#else
sif::printWarning("PoolDataSetBase::read: Call made in wrong position. Don't forget to "
"commit member datasets!\n");
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
result = SET_WAS_ALREADY_READ;
}
if(error != HasReturnvaluesIF::RETURN_OK) {
result = error;
}
return result;
}
uint16_t PoolDataSetBase::getFillCount() const {
return fillCount;
}
ReturnValue_t PoolDataSetBase::readVariable(uint16_t count) {
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
if(registeredVariables[count] == nullptr) {
/* Configuration error. */
return HasReturnvaluesIF::RETURN_FAILED;
}
/* These checks are often performed by the respective variable implementation too, but I guess
a double check does not hurt. */
if (registeredVariables[count]->getReadWriteMode() != PoolVariableIF::VAR_WRITE and
registeredVariables[count]->getDataPoolId() != PoolVariableIF::NO_PARAMETER) {
if(protectEveryReadCommitCall) {
result = registeredVariables[count]->read(timeoutTypeForSingleVars,
mutexTimeoutForSingleVars);
}
else {
/* The readWithoutLock function is protected, so we use the attorney here */
result = ReadCommitIFAttorney::readWithoutLock(registeredVariables[count]);
}
if(result != HasReturnvaluesIF::RETURN_OK) {
result = INVALID_PARAMETER_DEFINITION;
}
}
return result;
}
ReturnValue_t PoolDataSetBase::commit(MutexIF::TimeoutType timeoutType,
uint32_t lockTimeout) {
if (state == States::STATE_SET_WAS_READ) {
handleAlreadyReadDatasetCommit(timeoutType, lockTimeout);
return HasReturnvaluesIF::RETURN_OK;
}
else {
return handleUnreadDatasetCommit(timeoutType, lockTimeout);
}
}
void PoolDataSetBase::handleAlreadyReadDatasetCommit(
MutexIF::TimeoutType timeoutType, uint32_t lockTimeout) {
lockDataPool(timeoutType, lockTimeout);
for (uint16_t count = 0; count < fillCount; count++) {
if ((registeredVariables[count]->getReadWriteMode() != PoolVariableIF::VAR_READ) and
(registeredVariables[count]->getDataPoolId() != PoolVariableIF::NO_PARAMETER)) {
if(protectEveryReadCommitCall) {
registeredVariables[count]->commit(timeoutTypeForSingleVars,
mutexTimeoutForSingleVars);
}
else {
/* The commitWithoutLock function is protected, so we use the attorney here */
ReadCommitIFAttorney::commitWithoutLock(registeredVariables[count]);
}
}
}
state = States::STATE_SET_UNINITIALISED;
unlockDataPool();
}
ReturnValue_t PoolDataSetBase::handleUnreadDatasetCommit(
MutexIF::TimeoutType timeoutType, uint32_t lockTimeout) {
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
lockDataPool(timeoutType, lockTimeout);
for (uint16_t count = 0; count < fillCount; count++) {
if ((registeredVariables[count]->getReadWriteMode() == PoolVariableIF::VAR_WRITE) and
(registeredVariables[count]->getDataPoolId() != PoolVariableIF::NO_PARAMETER)) {
if(protectEveryReadCommitCall) {
result = registeredVariables[count]->commit(timeoutTypeForSingleVars,
mutexTimeoutForSingleVars);
}
else {
/* The commitWithoutLock function is protected, so we use the attorney here */
ReadCommitIFAttorney::commitWithoutLock(registeredVariables[count]);
}
} else if (registeredVariables[count]->getDataPoolId()
!= PoolVariableIF::NO_PARAMETER) {
if (result != COMMITING_WITHOUT_READING) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "DataSet::commit(): commit-without-read call made "
"with non write-only variable." << std::endl;
#endif
result = COMMITING_WITHOUT_READING;
}
}
}
state = States::STATE_SET_UNINITIALISED;
unlockDataPool();
return result;
}
ReturnValue_t PoolDataSetBase::lockDataPool(MutexIF::TimeoutType timeoutType,
uint32_t lockTimeout) {
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t PoolDataSetBase::unlockDataPool() {
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t PoolDataSetBase::serialize(uint8_t** buffer, size_t* size,
const size_t maxSize, SerializeIF::Endianness streamEndianness) const {
ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED;
for (uint16_t count = 0; count < fillCount; count++) {
result = registeredVariables[count]->serialize(buffer, size, maxSize, streamEndianness);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
}
return result;
}
ReturnValue_t PoolDataSetBase::deSerialize(const uint8_t** buffer, size_t* size,
SerializeIF::Endianness streamEndianness) {
ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED;
for (uint16_t count = 0; count < fillCount; count++) {
result = registeredVariables[count]->deSerialize(buffer, size,
streamEndianness);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
}
return result;
}
size_t PoolDataSetBase::getSerializedSize() const {
uint32_t size = 0;
for (uint16_t count = 0; count < fillCount; count++) {
size += registeredVariables[count]->getSerializedSize();
}
return size;
}
void PoolDataSetBase::setContainer(PoolVariableIF **variablesContainer) {
this->registeredVariables = variablesContainer;
}
PoolVariableIF** PoolDataSetBase::getContainer() const {
return registeredVariables;
}
void PoolDataSetBase::setReadCommitProtectionBehaviour(
bool protectEveryReadCommit, MutexIF::TimeoutType timeoutType,
uint32_t mutexTimeout) {
this->protectEveryReadCommitCall = protectEveryReadCommit;
this->timeoutTypeForSingleVars = timeoutType;
this->mutexTimeoutForSingleVars = mutexTimeout;
}

180
datapool/PoolDataSetBase.h Normal file
View File

@ -0,0 +1,180 @@
#ifndef FSFW_DATAPOOL_POOLDATASETBASE_H_
#define FSFW_DATAPOOL_POOLDATASETBASE_H_
#include "PoolDataSetIF.h"
#include "PoolVariableIF.h"
#include "../serialize/SerializeIF.h"
#include "../ipc/MutexIF.h"
/**
* @brief The DataSetBase 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.
*
* The base class lockDataPool und unlockDataPool implementation are empty
* and should be implemented to protect the underlying pool type.
* @author Bastian Baetz
* @ingroup data_pool
*/
class PoolDataSetBase:
public PoolDataSetIF,
public SerializeIF,
public HasReturnvaluesIF {
public:
/**
* @brief Creates an empty dataset. Use registerVariable or
* supply a pointer to this dataset to PoolVariable
* initializations to register pool variables.
*/
PoolDataSetBase(PoolVariableIF** registeredVariablesArray, const size_t maxFillCount);
/* Forbidden for now */
PoolDataSetBase(const PoolDataSetBase& otherSet) = delete;
const PoolDataSetBase& operator=(const PoolDataSetBase& otherSet) = delete;
virtual~ PoolDataSetBase();
/**
* @brief The read call initializes reading out all registered variables.
* It is mandatory to call commit after every read call!
* @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. It is mandatory to call commit after a read call,
* even if the read operation is not successful!
* @return
* - @c RETURN_OK if all variables were read successfully.
* - @c INVALID_PARAMETER_DEFINITION if a pool entry does not exist or there
* is a type conflict.
* - @c SET_WAS_ALREADY_READ if read() is called twice without calling
* commit() in between
*/
virtual ReturnValue_t read(MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING,
uint32_t lockTimeout = 20) override;
/**
* @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. Every read call must be followed by a commit 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
*/
virtual ReturnValue_t commit(MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING,
uint32_t lockTimeout = 20) override;
/**
* Register the passed pool variable instance into the data set.
* @param variable
* @return
*/
virtual ReturnValue_t registerVariable( PoolVariableIF* variable) override;
/**
* Provides the means to lock the underlying data structure to ensure
* thread-safety. Default implementation is empty
* @return Always returns -@c RETURN_OK
*/
virtual ReturnValue_t lockDataPool(
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING,
uint32_t timeoutMs = 20) override;
/**
* Provides the means to unlock the underlying data structure to ensure
* thread-safety. Default implementation is empty
* @return Always returns -@c RETURN_OK
*/
virtual ReturnValue_t unlockDataPool() override;
virtual uint16_t getFillCount() const;
/* SerializeIF implementations */
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size,
const size_t maxSize,
SerializeIF::Endianness streamEndianness) const override;
virtual size_t getSerializedSize() const override;
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
SerializeIF::Endianness streamEndianness) override;
/**
* Can be used to individually protect every read and commit call.
* @param protectEveryReadCommit
* @param mutexTimeout
*/
void setReadCommitProtectionBehaviour(bool protectEveryReadCommit,
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING,
uint32_t mutexTimeout = 20);
protected:
/**
* @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 fillCount = 0;
/**
* States of the seet.
*/
enum class States {
STATE_SET_UNINITIALISED, //!< DATA_SET_UNINITIALISED
STATE_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 = States::STATE_SET_UNINITIALISED;
/**
* @brief This array represents all pool variables registered in this set.
* Child classes can use a static or dynamic container to create
* an array of registered variables and assign the first entry here.
*/
PoolVariableIF** registeredVariables = nullptr;
const size_t maxFillCount = 0;
void setContainer(PoolVariableIF** variablesContainer);
PoolVariableIF** getContainer() const;
private:
bool protectEveryReadCommitCall = false;
MutexIF::TimeoutType timeoutTypeForSingleVars = MutexIF::TimeoutType::WAITING;
uint32_t mutexTimeoutForSingleVars = 20;
ReturnValue_t readVariable(uint16_t count);
void handleAlreadyReadDatasetCommit(
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING,
uint32_t timeoutMs = 20);
ReturnValue_t handleUnreadDatasetCommit(
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING,
uint32_t timeoutMs = 20);
};
#endif /* FSFW_DATAPOOL_POOLDATASETBASE_H_ */

36
datapool/PoolDataSetIF.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef FSFW_DATAPOOL_POOLDATASETIF_H_
#define FSFW_DATAPOOL_POOLDATASETIF_H_
#include "ReadCommitIF.h"
#include "DataSetIF.h"
/**
* @brief Extendes the DataSetIF by adding abstract functions to lock
* and unlock a data pool and read/commit semantics.
*/
class PoolDataSetIF:
virtual public DataSetIF,
virtual public ReadCommitIF {
public:
virtual~ PoolDataSetIF() {};
/**
* @brief Most underlying data structures will have a pool like structure
* and will require a lock and unlock mechanism to ensure
* thread-safety
* @return Lock operation result
*/
virtual ReturnValue_t lockDataPool(
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING,
uint32_t timeoutMs = 20) = 0;
/**
* @brief Unlock call corresponding to the lock call.
* @return Unlock operation result
*/
virtual ReturnValue_t unlockDataPool() = 0;
virtual bool isValid() const = 0;
};
#endif /* FSFW_DATAPOOL_POOLDATASETIF_H_ */

View File

@ -1,28 +1,24 @@
#include "PoolEntry.h"
#include "../serviceinterface/ServiceInterfaceStream.h"
#include "../serviceinterface/ServiceInterface.h"
#include "../globalfunctions/arrayprinter.h"
#include <cstring>
#include <algorithm>
template <typename T>
PoolEntry<T>::PoolEntry(std::initializer_list<T> initValue, uint8_t setLength,
bool setValid ) : length(setLength), valid(setValid) {
PoolEntry<T>::PoolEntry(std::initializer_list<T> initValue, bool setValid ):
length(static_cast<uint8_t>(initValue.size())), valid(setValid) {
this->address = new T[this->length];
if(initValue.size() == 0) {
std::memset(this->address, 0, this->getByteSize());
}
else 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) {
@ -66,10 +62,26 @@ bool PoolEntry<T>::getValid() {
template <typename T>
void PoolEntry<T>::print() {
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;
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;
}
template<typename T>
@ -80,8 +92,10 @@ 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 FRAMEWORK_DATAPOOL_POOLENTRY_H_
#define FRAMEWORK_DATAPOOL_POOLENTRY_H_
#ifndef FSFW_DATAPOOL_POOLENTRY_H_
#define FSFW_DATAPOOL_POOLENTRY_H_
#include "PoolEntryIF.h"
@ -35,24 +35,22 @@ public:
"uint8_t");
/**
* @brief In the classe's constructor, space is allocated on the heap and
* potential init values are copied to that space.
* potential initialization values are copied to that space.
* @details
* Not passing any arguments will initialize an non-array pool entry
* (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.
* 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.
* @param initValue
* 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.
* 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.
* @param setValid
* Sets the initialization flag. It is invalid by default.
*/
PoolEntry(std::initializer_list<T> initValue = {}, uint8_t setLength = 1,
bool setValid = false);
PoolEntry(std::initializer_list<T> initValue = {0}, bool setValid = false);
/**
* @brief In the classe's constructor, space is allocated on the heap and
* potential init values are copied to that space.
@ -66,9 +64,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;
/**
@ -82,21 +80,16 @@ public:
~PoolEntry();
/**
* @brief This is the address pointing to the allocated memory.
* Return typed pointer to start of data.
* @return
*/
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;
T* getDataPtr();
/**
* @brief getSize returns the array size of the entry.
* @details A single parameter has size 1.
* @details
* For non-array pool entries return type size, for vector entries
* return type size times the number of entries.
*/
uint8_t getSize();
/**
@ -123,8 +116,22 @@ 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;
};
#endif /* POOLENTRY_H_ */
#endif /* FSFW_DATAPOOL_POOLENTRY_H_ */

View File

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

View File

@ -1,187 +0,0 @@
#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;
}
}

View File

@ -1,152 +0,0 @@
#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_ */

62
datapool/PoolReadGuard.h Normal file
View File

@ -0,0 +1,62 @@
#ifndef FSFW_DATAPOOL_POOLREADHELPER_H_
#define FSFW_DATAPOOL_POOLREADHELPER_H_
#include "ReadCommitIF.h"
#include "../serviceinterface/ServiceInterface.h"
#include <FSFWConfig.h>
/**
* @brief Helper class to read data sets or pool variables
*/
class PoolReadGuard {
public:
PoolReadGuard(ReadCommitIF* readObject,
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING,
uint32_t mutexTimeout = 20):
readObject(readObject), mutexTimeout(mutexTimeout) {
if(readObject != nullptr) {
readResult = readObject->read(timeoutType, mutexTimeout);
if(readResult != HasReturnvaluesIF::RETURN_OK) {
#if FSFW_VERBOSE_LEVEL == 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "PoolReadHelper: Read failed!" << std::endl;
#else
sif::printError("PoolReadHelper: Read failed!\n");
#endif /* FSFW_PRINT_VERBOSITY_LEVEL == 1 */
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
}
}
}
ReturnValue_t getReadResult() const {
return readResult;
}
/**
* @brief Can be used to suppress commit on destruction.
*/
void setNoCommitMode(bool commit) {
this->noCommit = commit;
}
/**
* @brief Default destructor which will take care of commiting changed values.
*/
~PoolReadGuard() {
if(readObject != nullptr and not noCommit) {
readObject->commit(timeoutType, mutexTimeout);
}
}
private:
ReadCommitIF* readObject = nullptr;
ReturnValue_t readResult = HasReturnvaluesIF::RETURN_OK;
bool noCommit = false;
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING;
uint32_t mutexTimeout = 20;
};
#endif /* FSFW_DATAPOOL_POOLREADHELPER_H_ */

View File

@ -1,14 +1,15 @@
#ifndef POOLVARLIST_H_
#define POOLVARLIST_H_
#ifndef FSFW_DATAPOOL_POOLVARLIST_H_
#define FSFW_DATAPOOL_POOLVARLIST_H_
#include "PoolVariable.h"
#include "PoolVariableIF.h"
#include "../datapool/PoolVariableIF.h"
#include "../datapoolglob/GlobalPoolVariable.h"
template <class T, uint8_t n_var>
class PoolVarList {
private:
PoolVariable<T> variables[n_var];
GlobPoolVar<T> variables[n_var];
public:
PoolVarList( const uint32_t set_id[n_var], DataSetIF* dataSet, PoolVariableIF::ReadWriteMode_t setReadWriteMode ) {
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;
@ -20,9 +21,9 @@ public:
}
}
PoolVariable<T> &operator [](int i) { return variables[i]; }
GlobPoolVar<T> &operator [](int i) { return variables[i]; }
};
#endif /* POOLVARLIST_H_ */
#endif /* FSFW_DATAPOOL_POOLVARLIST_H_ */

View File

@ -1,295 +0,0 @@
/*
* \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_ */

View File

@ -1,71 +1,68 @@
/*
* \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_
#ifndef FSFW_DATAPOOL_POOLVARIABLEIF_H_
#define FSFW_DATAPOOL_POOLVARIABLEIF_H_
#include "ReadCommitIF.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
* @brief This interface is used to control 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,
* like the DataSet classes. This interface provides unified access to
* local pool variables for such manager classes.
* @author Bastian Baetz
* @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;
class PoolVariableIF :
public SerializeIF,
public ReadCommitIF {
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
};
static constexpr uint8_t INTERFACE_ID = CLASS_ID::POOL_VARIABLE_IF;
static constexpr ReturnValue_t INVALID_READ_WRITE_MODE = MAKE_RETURN_CODE(0xA0);
static constexpr ReturnValue_t INVALID_POOL_ENTRY = MAKE_RETURN_CODE(0xA1);
/**
* \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;
static constexpr bool VALID = 1;
static constexpr bool INVALID = 0;
static constexpr uint32_t NO_PARAMETER = 0xffffffff;
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;
virtual void setReadWriteMode(ReadWriteMode_t newMode) = 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(bool validity) = 0;
};
#endif /* POOLVARIABLEIF_H_ */
using pool_rwm_t = PoolVariableIF::ReadWriteMode_t;
#endif /* FSFW_DATAPOOL_POOLVARIABLEIF_H_ */

View File

@ -1,233 +0,0 @@
/*
* \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_ */

34
datapool/ReadCommitIF.h Normal file
View File

@ -0,0 +1,34 @@
#ifndef FSFW_DATAPOOL_READCOMMITIF_H_
#define FSFW_DATAPOOL_READCOMMITIF_H_
#include "../returnvalues/HasReturnvaluesIF.h"
#include "../ipc/MutexIF.h"
/**
* @brief Common interface for all software objects which employ read-commit
* semantics.
*/
class ReadCommitIF {
friend class ReadCommitIFAttorney;
public:
virtual ~ReadCommitIF() {}
virtual ReturnValue_t read(MutexIF::TimeoutType timeoutType,
uint32_t timeoutMs) = 0;
virtual ReturnValue_t commit(MutexIF::TimeoutType timeoutType,
uint32_t timeoutMs) = 0;
protected:
/* Optional and protected because this is interesting for classes grouping members with commit
and read semantics where the lock is only necessary once. */
virtual ReturnValue_t readWithoutLock() {
return read(MutexIF::TimeoutType::WAITING, 20);
}
virtual ReturnValue_t commitWithoutLock() {
return commit(MutexIF::TimeoutType::WAITING, 20);
}
};
#endif /* FSFW_DATAPOOL_READCOMMITIF_H_ */

View File

@ -0,0 +1,32 @@
#ifndef FSFW_DATAPOOL_READCOMMITIFATTORNEY_H_
#define FSFW_DATAPOOL_READCOMMITIFATTORNEY_H_
#include <fsfw/datapool/ReadCommitIF.h>
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
/**
* @brief This class determines which members are allowed to access protected members
* of the ReadCommitIF.
*/
class ReadCommitIFAttorney {
private:
static ReturnValue_t readWithoutLock(ReadCommitIF* readCommitIF) {
if(readCommitIF == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
return readCommitIF->readWithoutLock();
}
static ReturnValue_t commitWithoutLock(ReadCommitIF* readCommitIF) {
if(readCommitIF == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
return readCommitIF->commitWithoutLock();
}
friend class PoolDataSetBase;
};
#endif /* FSFW_DATAPOOL_READCOMMITIFATTORNEY_H_ */

View File

@ -0,0 +1,16 @@
#ifndef FRAMEWORK_DATAPOOL_SHAREDDATASETIF_H_
#define FRAMEWORK_DATAPOOL_SHAREDDATASETIF_H_
#include "PoolDataSetIF.h"
class SharedDataSetIF {
public:
virtual ~SharedDataSetIF() {};
private:
virtual ReturnValue_t lockDataset(MutexIF::TimeoutType timeoutType,
dur_millis_t mutexTimeout) = 0;
virtual ReturnValue_t unlockDataset() = 0;
};
#endif /* FRAMEWORK_DATAPOOL_SHAREDDATASETIF_H_ */

View File

@ -0,0 +1,27 @@
#ifndef FSFW_DATAPOOLLOCAL_ACCESSLOCALPOOLF_H_
#define FSFW_DATAPOOLLOCAL_ACCESSLOCALPOOLF_H_
class LocalDataPoolManager;
class MutexIF;
/**
* @brief Accessor class which can be used by classes which like to use the pool manager.
*/
class AccessPoolManagerIF {
public:
virtual ~AccessPoolManagerIF() {};
virtual MutexIF* getLocalPoolMutex() = 0;
/**
* Can be used to get a handle to the local data pool manager.
* This function is protected because it should only be used by the
* class imlementing the interface.
*/
virtual LocalDataPoolManager* getPoolManagerHandle() = 0;
protected:
};
#endif /* FSFW_DATAPOOLLOCAL_ACCESSLOCALPOOLF_H_ */

View File

@ -0,0 +1,10 @@
target_sources(${LIB_FSFW_NAME}
PRIVATE
LocalDataPoolManager.cpp
LocalDataSet.cpp
LocalPoolDataSetBase.cpp
LocalPoolObjectBase.cpp
SharedLocalDataSet.cpp
)
add_subdirectory(internal)

View File

@ -0,0 +1,186 @@
#ifndef FSFW_DATAPOOLLOCAL_HASLOCALDATAPOOLIF_H_
#define FSFW_DATAPOOLLOCAL_HASLOCALDATAPOOLIF_H_
#include "localPoolDefinitions.h"
#include "LocalDataPoolManager.h"
#include "../datapool/PoolEntryIF.h"
#include "../serviceinterface/ServiceInterface.h"
#include "../ipc/MessageQueueSenderIF.h"
#include "../housekeeping/HousekeepingMessage.h"
#include <map>
class AccessPoolManagerIF;
class ProvidesDataPoolSubscriptionIF;
class LocalPoolDataSetBase;
class LocalPoolObjectBase;
/**
* @brief This interface is implemented by classes which posses a local data pool (not the
* managing class). It defines the relationship between the local data pool owner
* and the LocalDataPoolManager.
* @details
* Any class implementing this interface shall also have a LocalDataPoolManager member class which
* contains the actual pool data structure and exposes the public interface for it.
*
* The local data pool can be accessed using helper classes by using the
* LocalPoolVariable, LocalPoolVector or LocalDataSet classes. Every local pool variable can
* be uniquely identified by a global pool ID (gp_id_t) and every dataset tied
* to a pool manager can be uniqely identified by a global structure ID (sid_t).
*
* All software objects which want to use the local pool of another object shall also use this
* interface, for example to get a handle to the subscription interface. The interface
* can be retrieved using the object manager, provided the target object is a SystemObject.
* For example, the following line of code can be used to retrieve the interface
*
* HasLocalDataPoolIF* poolIF = objectManager->get<HasLocalDataPoolIF>(objects::SOME_OBJECT);
* if(poolIF != nullptr) {
* doSomething()
* }
*/
class HasLocalDataPoolIF {
friend class HasLocalDpIFManagerAttorney;
friend class HasLocalDpIFUserAttorney;
public:
virtual~ HasLocalDataPoolIF() {};
static constexpr uint32_t INVALID_LPID = localpool::INVALID_LPID;
virtual object_id_t getObjectId() const = 0;
/** Command queue for housekeeping messages. */
virtual MessageQueueId_t getCommandQueue() const = 0;
/**
* Is used by pool owner to initialize the pool map once
* The manager instance shall also be passed to this function.
* It can be used to subscribe for periodic packets for for updates.
*/
virtual ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
LocalDataPoolManager& poolManager) = 0;
/**
* Returns the minimum sampling frequency in milliseconds, which will
* usually be the period the pool owner performs its periodic operation.
* @return
*/
virtual dur_millis_t getPeriodicOperationFrequency() const = 0;
/**
* @brief This function will be called by the manager if an update
* notification is received.
* @details HasLocalDataPoolIF
* Can be overriden by the child class to handle changed datasets.
* @param sid SID of the updated set
* @param storeId If a snapshot was requested, data will be located inside
* the IPC store with this store ID.
* @param clearMessage If this is set to true, the pool manager will take care of
* clearing the store automatically
*/
virtual void handleChangedDataset(sid_t sid,
store_address_t storeId = storeId::INVALID_STORE_ADDRESS,
bool* clearMessage = nullptr) {
if(clearMessage != nullptr) {
*clearMessage = true;
}
}
/**
* @brief This function will be called by the manager if an update
* notification is received.
* @details
* Can be overriden by the child class to handle changed pool variables.
* @param gpid GPID of the updated variable.
* @param storeId If a snapshot was requested, data will be located inside
* the IPC store with this store ID.
* @param clearMessage Relevant for snapshots. If the boolean this points to is set to true,
* the pool manager will take care of clearing the store automatically
* after the callback.
*/
virtual void handleChangedPoolVariable(gp_id_t gpid,
store_address_t storeId = storeId::INVALID_STORE_ADDRESS,
bool* clearMessage = nullptr) {
if(clearMessage != nullptr) {
*clearMessage = true;
}
}
/**
* These function can be implemented by pool owner, if they are required
* and used by the housekeeping message interface.
* */
virtual ReturnValue_t addDataSet(sid_t sid) {
return HasReturnvaluesIF::RETURN_FAILED;
};
virtual ReturnValue_t removeDataSet(sid_t sid) {
return HasReturnvaluesIF::RETURN_FAILED;
};
virtual ReturnValue_t changeCollectionInterval(sid_t sid, float newIntervalSeconds) {
return HasReturnvaluesIF::RETURN_FAILED;
};
/**
* This function can be used by data pool consumers to retrieve a handle
* which allows subscriptions to dataset and variable updates in form of messages.
* The consumers can then read the most recent variable value by calling read with
* an own pool variable or set instance or using the deserialized snapshot data.
* Returns the HK manager casted to the required interface by default.
* @return
*/
virtual ProvidesDataPoolSubscriptionIF* getSubscriptionInterface() {
return getHkManagerHandle();
}
protected:
/**
* Every class implementing this interface should have a local data pool manager. This
* function will return a reference to the manager.
* @return
*/
virtual LocalDataPoolManager* getHkManagerHandle() = 0;
/**
* Accessor handle required for internal handling. Not intended for users and therefore
* declared protected. Users should instead use pool variables, sets or the subscription
* interface to access pool entries. Returns the HK manager casted to a different interface
* by default.
* @return
*/
virtual AccessPoolManagerIF* getAccessorHandle() {
return getHkManagerHandle();
}
/**
* This function is used by the pool manager to get a valid dataset
* from a SID. This function is protected to prevent users from
* using raw data set pointers which could not be thread-safe. Users
* should use the #ProvidesDataPoolSubscriptionIF.
* @param sid Corresponding structure ID
* @return
*/
virtual LocalPoolDataSetBase* getDataSetHandle(sid_t sid) = 0;
/**
* Similar to the function above, but used to get a local pool variable
* handle. This is only needed for update notifications, so it is not
* defined as abstract. This function is protected to prevent users from
* using raw pool variable pointers which could not be thread-safe.
* Users should use the #ProvidesDataPoolSubscriptionIF.
* @param localPoolId
* @return
*/
virtual LocalPoolObjectBase* getPoolObjectHandle(lp_id_t localPoolId) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "HasLocalDataPoolIF::getPoolObjectHandle: Not overriden. "
"Returning nullptr!" << std::endl;
#else
sif::printWarning("HasLocalDataPoolIF::getPoolObjectHandle: "
"Not overriden. Returning nullptr!\n");
#endif
return nullptr;
}
};
#endif /* FSFW_DATAPOOLLOCAL_HASLOCALDATAPOOLIF_H_ */

View File

@ -0,0 +1,942 @@
#include "HasLocalDataPoolIF.h"
#include "LocalDataPoolManager.h"
#include "LocalPoolObjectBase.h"
#include "LocalPoolDataSetBase.h"
#include "internal/LocalPoolDataSetAttorney.h"
#include "internal/HasLocalDpIFManagerAttorney.h"
#include "../housekeeping/HousekeepingSetPacket.h"
#include "../housekeeping/HousekeepingSnapshot.h"
#include "../housekeeping/AcceptsHkPacketsIF.h"
#include "../timemanager/CCSDSTime.h"
#include "../ipc/MutexFactory.h"
#include "../ipc/MutexGuard.h"
#include "../ipc/QueueFactory.h"
#include <array>
#include <cmath>
object_id_t LocalDataPoolManager::defaultHkDestination = objects::PUS_SERVICE_3_HOUSEKEEPING;
LocalDataPoolManager::LocalDataPoolManager(HasLocalDataPoolIF* owner, MessageQueueIF* queueToUse,
bool appendValidityBuffer):
appendValidityBuffer(appendValidityBuffer) {
if(owner == nullptr) {
printWarningOrError(sif::OutputTypes::OUT_WARNING,
"LocalDataPoolManager", HasReturnvaluesIF::RETURN_FAILED,
"Invalid supplied owner");
return;
}
this->owner = owner;
mutex = MutexFactory::instance()->createMutex();
if(mutex == nullptr) {
printWarningOrError(sif::OutputTypes::OUT_ERROR,
"LocalDataPoolManager", HasReturnvaluesIF::RETURN_FAILED,
"Could not create mutex");
}
hkQueue = queueToUse;
}
LocalDataPoolManager::~LocalDataPoolManager() {
if(mutex != nullptr) {
MutexFactory::instance()->deleteMutex(mutex);
}
}
ReturnValue_t LocalDataPoolManager::initialize(MessageQueueIF* queueToUse) {
if(queueToUse == nullptr) {
/* Error, all destinations invalid */
printWarningOrError(sif::OutputTypes::OUT_ERROR, "initialize",
QUEUE_OR_DESTINATION_INVALID);
}
hkQueue = queueToUse;
ipcStore = objectManager->get<StorageManagerIF>(objects::IPC_STORE);
if(ipcStore == nullptr) {
/* Error, all destinations invalid */
printWarningOrError(sif::OutputTypes::OUT_ERROR,
"initialize", HasReturnvaluesIF::RETURN_FAILED,
"Could not set IPC store.");
return HasReturnvaluesIF::RETURN_FAILED;
}
if(defaultHkDestination != objects::NO_OBJECT) {
AcceptsHkPacketsIF* hkPacketReceiver =
objectManager->get<AcceptsHkPacketsIF>(defaultHkDestination);
if(hkPacketReceiver != nullptr) {
hkDestinationId = hkPacketReceiver->getHkQueue();
}
else {
printWarningOrError(sif::OutputTypes::OUT_ERROR,
"initialize", QUEUE_OR_DESTINATION_INVALID);
return QUEUE_OR_DESTINATION_INVALID;
}
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t LocalDataPoolManager::initializeAfterTaskCreation(
uint8_t nonDiagInvlFactor) {
setNonDiagnosticIntervalFactor(nonDiagInvlFactor);
return initializeHousekeepingPoolEntriesOnce();
}
ReturnValue_t LocalDataPoolManager::initializeHousekeepingPoolEntriesOnce() {
if(not mapInitialized) {
ReturnValue_t result = owner->initializeLocalDataPool(localPoolMap,
*this);
if(result == HasReturnvaluesIF::RETURN_OK) {
mapInitialized = true;
}
return result;
}
printWarningOrError(sif::OutputTypes::OUT_WARNING,
"initialize", HasReturnvaluesIF::RETURN_FAILED,
"The map should only be initialized once");
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t LocalDataPoolManager::performHkOperation() {
ReturnValue_t status = HasReturnvaluesIF::RETURN_OK;
for(auto& receiver: hkReceivers) {
switch(receiver.reportingType) {
case(ReportingType::PERIODIC): {
if(receiver.dataType == DataType::LOCAL_POOL_VARIABLE) {
/* Periodic packets shall only be generated from datasets */
continue;
}
performPeriodicHkGeneration(receiver);
break;
}
case(ReportingType::UPDATE_HK): {
handleHkUpdate(receiver, status);
break;
}
case(ReportingType::UPDATE_NOTIFICATION): {
handleNotificationUpdate(receiver, status);
break;
}
case(ReportingType::UPDATE_SNAPSHOT): {
handleNotificationSnapshot(receiver, status);
break;
}
default:
// This should never happen.
return HasReturnvaluesIF::RETURN_FAILED;
}
}
resetHkUpdateResetHelper();
return status;
}
ReturnValue_t LocalDataPoolManager::handleHkUpdate(HkReceiver& receiver,
ReturnValue_t& status) {
if(receiver.dataType == DataType::LOCAL_POOL_VARIABLE) {
/* Update packets shall only be generated from datasets. */
return HasReturnvaluesIF::RETURN_FAILED;
}
LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner,
receiver.dataId.sid);
if(dataSet == nullptr) {
return DATASET_NOT_FOUND;
}
if(dataSet->hasChanged()) {
/* Prepare and send update notification */
ReturnValue_t result = generateHousekeepingPacket(
receiver.dataId.sid, dataSet, true);
if(result != HasReturnvaluesIF::RETURN_OK) {
status = result;
}
}
handleChangeResetLogic(receiver.dataType, receiver.dataId,
dataSet);
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t LocalDataPoolManager::handleNotificationUpdate(HkReceiver& receiver,
ReturnValue_t& status) {
MarkChangedIF* toReset = nullptr;
if(receiver.dataType == DataType::LOCAL_POOL_VARIABLE) {
LocalPoolObjectBase* poolObj = HasLocalDpIFManagerAttorney::getPoolObjectHandle(owner,
receiver.dataId.localPoolId);
if(poolObj == nullptr) {
printWarningOrError(sif::OutputTypes::OUT_WARNING,
"handleNotificationUpdate", POOLOBJECT_NOT_FOUND);
return POOLOBJECT_NOT_FOUND;
}
if(poolObj->hasChanged()) {
/* Prepare and send update notification. */
CommandMessage notification;
HousekeepingMessage::setUpdateNotificationVariableCommand(&notification,
gp_id_t(owner->getObjectId(), receiver.dataId.localPoolId));
ReturnValue_t result = hkQueue->sendMessage(receiver.destinationQueue, &notification);
if(result != HasReturnvaluesIF::RETURN_OK) {
status = result;
}
toReset = poolObj;
}
}
else {
LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner,
receiver.dataId.sid);
if(dataSet == nullptr) {
printWarningOrError(sif::OutputTypes::OUT_WARNING,
"handleNotificationUpdate", DATASET_NOT_FOUND);
return DATASET_NOT_FOUND;
}
if(dataSet->hasChanged()) {
/* Prepare and send update notification */
CommandMessage notification;
HousekeepingMessage::setUpdateNotificationSetCommand(&notification,
receiver.dataId.sid);
ReturnValue_t result = hkQueue->sendMessage(
receiver.destinationQueue, &notification);
if(result != HasReturnvaluesIF::RETURN_OK) {
status = result;
}
toReset = dataSet;
}
}
if(toReset != nullptr) {
handleChangeResetLogic(receiver.dataType, receiver.dataId, toReset);
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t LocalDataPoolManager::handleNotificationSnapshot(
HkReceiver& receiver, ReturnValue_t& status) {
MarkChangedIF* toReset = nullptr;
/* Check whether data has changed and send messages in case it has */
if(receiver.dataType == DataType::LOCAL_POOL_VARIABLE) {
LocalPoolObjectBase* poolObj = HasLocalDpIFManagerAttorney::getPoolObjectHandle(owner,
receiver.dataId.localPoolId);
if(poolObj == nullptr) {
printWarningOrError(sif::OutputTypes::OUT_WARNING,
"handleNotificationSnapshot", POOLOBJECT_NOT_FOUND);
return POOLOBJECT_NOT_FOUND;
}
if (not poolObj->hasChanged()) {
return HasReturnvaluesIF::RETURN_OK;
}
/* Prepare and send update snapshot */
timeval now;
Clock::getClock_timeval(&now);
CCSDSTime::CDS_short cds;
CCSDSTime::convertToCcsds(&cds, &now);
HousekeepingSnapshot updatePacket(reinterpret_cast<uint8_t*>(&cds), sizeof(cds),
HasLocalDpIFManagerAttorney::getPoolObjectHandle(
owner,receiver.dataId.localPoolId));
store_address_t storeId;
ReturnValue_t result = addUpdateToStore(updatePacket, storeId);
if(result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
CommandMessage notification;
HousekeepingMessage::setUpdateSnapshotVariableCommand(&notification,
gp_id_t(owner->getObjectId(), receiver.dataId.localPoolId), storeId);
result = hkQueue->sendMessage(receiver.destinationQueue,
&notification);
if (result != HasReturnvaluesIF::RETURN_OK) {
status = result;
}
toReset = poolObj;
}
else {
LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner,
receiver.dataId.sid);
if(dataSet == nullptr) {
printWarningOrError(sif::OutputTypes::OUT_WARNING,
"handleNotificationSnapshot", DATASET_NOT_FOUND);
return DATASET_NOT_FOUND;
}
if(not dataSet->hasChanged()) {
return HasReturnvaluesIF::RETURN_OK;
}
/* Prepare and send update snapshot */
timeval now;
Clock::getClock_timeval(&now);
CCSDSTime::CDS_short cds;
CCSDSTime::convertToCcsds(&cds, &now);
HousekeepingSnapshot updatePacket(reinterpret_cast<uint8_t*>(&cds),
sizeof(cds), HasLocalDpIFManagerAttorney::getDataSetHandle(owner,
receiver.dataId.sid));
store_address_t storeId;
ReturnValue_t result = addUpdateToStore(updatePacket, storeId);
if(result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
CommandMessage notification;
HousekeepingMessage::setUpdateSnapshotSetCommand(
&notification, receiver.dataId.sid, storeId);
result = hkQueue->sendMessage(receiver.destinationQueue, &notification);
if(result != HasReturnvaluesIF::RETURN_OK) {
status = result;
}
toReset = dataSet;
}
if(toReset != nullptr) {
handleChangeResetLogic(receiver.dataType,
receiver.dataId, toReset);
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t LocalDataPoolManager::addUpdateToStore(
HousekeepingSnapshot& updatePacket, store_address_t& storeId) {
size_t updatePacketSize = updatePacket.getSerializedSize();
uint8_t *storePtr = nullptr;
ReturnValue_t result = ipcStore->getFreeElement(&storeId,
updatePacket.getSerializedSize(), &storePtr);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
size_t serializedSize = 0;
result = updatePacket.serialize(&storePtr, &serializedSize,
updatePacketSize, SerializeIF::Endianness::MACHINE);
return result;;
}
void LocalDataPoolManager::handleChangeResetLogic(
DataType type, DataId dataId, MarkChangedIF* toReset) {
if(hkUpdateResetList == nullptr) {
/* Config error */
return;
}
HkUpdateResetList& listRef = *hkUpdateResetList;
for(auto& changeInfo: listRef) {
if(changeInfo.dataType != type) {
continue;
}
if((changeInfo.dataType == DataType::DATA_SET) and
(changeInfo.dataId.sid != dataId.sid)) {
continue;
}
if((changeInfo.dataType == DataType::LOCAL_POOL_VARIABLE) and
(changeInfo.dataId.localPoolId != dataId.localPoolId)) {
continue;
}
/* Only one update recipient, we can reset changes status immediately */
if(changeInfo.updateCounter <= 1) {
toReset->setChanged(false);
}
/* All recipients have been notified, reset the changed flag */
else if(changeInfo.currentUpdateCounter <= 1) {
toReset->setChanged(false);
changeInfo.currentUpdateCounter = 0;
}
/* Not all recipiens have been notified yet, decrement */
else {
changeInfo.currentUpdateCounter--;
}
return;
}
}
void LocalDataPoolManager::resetHkUpdateResetHelper() {
if(hkUpdateResetList == nullptr) {
return;
}
for(auto& changeInfo: *hkUpdateResetList) {
changeInfo.currentUpdateCounter = changeInfo.updateCounter;
}
}
ReturnValue_t LocalDataPoolManager::subscribeForPeriodicPacket(sid_t sid,
bool enableReporting, float collectionInterval, bool isDiagnostics,
object_id_t packetDestination) {
AcceptsHkPacketsIF* hkReceiverObject =
objectManager->get<AcceptsHkPacketsIF>(packetDestination);
if(hkReceiverObject == nullptr) {
printWarningOrError(sif::OutputTypes::OUT_WARNING,
"subscribeForPeriodicPacket", QUEUE_OR_DESTINATION_INVALID);
return QUEUE_OR_DESTINATION_INVALID;
}
struct HkReceiver hkReceiver;
hkReceiver.dataId.sid = sid;
hkReceiver.reportingType = ReportingType::PERIODIC;
hkReceiver.dataType = DataType::DATA_SET;
hkReceiver.destinationQueue = hkReceiverObject->getHkQueue();
LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid);
if(dataSet != nullptr) {
LocalPoolDataSetAttorney::setReportingEnabled(*dataSet, enableReporting);
LocalPoolDataSetAttorney::setDiagnostic(*dataSet, isDiagnostics);
LocalPoolDataSetAttorney::initializePeriodicHelper(*dataSet, collectionInterval,
owner->getPeriodicOperationFrequency());
}
hkReceivers.push_back(hkReceiver);
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t LocalDataPoolManager::subscribeForUpdatePacket(sid_t sid,
bool isDiagnostics, bool reportingEnabled,
object_id_t packetDestination) {
AcceptsHkPacketsIF* hkReceiverObject =
objectManager->get<AcceptsHkPacketsIF>(packetDestination);
if(hkReceiverObject == nullptr) {
printWarningOrError(sif::OutputTypes::OUT_WARNING,
"subscribeForPeriodicPacket", QUEUE_OR_DESTINATION_INVALID);
return QUEUE_OR_DESTINATION_INVALID;
}
struct HkReceiver hkReceiver;
hkReceiver.dataId.sid = sid;
hkReceiver.reportingType = ReportingType::UPDATE_HK;
hkReceiver.dataType = DataType::DATA_SET;
hkReceiver.destinationQueue = hkReceiverObject->getHkQueue();
LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid);
if(dataSet != nullptr) {
LocalPoolDataSetAttorney::setReportingEnabled(*dataSet, true);
LocalPoolDataSetAttorney::setDiagnostic(*dataSet, isDiagnostics);
}
hkReceivers.push_back(hkReceiver);
handleHkUpdateResetListInsertion(hkReceiver.dataType, hkReceiver.dataId);
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t LocalDataPoolManager::subscribeForSetUpdateMessage(
const uint32_t setId, object_id_t destinationObject,
MessageQueueId_t targetQueueId, bool generateSnapshot) {
struct HkReceiver hkReceiver;
hkReceiver.dataType = DataType::DATA_SET;
hkReceiver.dataId.sid = sid_t(owner->getObjectId(), setId);
hkReceiver.destinationQueue = targetQueueId;
hkReceiver.objectId = destinationObject;
if(generateSnapshot) {
hkReceiver.reportingType = ReportingType::UPDATE_SNAPSHOT;
}
else {
hkReceiver.reportingType = ReportingType::UPDATE_NOTIFICATION;
}
hkReceivers.push_back(hkReceiver);
handleHkUpdateResetListInsertion(hkReceiver.dataType, hkReceiver.dataId);
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t LocalDataPoolManager::subscribeForVariableUpdateMessage(
const lp_id_t localPoolId, object_id_t destinationObject,
MessageQueueId_t targetQueueId, bool generateSnapshot) {
struct HkReceiver hkReceiver;
hkReceiver.dataType = DataType::LOCAL_POOL_VARIABLE;
hkReceiver.dataId.localPoolId = localPoolId;
hkReceiver.destinationQueue = targetQueueId;
hkReceiver.objectId = destinationObject;
if(generateSnapshot) {
hkReceiver.reportingType = ReportingType::UPDATE_SNAPSHOT;
}
else {
hkReceiver.reportingType = ReportingType::UPDATE_NOTIFICATION;
}
hkReceivers.push_back(hkReceiver);
handleHkUpdateResetListInsertion(hkReceiver.dataType, hkReceiver.dataId);
return HasReturnvaluesIF::RETURN_OK;
}
void LocalDataPoolManager::handleHkUpdateResetListInsertion(DataType dataType,
DataId dataId) {
if(hkUpdateResetList == nullptr) {
hkUpdateResetList = new std::vector<struct HkUpdateResetHelper>();
}
for(auto& updateResetStruct: *hkUpdateResetList) {
if(dataType == DataType::DATA_SET) {
if(updateResetStruct.dataId.sid == dataId.sid) {
updateResetStruct.updateCounter++;
updateResetStruct.currentUpdateCounter++;
return;
}
}
else {
if(updateResetStruct.dataId.localPoolId == dataId.localPoolId) {
updateResetStruct.updateCounter++;
updateResetStruct.currentUpdateCounter++;
return;
}
}
}
HkUpdateResetHelper hkUpdateResetHelper;
hkUpdateResetHelper.currentUpdateCounter = 1;
hkUpdateResetHelper.updateCounter = 1;
hkUpdateResetHelper.dataType = dataType;
if(dataType == DataType::DATA_SET) {
hkUpdateResetHelper.dataId.sid = dataId.sid;
}
else {
hkUpdateResetHelper.dataId.localPoolId = dataId.localPoolId;
}
hkUpdateResetList->push_back(hkUpdateResetHelper);
}
ReturnValue_t LocalDataPoolManager::handleHousekeepingMessage(
CommandMessage* message) {
Command_t command = message->getCommand();
sid_t sid = HousekeepingMessage::getSid(message);
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
switch(command) {
// Houskeeping interface handling.
case(HousekeepingMessage::ENABLE_PERIODIC_DIAGNOSTICS_GENERATION): {
result = togglePeriodicGeneration(sid, true, true);
break;
}
case(HousekeepingMessage::DISABLE_PERIODIC_DIAGNOSTICS_GENERATION): {
result = togglePeriodicGeneration(sid, false, true);
break;
}
case(HousekeepingMessage::ENABLE_PERIODIC_HK_REPORT_GENERATION): {
result = togglePeriodicGeneration(sid, true, false);
break;
}
case(HousekeepingMessage::DISABLE_PERIODIC_HK_REPORT_GENERATION): {
result = togglePeriodicGeneration(sid, false, false);
break;
}
case(HousekeepingMessage::REPORT_DIAGNOSTICS_REPORT_STRUCTURES): {
result = generateSetStructurePacket(sid, true);
if(result == HasReturnvaluesIF::RETURN_OK) {
return result;
}
break;
}
case(HousekeepingMessage::REPORT_HK_REPORT_STRUCTURES): {
result = generateSetStructurePacket(sid, false);
if(result == HasReturnvaluesIF::RETURN_OK) {
return result;
}
break;
}
case(HousekeepingMessage::MODIFY_DIAGNOSTICS_REPORT_COLLECTION_INTERVAL):
case(HousekeepingMessage::MODIFY_PARAMETER_REPORT_COLLECTION_INTERVAL): {
float newCollIntvl = 0;
HousekeepingMessage::getCollectionIntervalModificationCommand(message,
&newCollIntvl);
if(command == HousekeepingMessage::
MODIFY_DIAGNOSTICS_REPORT_COLLECTION_INTERVAL) {
result = changeCollectionInterval(sid, newCollIntvl, true);
}
else {
result = changeCollectionInterval(sid, newCollIntvl, false);
}
break;
}
case(HousekeepingMessage::GENERATE_ONE_PARAMETER_REPORT):
case(HousekeepingMessage::GENERATE_ONE_DIAGNOSTICS_REPORT): {
LocalPoolDataSetBase* dataSet =HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid);
if(command == HousekeepingMessage::GENERATE_ONE_PARAMETER_REPORT
and LocalPoolDataSetAttorney::isDiagnostics(*dataSet)) {
result = WRONG_HK_PACKET_TYPE;
break;
}
else if(command == HousekeepingMessage::GENERATE_ONE_DIAGNOSTICS_REPORT
and not LocalPoolDataSetAttorney::isDiagnostics(*dataSet)) {
result = WRONG_HK_PACKET_TYPE;
break;
}
return generateHousekeepingPacket(HousekeepingMessage::getSid(message),
dataSet, true);
}
/* Notification handling */
case(HousekeepingMessage::UPDATE_NOTIFICATION_SET): {
owner->handleChangedDataset(sid);
return HasReturnvaluesIF::RETURN_OK;
}
case(HousekeepingMessage::UPDATE_NOTIFICATION_VARIABLE): {
gp_id_t globPoolId = HousekeepingMessage::getUpdateNotificationVariableCommand(message);
owner->handleChangedPoolVariable(globPoolId);
return HasReturnvaluesIF::RETURN_OK;
}
case(HousekeepingMessage::UPDATE_SNAPSHOT_SET): {
store_address_t storeId;
HousekeepingMessage::getUpdateSnapshotSetCommand(message, &storeId);
bool clearMessage = true;
owner->handleChangedDataset(sid, storeId, &clearMessage);
if(clearMessage) {
message->clear();
}
return HasReturnvaluesIF::RETURN_OK;
}
case(HousekeepingMessage::UPDATE_SNAPSHOT_VARIABLE): {
store_address_t storeId;
gp_id_t globPoolId = HousekeepingMessage::getUpdateSnapshotVariableCommand(message,
&storeId);
bool clearMessage = true;
owner->handleChangedPoolVariable(globPoolId, storeId, &clearMessage);
if(clearMessage) {
message->clear();
}
return HasReturnvaluesIF::RETURN_OK;
}
default:
return CommandMessageIF::UNKNOWN_COMMAND;
}
CommandMessage reply;
if(result != HasReturnvaluesIF::RETURN_OK) {
HousekeepingMessage::setHkRequestFailureReply(&reply, sid, result);
}
else {
HousekeepingMessage::setHkRequestSuccessReply(&reply, sid);
}
hkQueue->sendMessage(hkDestinationId, &reply);
return result;
}
ReturnValue_t LocalDataPoolManager::printPoolEntry(
lp_id_t localPoolId) {
auto poolIter = localPoolMap.find(localPoolId);
if (poolIter == localPoolMap.end()) {
printWarningOrError(sif::OutputTypes::OUT_WARNING, "printPoolEntry",
localpool::POOL_ENTRY_NOT_FOUND);
return localpool::POOL_ENTRY_NOT_FOUND;
}
poolIter->second->print();
return HasReturnvaluesIF::RETURN_OK;
}
MutexIF* LocalDataPoolManager::getMutexHandle() {
return mutex;
}
HasLocalDataPoolIF* LocalDataPoolManager::getOwner() {
return owner;
}
ReturnValue_t LocalDataPoolManager::generateHousekeepingPacket(sid_t sid,
LocalPoolDataSetBase* dataSet, bool forDownlink,
MessageQueueId_t destination) {
if(dataSet == nullptr) {
/* Configuration error. */
printWarningOrError(sif::OutputTypes::OUT_WARNING,
"generateHousekeepingPacket",
DATASET_NOT_FOUND);
return DATASET_NOT_FOUND;
}
store_address_t storeId;
HousekeepingPacketDownlink hkPacket(sid, dataSet);
size_t serializedSize = 0;
ReturnValue_t result = serializeHkPacketIntoStore(hkPacket, storeId,
forDownlink, &serializedSize);
if(result != HasReturnvaluesIF::RETURN_OK or serializedSize == 0) {
return result;
}
/* Now we set a HK message and send it the HK packet destination. */
CommandMessage hkMessage;
if(LocalPoolDataSetAttorney::isDiagnostics(*dataSet)) {
HousekeepingMessage::setHkDiagnosticsReply(&hkMessage, sid, storeId);
}
else {
HousekeepingMessage::setHkReportReply(&hkMessage, sid, storeId);
}
if(hkQueue == nullptr) {
/* Error, no queue available to send packet with. */
printWarningOrError(sif::OutputTypes::OUT_WARNING,
"generateHousekeepingPacket",
QUEUE_OR_DESTINATION_INVALID);
return QUEUE_OR_DESTINATION_INVALID;
}
if(destination == MessageQueueIF::NO_QUEUE) {
if(hkDestinationId == MessageQueueIF::NO_QUEUE) {
/* Error, all destinations invalid */
printWarningOrError(sif::OutputTypes::OUT_WARNING,
"generateHousekeepingPacket",
QUEUE_OR_DESTINATION_INVALID);
}
destination = hkDestinationId;
}
return hkQueue->sendMessage(destination, &hkMessage);
}
ReturnValue_t LocalDataPoolManager::serializeHkPacketIntoStore(
HousekeepingPacketDownlink& hkPacket,
store_address_t& storeId, bool forDownlink,
size_t* serializedSize) {
uint8_t* dataPtr = nullptr;
const size_t maxSize = hkPacket.getSerializedSize();
ReturnValue_t result = ipcStore->getFreeElement(&storeId,
maxSize, &dataPtr);
if(result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
if(forDownlink) {
return hkPacket.serialize(&dataPtr, serializedSize, maxSize,
SerializeIF::Endianness::BIG);
}
return hkPacket.serialize(&dataPtr, serializedSize, maxSize,
SerializeIF::Endianness::MACHINE);
}
void LocalDataPoolManager::setNonDiagnosticIntervalFactor(
uint8_t nonDiagInvlFactor) {
this->nonDiagnosticIntervalFactor = nonDiagInvlFactor;
}
void LocalDataPoolManager::performPeriodicHkGeneration(HkReceiver& receiver) {
sid_t sid = receiver.dataId.sid;
LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid);
if(dataSet == nullptr) {
printWarningOrError(sif::OutputTypes::OUT_WARNING,
"performPeriodicHkGeneration",
DATASET_NOT_FOUND);
return;
}
if(not LocalPoolDataSetAttorney::getReportingEnabled(*dataSet)) {
return;
}
PeriodicHousekeepingHelper* periodicHelper =
LocalPoolDataSetAttorney::getPeriodicHelper(*dataSet);
if(periodicHelper == nullptr) {
/* Configuration error */
return;
}
if(not periodicHelper->checkOpNecessary()) {
return;
}
ReturnValue_t result = generateHousekeepingPacket(
sid, dataSet, true);
if(result != HasReturnvaluesIF::RETURN_OK) {
/* Configuration error */
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "LocalDataPoolManager::performHkOperation: HK generation failed." <<
std::endl;
#else
sif::printWarning("LocalDataPoolManager::performHkOperation: HK generation failed.\n");
#endif
}
}
ReturnValue_t LocalDataPoolManager::togglePeriodicGeneration(sid_t sid,
bool enable, bool isDiagnostics) {
LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid);
if(dataSet == nullptr) {
printWarningOrError(sif::OutputTypes::OUT_WARNING, "togglePeriodicGeneration",
DATASET_NOT_FOUND);
return DATASET_NOT_FOUND;
}
if((LocalPoolDataSetAttorney::isDiagnostics(*dataSet) and not isDiagnostics) or
(not LocalPoolDataSetAttorney::isDiagnostics(*dataSet) and isDiagnostics)) {
return WRONG_HK_PACKET_TYPE;
}
if((LocalPoolDataSetAttorney::getReportingEnabled(*dataSet) and enable) or
(not LocalPoolDataSetAttorney::getReportingEnabled(*dataSet) and not enable)) {
return REPORTING_STATUS_UNCHANGED;
}
LocalPoolDataSetAttorney::setReportingEnabled(*dataSet, enable);
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t LocalDataPoolManager::changeCollectionInterval(sid_t sid,
float newCollectionInterval, bool isDiagnostics) {
LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid);
if(dataSet == nullptr) {
printWarningOrError(sif::OutputTypes::OUT_WARNING, "changeCollectionInterval",
DATASET_NOT_FOUND);
return DATASET_NOT_FOUND;
}
bool targetIsDiagnostics = LocalPoolDataSetAttorney::isDiagnostics(*dataSet);
if((targetIsDiagnostics and not isDiagnostics) or
(not targetIsDiagnostics and isDiagnostics)) {
return WRONG_HK_PACKET_TYPE;
}
PeriodicHousekeepingHelper* periodicHelper =
LocalPoolDataSetAttorney::getPeriodicHelper(*dataSet);
if(periodicHelper == nullptr) {
/* Configuration error, set might not have a corresponding pool manager */
return PERIODIC_HELPER_INVALID;
}
periodicHelper->changeCollectionInterval(newCollectionInterval);
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t LocalDataPoolManager::generateSetStructurePacket(sid_t sid,
bool isDiagnostics) {
/* Get and check dataset first. */
LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid);
if(dataSet == nullptr) {
printWarningOrError(sif::OutputTypes::OUT_WARNING,
"performPeriodicHkGeneration", DATASET_NOT_FOUND);
return DATASET_NOT_FOUND;
}
bool targetIsDiagnostics = LocalPoolDataSetAttorney::isDiagnostics(*dataSet);
if((targetIsDiagnostics and not isDiagnostics) or
(not targetIsDiagnostics and isDiagnostics)) {
return WRONG_HK_PACKET_TYPE;
}
bool valid = dataSet->isValid();
bool reportingEnabled = LocalPoolDataSetAttorney::getReportingEnabled(*dataSet);
float collectionInterval = LocalPoolDataSetAttorney::getPeriodicHelper(*dataSet)->
getCollectionIntervalInSeconds();
// Generate set packet which can be serialized.
HousekeepingSetPacket setPacket(sid,
reportingEnabled, valid, collectionInterval, dataSet);
size_t expectedSize = setPacket.getSerializedSize();
uint8_t* storePtr = nullptr;
store_address_t storeId;
ReturnValue_t result = ipcStore->getFreeElement(&storeId,
expectedSize,&storePtr);
if(result != HasReturnvaluesIF::RETURN_OK) {
printWarningOrError(sif::OutputTypes::OUT_ERROR,
"generateSetStructurePacket", HasReturnvaluesIF::RETURN_FAILED,
"Could not get free element from IPC store.");
return result;
}
// Serialize set packet into store.
size_t size = 0;
result = setPacket.serialize(&storePtr, &size, expectedSize,
SerializeIF::Endianness::BIG);
if(expectedSize != size) {
printWarningOrError(sif::OutputTypes::OUT_WARNING,
"generateSetStructurePacket", HasReturnvaluesIF::RETURN_FAILED,
"Expected size is not equal to serialized size");
}
// Send structure reporting reply.
CommandMessage reply;
if(isDiagnostics) {
HousekeepingMessage::setDiagnosticsStuctureReportReply(&reply,
sid, storeId);
}
else {
HousekeepingMessage::setHkStuctureReportReply(&reply,
sid, storeId);
}
hkQueue->reply(&reply);
return result;
}
void LocalDataPoolManager::clearReceiversList() {
/* Clear the vector completely and releases allocated memory. */
HkReceivers().swap(hkReceivers);
/* Also clear the reset helper if it exists */
if(hkUpdateResetList != nullptr) {
HkUpdateResetList().swap(*hkUpdateResetList);
}
}
MutexIF* LocalDataPoolManager::getLocalPoolMutex() {
return this->mutex;
}
object_id_t LocalDataPoolManager::getCreatorObjectId() const {
return owner->getObjectId();
}
void LocalDataPoolManager::printWarningOrError(sif::OutputTypes outputType,
const char* functionName, ReturnValue_t error, const char* errorPrint) {
#if FSFW_VERBOSE_LEVEL >= 1
if(errorPrint == nullptr) {
if(error == DATASET_NOT_FOUND) {
errorPrint = "Dataset not found";
}
else if(error == POOLOBJECT_NOT_FOUND) {
errorPrint = "Pool Object not found";
}
else if(error == HasReturnvaluesIF::RETURN_FAILED) {
if(outputType == sif::OutputTypes::OUT_WARNING) {
errorPrint = "Generic Warning";
}
else {
errorPrint = "Generic error";
}
}
else if(error == QUEUE_OR_DESTINATION_INVALID) {
errorPrint = "Queue or destination not set";
}
else if(error == localpool::POOL_ENTRY_TYPE_CONFLICT) {
errorPrint = "Pool entry type conflict";
}
else if(error == localpool::POOL_ENTRY_NOT_FOUND) {
errorPrint = "Pool entry not found";
}
else {
errorPrint = "Unknown error";
}
}
object_id_t objectId = 0xffffffff;
if(owner != nullptr) {
objectId = owner->getObjectId();
}
if(outputType == sif::OutputTypes::OUT_WARNING) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "LocalDataPoolManager::" << functionName << ": Object ID 0x" <<
std::setw(8) << std::setfill('0') << std::hex << objectId << " | " << errorPrint <<
std::dec << std::setfill(' ') << std::endl;
#else
sif::printWarning("LocalDataPoolManager::%s: Object ID 0x%08x | %s\n",
functionName, objectId, errorPrint);
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
}
else if(outputType == sif::OutputTypes::OUT_ERROR) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "LocalDataPoolManager::" << functionName << ": Object ID 0x" <<
std::setw(8) << std::setfill('0') << std::hex << objectId << " | " << errorPrint <<
std::dec << std::setfill(' ') << std::endl;
#else
sif::printError("LocalDataPoolManager::%s: Object ID 0x%08x | %s\n",
functionName, objectId, errorPrint);
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
}
#endif /* #if FSFW_VERBOSE_LEVEL >= 1 */
}
LocalDataPoolManager* LocalDataPoolManager::getPoolManagerHandle() {
return this;
}

View File

@ -0,0 +1,415 @@
#ifndef FSFW_DATAPOOLLOCAL_LOCALDATAPOOLMANAGER_H_
#define FSFW_DATAPOOLLOCAL_LOCALDATAPOOLMANAGER_H_
#include "ProvidesDataPoolSubscriptionIF.h"
#include "AccessLocalPoolF.h"
#include "../serviceinterface/ServiceInterface.h"
#include "../housekeeping/HousekeepingPacketDownlink.h"
#include "../housekeeping/HousekeepingMessage.h"
#include "../housekeeping/PeriodicHousekeepingHelper.h"
#include "../datapool/DataSetIF.h"
#include "../datapool/PoolEntry.h"
#include "../objectmanager/SystemObjectIF.h"
#include "../ipc/MutexIF.h"
#include "../ipc/CommandMessage.h"
#include "../ipc/MessageQueueIF.h"
#include "../ipc/MutexGuard.h"
#include <map>
#include <vector>
namespace Factory {
void setStaticFrameworkObjectIds();
}
class LocalPoolDataSetBase;
class HousekeepingSnapshot;
class HasLocalDataPoolIF;
class LocalDataPool;
/**
* @brief This class is the managing instance for the local data pool.
* @details
* The actual data pool structure is a member of this class. Any class which
* has a local data pool shall have this manager class as a member and implement
* the HasLocalDataPoolIF.
*
* The manager offers some adaption points and functions which can be used
* by the owning class to simplify data handling significantly.
*
* Please ensure that both initialize and initializeAfterTaskCreation are
* called at some point by the owning class in the respective functions of the
* same name!
*
* Users of the data pool use the helper classes LocalDataSet,
* LocalPoolVariable and LocalPoolVector to access pool entries in
* a thread-safe and efficient way.
*
* The local data pools employ a blackboard logic: Only the most recent
* value is stored. The helper classes offer a read() and commit() interface
* through the PoolVariableIF which is used to read and update values.
* Each pool entry has a valid state too.
* @author R. Mueller
*/
class LocalDataPoolManager:
public ProvidesDataPoolSubscriptionIF,
public AccessPoolManagerIF {
friend void (Factory::setStaticFrameworkObjectIds)();
//! Some classes using the pool manager directly need to access class internals of the
//! manager. The attorney provides granular control of access to these internals.
friend class LocalDpManagerAttorney;
public:
static constexpr uint8_t INTERFACE_ID = CLASS_ID::HOUSEKEEPING_MANAGER;
static constexpr ReturnValue_t QUEUE_OR_DESTINATION_INVALID = MAKE_RETURN_CODE(0);
static constexpr ReturnValue_t WRONG_HK_PACKET_TYPE = MAKE_RETURN_CODE(1);
static constexpr ReturnValue_t REPORTING_STATUS_UNCHANGED = MAKE_RETURN_CODE(2);
static constexpr ReturnValue_t PERIODIC_HELPER_INVALID = MAKE_RETURN_CODE(3);
static constexpr ReturnValue_t POOLOBJECT_NOT_FOUND = MAKE_RETURN_CODE(4);
static constexpr ReturnValue_t DATASET_NOT_FOUND = MAKE_RETURN_CODE(5);
/**
* This constructor is used by a class which wants to implement
* a personal local data pool. The queueToUse can be supplied if it
* is already known.
*
* initialize() has to be called in any case before using the object!
* @param owner
* @param queueToUse
* @param appendValidityBuffer Specify whether a buffer containing the
* validity state is generated when serializing or deserializing packets.
*/
LocalDataPoolManager(HasLocalDataPoolIF* owner, MessageQueueIF* queueToUse,
bool appendValidityBuffer = true);
virtual~ LocalDataPoolManager();
/**
* Assigns the queue to use. Make sure to call this in the #initialize
* function of the owner.
* @param queueToUse
* @param nonDiagInvlFactor See #setNonDiagnosticIntervalFactor doc
* @return
*/
ReturnValue_t initialize(MessageQueueIF* queueToUse);
/**
* Initializes the map by calling the map initialization function and
* setting the periodic factor for non-diagnostic packets.
* Don't forget to call this in the #initializeAfterTaskCreation call of
* the owner, otherwise the map will be invalid!
* @param nonDiagInvlFactor
* @return
*/
ReturnValue_t initializeAfterTaskCreation(
uint8_t nonDiagInvlFactor = 5);
/**
* @brief This should be called in the periodic handler of the owner.
* @details
* This in generally called in the #performOperation function of the owner.
* It performs all the periodic functionalities of the data pool manager,
* for example generating periodic HK packets.
* Marked virtual as an adaption point for custom data pool managers.
* @return
*/
virtual ReturnValue_t performHkOperation();
/**
* @brief Subscribe for the generation of periodic packets.
* @details
* This subscription mechanism will generally be used by the data creator
* to generate housekeeping packets which are downlinked directly.
* @return
*/
ReturnValue_t subscribeForPeriodicPacket(sid_t sid, bool enableReporting,
float collectionInterval, bool isDiagnostics,
object_id_t packetDestination = defaultHkDestination) override;
/**
* @brief Subscribe for the generation of packets if the dataset
* is marked as changed.
* @details
* This subscription mechanism will generally be used by the data creator.
* @param sid
* @param isDiagnostics
* @param packetDestination
* @return
*/
ReturnValue_t subscribeForUpdatePacket(sid_t sid, bool reportingEnabled,
bool isDiagnostics,
object_id_t packetDestination = defaultHkDestination) override;
/**
* @brief Subscribe for a notification message which will be sent
* if a dataset has changed.
* @details
* This subscription mechanism will generally be used internally by
* other software components.
* @param setId Set ID of the set to receive update messages from.
* @param destinationObject
* @param targetQueueId
* @param generateSnapshot If this is set to true, a copy of the current
* data with a timestamp will be generated and sent via message.
* Otherwise, only an notification message is sent.
* @return
*/
ReturnValue_t subscribeForSetUpdateMessage(const uint32_t setId,
object_id_t destinationObject,
MessageQueueId_t targetQueueId,
bool generateSnapshot) override;
/**
* @brief Subscribe for an notification message which will be sent if a
* pool variable has changed.
* @details
* This subscription mechanism will generally be used internally by
* other software components.
* @param localPoolId Pool ID of the pool variable
* @param destinationObject
* @param targetQueueId
* @param generateSnapshot If this is set to true, a copy of the current
* data with a timestamp will be generated and sent via message.
* Otherwise, only an notification message is sent.
* @return
*/
ReturnValue_t subscribeForVariableUpdateMessage(const lp_id_t localPoolId,
object_id_t destinationObject,
MessageQueueId_t targetQueueId,
bool generateSnapshot) override;
/**
* Non-Diagnostics packets usually have a lower minimum sampling frequency
* than diagnostic packets.
* A factor can be specified to determine the minimum sampling frequency
* for non-diagnostic packets. The minimum sampling frequency of the
* diagnostics packets,which is usually jusst the period of the
* performOperation calls, is multiplied with that factor.
* @param factor
*/
void setNonDiagnosticIntervalFactor(uint8_t nonDiagInvlFactor);
/**
* @brief The manager is also able to handle housekeeping messages.
* @details
* This most commonly is used to handle messages for the housekeeping
* interface, but the manager is also able to handle update notifications
* and calls a special function which can be overriden by a child class
* to handle data set or pool variable updates. This is relevant
* for classes like controllers which have their own local datapool
* but pull their data from other local datapools.
* @param message
* @return
*/
virtual ReturnValue_t handleHousekeepingMessage(CommandMessage* message);
/**
* Generate a housekeeping packet with a given SID.
* @param sid
* @return
*/
ReturnValue_t generateHousekeepingPacket(sid_t sid,
LocalPoolDataSetBase* dataSet, bool forDownlink,
MessageQueueId_t destination = MessageQueueIF::NO_QUEUE);
HasLocalDataPoolIF* getOwner();
ReturnValue_t printPoolEntry(lp_id_t localPoolId);
/**
* Different types of housekeeping reporting are possible.
* 1. PERIODIC:
* HK packets are generated in fixed intervals and sent to
* destination. Fromat will be raw.
* 2. UPDATE_NOTIFICATION:
* Notification will be sent out if HK data has changed.
* 3. UPDATE_SNAPSHOT:
* HK packets are only generated if explicitely requested.
* Propably not necessary, just use multiple local data sets or
* shared datasets.
*/
enum class ReportingType: uint8_t {
//! Periodic generation of HK packets.
PERIODIC,
//! Housekeeping packet will be generated if values have changed.
UPDATE_HK,
//! Update notification will be sent out as message.
UPDATE_NOTIFICATION,
//! Notification will be sent out as message and a snapshot of the
//! current data will be generated.
UPDATE_SNAPSHOT,
};
/** Different data types are possible in the HK receiver map. For example, updates can be
requested for full datasets or for single pool variables. Periodic reporting is only possible
for data sets. */
enum class DataType: uint8_t {
LOCAL_POOL_VARIABLE,
DATA_SET
};
/* Copying forbidden */
LocalDataPoolManager(const LocalDataPoolManager &) = delete;
LocalDataPoolManager operator=(const LocalDataPoolManager&) = delete;
/**
* This function can be used to clear the receivers list. This is
* intended for test functions and not for regular operations, because
* the insertion operations allocate dynamically.
*/
void clearReceiversList();
object_id_t getCreatorObjectId() const;
/**
* Get the pointer to the mutex. Can be used to lock the data pool
* externally. Use with care and don't forget to unlock locked mutexes!
* For now, only friend classes can accss this function.
* @return
*/
MutexIF* getMutexHandle();
virtual LocalDataPoolManager* getPoolManagerHandle() override;
protected:
/** Core data structure for the actual pool data */
localpool::DataPool localPoolMap;
/** Every housekeeping data manager has a mutex to protect access
to it's data pool. */
MutexIF* mutex = nullptr;
/** The class which actually owns the manager (and its datapool). */
HasLocalDataPoolIF* owner = nullptr;
uint8_t nonDiagnosticIntervalFactor = 0;
/** Default receiver for periodic HK packets */
static object_id_t defaultHkDestination;
MessageQueueId_t hkDestinationId = MessageQueueIF::NO_QUEUE;
union DataId {
DataId(): sid() {};
sid_t sid;
lp_id_t localPoolId;
};
/** The data pool manager will keep an internal map of HK receivers. */
struct HkReceiver {
/** Object ID of receiver */
object_id_t objectId = objects::NO_OBJECT;
DataType dataType = DataType::DATA_SET;
DataId dataId;
ReportingType reportingType = ReportingType::PERIODIC;
MessageQueueId_t destinationQueue = MessageQueueIF::NO_QUEUE;
};
/** This vector will contain the list of HK receivers. */
using HkReceivers = std::vector<struct HkReceiver>;
HkReceivers hkReceivers;
struct HkUpdateResetHelper {
DataType dataType = DataType::DATA_SET;
DataId dataId;
uint8_t updateCounter;
uint8_t currentUpdateCounter;
};
using HkUpdateResetList = std::vector<struct HkUpdateResetHelper>;
/** This list is used to manage creating multiple update packets and only resetting
the update flag if all of them were created. Will only be created when needed. */
HkUpdateResetList* hkUpdateResetList = nullptr;
/** This is the map holding the actual data. Should only be initialized
* once ! */
bool mapInitialized = false;
/** This specifies whether a validity buffer is appended at the end
* of generated housekeeping packets. */
bool appendValidityBuffer = true;
/**
* @brief Queue used for communication, for example commands.
* Is also used to send messages. Can be set either in the constructor
* or in the initialize() function.
*/
MessageQueueIF* hkQueue = nullptr;
/** Global IPC store is used to store all packets. */
StorageManagerIF* ipcStore = nullptr;
/**
* Read a variable by supplying its local pool ID and assign the pool
* entry to the supplied PoolEntry pointer. The type of the pool entry
* is deduced automatically. This call is not thread-safe!
* For now, only classes designated by the LocalDpManagerAttorney may use this function.
* @tparam T Type of the pool entry
* @param localPoolId Pool ID of the variable to read
* @param poolVar [out] Corresponding pool entry will be assigned to the
* supplied pointer.
* @return
*/
template <class T> ReturnValue_t fetchPoolEntry(lp_id_t localPoolId, PoolEntry<T> **poolEntry);
/**
* This function is used to fill the local data pool map with pool
* entries. It should only be called once by the pool owner.
* @param localDataPoolMap
* @return
*/
ReturnValue_t initializeHousekeepingPoolEntriesOnce();
MutexIF* getLocalPoolMutex() override;
ReturnValue_t serializeHkPacketIntoStore(HousekeepingPacketDownlink& hkPacket,
store_address_t& storeId, bool forDownlink, size_t* serializedSize);
void performPeriodicHkGeneration(HkReceiver& hkReceiver);
ReturnValue_t togglePeriodicGeneration(sid_t sid, bool enable, bool isDiagnostics);
ReturnValue_t changeCollectionInterval(sid_t sid, float newCollectionInterval,
bool isDiagnostics);
ReturnValue_t generateSetStructurePacket(sid_t sid, bool isDiagnostics);
void handleHkUpdateResetListInsertion(DataType dataType, DataId dataId);
void handleChangeResetLogic(DataType type,
DataId dataId, MarkChangedIF* toReset);
void resetHkUpdateResetHelper();
ReturnValue_t handleHkUpdate(HkReceiver& hkReceiver, ReturnValue_t& status);
ReturnValue_t handleNotificationUpdate(HkReceiver& hkReceiver, ReturnValue_t& status);
ReturnValue_t handleNotificationSnapshot(HkReceiver& hkReceiver, ReturnValue_t& status);
ReturnValue_t addUpdateToStore(HousekeepingSnapshot& updatePacket, store_address_t& storeId);
void printWarningOrError(sif::OutputTypes outputType, const char* functionName,
ReturnValue_t errorCode = HasReturnvaluesIF::RETURN_FAILED,
const char* errorPrint = nullptr);
};
template<class T> inline
ReturnValue_t LocalDataPoolManager::fetchPoolEntry(lp_id_t localPoolId, PoolEntry<T> **poolEntry) {
if(poolEntry == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
auto poolIter = localPoolMap.find(localPoolId);
if (poolIter == localPoolMap.end()) {
printWarningOrError(sif::OutputTypes::OUT_WARNING, "fetchPoolEntry",
localpool::POOL_ENTRY_NOT_FOUND);
return localpool::POOL_ENTRY_NOT_FOUND;
}
*poolEntry = dynamic_cast< PoolEntry<T>* >(poolIter->second);
if(*poolEntry == nullptr) {
printWarningOrError(sif::OutputTypes::OUT_WARNING, "fetchPoolEntry",
localpool::POOL_ENTRY_TYPE_CONFLICT);
return localpool::POOL_ENTRY_TYPE_CONFLICT;
}
return HasReturnvaluesIF::RETURN_OK;
}
#endif /* FSFW_DATAPOOLLOCAL_LOCALDATAPOOLMANAGER_H_ */

View File

@ -0,0 +1,22 @@
#include "LocalDataSet.h"
#include "../datapoollocal/LocalDataPoolManager.h"
#include "../serialize/SerializeAdapter.h"
#include <cmath>
#include <cstring>
LocalDataSet::LocalDataSet(HasLocalDataPoolIF *hkOwner, uint32_t setId,
const size_t maxNumberOfVariables):
LocalPoolDataSetBase(hkOwner, setId, nullptr, maxNumberOfVariables),
poolVarList(maxNumberOfVariables) {
this->setContainer(poolVarList.data());
}
LocalDataSet::LocalDataSet(sid_t sid, const size_t maxNumberOfVariables):
LocalPoolDataSetBase(sid, nullptr, maxNumberOfVariables),
poolVarList(maxNumberOfVariables) {
this->setContainer(poolVarList.data());
}
LocalDataSet::~LocalDataSet() {}

View File

@ -0,0 +1,36 @@
#ifndef FSFW_DATAPOOLLOCAL_LOCALDATASET_H_
#define FSFW_DATAPOOLLOCAL_LOCALDATASET_H_
#include "LocalPoolDataSetBase.h"
#include <vector>
/**
* @brief This dataset type can be used to group related pool variables if the number of
* variables should not be fixed.
* @details
* This will is the primary data structure to organize pool variables into
* sets which can be accessed via the housekeeping service interface or
* which can be sent to other software objects.
*
* It is recommended to read the documentation of the LocalPoolDataSetBase
* class for more information on how this class works and how to use it.
* @tparam capacity Capacity of the static dataset, which is usually known
* beforehand.
*/
class LocalDataSet: public LocalPoolDataSetBase {
public:
LocalDataSet(HasLocalDataPoolIF* hkOwner, uint32_t setId,
const size_t maxSize);
LocalDataSet(sid_t sid, const size_t maxSize);
virtual~ LocalDataSet();
//! Copying forbidden for now.
LocalDataSet(const LocalDataSet&) = delete;
LocalDataSet& operator=(const LocalDataSet&) = delete;
private:
std::vector<PoolVariableIF*> poolVarList;
};
#endif /* FSFW_DATAPOOLLOCAL_LOCALDATASET_H_ */

View File

@ -0,0 +1,323 @@
#include "LocalPoolDataSetBase.h"
#include "HasLocalDataPoolIF.h"
#include "internal/HasLocalDpIFUserAttorney.h"
#include "../serviceinterface/ServiceInterface.h"
#include "../globalfunctions/bitutility.h"
#include "../datapoollocal/LocalDataPoolManager.h"
#include "../housekeeping/PeriodicHousekeepingHelper.h"
#include "../serialize/SerializeAdapter.h"
#include <cmath>
#include <cstring>
LocalPoolDataSetBase::LocalPoolDataSetBase(HasLocalDataPoolIF *hkOwner,
uint32_t setId, PoolVariableIF** registeredVariablesArray,
const size_t maxNumberOfVariables, bool periodicHandling):
PoolDataSetBase(registeredVariablesArray, maxNumberOfVariables) {
if(hkOwner == nullptr) {
// Configuration error.
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "LocalPoolDataSetBase::LocalPoolDataSetBase: Owner "
<< "invalid!" << std::endl;
#else
sif::printError("LocalPoolDataSetBase::LocalPoolDataSetBase: Owner "
"invalid!\n\r");
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
return;
}
AccessPoolManagerIF* accessor = HasLocalDpIFUserAttorney::getAccessorHandle(hkOwner);
if(accessor != nullptr) {
poolManager = accessor->getPoolManagerHandle();
mutexIfSingleDataCreator = accessor->getLocalPoolMutex();
}
this->sid.objectId = hkOwner->getObjectId();
this->sid.ownerSetId = setId;
/* Data creators get a periodic helper for periodic HK data generation. */
if(periodicHandling) {
periodicHelper = new PeriodicHousekeepingHelper(this);
}
}
LocalPoolDataSetBase::LocalPoolDataSetBase(sid_t sid, PoolVariableIF** registeredVariablesArray,
const size_t maxNumberOfVariables):
PoolDataSetBase(registeredVariablesArray, maxNumberOfVariables) {
HasLocalDataPoolIF* hkOwner = objectManager->get<HasLocalDataPoolIF>(
sid.objectId);
if(hkOwner != nullptr) {
AccessPoolManagerIF* accessor = HasLocalDpIFUserAttorney::getAccessorHandle(hkOwner);
if(accessor != nullptr) {
mutexIfSingleDataCreator = accessor->getLocalPoolMutex();
poolManager = accessor->getPoolManagerHandle();
}
}
this->sid = sid;
}
LocalPoolDataSetBase::LocalPoolDataSetBase(PoolVariableIF **registeredVariablesArray,
const size_t maxNumberOfVariables, bool protectEveryReadCommitCall):
PoolDataSetBase(registeredVariablesArray, maxNumberOfVariables) {
this->setReadCommitProtectionBehaviour(protectEveryReadCommitCall);
}
LocalPoolDataSetBase::~LocalPoolDataSetBase() {
/* We only delete objects which were created in the class constructor */
if(periodicHelper != nullptr) {
delete periodicHelper;
}
/* In case set was read but not comitted, we commit all variables with an invalid state */
if(state == States::STATE_SET_WAS_READ) {
for (uint16_t count = 0; count < fillCount; count++) {
if(registeredVariables[count] != nullptr) {
registeredVariables[count]->setValid(false);
registeredVariables[count]->commit(MutexIF::TimeoutType::WAITING, 20);
}
}
}
}
ReturnValue_t LocalPoolDataSetBase::lockDataPool(
MutexIF::TimeoutType timeoutType,
uint32_t timeoutMs) {
if(mutexIfSingleDataCreator != nullptr) {
return mutexIfSingleDataCreator->lockMutex(timeoutType, timeoutMs);
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t LocalPoolDataSetBase::serializeWithValidityBuffer(uint8_t **buffer,
size_t *size, size_t maxSize,
SerializeIF::Endianness streamEndianness) const {
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
const uint8_t validityMaskSize = std::ceil(static_cast<float>(fillCount)/8.0);
uint8_t* validityPtr = nullptr;
#ifdef _MSC_VER
/* Use a std::vector here because MSVC will (rightly) not create a fixed size array
with a non constant size specifier */
std::vector<uint8_t> validityMask(validityMaskSize);
validityPtr = validityMask.data();
#else
uint8_t validityMask[validityMaskSize] = {0};
validityPtr = validityMask;
#endif
uint8_t validBufferIndex = 0;
uint8_t validBufferIndexBit = 0;
for (uint16_t count = 0; count < fillCount; count++) {
if(registeredVariables[count]->isValid()) {
/* Set bit at correct position */
bitutil::bitSet(validityPtr + validBufferIndex, validBufferIndexBit);
}
if(validBufferIndexBit == 7) {
validBufferIndex ++;
validBufferIndexBit = 0;
}
else {
validBufferIndexBit ++;
}
result = registeredVariables[count]->serialize(buffer, size, maxSize,
streamEndianness);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
}
if(*size + validityMaskSize > maxSize) {
return SerializeIF::BUFFER_TOO_SHORT;
}
// copy validity buffer to end
std::memcpy(*buffer, validityPtr, validityMaskSize);
*size += validityMaskSize;
return result;
}
ReturnValue_t LocalPoolDataSetBase::deSerializeWithValidityBuffer(
const uint8_t **buffer, size_t *size,
SerializeIF::Endianness streamEndianness) {
ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED;
for (uint16_t count = 0; count < fillCount; count++) {
result = registeredVariables[count]->deSerialize(buffer, size,
streamEndianness);
if(result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
}
if(*size < std::ceil(static_cast<float>(fillCount) / 8.0)) {
return SerializeIF::STREAM_TOO_SHORT;
}
uint8_t validBufferIndex = 0;
uint8_t validBufferIndexBit = 0;
for (uint16_t count = 0; count < fillCount; count++) {
// set validity buffer here.
bool nextVarValid = bitutil::bitGet(*buffer +
validBufferIndex, validBufferIndexBit);
registeredVariables[count]->setValid(nextVarValid);
if(validBufferIndexBit == 7) {
validBufferIndex ++;
validBufferIndexBit = 0;
}
else {
validBufferIndexBit ++;
}
}
return result;
}
ReturnValue_t LocalPoolDataSetBase::unlockDataPool() {
if(mutexIfSingleDataCreator != nullptr) {
return mutexIfSingleDataCreator->unlockMutex();
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t LocalPoolDataSetBase::serializeLocalPoolIds(uint8_t** buffer,
size_t* size, size_t maxSize,SerializeIF::Endianness streamEndianness,
bool serializeFillCount) const {
/* Serialize fill count as uint8_t */
uint8_t fillCount = this->fillCount;
if(serializeFillCount) {
SerializeAdapter::serialize(&fillCount, buffer, size, maxSize,
streamEndianness);
}
for (uint16_t count = 0; count < fillCount; count++) {
lp_id_t currentPoolId = registeredVariables[count]->getDataPoolId();
auto result = SerializeAdapter::serialize(&currentPoolId, buffer,
size, maxSize, streamEndianness);
if(result != HasReturnvaluesIF::RETURN_OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "LocalPoolDataSetBase::serializeLocalPoolIds: "
<< "Serialization error!" << std::endl;
#else
sif::printWarning("LocalPoolDataSetBase::serializeLocalPoolIds: "
"Serialization error!\n\r");
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
return result;
}
}
return HasReturnvaluesIF::RETURN_OK;
}
uint8_t LocalPoolDataSetBase::getLocalPoolIdsSerializedSize(
bool serializeFillCount) const {
if(serializeFillCount) {
return fillCount * sizeof(lp_id_t) + sizeof(uint8_t);
}
else {
return fillCount * sizeof(lp_id_t);
}
}
size_t LocalPoolDataSetBase::getSerializedSize() const {
if(withValidityBuffer) {
uint8_t validityMaskSize = std::ceil(static_cast<float>(fillCount)/8.0);
return validityMaskSize + PoolDataSetBase::getSerializedSize();
}
else {
return PoolDataSetBase::getSerializedSize();
}
}
void LocalPoolDataSetBase::setValidityBufferGeneration(
bool withValidityBuffer) {
this->withValidityBuffer = withValidityBuffer;
}
ReturnValue_t LocalPoolDataSetBase::deSerialize(const uint8_t **buffer,
size_t *size, SerializeIF::Endianness streamEndianness) {
if(withValidityBuffer) {
return this->deSerializeWithValidityBuffer(buffer, size,
streamEndianness);
}
else {
return PoolDataSetBase::deSerialize(buffer, size, streamEndianness);
}
}
ReturnValue_t LocalPoolDataSetBase::serialize(uint8_t **buffer, size_t *size,
size_t maxSize, SerializeIF::Endianness streamEndianness) const {
if(withValidityBuffer) {
return this->serializeWithValidityBuffer(buffer, size,
maxSize, streamEndianness);
}
else {
return PoolDataSetBase::serialize(buffer, size, maxSize,
streamEndianness);
}
}
void LocalPoolDataSetBase::setDiagnostic(bool isDiagnostics) {
this->diagnostic = isDiagnostics;
}
bool LocalPoolDataSetBase::isDiagnostics() const {
return diagnostic;
}
void LocalPoolDataSetBase::setReportingEnabled(bool reportingEnabled) {
this->reportingEnabled = reportingEnabled;
}
bool LocalPoolDataSetBase::getReportingEnabled() const {
return reportingEnabled;
}
void LocalPoolDataSetBase::initializePeriodicHelper(float collectionInterval,
dur_millis_t minimumPeriodicInterval, uint8_t nonDiagIntervalFactor) {
periodicHelper->initialize(collectionInterval, minimumPeriodicInterval, nonDiagIntervalFactor);
}
void LocalPoolDataSetBase::setChanged(bool changed) {
this->changed = changed;
}
bool LocalPoolDataSetBase::hasChanged() const {
return changed;
}
sid_t LocalPoolDataSetBase::getSid() const {
return sid;
}
bool LocalPoolDataSetBase::isValid() const {
return this->valid;
}
void LocalPoolDataSetBase::setValidity(bool valid, bool setEntriesRecursively) {
if(setEntriesRecursively) {
for(size_t idx = 0; idx < this->getFillCount(); idx++) {
registeredVariables[idx]->setValid(valid);
}
}
this->valid = valid;
}
object_id_t LocalPoolDataSetBase::getCreatorObjectId() {
if(poolManager != nullptr) {
return poolManager->getCreatorObjectId();
}
return objects::NO_OBJECT;
}
void LocalPoolDataSetBase::setAllVariablesReadOnly() {
for(size_t idx = 0; idx < this->getFillCount(); idx++) {
registeredVariables[idx]->setReadWriteMode(pool_rwm_t::VAR_READ);
}
}
float LocalPoolDataSetBase::getCollectionInterval() const {
if(periodicHelper != nullptr) {
return periodicHelper->getCollectionIntervalInSeconds();
}
else {
return 0.0;
}
}

View File

@ -0,0 +1,241 @@
#ifndef FSFW_DATAPOOLLOCAL_LOCALPOOLDATASETBASE_H_
#define FSFW_DATAPOOLLOCAL_LOCALPOOLDATASETBASE_H_
#include "MarkChangedIF.h"
#include "localPoolDefinitions.h"
#include "../datapool/DataSetIF.h"
#include "../datapool/PoolDataSetBase.h"
#include <vector>
class LocalDataPoolManager;
class HasLocalDataPoolIF;
class PeriodicHousekeepingHelper;
/**
* @brief The LocalDataSet class manages a set of locally checked out
* variables for local data pools
* @details
* Extends the PoolDataSetBase class for local data pools by introducing
* a validity state, a flag to mark the set as changed, and various other
* functions to make it usable by the LocalDataPoolManager class.
*
* 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 local data
* pools, to ensure thread-safety.
*
* Pool variables can be added to the dataset by using the constructor
* argument of the pool variable or using the #registerVariable member function.
*
* An internal state manages usage of this class. Variables may only be
* registered before any read call is made, and the commit call can only happen
* 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 LocalPoolDataSetBase:
public PoolDataSetBase,
public MarkChangedIF {
friend class LocalPoolDataSetAttorney;
friend class PeriodicHousekeepingHelper;
public:
/**
* @brief Constructor for the creator of local pool data.
* @details
* This constructor also initializes the components required for
* periodic handling.
*/
LocalPoolDataSetBase(HasLocalDataPoolIF *hkOwner,
uint32_t setId, PoolVariableIF** registeredVariablesArray,
const size_t maxNumberOfVariables, bool periodicHandling = true);
/**
* @brief Constructor for users of the local pool data, which need
* to access data created by one HK manager.
* @details
* Unlike the first constructor, no component for periodic handling
* will be initiated.
* @param sid Unique identifier of dataset consisting of object ID and
* set ID.
* @param registeredVariablesArray
* @param maxNumberOfVariables
*/
LocalPoolDataSetBase(sid_t sid, PoolVariableIF** registeredVariablesArray,
const size_t maxNumberOfVariables);
/**
* @brief Simple constructor, if the dataset is not the owner by
* a class with a HK manager.
* @details
* This constructor won't create components required for periodic handling
* and it also won't try to deduce the HK manager because no SID is
* supplied. This function should therefore be called by classes which need
* to access pool variables from different creators.
*
* If the class is intended to access pool variables from different
* creators, the third argument should be set to true. The mutex
* properties can be set with #setReadCommitProtectionBehaviour .
* @param registeredVariablesArray
* @param maxNumberOfVariables
* @param protectEveryReadCommitCall If the pool variables are created by
* multiple creators, this flag can be set to protect all read and
* commit calls separately.
*/
LocalPoolDataSetBase(PoolVariableIF** registeredVariablesArray,
const size_t maxNumberOfVariables,
bool protectEveryReadCommitCall = true);
/**
* @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".
*/
~LocalPoolDataSetBase();
/* The copy constructor and assingment constructor are forbidden for now.
The use-cases are limited and the first step would be to implement them properly for the
base class */
LocalPoolDataSetBase(const LocalPoolDataSetBase& otherSet) = delete;
const LocalPoolDataSetBase& operator=(const LocalPoolDataSetBase& otherSet) = delete;
/**
* Helper functions used to set all currently contained variables to read-only.
* It is recommended to call this in set constructors intended to be used
* by data consumers to prevent accidentally changing pool data.
*/
void setAllVariablesReadOnly();
void setValidityBufferGeneration(bool withValidityBuffer);
sid_t getSid() const;
/** SerializeIF overrides */
ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
SerializeIF::Endianness streamEndianness) const override;
ReturnValue_t deSerialize(const uint8_t** buffer, size_t *size,
SerializeIF::Endianness streamEndianness) override;
size_t getSerializedSize() const override;
/**
* Special version of the serilization function which appends a
* validity buffer at the end. Each bit of this validity buffer
* denotes whether the container data set entries are valid from left
* to right, MSB first. (length = ceil(N/8), N = number of pool variables)
* @param buffer
* @param size
* @param maxSize
* @param bigEndian
* @param withValidityBuffer
* @return
*/
ReturnValue_t serializeWithValidityBuffer(uint8_t** buffer,
size_t* size, size_t maxSize,
SerializeIF::Endianness streamEndianness) const;
ReturnValue_t deSerializeWithValidityBuffer(const uint8_t** buffer,
size_t *size, SerializeIF::Endianness streamEndianness);
ReturnValue_t serializeLocalPoolIds(uint8_t** buffer,
size_t* size, size_t maxSize,
SerializeIF::Endianness streamEndianness,
bool serializeFillCount = true) const;
uint8_t getLocalPoolIdsSerializedSize(bool serializeFillCount = true) const;
/**
* Set the dataset valid or invalid. These calls are mutex protected.
* @param setEntriesRecursively
* If this is true, all contained datasets will also be set recursively.
*/
void setValidity(bool valid, bool setEntriesRecursively);
bool isValid() const override;
/**
* These calls are mutex protected.
* @param changed
*/
void setChanged(bool changed) override;
bool hasChanged() const override;
object_id_t getCreatorObjectId();
bool getReportingEnabled() const;
/**
* Returns the current periodic HK generation interval this set
* belongs to a HK manager and the interval is not 0. Otherwise,
* returns 0.0
* @return
*/
float getCollectionInterval() const;
protected:
sid_t sid;
//! This mutex is used if the data is created by one object only.
MutexIF* mutexIfSingleDataCreator = nullptr;
bool diagnostic = false;
void setDiagnostic(bool diagnostics);
bool isDiagnostics() const;
/**
* Used for periodic generation.
*/
bool reportingEnabled = false;
void setReportingEnabled(bool enabled);
void initializePeriodicHelper(float collectionInterval, dur_millis_t minimumPeriodicInterval,
uint8_t nonDiagIntervalFactor = 5);
/**
* If the valid state of a dataset is always relevant to the whole
* data set we can use this flag.
*/
bool valid = false;
/**
* Can be used to mark the dataset as changed, which is used
* by the LocalDataPoolManager to send out update messages.
*/
bool changed = false;
/**
* Specify whether the validity buffer is serialized too when serializing
* or deserializing the packet. Each bit of the validity buffer will
* contain the validity state of the pool variables from left to right.
* The size of validity buffer thus will be ceil(N / 8) with N = number of
* pool variables.
*/
bool withValidityBuffer = true;
/**
* @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.
*/
ReturnValue_t lockDataPool(MutexIF::TimeoutType timeoutType,
uint32_t timeoutMs) override;
/**
* @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.
*/
ReturnValue_t unlockDataPool() override;
PeriodicHousekeepingHelper* periodicHelper = nullptr;
LocalDataPoolManager* poolManager = nullptr;
};
#endif /* FSFW_DATAPOOLLOCAL_LOCALPOOLDATASETBASE_H_ */

View File

@ -0,0 +1,141 @@
#include "LocalPoolObjectBase.h"
#include "LocalDataPoolManager.h"
#include "AccessLocalPoolF.h"
#include "HasLocalDataPoolIF.h"
#include "internal/HasLocalDpIFUserAttorney.h"
#include "../objectmanager/ObjectManagerIF.h"
LocalPoolObjectBase::LocalPoolObjectBase(lp_id_t poolId, HasLocalDataPoolIF* hkOwner,
DataSetIF* dataSet, pool_rwm_t setReadWriteMode):
localPoolId(poolId), readWriteMode(setReadWriteMode) {
if(poolId == PoolVariableIF::NO_PARAMETER) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "LocalPoolVar<T>::LocalPoolVar: 0 passed as pool ID, "
<< "which is the NO_PARAMETER value!" << std::endl;
#endif
}
if(hkOwner == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "LocalPoolVar<T>::LocalPoolVar: The supplied pool "
<< "owner is a invalid!" << std::endl;
#endif
return;
}
AccessPoolManagerIF* poolManAccessor = HasLocalDpIFUserAttorney::getAccessorHandle(hkOwner);
hkManager = poolManAccessor->getPoolManagerHandle();
if (dataSet != nullptr) {
dataSet->registerVariable(this);
}
}
LocalPoolObjectBase::LocalPoolObjectBase(object_id_t poolOwner, lp_id_t poolId, DataSetIF *dataSet,
pool_rwm_t setReadWriteMode):
localPoolId(poolId), readWriteMode(setReadWriteMode) {
if(poolId == PoolVariableIF::NO_PARAMETER) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "LocalPoolVar<T>::LocalPoolVar: 0 passed as pool ID, "
"which is the NO_PARAMETER value!" << std::endl;
#else
sif::printWarning("LocalPoolVar<T>::LocalPoolVar: 0 passed as pool ID, "
"which is the NO_PARAMETER value!\n");
#endif
}
HasLocalDataPoolIF* hkOwner = objectManager->get<HasLocalDataPoolIF>(poolOwner);
if(hkOwner == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "LocalPoolVariable: The supplied pool owner did not implement the correct "
"interface HasLocalDataPoolIF!" << std::endl;
#else
sif::printError( "LocalPoolVariable: The supplied pool owner did not implement the correct "
"interface HasLocalDataPoolIF!\n");
#endif
return;
}
AccessPoolManagerIF* accessor = HasLocalDpIFUserAttorney::getAccessorHandle(hkOwner);
if(accessor != nullptr) {
hkManager = accessor->getPoolManagerHandle();
}
if(dataSet != nullptr) {
dataSet->registerVariable(this);
}
}
pool_rwm_t LocalPoolObjectBase::getReadWriteMode() const {
return readWriteMode;
}
bool LocalPoolObjectBase::isValid() const {
return valid;
}
void LocalPoolObjectBase::setValid(bool valid) {
this->valid = valid;
}
lp_id_t LocalPoolObjectBase::getDataPoolId() const {
return localPoolId;
}
void LocalPoolObjectBase::setDataPoolId(lp_id_t poolId) {
this->localPoolId = poolId;
}
void LocalPoolObjectBase::setChanged(bool changed) {
this->changed = changed;
}
bool LocalPoolObjectBase::hasChanged() const {
return changed;
}
void LocalPoolObjectBase::setReadWriteMode(pool_rwm_t newReadWriteMode) {
this->readWriteMode = newReadWriteMode;
}
void LocalPoolObjectBase::reportReadCommitError(const char* variableType,
ReturnValue_t error, bool read, object_id_t objectId, lp_id_t lpId) {
#if FSFW_DISABLE_PRINTOUT == 0
const char* variablePrintout = variableType;
if(variablePrintout == nullptr) {
variablePrintout = "Unknown Type";
}
const char* type = nullptr;
if(read) {
type = "read";
}
else {
type = "commit";
}
const char* errMsg = nullptr;
if(error == localpool::POOL_ENTRY_NOT_FOUND) {
errMsg = "Pool entry not found";
}
else if(error == localpool::POOL_ENTRY_TYPE_CONFLICT) {
errMsg = "Pool entry type conflict";
}
else if(error == PoolVariableIF::INVALID_READ_WRITE_MODE) {
errMsg = "Pool variable wrong read-write mode";
}
else if(error == PoolVariableIF::INVALID_POOL_ENTRY) {
errMsg = "Pool entry invalid";
}
else {
errMsg = "Unknown error code";
}
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << variablePrintout << ": " << type << " call | " << errMsg << " | Owner: 0x"
<< std::hex << std::setw(8) << std::setfill('0') << objectId << std::dec
<< " LPID: " << lpId << std::endl;
#else
sif::printWarning("%s: %s call | %s | Owner: 0x%08x LPID: %lu\n",
variablePrintout, type, errMsg, objectId, lpId);
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
#endif /* FSFW_DISABLE_PRINTOUT == 0 */
}

View File

@ -0,0 +1,71 @@
#ifndef FSFW_DATAPOOLLOCAL_LOCALPOOLOBJECTBASE_H_
#define FSFW_DATAPOOLLOCAL_LOCALPOOLOBJECTBASE_H_
#include "MarkChangedIF.h"
#include "localPoolDefinitions.h"
#include "../objectmanager/SystemObjectIF.h"
#include "../datapool/PoolVariableIF.h"
#include "../returnvalues/HasReturnvaluesIF.h"
class LocalDataPoolManager;
class DataSetIF;
class HasLocalDataPoolIF;
/**
* @brief This class serves as a non-template base for pool objects like pool variables
* or pool vectors.
*/
class LocalPoolObjectBase: public PoolVariableIF,
public HasReturnvaluesIF,
public MarkChangedIF {
public:
LocalPoolObjectBase(lp_id_t poolId, HasLocalDataPoolIF* hkOwner, DataSetIF* dataSet,
pool_rwm_t setReadWriteMode);
LocalPoolObjectBase(object_id_t poolOwner, lp_id_t poolId, DataSetIF* dataSet = nullptr,
pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE);
void setReadWriteMode(pool_rwm_t newReadWriteMode);
pool_rwm_t getReadWriteMode() const;
bool isValid() const override;
void setValid(bool valid) override;
void setChanged(bool changed) override;
bool hasChanged() const override;
lp_id_t getDataPoolId() const override;
void setDataPoolId(lp_id_t poolId);
protected:
/**
* @brief To access the correct data pool entry on read and commit calls,
* the data pool id is stored.
*/
uint32_t localPoolId = PoolVariableIF::NO_PARAMETER;
/**
* @brief The valid information as it was stored in the data pool
* is copied to this attribute.
*/
bool valid = false;
/**
* @brief A local pool variable can be marked as changed.
*/
bool changed = false;
/**
* @brief The information whether the class is read-write or
* read-only is stored here.
*/
ReadWriteMode_t readWriteMode = pool_rwm_t::VAR_READ_WRITE;
//! @brief Pointer to the class which manages the HK pool.
LocalDataPoolManager* hkManager = nullptr;
void reportReadCommitError(const char* variableType,
ReturnValue_t error, bool read, object_id_t objectId, lp_id_t lpId);
};
#endif /* FSFW_DATAPOOLLOCAL_LOCALPOOLOBJECTBASE_H_ */

View File

@ -0,0 +1,203 @@
#ifndef FSFW_DATAPOOLLOCAL_LOCALPOOLVARIABLE_H_
#define FSFW_DATAPOOLLOCAL_LOCALPOOLVARIABLE_H_
#include "LocalPoolObjectBase.h"
#include "HasLocalDataPoolIF.h"
#include "LocalDataPoolManager.h"
#include "AccessLocalPoolF.h"
#include "internal/LocalDpManagerAttorney.h"
#include "../datapool/PoolVariableIF.h"
#include "../datapool/DataSetIF.h"
#include "../serviceinterface/ServiceInterface.h"
#include "../objectmanager/ObjectManagerIF.h"
#include "../serialize/SerializeAdapter.h"
/**
* @brief Local Pool Variable class which is used to access the local pools.
* @details
* This class is not stored in the map. Instead, it is used to access
* the pool entries by using a pointer to the map storing the pool
* entries. It can also be used to organize these pool entries into data sets.
*
* @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 LocalPoolVariable: public LocalPoolObjectBase {
public:
//! Default ctor is forbidden.
LocalPoolVariable() = delete;
/**
* This constructor is used by the data creators to have pool variable
* instances which can also be stored in datasets.
*
* It does not fetch the current value from the data pool, which
* has to be done by calling the read() operation.
* Datasets can be used to access multiple local pool entries in an
* efficient way. A pointer to a dataset can be passed to register
* the pool variable in that dataset directly.
* @param poolId ID of the local pool entry.
* @param hkOwner Pointer of the owner. This will generally be the calling
* class itself which passes "this".
* @param dataSet The data set in which the variable shall register itself.
* If nullptr, the variable is not registered.
* @param setReadWriteMode Specify the read-write mode of the pool variable.
*/
LocalPoolVariable(HasLocalDataPoolIF* hkOwner, lp_id_t poolId,
DataSetIF* dataSet = nullptr,
pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE);
/**
* This constructor is used by data users like controllers to have
* access to the local pool variables of data creators by supplying
* the respective creator object ID.
*
* It does not fetch the current value from the data pool, which
* has to be done by calling the read() operation.
* Datasets can be used to access multiple local pool entries in an
* efficient way. A pointer to a dataset can be passed to register
* the pool variable in that dataset directly.
* @param poolId ID of the local pool entry.
* @param hkOwner object ID of the pool owner.
* @param dataSet The data set in which the variable shall register itself.
* If nullptr, the variable is not registered.
* @param setReadWriteMode Specify the read-write mode of the pool variable.
*
*/
LocalPoolVariable(object_id_t poolOwner, lp_id_t poolId,
DataSetIF* dataSet = nullptr,
pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE);
/**
* Variation which takes the global unique identifier of a pool variable.
* @param globalPoolId
* @param dataSet
* @param setReadWriteMode
*/
LocalPoolVariable(gp_id_t globalPoolId, DataSetIF* dataSet = nullptr,
pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE);
virtual~ LocalPoolVariable() {};
/**
* @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 = 0;
ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
SerializeIF::Endianness streamEndianness) const override;
virtual size_t getSerializedSize() const override;
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
SerializeIF::Endianness streamEndianness) override;
/**
* @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 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 read call is protected with a lock.
* It is recommended to use DataSets to read and commit multiple variables
* at once to avoid the overhead of unnecessary lock und unlock operations.
*
*/
ReturnValue_t read(MutexIF::TimeoutType timeoutType =
MutexIF::TimeoutType::WAITING,
uint32_t timeoutMs = 20) override;
/**
* @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 local valid flag is written back as well.
* The read call is protected with a lock.
* It is recommended to use DataSets to read and commit multiple variables
* at once to avoid the overhead of unnecessary lock und unlock operations.
*/
ReturnValue_t commit(MutexIF::TimeoutType timeoutType =
MutexIF::TimeoutType::WAITING,
uint32_t timeoutMs = 20) override;
/**
* @brief This commit function can be used to set the pool variable valid
* as well.
* @param setValid
* @param timeoutType
* @param timeoutMs
* @return
*/
ReturnValue_t commit(bool setValid, MutexIF::TimeoutType timeoutType =
MutexIF::TimeoutType::WAITING,
uint32_t timeoutMs = 20);
LocalPoolVariable<T> &operator=(const T& newValue);
LocalPoolVariable<T> &operator=(const LocalPoolVariable<T>& newPoolVariable);
//! Explicit type conversion operator. Allows casting the class to
//! its template type to perform operations on value.
explicit operator T() const;
bool operator==(const LocalPoolVariable<T>& other) const;
bool operator==(const T& other) const;
bool operator!=(const LocalPoolVariable<T>& other) const;
bool operator!=(const T& other) const;
bool operator<(const LocalPoolVariable<T>& other) const;
bool operator<(const T& other) const;
bool operator>(const LocalPoolVariable<T>& other) const;
bool operator>(const T& other) const;
protected:
/**
* @brief Like #read, but without a lock protection of the global pool.
* @details
* The operation does NOT provide any mutual exclusive protection by itself.
* This can be used if the lock is handled externally to avoid the overhead
* of consecutive lock und unlock operations.
* Declared protected to discourage free public usage.
*/
ReturnValue_t readWithoutLock() override;
/**
* @brief Like #commit, but without a lock protection of the global pool.
* @details
* The operation does NOT provide any mutual exclusive protection by itself.
* This can be used if the lock is handled externally to avoid the overhead
* of consecutive lock und unlock operations.
* Declared protected to discourage free public usage.
*/
ReturnValue_t commitWithoutLock() override;
#if FSFW_CPP_OSTREAM_ENABLED == 1
// std::ostream is the type for object std::cout
template <typename U>
friend std::ostream& operator<< (std::ostream &out,
const LocalPoolVariable<U> &var);
#endif
};
#include "LocalPoolVariable.tpp"
template<class T>
using lp_var_t = LocalPoolVariable<T>;
using lp_bool_t = LocalPoolVariable<uint8_t>;
using lp_uint8_t = LocalPoolVariable<uint8_t>;
using lp_uint16_t = LocalPoolVariable<uint16_t>;
using lp_uint32_t = LocalPoolVariable<uint32_t>;
using lp_uint64_t = LocalPoolVariable<uint64_t>;
using lp_int8_t = LocalPoolVariable<int8_t>;
using lp_int16_t = LocalPoolVariable<int16_t>;
using lp_int32_t = LocalPoolVariable<int32_t>;
using lp_int64_t = LocalPoolVariable<int64_t>;
using lp_float_t = LocalPoolVariable<float>;
using lp_double_t = LocalPoolVariable<double>;
#endif /* FSFW_DATAPOOLLOCAL_LOCALPOOLVARIABLE_H_ */

View File

@ -0,0 +1,209 @@
#ifndef FSFW_DATAPOOLLOCAL_LOCALPOOLVARIABLE_TPP_
#define FSFW_DATAPOOLLOCAL_LOCALPOOLVARIABLE_TPP_
#ifndef FSFW_DATAPOOLLOCAL_LOCALPOOLVARIABLE_H_
#error Include LocalPoolVariable.h before LocalPoolVariable.tpp!
#endif
template<typename T>
inline LocalPoolVariable<T>::LocalPoolVariable(HasLocalDataPoolIF* hkOwner,
lp_id_t poolId, DataSetIF* dataSet, pool_rwm_t setReadWriteMode):
LocalPoolObjectBase(poolId, hkOwner, dataSet, setReadWriteMode) {}
template<typename T>
inline LocalPoolVariable<T>::LocalPoolVariable(object_id_t poolOwner,
lp_id_t poolId, DataSetIF *dataSet, pool_rwm_t setReadWriteMode):
LocalPoolObjectBase(poolOwner, poolId, dataSet, setReadWriteMode) {}
template<typename T>
inline LocalPoolVariable<T>::LocalPoolVariable(gp_id_t globalPoolId,
DataSetIF *dataSet, pool_rwm_t setReadWriteMode):
LocalPoolObjectBase(globalPoolId.objectId, globalPoolId.localPoolId,
dataSet, setReadWriteMode){}
template<typename T>
inline ReturnValue_t LocalPoolVariable<T>::read(
MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) {
if(hkManager == nullptr) {
return readWithoutLock();
}
MutexIF* mutex = LocalDpManagerAttorney::getMutexHandle(*hkManager);
ReturnValue_t result = mutex->lockMutex(timeoutType, timeoutMs);
if(result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
result = readWithoutLock();
mutex->unlockMutex();
return result;
}
template<typename T>
inline ReturnValue_t LocalPoolVariable<T>::readWithoutLock() {
if(readWriteMode == pool_rwm_t::VAR_WRITE) {
object_id_t targetObjectId = hkManager->getCreatorObjectId();
reportReadCommitError("LocalPoolVector",
PoolVariableIF::INVALID_READ_WRITE_MODE, true, targetObjectId,
localPoolId);
return PoolVariableIF::INVALID_READ_WRITE_MODE;
}
PoolEntry<T>* poolEntry = nullptr;
ReturnValue_t result = LocalDpManagerAttorney::fetchPoolEntry(*hkManager, localPoolId,
&poolEntry);
if(result != RETURN_OK) {
object_id_t ownerObjectId = hkManager->getCreatorObjectId();
reportReadCommitError("LocalPoolVariable", result,
false, ownerObjectId, localPoolId);
return result;
}
this->value = *(poolEntry->getDataPtr());
this->valid = poolEntry->getValid();
return RETURN_OK;
}
template<typename T>
inline ReturnValue_t LocalPoolVariable<T>::commit(bool setValid,
MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) {
this->setValid(setValid);
return commit(timeoutType, timeoutMs);
}
template<typename T>
inline ReturnValue_t LocalPoolVariable<T>::commit(
MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) {
if(hkManager == nullptr) {
return commitWithoutLock();
}
MutexIF* mutex = LocalDpManagerAttorney::getMutexHandle(*hkManager);
ReturnValue_t result = mutex->lockMutex(timeoutType, timeoutMs);
if(result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
result = commitWithoutLock();
mutex->unlockMutex();
return result;
}
template<typename T>
inline ReturnValue_t LocalPoolVariable<T>::commitWithoutLock() {
if(readWriteMode == pool_rwm_t::VAR_READ) {
object_id_t targetObjectId = hkManager->getCreatorObjectId();
reportReadCommitError("LocalPoolVector",
PoolVariableIF::INVALID_READ_WRITE_MODE, false, targetObjectId,
localPoolId);
return PoolVariableIF::INVALID_READ_WRITE_MODE;
}
PoolEntry<T>* poolEntry = nullptr;
ReturnValue_t result = LocalDpManagerAttorney::fetchPoolEntry(*hkManager, localPoolId,
&poolEntry);
if(result != RETURN_OK) {
object_id_t ownerObjectId = hkManager->getCreatorObjectId();
reportReadCommitError("LocalPoolVariable", result,
false, ownerObjectId, localPoolId);
return result;
}
*(poolEntry->getDataPtr()) = this->value;
poolEntry->setValid(this->valid);
return RETURN_OK;
}
template<typename T>
inline ReturnValue_t LocalPoolVariable<T>::serialize(uint8_t** buffer,
size_t* size, const size_t max_size,
SerializeIF::Endianness streamEndianness) const {
return SerializeAdapter::serialize(&value,
buffer, size ,max_size, streamEndianness);
}
template<typename T>
inline size_t LocalPoolVariable<T>::getSerializedSize() const {
return SerializeAdapter::getSerializedSize(&value);
}
template<typename T>
inline ReturnValue_t LocalPoolVariable<T>::deSerialize(const uint8_t** buffer,
size_t* size, SerializeIF::Endianness streamEndianness) {
return SerializeAdapter::deSerialize(&value, buffer, size, streamEndianness);
}
#if FSFW_CPP_OSTREAM_ENABLED == 1
template<typename T>
inline std::ostream& operator<< (std::ostream &out,
const LocalPoolVariable<T> &var) {
out << var.value;
return out;
}
#endif
template<typename T>
inline LocalPoolVariable<T>::operator T() const {
return value;
}
template<typename T>
inline LocalPoolVariable<T> & LocalPoolVariable<T>::operator=(
const T& newValue) {
value = newValue;
return *this;
}
template<typename T>
inline LocalPoolVariable<T>& LocalPoolVariable<T>::operator =(
const LocalPoolVariable<T>& newPoolVariable) {
value = newPoolVariable.value;
return *this;
}
template<typename T>
inline bool LocalPoolVariable<T>::operator ==(
const LocalPoolVariable<T> &other) const {
return this->value == other.value;
}
template<typename T>
inline bool LocalPoolVariable<T>::operator ==(const T &other) const {
return this->value == other;
}
template<typename T>
inline bool LocalPoolVariable<T>::operator !=(
const LocalPoolVariable<T> &other) const {
return not (*this == other);
}
template<typename T>
inline bool LocalPoolVariable<T>::operator !=(const T &other) const {
return not (*this == other);
}
template<typename T>
inline bool LocalPoolVariable<T>::operator <(
const LocalPoolVariable<T> &other) const {
return this->value < other.value;
}
template<typename T>
inline bool LocalPoolVariable<T>::operator <(const T &other) const {
return this->value < other;
}
template<typename T>
inline bool LocalPoolVariable<T>::operator >(
const LocalPoolVariable<T> &other) const {
return not (*this < other);
}
template<typename T>
inline bool LocalPoolVariable<T>::operator >(const T &other) const {
return not (*this < other);
}
#endif /* FSFW_DATAPOOLLOCAL_LOCALPOOLVARIABLE_TPP_ */

View File

@ -0,0 +1,188 @@
#ifndef FSFW_DATAPOOLLOCAL_LOCALPOOLVECTOR_H_
#define FSFW_DATAPOOLLOCAL_LOCALPOOLVECTOR_H_
#include "LocalPoolObjectBase.h"
#include "internal/LocalDpManagerAttorney.h"
#include "../datapool/DataSetIF.h"
#include "../datapool/PoolEntry.h"
#include "../datapool/PoolVariableIF.h"
#include "../datapoollocal/LocalDataPoolManager.h"
#include "../serialize/SerializeAdapter.h"
#include "../serviceinterface/ServiceInterface.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 vectorSize>
class LocalPoolVector: public LocalPoolObjectBase {
public:
LocalPoolVector() = delete;
/**
* This constructor is used by the data creators to have pool variable
* instances which can also be stored in datasets.
* It does not fetch the current value from the data pool. This is performed
* by the read() operation (which is not thread-safe).
* Datasets can be used to access local pool entires in a thread-safe way.
* @param poolId ID of the local pool entry.
* @param hkOwner Pointer of the owner. This will generally be the calling
* class itself which passes "this".
* @param setReadWriteMode Specify the read-write mode of the pool variable.
* @param dataSet The data set in which the variable shall register itself.
* If nullptr, the variable is not registered.
*/
LocalPoolVector(HasLocalDataPoolIF* hkOwner, lp_id_t poolId,
DataSetIF* dataSet = nullptr,
pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE);
/**
* This constructor is used by data users like controllers to have
* access to the local pool variables of data creators by supplying
* the respective creator object ID.
* It does not fetch the current value from the data pool. This is performed
* by the read() operation (which is not thread-safe).
* Datasets can be used to access local pool entires in a thread-safe way.
* @param poolId ID of the local pool entry.
* @param hkOwner Pointer of the owner. This will generally be the calling
* class itself which passes "this".
* @param setReadWriteMode Specify the read-write mode of the pool variable.
* @param dataSet The data set in which the variable shall register itself.
* If nullptr, the variable is not registered.
*/
LocalPoolVector(object_id_t poolOwner, lp_id_t poolId,
DataSetIF* dataSet = nullptr,
pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE);
/**
* Variation which takes the unique global identifier of a local pool
* vector.
* @param globalPoolId
* @param dataSet
* @param setReadWriteMode
*/
LocalPoolVector(gp_id_t globalPoolId, DataSetIF* dataSet = nullptr,
pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE);
/**
* @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 local
* array of this type.
*/
T value[vectorSize]= {};
/**
* @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.
*/
~LocalPoolVector() {};
/**
* @brief The operation returns the number of array entries
* in this variable.
*/
uint8_t getSize() {
return vectorSize;
}
T& operator [](size_t i);
const T &operator [](size_t i) const;
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size,
const size_t maxSize,
SerializeIF::Endianness streamEndiannes) const override;
virtual size_t getSerializedSize() const override;
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
SerializeIF::Endianness streamEndianness) override;
/**
* @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 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 read call is protected with a lock.
* It is recommended to use DataSets to read and commit multiple variables
* at once to avoid the overhead of unnecessary lock und unlock operations.
*/
ReturnValue_t read(MutexIF::TimeoutType timeoutType =
MutexIF::TimeoutType::WAITING,
uint32_t timeoutMs = 20) override;
/**
* @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 local valid flag is written back as well.
* The read call is protected with a lock.
* It is recommended to use DataSets to read and commit multiple variables
* at once to avoid the overhead of unnecessary lock und unlock operations.
*/
ReturnValue_t commit(MutexIF::TimeoutType timeoutType =
MutexIF::TimeoutType::WAITING,
uint32_t timeoutMs = 20) override;
/**
* @brief This commit call also sets the validity of the pool entry.
* @details
*/
ReturnValue_t commit(bool valid, MutexIF::TimeoutType timeoutType =
MutexIF::TimeoutType::WAITING,
uint32_t timeoutMs = 20);
protected:
/**
* @brief Like #read, but without a lock protection of the global pool.
* @details
* The operation does NOT provide any mutual exclusive protection by itself.
* This can be used if the lock is handled externally to avoid the overhead
* of consecutive lock und unlock operations.
* Declared protected to discourage free public usage.
*/
ReturnValue_t readWithoutLock() override;
/**
* @brief Like #commit, but without a lock protection of the global pool.
* @details
* The operation does NOT provide any mutual exclusive protection by itself.
* This can be used if the lock is handled externally to avoid the overhead
* of consecutive lock und unlock operations.
* Declared protected to discourage free public usage.
*/
ReturnValue_t commitWithoutLock() override;
private:
#if FSFW_CPP_OSTREAM_ENABLED == 1
// std::ostream is the type for object std::cout
template <typename U, uint16_t otherSize>
friend std::ostream& operator<< (std::ostream &out,
const LocalPoolVector<U, otherSize> &var);
#endif
};
#include "LocalPoolVector.tpp"
template<typename T, uint16_t vectorSize>
using lp_vec_t = LocalPoolVector<T, vectorSize>;
#endif /* FSFW_DATAPOOLLOCAL_LOCALPOOLVECTOR_H_ */

View File

@ -0,0 +1,179 @@
#ifndef FSFW_DATAPOOLLOCAL_LOCALPOOLVECTOR_TPP_
#define FSFW_DATAPOOLLOCAL_LOCALPOOLVECTOR_TPP_
#ifndef FSFW_DATAPOOLLOCAL_LOCALPOOLVECTOR_H_
#error Include LocalPoolVector.h before LocalPoolVector.tpp!
#endif
template<typename T, uint16_t vectorSize>
inline LocalPoolVector<T, vectorSize>::LocalPoolVector(
HasLocalDataPoolIF* hkOwner, lp_id_t poolId, DataSetIF* dataSet,
pool_rwm_t setReadWriteMode):
LocalPoolObjectBase(poolId, hkOwner, dataSet, setReadWriteMode) {}
template<typename T, uint16_t vectorSize>
inline LocalPoolVector<T, vectorSize>::LocalPoolVector(object_id_t poolOwner,
lp_id_t poolId, DataSetIF *dataSet, pool_rwm_t setReadWriteMode):
LocalPoolObjectBase(poolOwner, poolId, dataSet, setReadWriteMode) {}
template<typename T, uint16_t vectorSize>
inline LocalPoolVector<T, vectorSize>::LocalPoolVector(gp_id_t globalPoolId,
DataSetIF *dataSet, pool_rwm_t setReadWriteMode):
LocalPoolObjectBase(globalPoolId.objectId, globalPoolId.localPoolId,
dataSet, setReadWriteMode) {}
template<typename T, uint16_t vectorSize>
inline ReturnValue_t LocalPoolVector<T, vectorSize>::read(
MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) {
MutexGuard(LocalDpManagerAttorney::getMutexHandle(*hkManager), timeoutType, timeoutMs);
return readWithoutLock();
}
template<typename T, uint16_t vectorSize>
inline ReturnValue_t LocalPoolVector<T, vectorSize>::readWithoutLock() {
if(readWriteMode == pool_rwm_t::VAR_WRITE) {
object_id_t targetObjectId = hkManager->getCreatorObjectId();
reportReadCommitError("LocalPoolVector",
PoolVariableIF::INVALID_READ_WRITE_MODE, true, targetObjectId,
localPoolId);
return PoolVariableIF::INVALID_READ_WRITE_MODE;
}
PoolEntry<T>* poolEntry = nullptr;
ReturnValue_t result = LocalDpManagerAttorney::fetchPoolEntry(*hkManager, localPoolId,
&poolEntry);
memset(this->value, 0, vectorSize * sizeof(T));
if(result != RETURN_OK) {
object_id_t targetObjectId = hkManager->getCreatorObjectId();
reportReadCommitError("LocalPoolVector", result, true, targetObjectId,
localPoolId);
return result;
}
std::memcpy(this->value, poolEntry->getDataPtr(), poolEntry->getByteSize());
this->valid = poolEntry->getValid();
return RETURN_OK;
}
template<typename T, uint16_t vectorSize>
inline ReturnValue_t LocalPoolVector<T, vectorSize>::commit(bool valid,
MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) {
this->setValid(valid);
return commit(timeoutType, timeoutMs);
}
template<typename T, uint16_t vectorSize>
inline ReturnValue_t LocalPoolVector<T, vectorSize>::commit(
MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) {
MutexGuard(LocalDpManagerAttorney::getMutexHandle(*hkManager), timeoutType, timeoutMs);
return commitWithoutLock();
}
template<typename T, uint16_t vectorSize>
inline ReturnValue_t LocalPoolVector<T, vectorSize>::commitWithoutLock() {
if(readWriteMode == pool_rwm_t::VAR_READ) {
object_id_t targetObjectId = hkManager->getCreatorObjectId();
reportReadCommitError("LocalPoolVector",
PoolVariableIF::INVALID_READ_WRITE_MODE, false, targetObjectId,
localPoolId);
return PoolVariableIF::INVALID_READ_WRITE_MODE;
}
PoolEntry<T>* poolEntry = nullptr;
ReturnValue_t result = LocalDpManagerAttorney::fetchPoolEntry(*hkManager, localPoolId,
&poolEntry);
if(result != RETURN_OK) {
object_id_t targetObjectId = hkManager->getCreatorObjectId();
reportReadCommitError("LocalPoolVector", result, false, targetObjectId,
localPoolId);
return result;
}
std::memcpy(poolEntry->getDataPtr(), this->value, poolEntry->getByteSize());
poolEntry->setValid(this->valid);
return RETURN_OK;
}
template<typename T, uint16_t vectorSize>
inline T& LocalPoolVector<T, vectorSize>::operator [](size_t i) {
if(i < vectorSize) {
return value[i];
}
// If this happens, I have to set some value. I consider this
// a configuration error, but I wont exit here.
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "LocalPoolVector: Invalid index. Setting or returning"
" last value!" << std::endl;
#else
sif::printWarning("LocalPoolVector: Invalid index. Setting or returning"
" last value!\n");
#endif
return value[vectorSize - 1];
}
template<typename T, uint16_t vectorSize>
inline const T& LocalPoolVector<T, vectorSize>::operator [](size_t i) const {
if(i < vectorSize) {
return value[i];
}
// If this happens, I have to set some value. I consider this
// a configuration error, but I wont exit here.
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "LocalPoolVector: Invalid index. Setting or returning"
" last value!" << std::endl;
#else
sif::printWarning("LocalPoolVector: Invalid index. Setting or returning"
" last value!\n");
#endif
return value[vectorSize - 1];
}
template<typename T, uint16_t vectorSize>
inline ReturnValue_t LocalPoolVector<T, vectorSize>::serialize(uint8_t** buffer,
size_t* size, size_t maxSize,
SerializeIF::Endianness streamEndianness) const {
ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED;
for (uint16_t i = 0; i < vectorSize; i++) {
result = SerializeAdapter::serialize(&(value[i]), buffer, size,
maxSize, streamEndianness);
if (result != HasReturnvaluesIF::RETURN_OK) {
break;
}
}
return result;
}
template<typename T, uint16_t vectorSize>
inline size_t LocalPoolVector<T, vectorSize>::getSerializedSize() const {
return vectorSize * SerializeAdapter::getSerializedSize(value);
}
template<typename T, uint16_t vectorSize>
inline ReturnValue_t LocalPoolVector<T, vectorSize>::deSerialize(
const uint8_t** buffer, size_t* size,
SerializeIF::Endianness streamEndianness) {
ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED;
for (uint16_t i = 0; i < vectorSize; i++) {
result = SerializeAdapter::deSerialize(&(value[i]), buffer, size,
streamEndianness);
if (result != HasReturnvaluesIF::RETURN_OK) {
break;
}
}
return result;
}
#if FSFW_CPP_OSTREAM_ENABLED == 1
template<typename T, uint16_t vectorSize>
inline std::ostream& operator<< (std::ostream &out,
const LocalPoolVector<T, vectorSize> &var) {
out << "Vector: [";
for(int i = 0;i < vectorSize; i++) {
out << var.value[i];
if(i < vectorSize - 1) {
out << ", ";
}
}
out << "]";
return out;
}
#endif
#endif /* FSFW_DATAPOOLLOCAL_LOCALPOOLVECTOR_TPP_ */

View File

@ -0,0 +1,17 @@
#ifndef FSFW_DATAPOOLLOCAL_MARKCHANGEDIF_H_
#define FSFW_DATAPOOLLOCAL_MARKCHANGEDIF_H_
/**
* Common interface for local pool entities which can be marked as changed.
*/
class MarkChangedIF {
public:
virtual~ MarkChangedIF() {};
virtual bool hasChanged() const = 0;
virtual void setChanged(bool changed) = 0;
};
#endif /* FSFW_DATAPOOLLOCAL_MARKCHANGEDIF_H_ */

View File

@ -0,0 +1,70 @@
#ifndef FSFW_DATAPOOLLOCAL_PROVIDESDATAPOOLSUBSCRIPTION_H_
#define FSFW_DATAPOOLLOCAL_PROVIDESDATAPOOLSUBSCRIPTION_H_
#include "localPoolDefinitions.h"
#include "../ipc/messageQueueDefinitions.h"
#include "../returnvalues/HasReturnvaluesIF.h"
class ProvidesDataPoolSubscriptionIF {
public:
virtual ~ProvidesDataPoolSubscriptionIF(){};
/**
* @brief Subscribe for the generation of periodic packets.
* @details
* This subscription mechanism will generally be used by the data creator
* to generate housekeeping packets which are downlinked directly.
* @return
*/
virtual ReturnValue_t subscribeForPeriodicPacket(sid_t sid, bool enableReporting,
float collectionInterval, bool isDiagnostics, object_id_t packetDestination) = 0;
/**
* @brief Subscribe for the generation of packets if the dataset
* is marked as changed.
* @details
* This subscription mechanism will generally be used by the data creator.
* @param sid
* @param isDiagnostics
* @param packetDestination
* @return
*/
virtual ReturnValue_t subscribeForUpdatePacket(sid_t sid, bool reportingEnabled,
bool isDiagnostics, object_id_t packetDestination) = 0;
/**
* @brief Subscribe for a notification message which will be sent
* if a dataset has changed.
* @details
* This subscription mechanism will generally be used internally by
* other software components.
* @param setId Set ID of the set to receive update messages from.
* @param destinationObject Object ID of the receiver.
* @param targetQueueId Receiver queue ID
* @param generateSnapshot If this is set to true, a copy of the current data with a
* timestamp will be generated and sent via message.
* Otherwise, only an notification message is sent.
* @return
*/
virtual ReturnValue_t subscribeForSetUpdateMessage(const uint32_t setId,
object_id_t destinationObject, MessageQueueId_t targetQueueId,
bool generateSnapshot) = 0;
/**
* @brief Subscribe for an notification message which will be sent if a
* pool variable has changed.
* @details
* This subscription mechanism will generally be used internally by
* other software components.
* @param localPoolId Pool ID of the pool variable
* @param destinationObject Object ID of the receiver
* @param targetQueueId Receiver queue ID
* @param generateSnapshot If this is set to true, a copy of the current data with a
* timestamp will be generated and sent via message. Otherwise,
* only an notification message is sent.
* @return
*/
virtual ReturnValue_t subscribeForVariableUpdateMessage(const lp_id_t localPoolId,
object_id_t destinationObject, MessageQueueId_t targetQueueId,
bool generateSnapshot) = 0;
};
#endif /* FSFW_DATAPOOLLOCAL_PROVIDESDATAPOOLSUBSCRIPTION_H_ */

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