Merge remote-tracking branch 'upstream/development' into eive/develop

This commit is contained in:
Robin Müller 2021-01-19 16:03:50 +01:00
commit 65f493b230
247 changed files with 5295 additions and 2323 deletions

View File

@ -70,3 +70,15 @@ now
### Commanding Service Base ### 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 - 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.
-

View File

@ -106,14 +106,16 @@ else()
) )
endif() endif()
if(CMAKE_COMPILER_IS_GNUCXX) if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set(WARNING_FLAGS if(NOT DEFINED FSFW_WARNING_FLAGS)
-Wall set(FSFW_WARNING_FLAGS
-Wextra -Wall
-Wimplicit-fallthrough=1 -Wextra
-Wno-unused-parameter -Wshadow=local
-Wno-psabi -Wimplicit-fallthrough=1
) -Wno-unused-parameter
-Wno-psabi
)
if(NOT DEFINED WARNING_SHADOW_LOCAL) if(NOT DEFINED WARNING_SHADOW_LOCAL)
option(WARNING_SHADOW_LOCAL "Show shadows declarations warning." ON) option(WARNING_SHADOW_LOCAL "Show shadows declarations warning." ON)
@ -122,6 +124,7 @@ if(CMAKE_COMPILER_IS_GNUCXX)
if(WARNING_SHADOW_LOCAL) if(WARNING_SHADOW_LOCAL)
list(APPEND WARNING_FLAGS "-Wshadow=local") list(APPEND WARNING_FLAGS "-Wshadow=local")
endif() endif()
endif() endif()
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
@ -142,9 +145,7 @@ target_include_directories(${LIB_FSFW_NAME} PRIVATE
${FSFW_CONFIG_PATH_ABSOLUTE} ${FSFW_CONFIG_PATH_ABSOLUTE}
) )
# Machine specific options can be set with the ABI_FLAGS variable.
target_compile_options(${LIB_FSFW_NAME} PRIVATE target_compile_options(${LIB_FSFW_NAME} PRIVATE
${WARNING_FLAGS} ${FSFW_WARNING_FLAGS}
${COMPILER_FLAGS} ${COMPILER_FLAGS}
${ABI_FLAGS}
) )

133
README.md
View File

@ -9,121 +9,40 @@ The initial version of the Flight Software Framework was developed during
the Flying Laptop Project by the University of Stuttgart in cooperation the Flying Laptop Project by the University of Stuttgart in cooperation
with Airbus Defence and Space GmbH. 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. 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.
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 1 MB of RAM and 1 MB of non-volatile Memory. 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.
For reference, current Applications use a Cobham Gaisler UT699 (LEON3FT), a ISISPACE IOBC or a Zynq-7020 SoC.
The `fsfw` was also tested on the STM32H743ZI-Nucleo board.
## How to Use 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.
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.
Generally, the FSFW is included in a project by compiling the FSFW sources and providing 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. 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 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 a starting point. The [configuration section](doc/README-config.md#top) provides more specific information about the possible options.
the possible options.
## Structure ## Index
The general structure is driven by the usage of interfaces provided by objects. [1. High-level overview](doc/README-highlevel.md#top) <br>
The FSFW uses C++11 as baseline. The intention behind this is that this C++ Standard should be widely available, even with older compilers. [2. Core components](doc/README-core.md#top) <br>
The FSFW uses dynamic allocation during the initialization but provides static containers during runtime. [3. OSAL overview](doc/README-osal.md#top) <br>
This simplifies the instantiation of objects and allows the usage of some standard containers. [4. PUS services](doc/README-pus.md#top) <br>
Dynamic Allocation after initialization is discouraged and different solutions are provided in the FSFW to achieve that. [5. Device Handler overview](doc/README-devicehandlers.md#top) <br>
The fsfw uses run-time type information but exceptions are not allowed. [6. Controller overview](doc/README-controllers.md#top) <br>
[7. Local Data Pools](doc/README-localpools.md#top) <br>
### Failure Handling
Functions should return a defined ReturnValue_t to signal to the caller that something has 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 Host OSAL is in development which will provide abstraction for common type of
host OSes (tested for Linux and Windows, not for MacOS yet).
The OSAL provides periodic tasks, message queues, clocks and semaphores as well as mutexes.
### Core Components
The FSFW has following core components. More detailed informations can be found in the
[core component section](doc/README-core.md#top):
1. Tasks: Abstraction for different (periodic) task types like periodic tasks or tasks with fixed timeslots
2. ObjectManager: This module stores all `SystemObjects` by mapping a provided unique object ID to the object handles.
3. Static Stores: Different stores are provided to store data of variable size (like telecommands or small telemetry) in a pool structure without
using dynamic memory allocation. These pools are allocated up front.
3. Clock: This module provided common time related functions
4. EventManager: This module allows routing of events generated by `SystemObjects`
5. HealthTable: A component which stores the health states of objects
### 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.
#### Device Handlers
DeviceHandlers are another important 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 device handler (DH) can be tested on different hardware.
The DH has mechanisms to monitor the communication with the physical device which allow for FDIR reaction.
Device Handlers can be created by overriding `DeviceHandlerBase`.
A standard FDIR component for the DH will be created automatically but can be overwritten by the user.
More information on DeviceHandlers can be found in the related [documentation section](doc/README-devicehandlers.md#top).
#### 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.
## 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,6 +3,7 @@
#include "ArrayList.h" #include "ArrayList.h"
#include <cstring> #include <cstring>
#include <functional>
/** /**
* @brief An associative container which allows multiple entries of the same key. * @brief An associative container which allows multiple entries of the same key.

View File

@ -47,9 +47,11 @@ ReturnValue_t SharedRingBuffer::initialize() {
DynamicFIFO<size_t>* SharedRingBuffer::getReceiveSizesFIFO() { DynamicFIFO<size_t>* SharedRingBuffer::getReceiveSizesFIFO() {
if(receiveSizesFIFO == nullptr) { if(receiveSizesFIFO == nullptr) {
// Configuration error. // Configuration error.
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "SharedRingBuffer::getReceiveSizesFIFO: Ring buffer" sif::warning << "SharedRingBuffer::getReceiveSizesFIFO: Ring buffer"
<< " was not configured to have sizes FIFO, returning nullptr!" << " was not configured to have sizes FIFO, returning nullptr!"
<< std::endl; << std::endl;
#endif
} }
return receiveSizesFIFO; return receiveSizesFIFO;
} }

View File

@ -4,7 +4,7 @@
ExtendedControllerBase::ExtendedControllerBase(object_id_t objectId, ExtendedControllerBase::ExtendedControllerBase(object_id_t objectId,
object_id_t parentId, size_t commandQueueDepth): object_id_t parentId, size_t commandQueueDepth):
ControllerBase(objectId, parentId, commandQueueDepth), ControllerBase(objectId, parentId, commandQueueDepth),
localPoolManager(this, commandQueue), poolManager(this, commandQueue),
actionHelper(this, commandQueue) { actionHelper(this, commandQueue) {
} }
@ -17,7 +17,7 @@ ReturnValue_t ExtendedControllerBase::executeAction(ActionId_t actionId,
ReturnValue_t ExtendedControllerBase::initializeLocalDataPool( ReturnValue_t ExtendedControllerBase::initializeLocalDataPool(
LocalDataPool &localDataPoolMap, LocalDataPoolManager &poolManager) { localpool::DataPool &localDataPoolMap, LocalDataPoolManager &poolManager) {
// needs to be overriden and implemented by child class. // needs to be overriden and implemented by child class.
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
@ -26,10 +26,6 @@ object_id_t ExtendedControllerBase::getObjectId() const {
return SystemObject::getObjectId(); return SystemObject::getObjectId();
} }
LocalDataPoolManager* ExtendedControllerBase::getHkManagerHandle() {
return &localPoolManager;
}
uint32_t ExtendedControllerBase::getPeriodicOperationFrequency() const { uint32_t ExtendedControllerBase::getPeriodicOperationFrequency() const {
return this->executingTask->getPeriodMs(); return this->executingTask->getPeriodMs();
} }
@ -40,7 +36,7 @@ ReturnValue_t ExtendedControllerBase::handleCommandMessage(
if(result == HasReturnvaluesIF::RETURN_OK) { if(result == HasReturnvaluesIF::RETURN_OK) {
return result; return result;
} }
return localPoolManager.handleHousekeepingMessage(message); return poolManager.handleHousekeepingMessage(message);
} }
void ExtendedControllerBase::handleQueue() { void ExtendedControllerBase::handleQueue() {
@ -64,7 +60,7 @@ void ExtendedControllerBase::handleQueue() {
continue; continue;
} }
result = localPoolManager.handleHousekeepingMessage(&command); result = poolManager.handleHousekeepingMessage(&command);
if (result == RETURN_OK) { if (result == RETURN_OK) {
continue; continue;
} }
@ -88,16 +84,16 @@ ReturnValue_t ExtendedControllerBase::initialize() {
return result; return result;
} }
return localPoolManager.initialize(commandQueue); return poolManager.initialize(commandQueue);
} }
ReturnValue_t ExtendedControllerBase::initializeAfterTaskCreation() { ReturnValue_t ExtendedControllerBase::initializeAfterTaskCreation() {
return localPoolManager.initializeAfterTaskCreation(); return poolManager.initializeAfterTaskCreation();
} }
ReturnValue_t ExtendedControllerBase::performOperation(uint8_t opCode) { ReturnValue_t ExtendedControllerBase::performOperation(uint8_t opCode) {
handleQueue(); handleQueue();
localPoolManager.performHkOperation(); poolManager.performHkOperation();
performControlOperation(); performControlOperation();
return RETURN_OK; return RETURN_OK;
} }
@ -107,7 +103,13 @@ MessageQueueId_t ExtendedControllerBase::getCommandQueue() const {
} }
LocalPoolDataSetBase* ExtendedControllerBase::getDataSetHandle(sid_t sid) { LocalPoolDataSetBase* ExtendedControllerBase::getDataSetHandle(sid_t sid) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "ExtendedControllerBase::getDataSetHandle: No child " sif::warning << "ExtendedControllerBase::getDataSetHandle: No child "
<< " implementation provided, returning nullptr!" << std::endl; << " implementation provided, returning nullptr!" << std::endl;
#endif
return nullptr; return nullptr;
} }
LocalDataPoolManager* ExtendedControllerBase::getHkManagerHandle() {
return &poolManager;
}

View File

@ -33,7 +33,7 @@ public:
virtual ReturnValue_t initializeAfterTaskCreation() override; virtual ReturnValue_t initializeAfterTaskCreation() override;
protected: protected:
LocalDataPoolManager localPoolManager; LocalDataPoolManager poolManager;
ActionHelper actionHelper; ActionHelper actionHelper;
/** /**
@ -58,11 +58,11 @@ protected:
size_t size) override; size_t size) override;
/** HasLocalDatapoolIF overrides */ /** HasLocalDatapoolIF overrides */
virtual LocalDataPoolManager* getHkManagerHandle() override;
virtual object_id_t getObjectId() const override; virtual object_id_t getObjectId() const override;
virtual ReturnValue_t initializeLocalDataPool( virtual ReturnValue_t initializeLocalDataPool(
LocalDataPool& localDataPoolMap, localpool::DataPool& localDataPoolMap,
LocalDataPoolManager& poolManager) override; LocalDataPoolManager& poolManager) override;
virtual LocalDataPoolManager* getHkManagerHandle() override;
virtual uint32_t getPeriodicOperationFrequency() const override; virtual uint32_t getPeriodicOperationFrequency() const override;
virtual LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override; virtual LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override;
}; };

View File

@ -55,7 +55,9 @@ void Clcw::setBitLock(bool bitLock) {
} }
void Clcw::print() { void Clcw::print() {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "Clcw::print: Clcw is: " << std::hex << getAsWhole() << std::dec << std::endl; sif::debug << "Clcw::print: Clcw is: " << std::hex << getAsWhole() << std::dec << std::endl;
#endif
} }
void Clcw::setWhole(uint32_t rawClcw) { void Clcw::setWhole(uint32_t rawClcw) {

View File

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

View File

@ -29,9 +29,11 @@ ReturnValue_t MapPacketExtraction::extractPackets(TcTransferFrame* frame) {
bufferPosition = &packetBuffer[packetLength]; bufferPosition = &packetBuffer[packetLength];
status = RETURN_OK; status = RETURN_OK;
} else { } else {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error sif::error
<< "MapPacketExtraction::extractPackets. Packet too large! Size: " << "MapPacketExtraction::extractPackets. Packet too large! Size: "
<< packetLength << std::endl; << packetLength << std::endl;
#endif
clearBuffers(); clearBuffers();
status = CONTENT_TOO_LARGE; status = CONTENT_TOO_LARGE;
} }
@ -51,24 +53,30 @@ ReturnValue_t MapPacketExtraction::extractPackets(TcTransferFrame* frame) {
} }
status = RETURN_OK; status = RETURN_OK;
} else { } else {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error sif::error
<< "MapPacketExtraction::extractPackets. Packet too large! Size: " << "MapPacketExtraction::extractPackets. Packet too large! Size: "
<< packetLength << std::endl; << packetLength << std::endl;
#endif
clearBuffers(); clearBuffers();
status = CONTENT_TOO_LARGE; status = CONTENT_TOO_LARGE;
} }
} else { } else {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error sif::error
<< "MapPacketExtraction::extractPackets. Illegal segment! Last flag: " << "MapPacketExtraction::extractPackets. Illegal segment! Last flag: "
<< (int) lastSegmentationFlag << std::endl; << (int) lastSegmentationFlag << std::endl;
#endif
clearBuffers(); clearBuffers();
status = ILLEGAL_SEGMENTATION_FLAG; status = ILLEGAL_SEGMENTATION_FLAG;
} }
break; break;
default: default:
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error sif::error
<< "MapPacketExtraction::extractPackets. Illegal segmentationFlag: " << "MapPacketExtraction::extractPackets. Illegal segmentationFlag: "
<< (int) segmentationFlag << std::endl; << (int) segmentationFlag << std::endl;
#endif
clearBuffers(); clearBuffers();
status = DATA_CORRUPTED; status = DATA_CORRUPTED;
break; break;
@ -135,10 +143,14 @@ ReturnValue_t MapPacketExtraction::initialize() {
} }
void MapPacketExtraction::printPacketBuffer(void) { void MapPacketExtraction::printPacketBuffer(void) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "DLL: packet_buffer contains: " << std::endl; sif::debug << "DLL: packet_buffer contains: " << std::endl;
#endif
for (uint32_t i = 0; i < this->packetLength; ++i) { 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 sif::debug << "packet_buffer[" << std::dec << i << "]: 0x" << std::hex
<< (uint16_t) this->packetBuffer[i] << std::endl; << (uint16_t) this->packetBuffer[i] << std::endl;
#endif
} }
} }

View File

@ -87,16 +87,25 @@ uint8_t* TcTransferFrame::getFullDataField() {
} }
void TcTransferFrame::print() { void TcTransferFrame::print() {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "Raw Frame: " << std::hex << std::endl; sif::debug << "Raw Frame: " << std::hex << std::endl;
for (uint16_t count = 0; count < this->getFullSize(); count++ ) { for (uint16_t count = 0; count < this->getFullSize(); count++ ) {
sif::debug << (uint16_t)this->getFullFrame()[count] << " "; sif::debug << (uint16_t)this->getFullFrame()[count] << " ";
} }
sif::debug << std::dec << std::endl; sif::debug << std::dec << std::endl;
// debug << "Frame Header:" << std::endl;
// debug << "Version Number: " << std::hex << (uint16_t)this->current_frame.getVersionNumber() << std::endl; sif::debug << "Frame Header:" << std::endl;
// debug << "Bypass Flag set?| Ctrl Cmd Flag set?: " << (uint16_t)this->current_frame.bypassFlagSet() << " | " << (uint16_t)this->current_frame.controlCommandFlagSet() << std::endl; sif::debug << "Version Number: " << std::hex
// debug << "SCID : " << this->current_frame.getSpacecraftId() << std::endl; << (uint16_t)this->getVersionNumber() << std::endl;
// debug << "VCID : " << (uint16_t)this->current_frame.getVirtualChannelId() << std::endl; sif::debug << "Bypass Flag set?| Ctrl Cmd Flag set?: "
// debug << "Frame length: " << std::dec << this->current_frame.getFrameLength() << std::endl; << (uint16_t)this->bypassFlagSet() << " | "
// debug << "Sequence Number: " << (uint16_t)this->current_frame.getSequenceNumber() << std::endl; << (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()-2] = (crc & 0xFF00) >> 8;
this->getFullFrame()[getFullSize()-1] = (crc & 0x00FF); this->getFullFrame()[getFullSize()-1] = (crc & 0x00FF);
} else { } else {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "TcTransferFrameLocal: dataSize too large: " << dataSize << std::endl; sif::debug << "TcTransferFrameLocal: dataSize too large: " << dataSize << std::endl;
#endif
} }
} else { } else {
//No data in frame //No data in frame

View File

@ -102,8 +102,10 @@ uint8_t VirtualChannelReception::getChannelId() const {
ReturnValue_t VirtualChannelReception::initialize() { ReturnValue_t VirtualChannelReception::initialize() {
ReturnValue_t returnValue = RETURN_FAILED; ReturnValue_t returnValue = RETURN_FAILED;
if ((slidingWindowWidth > 254) || (slidingWindowWidth % 2 != 0)) { if ((slidingWindowWidth > 254) || (slidingWindowWidth % 2 != 0)) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "VirtualChannelReception::initialize: Illegal sliding window width: " sif::error << "VirtualChannelReception::initialize: Illegal sliding window width: "
<< (int) slidingWindowWidth << std::endl; << (int) slidingWindowWidth << std::endl;
#endif
return RETURN_FAILED; return RETURN_FAILED;
} }
for (mapChannelIterator iterator = mapChannels.begin(); iterator != mapChannels.end(); for (mapChannelIterator iterator = mapChannels.begin(); iterator != mapChannels.end();

View File

@ -9,21 +9,28 @@ PoolDataSetBase::PoolDataSetBase(PoolVariableIF** registeredVariablesArray,
PoolDataSetBase::~PoolDataSetBase() {} PoolDataSetBase::~PoolDataSetBase() {}
ReturnValue_t PoolDataSetBase::registerVariable( ReturnValue_t PoolDataSetBase::registerVariable(
PoolVariableIF *variable) { PoolVariableIF *variable) {
if (state != States::DATA_SET_UNINITIALISED) { if (state != States::STATE_SET_UNINITIALISED) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "DataSet::registerVariable: " sif::error << "DataSet::registerVariable: "
"Call made in wrong position." << std::endl; "Call made in wrong position." << std::endl;
#endif
return DataSetIF::DATA_SET_UNINITIALISED; return DataSetIF::DATA_SET_UNINITIALISED;
} }
if (variable == nullptr) { if (variable == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "DataSet::registerVariable: " sif::error << "DataSet::registerVariable: "
"Pool variable is nullptr." << std::endl; "Pool variable is nullptr." << std::endl;
#endif
return DataSetIF::POOL_VAR_NULL; return DataSetIF::POOL_VAR_NULL;
} }
if (fillCount >= maxFillCount) { if (fillCount >= maxFillCount) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "DataSet::registerVariable: " sif::error << "DataSet::registerVariable: "
"DataSet is full." << std::endl; "DataSet is full." << std::endl;
#endif
return DataSetIF::DATA_SET_FULL; return DataSetIF::DATA_SET_FULL;
} }
registeredVariables[fillCount] = variable; registeredVariables[fillCount] = variable;
@ -31,25 +38,33 @@ ReturnValue_t PoolDataSetBase::registerVariable(
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t PoolDataSetBase::read(uint32_t lockTimeout) { ReturnValue_t PoolDataSetBase::read(MutexIF::TimeoutType timeoutType,
uint32_t lockTimeout) {
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
if (state == States::DATA_SET_UNINITIALISED) { ReturnValue_t error = result;
lockDataPool(lockTimeout); if (state == States::STATE_SET_UNINITIALISED) {
lockDataPool(timeoutType, lockTimeout);
for (uint16_t count = 0; count < fillCount; count++) { for (uint16_t count = 0; count < fillCount; count++) {
result = readVariable(count); result = readVariable(count);
if(result != RETURN_OK) { if(result != RETURN_OK) {
break; error = result;
} }
} }
state = States::DATA_SET_WAS_READ; state = States::STATE_SET_WAS_READ;
unlockDataPool(); unlockDataPool();
} }
else { else {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "DataSet::read(): " sif::error << "DataSet::read(): "
"Call made in wrong position. Don't forget to commit" "Call made in wrong position. Don't forget to commit"
" member datasets!" << std::endl; " member datasets!" << std::endl;
#endif
result = SET_WAS_ALREADY_READ; result = SET_WAS_ALREADY_READ;
} }
if(error != HasReturnvaluesIF::RETURN_OK) {
result = error;
}
return result; return result;
} }
@ -71,7 +86,15 @@ ReturnValue_t PoolDataSetBase::readVariable(uint16_t count) {
registeredVariables[count]->getDataPoolId() registeredVariables[count]->getDataPoolId()
!= PoolVariableIF::NO_PARAMETER) != PoolVariableIF::NO_PARAMETER)
{ {
result = registeredVariables[count]->readWithoutLock(); if(protectEveryReadCommitCall) {
result = registeredVariables[count]->read(
timeoutTypeForSingleVars,
mutexTimeoutForSingleVars);
}
else {
result = registeredVariables[count]->readWithoutLock();
}
if(result != HasReturnvaluesIF::RETURN_OK) { if(result != HasReturnvaluesIF::RETURN_OK) {
result = INVALID_PARAMETER_DEFINITION; result = INVALID_PARAMETER_DEFINITION;
} }
@ -79,55 +102,76 @@ ReturnValue_t PoolDataSetBase::readVariable(uint16_t count) {
return result; return result;
} }
ReturnValue_t PoolDataSetBase::commit(uint32_t lockTimeout) { ReturnValue_t PoolDataSetBase::commit(MutexIF::TimeoutType timeoutType,
if (state == States::DATA_SET_WAS_READ) { uint32_t lockTimeout) {
handleAlreadyReadDatasetCommit(lockTimeout); if (state == States::STATE_SET_WAS_READ) {
handleAlreadyReadDatasetCommit(timeoutType, lockTimeout);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
else { else {
return handleUnreadDatasetCommit(lockTimeout); return handleUnreadDatasetCommit(timeoutType, lockTimeout);
} }
} }
void PoolDataSetBase::handleAlreadyReadDatasetCommit(uint32_t lockTimeout) { void PoolDataSetBase::handleAlreadyReadDatasetCommit(
lockDataPool(lockTimeout); MutexIF::TimeoutType timeoutType, uint32_t lockTimeout) {
lockDataPool(timeoutType, lockTimeout);
for (uint16_t count = 0; count < fillCount; count++) { for (uint16_t count = 0; count < fillCount; count++) {
if (registeredVariables[count]->getReadWriteMode() if (registeredVariables[count]->getReadWriteMode()
!= PoolVariableIF::VAR_READ != PoolVariableIF::VAR_READ
&& registeredVariables[count]->getDataPoolId() && registeredVariables[count]->getDataPoolId()
!= PoolVariableIF::NO_PARAMETER) { != PoolVariableIF::NO_PARAMETER) {
registeredVariables[count]->commitWithoutLock(); if(protectEveryReadCommitCall) {
registeredVariables[count]->commit(
timeoutTypeForSingleVars,
mutexTimeoutForSingleVars);
}
else {
registeredVariables[count]->commitWithoutLock();
}
} }
} }
state = States::DATA_SET_UNINITIALISED; state = States::STATE_SET_UNINITIALISED;
unlockDataPool(); unlockDataPool();
} }
ReturnValue_t PoolDataSetBase::handleUnreadDatasetCommit(uint32_t lockTimeout) { ReturnValue_t PoolDataSetBase::handleUnreadDatasetCommit(
MutexIF::TimeoutType timeoutType, uint32_t lockTimeout) {
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
lockDataPool(lockTimeout); lockDataPool(timeoutType, lockTimeout);
for (uint16_t count = 0; count < fillCount; count++) { for (uint16_t count = 0; count < fillCount; count++) {
if (registeredVariables[count]->getReadWriteMode() if (registeredVariables[count]->getReadWriteMode()
== PoolVariableIF::VAR_WRITE == PoolVariableIF::VAR_WRITE
&& registeredVariables[count]->getDataPoolId() && registeredVariables[count]->getDataPoolId()
!= PoolVariableIF::NO_PARAMETER) { != PoolVariableIF::NO_PARAMETER) {
registeredVariables[count]->commitWithoutLock(); if(protectEveryReadCommitCall) {
result = registeredVariables[count]->commit(
timeoutTypeForSingleVars,
mutexTimeoutForSingleVars);
}
else {
result = registeredVariables[count]->commitWithoutLock();
}
} else if (registeredVariables[count]->getDataPoolId() } else if (registeredVariables[count]->getDataPoolId()
!= PoolVariableIF::NO_PARAMETER) { != PoolVariableIF::NO_PARAMETER) {
if (result != COMMITING_WITHOUT_READING) { if (result != COMMITING_WITHOUT_READING) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "DataSet::commit(): commit-without-read call made " sif::error << "DataSet::commit(): commit-without-read call made "
"with non write-only variable." << std::endl; "with non write-only variable." << std::endl;
#endif
result = COMMITING_WITHOUT_READING; result = COMMITING_WITHOUT_READING;
} }
} }
} }
state = States::DATA_SET_UNINITIALISED; state = States::STATE_SET_UNINITIALISED;
unlockDataPool(); unlockDataPool();
return result; return result;
} }
ReturnValue_t PoolDataSetBase::lockDataPool(uint32_t timeoutMs) { ReturnValue_t PoolDataSetBase::lockDataPool(MutexIF::TimeoutType timeoutType,
uint32_t lockTimeout) {
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
@ -172,3 +216,15 @@ size_t PoolDataSetBase::getSerializedSize() const {
void PoolDataSetBase::setContainer(PoolVariableIF **variablesContainer) { void PoolDataSetBase::setContainer(PoolVariableIF **variablesContainer) {
this->registeredVariables = 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;
}

View File

@ -3,6 +3,7 @@
#include "PoolDataSetIF.h" #include "PoolDataSetIF.h"
#include "PoolVariableIF.h" #include "PoolVariableIF.h"
#include "../serialize/SerializeIF.h"
#include "../ipc/MutexIF.h" #include "../ipc/MutexIF.h"
/** /**
@ -44,6 +45,7 @@ public:
/** /**
* @brief The read call initializes reading out all registered variables. * @brief The read call initializes reading out all registered variables.
* It is mandatory to call commit after every read call!
* @details * @details
* It iterates through the list of registered variables and calls all read() * It iterates through the list of registered variables and calls all read()
* functions of the registered pool variables (which read out their values * functions of the registered pool variables (which read out their values
@ -52,16 +54,18 @@ public:
* the operation is aborted and @c INVALID_PARAMETER_DEFINITION returned. * the operation is aborted and @c INVALID_PARAMETER_DEFINITION returned.
* *
* The data pool is locked during the whole read operation and * The data pool is locked during the whole read operation and
* freed afterwards.The state changes to "was written" after this operation. * freed afterwards. It is mandatory to call commit after a read call,
* even if the read operation is not successful!
* @return * @return
* - @c RETURN_OK if all variables were read successfully. * - @c RETURN_OK if all variables were read successfully.
* - @c INVALID_PARAMETER_DEFINITION if PID, size or type of the * - @c INVALID_PARAMETER_DEFINITION if a pool entry does not exist or there
* requested variable is invalid. * is a type conflict.
* - @c SET_WAS_ALREADY_READ if read() is called twice without calling * - @c SET_WAS_ALREADY_READ if read() is called twice without calling
* commit() in between * commit() in between
*/ */
virtual ReturnValue_t read(uint32_t lockTimeout = virtual ReturnValue_t read(
MutexIF::BLOCKING) override; MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING,
uint32_t lockTimeout = 20) override;
/** /**
* @brief The commit call initializes writing back the registered variables. * @brief The commit call initializes writing back the registered variables.
* @details * @details
@ -75,13 +79,14 @@ public:
* If the set does contain at least one variable which is not write-only * 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 * commit() can only be called after read(). If the set only contains
* variables which are write only, commit() can be called without a * variables which are write only, commit() can be called without a
* preceding read() call. * preceding read() call. Every read call must be followed by a commit call!
* @return - @c RETURN_OK if all variables were read successfully. * @return - @c RETURN_OK if all variables were read successfully.
* - @c COMMITING_WITHOUT_READING if set was not read yet and * - @c COMMITING_WITHOUT_READING if set was not read yet and
* contains non write-only variables * contains non write-only variables
*/ */
virtual ReturnValue_t commit(uint32_t lockTimeout = virtual ReturnValue_t commit(
MutexIF::BLOCKING) override; MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING,
uint32_t lockTimeout = 20) override;
/** /**
* Register the passed pool variable instance into the data set. * Register the passed pool variable instance into the data set.
@ -89,13 +94,15 @@ public:
* @return * @return
*/ */
virtual ReturnValue_t registerVariable( PoolVariableIF* variable) override; virtual ReturnValue_t registerVariable( PoolVariableIF* variable) override;
/** /**
* Provides the means to lock the underlying data structure to ensure * Provides the means to lock the underlying data structure to ensure
* thread-safety. Default implementation is empty * thread-safety. Default implementation is empty
* @return Always returns -@c RETURN_OK * @return Always returns -@c RETURN_OK
*/ */
virtual ReturnValue_t lockDataPool(uint32_t timeoutMs = virtual ReturnValue_t lockDataPool(
MutexIF::BLOCKING) override; MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING,
uint32_t timeoutMs = 20) override;
/** /**
* Provides the means to unlock the underlying data structure to ensure * Provides the means to unlock the underlying data structure to ensure
* thread-safety. Default implementation is empty * thread-safety. Default implementation is empty
@ -113,7 +120,16 @@ public:
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
SerializeIF::Endianness streamEndianness) override; 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: protected:
/** /**
* @brief The fill_count attribute ensures that the variables * @brief The fill_count attribute ensures that the variables
* register in the correct array position and that the maximum * register in the correct array position and that the maximum
@ -124,14 +140,14 @@ protected:
* States of the seet. * States of the seet.
*/ */
enum class States { enum class States {
DATA_SET_UNINITIALISED, //!< DATA_SET_UNINITIALISED STATE_SET_UNINITIALISED, //!< DATA_SET_UNINITIALISED
DATA_SET_WAS_READ //!< DATA_SET_WAS_READ STATE_SET_WAS_READ //!< DATA_SET_WAS_READ
}; };
/** /**
* @brief state manages the internal state of the data set, * @brief state manages the internal state of the data set,
* which is important e.g. for the behavior on destruction. * which is important e.g. for the behavior on destruction.
*/ */
States state = States::DATA_SET_UNINITIALISED; States state = States::STATE_SET_UNINITIALISED;
/** /**
* @brief This array represents all pool variables registered in this set. * @brief This array represents all pool variables registered in this set.
@ -142,11 +158,20 @@ protected:
const size_t maxFillCount = 0; const size_t maxFillCount = 0;
void setContainer(PoolVariableIF** variablesContainer); void setContainer(PoolVariableIF** variablesContainer);
PoolVariableIF** getContainer() const;
private: private:
bool protectEveryReadCommitCall = false;
MutexIF::TimeoutType timeoutTypeForSingleVars = MutexIF::TimeoutType::WAITING;
uint32_t mutexTimeoutForSingleVars = 20;
ReturnValue_t readVariable(uint16_t count); ReturnValue_t readVariable(uint16_t count);
void handleAlreadyReadDatasetCommit(uint32_t lockTimeout); void handleAlreadyReadDatasetCommit(
ReturnValue_t handleUnreadDatasetCommit(uint32_t lockTimeout); 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_ */ #endif /* FSFW_DATAPOOL_POOLDATASETBASE_H_ */

View File

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

View File

@ -1,29 +1,24 @@
#include "PoolEntry.h" #include "PoolEntry.h"
#include "../serviceinterface/ServiceInterfaceStream.h" #include "../serviceinterface/ServiceInterface.h"
#include "../globalfunctions/arrayprinter.h" #include "../globalfunctions/arrayprinter.h"
#include <cstring> #include <cstring>
#include <algorithm>
template <typename T> template <typename T>
PoolEntry<T>::PoolEntry(std::initializer_list<T> initValue, uint8_t setLength, PoolEntry<T>::PoolEntry(std::initializer_list<T> initValue, bool setValid ):
bool setValid ) : length(setLength), valid(setValid) { length(initValue.size()), valid(setValid) {
this->address = new T[this->length]; this->address = new T[this->length];
if(initValue.size() == 0) { if(initValue.size() == 0) {
std::memset(this->address, 0, this->getByteSize()); 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 { else {
std::copy(initValue.begin(), initValue.end(), this->address); std::copy(initValue.begin(), initValue.end(), this->address);
} }
} }
template <typename T> 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) { length(setLength), valid(setValid) {
this->address = new T[this->length]; this->address = new T[this->length];
if (initValue != nullptr) { if (initValue != nullptr) {
@ -67,10 +62,26 @@ bool PoolEntry<T>::getValid() {
template <typename T> template <typename T>
void PoolEntry<T>::print() { void PoolEntry<T>::print() {
sif::debug << "Pool Entry Validity: " << const char* validString = nullptr;
(this->valid? " (valid) " : " (invalid) ") << std::endl; if(valid) {
arrayprinter::print(reinterpret_cast<uint8_t*>(address), length); validString = "Valid";
sif::debug << std::dec << std::endl; }
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> template<typename T>
@ -81,8 +92,10 @@ Type PoolEntry<T>::getType() {
template class PoolEntry<uint8_t>; template class PoolEntry<uint8_t>;
template class PoolEntry<uint16_t>; template class PoolEntry<uint16_t>;
template class PoolEntry<uint32_t>; template class PoolEntry<uint32_t>;
template class PoolEntry<uint64_t>;
template class PoolEntry<int8_t>; template class PoolEntry<int8_t>;
template class PoolEntry<int16_t>; template class PoolEntry<int16_t>;
template class PoolEntry<int32_t>; template class PoolEntry<int32_t>;
template class PoolEntry<int64_t>;
template class PoolEntry<float>; template class PoolEntry<float>;
template class PoolEntry<double>; template class PoolEntry<double>;

View File

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

51
datapool/PoolReadHelper.h Normal file
View File

@ -0,0 +1,51 @@
#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 PoolReadHelper {
public:
PoolReadHelper(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;
}
~PoolReadHelper() {
if(readObject != nullptr) {
readObject->commit(timeoutType, mutexTimeout);
}
}
private:
ReadCommitIF* readObject = nullptr;
ReturnValue_t readResult = HasReturnvaluesIF::RETURN_OK;
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING;
uint32_t mutexTimeout = 20;
};
#endif /* FSFW_DATAPOOL_POOLREADHELPER_H_ */

View File

@ -3,6 +3,7 @@
#include "../returnvalues/HasReturnvaluesIF.h" #include "../returnvalues/HasReturnvaluesIF.h"
#include "../serialize/SerializeIF.h" #include "../serialize/SerializeIF.h"
#include "ReadCommitIF.h"
/** /**
* @brief This interface is used to control data pool * @brief This interface is used to control data pool
@ -17,13 +18,14 @@
* @author Bastian Baetz * @author Bastian Baetz
* @ingroup data_pool * @ingroup data_pool
*/ */
class PoolVariableIF : public SerializeIF { class PoolVariableIF : public SerializeIF,
public ReadCommitIF {
friend class PoolDataSetBase; friend class PoolDataSetBase;
friend class GlobDataSet;
friend class LocalPoolDataSetBase; friend class LocalPoolDataSetBase;
public: public:
static constexpr uint8_t INTERFACE_ID = CLASS_ID::POOL_VARIABLE_IF; 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_READ_WRITE_MODE = MAKE_RETURN_CODE(0xA0);
static constexpr ReturnValue_t INVALID_POOL_ENTRY = MAKE_RETURN_CODE(0xA1);
static constexpr bool VALID = 1; static constexpr bool VALID = 1;
static constexpr bool INVALID = 0; static constexpr bool INVALID = 0;
@ -57,41 +59,6 @@ public:
*/ */
virtual void setValid(bool validity) = 0; virtual void setValid(bool validity) = 0;
/**
* @brief The commit call shall write back a newly calculated local
* value to the data pool.
* @details
* It is assumed that these calls are implemented in a thread-safe manner!
*/
virtual ReturnValue_t commit(uint32_t lockTimeout) = 0;
/**
* @brief The read call shall read the value of this parameter from
* the data pool and store the content locally.
* @details
* It is assumbed that these calls are implemented in a thread-safe manner!
*/
virtual ReturnValue_t read(uint32_t lockTimeout) = 0;
protected:
/**
* @brief Same as commit with the difference that comitting will be
* performed without a lock
* @return
* This can be used if the lock protection is handled externally
* to avoid the overhead of locking and unlocking consecutively.
* Declared protected to avoid free public usage.
*/
virtual ReturnValue_t readWithoutLock() = 0;
/**
* @brief Same as commit with the difference that comitting will be
* performed without a lock
* @return
* This can be used if the lock protection is handled externally
* to avoid the overhead of locking and unlocking consecutively.
* Declared protected to avoid free public usage.
*/
virtual ReturnValue_t commitWithoutLock() = 0;
}; };
using pool_rwm_t = PoolVariableIF::ReadWriteMode_t; using pool_rwm_t = PoolVariableIF::ReadWriteMode_t;

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 {
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,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* getHkManagerHandle() = 0;
protected:
};
#endif /* FSFW_DATAPOOLLOCAL_ACCESSLOCALPOOLF_H_ */

View File

@ -6,3 +6,5 @@ target_sources(${LIB_FSFW_NAME}
LocalPoolObjectBase.cpp LocalPoolObjectBase.cpp
SharedLocalDataSet.cpp SharedLocalDataSet.cpp
) )
add_subdirectory(internal)

View File

@ -1,100 +1,66 @@
#ifndef FSFW_DATAPOOLLOCAL_HASLOCALDATAPOOLIF_H_ #ifndef FSFW_DATAPOOLLOCAL_HASLOCALDATAPOOLIF_H_
#define FSFW_DATAPOOLLOCAL_HASLOCALDATAPOOLIF_H_ #define FSFW_DATAPOOLLOCAL_HASLOCALDATAPOOLIF_H_
#include "locPoolDefinitions.h" #include "localPoolDefinitions.h"
#include "LocalDataPoolManager.h"
#include "../datapool/PoolEntryIF.h" #include "../datapool/PoolEntryIF.h"
#include "../serviceinterface/ServiceInterface.h"
#include "../ipc/MessageQueueSenderIF.h" #include "../ipc/MessageQueueSenderIF.h"
#include "../housekeeping/HousekeepingMessage.h" #include "../housekeeping/HousekeepingMessage.h"
#include <map> #include <map>
class LocalDataPoolManager; class AccessPoolManagerIF;
class ProvidesDataPoolSubscriptionIF;
class LocalPoolDataSetBase; class LocalPoolDataSetBase;
class LocalPoolObjectBase; class LocalPoolObjectBase;
using LocalDataPool = std::map<lp_id_t, PoolEntryIF*>;
using LocalDataPoolMapIter = LocalDataPool::iterator;
/** /**
* @brief This interface is implemented by classes which posses a local * @brief This interface is implemented by classes which posses a local data pool (not the
* data pool (not the managing class). It defines the relationship * managing class). It defines the relationship between the local data pool owner
* between the local data pool owner and the LocalDataPoolManager. * and the LocalDataPoolManager.
* @details * @details
* Any class implementing this interface shall also have a LocalDataPoolManager * Any class implementing this interface shall also have a LocalDataPoolManager member class which
* member class which contains the actual pool data structure * contains the actual pool data structure and exposes the public interface for it.
* and exposes the public interface for it. * The local data pool can be accessed using helper classes by using the
* This is required because the pool entries are templates, which makes * LocalPoolVariable, LocalPoolVector or LocalDataSet classes. Every local pool variable can
* specifying an interface rather difficult. The local data pool can be * be uniquely identified by a global pool ID (gp_id_t) and every dataset tied
* accessed by using the LocalPoolVariable, LocalPoolVector or LocalDataSet * to a pool manager can be uniqely identified by a global structure ID (sid_t).
* classes.
* *
* Architectural Note:
* This could be circumvented by using a wrapper/accessor function or
* implementing the templated function in this interface..
* The first solution sounds better than the second but
* the LocalPoolVariable classes are templates as well, so this just shifts
* the problem somewhere else. Interfaces are nice, but the most
* pragmatic solution I found was to offer the client the full interface
* of the LocalDataPoolManager.
*/ */
class HasLocalDataPoolIF { class HasLocalDataPoolIF {
friend class HasLocalDpIFManagerAttorney;
friend class HasLocalDpIFUserAttorney;
public: public:
virtual~ HasLocalDataPoolIF() {}; virtual~ HasLocalDataPoolIF() {};
static constexpr uint8_t INTERFACE_ID = CLASS_ID::LOCAL_POOL_OWNER_IF; static constexpr uint32_t INVALID_LPID = localpool::INVALID_LPID;
static constexpr uint32_t INVALID_LPID = localpool::INVALID_LPID; virtual object_id_t getObjectId() const = 0;
virtual object_id_t getObjectId() const = 0; /** Command queue for housekeeping messages. */
virtual MessageQueueId_t getCommandQueue() 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;
/** /**
* Is used by pool owner to initialize the pool map once * Returns the minimum sampling frequency in milliseconds, which will
* The manager instance shall also be passed to this function. * usually be the period the pool owner performs its periodic operation.
* It can be used to subscribe for periodic packets for for updates. * @return
*/ */
virtual ReturnValue_t initializeLocalDataPool( virtual uint32_t getPeriodicOperationFrequency() const = 0;
LocalDataPool& localDataPoolMap,
LocalDataPoolManager& poolManager) = 0;
/** Can be used to get a handle to the local data pool manager. */
virtual LocalDataPoolManager* getHkManagerHandle() = 0;
/**
* Returns the minimum sampling frequency in milliseconds, which will
* usually be the period the pool owner performs its periodic operation.
* @return
*/
virtual uint32_t getPeriodicOperationFrequency() const = 0;
/**
* This function is used by the pool manager to get a valid dataset
* from a SID
* @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.
* @param localPoolId
* @return
*/
virtual LocalPoolObjectBase* getPoolObjectHandle(lp_id_t localPoolId) {
sif::warning << "HasLocalDataPoolIF::getPoolObjectHandle: Not overriden"
<< ". Returning nullptr!" << std::endl;
return nullptr;
}
/** /**
* @brief This function will be called by the manager if an update * @brief This function will be called by the manager if an update
* notification is received. * notification is received.
* @details * @details HasLocalDataPoolIF
* Can be overriden by the child class to handle changed datasets. * Can be overriden by the child class to handle changed datasets.
* @param sid * @param sid
* @param storeId If a snapshot was requested, data will be located inside * @param storeId If a snapshot was requested, data will be located inside
@ -119,18 +85,81 @@ public:
return; return;
} }
/* These function can be implemented by pool owner, as they are required /**
* by the housekeeping message interface */ * These function can be implemented by pool owner, if they are required
virtual ReturnValue_t addDataSet(sid_t sid) { * and used by the housekeeping message interface.
return HasReturnvaluesIF::RETURN_FAILED; * */
}; virtual ReturnValue_t addDataSet(sid_t sid) {
virtual ReturnValue_t removeDataSet(sid_t sid) { return HasReturnvaluesIF::RETURN_FAILED;
return HasReturnvaluesIF::RETURN_FAILED; };
}; virtual ReturnValue_t removeDataSet(sid_t sid) {
virtual ReturnValue_t changeCollectionInterval(sid_t sid, return HasReturnvaluesIF::RETURN_FAILED;
float newIntervalSeconds) { };
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_ */ #endif /* FSFW_DATAPOOLLOCAL_HASLOCALDATAPOOLIF_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,10 @@
#ifndef FSFW_DATAPOOLLOCAL_LOCALDATAPOOLMANAGER_H_ #ifndef FSFW_DATAPOOLLOCAL_LOCALDATAPOOLMANAGER_H_
#define FSFW_DATAPOOLLOCAL_LOCALDATAPOOLMANAGER_H_ #define FSFW_DATAPOOLLOCAL_LOCALDATAPOOLMANAGER_H_
#include "HasLocalDataPoolIF.h" #include "ProvidesDataPoolSubscriptionIF.h"
#include "AccessLocalPoolF.h"
#include "../serviceinterface/ServiceInterface.h"
#include "../housekeeping/HousekeepingPacketDownlink.h" #include "../housekeeping/HousekeepingPacketDownlink.h"
#include "../housekeeping/HousekeepingMessage.h" #include "../housekeeping/HousekeepingMessage.h"
#include "../housekeeping/PeriodicHousekeepingHelper.h" #include "../housekeeping/PeriodicHousekeepingHelper.h"
@ -15,6 +17,7 @@
#include "../ipc/MutexHelper.h" #include "../ipc/MutexHelper.h"
#include <map> #include <map>
#include <vector>
namespace Factory { namespace Factory {
void setStaticFrameworkObjectIds(); void setStaticFrameworkObjectIds();
@ -22,6 +25,8 @@ void setStaticFrameworkObjectIds();
class LocalPoolDataSetBase; class LocalPoolDataSetBase;
class HousekeepingPacketUpdate; class HousekeepingPacketUpdate;
class HasLocalDataPoolIF;
class LocalDataPool;
/** /**
* @brief This class is the managing instance for the local data pool. * @brief This class is the managing instance for the local data pool.
@ -47,22 +52,23 @@ class HousekeepingPacketUpdate;
* Each pool entry has a valid state too. * Each pool entry has a valid state too.
* @author R. Mueller * @author R. Mueller
*/ */
class LocalDataPoolManager { class LocalDataPoolManager: public ProvidesDataPoolSubscriptionIF,
template<typename T> friend class LocalPoolVariable; public AccessPoolManagerIF {
template<typename T, uint16_t vecSize> friend class LocalPoolVector;
friend class LocalPoolDataSetBase;
friend void (Factory::setStaticFrameworkObjectIds)(); 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: public:
static constexpr uint8_t INTERFACE_ID = CLASS_ID::HOUSEKEEPING_MANAGER; static constexpr uint8_t INTERFACE_ID = CLASS_ID::HOUSEKEEPING_MANAGER;
static constexpr ReturnValue_t POOL_ENTRY_NOT_FOUND = MAKE_RETURN_CODE(0x00); static constexpr ReturnValue_t QUEUE_OR_DESTINATION_INVALID = MAKE_RETURN_CODE(0);
static constexpr ReturnValue_t POOL_ENTRY_TYPE_CONFLICT = MAKE_RETURN_CODE(0x01);
static constexpr ReturnValue_t QUEUE_OR_DESTINATION_NOT_SET = MAKE_RETURN_CODE(0x02); 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);
static constexpr ReturnValue_t WRONG_HK_PACKET_TYPE = MAKE_RETURN_CODE(0x03);
static constexpr ReturnValue_t REPORTING_STATUS_UNCHANGED = MAKE_RETURN_CODE(0x04);
static constexpr ReturnValue_t PERIODIC_HELPER_INVALID = MAKE_RETURN_CODE(0x05);
/** /**
* This constructor is used by a class which wants to implement * This constructor is used by a class which wants to implement
@ -119,7 +125,7 @@ public:
*/ */
ReturnValue_t subscribeForPeriodicPacket(sid_t sid, bool enableReporting, ReturnValue_t subscribeForPeriodicPacket(sid_t sid, bool enableReporting,
float collectionInterval, bool isDiagnostics, float collectionInterval, bool isDiagnostics,
object_id_t packetDestination = defaultHkDestination); object_id_t packetDestination = defaultHkDestination) override;
/** /**
* @brief Subscribe for the generation of packets if the dataset * @brief Subscribe for the generation of packets if the dataset
@ -133,7 +139,7 @@ public:
*/ */
ReturnValue_t subscribeForUpdatePackets(sid_t sid, bool reportingEnabled, ReturnValue_t subscribeForUpdatePackets(sid_t sid, bool reportingEnabled,
bool isDiagnostics, bool isDiagnostics,
object_id_t packetDestination = defaultHkDestination); object_id_t packetDestination = defaultHkDestination) override;
/** /**
* @brief Subscribe for a notification message which will be sent * @brief Subscribe for a notification message which will be sent
@ -152,7 +158,7 @@ public:
ReturnValue_t subscribeForSetUpdateMessages(const uint32_t setId, ReturnValue_t subscribeForSetUpdateMessages(const uint32_t setId,
object_id_t destinationObject, object_id_t destinationObject,
MessageQueueId_t targetQueueId, MessageQueueId_t targetQueueId,
bool generateSnapshot); bool generateSnapshot) override;
/** /**
* @brief Subscribe for an notification message which will be sent if a * @brief Subscribe for an notification message which will be sent if a
@ -171,7 +177,9 @@ public:
ReturnValue_t subscribeForVariableUpdateMessages(const lp_id_t localPoolId, ReturnValue_t subscribeForVariableUpdateMessages(const lp_id_t localPoolId,
object_id_t destinationObject, object_id_t destinationObject,
MessageQueueId_t targetQueueId, MessageQueueId_t targetQueueId,
bool generateSnapshot); bool generateSnapshot) override;
MutexIF* getLocalPoolMutex() override;
/** /**
* Non-Diagnostics packets usually have a lower minimum sampling frequency * Non-Diagnostics packets usually have a lower minimum sampling frequency
@ -250,8 +258,18 @@ public:
LocalDataPoolManager(const LocalDataPoolManager &) = delete; LocalDataPoolManager(const LocalDataPoolManager &) = delete;
LocalDataPoolManager operator=(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;
virtual LocalDataPoolManager* getHkManagerHandle() override;
private: private:
LocalDataPool localPoolMap; localpool::DataPool localPoolMap;
//! Every housekeeping data manager has a mutex to protect access //! Every housekeeping data manager has a mutex to protect access
//! to it's data pool. //! to it's data pool.
MutexIF* mutex = nullptr; MutexIF* mutex = nullptr;
@ -370,6 +388,11 @@ private:
ReturnValue_t& status); ReturnValue_t& status);
ReturnValue_t addUpdateToStore(HousekeepingPacketUpdate& updatePacket, ReturnValue_t addUpdateToStore(HousekeepingPacketUpdate& updatePacket,
store_address_t& storeId); store_address_t& storeId);
void printWarningOrError(sif::OutputTypes outputType,
const char* functionName,
ReturnValue_t errorCode = HasReturnvaluesIF::RETURN_FAILED,
const char* errorPrint = nullptr);
}; };
@ -378,16 +401,16 @@ ReturnValue_t LocalDataPoolManager::fetchPoolEntry(lp_id_t localPoolId,
PoolEntry<T> **poolEntry) { PoolEntry<T> **poolEntry) {
auto poolIter = localPoolMap.find(localPoolId); auto poolIter = localPoolMap.find(localPoolId);
if (poolIter == localPoolMap.end()) { if (poolIter == localPoolMap.end()) {
sif::warning << "HousekeepingManager::fechPoolEntry: Pool entry " printWarningOrError(sif::OutputTypes::OUT_ERROR, "fetchPoolEntry",
"not found." << std::endl; localpool::POOL_ENTRY_NOT_FOUND);
return POOL_ENTRY_NOT_FOUND; return localpool::POOL_ENTRY_NOT_FOUND;
} }
*poolEntry = dynamic_cast< PoolEntry<T>* >(poolIter->second); *poolEntry = dynamic_cast< PoolEntry<T>* >(poolIter->second);
if(*poolEntry == nullptr) { if(*poolEntry == nullptr) {
sif::debug << "HousekeepingManager::fetchPoolEntry:" printWarningOrError(sif::OutputTypes::OUT_ERROR, "fetchPoolEntry",
" Pool entry not found." << std::endl; localpool::POOL_ENTRY_TYPE_CONFLICT);
return POOL_ENTRY_TYPE_CONFLICT; return localpool::POOL_ENTRY_TYPE_CONFLICT;
} }
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }

View File

@ -9,13 +9,13 @@ LocalDataSet::LocalDataSet(HasLocalDataPoolIF *hkOwner, uint32_t setId,
const size_t maxNumberOfVariables): const size_t maxNumberOfVariables):
LocalPoolDataSetBase(hkOwner, setId, nullptr, maxNumberOfVariables), LocalPoolDataSetBase(hkOwner, setId, nullptr, maxNumberOfVariables),
poolVarList(maxNumberOfVariables) { poolVarList(maxNumberOfVariables) {
this->setContainer(poolVarList.data()); this->setContainer(poolVarList.data());
} }
LocalDataSet::LocalDataSet(sid_t sid, const size_t maxNumberOfVariables): LocalDataSet::LocalDataSet(sid_t sid, const size_t maxNumberOfVariables):
LocalPoolDataSetBase(sid, nullptr, maxNumberOfVariables), LocalPoolDataSetBase(sid, nullptr, maxNumberOfVariables),
poolVarList(maxNumberOfVariables) { poolVarList(maxNumberOfVariables) {
this->setContainer(poolVarList.data()); this->setContainer(poolVarList.data());
} }
LocalDataSet::~LocalDataSet() {} LocalDataSet::~LocalDataSet() {}

View File

@ -7,7 +7,7 @@
class LocalDataSet: public LocalPoolDataSetBase { class LocalDataSet: public LocalPoolDataSetBase {
public: public:
LocalDataSet(HasLocalDataPoolIF* hkOwner, uint32_t setId, LocalDataSet(HasLocalDataPoolIF* hkOwner, uint32_t setId,
const size_t maxSize); const size_t maxSize);
LocalDataSet(sid_t sid, const size_t maxSize); LocalDataSet(sid_t sid, const size_t maxSize);
virtual~ LocalDataSet(); virtual~ LocalDataSet();

View File

@ -1,4 +1,8 @@
#include "LocalPoolDataSetBase.h" #include "LocalPoolDataSetBase.h"
#include "HasLocalDataPoolIF.h"
#include "internal/HasLocalDpIFUserAttorney.h"
#include "../serviceinterface/ServiceInterface.h"
#include "../datapoollocal/LocalDataPoolManager.h" #include "../datapoollocal/LocalDataPoolManager.h"
#include "../housekeeping/PeriodicHousekeepingHelper.h" #include "../housekeeping/PeriodicHousekeepingHelper.h"
#include "../serialize/SerializeAdapter.h" #include "../serialize/SerializeAdapter.h"
@ -8,22 +12,31 @@
LocalPoolDataSetBase::LocalPoolDataSetBase(HasLocalDataPoolIF *hkOwner, LocalPoolDataSetBase::LocalPoolDataSetBase(HasLocalDataPoolIF *hkOwner,
uint32_t setId, PoolVariableIF** registeredVariablesArray, uint32_t setId, PoolVariableIF** registeredVariablesArray,
const size_t maxNumberOfVariables, bool noPeriodicHandling): const size_t maxNumberOfVariables, bool periodicHandling):
PoolDataSetBase(registeredVariablesArray, maxNumberOfVariables) { PoolDataSetBase(registeredVariablesArray, maxNumberOfVariables) {
if(hkOwner == nullptr) { if(hkOwner == nullptr) {
// Configuration error. // Configuration error.
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "LocalPoolDataSetBase::LocalPoolDataSetBase: Owner " sif::error << "LocalPoolDataSetBase::LocalPoolDataSetBase: Owner "
<< "invalid!" << std::endl; << "invalid!" << std::endl;
#else
sif::printError("LocalPoolDataSetBase::LocalPoolDataSetBase: Owner "
"invalid!\n\r");
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
return; return;
} }
hkManager = hkOwner->getHkManagerHandle(); AccessPoolManagerIF* accessor = HasLocalDpIFUserAttorney::getAccessorHandle(hkOwner);
if(accessor != nullptr) {
poolManager = accessor->getHkManagerHandle();
mutexIfSingleDataCreator = accessor->getLocalPoolMutex();
}
this->sid.objectId = hkOwner->getObjectId(); this->sid.objectId = hkOwner->getObjectId();
this->sid.ownerSetId = setId; this->sid.ownerSetId = setId;
mutex = MutexFactory::instance()->createMutex();
// Data creators get a periodic helper for periodic HK data generation. // Data creators get a periodic helper for periodic HK data generation.
if(not noPeriodicHandling) { if(periodicHandling) {
periodicHelper = new PeriodicHousekeepingHelper(this); periodicHelper = new PeriodicHousekeepingHelper(this);
} }
} }
@ -31,27 +44,40 @@ LocalPoolDataSetBase::LocalPoolDataSetBase(HasLocalDataPoolIF *hkOwner,
LocalPoolDataSetBase::LocalPoolDataSetBase(sid_t sid, LocalPoolDataSetBase::LocalPoolDataSetBase(sid_t sid,
PoolVariableIF** registeredVariablesArray, PoolVariableIF** registeredVariablesArray,
const size_t maxNumberOfVariables): const size_t maxNumberOfVariables):
PoolDataSetBase(registeredVariablesArray, maxNumberOfVariables) { PoolDataSetBase(registeredVariablesArray, maxNumberOfVariables) {
HasLocalDataPoolIF* hkOwner = objectManager->get<HasLocalDataPoolIF>( HasLocalDataPoolIF* hkOwner = objectManager->get<HasLocalDataPoolIF>(
sid.objectId); sid.objectId);
if(hkOwner == nullptr) { if(hkOwner != nullptr) {
// Configuration error. AccessPoolManagerIF* accessor = HasLocalDpIFUserAttorney::getAccessorHandle(hkOwner);
sif::error << "LocalPoolDataSetBase::LocalPoolDataSetBase: Owner " if(accessor != nullptr) {
<< "invalid!" << std::endl; mutexIfSingleDataCreator = accessor->getLocalPoolMutex();
return; }
} }
hkManager = hkOwner->getHkManagerHandle();
this->sid = sid;
mutex = MutexFactory::instance()->createMutex(); this->sid = sid;
} }
LocalPoolDataSetBase::LocalPoolDataSetBase(
PoolVariableIF **registeredVariablesArray,
const size_t maxNumberOfVariables, bool protectEveryReadCommitCall):
PoolDataSetBase(registeredVariablesArray, maxNumberOfVariables) {
this->setReadCommitProtectionBehaviour(protectEveryReadCommitCall);
}
LocalPoolDataSetBase::~LocalPoolDataSetBase() { LocalPoolDataSetBase::~LocalPoolDataSetBase() {
if(periodicHelper != nullptr) {
delete periodicHelper;
}
} }
ReturnValue_t LocalPoolDataSetBase::lockDataPool(uint32_t timeoutMs) { ReturnValue_t LocalPoolDataSetBase::lockDataPool(
MutexIF* mutex = hkManager->getMutexHandle(); MutexIF::TimeoutType timeoutType,
return mutex->lockMutex(MutexIF::TimeoutType::WAITING, timeoutMs); uint32_t timeoutMs) {
if(mutexIfSingleDataCreator != nullptr) {
return mutexIfSingleDataCreator->lockMutex(timeoutType, timeoutMs);
}
return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t LocalPoolDataSetBase::serializeWithValidityBuffer(uint8_t **buffer, ReturnValue_t LocalPoolDataSetBase::serializeWithValidityBuffer(uint8_t **buffer,
@ -127,8 +153,10 @@ ReturnValue_t LocalPoolDataSetBase::deSerializeWithValidityBuffer(
} }
ReturnValue_t LocalPoolDataSetBase::unlockDataPool() { ReturnValue_t LocalPoolDataSetBase::unlockDataPool() {
MutexIF* mutex = hkManager->getMutexHandle(); if(mutexIfSingleDataCreator != nullptr) {
return mutex->unlockMutex(); return mutexIfSingleDataCreator->unlockMutex();
}
return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t LocalPoolDataSetBase::serializeLocalPoolIds(uint8_t** buffer, ReturnValue_t LocalPoolDataSetBase::serializeLocalPoolIds(uint8_t** buffer,
@ -145,8 +173,13 @@ ReturnValue_t LocalPoolDataSetBase::serializeLocalPoolIds(uint8_t** buffer,
auto result = SerializeAdapter::serialize(&currentPoolId, buffer, auto result = SerializeAdapter::serialize(&currentPoolId, buffer,
size, maxSize, streamEndianness); size, maxSize, streamEndianness);
if(result != HasReturnvaluesIF::RETURN_OK) { if(result != HasReturnvaluesIF::RETURN_OK) {
sif::warning << "LocalDataSet::serializeLocalPoolIds: Serialization" #if FSFW_CPP_OSTREAM_ENABLED == 1
" error!" << std::endl; 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 result;
} }
} }
@ -204,8 +237,13 @@ ReturnValue_t LocalPoolDataSetBase::serialize(uint8_t **buffer, size_t *size,
void LocalPoolDataSetBase::bitSetter(uint8_t* byte, uint8_t position) const { void LocalPoolDataSetBase::bitSetter(uint8_t* byte, uint8_t position) const {
if(position > 7) { if(position > 7) {
sif::debug << "Pool Raw Access: Bit setting invalid position" #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "LocalPoolDataSetBase::bitSetter: Invalid position!"
<< std::endl; << std::endl;
#else
sif::printWarning("LocalPoolDataSetBase::bitSetter: "
"Invalid position!\n\r");
#endif
return; return;
} }
uint8_t shiftNumber = position + (7 - 2 * position); uint8_t shiftNumber = position + (7 - 2 * position);
@ -236,14 +274,10 @@ void LocalPoolDataSetBase::initializePeriodicHelper(
} }
void LocalPoolDataSetBase::setChanged(bool changed) { void LocalPoolDataSetBase::setChanged(bool changed) {
// TODO: Make this configurable?
MutexHelper(mutex, MutexIF::TimeoutType::WAITING, 20);
this->changed = changed; this->changed = changed;
} }
bool LocalPoolDataSetBase::hasChanged() const { bool LocalPoolDataSetBase::hasChanged() const {
// TODO: Make this configurable?
MutexHelper(mutex, MutexIF::TimeoutType::WAITING, 20);
return changed; return changed;
} }
@ -254,8 +288,10 @@ sid_t LocalPoolDataSetBase::getSid() const {
bool LocalPoolDataSetBase::bitGetter(const uint8_t* byte, bool LocalPoolDataSetBase::bitGetter(const uint8_t* byte,
uint8_t position) const { uint8_t position) const {
if(position > 7) { if(position > 7) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "Pool Raw Access: Bit setting invalid position" sif::debug << "Pool Raw Access: Bit setting invalid position"
<< std::endl; << std::endl;
#endif
return false; return false;
} }
uint8_t shiftNumber = position + (7 - 2 * position); uint8_t shiftNumber = position + (7 - 2 * position);
@ -263,12 +299,10 @@ bool LocalPoolDataSetBase::bitGetter(const uint8_t* byte,
} }
bool LocalPoolDataSetBase::isValid() const { bool LocalPoolDataSetBase::isValid() const {
MutexHelper(mutex, MutexIF::TimeoutType::WAITING, 5);
return this->valid; return this->valid;
} }
void LocalPoolDataSetBase::setValidity(bool valid, bool setEntriesRecursively) { void LocalPoolDataSetBase::setValidity(bool valid, bool setEntriesRecursively) {
MutexHelper(mutex, MutexIF::TimeoutType::WAITING, 5);
if(setEntriesRecursively) { if(setEntriesRecursively) {
for(size_t idx = 0; idx < this->getFillCount(); idx++) { for(size_t idx = 0; idx < this->getFillCount(); idx++) {
registeredVariables[idx] -> setValid(valid); registeredVariables[idx] -> setValid(valid);
@ -276,3 +310,10 @@ void LocalPoolDataSetBase::setValidity(bool valid, bool setEntriesRecursively) {
} }
this->valid = valid; this->valid = valid;
} }
object_id_t LocalPoolDataSetBase::getCreatorObjectId() {
if(poolManager != nullptr) {
return poolManager->getCreatorObjectId();
}
return objects::NO_OBJECT;
}

View File

@ -1,16 +1,16 @@
#ifndef FSFW_DATAPOOLLOCAL_LOCALPOOLDATASETBASE_H_ #ifndef FSFW_DATAPOOLLOCAL_LOCALPOOLDATASETBASE_H_
#define FSFW_DATAPOOLLOCAL_LOCALPOOLDATASETBASE_H_ #define FSFW_DATAPOOLLOCAL_LOCALPOOLDATASETBASE_H_
#include "HasLocalDataPoolIF.h"
#include "MarkChangedIF.h" #include "MarkChangedIF.h"
#include "localPoolDefinitions.h"
#include "../datapool/DataSetIF.h" #include "../datapool/DataSetIF.h"
#include "../datapool/PoolDataSetBase.h" #include "../datapool/PoolDataSetBase.h"
#include "../serialize/SerializeIF.h"
#include <vector> #include <vector>
class LocalDataPoolManager; class LocalDataPoolManager;
class HasLocalDataPoolIF;
class PeriodicHousekeepingHelper; class PeriodicHousekeepingHelper;
/** /**
@ -41,156 +41,185 @@ class PeriodicHousekeepingHelper;
* *
* @ingroup data_pool * @ingroup data_pool
*/ */
class LocalPoolDataSetBase: public PoolDataSetBase, class LocalPoolDataSetBase:
public PoolDataSetBase,
public MarkChangedIF { public MarkChangedIF {
friend class LocalDataPoolManager; friend class LocalPoolDataSetAttorney;
friend class PeriodicHousekeepingHelper; friend class PeriodicHousekeepingHelper;
public: public:
/** /**
* @brief Constructor for the creator of local pool data. * @brief Constructor for the creator of local pool data.
* @details * @details
* This constructor also initializes the components required for * This constructor also initializes the components required for
* periodic handling. * periodic handling.
*/ */
LocalPoolDataSetBase(HasLocalDataPoolIF *hkOwner, LocalPoolDataSetBase(HasLocalDataPoolIF *hkOwner,
uint32_t setId, PoolVariableIF** registeredVariablesArray, uint32_t setId, PoolVariableIF** registeredVariablesArray,
const size_t maxNumberOfVariables, bool noPeriodicHandling = false); const size_t maxNumberOfVariables, bool periodicHandling = true);
/** /**
* @brief Constructor for users of local pool data. * @brief Constructor for users of the local pool data, which need
* @details * to access data created by one (!) HK manager.
* @param sid Unique identifier of dataset consisting of object ID and * @details
* set ID. * Unlike the first constructor, no component for periodic handling
* @param registeredVariablesArray * will be initiated.
* @param maxNumberOfVariables * @param sid Unique identifier of dataset consisting of object ID and
*/ * set ID.
LocalPoolDataSetBase(sid_t sid, PoolVariableIF** registeredVariablesArray, * @param registeredVariablesArray
const size_t maxNumberOfVariables); * @param maxNumberOfVariables
*/
LocalPoolDataSetBase(sid_t sid, PoolVariableIF** registeredVariablesArray,
const size_t maxNumberOfVariables);
/** /**
* @brief The destructor automatically manages writing the valid * @brief Simple constructor, if the dataset is not the owner by
* information of variables. * a class with a HK manager.
* @details * @details
* In case the data set was read out, but not committed(indicated by state), * This constructor won't create components required for periodic handling
* the destructor parses all variables that are still registered to the set. * and it also won't try to deduce the HK manager because no SID is
* For each, the valid flag in the data pool is set to "invalid". * supplied. This function should therefore be called by classes which need
*/ * to access pool variables from different creators.
~LocalPoolDataSetBase(); *
* 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);
void setValidityBufferGeneration(bool withValidityBuffer); /**
* @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();
sid_t getSid() const; void setValidityBufferGeneration(bool withValidityBuffer);
/** SerializeIF overrides */ sid_t getSid() const;
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;
/** /** SerializeIF overrides */
* Special version of the serilization function which appends a ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
* validity buffer at the end. Each bit of this validity buffer SerializeIF::Endianness streamEndianness) const override;
* denotes whether the container data set entries are valid from left ReturnValue_t deSerialize(const uint8_t** buffer, size_t *size,
* to right, MSB first. (length = ceil(N/8), N = number of pool variables) SerializeIF::Endianness streamEndianness) override;
* @param buffer size_t getSerializedSize() const override;
* @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. * Special version of the serilization function which appends a
* @param setEntriesRecursively * validity buffer at the end. Each bit of this validity buffer
* If this is true, all contained datasets will also be set recursively. * denotes whether the container data set entries are valid from left
*/ * to right, MSB first. (length = ceil(N/8), N = number of pool variables)
void setValidity(bool valid, bool setEntriesRecursively); * @param buffer
bool isValid() const override; * @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;
/** /**
* These calls are mutex protected. * Set the dataset valid or invalid. These calls are mutex protected.
* @param changed * @param setEntriesRecursively
*/ * If this is true, all contained datasets will also be set recursively.
void setChanged(bool changed) override; */
bool hasChanged() const override; 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();
protected: protected:
sid_t sid; sid_t sid;
MutexIF* mutex = nullptr; //! This mutex is used if the data is created by one object only.
MutexIF* mutexIfSingleDataCreator = nullptr;
bool diagnostic = false; bool diagnostic = false;
void setDiagnostic(bool diagnostics); void setDiagnostic(bool diagnostics);
bool isDiagnostics() const; bool isDiagnostics() const;
/** /**
* Used for periodic generation. * Used for periodic generation.
*/ */
bool reportingEnabled = false; bool reportingEnabled = false;
void setReportingEnabled(bool enabled); void setReportingEnabled(bool enabled);
bool getReportingEnabled() const; bool getReportingEnabled() const;
void initializePeriodicHelper(float collectionInterval, void initializePeriodicHelper(float collectionInterval,
dur_millis_t minimumPeriodicInterval, dur_millis_t minimumPeriodicInterval,
bool isDiagnostics, uint8_t nonDiagIntervalFactor = 5); bool isDiagnostics, uint8_t nonDiagIntervalFactor = 5);
/** /**
* If the valid state of a dataset is always relevant to the whole * If the valid state of a dataset is always relevant to the whole
* data set we can use this flag. * data set we can use this flag.
*/ */
bool valid = false; bool valid = false;
/** /**
* Can be used to mark the dataset as changed, which is used * Can be used to mark the dataset as changed, which is used
* by the LocalDataPoolManager to send out update messages. * by the LocalDataPoolManager to send out update messages.
*/ */
bool changed = false; bool changed = false;
/** /**
* Specify whether the validity buffer is serialized too when serializing * Specify whether the validity buffer is serialized too when serializing
* or deserializing the packet. Each bit of the validity buffer will * or deserializing the packet. Each bit of the validity buffer will
* contain the validity state of the pool variables from left to right. * 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 * The size of validity buffer thus will be ceil(N / 8) with N = number of
* pool variables. * pool variables.
*/ */
bool withValidityBuffer = true; bool withValidityBuffer = true;
/** /**
* @brief This is a small helper function to facilitate locking * @brief This is a small helper function to facilitate locking
* the global data pool. * the global data pool.
* @details * @details
* It makes use of the lockDataPool method offered by the DataPool class. * It makes use of the lockDataPool method offered by the DataPool class.
*/ */
ReturnValue_t lockDataPool(uint32_t timeoutMs) override; 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;
LocalDataPoolManager* hkManager; /**
* @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;
/** /**
* Set n-th bit of a byte, with n being the position from 0 * Set n-th bit of a byte, with n being the position from 0
* (most significant bit) to 7 (least significant bit) * (most significant bit) to 7 (least significant bit)
*/ */
void bitSetter(uint8_t* byte, uint8_t position) const; void bitSetter(uint8_t* byte, uint8_t position) const;
bool bitGetter(const uint8_t* byte, uint8_t position) const; bool bitGetter(const uint8_t* byte, uint8_t position) const;
PeriodicHousekeepingHelper* periodicHelper = nullptr; PeriodicHousekeepingHelper* periodicHelper = nullptr;
LocalDataPoolManager* poolManager = nullptr;
}; };

View File

@ -1,40 +1,58 @@
#include "LocalPoolObjectBase.h" #include "LocalPoolObjectBase.h"
#include "LocalDataPoolManager.h"
#include "internal/HasLocalDpIFUserAttorney.h"
#include "HasLocalDataPoolIF.h"
LocalPoolObjectBase::LocalPoolObjectBase(lp_id_t poolId, #include "../objectmanager/ObjectManagerIF.h"
HasLocalDataPoolIF* hkOwner, DataSetIF* dataSet,
pool_rwm_t setReadWriteMode): localPoolId(poolId), LocalPoolObjectBase::LocalPoolObjectBase(lp_id_t poolId, HasLocalDataPoolIF* hkOwner,
readWriteMode(setReadWriteMode) { DataSetIF* dataSet, pool_rwm_t setReadWriteMode):
localPoolId(poolId), readWriteMode(setReadWriteMode) {
if(poolId == PoolVariableIF::NO_PARAMETER) { if(poolId == PoolVariableIF::NO_PARAMETER) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "LocalPoolVar<T>::LocalPoolVar: 0 passed as pool ID, " sif::warning << "LocalPoolVar<T>::LocalPoolVar: 0 passed as pool ID, "
<< "which is the NO_PARAMETER value!" << std::endl; << "which is the NO_PARAMETER value!" << std::endl;
#endif
} }
if(hkOwner == nullptr) { if(hkOwner == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "LocalPoolVar<T>::LocalPoolVar: The supplied pool " sif::error << "LocalPoolVar<T>::LocalPoolVar: The supplied pool "
<< "owner is a invalid!" << std::endl; << "owner is a invalid!" << std::endl;
#endif
return; return;
} }
hkManager = hkOwner->getHkManagerHandle(); AccessPoolManagerIF* poolManAccessor = HasLocalDpIFUserAttorney::getAccessorHandle(hkOwner);
hkManager = poolManAccessor->getHkManagerHandle();
if (dataSet != nullptr) { if (dataSet != nullptr) {
dataSet->registerVariable(this); dataSet->registerVariable(this);
} }
} }
LocalPoolObjectBase::LocalPoolObjectBase(object_id_t poolOwner, lp_id_t poolId, LocalPoolObjectBase::LocalPoolObjectBase(object_id_t poolOwner, lp_id_t poolId, DataSetIF *dataSet,
DataSetIF *dataSet, pool_rwm_t setReadWriteMode): localPoolId(poolId), pool_rwm_t setReadWriteMode):
readWriteMode(setReadWriteMode) { localPoolId(poolId), readWriteMode(setReadWriteMode) {
if(poolId == PoolVariableIF::NO_PARAMETER) { if(poolId == PoolVariableIF::NO_PARAMETER) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "LocalPoolVar<T>::LocalPoolVar: 0 passed as pool ID, " sif::warning << "LocalPoolVar<T>::LocalPoolVar: 0 passed as pool ID, "
<< "which is the NO_PARAMETER value!" << std::endl; << "which is the NO_PARAMETER value!" << std::endl;
#endif
} }
HasLocalDataPoolIF* hkOwner = HasLocalDataPoolIF* hkOwner = objectManager->get<HasLocalDataPoolIF>(poolOwner);
objectManager->get<HasLocalDataPoolIF>(poolOwner);
if(hkOwner == nullptr) { if(hkOwner == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "LocalPoolVariable: The supplied pool owner did not " sif::error << "LocalPoolVariable: The supplied pool owner did not "
<< "implement the correct interface" << "implement the correct interface"
<< " HasLocalDataPoolIF!" << std::endl; << " HasLocalDataPoolIF!" << std::endl;
#endif
return; return;
} }
hkManager = hkOwner->getHkManagerHandle();
AccessPoolManagerIF* accessor = HasLocalDpIFUserAttorney::getAccessorHandle(hkOwner);
if(accessor != nullptr) {
hkManager = accessor->getHkManagerHandle();
}
if(dataSet != nullptr) { if(dataSet != nullptr) {
dataSet->registerVariable(this); dataSet->registerVariable(this);
} }
@ -69,5 +87,44 @@ bool LocalPoolObjectBase::hasChanged() const {
} }
void LocalPoolObjectBase::setReadWriteMode(pool_rwm_t newReadWriteMode) { void LocalPoolObjectBase::setReadWriteMode(pool_rwm_t newReadWriteMode) {
this->readWriteMode = 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* 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 << variableType << ": " << 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",
variableType, type, errMsg, objectId, lpId);
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
#endif /* FSFW_DISABLE_PRINTOUT == 0 */
} }

View File

@ -2,10 +2,20 @@
#define FSFW_DATAPOOLLOCAL_LOCALPOOLOBJECTBASE_H_ #define FSFW_DATAPOOLLOCAL_LOCALPOOLOBJECTBASE_H_
#include "MarkChangedIF.h" #include "MarkChangedIF.h"
#include "../datapoollocal/LocalDataPoolManager.h" #include "localPoolDefinitions.h"
#include "../objectmanager/SystemObjectIF.h"
#include "../datapool/PoolVariableIF.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, class LocalPoolObjectBase: public PoolVariableIF,
public HasReturnvaluesIF, public HasReturnvaluesIF,
public MarkChangedIF { public MarkChangedIF {
@ -54,10 +64,10 @@ protected:
ReadWriteMode_t readWriteMode = pool_rwm_t::VAR_READ_WRITE; ReadWriteMode_t readWriteMode = pool_rwm_t::VAR_READ_WRITE;
//! @brief Pointer to the class which manages the HK pool. //! @brief Pointer to the class which manages the HK pool.
LocalDataPoolManager* hkManager; 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_ */ #endif /* FSFW_DATAPOOLLOCAL_LOCALPOOLOBJECTBASE_H_ */

View File

@ -4,9 +4,12 @@
#include "LocalPoolObjectBase.h" #include "LocalPoolObjectBase.h"
#include "HasLocalDataPoolIF.h" #include "HasLocalDataPoolIF.h"
#include "LocalDataPoolManager.h" #include "LocalDataPoolManager.h"
#include "AccessLocalPoolF.h"
#include "internal/LocalDpManagerAttorney.h"
#include "../datapool/PoolVariableIF.h" #include "../datapool/PoolVariableIF.h"
#include "../datapool/DataSetIF.h" #include "../datapool/DataSetIF.h"
#include "../serviceinterface/ServiceInterface.h"
#include "../objectmanager/ObjectManagerIF.h" #include "../objectmanager/ObjectManagerIF.h"
#include "../serialize/SerializeAdapter.h" #include "../serialize/SerializeAdapter.h"
@ -24,145 +27,160 @@
template<typename T> template<typename T>
class LocalPoolVariable: public LocalPoolObjectBase { class LocalPoolVariable: public LocalPoolObjectBase {
public: public:
//! Default ctor is forbidden. //! Default ctor is forbidden.
LocalPoolVariable() = delete; LocalPoolVariable() = delete;
/** /**
* This constructor is used by the data creators to have pool variable * This constructor is used by the data creators to have pool variable
* instances which can also be stored in datasets. * instances which can also be stored in datasets.
* *
* It does not fetch the current value from the data pool, which * It does not fetch the current value from the data pool, which
* has to be done by calling the read() operation. * has to be done by calling the read() operation.
* Datasets can be used to access multiple local pool entries in an * Datasets can be used to access multiple local pool entries in an
* efficient way. A pointer to a dataset can be passed to register * efficient way. A pointer to a dataset can be passed to register
* the pool variable in that dataset directly. * the pool variable in that dataset directly.
* @param poolId ID of the local pool entry. * @param poolId ID of the local pool entry.
* @param hkOwner Pointer of the owner. This will generally be the calling * @param hkOwner Pointer of the owner. This will generally be the calling
* class itself which passes "this". * class itself which passes "this".
* @param dataSet The data set in which the variable shall register itself. * @param dataSet The data set in which the variable shall register itself.
* If nullptr, the variable is not registered. * If nullptr, the variable is not registered.
* @param setReadWriteMode Specify the read-write mode of the pool variable. * @param setReadWriteMode Specify the read-write mode of the pool variable.
*/ */
LocalPoolVariable(HasLocalDataPoolIF* hkOwner, lp_id_t poolId, LocalPoolVariable(HasLocalDataPoolIF* hkOwner, lp_id_t poolId,
DataSetIF* dataSet = nullptr, DataSetIF* dataSet = nullptr,
pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE); pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE);
/** /**
* This constructor is used by data users like controllers to have * This constructor is used by data users like controllers to have
* access to the local pool variables of data creators by supplying * access to the local pool variables of data creators by supplying
* the respective creator object ID. * the respective creator object ID.
* *
* It does not fetch the current value from the data pool, which * It does not fetch the current value from the data pool, which
* has to be done by calling the read() operation. * has to be done by calling the read() operation.
* Datasets can be used to access multiple local pool entries in an * Datasets can be used to access multiple local pool entries in an
* efficient way. A pointer to a dataset can be passed to register * efficient way. A pointer to a dataset can be passed to register
* the pool variable in that dataset directly. * the pool variable in that dataset directly.
* @param poolId ID of the local pool entry. * @param poolId ID of the local pool entry.
* @param hkOwner object ID of the pool owner. * @param hkOwner object ID of the pool owner.
* @param dataSet The data set in which the variable shall register itself. * @param dataSet The data set in which the variable shall register itself.
* If nullptr, the variable is not registered. * If nullptr, the variable is not registered.
* @param setReadWriteMode Specify the read-write mode of the pool variable. * @param setReadWriteMode Specify the read-write mode of the pool variable.
* *
*/ */
LocalPoolVariable(object_id_t poolOwner, lp_id_t poolId, LocalPoolVariable(object_id_t poolOwner, lp_id_t poolId,
DataSetIF* dataSet = nullptr, DataSetIF* dataSet = nullptr,
pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE); pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE);
/** /**
* Variation which takes the global unique identifier of a pool variable. * Variation which takes the global unique identifier of a pool variable.
* @param globalPoolId * @param globalPoolId
* @param dataSet * @param dataSet
* @param setReadWriteMode * @param setReadWriteMode
*/ */
LocalPoolVariable(gp_id_t globalPoolId, DataSetIF* dataSet = nullptr, LocalPoolVariable(gp_id_t globalPoolId, DataSetIF* dataSet = nullptr,
pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE); pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE);
virtual~ LocalPoolVariable() {}; virtual~ LocalPoolVariable() {};
/** /**
* @brief This is the local copy of the data pool entry. * @brief This is the local copy of the data pool entry.
* @details The user can work on this attribute * @details The user can work on this attribute
* just like he would on a simple local variable. * just like he would on a simple local variable.
*/ */
T value = 0; T value = 0;
ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
SerializeIF::Endianness streamEndianness) const override; SerializeIF::Endianness streamEndianness) const override;
virtual size_t getSerializedSize() const override; virtual size_t getSerializedSize() const override;
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
SerializeIF::Endianness streamEndianness) override; SerializeIF::Endianness streamEndianness) override;
/** /**
* @brief This is a call to read the array's values * @brief This is a call to read the array's values
* from the global data pool. * from the global data pool.
* @details * @details
* When executed, this operation tries to fetch the pool entry with matching * 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 * data pool id from the data pool and copies all array values and the valid
* information to its local attributes. * information to its local attributes.
* In case of a failure (wrong type, size or pool id not found), the * In case of a failure (wrong type, size or pool id not found), the
* variable is set to zero and invalid. * variable is set to zero and invalid.
* The read call is protected with a lock. * The read call is protected with a lock.
* It is recommended to use DataSets to read and commit multiple variables * It is recommended to use DataSets to read and commit multiple variables
* at once to avoid the overhead of unnecessary lock und unlock operations. * at once to avoid the overhead of unnecessary lock und unlock operations.
* *
*/ */
ReturnValue_t read(dur_millis_t lockTimeout = MutexIF::BLOCKING) override; ReturnValue_t read(MutexIF::TimeoutType timeoutType =
/** MutexIF::TimeoutType::WAITING,
* @brief The commit call copies the array values back to the data pool. uint32_t timeoutMs = 20) override;
* @details /**
* It checks type and size, as well as if the variable is writable. If so, * @brief The commit call copies the array values back to the data pool.
* the value is copied and the local valid flag is written back as well. * @details
* The read call is protected with a lock. * It checks type and size, as well as if the variable is writable. If so,
* It is recommended to use DataSets to read and commit multiple variables * the value is copied and the local valid flag is written back as well.
* at once to avoid the overhead of unnecessary lock und unlock operations. * The read call is protected with a lock.
*/ * It is recommended to use DataSets to read and commit multiple variables
ReturnValue_t commit(dur_millis_t lockTimeout = MutexIF::BLOCKING) override; * 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 T& newValue);
LocalPoolVariable<T> &operator=(const LocalPoolVariable<T>& newPoolVariable); LocalPoolVariable<T> &operator=(const LocalPoolVariable<T>& newPoolVariable);
//! Explicit type conversion operator. Allows casting the class to //! Explicit type conversion operator. Allows casting the class to
//! its template type to perform operations on value. //! its template type to perform operations on value.
explicit operator T() const; explicit operator T() const;
bool operator==(const LocalPoolVariable<T>& other) const; bool operator==(const LocalPoolVariable<T>& other) const;
bool operator==(const T& other) const; bool operator==(const T& other) const;
bool operator!=(const LocalPoolVariable<T>& other) const; bool operator!=(const LocalPoolVariable<T>& other) const;
bool operator!=(const T& other) const; bool operator!=(const T& other) const;
bool operator<(const LocalPoolVariable<T>& other) const; bool operator<(const LocalPoolVariable<T>& other) const;
bool operator<(const T& other) const; bool operator<(const T& other) const;
bool operator>(const LocalPoolVariable<T>& other) const; bool operator>(const LocalPoolVariable<T>& other) const;
bool operator>(const T& other) const; bool operator>(const T& other) const;
protected: protected:
/** /**
* @brief Like #read, but without a lock protection of the global pool. * @brief Like #read, but without a lock protection of the global pool.
* @details * @details
* The operation does NOT provide any mutual exclusive protection by itself. * 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 * This can be used if the lock is handled externally to avoid the overhead
* of consecutive lock und unlock operations. * of consecutive lock und unlock operations.
* Declared protected to discourage free public usage. * Declared protected to discourage free public usage.
*/ */
ReturnValue_t readWithoutLock() override; ReturnValue_t readWithoutLock() override;
/** /**
* @brief Like #commit, but without a lock protection of the global pool. * @brief Like #commit, but without a lock protection of the global pool.
* @details * @details
* The operation does NOT provide any mutual exclusive protection by itself. * 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 * This can be used if the lock is handled externally to avoid the overhead
* of consecutive lock und unlock operations. * of consecutive lock und unlock operations.
* Declared protected to discourage free public usage. * Declared protected to discourage free public usage.
*/ */
ReturnValue_t commitWithoutLock() override; ReturnValue_t commitWithoutLock() override;
// std::ostream is the type for object std::cout #if FSFW_CPP_OSTREAM_ENABLED == 1
template <typename U> // std::ostream is the type for object std::cout
friend std::ostream& operator<< (std::ostream &out, template <typename U>
const LocalPoolVariable<U> &var); friend std::ostream& operator<< (std::ostream &out,
const LocalPoolVariable<U> &var);
private: #endif
}; };
#include "LocalPoolVariable.tpp" #include "LocalPoolVariable.tpp"

View File

@ -7,163 +7,196 @@
template<typename T> template<typename T>
inline LocalPoolVariable<T>::LocalPoolVariable(HasLocalDataPoolIF* hkOwner, inline LocalPoolVariable<T>::LocalPoolVariable(HasLocalDataPoolIF* hkOwner,
lp_id_t poolId, DataSetIF* dataSet, pool_rwm_t setReadWriteMode): lp_id_t poolId, DataSetIF* dataSet, pool_rwm_t setReadWriteMode):
LocalPoolObjectBase(poolId, hkOwner, dataSet, setReadWriteMode) {} LocalPoolObjectBase(poolId, hkOwner, dataSet, setReadWriteMode) {}
template<typename T> template<typename T>
inline LocalPoolVariable<T>::LocalPoolVariable(object_id_t poolOwner, lp_id_t poolId, inline LocalPoolVariable<T>::LocalPoolVariable(object_id_t poolOwner,
DataSetIF *dataSet, pool_rwm_t setReadWriteMode): lp_id_t poolId, DataSetIF *dataSet, pool_rwm_t setReadWriteMode):
LocalPoolObjectBase(poolOwner, poolId, dataSet, setReadWriteMode) {} LocalPoolObjectBase(poolOwner, poolId, dataSet, setReadWriteMode) {}
template<typename T> template<typename T>
inline LocalPoolVariable<T>::LocalPoolVariable(gp_id_t globalPoolId, DataSetIF *dataSet, inline LocalPoolVariable<T>::LocalPoolVariable(gp_id_t globalPoolId,
pool_rwm_t setReadWriteMode): DataSetIF *dataSet, pool_rwm_t setReadWriteMode):
LocalPoolObjectBase(globalPoolId.objectId, globalPoolId.localPoolId, LocalPoolObjectBase(globalPoolId.objectId, globalPoolId.localPoolId,
dataSet, setReadWriteMode){} dataSet, setReadWriteMode){}
template<typename T> template<typename T>
inline ReturnValue_t LocalPoolVariable<T>::read(dur_millis_t lockTimeout) { inline ReturnValue_t LocalPoolVariable<T>::read(
MutexHelper(hkManager->getMutexHandle(), MutexIF::TimeoutType::WAITING, MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) {
lockTimeout); MutexHelper(LocalDpManagerAttorney::getMutexHandle(*hkManager), timeoutType, timeoutMs);
return readWithoutLock(); return readWithoutLock();
} }
template<typename T> template<typename T>
inline ReturnValue_t LocalPoolVariable<T>::readWithoutLock() { inline ReturnValue_t LocalPoolVariable<T>::readWithoutLock() {
if(readWriteMode == pool_rwm_t::VAR_WRITE) { if(readWriteMode == pool_rwm_t::VAR_WRITE) {
sif::debug << "LocalPoolVar: Invalid read write " object_id_t targetObjectId = hkManager->getCreatorObjectId();
"mode for read() call." << std::endl; reportReadCommitError("LocalPoolVector",
return PoolVariableIF::INVALID_READ_WRITE_MODE; PoolVariableIF::INVALID_READ_WRITE_MODE, true, targetObjectId,
} localPoolId);
return PoolVariableIF::INVALID_READ_WRITE_MODE;
}
PoolEntry<T>* poolEntry = nullptr; PoolEntry<T>* poolEntry = nullptr;
ReturnValue_t result = hkManager->fetchPoolEntry(localPoolId, &poolEntry); ReturnValue_t result = LocalDpManagerAttorney::fetchPoolEntry(*hkManager, localPoolId,
if(result != RETURN_OK and poolEntry != nullptr) { &poolEntry);
sif::error << "PoolVector: Read of local pool variable of object " //ReturnValue_t result = hkManager->fetchPoolEntry(localPoolId, &poolEntry);
"0x" << std::hex << std::setw(8) << std::setfill('0') << if(result != RETURN_OK) {
hkManager->getOwner() << " and lp ID 0x" << localPoolId << object_id_t ownerObjectId = hkManager->getCreatorObjectId();
std::dec << " failed.\n" << std::flush; reportReadCommitError("LocalPoolVariable", result,
return result; false, ownerObjectId, localPoolId);
} return result;
this->value = *(poolEntry->address); }
this->valid = poolEntry->valid;
return RETURN_OK; // Actually this should never happen..
// if(poolEntry->address == nullptr) {
// result = PoolVariableIF::INVALID_POOL_ENTRY;
// object_id_t ownerObjectId = hkManager->getOwner()->getObjectId();
// reportReadCommitError("LocalPoolVariable", result,
// false, ownerObjectId, localPoolId);
// return result;
// }
this->value = *(poolEntry->getDataPtr());
this->valid = poolEntry->getValid();
return RETURN_OK;
} }
template<typename T> template<typename T>
inline ReturnValue_t LocalPoolVariable<T>::commit(dur_millis_t lockTimeout) { inline ReturnValue_t LocalPoolVariable<T>::commit(bool setValid,
MutexHelper(hkManager->getMutexHandle(), MutexIF::TimeoutType::WAITING, MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) {
lockTimeout); this->setValid(setValid);
return commitWithoutLock(); return commit(timeoutType, timeoutMs);
}
template<typename T>
inline ReturnValue_t LocalPoolVariable<T>::commit(
MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) {
MutexHelper(LocalDpManagerAttorney::getMutexHandle(*hkManager), timeoutType, timeoutMs);
return commitWithoutLock();
} }
template<typename T> template<typename T>
inline ReturnValue_t LocalPoolVariable<T>::commitWithoutLock() { inline ReturnValue_t LocalPoolVariable<T>::commitWithoutLock() {
if(readWriteMode == pool_rwm_t::VAR_READ) { if(readWriteMode == pool_rwm_t::VAR_READ) {
sif::debug << "LocalPoolVar: Invalid read write " object_id_t targetObjectId = hkManager->getCreatorObjectId();
"mode for commit() call." << std::endl; reportReadCommitError("LocalPoolVector",
return PoolVariableIF::INVALID_READ_WRITE_MODE; PoolVariableIF::INVALID_READ_WRITE_MODE, false, targetObjectId,
} localPoolId);
PoolEntry<T>* poolEntry = nullptr; return PoolVariableIF::INVALID_READ_WRITE_MODE;
ReturnValue_t result = hkManager->fetchPoolEntry(localPoolId, &poolEntry); }
if(result != RETURN_OK) {
sif::error << "PoolVector: Read of local pool variable of object " PoolEntry<T>* poolEntry = nullptr;
"0x" << std::hex << std::setw(8) << std::setfill('0') << //ReturnValue_t result = hkManager->fetchPoolEntry(localPoolId, &poolEntry);
hkManager->getOwner() << " and lp ID 0x" << localPoolId << ReturnValue_t result = LocalDpManagerAttorney::fetchPoolEntry(*hkManager, localPoolId,
std::dec << " failed.\n" << std::flush; &poolEntry);
return result; if(result != RETURN_OK) {
} object_id_t ownerObjectId = hkManager->getCreatorObjectId();
*(poolEntry->address) = this->value; reportReadCommitError("LocalPoolVariable", result,
poolEntry->valid = this->valid; false, ownerObjectId, localPoolId);
return RETURN_OK; return result;
}
*(poolEntry->getDataPtr()) = this->value;
poolEntry->setValid(this->valid);
return RETURN_OK;
} }
template<typename T> template<typename T>
inline ReturnValue_t LocalPoolVariable<T>::serialize(uint8_t** buffer, size_t* size, inline ReturnValue_t LocalPoolVariable<T>::serialize(uint8_t** buffer,
const size_t max_size, SerializeIF::Endianness streamEndianness) const { size_t* size, const size_t max_size,
return SerializeAdapter::serialize(&value, SerializeIF::Endianness streamEndianness) const {
buffer, size ,max_size, streamEndianness); return SerializeAdapter::serialize(&value,
buffer, size ,max_size, streamEndianness);
} }
template<typename T> template<typename T>
inline size_t LocalPoolVariable<T>::getSerializedSize() const { inline size_t LocalPoolVariable<T>::getSerializedSize() const {
return SerializeAdapter::getSerializedSize(&value); return SerializeAdapter::getSerializedSize(&value);
} }
template<typename T> template<typename T>
inline ReturnValue_t LocalPoolVariable<T>::deSerialize(const uint8_t** buffer, inline ReturnValue_t LocalPoolVariable<T>::deSerialize(const uint8_t** buffer,
size_t* size, SerializeIF::Endianness streamEndianness) { size_t* size, SerializeIF::Endianness streamEndianness) {
return SerializeAdapter::deSerialize(&value, buffer, size, streamEndianness); return SerializeAdapter::deSerialize(&value, buffer, size, streamEndianness);
} }
#if FSFW_CPP_OSTREAM_ENABLED == 1
template<typename T> template<typename T>
inline std::ostream& operator<< (std::ostream &out, inline std::ostream& operator<< (std::ostream &out,
const LocalPoolVariable<T> &var) { const LocalPoolVariable<T> &var) {
out << var.value; out << var.value;
return out; return out;
} }
#endif
template<typename T> template<typename T>
inline LocalPoolVariable<T>::operator T() const { inline LocalPoolVariable<T>::operator T() const {
return value; return value;
} }
template<typename T> template<typename T>
inline LocalPoolVariable<T> & LocalPoolVariable<T>::operator=(const T& newValue) { inline LocalPoolVariable<T> & LocalPoolVariable<T>::operator=(
const T& newValue) {
value = newValue; value = newValue;
return *this; return *this;
} }
template<typename T> template<typename T>
inline LocalPoolVariable<T>& LocalPoolVariable<T>::operator =( inline LocalPoolVariable<T>& LocalPoolVariable<T>::operator =(
const LocalPoolVariable<T>& newPoolVariable) { const LocalPoolVariable<T>& newPoolVariable) {
value = newPoolVariable.value; value = newPoolVariable.value;
return *this; return *this;
} }
template<typename T> template<typename T>
inline bool LocalPoolVariable<T>::operator ==(const LocalPoolVariable<T> &other) const { inline bool LocalPoolVariable<T>::operator ==(
return this->value == other.value; const LocalPoolVariable<T> &other) const {
return this->value == other.value;
} }
template<typename T> template<typename T>
inline bool LocalPoolVariable<T>::operator ==(const T &other) const { inline bool LocalPoolVariable<T>::operator ==(const T &other) const {
return this->value == other; return this->value == other;
} }
template<typename T> template<typename T>
inline bool LocalPoolVariable<T>::operator !=(const LocalPoolVariable<T> &other) const { inline bool LocalPoolVariable<T>::operator !=(
return not (*this == other); const LocalPoolVariable<T> &other) const {
return not (*this == other);
} }
template<typename T> template<typename T>
inline bool LocalPoolVariable<T>::operator !=(const T &other) const { inline bool LocalPoolVariable<T>::operator !=(const T &other) const {
return not (*this == other); return not (*this == other);
} }
template<typename T> template<typename T>
inline bool LocalPoolVariable<T>::operator <(const LocalPoolVariable<T> &other) const { inline bool LocalPoolVariable<T>::operator <(
return this->value < other.value; const LocalPoolVariable<T> &other) const {
return this->value < other.value;
} }
template<typename T> template<typename T>
inline bool LocalPoolVariable<T>::operator <(const T &other) const { inline bool LocalPoolVariable<T>::operator <(const T &other) const {
return this->value < other; return this->value < other;
} }
template<typename T> template<typename T>
inline bool LocalPoolVariable<T>::operator >(const LocalPoolVariable<T> &other) const { inline bool LocalPoolVariable<T>::operator >(
return not (*this < other); const LocalPoolVariable<T> &other) const {
return not (*this < other);
} }
template<typename T> template<typename T>
inline bool LocalPoolVariable<T>::operator >(const T &other) const { inline bool LocalPoolVariable<T>::operator >(const T &other) const {
return not (*this < other); return not (*this < other);
} }
#endif /* FSFW_DATAPOOLLOCAL_LOCALPOOLVARIABLE_TPP_ */ #endif /* FSFW_DATAPOOLLOCAL_LOCALPOOLVARIABLE_TPP_ */

View File

@ -2,12 +2,14 @@
#define FSFW_DATAPOOLLOCAL_LOCALPOOLVECTOR_H_ #define FSFW_DATAPOOLLOCAL_LOCALPOOLVECTOR_H_
#include "LocalPoolObjectBase.h" #include "LocalPoolObjectBase.h"
#include "internal/LocalDpManagerAttorney.h"
#include "../datapool/DataSetIF.h" #include "../datapool/DataSetIF.h"
#include "../datapool/PoolEntry.h" #include "../datapool/PoolEntry.h"
#include "../datapool/PoolVariableIF.h" #include "../datapool/PoolVariableIF.h"
#include "../datapoollocal/LocalDataPoolManager.h" #include "../datapoollocal/LocalDataPoolManager.h"
#include "../serialize/SerializeAdapter.h" #include "../serialize/SerializeAdapter.h"
#include "../serviceinterface/ServiceInterfaceStream.h" #include "../serviceinterface/ServiceInterface.h"
/** /**
@ -33,136 +35,149 @@
template<typename T, uint16_t vectorSize> template<typename T, uint16_t vectorSize>
class LocalPoolVector: public LocalPoolObjectBase { class LocalPoolVector: public LocalPoolObjectBase {
public: public:
LocalPoolVector() = delete; LocalPoolVector() = delete;
/** /**
* This constructor is used by the data creators to have pool variable * This constructor is used by the data creators to have pool variable
* instances which can also be stored in datasets. * instances which can also be stored in datasets.
* It does not fetch the current value from the data pool. This is performed * It does not fetch the current value from the data pool. This is performed
* by the read() operation (which is not thread-safe). * by the read() operation (which is not thread-safe).
* Datasets can be used to access local pool entires in a thread-safe way. * Datasets can be used to access local pool entires in a thread-safe way.
* @param poolId ID of the local pool entry. * @param poolId ID of the local pool entry.
* @param hkOwner Pointer of the owner. This will generally be the calling * @param hkOwner Pointer of the owner. This will generally be the calling
* class itself which passes "this". * class itself which passes "this".
* @param setReadWriteMode Specify the read-write mode of the pool variable. * @param setReadWriteMode Specify the read-write mode of the pool variable.
* @param dataSet The data set in which the variable shall register itself. * @param dataSet The data set in which the variable shall register itself.
* If nullptr, the variable is not registered. * If nullptr, the variable is not registered.
*/ */
LocalPoolVector(HasLocalDataPoolIF* hkOwner, lp_id_t poolId, LocalPoolVector(HasLocalDataPoolIF* hkOwner, lp_id_t poolId,
DataSetIF* dataSet = nullptr, DataSetIF* dataSet = nullptr,
pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE); pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE);
/** /**
* This constructor is used by data users like controllers to have * This constructor is used by data users like controllers to have
* access to the local pool variables of data creators by supplying * access to the local pool variables of data creators by supplying
* the respective creator object ID. * the respective creator object ID.
* It does not fetch the current value from the data pool. This is performed * It does not fetch the current value from the data pool. This is performed
* by the read() operation (which is not thread-safe). * by the read() operation (which is not thread-safe).
* Datasets can be used to access local pool entires in a thread-safe way. * Datasets can be used to access local pool entires in a thread-safe way.
* @param poolId ID of the local pool entry. * @param poolId ID of the local pool entry.
* @param hkOwner Pointer of the owner. This will generally be the calling * @param hkOwner Pointer of the owner. This will generally be the calling
* class itself which passes "this". * class itself which passes "this".
* @param setReadWriteMode Specify the read-write mode of the pool variable. * @param setReadWriteMode Specify the read-write mode of the pool variable.
* @param dataSet The data set in which the variable shall register itself. * @param dataSet The data set in which the variable shall register itself.
* If nullptr, the variable is not registered. * If nullptr, the variable is not registered.
*/ */
LocalPoolVector(object_id_t poolOwner, lp_id_t poolId, LocalPoolVector(object_id_t poolOwner, lp_id_t poolId,
DataSetIF* dataSet = nullptr, DataSetIF* dataSet = nullptr,
pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE); pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE);
/** /**
* Variation which takes the unique global identifier of a local pool * Variation which takes the unique global identifier of a local pool
* vector. * vector.
* @param globalPoolId * @param globalPoolId
* @param dataSet * @param dataSet
* @param setReadWriteMode * @param setReadWriteMode
*/ */
LocalPoolVector(gp_id_t globalPoolId, LocalPoolVector(gp_id_t globalPoolId,
DataSetIF* dataSet = nullptr, DataSetIF* dataSet = nullptr,
pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE); pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE);
/** /**
* @brief This is the local copy of the data pool entry. * @brief This is the local copy of the data pool entry.
* @details * @details
* The user can work on this attribute just like he would on a local * The user can work on this attribute just like he would on a local
* array of this type. * array of this type.
*/ */
T value[vectorSize]; T value[vectorSize];
/** /**
* @brief The classes destructor is empty. * @brief The classes destructor is empty.
* @details If commit() was not called, the local value is * @details If commit() was not called, the local value is
* discarded and not written back to the data pool. * discarded and not written back to the data pool.
*/ */
~LocalPoolVector() {}; ~LocalPoolVector() {};
/** /**
* @brief The operation returns the number of array entries * @brief The operation returns the number of array entries
* in this variable. * in this variable.
*/ */
uint8_t getSize() { uint8_t getSize() {
return vectorSize; return vectorSize;
} }
T& operator [](int i); T& operator [](size_t i);
const T &operator [](int i) const; const T &operator [](size_t i) const;
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size,
const size_t maxSize, const size_t maxSize,
SerializeIF::Endianness streamEndiannes) const override; SerializeIF::Endianness streamEndiannes) const override;
virtual size_t getSerializedSize() const override; virtual size_t getSerializedSize() const override;
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
SerializeIF::Endianness streamEndianness) override; SerializeIF::Endianness streamEndianness) override;
/** /**
* @brief This is a call to read the array's values * @brief This is a call to read the array's values
* from the global data pool. * from the global data pool.
* @details * @details
* When executed, this operation tries to fetch the pool entry with matching * 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 * data pool id from the data pool and copies all array values and the valid
* information to its local attributes. * information to its local attributes.
* In case of a failure (wrong type, size or pool id not found), the * In case of a failure (wrong type, size or pool id not found), the
* variable is set to zero and invalid. * variable is set to zero and invalid.
* The read call is protected with a lock. * The read call is protected with a lock.
* It is recommended to use DataSets to read and commit multiple variables * It is recommended to use DataSets to read and commit multiple variables
* at once to avoid the overhead of unnecessary lock und unlock operations. * at once to avoid the overhead of unnecessary lock und unlock operations.
*/ */
ReturnValue_t read(uint32_t lockTimeout = MutexIF::BLOCKING) override; ReturnValue_t read(MutexIF::TimeoutType timeoutType =
/** MutexIF::TimeoutType::WAITING,
* @brief The commit call copies the array values back to the data pool. uint32_t timeoutMs = 20) override;
* @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. * @brief The commit call copies the array values back to the data pool.
* The read call is protected with a lock. * @details
* It is recommended to use DataSets to read and commit multiple variables * It checks type and size, as well as if the variable is writable. If so,
* at once to avoid the overhead of unnecessary lock und unlock operations. * the value is copied and the local valid flag is written back as well.
*/ * The read call is protected with a lock.
ReturnValue_t commit(uint32_t lockTimeout = MutexIF::BLOCKING) override; * 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: protected:
/** /**
* @brief Like #read, but without a lock protection of the global pool. * @brief Like #read, but without a lock protection of the global pool.
* @details * @details
* The operation does NOT provide any mutual exclusive protection by itself. * 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 * This can be used if the lock is handled externally to avoid the overhead
* of consecutive lock und unlock operations. * of consecutive lock und unlock operations.
* Declared protected to discourage free public usage. * Declared protected to discourage free public usage.
*/ */
ReturnValue_t readWithoutLock() override; ReturnValue_t readWithoutLock() override;
/** /**
* @brief Like #commit, but without a lock protection of the global pool. * @brief Like #commit, but without a lock protection of the global pool.
* @details * @details
* The operation does NOT provide any mutual exclusive protection by itself. * 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 * This can be used if the lock is handled externally to avoid the overhead
* of consecutive lock und unlock operations. * of consecutive lock und unlock operations.
* Declared protected to discourage free public usage. * Declared protected to discourage free public usage.
*/ */
ReturnValue_t commitWithoutLock() override; ReturnValue_t commitWithoutLock() override;
private: private:
#if FSFW_CPP_OSTREAM_ENABLED == 1
// std::ostream is the type for object std::cout // std::ostream is the type for object std::cout
template <typename U, uint16_t otherSize> template <typename U, uint16_t otherSize>
friend std::ostream& operator<< (std::ostream &out, friend std::ostream& operator<< (std::ostream &out,
const LocalPoolVector<U, otherSize> &var); const LocalPoolVector<U, otherSize> &var);
#endif
}; };

View File

@ -7,140 +7,161 @@
template<typename T, uint16_t vectorSize> template<typename T, uint16_t vectorSize>
inline LocalPoolVector<T, vectorSize>::LocalPoolVector( inline LocalPoolVector<T, vectorSize>::LocalPoolVector(
HasLocalDataPoolIF* hkOwner, lp_id_t poolId, DataSetIF* dataSet, HasLocalDataPoolIF* hkOwner, lp_id_t poolId, DataSetIF* dataSet,
pool_rwm_t setReadWriteMode): pool_rwm_t setReadWriteMode):
LocalPoolObjectBase(poolId, hkOwner, dataSet, setReadWriteMode) {} LocalPoolObjectBase(poolId, hkOwner, dataSet, setReadWriteMode) {}
template<typename T, uint16_t vectorSize> template<typename T, uint16_t vectorSize>
inline LocalPoolVector<T, vectorSize>::LocalPoolVector(object_id_t poolOwner, inline LocalPoolVector<T, vectorSize>::LocalPoolVector(object_id_t poolOwner,
lp_id_t poolId, DataSetIF *dataSet, pool_rwm_t setReadWriteMode): lp_id_t poolId, DataSetIF *dataSet, pool_rwm_t setReadWriteMode):
LocalPoolObjectBase(poolOwner, poolId, dataSet, setReadWriteMode) {} LocalPoolObjectBase(poolOwner, poolId, dataSet, setReadWriteMode) {}
template<typename T, uint16_t vectorSize> template<typename T, uint16_t vectorSize>
inline LocalPoolVector<T, vectorSize>::LocalPoolVector(gp_id_t globalPoolId, inline LocalPoolVector<T, vectorSize>::LocalPoolVector(gp_id_t globalPoolId,
DataSetIF *dataSet, pool_rwm_t setReadWriteMode): DataSetIF *dataSet, pool_rwm_t setReadWriteMode):
LocalPoolObjectBase(globalPoolId.objectId, globalPoolId.localPoolId, LocalPoolObjectBase(globalPoolId.objectId, globalPoolId.localPoolId,
dataSet, setReadWriteMode) {} dataSet, setReadWriteMode) {}
template<typename T, uint16_t vectorSize> template<typename T, uint16_t vectorSize>
inline ReturnValue_t LocalPoolVector<T, vectorSize>::read(uint32_t lockTimeout) { inline ReturnValue_t LocalPoolVector<T, vectorSize>::read(
MutexHelper(hkManager->getMutexHandle(), MutexIF::TimeoutType::WAITING, MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) {
lockTimeout); MutexHelper(LocalDpManagerAttorney::getMutexHandle(*hkManager), timeoutType, timeoutMs);
return readWithoutLock(); return readWithoutLock();
} }
template<typename T, uint16_t vectorSize> template<typename T, uint16_t vectorSize>
inline ReturnValue_t LocalPoolVector<T, vectorSize>::readWithoutLock() { inline ReturnValue_t LocalPoolVector<T, vectorSize>::readWithoutLock() {
if(readWriteMode == pool_rwm_t::VAR_WRITE) { if(readWriteMode == pool_rwm_t::VAR_WRITE) {
sif::debug << "LocalPoolVar: Invalid read write " object_id_t targetObjectId = hkManager->getCreatorObjectId();
"mode for read() call." << std::endl; reportReadCommitError("LocalPoolVector",
return PoolVariableIF::INVALID_READ_WRITE_MODE; PoolVariableIF::INVALID_READ_WRITE_MODE, true, targetObjectId,
} localPoolId);
return PoolVariableIF::INVALID_READ_WRITE_MODE;
}
PoolEntry<T>* poolEntry = nullptr; PoolEntry<T>* poolEntry = nullptr;
ReturnValue_t result = hkManager->fetchPoolEntry(localPoolId, &poolEntry); ReturnValue_t result = LocalDpManagerAttorney::fetchPoolEntry(*hkManager, localPoolId,
memset(this->value, 0, vectorSize * sizeof(T)); &poolEntry);
memset(this->value, 0, vectorSize * sizeof(T));
if(result != RETURN_OK) { if(result != RETURN_OK) {
sif::error << "PoolVector: Read of local pool variable of object " object_id_t targetObjectId = hkManager->getCreatorObjectId();
"0x" << std::hex << std::setw(8) << std::setfill('0') << reportReadCommitError("LocalPoolVector", result, true, targetObjectId,
hkManager->getOwner() << "and lp ID 0x" << localPoolId << localPoolId);
std::dec << " failed." << std::endl; return result;
return result; }
} std::memcpy(this->value, poolEntry->getDataPtr(), poolEntry->getByteSize());
std::memcpy(this->value, poolEntry->address, poolEntry->getByteSize()); this->valid = poolEntry->getValid();
this->valid = poolEntry->valid; return RETURN_OK;
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> template<typename T, uint16_t vectorSize>
inline ReturnValue_t LocalPoolVector<T, vectorSize>::commit( inline ReturnValue_t LocalPoolVector<T, vectorSize>::commit(
uint32_t lockTimeout) { MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) {
MutexHelper(hkManager->getMutexHandle(), MutexIF::TimeoutType::WAITING, MutexHelper(LocalDpManagerAttorney::getMutexHandle(*hkManager), timeoutType, timeoutMs);
lockTimeout); return commitWithoutLock();
return commitWithoutLock();
} }
template<typename T, uint16_t vectorSize> template<typename T, uint16_t vectorSize>
inline ReturnValue_t LocalPoolVector<T, vectorSize>::commitWithoutLock() { inline ReturnValue_t LocalPoolVector<T, vectorSize>::commitWithoutLock() {
if(readWriteMode == pool_rwm_t::VAR_READ) { if(readWriteMode == pool_rwm_t::VAR_READ) {
sif::debug << "LocalPoolVar: Invalid read write " object_id_t targetObjectId = hkManager->getCreatorObjectId();
"mode for commit() call." << std::endl; reportReadCommitError("LocalPoolVector",
return PoolVariableIF::INVALID_READ_WRITE_MODE; PoolVariableIF::INVALID_READ_WRITE_MODE, false, targetObjectId,
} localPoolId);
PoolEntry<T>* poolEntry = nullptr; return PoolVariableIF::INVALID_READ_WRITE_MODE;
ReturnValue_t result = hkManager->fetchPoolEntry(localPoolId, &poolEntry); }
if(result != RETURN_OK) { PoolEntry<T>* poolEntry = nullptr;
sif::error << "PoolVector: Read of local pool variable of object " ReturnValue_t result = LocalDpManagerAttorney::fetchPoolEntry(*hkManager, localPoolId,
"0x" << std::hex << std::setw(8) << std::setfill('0') << &poolEntry);
hkManager->getOwner() << " and lp ID 0x" << localPoolId << if(result != RETURN_OK) {
std::dec << " failed.\n" << std::flush; object_id_t targetObjectId = hkManager->getCreatorObjectId();
return result; reportReadCommitError("LocalPoolVector", result, false, targetObjectId,
} localPoolId);
std::memcpy(poolEntry->address, this->value, poolEntry->getByteSize()); return result;
poolEntry->valid = this->valid; }
return RETURN_OK; std::memcpy(poolEntry->getDataPtr(), this->value, poolEntry->getByteSize());
poolEntry->setValid(this->valid);
return RETURN_OK;
} }
template<typename T, uint16_t vectorSize> template<typename T, uint16_t vectorSize>
inline T& LocalPoolVector<T, vectorSize>::operator [](int i) { inline T& LocalPoolVector<T, vectorSize>::operator [](size_t i) {
if(i <= vectorSize) { if(i < vectorSize) {
return value[i]; return value[i];
} }
// If this happens, I have to set some value. I consider this // If this happens, I have to set some value. I consider this
// a configuration error, but I wont exit here. // a configuration error, but I wont exit here.
sif::error << "LocalPoolVector: Invalid index. Setting or returning" #if FSFW_CPP_OSTREAM_ENABLED == 1
" last value!" << std::endl; sif::warning << "LocalPoolVector: Invalid index. Setting or returning"
return value[i]; " 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> template<typename T, uint16_t vectorSize>
inline const T& LocalPoolVector<T, vectorSize>::operator [](int i) const { inline const T& LocalPoolVector<T, vectorSize>::operator [](size_t i) const {
if(i <= vectorSize) { if(i < vectorSize) {
return value[i]; return value[i];
} }
// If this happens, I have to set some value. I consider this // If this happens, I have to set some value. I consider this
// a configuration error, but I wont exit here. // a configuration error, but I wont exit here.
sif::error << "LocalPoolVector: Invalid index. Setting or returning" #if FSFW_CPP_OSTREAM_ENABLED == 1
" last value!" << std::endl; sif::warning << "LocalPoolVector: Invalid index. Setting or returning"
return value[i]; " 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> template<typename T, uint16_t vectorSize>
inline ReturnValue_t LocalPoolVector<T, vectorSize>::serialize(uint8_t** buffer, inline ReturnValue_t LocalPoolVector<T, vectorSize>::serialize(uint8_t** buffer,
size_t* size, size_t maxSize, size_t* size, size_t maxSize,
SerializeIF::Endianness streamEndianness) const { SerializeIF::Endianness streamEndianness) const {
ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED;
for (uint16_t i = 0; i < vectorSize; i++) { for (uint16_t i = 0; i < vectorSize; i++) {
result = SerializeAdapter::serialize(&(value[i]), buffer, size, result = SerializeAdapter::serialize(&(value[i]), buffer, size,
maxSize, streamEndianness); maxSize, streamEndianness);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
break; break;
} }
} }
return result; return result;
} }
template<typename T, uint16_t vectorSize> template<typename T, uint16_t vectorSize>
inline size_t LocalPoolVector<T, vectorSize>::getSerializedSize() const { inline size_t LocalPoolVector<T, vectorSize>::getSerializedSize() const {
return vectorSize * SerializeAdapter::getSerializedSize(value); return vectorSize * SerializeAdapter::getSerializedSize(value);
} }
template<typename T, uint16_t vectorSize> template<typename T, uint16_t vectorSize>
inline ReturnValue_t LocalPoolVector<T, vectorSize>::deSerialize( inline ReturnValue_t LocalPoolVector<T, vectorSize>::deSerialize(
const uint8_t** buffer, size_t* size, const uint8_t** buffer, size_t* size,
SerializeIF::Endianness streamEndianness) { SerializeIF::Endianness streamEndianness) {
ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED;
for (uint16_t i = 0; i < vectorSize; i++) { for (uint16_t i = 0; i < vectorSize; i++) {
result = SerializeAdapter::deSerialize(&(value[i]), buffer, size, result = SerializeAdapter::deSerialize(&(value[i]), buffer, size,
streamEndianness); streamEndianness);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
break; break;
} }
} }
return result; return result;
} }
#if FSFW_CPP_OSTREAM_ENABLED == 1
template<typename T, uint16_t vectorSize> template<typename T, uint16_t vectorSize>
inline std::ostream& operator<< (std::ostream &out, inline std::ostream& operator<< (std::ostream &out,
const LocalPoolVector<T, vectorSize> &var) { const LocalPoolVector<T, vectorSize> &var) {
@ -154,5 +175,6 @@ inline std::ostream& operator<< (std::ostream &out,
out << "]"; out << "]";
return out; return out;
} }
#endif
#endif /* FSFW_DATAPOOLLOCAL_LOCALPOOLVECTOR_TPP_ */ #endif /* FSFW_DATAPOOLLOCAL_LOCALPOOLVECTOR_TPP_ */

View File

@ -0,0 +1,83 @@
#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 subscribeForUpdatePackets(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
* @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
*/
virtual ReturnValue_t subscribeForSetUpdateMessages(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
* @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
*/
virtual ReturnValue_t subscribeForVariableUpdateMessages(
const lp_id_t localPoolId,
object_id_t destinationObject,
MessageQueueId_t targetQueueId,
bool generateSnapshot) = 0;
};
#endif /* FSFW_DATAPOOLLOCAL_PROVIDESDATAPOOLSUBSCRIPTION_H_ */

View File

@ -6,7 +6,15 @@
#include "../objectmanager/SystemObject.h" #include "../objectmanager/SystemObject.h"
#include <vector> #include <vector>
class SharedLocalDataSet: public SystemObject, /**
* This local dataset variation can be used if the dataset is used concurrently across
* multiple threads. It provides a lock in addition to all other functionalities provided
* by the LocalPoolDataSetBase class.
*
* TODO: override and protect read, commit and some other calls used by pool manager.
*/
class SharedLocalDataSet:
public SystemObject,
public LocalPoolDataSetBase, public LocalPoolDataSetBase,
public SharedDataSetIF { public SharedDataSetIF {
public: public:

View File

@ -20,26 +20,24 @@
template <uint8_t NUM_VARIABLES> template <uint8_t NUM_VARIABLES>
class StaticLocalDataSet: public LocalPoolDataSetBase { class StaticLocalDataSet: public LocalPoolDataSetBase {
public: public:
/** /**
* Constructor used by data owner and creator like device handlers. * Constructor used by data owner and creator like device handlers.
* This constructor also initialized the components required for * This constructor also initialized the components required for
* periodic handling. * periodic handling.
* @param hkOwner * @param hkOwner
* @param setId * @param setId
*/ */
StaticLocalDataSet(HasLocalDataPoolIF* hkOwner, StaticLocalDataSet(HasLocalDataPoolIF* hkOwner, uint32_t setId):
uint32_t setId): LocalPoolDataSetBase(hkOwner, setId, nullptr, LocalPoolDataSetBase(hkOwner, setId, nullptr, NUM_VARIABLES) {
NUM_VARIABLES) {
this->setContainer(poolVarList.data()); this->setContainer(poolVarList.data());
} }
/** /**
* Constructor used by data users like controllers. * Constructor used by data users like controllers.
* @param hkOwner * @param hkOwner
* @param setId * @param setId
*/ */
StaticLocalDataSet(sid_t sid): LocalPoolDataSetBase(sid, nullptr, StaticLocalDataSet(sid_t sid): LocalPoolDataSetBase(sid, nullptr, NUM_VARIABLES) {
NUM_VARIABLES) {
this->setContainer(poolVarList.data()); this->setContainer(poolVarList.data());
} }

View File

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

View File

@ -0,0 +1,18 @@
#include "HasLocalDpIFManagerAttorney.h"
#include "../LocalPoolObjectBase.h"
#include "../LocalPoolDataSetBase.h"
#include "../HasLocalDataPoolIF.h"
LocalPoolDataSetBase* HasLocalDpIFManagerAttorney::getDataSetHandle(HasLocalDataPoolIF* clientIF,
sid_t sid) {
return clientIF->getDataSetHandle(sid);
}
LocalPoolObjectBase* HasLocalDpIFManagerAttorney::getPoolObjectHandle(HasLocalDataPoolIF* clientIF,
lp_id_t localPoolId) {
return clientIF->getPoolObjectHandle(localPoolId);
}
object_id_t HasLocalDpIFManagerAttorney::getObjectId(HasLocalDataPoolIF* clientIF) {
return clientIF->getObjectId();
}

View File

@ -0,0 +1,22 @@
#ifndef FSFW_DATAPOOLLOCAL_HASLOCALDPIFMANAGERATTORNEY_H_
#define FSFW_DATAPOOLLOCAL_HASLOCALDPIFMANAGERATTORNEY_H_
#include "../localPoolDefinitions.h"
class HasLocalDataPoolIF;
class LocalPoolDataSetBase;
class LocalPoolObjectBase;
class HasLocalDpIFManagerAttorney {
static LocalPoolDataSetBase* getDataSetHandle(HasLocalDataPoolIF* clientIF, sid_t sid);
static LocalPoolObjectBase* getPoolObjectHandle(HasLocalDataPoolIF* clientIF,
lp_id_t localPoolId);
static object_id_t getObjectId(HasLocalDataPoolIF* clientIF);
friend class LocalDataPoolManager;
};
#endif /* FSFW_DATAPOOLLOCAL_HASLOCALDPIFMANAGERATTORNEY_H_ */

View File

@ -0,0 +1,7 @@
#include "HasLocalDpIFUserAttorney.h"
#include "../AccessLocalPoolF.h"
#include "../HasLocalDataPoolIF.h"
AccessPoolManagerIF* HasLocalDpIFUserAttorney::getAccessorHandle(HasLocalDataPoolIF *clientIF) {
return clientIF->getAccessorHandle();
}

View File

@ -0,0 +1,18 @@
#ifndef FSFW_DATAPOOLLOCAL_HASLOCALDPIFUSERATTORNEY_H_
#define FSFW_DATAPOOLLOCAL_HASLOCALDPIFUSERATTORNEY_H_
class HasLocalDataPoolIF;
class AccessPoolManagerIF;
class HasLocalDpIFUserAttorney {
private:
static AccessPoolManagerIF* getAccessorHandle(HasLocalDataPoolIF* clientIF);
friend class LocalPoolObjectBase;
friend class LocalPoolDataSetBase;
};
#endif /* FSFW_DATAPOOLLOCAL_HASLOCALDPIFUSERATTORNEY_H_ */

View File

@ -0,0 +1,32 @@
#ifndef FSFW_DATAPOOLLOCAL_LOCALDPMANAGERATTORNEY_H_
#define FSFW_DATAPOOLLOCAL_LOCALDPMANAGERATTORNEY_H_
#include "../LocalDataPoolManager.h"
/**
* @brief This is a helper class implements the Attorney-Client idiom for access to
* LocalDataPoolManager internals
* @details
* This helper class provides better control over which classes are allowed to access
* LocalDataPoolManager internals in a granular and encapsulated way when compared to
* other methods like direct friend declarations. It allows these classes to use
* an explicit subset of the pool manager private/protected functions.
* See: https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Friendship_and_the_Attorney-Client
*/
class LocalDpManagerAttorney {
private:
template<typename T> static ReturnValue_t fetchPoolEntry(LocalDataPoolManager& manager,
lp_id_t localPoolId, PoolEntry<T> **poolEntry) {
return manager.fetchPoolEntry(localPoolId, poolEntry);
}
static MutexIF* getMutexHandle(LocalDataPoolManager& manager) {
return manager.getMutexHandle();
}
template<typename T> friend class LocalPoolVariable;
template<typename T, uint16_t vecSize> friend class LocalPoolVector;
};
#endif /* FSFW_DATAPOOLLOCAL_LOCALDPMANAGERATTORNEY_H_ */

View File

@ -0,0 +1,39 @@
#ifndef FSFW_DATAPOOLLOCAL_LOCALPOOLDATASETATTORNEY_H_
#define FSFW_DATAPOOLLOCAL_LOCALPOOLDATASETATTORNEY_H_
#include "../LocalPoolDataSetBase.h"
class LocalPoolDataSetAttorney {
private:
static void setDiagnostic(LocalPoolDataSetBase& set, bool diagnostics) {
set.setDiagnostic(diagnostics);
}
static bool isDiagnostics(LocalPoolDataSetBase& set) {
return set.isDiagnostics();
}
static void initializePeriodicHelper(LocalPoolDataSetBase& set, float collectionInterval,
uint32_t minimumPeriodicIntervalMs,
bool isDiagnostics, uint8_t nonDiagIntervalFactor = 5) {
set.initializePeriodicHelper(collectionInterval, minimumPeriodicIntervalMs, isDiagnostics,
nonDiagIntervalFactor);
}
static void setReportingEnabled(LocalPoolDataSetBase& set, bool enabled) {
set.setReportingEnabled(enabled);
}
static bool getReportingEnabled(LocalPoolDataSetBase& set) {
return set.getReportingEnabled();
}
static PeriodicHousekeepingHelper* getPeriodicHelper(LocalPoolDataSetBase& set) {
return set.periodicHelper;
}
friend class LocalDataPoolManager;
};
#endif /* FSFW_DATAPOOLLOCAL_LOCALPOOLDATASETATTORNEY_H_ */

View File

@ -1,10 +1,13 @@
#ifndef FSFW_DATAPOOLLOCAL_LOCPOOLDEFINITIONS_H_ #ifndef FSFW_DATAPOOLLOCAL_LOCALPOOLDEFINITIONS_H_
#define FSFW_DATAPOOLLOCAL_LOCPOOLDEFINITIONS_H_ #define FSFW_DATAPOOLLOCAL_LOCALPOOLDEFINITIONS_H_
#include <cstdint> #include "../datapool/PoolEntryIF.h"
#include "../objectmanager/SystemObjectIF.h" #include "../objectmanager/SystemObjectIF.h"
#include "../objectmanager/frameworkObjects.h" #include "../objectmanager/frameworkObjects.h"
#include <cstdint>
#include <map>
/** /**
* @brief Type definition for local pool entries. * @brief Type definition for local pool entries.
*/ */
@ -12,10 +15,21 @@ using lp_id_t = uint32_t;
namespace localpool { namespace localpool {
static constexpr uint32_t INVALID_LPID = -1; static constexpr uint32_t INVALID_LPID = -1;
static constexpr uint8_t INTERFACE_ID = CLASS_ID::LOCAL_POOL_OWNER_IF;
static constexpr ReturnValue_t POOL_ENTRY_NOT_FOUND = MAKE_RETURN_CODE(0x00);
static constexpr ReturnValue_t POOL_ENTRY_TYPE_CONFLICT = MAKE_RETURN_CODE(0x01);
//! This is the core data structure of the local data pools. Users should insert all desired
//! pool variables, using the std::map interface.
using DataPool = std::map<lp_id_t, PoolEntryIF*>;
using DataPoolMapIter = DataPool::iterator;
} }
/** /**
* Used as a unique identifier for data sets. * Used as a unique identifier for data sets. Consists of 4 byte object ID and 4 byte set ID.
*/ */
union sid_t { union sid_t {
static constexpr uint64_t INVALID_SID = -1; static constexpr uint64_t INVALID_SID = -1;
@ -26,8 +40,8 @@ union sid_t {
sid_t(): raw(INVALID_SID) {} sid_t(): raw(INVALID_SID) {}
sid_t(object_id_t objectId, uint32_t setId): sid_t(object_id_t objectId, uint32_t setId):
objectId(objectId), objectId(objectId),
ownerSetId(setId) {} ownerSetId(setId) {}
struct { struct {
object_id_t objectId ; object_id_t objectId ;
@ -57,29 +71,30 @@ union sid_t {
}; };
/** /**
* Used as a global unique identifier for local pool variables. * Used as a global unique identifier for local pool variables. Consists of 4 byte object ID
* and 4 byte local pool ID.
*/ */
union gp_id_t { union gp_id_t {
static constexpr uint64_t INVALID_GPID = -1; static constexpr uint64_t INVALID_GPID = -1;
static constexpr uint32_t INVALID_OBJECT_ID = objects::NO_OBJECT; static constexpr uint32_t INVALID_OBJECT_ID = objects::NO_OBJECT;
static constexpr uint32_t INVALID_LPID = localpool::INVALID_LPID; static constexpr uint32_t INVALID_LPID = localpool::INVALID_LPID;
gp_id_t(): raw(INVALID_GPID) {} gp_id_t(): raw(INVALID_GPID) {}
gp_id_t(object_id_t objectId, lp_id_t localPoolId): gp_id_t(object_id_t objectId, lp_id_t localPoolId):
objectId(objectId), objectId(objectId),
localPoolId(localPoolId) {} localPoolId(localPoolId) {}
struct { struct {
object_id_t objectId; object_id_t objectId;
lp_id_t localPoolId; lp_id_t localPoolId;
}; };
uint64_t raw; uint64_t raw;
bool notSet() const { bool notSet() const {
return raw == INVALID_GPID; return raw == INVALID_GPID;
} }
bool operator==(const sid_t& other) const { bool operator==(const sid_t& other) const {
return raw == other.raw; return raw == other.raw;
@ -90,4 +105,4 @@ union gp_id_t {
} }
}; };
#endif /* FSFW_DATAPOOLLOCAL_LOCPOOLDEFINITIONS_H_ */ #endif /* FSFW_DATAPOOLLOCAL_LOCALPOOLDEFINITIONS_H_ */

View File

@ -1,15 +1,15 @@
target_sources(${TARGET_NAME} target_sources(${LIB_FSFW_NAME} PRIVATE
PRIVATE ipc/missionMessageTypes.cpp
objects/FsfwFactory.cpp
pollingsequence/PollingSequenceFactory.cpp
) )
# Add include paths for the executable # Should be added to include path
target_include_directories(${TARGET_NAME} target_include_directories(${TARGET_NAME} PRIVATE
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}
) )
# Add include paths for the FSFW library if(NOT FSFW_CONFIG_PATH)
target_include_directories(${LIB_FSFW_NAME} set(FSFW_CONFIG_PATH ${CMAKE_CURRENT_SOURCE_DIR})
PUBLIC endif()
${CMAKE_CURRENT_SOURCE_DIR}
)

View File

@ -4,16 +4,21 @@
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
//! Used to determine whether C++ ostreams are used //! Used to determine whether C++ ostreams are used which can increase
//! Those can lead to code bloat. //! the binary size significantly. If this is disabled,
//! the C stdio functions can be used alternatively
#define FSFW_CPP_OSTREAM_ENABLED 1 #define FSFW_CPP_OSTREAM_ENABLED 1
//! Reduced printout to further decrease code size //! More FSFW related printouts depending on level. Useful for development.
//! Be careful, this also turns off most diagnostic prinouts! #define FSFW_VERBOSE_LEVEL 1
#define FSFW_ENHANCED_PRINTOUT 0
//! Can be used to enable additional debugging printouts for developing the FSFW //! Can be used to completely disable printouts, even the C stdio ones.
#define FSFW_PRINT_VERBOSITY_LEVEL 0 #if FSFW_CPP_OSTREAM_ENABLED == 0 && FSFW_VERBOSE_LEVEL == 0
#define FSFW_DISABLE_PRINTOUT 0
#endif
//! Can be used to disable the ANSI color sequences for C stdio.
#define FSFW_COLORED_OUTPUT 1
//! If FSFW_OBJ_EVENT_TRANSLATION is set to one, //! If FSFW_OBJ_EVENT_TRANSLATION is set to one,
//! additional output which requires the translation files translateObjects //! additional output which requires the translation files translateObjects
@ -50,6 +55,8 @@ static constexpr size_t FSFW_EVENTMGMR_RANGEMATCHERS = 120;
//! simulataneously. This will increase the required RAM for //! simulataneously. This will increase the required RAM for
//! each CSB service ! //! each CSB service !
static constexpr uint8_t FSFW_CSB_FIFO_DEPTH = 6; static constexpr uint8_t FSFW_CSB_FIFO_DEPTH = 6;
static constexpr size_t FSFW_PRINT_BUFFER_SIZE = 124;
} }
#endif /* CONFIG_FSFWCONFIG_H_ */ #endif /* CONFIG_FSFWCONFIG_H_ */

View File

@ -3,11 +3,12 @@
#include "OBSWVersion.h" #include "OBSWVersion.h"
#ifdef __cplusplus
#include "objects/systemObjectList.h" #include "objects/systemObjectList.h"
#include "events/subsystemIdRanges.h" #include "events/subsystemIdRanges.h"
#include "returnvalues/classIds.h" #include "returnvalues/classIds.h"
#ifdef __cplusplus
namespace config { namespace config {
#endif #endif

View File

@ -2,7 +2,7 @@
#define CONFIG_DEVICES_LOGICALADDRESSES_H_ #define CONFIG_DEVICES_LOGICALADDRESSES_H_
#include <fsfw/devicehandlers/CookieIF.h> #include <fsfw/devicehandlers/CookieIF.h>
#include "../objects/systemObjectList.h" #include <objects/systemObjectList.h>
#include <cstdint> #include <cstdint>
/** /**

View File

@ -1,9 +1,5 @@
#include "Factory.h" #include "FsfwFactory.h"
#include "../tmtc/apid.h" #include <OBSWConfig.h>
#include "../tmtc/pusIds.h"
#include "../objects/systemObjectList.h"
#include "../devices/logicalAddresses.h"
#include "../devices/powerSwitcherList.h"
#include <fsfw/devicehandlers/DeviceHandlerBase.h> #include <fsfw/devicehandlers/DeviceHandlerBase.h>
#include <fsfw/events/EventManager.h> #include <fsfw/events/EventManager.h>
@ -11,24 +7,27 @@
#include <fsfw/tmtcpacket/pus/TmPacketStored.h> #include <fsfw/tmtcpacket/pus/TmPacketStored.h>
#include <fsfw/tmtcservices/CommandingServiceBase.h> #include <fsfw/tmtcservices/CommandingServiceBase.h>
#include <fsfw/tmtcservices/PusServiceBase.h> #include <fsfw/tmtcservices/PusServiceBase.h>
#include <internalError/InternalErrorReporter.h> #include <fsfw/internalError/InternalErrorReporter.h>
#include <cstdint> #include <cstdint>
/** /**
* This class should be used to create all system objects required for * This function builds all system objects required for using
* the on-board software, using the object ID list from the configuration * the FSFW. It is recommended to build all other required objects
* folder. * in a function with an identical prototype, call this function in it and
* then pass the function to the object manager so it builds all system
* objects on software startup.
* *
* The objects are registered in the internal object manager automatically. * All system objects are registered in the internal object manager
* This is used later to add objects to tasks. * automatically. The objects should be added to tasks at a later stage, using
* their objects IDs.
* *
* This file also sets static framework IDs. * This function also sets static framework IDs.
* *
* Framework objects are created first. * Framework should be created first before creating mission system objects.
* @ingroup init * @ingroup init
*/ */
void Factory::produce(void) { void Factory::produceFsfwObjects(void) {
setStaticFrameworkObjectIds(); setStaticFrameworkObjectIds();
new EventManager(objects::EVENT_MANAGER); new EventManager(objects::EVENT_MANAGER);
new HealthTable(objects::HEALTH_TABLE); new HealthTable(objects::HEALTH_TABLE);

View File

@ -1,5 +1,5 @@
#ifndef FACTORY_H_ #ifndef FSFWCONFIG_OBJECTS_FACTORY_H_
#define FACTORY_H_ #define FSFWCONFIG_OBJECTS_FACTORY_H_
#include <fsfw/objectmanager/SystemObjectIF.h> #include <fsfw/objectmanager/SystemObjectIF.h>
#include <cstddef> #include <cstddef>
@ -9,9 +9,9 @@ namespace Factory {
* @brief Creates all SystemObject elements which are persistent * @brief Creates all SystemObject elements which are persistent
* during execution. * during execution.
*/ */
void produce(); void produceFsfwObjects();
void setStaticFrameworkObjectIds(); void setStaticFrameworkObjectIds();
} }
#endif /* FACTORY_H_ */ #endif /* FSFWCONFIG_OBJECTS_FACTORY_H_ */

View File

@ -15,8 +15,10 @@ ReturnValue_t pst::pollingSequenceInitDefault(
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
else { else {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "pst::pollingSequenceInitDefault: Sequence invalid!" sif::error << "pst::pollingSequenceInitDefault: Sequence invalid!"
<< std::endl; << std::endl;
#endif
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
} }

View File

@ -2,7 +2,7 @@
#include "AcceptsDeviceResponsesIF.h" #include "AcceptsDeviceResponsesIF.h"
#include "DeviceTmReportingWrapper.h" #include "DeviceTmReportingWrapper.h"
#include "../serviceinterface/ServiceInterfaceStream.h" #include "../serviceinterface/ServiceInterface.h"
#include "../objectmanager/ObjectManager.h" #include "../objectmanager/ObjectManager.h"
#include "../storagemanager/StorageManagerIF.h" #include "../storagemanager/StorageManagerIF.h"
#include "../thermal/ThermalComponentIF.h" #include "../thermal/ThermalComponentIF.h"
@ -13,9 +13,6 @@
#include "../subsystem/SubsystemBase.h" #include "../subsystem/SubsystemBase.h"
#include "../datapoollocal/LocalPoolVariable.h" #include "../datapoollocal/LocalPoolVariable.h"
#include <iomanip>
object_id_t DeviceHandlerBase::powerSwitcherId = objects::NO_OBJECT; object_id_t DeviceHandlerBase::powerSwitcherId = objects::NO_OBJECT;
object_id_t DeviceHandlerBase::rawDataReceiverId = objects::NO_OBJECT; object_id_t DeviceHandlerBase::rawDataReceiverId = objects::NO_OBJECT;
object_id_t DeviceHandlerBase::defaultFdirParentId = objects::NO_OBJECT; object_id_t DeviceHandlerBase::defaultFdirParentId = objects::NO_OBJECT;
@ -27,7 +24,7 @@ DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId,
wiretappingMode(OFF), storedRawData(StorageManagerIF::INVALID_ADDRESS), wiretappingMode(OFF), storedRawData(StorageManagerIF::INVALID_ADDRESS),
deviceCommunicationId(deviceCommunication), comCookie(comCookie), deviceCommunicationId(deviceCommunication), comCookie(comCookie),
healthHelper(this,setObjectId), modeHelper(this), parameterHelper(this), healthHelper(this,setObjectId), modeHelper(this), parameterHelper(this),
actionHelper(this, nullptr), hkManager(this, nullptr), actionHelper(this, nullptr), poolManager(this, nullptr),
childTransitionFailure(RETURN_OK), fdirInstance(fdirInstance), childTransitionFailure(RETURN_OK), fdirInstance(fdirInstance),
hkSwitcher(this), defaultFDIRUsed(fdirInstance == nullptr), hkSwitcher(this), defaultFDIRUsed(fdirInstance == nullptr),
switchOffWasReported(false), childTransitionDelay(5000), switchOffWasReported(false), childTransitionDelay(5000),
@ -39,11 +36,8 @@ DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId,
cookieInfo.state = COOKIE_UNUSED; cookieInfo.state = COOKIE_UNUSED;
cookieInfo.pendingCommand = deviceCommandMap.end(); cookieInfo.pendingCommand = deviceCommandMap.end();
if (comCookie == nullptr) { if (comCookie == nullptr) {
sif::error << "DeviceHandlerBase: ObjectID 0x" << std::hex printWarningOrError(sif::OutputTypes::OUT_ERROR, "DeviceHandlerBase",
<< std::setw(8) << std::setfill('0') << this->getObjectId() HasReturnvaluesIF::RETURN_FAILED, "Invalid cookie");
<< std::dec << ": Do not pass nullptr as a cookie, consider "
<< std::setfill(' ') << "passing a dummy cookie instead!"
<< std::endl;
} }
if (this->fdirInstance == nullptr) { if (this->fdirInstance == nullptr) {
this->fdirInstance = new DeviceHandlerFailureIsolation(setObjectId, this->fdirInstance = new DeviceHandlerFailureIsolation(setObjectId,
@ -113,7 +107,7 @@ ReturnValue_t DeviceHandlerBase::performOperation(uint8_t counter) {
doGetRead(); doGetRead();
// This will be performed after datasets have been updated by the // This will be performed after datasets have been updated by the
// custom device implementation. // custom device implementation.
hkManager.performHkOperation(); poolManager.performHkOperation();
break; break;
default: default:
break; break;
@ -130,24 +124,24 @@ ReturnValue_t DeviceHandlerBase::initialize() {
communicationInterface = objectManager->get<DeviceCommunicationIF>( communicationInterface = objectManager->get<DeviceCommunicationIF>(
deviceCommunicationId); deviceCommunicationId);
if (communicationInterface == nullptr) { if (communicationInterface == nullptr) {
sif::error << "DeviceHandlerBase::initialize: Communication interface " printWarningOrError(sif::OutputTypes::OUT_ERROR, "initialize",
"invalid." << std::endl; ObjectManagerIF::CHILD_INIT_FAILED,
sif::error << "Make sure it is set up properly and implements" "Passed communication IF invalid");
" DeviceCommunicationIF" << std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED; return ObjectManagerIF::CHILD_INIT_FAILED;
} }
result = communicationInterface->initializeInterface(comCookie); result = communicationInterface->initializeInterface(comCookie);
if (result != RETURN_OK) { if (result != RETURN_OK) {
sif::error << "DeviceHandlerBase::initialize: Initializing " printWarningOrError(sif::OutputTypes::OUT_ERROR, "initialize",
"communication interface failed!" << std::endl; ObjectManagerIF::CHILD_INIT_FAILED,
"ComIF initialization failed");
return result; return result;
} }
IPCStore = objectManager->get<StorageManagerIF>(objects::IPC_STORE); IPCStore = objectManager->get<StorageManagerIF>(objects::IPC_STORE);
if (IPCStore == nullptr) { if (IPCStore == nullptr) {
sif::error << "DeviceHandlerBase::initialize: IPC store not set up in " printWarningOrError(sif::OutputTypes::OUT_ERROR, "initialize",
"factory." << std::endl; ObjectManagerIF::CHILD_INIT_FAILED, "IPC Store not set up");
return ObjectManagerIF::CHILD_INIT_FAILED; return ObjectManagerIF::CHILD_INIT_FAILED;
} }
@ -156,10 +150,16 @@ ReturnValue_t DeviceHandlerBase::initialize() {
AcceptsDeviceResponsesIF>(rawDataReceiverId); AcceptsDeviceResponsesIF>(rawDataReceiverId);
if (rawReceiver == nullptr) { if (rawReceiver == nullptr) {
sif::error << "DeviceHandlerBase::initialize: Raw receiver object " printWarningOrError(sif::OutputTypes::OUT_ERROR,
"ID set but no valid object found." << std::endl; "initialize", ObjectManagerIF::CHILD_INIT_FAILED,
"Raw receiver object ID set but no valid object found.");
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "Make sure the raw receiver object is set up properly" sif::error << "Make sure the raw receiver object is set up properly"
" and implements AcceptsDeviceResponsesIF" << std::endl; " and implements AcceptsDeviceResponsesIF" << std::endl;
#else
sif::printError("Make sure the raw receiver object is set up "
"properly and implements AcceptsDeviceResponsesIF\n");
#endif
return ObjectManagerIF::CHILD_INIT_FAILED; return ObjectManagerIF::CHILD_INIT_FAILED;
} }
defaultRawReceiver = rawReceiver->getDeviceQueue(); defaultRawReceiver = rawReceiver->getDeviceQueue();
@ -168,10 +168,16 @@ ReturnValue_t DeviceHandlerBase::initialize() {
if(powerSwitcherId != objects::NO_OBJECT) { if(powerSwitcherId != objects::NO_OBJECT) {
powerSwitcher = objectManager->get<PowerSwitchIF>(powerSwitcherId); powerSwitcher = objectManager->get<PowerSwitchIF>(powerSwitcherId);
if (powerSwitcher == nullptr) { if (powerSwitcher == nullptr) {
sif::error << "DeviceHandlerBase::initialize: Power switcher " printWarningOrError(sif::OutputTypes::OUT_ERROR,
<< "object ID set but no valid object found." << std::endl; "initialize", ObjectManagerIF::CHILD_INIT_FAILED,
sif::error << "Make sure the raw receiver object is set up properly" "Power switcher set but no valid object found.");
<< " and implements PowerSwitchIF" << std::endl; #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "Make sure the power switcher object is set up "
<< "properly and implements PowerSwitchIF" << std::endl;
#else
sif::printError("Make sure the power switcher object is set up "
"properly and implements PowerSwitchIF\n");
#endif
return ObjectManagerIF::CHILD_INIT_FAILED; return ObjectManagerIF::CHILD_INIT_FAILED;
} }
} }
@ -204,7 +210,7 @@ ReturnValue_t DeviceHandlerBase::initialize() {
return result; return result;
} }
result = hkManager.initialize(commandQueue); result = poolManager.initialize(commandQueue);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
return result; return result;
} }
@ -217,7 +223,8 @@ ReturnValue_t DeviceHandlerBase::initialize() {
if(result == HasReturnvaluesIF::RETURN_OK) { if(result == HasReturnvaluesIF::RETURN_OK) {
thermalSet->heaterRequest.value = thermalSet->heaterRequest.value =
ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL; ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL;
thermalSet->commit(PoolVariableIF::VALID); thermalSet->heaterRequest.setValid(true);
thermalSet->commit();
} }
} }
@ -273,7 +280,7 @@ void DeviceHandlerBase::readCommandQueue() {
return; return;
} }
result = hkManager.handleHousekeepingMessage(&command); result = poolManager.handleHousekeepingMessage(&command);
if (result == RETURN_OK) { if (result == RETURN_OK) {
return; return;
} }
@ -543,17 +550,17 @@ void DeviceHandlerBase::replyReturnvalueToCommand(ReturnValue_t status,
void DeviceHandlerBase::replyToCommand(ReturnValue_t status, void DeviceHandlerBase::replyToCommand(ReturnValue_t status,
uint32_t parameter) { uint32_t parameter) {
//Check if we reply to a raw command. // Check if we reply to a raw command.
if (cookieInfo.pendingCommand->first == RAW_COMMAND_ID) { if (cookieInfo.pendingCommand->first == RAW_COMMAND_ID) {
if (status == NO_REPLY_EXPECTED) { if (status == NO_REPLY_EXPECTED) {
status = RETURN_OK; status = RETURN_OK;
} }
replyReturnvalueToCommand(status, parameter); replyReturnvalueToCommand(status, parameter);
//Always delete data from a raw command. // Always delete data from a raw command.
IPCStore->deleteData(storedRawData); IPCStore->deleteData(storedRawData);
return; return;
} }
//Check if we were externally commanded. // Check if we were externally commanded.
if (cookieInfo.pendingCommand->second.sendReplyTo != NO_COMMANDER) { if (cookieInfo.pendingCommand->second.sendReplyTo != NO_COMMANDER) {
MessageQueueId_t queueId = cookieInfo.pendingCommand->second.sendReplyTo; MessageQueueId_t queueId = cookieInfo.pendingCommand->second.sendReplyTo;
if (status == NO_REPLY_EXPECTED) { if (status == NO_REPLY_EXPECTED) {
@ -568,15 +575,17 @@ void DeviceHandlerBase::replyToCommand(ReturnValue_t status,
void DeviceHandlerBase::replyToReply(DeviceReplyMap::iterator iter, void DeviceHandlerBase::replyToReply(DeviceReplyMap::iterator iter,
ReturnValue_t status) { ReturnValue_t status) {
//No need to check if iter exists, as this is checked by callers. If someone else uses the method, add check. // No need to check if iter exists, as this is checked by callers.
// If someone else uses the method, add check.
if (iter->second.command == deviceCommandMap.end()) { if (iter->second.command == deviceCommandMap.end()) {
//Is most likely periodic reply. Silent return. //Is most likely periodic reply. Silent return.
return; return;
} }
//Check if more replies are expected. If so, do nothing. // Check if more replies are expected. If so, do nothing.
DeviceCommandInfo* info = &(iter->second.command->second); DeviceCommandInfo* info = &(iter->second.command->second);
if (--info->expectedReplies == 0) { if (--info->expectedReplies == 0) {
//Check if it was transition or internal command. Don't send any replies in that case. // Check if it was transition or internal command.
// Don't send any replies in that case.
if (info->sendReplyTo != NO_COMMANDER) { if (info->sendReplyTo != NO_COMMANDER) {
actionHelper.finish(info->sendReplyTo, iter->first, status); actionHelper.finish(info->sendReplyTo, iter->first, status);
} }
@ -593,7 +602,7 @@ void DeviceHandlerBase::doSendWrite() {
if (result == RETURN_OK) { if (result == RETURN_OK) {
cookieInfo.state = COOKIE_WRITE_SENT; cookieInfo.state = COOKIE_WRITE_SENT;
} else { } else {
//always generate a failure event, so that FDIR knows what's up // always generate a failure event, so that FDIR knows what's up
triggerEvent(DEVICE_SENDING_COMMAND_FAILED, result, triggerEvent(DEVICE_SENDING_COMMAND_FAILED, result,
cookieInfo.pendingCommand->first); cookieInfo.pendingCommand->first);
replyToCommand(result); replyToCommand(result);
@ -682,8 +691,10 @@ void DeviceHandlerBase::doGetRead() {
replyRawData(receivedData, receivedDataLen, requestedRawTraffic); replyRawData(receivedData, receivedDataLen, requestedRawTraffic);
} }
if (mode == MODE_RAW and defaultRawReceiver != MessageQueueIF::NO_QUEUE) { if (mode == MODE_RAW) {
replyRawReplyIfnotWiretapped(receivedData, receivedDataLen); if (defaultRawReceiver != MessageQueueIF::NO_QUEUE) {
replyRawReplyIfnotWiretapped(receivedData, receivedDataLen);
}
} }
else { else {
parseReply(receivedData, receivedDataLen); parseReply(receivedData, receivedDataLen);
@ -706,8 +717,9 @@ void DeviceHandlerBase::parseReply(const uint8_t* receivedData,
case RETURN_OK: case RETURN_OK:
handleReply(receivedData, foundId, foundLen); handleReply(receivedData, foundId, foundLen);
if(foundLen == 0) { if(foundLen == 0) {
sif::warning << "DeviceHandlerBase::parseReply: foundLen is 0!" printWarningOrError(sif::OutputTypes::OUT_WARNING,
" Packet parsing will be stuck." << std::endl; "parseReply", ObjectManagerIF::CHILD_INIT_FAILED,
"Found length is one, parsing might be stuck");
} }
break; break;
case APERIODIC_REPLY: { case APERIODIC_REPLY: {
@ -718,8 +730,13 @@ void DeviceHandlerBase::parseReply(const uint8_t* receivedData,
foundId); foundId);
} }
if(foundLen == 0) { if(foundLen == 0) {
printWarningOrError(sif::OutputTypes::OUT_ERROR,
"parseReply", ObjectManagerIF::CHILD_INIT_FAILED,
"Power switcher set but no valid object found.");
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "DeviceHandlerBase::parseReply: foundLen is 0!" sif::warning << "DeviceHandlerBase::parseReply: foundLen is 0!"
" Packet parsing will be stuck." << std::endl; " Packet parsing will be stuck." << std::endl;
#endif
} }
break; break;
} }
@ -728,7 +745,8 @@ void DeviceHandlerBase::parseReply(const uint8_t* receivedData,
case IGNORE_FULL_PACKET: case IGNORE_FULL_PACKET:
return; return;
default: default:
//We need to wait for timeout.. don't know what command failed and who sent it. // We need to wait for timeout.. don't know what command failed
// and who sent it.
replyRawReplyIfnotWiretapped(receivedData, foundLen); replyRawReplyIfnotWiretapped(receivedData, foundLen);
triggerEvent(DEVICE_READING_REPLY_FAILED, result, foundLen); triggerEvent(DEVICE_READING_REPLY_FAILED, result, foundLen);
break; break;
@ -949,7 +967,8 @@ ReturnValue_t DeviceHandlerBase::getStateOfSwitches(void) {
} }
Mode_t DeviceHandlerBase::getBaseMode(Mode_t transitionMode) { Mode_t DeviceHandlerBase::getBaseMode(Mode_t transitionMode) {
//only child action special modes are handled, as a child should never see any base action modes // only child action special modes are handled, as a child should
// never see any base action modes
if (transitionMode == _MODE_START_UP) { if (transitionMode == _MODE_START_UP) {
return _MODE_TO_ON; return _MODE_TO_ON;
} }
@ -1272,10 +1291,11 @@ void DeviceHandlerBase::buildInternalCommand(void) {
if (mode == MODE_NORMAL) { if (mode == MODE_NORMAL) {
result = buildNormalDeviceCommand(&deviceCommandId); result = buildNormalDeviceCommand(&deviceCommandId);
if (result == BUSY) { if (result == BUSY) {
//so we can track misconfigurations // so we can track misconfigurations
sif::debug << std::hex << getObjectId() printWarningOrError(sif::OutputTypes::OUT_WARNING,
<< ": DHB::buildInternalCommand: Busy" << std::dec "buildInternalCommand",
<< std::endl; HasReturnvaluesIF::RETURN_FAILED,
"Busy.");
result = NOTHING_TO_SEND; //no need to report this result = NOTHING_TO_SEND; //no need to report this
} }
} }
@ -1299,11 +1319,16 @@ void DeviceHandlerBase::buildInternalCommand(void) {
if (iter == deviceCommandMap.end()) { if (iter == deviceCommandMap.end()) {
result = COMMAND_NOT_SUPPORTED; result = COMMAND_NOT_SUPPORTED;
} else if (iter->second.isExecuting) { } else if (iter->second.isExecuting) {
//so we can track misconfigurations #if FSFW_DISABLE_PRINTOUT == 0
sif::debug << std::hex << getObjectId() char output[36];
<< ": DHB::buildInternalCommand: Command " sprintf(output, "Command 0x%08x is executing",
<< deviceCommandId << " isExecuting" << std::dec static_cast<unsigned int>(deviceCommandId));
<< std::endl; // so we can track misconfigurations
printWarningOrError(sif::OutputTypes::OUT_WARNING,
"buildInternalCommand",
HasReturnvaluesIF::RETURN_FAILED,
output);
#endif
// this is an internal command, no need to report a failure here, // this is an internal command, no need to report a failure here,
// missed reply will track if a reply is too late, otherwise, it's ok // missed reply will track if a reply is too late, otherwise, it's ok
return; return;
@ -1396,7 +1421,7 @@ void DeviceHandlerBase::performOperationHook() {
} }
ReturnValue_t DeviceHandlerBase::initializeLocalDataPool( ReturnValue_t DeviceHandlerBase::initializeLocalDataPool(
LocalDataPool &localDataPoolMap, localpool::DataPool &localDataPoolMap,
LocalDataPoolManager& poolManager) { LocalDataPoolManager& poolManager) {
if(thermalSet != nullptr) { if(thermalSet != nullptr) {
localDataPoolMap.emplace(thermalSet->thermalStatePoolId, localDataPoolMap.emplace(thermalSet->thermalStatePoolId,
@ -1407,18 +1432,13 @@ ReturnValue_t DeviceHandlerBase::initializeLocalDataPool(
return RETURN_OK; return RETURN_OK;
} }
LocalDataPoolManager* DeviceHandlerBase::getHkManagerHandle() {
return &hkManager;
}
ReturnValue_t DeviceHandlerBase::initializeAfterTaskCreation() { ReturnValue_t DeviceHandlerBase::initializeAfterTaskCreation() {
// In this function, the task handle should be valid if the task // In this function, the task handle should be valid if the task
// was implemented correctly. We still check to be 1000 % sure :-) // was implemented correctly. We still check to be 1000 % sure :-)
if(executingTask != nullptr) { if(executingTask != nullptr) {
pstIntervalMs = executingTask->getPeriodMs(); pstIntervalMs = executingTask->getPeriodMs();
} }
this->hkManager.initializeAfterTaskCreation(); this->poolManager.initializeAfterTaskCreation();
if(setStartupImmediately) { if(setStartupImmediately) {
startTransition(MODE_ON, SUBMODE_NONE); startTransition(MODE_ON, SUBMODE_NONE);
@ -1462,3 +1482,52 @@ void DeviceHandlerBase::setNormalDatapoolEntriesInvalid() {
} }
} }
} }
void DeviceHandlerBase::printWarningOrError(sif::OutputTypes errorType,
const char *functionName, ReturnValue_t errorCode,
const char *errorPrint) {
if(errorPrint == nullptr) {
if(errorCode == ObjectManagerIF::CHILD_INIT_FAILED) {
errorPrint = "Initialization error";
}
if(errorCode == HasReturnvaluesIF::RETURN_FAILED) {
if(errorType == sif::OutputTypes::OUT_WARNING) {
errorPrint = "Generic Warning";
}
else {
errorPrint = "Generic Error";
}
}
else {
errorPrint = "Unknown error";
}
}
if(errorType == sif::OutputTypes::OUT_WARNING) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "DeviceHandlerBase::" << functionName << ": Object ID "
<< std::hex << std::setw(8) << std::setfill('0')
<< this->getObjectId() << " | " << errorPrint << std::dec
<< std::setfill(' ') << std::endl;
#else
sif::printWarning("DeviceHandlerBase::%s: Object ID 0x%08x | %s\n",
this->getObjectId(), errorPrint);
#endif
}
else if(errorType == sif::OutputTypes::OUT_ERROR) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "DeviceHandlerBase::" << functionName << ": Object ID "
<< std::hex << std::setw(8) << std::setfill('0')
<< this->getObjectId() << " | " << errorPrint << std::dec
<< std::setfill(' ') << std::endl;
#else
sif::printError("DeviceHandlerBase::%s: Object ID 0x%08x | %s\n",
this->getObjectId(), errorPrint);
#endif
}
}
LocalDataPoolManager* DeviceHandlerBase::getHkManagerHandle() {
return &poolManager;
}

View File

@ -6,6 +6,8 @@
#include "DeviceHandlerFailureIsolation.h" #include "DeviceHandlerFailureIsolation.h"
#include "DeviceHandlerThermalSet.h" #include "DeviceHandlerThermalSet.h"
#include "../serviceinterface/ServiceInterface.h"
#include "../serviceinterface/serviceInterfaceDefintions.h"
#include "../objectmanager/SystemObject.h" #include "../objectmanager/SystemObject.h"
#include "../tasks/ExecutableObjectIF.h" #include "../tasks/ExecutableObjectIF.h"
#include "../returnvalues/HasReturnvaluesIF.h" #include "../returnvalues/HasReturnvaluesIF.h"
@ -512,11 +514,14 @@ protected:
* @param localDataPoolMap * @param localDataPoolMap
* @return * @return
*/ */
virtual ReturnValue_t initializeLocalDataPool(LocalDataPool& localDataPoolMap, virtual ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
LocalDataPoolManager& poolManager) override; LocalDataPoolManager& poolManager) override;
/** Get the HK manager object handle */ /**
virtual LocalDataPoolManager* getHkManagerHandle() override; * Required for HasLocalDataPoolIF, return a handle to the local pool manager.
* @return
*/
LocalDataPoolManager* getHkManagerHandle() override;
/** /**
* @brief Hook function for child handlers which is called once per * @brief Hook function for child handlers which is called once per
@ -646,7 +651,7 @@ protected:
/** Action helper for HasActionsIF */ /** Action helper for HasActionsIF */
ActionHelper actionHelper; ActionHelper actionHelper;
/** Housekeeping Manager */ /** Housekeeping Manager */
LocalDataPoolManager hkManager; LocalDataPoolManager poolManager;
/** /**
* @brief Information about commands * @brief Information about commands
@ -1111,7 +1116,7 @@ private:
/** /**
* @brief The mode the current transition originated from * @brief The mode the current transition originated from
* *
* This is private so the child can not change it and fuck up the timeouts * This is private so the child can not change it and mess up the timeouts
* *
* IMPORTANT: This is not valid during _MODE_SHUT_DOWN and _MODE_START_UP!! * IMPORTANT: This is not valid during _MODE_SHUT_DOWN and _MODE_START_UP!!
* (it is _MODE_POWER_DOWN during this modes) * (it is _MODE_POWER_DOWN during this modes)
@ -1190,7 +1195,8 @@ private:
* Check if the RMAP sendWrite action was successful. * Check if the RMAP sendWrite action was successful.
* *
* Depending on the result, the following is done * Depending on the result, the following is done
* - if the device command was external commanded, a reply is sent indicating the result * - if the device command was external commanded, a reply is sent
* indicating the result
* - if the action was successful, the reply timout counter is initialized * - if the action was successful, the reply timout counter is initialized
*/ */
void doGetWrite(void); void doGetWrite(void);
@ -1206,9 +1212,9 @@ private:
/** /**
* Check the getRead reply and the contained data. * Check the getRead reply and the contained data.
* *
* If data was received scanForReply() and, if successful, handleReply() are called. * If data was received scanForReply() and, if successful, handleReply()
* If the current mode is @c MODE_RAW, the received packet is sent to the commanding object * are called. If the current mode is @c MODE_RAW, the received packet
* via commandQueue. * is sent to the commanding object via commandQueue.
*/ */
void doGetRead(void); void doGetRead(void);
@ -1227,7 +1233,7 @@ private:
uint32_t *len); uint32_t *len);
/** /**
* @param modeTo either @c MODE_ON, MODE_NORMAL or MODE_RAW NOTHING ELSE!!! * @param modeTo either @c MODE_ON, MODE_NORMAL or MODE_RAW, nothing else!
*/ */
void setTransition(Mode_t modeTo, Submode_t submodeTo); void setTransition(Mode_t modeTo, Submode_t submodeTo);
@ -1247,6 +1253,11 @@ private:
void handleTransitionToOnMode(Mode_t commandedMode, void handleTransitionToOnMode(Mode_t commandedMode,
Submode_t commandedSubmode); Submode_t commandedSubmode);
void printWarningOrError(sif::OutputTypes errorType,
const char* functionName,
ReturnValue_t errorCode = HasReturnvaluesIF::RETURN_FAILED,
const char* errorPrint = nullptr);
}; };
#endif /* FSFW_DEVICEHANDLERS_DEVICEHANDLERBASE_H_ */ #endif /* FSFW_DEVICEHANDLERS_DEVICEHANDLERBASE_H_ */

View File

@ -169,8 +169,10 @@ void DeviceHandlerFailureIsolation::clearFaultCounters() {
ReturnValue_t DeviceHandlerFailureIsolation::initialize() { ReturnValue_t DeviceHandlerFailureIsolation::initialize() {
ReturnValue_t result = FailureIsolationBase::initialize(); ReturnValue_t result = FailureIsolationBase::initialize();
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "DeviceHandlerFailureIsolation::initialize: Could not" sif::error << "DeviceHandlerFailureIsolation::initialize: Could not"
" initialize FailureIsolationBase." << std::endl; " initialize FailureIsolationBase." << std::endl;
#endif
return result; return result;
} }
ConfirmsFailuresIF* power = objectManager->get<ConfirmsFailuresIF>( ConfirmsFailuresIF* power = objectManager->get<ConfirmsFailuresIF>(
@ -250,8 +252,10 @@ bool DeviceHandlerFailureIsolation::isFdirInActionOrAreWeFaulty(
if (owner == nullptr) { if (owner == nullptr) {
// Configuration error. // Configuration error.
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "DeviceHandlerFailureIsolation::" sif::error << "DeviceHandlerFailureIsolation::"
<< "isFdirInActionOrAreWeFaulty: Owner not set!" << std::endl; << "isFdirInActionOrAreWeFaulty: Owner not set!" << std::endl;
#endif
return false; return false;
} }

View File

@ -3,8 +3,8 @@
#include "DeviceHandlerMessage.h" #include "DeviceHandlerMessage.h"
#include "../datapoollocal/localPoolDefinitions.h"
#include "../action/HasActionsIF.h" #include "../action/HasActionsIF.h"
#include "../datapoollocal/locPoolDefinitions.h"
#include "../events/Event.h" #include "../events/Event.h"
#include "../modes/HasModesIF.h" #include "../modes/HasModesIF.h"
#include "../ipc/MessageQueueSenderIF.h" #include "../ipc/MessageQueueSenderIF.h"

View File

@ -0,0 +1 @@
## Controllers

View File

@ -16,9 +16,8 @@ Flight Software Framework
* A reference to an object can be get by calling the following function. T must be the specific Interface you want to call. * 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. A nullptr check of the returning Pointer must be done. This function is based on Run-time type information.
``` c++ ```cpp
template <typename T> T* ObjectManagerIF::get( object_id_t id ) 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. * 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. By calling objectManager->initialize() the produce function will be called and all SystemObjects will be initialized afterwards.

View File

@ -1 +1 @@
## FSFW DeviceHandlers ## Device Handlers

99
doc/README-highlevel.md Normal file
View File

@ -0,0 +1,99 @@
# High-level overview
## 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 but exceptions are not allowed.
### Failure Handling
Functions should return a defined ReturnValue_t to signal to the caller that something has 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.
The OSAL provides periodic tasks, message queues, clocks and semaphores as well as mutexes.
The [OSAL README](doc/README-osal.md#top) provides more detailed information on provided components and how to use them.
### Core Components
The FSFW has following core components. More detailed informations can be found in the
[core component section](doc/README-core.md#top):
1. Tasks: Abstraction for different (periodic) task types like periodic tasks or tasks with fixed timeslots
2. ObjectManager: This module stores all `SystemObjects` by mapping a provided unique object ID to the object handles.
3. Static Stores: Different stores are provided to store data of variable size (like telecommands or small telemetry) in a pool structure without
using dynamic memory allocation. These pools are allocated up front.
3. Clock: This module provided common time related functions
4. EventManager: This module allows routing of events generated by `SystemObjects`
5. HealthTable: A component which stores the health states of objects
### 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.
#### Device Handlers
DeviceHandlers are another important 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 device handler (DH) can be tested on different hardware.
The DH has mechanisms to monitor the communication with the physical device which allow for FDIR reaction.
Device Handlers can be created by overriding `DeviceHandlerBase`.
A standard FDIR component for the DH will be created automatically but can be overwritten by the user.
More information on DeviceHandlers can be found in the related [documentation section](doc/README-devicehandlers.md#top).
#### 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.
## Unit Tests
Unit Tests are provided in the unittest folder. Those use the catch2 framework but do not include catch2 itself. More information on how to run these tests can be found in the separate
[`fsfw_tests` reposoitory](https://egit.irs.uni-stuttgart.de/fsfw/fsfw_tests)

3
doc/README-localpools.md Normal file
View File

@ -0,0 +1,3 @@
## Local Data Pools

32
doc/README-osal.md Normal file
View File

@ -0,0 +1,32 @@
# Operating System Abstraction Layer (OSAL)
Some specific information on the provided OSALs are provided.
## Linux OSAL
This OSAL can be used to compile for Linux host systems like Ubuntu 20.04 or for
embedded Linux targets like the Raspberry Pi. This OSAL generally requires threading support
and real-time functionalities. For most UNIX systems, this is done by adding `-lrt` and `-lpthread` to the linked libraries in the compilation process. The CMake build support provided will do this automatically for the `fsfw` target. It should be noted that most UNIX systems need to be configured specifically to allow the real-time functionalities required by the FSFW.
More information on how to set up a Linux system accordingly can be found in the
[Linux README of the FSFW example application](https://egit.irs.uni-stuttgart.de/fsfw/fsfw_example/src/branch/master/doc/README-linux.md#top)
## Hosted OSAL
This is the newest OSAL. Support for Semaphores has not been implemented yet and will propably be implemented as soon as C++20 with Semaphore support has matured. This OSAL can be used to run the FSFW on any host system, but currently has only been tested on Windows 10 and Ubuntu 20.04. Unlike the other OSALs, it uses dynamic memory allocation (e.g. for the message queue implementation). Cross-platform serial port (USB) support might be added soon.
## FreeRTOS OSAL
FreeRTOS is not included and the developer needs to take care of compiling the FreeRTOS sources and adding the `FreeRTOSConfig.h` file location to the include path. This OSAL has only been tested extensively with the pre-emptive scheduler configuration so far but it should in principle also be possible to use a cooperative scheduler. It is recommended to use the `heap_4` allocation scheme. When using newlib (nano), it is also recommended to add `#define configUSE_NEWLIB_REENTRANT` to the FreeRTOS configuration file to ensure thread-safety.
When using this OSAL, developers also need to provide an implementation for the `vRequestContextSwitchFromISR` function. This has been done because the call to request a context switch from an ISR is generally located in the `portmacro.h` header and is different depending on the target architecture or device.
## RTEMS OSAL
The RTEMS OSAL was the first implemented OSAL which is also used on the active satellite Flying Laptop.
## TCP/IP socket abstraction
The Linux and Host OSAL provide abstraction layers for the socket API. Currently, only UDP sockets have been imlemented. This is very useful to test TMTC handling either on the host computer directly (targeting localhost with a TMTC application) or on embedded Linux devices, sending TMTC packets via Ethernet.

1
doc/README-pus.md Normal file
View File

@ -0,0 +1 @@
## PUS Services

View File

@ -122,6 +122,7 @@ void EventManager::printEvent(EventMessage* message) {
case severity::INFO: case severity::INFO:
#if DEBUG_INFO_EVENT == 1 #if DEBUG_INFO_EVENT == 1
string = translateObject(message->getReporter()); string = translateObject(message->getReporter());
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "EVENT: "; sif::info << "EVENT: ";
if (string != 0) { if (string != 0) {
sif::info << string; sif::info << string;
@ -132,10 +133,12 @@ void EventManager::printEvent(EventMessage* message) {
<< std::dec << message->getEventId() << std::hex << ") P1: 0x" << std::dec << message->getEventId() << std::hex << ") P1: 0x"
<< message->getParameter1() << " P2: 0x" << message->getParameter1() << " P2: 0x"
<< message->getParameter2() << std::dec << std::endl; << message->getParameter2() << std::dec << std::endl;
#endif #endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
#endif /* DEBUG_INFO_EVENT == 1 */
break; break;
default: default:
string = translateObject(message->getReporter()); string = translateObject(message->getReporter());
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "EventManager: "; sif::debug << "EventManager: ";
if (string != 0) { if (string != 0) {
sif::debug << string; sif::debug << string;
@ -146,22 +149,28 @@ void EventManager::printEvent(EventMessage* message) {
sif::debug << " reported " << translateEvents(message->getEvent()) sif::debug << " reported " << translateEvents(message->getEvent())
<< " (" << std::dec << message->getEventId() << ") " << " (" << std::dec << message->getEventId() << ") "
<< std::endl; << std::endl;
sif::debug << std::hex << "P1 Hex: 0x" << message->getParameter1() sif::debug << std::hex << "P1 Hex: 0x" << message->getParameter1()
<< ", P1 Dec: " << std::dec << message->getParameter1() << ", P1 Dec: " << std::dec << message->getParameter1()
<< std::endl; << std::endl;
sif::debug << std::hex << "P2 Hex: 0x" << message->getParameter2() sif::debug << std::hex << "P2 Hex: 0x" << message->getParameter2()
<< ", P2 Dec: " << std::dec << message->getParameter2() << ", P2 Dec: " << std::dec << message->getParameter2()
<< std::endl; << std::endl;
#endif
break; break;
} }
} }
#endif #endif
void EventManager::lockMutex() { void EventManager::lockMutex() {
mutex->lockMutex(MutexIF::BLOCKING); mutex->lockMutex(timeoutType, timeoutMs);
} }
void EventManager::unlockMutex() { void EventManager::unlockMutex() {
mutex->unlockMutex(); mutex->unlockMutex();
} }
void EventManager::setMutexTimeout(MutexIF::TimeoutType timeoutType,
uint32_t timeoutMs) {
this->timeoutType = timeoutType;
this->timeoutMs = timeoutMs;
}

View File

@ -29,6 +29,8 @@ public:
EventManager(object_id_t setObjectId); EventManager(object_id_t setObjectId);
virtual ~EventManager(); virtual ~EventManager();
void setMutexTimeout(MutexIF::TimeoutType timeoutType, uint32_t timeoutMs);
MessageQueueId_t getEventReportQueue(); MessageQueueId_t getEventReportQueue();
ReturnValue_t registerListener(MessageQueueId_t listener, bool forwardAllButSelected = false); ReturnValue_t registerListener(MessageQueueId_t listener, bool forwardAllButSelected = false);
@ -51,6 +53,8 @@ protected:
std::map<MessageQueueId_t, EventMatchTree> listenerList; std::map<MessageQueueId_t, EventMatchTree> listenerList;
MutexIF* mutex = nullptr; MutexIF* mutex = nullptr;
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING;
uint32_t timeoutMs = 20;
static const uint8_t N_POOLS = 3; static const uint8_t N_POOLS = 3;
LocalPool factoryBackend; LocalPool factoryBackend;

View File

@ -21,8 +21,10 @@ ReturnValue_t FailureIsolationBase::initialize() {
EventManagerIF* manager = objectManager->get<EventManagerIF>( EventManagerIF* manager = objectManager->get<EventManagerIF>(
objects::EVENT_MANAGER); objects::EVENT_MANAGER);
if (manager == nullptr) { if (manager == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "FailureIsolationBase::initialize: Event Manager has not" sif::error << "FailureIsolationBase::initialize: Event Manager has not"
" been initialized!" << std::endl; " been initialized!" << std::endl;
#endif
return RETURN_FAILED; return RETURN_FAILED;
} }
ReturnValue_t result = manager->registerListener(eventQueue->getId()); ReturnValue_t result = manager->registerListener(eventQueue->getId());
@ -36,8 +38,10 @@ ReturnValue_t FailureIsolationBase::initialize() {
} }
owner = objectManager->get<HasHealthIF>(ownerId); owner = objectManager->get<HasHealthIF>(ownerId);
if (owner == nullptr) { if (owner == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "FailureIsolationBase::intialize: Owner object " sif::error << "FailureIsolationBase::intialize: Owner object "
"invalid. Make sure it implements HasHealthIF" << std::endl; "invalid. Make sure it implements HasHealthIF" << std::endl;
#endif
return ObjectManagerIF::CHILD_INIT_FAILED; return ObjectManagerIF::CHILD_INIT_FAILED;
} }
} }
@ -45,10 +49,14 @@ ReturnValue_t FailureIsolationBase::initialize() {
ConfirmsFailuresIF* parentIF = objectManager->get<ConfirmsFailuresIF>( ConfirmsFailuresIF* parentIF = objectManager->get<ConfirmsFailuresIF>(
faultTreeParent); faultTreeParent);
if (parentIF == nullptr) { if (parentIF == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "FailureIsolationBase::intialize: Parent object" sif::error << "FailureIsolationBase::intialize: Parent object"
<< "invalid." << std::endl; << "invalid." << std::endl;
#endif
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "Make sure it implements ConfirmsFailuresIF." sif::error << "Make sure it implements ConfirmsFailuresIF."
<< std::endl; << std::endl;
#endif
return ObjectManagerIF::CHILD_INIT_FAILED; return ObjectManagerIF::CHILD_INIT_FAILED;
return RETURN_FAILED; return RETURN_FAILED;
} }

View File

@ -10,6 +10,7 @@ CXXSRC += $(wildcard $(FRAMEWORK_PATH)/coordinates/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/datalinklayer/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/datalinklayer/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/datapool/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/datapool/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/datapoollocal/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/datapoollocal/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/datapoollocal/internal/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/housekeeping/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/housekeeping/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/devicehandlers/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/devicehandlers/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/events/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/events/*.cpp)

View File

@ -1,13 +1,17 @@
#include "arrayprinter.h" #include "arrayprinter.h"
#include "../serviceinterface/ServiceInterfaceStream.h" #include "../serviceinterface/ServiceInterface.h"
#include <bitset> #include <bitset>
void arrayprinter::print(const uint8_t *data, size_t size, OutputType type, void arrayprinter::print(const uint8_t *data, size_t size, OutputType type,
bool printInfo, size_t maxCharPerLine) { bool printInfo, size_t maxCharPerLine) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
if(printInfo) { if(printInfo) {
sif::info << "Printing data with size " << size << ": "; sif::info << "Printing data with size " << size << ": ";
} }
sif::info << "["; sif::info << "[";
#else
sif::printInfo("Printing data with size %zu: [", size);
#endif
if(type == OutputType::HEX) { if(type == OutputType::HEX) {
arrayprinter::printHex(data, size, maxCharPerLine); arrayprinter::printHex(data, size, maxCharPerLine);
} }
@ -21,6 +25,7 @@ void arrayprinter::print(const uint8_t *data, size_t size, OutputType type,
void arrayprinter::printHex(const uint8_t *data, size_t size, void arrayprinter::printHex(const uint8_t *data, size_t size,
size_t maxCharPerLine) { size_t maxCharPerLine) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << std::hex; sif::info << std::hex;
for(size_t i = 0; i < size; i++) { for(size_t i = 0; i < size; i++) {
sif::info << "0x" << static_cast<int>(data[i]); sif::info << "0x" << static_cast<int>(data[i]);
@ -28,16 +33,20 @@ void arrayprinter::printHex(const uint8_t *data, size_t size,
sif::info << " , "; sif::info << " , ";
if(i > 0 and i % maxCharPerLine == 0) { if(i > 0 and i % maxCharPerLine == 0) {
sif::info << std::endl; sif::info << std::endl;
} }
} }
} }
sif::info << std::dec; sif::info << std::dec;
sif::info << "]" << std::endl; sif::info << "]" << std::endl;
#else
// how much memory to reserve for printout?
#endif
} }
void arrayprinter::printDec(const uint8_t *data, size_t size, void arrayprinter::printDec(const uint8_t *data, size_t size,
size_t maxCharPerLine) { size_t maxCharPerLine) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << std::dec; sif::info << std::dec;
for(size_t i = 0; i < size; i++) { for(size_t i = 0; i < size; i++) {
sif::info << static_cast<int>(data[i]); sif::info << static_cast<int>(data[i]);
@ -49,13 +58,20 @@ void arrayprinter::printDec(const uint8_t *data, size_t size,
} }
} }
sif::info << "]" << std::endl; sif::info << "]" << std::endl;
#else
// how much memory to reserve for printout?
#endif
} }
void arrayprinter::printBin(const uint8_t *data, size_t size) { void arrayprinter::printBin(const uint8_t *data, size_t size) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "\n" << std::flush; sif::info << "\n" << std::flush;
for(size_t i = 0; i < size; i++) { for(size_t i = 0; i < size; i++) {
sif::info << "Byte " << i + 1 << ": 0b"<< sif::info << "Byte " << i + 1 << ": 0b"<<
std::bitset<8>(data[i]) << ",\n" << std::flush; std::bitset<8>(data[i]) << ",\n" << std::flush;
} }
sif::info << "]" << std::endl; sif::info << "]" << std::endl;
#else
// how much memory to reserve for printout?
#endif
} }

View File

@ -41,14 +41,18 @@ ReturnValue_t HealthHelper::initialize() {
eventSender = objectManager->get<EventReportingProxyIF>(objectId); eventSender = objectManager->get<EventReportingProxyIF>(objectId);
if (healthTable == nullptr) { if (healthTable == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "HealthHelper::initialize: Health table object needs" sif::error << "HealthHelper::initialize: Health table object needs"
"to be created in factory." << std::endl; "to be created in factory." << std::endl;
#endif
return ObjectManagerIF::CHILD_INIT_FAILED; return ObjectManagerIF::CHILD_INIT_FAILED;
} }
if(eventSender == nullptr) { if(eventSender == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "HealthHelper::initialize: Owner has to implement " sif::error << "HealthHelper::initialize: Owner has to implement "
"ReportingProxyIF." << std::endl; "ReportingProxyIF." << std::endl;
#endif
return ObjectManagerIF::CHILD_INIT_FAILED; return ObjectManagerIF::CHILD_INIT_FAILED;
} }
@ -79,8 +83,10 @@ void HealthHelper::informParent(HasHealthIF::HealthState health,
health, oldHealth); health, oldHealth);
if (MessageQueueSenderIF::sendMessage(parentQueue, &information, if (MessageQueueSenderIF::sendMessage(parentQueue, &information,
owner->getCommandQueue()) != HasReturnvaluesIF::RETURN_OK) { owner->getCommandQueue()) != HasReturnvaluesIF::RETURN_OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "HealthHelper::informParent: sending health reply failed." sif::debug << "HealthHelper::informParent: sending health reply failed."
<< std::endl; << std::endl;
#endif
} }
} }
@ -98,8 +104,10 @@ void HealthHelper::handleSetHealthCommand(CommandMessage* command) {
} }
if (MessageQueueSenderIF::sendMessage(command->getSender(), &reply, if (MessageQueueSenderIF::sendMessage(command->getSender(), &reply,
owner->getCommandQueue()) != HasReturnvaluesIF::RETURN_OK) { owner->getCommandQueue()) != HasReturnvaluesIF::RETURN_OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "HealthHelper::handleHealthCommand: sending health " sif::debug << "HealthHelper::handleHealthCommand: sending health "
"reply failed." << std::endl; "reply failed." << std::endl;
#endif
} }
} }

View File

@ -5,6 +5,8 @@
#include "../objectmanager/ObjectManagerIF.h" #include "../objectmanager/ObjectManagerIF.h"
#include "../returnvalues/HasReturnvaluesIF.h" #include "../returnvalues/HasReturnvaluesIF.h"
#include <utility>
class HealthTableIF: public ManagesHealthIF { class HealthTableIF: public ManagesHealthIF {
public: public:
virtual ~HealthTableIF() {} virtual ~HealthTableIF() {}

View File

@ -1,7 +1,7 @@
#ifndef FSFW_HOUSEKEEPING_HOUSEKEEPINGMESSAGE_H_ #ifndef FSFW_HOUSEKEEPING_HOUSEKEEPINGMESSAGE_H_
#define FSFW_HOUSEKEEPING_HOUSEKEEPINGMESSAGE_H_ #define FSFW_HOUSEKEEPING_HOUSEKEEPINGMESSAGE_H_
#include "../datapoollocal/locPoolDefinitions.h" #include "../datapoollocal/localPoolDefinitions.h"
#include "../ipc/CommandMessage.h" #include "../ipc/CommandMessage.h"
#include "../ipc/FwMessageTypes.h" #include "../ipc/FwMessageTypes.h"
#include "../objectmanager/frameworkObjects.h" #include "../objectmanager/frameworkObjects.h"

View File

@ -21,11 +21,11 @@ public:
InternalErrorDataset(object_id_t objectId): InternalErrorDataset(object_id_t objectId):
StaticLocalDataSet(sid_t(objectId , ERROR_SET_ID)) {} StaticLocalDataSet(sid_t(objectId , ERROR_SET_ID)) {}
lp_var_t<uint32_t> tmHits = lp_var_t<uint32_t>(hkManager->getOwner(), lp_var_t<uint32_t> tmHits = lp_var_t<uint32_t>(sid.objectId,
TM_HITS, this); TM_HITS, this);
lp_var_t<uint32_t> queueHits = lp_var_t<uint32_t>(hkManager->getOwner(), lp_var_t<uint32_t> queueHits = lp_var_t<uint32_t>(sid.objectId,
QUEUE_HITS, this); QUEUE_HITS, this);
lp_var_t<uint32_t> storeHits = lp_var_t<uint32_t>(hkManager->getOwner(), lp_var_t<uint32_t> storeHits = lp_var_t<uint32_t>(sid.objectId,
STORE_HITS, this); STORE_HITS, this);
}; };

View File

@ -2,7 +2,7 @@
#include "../ipc/QueueFactory.h" #include "../ipc/QueueFactory.h"
#include "../ipc/MutexFactory.h" #include "../ipc/MutexFactory.h"
#include "../serviceinterface/ServiceInterfaceStream.h" #include "../serviceinterface/ServiceInterface.h"
InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId, InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId,
uint32_t messageQueueDepth): SystemObject(setObjectId), uint32_t messageQueueDepth): SystemObject(setObjectId),
@ -23,20 +23,27 @@ void InternalErrorReporter::setDiagnosticPrintout(bool enable) {
} }
ReturnValue_t InternalErrorReporter::performOperation(uint8_t opCode) { ReturnValue_t InternalErrorReporter::performOperation(uint8_t opCode) {
internalErrorDataset.read(INTERNAL_ERROR_MUTEX_TIMEOUT); internalErrorDataset.read(timeoutType, timeoutMs);
uint32_t newQueueHits = getAndResetQueueHits(); uint32_t newQueueHits = getAndResetQueueHits();
uint32_t newTmHits = getAndResetTmHits(); uint32_t newTmHits = getAndResetTmHits();
uint32_t newStoreHits = getAndResetStoreHits(); uint32_t newStoreHits = getAndResetStoreHits();
#ifdef DEBUG #if FSFW_VERBOSE_LEVEL == 1
if(diagnosticPrintout) { if(diagnosticPrintout) {
if((newQueueHits > 0) or (newTmHits > 0) or (newStoreHits > 0)) { if((newQueueHits > 0) or (newTmHits > 0) or (newStoreHits > 0)) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "InternalErrorReporter::performOperation: Errors " sif::debug << "InternalErrorReporter::performOperation: Errors "
<< "occured!" << std::endl; << "occured!" << std::endl;
sif::debug << "Queue errors: " << newQueueHits << std::endl; sif::debug << "Queue errors: " << newQueueHits << std::endl;
sif::debug << "TM errors: " << newTmHits << std::endl; sif::debug << "TM errors: " << newTmHits << std::endl;
sif::debug << "Store errors: " << newStoreHits << std::endl; sif::debug << "Store errors: " << newStoreHits << std::endl;
#else
sif::printDebug("InternalErrorReporter::performOperation: Errors occured!\n");
sif::printDebug("Queue errors: %lu\n", static_cast<unsigned int>(newQueueHits));
sif::printDebug("TM errors: %lu\n", static_cast<unsigned int>(newTmHits));
sif::printDebug("Store errors: %lu\n", static_cast<unsigned int>(newStoreHits));
#endif
} }
} }
#endif #endif
@ -44,8 +51,8 @@ ReturnValue_t InternalErrorReporter::performOperation(uint8_t opCode) {
internalErrorDataset.queueHits.value += newQueueHits; internalErrorDataset.queueHits.value += newQueueHits;
internalErrorDataset.storeHits.value += newStoreHits; internalErrorDataset.storeHits.value += newStoreHits;
internalErrorDataset.tmHits.value += newTmHits; internalErrorDataset.tmHits.value += newTmHits;
internalErrorDataset.setValidity(true, true);
internalErrorDataset.commit(INTERNAL_ERROR_MUTEX_TIMEOUT); internalErrorDataset.commit(timeoutType, timeoutMs);
poolManager.performHkOperation(); poolManager.performHkOperation();
@ -67,7 +74,7 @@ void InternalErrorReporter::lostTm() {
uint32_t InternalErrorReporter::getAndResetQueueHits() { uint32_t InternalErrorReporter::getAndResetQueueHits() {
uint32_t value; uint32_t value;
mutex->lockMutex(MutexIF::WAITING, INTERNAL_ERROR_MUTEX_TIMEOUT); mutex->lockMutex(timeoutType, timeoutMs);
value = queueHits; value = queueHits;
queueHits = 0; queueHits = 0;
mutex->unlockMutex(); mutex->unlockMutex();
@ -76,21 +83,21 @@ uint32_t InternalErrorReporter::getAndResetQueueHits() {
uint32_t InternalErrorReporter::getQueueHits() { uint32_t InternalErrorReporter::getQueueHits() {
uint32_t value; uint32_t value;
mutex->lockMutex(MutexIF::WAITING, INTERNAL_ERROR_MUTEX_TIMEOUT); mutex->lockMutex(timeoutType, timeoutMs);
value = queueHits; value = queueHits;
mutex->unlockMutex(); mutex->unlockMutex();
return value; return value;
} }
void InternalErrorReporter::incrementQueueHits() { void InternalErrorReporter::incrementQueueHits() {
mutex->lockMutex(MutexIF::WAITING, INTERNAL_ERROR_MUTEX_TIMEOUT); mutex->lockMutex(timeoutType, timeoutMs);
queueHits++; queueHits++;
mutex->unlockMutex(); mutex->unlockMutex();
} }
uint32_t InternalErrorReporter::getAndResetTmHits() { uint32_t InternalErrorReporter::getAndResetTmHits() {
uint32_t value; uint32_t value;
mutex->lockMutex(MutexIF::WAITING, INTERNAL_ERROR_MUTEX_TIMEOUT); mutex->lockMutex(timeoutType, timeoutMs);
value = tmHits; value = tmHits;
tmHits = 0; tmHits = 0;
mutex->unlockMutex(); mutex->unlockMutex();
@ -99,14 +106,14 @@ uint32_t InternalErrorReporter::getAndResetTmHits() {
uint32_t InternalErrorReporter::getTmHits() { uint32_t InternalErrorReporter::getTmHits() {
uint32_t value; uint32_t value;
mutex->lockMutex(MutexIF::WAITING, INTERNAL_ERROR_MUTEX_TIMEOUT); mutex->lockMutex(timeoutType, timeoutMs);
value = tmHits; value = tmHits;
mutex->unlockMutex(); mutex->unlockMutex();
return value; return value;
} }
void InternalErrorReporter::incrementTmHits() { void InternalErrorReporter::incrementTmHits() {
mutex->lockMutex(MutexIF::WAITING, INTERNAL_ERROR_MUTEX_TIMEOUT); mutex->lockMutex(timeoutType, timeoutMs);
tmHits++; tmHits++;
mutex->unlockMutex(); mutex->unlockMutex();
} }
@ -117,7 +124,7 @@ void InternalErrorReporter::storeFull() {
uint32_t InternalErrorReporter::getAndResetStoreHits() { uint32_t InternalErrorReporter::getAndResetStoreHits() {
uint32_t value; uint32_t value;
mutex->lockMutex(MutexIF::WAITING, INTERNAL_ERROR_MUTEX_TIMEOUT); mutex->lockMutex(timeoutType, timeoutMs);
value = storeHits; value = storeHits;
storeHits = 0; storeHits = 0;
mutex->unlockMutex(); mutex->unlockMutex();
@ -126,14 +133,14 @@ uint32_t InternalErrorReporter::getAndResetStoreHits() {
uint32_t InternalErrorReporter::getStoreHits() { uint32_t InternalErrorReporter::getStoreHits() {
uint32_t value; uint32_t value;
mutex->lockMutex(MutexIF::WAITING, INTERNAL_ERROR_MUTEX_TIMEOUT); mutex->lockMutex(timeoutType, timeoutMs);
value = storeHits; value = storeHits;
mutex->unlockMutex(); mutex->unlockMutex();
return value; return value;
} }
void InternalErrorReporter::incrementStoreHits() { void InternalErrorReporter::incrementStoreHits() {
mutex->lockMutex(MutexIF::WAITING, INTERNAL_ERROR_MUTEX_TIMEOUT); mutex->lockMutex(timeoutType, timeoutMs);
storeHits++; storeHits++;
mutex->unlockMutex(); mutex->unlockMutex();
} }
@ -147,7 +154,7 @@ MessageQueueId_t InternalErrorReporter::getCommandQueue() const {
} }
ReturnValue_t InternalErrorReporter::initializeLocalDataPool( ReturnValue_t InternalErrorReporter::initializeLocalDataPool(
LocalDataPool &localDataPoolMap, LocalDataPoolManager &poolManager) { localpool::DataPool &localDataPoolMap, LocalDataPoolManager &poolManager) {
localDataPoolMap.emplace(errorPoolIds::TM_HITS, localDataPoolMap.emplace(errorPoolIds::TM_HITS,
new PoolEntry<uint32_t>()); new PoolEntry<uint32_t>());
localDataPoolMap.emplace(errorPoolIds::QUEUE_HITS, localDataPoolMap.emplace(errorPoolIds::QUEUE_HITS,
@ -160,10 +167,6 @@ ReturnValue_t InternalErrorReporter::initializeLocalDataPool(
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
LocalDataPoolManager* InternalErrorReporter::getHkManagerHandle() {
return &poolManager;
}
dur_millis_t InternalErrorReporter::getPeriodicOperationFrequency() const { dur_millis_t InternalErrorReporter::getPeriodicOperationFrequency() const {
return this->executingTask->getPeriodMs(); return this->executingTask->getPeriodMs();
} }
@ -188,3 +191,12 @@ ReturnValue_t InternalErrorReporter::initializeAfterTaskCreation() {
return poolManager.initializeAfterTaskCreation(); return poolManager.initializeAfterTaskCreation();
} }
void InternalErrorReporter::setMutexTimeout(MutexIF::TimeoutType timeoutType,
uint32_t timeoutMs) {
this->timeoutType = timeoutType;
this->timeoutMs = timeoutMs;
}
LocalDataPoolManager* InternalErrorReporter::getHkManagerHandle() {
return &poolManager;
}

View File

@ -22,7 +22,6 @@ class InternalErrorReporter: public SystemObject,
public InternalErrorReporterIF, public InternalErrorReporterIF,
public HasLocalDataPoolIF { public HasLocalDataPoolIF {
public: public:
static constexpr uint8_t INTERNAL_ERROR_MUTEX_TIMEOUT = 20;
InternalErrorReporter(object_id_t setObjectId, InternalErrorReporter(object_id_t setObjectId,
uint32_t messageQueueDepth = 5); uint32_t messageQueueDepth = 5);
@ -34,16 +33,19 @@ public:
*/ */
void setDiagnosticPrintout(bool enable); void setDiagnosticPrintout(bool enable);
void setMutexTimeout(MutexIF::TimeoutType timeoutType,
uint32_t timeoutMs);
virtual ~InternalErrorReporter(); virtual ~InternalErrorReporter();
virtual object_id_t getObjectId() const override; virtual object_id_t getObjectId() const override;
virtual MessageQueueId_t getCommandQueue() const override; virtual MessageQueueId_t getCommandQueue() const override;
virtual ReturnValue_t initializeLocalDataPool( virtual ReturnValue_t initializeLocalDataPool(
LocalDataPool& localDataPoolMap, localpool::DataPool& localDataPoolMap,
LocalDataPoolManager& poolManager) override; LocalDataPoolManager& poolManager) override;
virtual LocalDataPoolManager* getHkManagerHandle() override;
virtual dur_millis_t getPeriodicOperationFrequency() const override; virtual dur_millis_t getPeriodicOperationFrequency() const override;
virtual LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override; virtual LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override;
LocalDataPoolManager* getHkManagerHandle() override;
virtual ReturnValue_t initialize() override; virtual ReturnValue_t initialize() override;
virtual ReturnValue_t initializeAfterTaskCreation() override; virtual ReturnValue_t initializeAfterTaskCreation() override;
@ -61,7 +63,11 @@ protected:
LocalDataPoolManager poolManager; LocalDataPoolManager poolManager;
PeriodicTaskIF* executingTask = nullptr; PeriodicTaskIF* executingTask = nullptr;
MutexIF* mutex = nullptr; MutexIF* mutex = nullptr;
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING;
uint32_t timeoutMs = 20;
sid_t internalErrorSid; sid_t internalErrorSid;
InternalErrorDataset internalErrorDataset; InternalErrorDataset internalErrorDataset;

View File

@ -15,8 +15,10 @@ MessageQueueMessage::MessageQueueMessage(uint8_t* data, size_t size) :
this->messageSize = this->HEADER_SIZE + size; this->messageSize = this->HEADER_SIZE + size;
} }
else { else {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "MessageQueueMessage: Passed size larger than maximum" sif::warning << "MessageQueueMessage: Passed size larger than maximum"
"allowed size! Setting content to 0" << std::endl; "allowed size! Setting content to 0" << std::endl;
#endif
memset(this->internalBuffer, 0, sizeof(this->internalBuffer)); memset(this->internalBuffer, 0, sizeof(this->internalBuffer));
this->messageSize = this->HEADER_SIZE; this->messageSize = this->HEADER_SIZE;
} }
@ -52,7 +54,9 @@ void MessageQueueMessage::setSender(MessageQueueId_t setId) {
} }
void MessageQueueMessage::print(bool printWholeMessage) { void MessageQueueMessage::print(bool printWholeMessage) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "MessageQueueMessage content: " << std::endl; sif::debug << "MessageQueueMessage content: " << std::endl;
#endif
if(printWholeMessage) { if(printWholeMessage) {
arrayprinter::print(getData(), getMaximumMessageSize()); arrayprinter::print(getData(), getMaximumMessageSize());
} }

View File

@ -12,12 +12,16 @@ public:
ReturnValue_t status = mutex->lockMutex(timeoutType, ReturnValue_t status = mutex->lockMutex(timeoutType,
timeoutMs); timeoutMs);
if(status == MutexIF::MUTEX_TIMEOUT) { if(status == MutexIF::MUTEX_TIMEOUT) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "MutexHelper: Lock of mutex failed with timeout of " sif::error << "MutexHelper: Lock of mutex failed with timeout of "
<< timeoutMs << " milliseconds!" << std::endl; << timeoutMs << " milliseconds!" << std::endl;
#endif
} }
else if(status != HasReturnvaluesIF::RETURN_OK){ else if(status != HasReturnvaluesIF::RETURN_OK){
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "MutexHelper: Lock of Mutex failed with code " sif::error << "MutexHelper: Lock of Mutex failed with code "
<< status << std::endl; << status << std::endl;
#endif
} }
} }

View File

@ -14,7 +14,7 @@ public:
/** /**
* Different types of timeout for the mutex lock. * Different types of timeout for the mutex lock.
*/ */
enum TimeoutType { enum class TimeoutType {
POLLING, //!< If mutex is not available, return immediately POLLING, //!< If mutex is not available, return immediately
WAITING, //!< Wait a specified time for the mutex to become available WAITING, //!< Wait a specified time for the mutex to become available
BLOCKING //!< Block indefinitely until the mutex becomes available. BLOCKING //!< Block indefinitely until the mutex becomes available.

View File

@ -16,7 +16,9 @@ ReturnValue_t MemoryHelper::handleMemoryCommand(CommandMessage* message) {
lastSender = message->getSender(); lastSender = message->getSender();
lastCommand = message->getCommand(); lastCommand = message->getCommand();
if (busy) { if (busy) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "MemHelper: Busy!" << std::endl; sif::debug << "MemHelper: Busy!" << std::endl;
#endif
} }
switch (lastCommand) { switch (lastCommand) {
case MemoryMessage::CMD_MEMORY_DUMP: case MemoryMessage::CMD_MEMORY_DUMP:

View File

@ -5,7 +5,7 @@
#include "MonitoringIF.h" #include "MonitoringIF.h"
#include "MonitoringMessageContent.h" #include "MonitoringMessageContent.h"
#include "../datapoollocal/locPoolDefinitions.h" #include "../datapoollocal/localPoolDefinitions.h"
#include "../events/EventManagerIF.h" #include "../events/EventManagerIF.h"
#include "../parameters/HasParametersIF.h" #include "../parameters/HasParametersIF.h"

View File

@ -1,9 +1,10 @@
#ifndef MONITORINGMESSAGECONTENT_H_ #ifndef FSFW_MONITORING_MONITORINGMESSAGECONTENT_H_
#define MONITORINGMESSAGECONTENT_H_ #define FSFW_MONITORING_MONITORINGMESSAGECONTENT_H_
#include "HasMonitorsIF.h" #include "HasMonitorsIF.h"
#include "MonitoringIF.h" #include "MonitoringIF.h"
#include "../datapoollocal/locPoolDefinitions.h"
#include "../datapoollocal/localPoolDefinitions.h"
#include "../objectmanager/ObjectManagerIF.h" #include "../objectmanager/ObjectManagerIF.h"
#include "../serialize/SerialBufferAdapter.h" #include "../serialize/SerialBufferAdapter.h"
#include "../serialize/SerialFixedArrayListAdapter.h" #include "../serialize/SerialFixedArrayListAdapter.h"
@ -72,8 +73,10 @@ private:
if (timeStamper == nullptr) { if (timeStamper == nullptr) {
timeStamper = objectManager->get<TimeStamperIF>( timeStamperId ); timeStamper = objectManager->get<TimeStamperIF>( timeStamperId );
if ( timeStamper == nullptr ) { if ( timeStamper == nullptr ) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "MonitoringReportContent::checkAndSetStamper: " sif::error << "MonitoringReportContent::checkAndSetStamper: "
"Stamper not found!" << std::endl; "Stamper not found!" << std::endl;
#endif
return false; return false;
} }
} }
@ -83,4 +86,4 @@ private:
template<typename T> template<typename T>
object_id_t MonitoringReportContent<T>::timeStamperId = 0; object_id_t MonitoringReportContent<T>::timeStamperId = 0;
#endif /* MONITORINGMESSAGECONTENT_H_ */ #endif /* FSFW_MONITORING_MONITORINGMESSAGECONTENT_H_ */

View File

@ -1,6 +1,9 @@
#include "ObjectManager.h" #include "ObjectManager.h"
#include "../serviceinterface/ServiceInterfaceStream.h" #include "../serviceinterface/ServiceInterfaceStream.h"
#if FSFW_CPP_OSTREAM_ENABLED == 1
#include <iomanip> #include <iomanip>
#endif
#include <cstdlib> #include <cstdlib>
ObjectManager::ObjectManager( void (*setProducer)() ): ObjectManager::ObjectManager( void (*setProducer)() ):
@ -18,13 +21,18 @@ ObjectManager::~ObjectManager() {
ReturnValue_t ObjectManager::insert( object_id_t id, SystemObjectIF* object) { ReturnValue_t ObjectManager::insert( object_id_t id, SystemObjectIF* object) {
auto returnPair = objectList.emplace(id, object); auto returnPair = objectList.emplace(id, object);
if (returnPair.second) { if (returnPair.second) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
// sif::debug << "ObjectManager::insert: Object " << std::hex // sif::debug << "ObjectManager::insert: Object " << std::hex
// << (int)id << std::dec << " inserted." << std::endl; // << (int)id << std::dec << " inserted." << std::endl;
#endif
return this->RETURN_OK; return this->RETURN_OK;
} else { } else {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "ObjectManager::insert: Object id " << std::hex sif::error << "ObjectManager::insert: Object id " << std::hex
<< (int)id << std::dec << " is already in use!" << std::endl; << static_cast<uint32_t>(id) << std::dec
<< " is already in use!" << std::endl;
sif::error << "Terminating program." << std::endl; sif::error << "Terminating program." << std::endl;
#endif
//This is very severe and difficult to handle in other places. //This is very severe and difficult to handle in other places.
std::exit(INSERTION_FAILED); std::exit(INSERTION_FAILED);
} }
@ -33,12 +41,16 @@ ReturnValue_t ObjectManager::insert( object_id_t id, SystemObjectIF* object) {
ReturnValue_t ObjectManager::remove( object_id_t id ) { ReturnValue_t ObjectManager::remove( object_id_t id ) {
if ( this->getSystemObject(id) != NULL ) { if ( this->getSystemObject(id) != NULL ) {
this->objectList.erase( id ); this->objectList.erase( id );
#if FSFW_CPP_OSTREAM_ENABLED == 1
//sif::debug << "ObjectManager::removeObject: Object " << std::hex //sif::debug << "ObjectManager::removeObject: Object " << std::hex
// << (int)id << std::dec << " removed." << std::endl; // << (int)id << std::dec << " removed." << std::endl;
#endif
return RETURN_OK; return RETURN_OK;
} else { } else {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "ObjectManager::removeObject: Requested object " sif::error << "ObjectManager::removeObject: Requested object "
<< std::hex << (int)id << std::dec << " not found." << std::endl; << std::hex << (int)id << std::dec << " not found." << std::endl;
#endif
return NOT_FOUND; return NOT_FOUND;
} }
} }
@ -60,8 +72,10 @@ ObjectManager::ObjectManager() : produceObjects(nullptr) {
void ObjectManager::initialize() { void ObjectManager::initialize() {
if(produceObjects == nullptr) { if(produceObjects == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "ObjectManager::initialize: Passed produceObjects " sif::error << "ObjectManager::initialize: Passed produceObjects "
"functions is nullptr!" << std::endl; "functions is nullptr!" << std::endl;
#endif
return; return;
} }
this->produceObjects(); this->produceObjects();
@ -70,38 +84,49 @@ void ObjectManager::initialize() {
for (auto const& it : objectList) { for (auto const& it : objectList) {
result = it.second->initialize(); result = it.second->initialize();
if ( result != RETURN_OK ) { if ( result != RETURN_OK ) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
object_id_t var = it.first; object_id_t var = it.first;
sif::error << "ObjectManager::initialize: Object 0x" << std::hex << sif::error << "ObjectManager::initialize: Object 0x" << std::hex <<
std::setw(8) << std::setfill('0')<< var << " failed to " std::setw(8) << std::setfill('0')<< var << " failed to "
"initialize with code 0x" << result << std::dec << "initialize with code 0x" << result << std::dec <<
std::setfill(' ') << std::endl; std::setfill(' ') << std::endl;
#endif
errorCount++; errorCount++;
} }
} }
if (errorCount > 0) { if (errorCount > 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "ObjectManager::ObjectManager: Counted " << errorCount sif::error << "ObjectManager::ObjectManager: Counted " << errorCount
<< " failed initializations." << std::endl; << " failed initializations." << std::endl;
#endif
} }
//Init was successful. Now check successful interconnections. //Init was successful. Now check successful interconnections.
errorCount = 0; errorCount = 0;
for (auto const& it : objectList) { for (auto const& it : objectList) {
result = it.second->checkObjectConnections(); result = it.second->checkObjectConnections();
if ( result != RETURN_OK ) { if ( result != RETURN_OK ) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "ObjectManager::ObjectManager: Object " << std::hex << sif::error << "ObjectManager::ObjectManager: Object " << std::hex <<
(int) it.first << " connection check failed with code 0x" (int) it.first << " connection check failed with code 0x"
<< result << std::dec << std::endl; << result << std::dec << std::endl;
#endif
errorCount++; errorCount++;
} }
} }
if (errorCount > 0) { if (errorCount > 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "ObjectManager::ObjectManager: Counted " << errorCount sif::error << "ObjectManager::ObjectManager: Counted " << errorCount
<< " failed connection checks." << std::endl; << " failed connection checks." << std::endl;
#endif
} }
} }
void ObjectManager::printList() { void ObjectManager::printList() {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "ObjectManager: Object List contains:" << std::endl; sif::debug << "ObjectManager: Object List contains:" << std::endl;
for (auto const& it : objectList) { for (auto const& it : objectList) {
sif::debug << std::hex << it.first << " | " << it.second << std::endl; sif::debug << std::hex << it.first << " | " << it.second << std::endl;
} }
#endif
} }

View File

@ -86,8 +86,10 @@ extern ObjectManagerIF *objectManager;
template <typename T> template <typename T>
T* ObjectManagerIF::get( object_id_t id ) { T* ObjectManagerIF::get( object_id_t id ) {
if(objectManager == nullptr) { if(objectManager == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "ObjectManagerIF: Global object manager has not " sif::error << "ObjectManagerIF: Global object manager has not "
"been initialized yet!" << std::endl; "been initialized yet!" << std::endl;
#endif
} }
SystemObjectIF* temp = this->getSystemObject(id); SystemObjectIF* temp = this->getSystemObject(id);
return dynamic_cast<T*>(temp); return dynamic_cast<T*>(temp);

View File

@ -8,8 +8,10 @@
BinarySemaphoreUsingTask::BinarySemaphoreUsingTask() { BinarySemaphoreUsingTask::BinarySemaphoreUsingTask() {
handle = TaskManagement::getCurrentTaskHandle(); handle = TaskManagement::getCurrentTaskHandle();
if(handle == nullptr) { if(handle == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "Could not retrieve task handle. Please ensure the" sif::error << "Could not retrieve task handle. Please ensure the"
"constructor was called inside a task." << std::endl; "constructor was called inside a task." << std::endl;
#endif
} }
xTaskNotifyGive(handle); xTaskNotifyGive(handle);
} }

View File

@ -5,7 +5,9 @@
BinarySemaphore::BinarySemaphore() { BinarySemaphore::BinarySemaphore() {
handle = xSemaphoreCreateBinary(); handle = xSemaphoreCreateBinary();
if(handle == nullptr) { if(handle == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "Semaphore: Binary semaph creation failure" << std::endl; sif::error << "Semaphore: Binary semaph creation failure" << std::endl;
#endif
} }
// Initiated semaphore must be given before it can be taken. // Initiated semaphore must be given before it can be taken.
xSemaphoreGive(handle); xSemaphoreGive(handle);
@ -18,7 +20,9 @@ BinarySemaphore::~BinarySemaphore() {
BinarySemaphore::BinarySemaphore(BinarySemaphore&& s) { BinarySemaphore::BinarySemaphore(BinarySemaphore&& s) {
handle = xSemaphoreCreateBinary(); handle = xSemaphoreCreateBinary();
if(handle == nullptr) { if(handle == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "Binary semaphore creation failure" << std::endl; sif::error << "Binary semaphore creation failure" << std::endl;
#endif
} }
xSemaphoreGive(handle); xSemaphoreGive(handle);
} }
@ -28,7 +32,9 @@ BinarySemaphore& BinarySemaphore::operator =(
if(&s != this) { if(&s != this) {
handle = xSemaphoreCreateBinary(); handle = xSemaphoreCreateBinary();
if(handle == nullptr) { if(handle == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "Binary semaphore creation failure" << std::endl; sif::error << "Binary semaphore creation failure" << std::endl;
#endif
} }
xSemaphoreGive(handle); xSemaphoreGive(handle);
} }

View File

@ -163,7 +163,7 @@ ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) {
if (checkOrCreateClockMutex() != HasReturnvaluesIF::RETURN_OK) { if (checkOrCreateClockMutex() != HasReturnvaluesIF::RETURN_OK) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
ReturnValue_t result = timeMutex->lockMutex(MutexIF::BLOCKING); ReturnValue_t result = timeMutex->lockMutex(MutexIF::TimeoutType::BLOCKING);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
return result; return result;
} }
@ -178,7 +178,7 @@ ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) {
if (timeMutex == NULL) { if (timeMutex == NULL) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
ReturnValue_t result = timeMutex->lockMutex(MutexIF::BLOCKING); ReturnValue_t result = timeMutex->lockMutex(MutexIF::TimeoutType::BLOCKING);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
return result; return result;
} }

View File

@ -9,25 +9,31 @@
CountingSemaphoreUsingTask::CountingSemaphoreUsingTask(const uint8_t maxCount, CountingSemaphoreUsingTask::CountingSemaphoreUsingTask(const uint8_t maxCount,
uint8_t initCount): maxCount(maxCount) { uint8_t initCount): maxCount(maxCount) {
if(initCount > maxCount) { if(initCount > maxCount) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "CountingSemaphoreUsingTask: Max count bigger than " sif::error << "CountingSemaphoreUsingTask: Max count bigger than "
"intial cout. Setting initial count to max count." << std::endl; "intial cout. Setting initial count to max count." << std::endl;
#endif
initCount = maxCount; initCount = maxCount;
} }
handle = TaskManagement::getCurrentTaskHandle(); handle = TaskManagement::getCurrentTaskHandle();
if(handle == nullptr) { if(handle == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "CountingSemaphoreUsingTask: Could not retrieve task " sif::error << "CountingSemaphoreUsingTask: Could not retrieve task "
"handle. Please ensure the constructor was called inside a " "handle. Please ensure the constructor was called inside a "
"task." << std::endl; "task." << std::endl;
#endif
} }
uint32_t oldNotificationValue; uint32_t oldNotificationValue;
xTaskNotifyAndQuery(handle, 0, eSetValueWithOverwrite, xTaskNotifyAndQuery(handle, 0, eSetValueWithOverwrite,
&oldNotificationValue); &oldNotificationValue);
if(oldNotificationValue != 0) { if(oldNotificationValue != 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "CountinSemaphoreUsingTask: Semaphore initiated but " sif::warning << "CountinSemaphoreUsingTask: Semaphore initiated but "
"current notification value is not 0. Please ensure the " "current notification value is not 0. Please ensure the "
"notification value is not used for other purposes!" << std::endl; "notification value is not used for other purposes!" << std::endl;
#endif
} }
for(int i = 0; i < initCount; i++) { for(int i = 0; i < initCount; i++) {
xTaskNotifyGive(handle); xTaskNotifyGive(handle);

View File

@ -10,14 +10,18 @@
CountingSemaphore::CountingSemaphore(const uint8_t maxCount, uint8_t initCount): CountingSemaphore::CountingSemaphore(const uint8_t maxCount, uint8_t initCount):
maxCount(maxCount), initCount(initCount) { maxCount(maxCount), initCount(initCount) {
if(initCount > maxCount) { if(initCount > maxCount) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "CountingSemaphoreUsingTask: Max count bigger than " sif::error << "CountingSemaphoreUsingTask: Max count bigger than "
"intial cout. Setting initial count to max count." << std::endl; "intial cout. Setting initial count to max count." << std::endl;
#endif
initCount = maxCount; initCount = maxCount;
} }
handle = xSemaphoreCreateCounting(maxCount, initCount); handle = xSemaphoreCreateCounting(maxCount, initCount);
if(handle == nullptr) { if(handle == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "CountingSemaphore: Creation failure" << std::endl; sif::error << "CountingSemaphore: Creation failure" << std::endl;
#endif
} }
} }
@ -25,7 +29,9 @@ CountingSemaphore::CountingSemaphore(CountingSemaphore&& other):
maxCount(other.maxCount), initCount(other.initCount) { maxCount(other.maxCount), initCount(other.initCount) {
handle = xSemaphoreCreateCounting(other.maxCount, other.initCount); handle = xSemaphoreCreateCounting(other.maxCount, other.initCount);
if(handle == nullptr) { if(handle == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "CountingSemaphore: Creation failure" << std::endl; sif::error << "CountingSemaphore: Creation failure" << std::endl;
#endif
} }
} }
@ -33,7 +39,9 @@ CountingSemaphore& CountingSemaphore::operator =(
CountingSemaphore&& other) { CountingSemaphore&& other) {
handle = xSemaphoreCreateCounting(other.maxCount, other.initCount); handle = xSemaphoreCreateCounting(other.maxCount, other.initCount);
if(handle == nullptr) { if(handle == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "CountingSemaphore: Creation failure" << std::endl; sif::error << "CountingSemaphore: Creation failure" << std::endl;
#endif
} }
return * this; return * this;
} }

View File

@ -37,15 +37,19 @@ void FixedTimeslotTask::taskEntryPoint(void* argument) {
} }
originalTask->taskFunctionality(); originalTask->taskFunctionality();
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "Polling task " << originalTask->handle sif::debug << "Polling task " << originalTask->handle
<< " returned from taskFunctionality." << std::endl; << " returned from taskFunctionality." << std::endl;
#endif
} }
void FixedTimeslotTask::missedDeadlineCounter() { void FixedTimeslotTask::missedDeadlineCounter() {
FixedTimeslotTask::deadlineMissedCount++; FixedTimeslotTask::deadlineMissedCount++;
if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) { if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "PST missed " << FixedTimeslotTask::deadlineMissedCount sif::error << "PST missed " << FixedTimeslotTask::deadlineMissedCount
<< " deadlines." << std::endl; << " deadlines." << std::endl;
#endif
} }
} }
@ -69,8 +73,10 @@ ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId,
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "Component " << std::hex << componentId << sif::error << "Component " << std::hex << componentId <<
" not found, not adding it to pst" << std::endl; " not found, not adding it to pst" << std::endl;
#endif
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }

View File

@ -10,6 +10,7 @@
MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize): MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize):
maxMessageSize(maxMessageSize) { maxMessageSize(maxMessageSize) {
handle = xQueueCreate(messageDepth, maxMessageSize); handle = xQueueCreate(messageDepth, maxMessageSize);
#if FSFW_CPP_OSTREAM_ENABLED == 1
if (handle == nullptr) { if (handle == nullptr) {
sif::error << "MessageQueue::MessageQueue:" sif::error << "MessageQueue::MessageQueue:"
<< " Creation failed." << std::endl; << " Creation failed." << std::endl;
@ -17,7 +18,9 @@ MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize):
<< std::endl; << std::endl;
sif::error << "Specified Maximum Message Size: " sif::error << "Specified Maximum Message Size: "
<< maxMessageSize << std::endl; << maxMessageSize << std::endl;
} }
#endif
} }
MessageQueue::~MessageQueue() { MessageQueue::~MessageQueue() {

View File

@ -5,7 +5,9 @@
Mutex::Mutex() { Mutex::Mutex() {
handle = xSemaphoreCreateMutex(); handle = xSemaphoreCreateMutex();
if(handle == nullptr) { if(handle == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "Mutex::Mutex(FreeRTOS): Creation failure" << std::endl; sif::error << "Mutex::Mutex(FreeRTOS): Creation failure" << std::endl;
#endif
} }
} }

View File

@ -13,8 +13,10 @@ PeriodicTask::PeriodicTask(const char *name, TaskPriority setPriority,
BaseType_t status = xTaskCreate(taskEntryPoint, name, BaseType_t status = xTaskCreate(taskEntryPoint, name,
stackSize, this, setPriority, &handle); stackSize, this, setPriority, &handle);
if(status != pdPASS){ if(status != pdPASS){
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "PeriodicTask Insufficient heap memory remaining. " sif::debug << "PeriodicTask Insufficient heap memory remaining. "
"Status: " << status << std::endl; "Status: " << status << std::endl;
#endif
} }
} }
@ -41,8 +43,10 @@ void PeriodicTask::taskEntryPoint(void* argument) {
} }
originalTask->taskFunctionality(); originalTask->taskFunctionality();
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "Polling task " << originalTask->handle sif::debug << "Polling task " << originalTask->handle
<< " returned from taskFunctionality." << std::endl; << " returned from taskFunctionality." << std::endl;
#endif
} }
ReturnValue_t PeriodicTask::startTask() { ReturnValue_t PeriodicTask::startTask() {
@ -99,8 +103,10 @@ ReturnValue_t PeriodicTask::addComponent(object_id_t object) {
ExecutableObjectIF* newObject = objectManager->get<ExecutableObjectIF>( ExecutableObjectIF* newObject = objectManager->get<ExecutableObjectIF>(
object); object);
if (newObject == nullptr) { if (newObject == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "PeriodicTask::addComponent: Invalid object. Make sure" sif::error << "PeriodicTask::addComponent: Invalid object. Make sure"
"it implement ExecutableObjectIF" << std::endl; "it implement ExecutableObjectIF" << std::endl;
#endif
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
objectList.push_back(newObject); objectList.push_back(newObject);

View File

@ -32,8 +32,10 @@ SemaphoreIF* SemaphoreFactory::createBinarySemaphore(uint32_t argument) {
return new BinarySemaphoreUsingTask(); return new BinarySemaphoreUsingTask();
} }
else { else {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "SemaphoreFactory: Invalid argument, return regular" sif::warning << "SemaphoreFactory: Invalid argument, return regular"
"binary semaphore" << std::endl; "binary semaphore" << std::endl;
#endif
return new BinarySemaphore(); return new BinarySemaphore();
} }
} }
@ -47,8 +49,10 @@ SemaphoreIF* SemaphoreFactory::createCountingSemaphore(uint8_t maxCount,
return new CountingSemaphoreUsingTask(maxCount, initCount); return new CountingSemaphoreUsingTask(maxCount, initCount);
} }
else { else {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "SemaphoreFactory: Invalid argument, return regular" sif::warning << "SemaphoreFactory: Invalid argument, return regular"
"binary semaphore" << std::endl; "binary semaphore" << std::endl;
#endif
return new CountingSemaphore(maxCount, initCount); return new CountingSemaphore(maxCount, initCount);
} }

View File

@ -13,9 +13,11 @@ target_sources(${LIB_FSFW_NAME}
) )
if(UNIX) if(UNIX)
find_package(Threads REQUIRED)
target_link_libraries(${LIB_FSFW_NAME} target_link_libraries(${LIB_FSFW_NAME}
PRIVATE PRIVATE
rt rt
pthread ${CMAKE_THREAD_LIBS_INIT}
) )
endif() endif()

View File

@ -14,7 +14,9 @@ MutexIF* Clock::timeMutex = NULL;
using SystemClock = std::chrono::system_clock; using SystemClock = std::chrono::system_clock;
uint32_t Clock::getTicksPerSecond(void){ uint32_t Clock::getTicksPerSecond(void){
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "Clock::getTicksPerSecond: not implemented yet" << std::endl; sif::warning << "Clock::getTicksPerSecond: not implemented yet" << std::endl;
#endif
return 0; return 0;
//return CLOCKS_PER_SEC; //return CLOCKS_PER_SEC;
//uint32_t ticks = sysconf(_SC_CLK_TCK); //uint32_t ticks = sysconf(_SC_CLK_TCK);
@ -23,7 +25,9 @@ uint32_t Clock::getTicksPerSecond(void){
ReturnValue_t Clock::setClock(const TimeOfDay_t* time) { ReturnValue_t Clock::setClock(const TimeOfDay_t* time) {
// do some magic with chrono // do some magic with chrono
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "Clock::setClock: not implemented yet" << std::endl; sif::warning << "Clock::setClock: not implemented yet" << std::endl;
#endif
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
@ -36,7 +40,9 @@ ReturnValue_t Clock::setClock(const timeval* time) {
#else #else
#endif #endif
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "Clock::getUptime: Not implemented for found OS" << std::endl; sif::warning << "Clock::getUptime: Not implemented for found OS" << std::endl;
#endif
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
@ -60,7 +66,9 @@ ReturnValue_t Clock::getClock_timeval(timeval* time) {
time->tv_usec = timeUnix.tv_nsec / 1000.0; time->tv_usec = timeUnix.tv_nsec / 1000.0;
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
#else #else
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "Clock::getUptime: Not implemented for found OS" << std::endl; sif::warning << "Clock::getUptime: Not implemented for found OS" << std::endl;
#endif
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
#endif #endif
@ -68,7 +76,9 @@ ReturnValue_t Clock::getClock_timeval(timeval* time) {
ReturnValue_t Clock::getClock_usecs(uint64_t* time) { ReturnValue_t Clock::getClock_usecs(uint64_t* time) {
// do some magic with chrono // do some magic with chrono
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "Clock::gerClock_usecs: not implemented yet" << std::endl; sif::warning << "Clock::gerClock_usecs: not implemented yet" << std::endl;
#endif
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
@ -90,7 +100,9 @@ timeval Clock::getUptime() {
timeval.tv_usec = uptimeSeconds *(double) 1e6 - (timeval.tv_sec *1e6); timeval.tv_usec = uptimeSeconds *(double) 1e6 - (timeval.tv_sec *1e6);
} }
#else #else
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "Clock::getUptime: Not implemented for found OS" << std::endl; sif::warning << "Clock::getUptime: Not implemented for found OS" << std::endl;
#endif
#endif #endif
return timeval; return timeval;
} }
@ -126,7 +138,9 @@ ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) {
auto usecond = std::chrono::duration_cast<std::chrono::microseconds>(fraction); auto usecond = std::chrono::duration_cast<std::chrono::microseconds>(fraction);
time->usecond = usecond.count(); time->usecond = usecond.count();
#if FSFW_CPP_OSTREAM_ENABLED == 1
//sif::warning << "Clock::getDateAndTime: not implemented yet" << std::endl; //sif::warning << "Clock::getDateAndTime: not implemented yet" << std::endl;
#endif
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
@ -148,7 +162,9 @@ ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from,
to->tv_usec = from->usecond; to->tv_usec = from->usecond;
//Fails in 2038.. //Fails in 2038..
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "Clock::convertTimeBla: not implemented yet" << std::endl; sif::warning << "Clock::convertTimeBla: not implemented yet" << std::endl;
#endif
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
@ -186,7 +202,7 @@ ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) {
if(checkOrCreateClockMutex()!=HasReturnvaluesIF::RETURN_OK){ if(checkOrCreateClockMutex()!=HasReturnvaluesIF::RETURN_OK){
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
ReturnValue_t result = timeMutex->lockMutex(MutexIF::BLOCKING); ReturnValue_t result = timeMutex->lockMutex();
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
return result; return result;
} }
@ -201,7 +217,7 @@ ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) {
if(timeMutex == nullptr){ if(timeMutex == nullptr){
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
ReturnValue_t result = timeMutex->lockMutex(MutexIF::BLOCKING); ReturnValue_t result = timeMutex->lockMutex();
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
return result; return result;
} }

View File

@ -35,15 +35,19 @@ FixedTimeslotTask::FixedTimeslotTask(const char *name, TaskPriority setPriority,
reinterpret_cast<HANDLE>(mainThread.native_handle()), reinterpret_cast<HANDLE>(mainThread.native_handle()),
ABOVE_NORMAL_PRIORITY_CLASS); ABOVE_NORMAL_PRIORITY_CLASS);
if(result != 0) { if(result != 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "FixedTimeslotTask: Windows SetPriorityClass failed with code " sif::error << "FixedTimeslotTask: Windows SetPriorityClass failed with code "
<< GetLastError() << std::endl; << GetLastError() << std::endl;
#endif
} }
result = SetThreadPriority( result = SetThreadPriority(
reinterpret_cast<HANDLE>(mainThread.native_handle()), reinterpret_cast<HANDLE>(mainThread.native_handle()),
THREAD_PRIORITY_NORMAL); THREAD_PRIORITY_NORMAL);
if(result != 0) { if(result != 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "FixedTimeslotTask: Windows SetPriorityClass failed with code " sif::error << "FixedTimeslotTask: Windows SetPriorityClass failed with code "
<< GetLastError() << std::endl; << GetLastError() << std::endl;
#endif
} }
#elif defined(LINUX) #elif defined(LINUX)
// TODO: we can just copy and paste the code from the linux OSAL here. // TODO: we can just copy and paste the code from the linux OSAL here.
@ -70,8 +74,10 @@ void FixedTimeslotTask::taskEntryPoint(void* argument) {
} }
this->taskFunctionality(); this->taskFunctionality();
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "FixedTimeslotTask::taskEntryPoint: " sif::debug << "FixedTimeslotTask::taskEntryPoint: "
"Returned from taskFunctionality." << std::endl; "Returned from taskFunctionality." << std::endl;
#endif
} }
ReturnValue_t FixedTimeslotTask::startTask() { ReturnValue_t FixedTimeslotTask::startTask() {
@ -134,8 +140,10 @@ ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId,
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "Component " << std::hex << componentId << sif::error << "Component " << std::hex << componentId <<
" not found, not adding it to pst" << std::endl; " not found, not adding it to pst" << std::endl;
#endif
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }

View File

@ -10,8 +10,10 @@ MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize):
queueLock = MutexFactory::instance()->createMutex(); queueLock = MutexFactory::instance()->createMutex();
auto result = QueueMapManager::instance()->addMessageQueue(this, &mqId); auto result = QueueMapManager::instance()->addMessageQueue(this, &mqId);
if(result != HasReturnvaluesIF::RETURN_OK) { if(result != HasReturnvaluesIF::RETURN_OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "MessageQueue::MessageQueue:" sif::error << "MessageQueue::MessageQueue:"
<< " Could not be created" << std::endl; << " Could not be created" << std::endl;
#endif
} }
} }
@ -137,8 +139,10 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
targetQueue->messageQueue.push(*mqmMessage); targetQueue->messageQueue.push(*mqmMessage);
} }
else { else {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "MessageQueue::sendMessageFromMessageQueue: Message" sif::error << "MessageQueue::sendMessageFromMessageQueue: Message"
"is not MessageQueueMessage!" << std::endl; "is not MessageQueueMessage!" << std::endl;
#endif
} }
} }

View File

@ -4,16 +4,16 @@
Mutex::Mutex() {} Mutex::Mutex() {}
ReturnValue_t Mutex::lockMutex(TimeoutType timeoutType, uint32_t timeoutMs) { ReturnValue_t Mutex::lockMutex(TimeoutType timeoutType, uint32_t timeoutMs) {
if(timeoutType == MutexIF::BLOCKING) { if(timeoutType == TimeoutType::BLOCKING) {
mutex.lock(); mutex.lock();
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
else if(timeoutType == MutexIF::POLLING) { else if(timeoutType == TimeoutType::POLLING) {
if(mutex.try_lock()) { if(mutex.try_lock()) {
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
} }
else if(timeoutMs > MutexIF::POLLING){ else if(timeoutType == TimeoutType::WAITING){
auto chronoMs = std::chrono::milliseconds(timeoutMs); auto chronoMs = std::chrono::milliseconds(timeoutMs);
if(mutex.try_lock_for(chronoMs)) { if(mutex.try_lock_for(chronoMs)) {
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;

View File

@ -22,7 +22,6 @@ public:
std::timed_mutex* getMutexHandle(); std::timed_mutex* getMutexHandle();
private: private:
//bool locked = false;
std::timed_mutex mutex; std::timed_mutex mutex;
}; };

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