diff --git a/CHANGELOG b/CHANGELOG index 2d901791..298ef0d4 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -70,3 +70,15 @@ now ### Commanding Service Base - CSB uses the new fsfwconfig::FSFW_CSB_FIFO_DEPTH variable to determine the FIFO depth for each CSB instance. This variable has to be set in the FSFWConfig.h file + +### Service Interface + +- Proper printf support contained in ServiceInterfacePrinter.h +- CPP ostream support now optional (can reduce executable size by 150 - 250 kB) +- Amalagated header which determines automatically which service interface to use depending on FSFWConfig.h configuration. + Users can just use #include +- 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. +- \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index aaf9a8af..d6911f61 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -106,15 +106,17 @@ else() ) endif() -if(CMAKE_COMPILER_IS_GNUCXX) - set(WARNING_FLAGS - -Wall - -Wextra - -Wimplicit-fallthrough=1 - -Wno-unused-parameter - -Wno-psabi - ) - +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + if(NOT DEFINED FSFW_WARNING_FLAGS) + set(FSFW_WARNING_FLAGS + -Wall + -Wextra + -Wshadow=local + -Wimplicit-fallthrough=1 + -Wno-unused-parameter + -Wno-psabi + ) + if(NOT DEFINED WARNING_SHADOW_LOCAL) option(WARNING_SHADOW_LOCAL "Show shadows declarations warning." ON) endif() @@ -122,6 +124,7 @@ if(CMAKE_COMPILER_IS_GNUCXX) if(WARNING_SHADOW_LOCAL) list(APPEND WARNING_FLAGS "-Wshadow=local") endif() + endif() if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") @@ -142,9 +145,7 @@ target_include_directories(${LIB_FSFW_NAME} PRIVATE ${FSFW_CONFIG_PATH_ABSOLUTE} ) -# Machine specific options can be set with the ABI_FLAGS variable. target_compile_options(${LIB_FSFW_NAME} PRIVATE - ${WARNING_FLAGS} + ${FSFW_WARNING_FLAGS} ${COMPILER_FLAGS} - ${ABI_FLAGS} ) diff --git a/README.md b/README.md index 8552e0c8..fb3be429 100644 --- a/README.md +++ b/README.md @@ -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 with Airbus Defence and Space GmbH. -## Intended Use +## Quick facts -The framework is designed for systems, which communicate with external devices, perform control loops, receive telecommands and send telemetry, and need to maintain a high level of availability. -Therefore, a mode and health system provides control over the states of the software and the controlled devices. -In addition, a simple mechanism of event based fault detection, isolation and recovery is implemented as well. +The framework is designed for systems, which communicate with external devices, perform control loops, receive telecommands and send telemetry, and need to maintain a high level of availability. Therefore, a mode and health system provides control over the states of the software and the controlled devices. In addition, a simple mechanism of event based fault detection, isolation and recovery is implemented as well. -The recommended hardware is a microprocessor with more than 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 tested on the STM32H743ZI-Nucleo board. +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. -## 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 -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 starting point. The [configuration section](doc/README-config.md#top) provides more specific information about -the possible options. +a starting point. The [configuration section](doc/README-config.md#top) provides more specific information about the possible options. -## Structure +## Index -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. +[1. High-level overview](doc/README-highlevel.md#top)
+[2. Core components](doc/README-core.md#top)
+[3. OSAL overview](doc/README-osal.md#top)
+[4. PUS services](doc/README-pus.md#top)
+[5. Device Handler overview](doc/README-devicehandlers.md#top)
+[6. Controller overview](doc/README-controllers.md#top)
+[7. Local Data Pools](doc/README-localpools.md#top)
-### 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. \ No newline at end of file diff --git a/container/FixedOrderedMultimap.h b/container/FixedOrderedMultimap.h index 96bc0073..acf2368a 100644 --- a/container/FixedOrderedMultimap.h +++ b/container/FixedOrderedMultimap.h @@ -3,6 +3,7 @@ #include "ArrayList.h" #include +#include /** * @brief An associative container which allows multiple entries of the same key. diff --git a/container/SharedRingBuffer.cpp b/container/SharedRingBuffer.cpp index 6ddb3d3e..769ce000 100644 --- a/container/SharedRingBuffer.cpp +++ b/container/SharedRingBuffer.cpp @@ -47,9 +47,11 @@ ReturnValue_t SharedRingBuffer::initialize() { DynamicFIFO* SharedRingBuffer::getReceiveSizesFIFO() { if(receiveSizesFIFO == nullptr) { // Configuration error. +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "SharedRingBuffer::getReceiveSizesFIFO: Ring buffer" << " was not configured to have sizes FIFO, returning nullptr!" << std::endl; +#endif } return receiveSizesFIFO; } diff --git a/controller/ExtendedControllerBase.cpp b/controller/ExtendedControllerBase.cpp index fa4f6786..397c8c10 100644 --- a/controller/ExtendedControllerBase.cpp +++ b/controller/ExtendedControllerBase.cpp @@ -4,7 +4,7 @@ ExtendedControllerBase::ExtendedControllerBase(object_id_t objectId, object_id_t parentId, size_t commandQueueDepth): ControllerBase(objectId, parentId, commandQueueDepth), - localPoolManager(this, commandQueue), + poolManager(this, commandQueue), actionHelper(this, commandQueue) { } @@ -17,7 +17,7 @@ ReturnValue_t ExtendedControllerBase::executeAction(ActionId_t actionId, ReturnValue_t ExtendedControllerBase::initializeLocalDataPool( - LocalDataPool &localDataPoolMap, LocalDataPoolManager &poolManager) { + localpool::DataPool &localDataPoolMap, LocalDataPoolManager &poolManager) { // needs to be overriden and implemented by child class. return HasReturnvaluesIF::RETURN_OK; } @@ -26,10 +26,6 @@ object_id_t ExtendedControllerBase::getObjectId() const { return SystemObject::getObjectId(); } -LocalDataPoolManager* ExtendedControllerBase::getHkManagerHandle() { - return &localPoolManager; -} - uint32_t ExtendedControllerBase::getPeriodicOperationFrequency() const { return this->executingTask->getPeriodMs(); } @@ -40,7 +36,7 @@ ReturnValue_t ExtendedControllerBase::handleCommandMessage( if(result == HasReturnvaluesIF::RETURN_OK) { return result; } - return localPoolManager.handleHousekeepingMessage(message); + return poolManager.handleHousekeepingMessage(message); } void ExtendedControllerBase::handleQueue() { @@ -64,7 +60,7 @@ void ExtendedControllerBase::handleQueue() { continue; } - result = localPoolManager.handleHousekeepingMessage(&command); + result = poolManager.handleHousekeepingMessage(&command); if (result == RETURN_OK) { continue; } @@ -88,16 +84,16 @@ ReturnValue_t ExtendedControllerBase::initialize() { return result; } - return localPoolManager.initialize(commandQueue); + return poolManager.initialize(commandQueue); } ReturnValue_t ExtendedControllerBase::initializeAfterTaskCreation() { - return localPoolManager.initializeAfterTaskCreation(); + return poolManager.initializeAfterTaskCreation(); } ReturnValue_t ExtendedControllerBase::performOperation(uint8_t opCode) { handleQueue(); - localPoolManager.performHkOperation(); + poolManager.performHkOperation(); performControlOperation(); return RETURN_OK; } @@ -107,7 +103,13 @@ MessageQueueId_t ExtendedControllerBase::getCommandQueue() const { } LocalPoolDataSetBase* ExtendedControllerBase::getDataSetHandle(sid_t sid) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "ExtendedControllerBase::getDataSetHandle: No child " << " implementation provided, returning nullptr!" << std::endl; +#endif return nullptr; } + +LocalDataPoolManager* ExtendedControllerBase::getHkManagerHandle() { + return &poolManager; +} diff --git a/controller/ExtendedControllerBase.h b/controller/ExtendedControllerBase.h index 02c5728e..bcb414dd 100644 --- a/controller/ExtendedControllerBase.h +++ b/controller/ExtendedControllerBase.h @@ -33,7 +33,7 @@ public: virtual ReturnValue_t initializeAfterTaskCreation() override; protected: - LocalDataPoolManager localPoolManager; + LocalDataPoolManager poolManager; ActionHelper actionHelper; /** @@ -58,11 +58,11 @@ protected: size_t size) override; /** HasLocalDatapoolIF overrides */ + virtual LocalDataPoolManager* getHkManagerHandle() override; virtual object_id_t getObjectId() const override; virtual ReturnValue_t initializeLocalDataPool( - LocalDataPool& localDataPoolMap, + localpool::DataPool& localDataPoolMap, LocalDataPoolManager& poolManager) override; - virtual LocalDataPoolManager* getHkManagerHandle() override; virtual uint32_t getPeriodicOperationFrequency() const override; virtual LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override; }; diff --git a/datalinklayer/Clcw.cpp b/datalinklayer/Clcw.cpp index dc435a2b..13971929 100644 --- a/datalinklayer/Clcw.cpp +++ b/datalinklayer/Clcw.cpp @@ -55,7 +55,9 @@ void Clcw::setBitLock(bool bitLock) { } void Clcw::print() { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::debug << "Clcw::print: Clcw is: " << std::hex << getAsWhole() << std::dec << std::endl; +#endif } void Clcw::setWhole(uint32_t rawClcw) { diff --git a/datalinklayer/DataLinkLayer.cpp b/datalinklayer/DataLinkLayer.cpp index 75f2edda..1bdaa4f5 100644 --- a/datalinklayer/DataLinkLayer.cpp +++ b/datalinklayer/DataLinkLayer.cpp @@ -98,8 +98,10 @@ ReturnValue_t DataLinkLayer::processFrame(uint16_t length) { receivedDataLength = length; ReturnValue_t status = allFramesReception(); if (status != RETURN_OK) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "DataLinkLayer::processFrame: frame reception failed. " "Error code: " << std::hex << status << std::dec << std::endl; +#endif // currentFrame.print(); return status; } else { @@ -124,7 +126,9 @@ ReturnValue_t DataLinkLayer::initialize() { if ( virtualChannels.begin() != virtualChannels.end() ) { clcw->setVirtualChannel( virtualChannels.begin()->second->getChannelId() ); } else { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "DataLinkLayer::initialize: No VC assigned to this DLL instance! " << std::endl; +#endif return RETURN_FAILED; } diff --git a/datalinklayer/MapPacketExtraction.cpp b/datalinklayer/MapPacketExtraction.cpp index 845ed7c1..cdc9ae27 100644 --- a/datalinklayer/MapPacketExtraction.cpp +++ b/datalinklayer/MapPacketExtraction.cpp @@ -29,9 +29,11 @@ ReturnValue_t MapPacketExtraction::extractPackets(TcTransferFrame* frame) { bufferPosition = &packetBuffer[packetLength]; status = RETURN_OK; } else { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "MapPacketExtraction::extractPackets. Packet too large! Size: " << packetLength << std::endl; +#endif clearBuffers(); status = CONTENT_TOO_LARGE; } @@ -51,24 +53,30 @@ ReturnValue_t MapPacketExtraction::extractPackets(TcTransferFrame* frame) { } status = RETURN_OK; } else { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "MapPacketExtraction::extractPackets. Packet too large! Size: " << packetLength << std::endl; +#endif clearBuffers(); status = CONTENT_TOO_LARGE; } } else { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "MapPacketExtraction::extractPackets. Illegal segment! Last flag: " << (int) lastSegmentationFlag << std::endl; +#endif clearBuffers(); status = ILLEGAL_SEGMENTATION_FLAG; } break; default: +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "MapPacketExtraction::extractPackets. Illegal segmentationFlag: " << (int) segmentationFlag << std::endl; +#endif clearBuffers(); status = DATA_CORRUPTED; break; @@ -135,10 +143,14 @@ ReturnValue_t MapPacketExtraction::initialize() { } void MapPacketExtraction::printPacketBuffer(void) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::debug << "DLL: packet_buffer contains: " << std::endl; +#endif for (uint32_t i = 0; i < this->packetLength; ++i) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::debug << "packet_buffer[" << std::dec << i << "]: 0x" << std::hex << (uint16_t) this->packetBuffer[i] << std::endl; +#endif } } diff --git a/datalinklayer/TcTransferFrame.cpp b/datalinklayer/TcTransferFrame.cpp index f1a70bdc..ee094dc3 100644 --- a/datalinklayer/TcTransferFrame.cpp +++ b/datalinklayer/TcTransferFrame.cpp @@ -87,16 +87,25 @@ uint8_t* TcTransferFrame::getFullDataField() { } void TcTransferFrame::print() { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::debug << "Raw Frame: " << std::hex << std::endl; for (uint16_t count = 0; count < this->getFullSize(); count++ ) { sif::debug << (uint16_t)this->getFullFrame()[count] << " "; } sif::debug << std::dec << std::endl; -// debug << "Frame Header:" << std::endl; -// debug << "Version Number: " << std::hex << (uint16_t)this->current_frame.getVersionNumber() << std::endl; -// debug << "Bypass Flag set?| Ctrl Cmd Flag set?: " << (uint16_t)this->current_frame.bypassFlagSet() << " | " << (uint16_t)this->current_frame.controlCommandFlagSet() << std::endl; -// debug << "SCID : " << this->current_frame.getSpacecraftId() << std::endl; -// debug << "VCID : " << (uint16_t)this->current_frame.getVirtualChannelId() << std::endl; -// debug << "Frame length: " << std::dec << this->current_frame.getFrameLength() << std::endl; -// debug << "Sequence Number: " << (uint16_t)this->current_frame.getSequenceNumber() << std::endl; + + sif::debug << "Frame Header:" << std::endl; + sif::debug << "Version Number: " << std::hex + << (uint16_t)this->getVersionNumber() << std::endl; + sif::debug << "Bypass Flag set?| Ctrl Cmd Flag set?: " + << (uint16_t)this->bypassFlagSet() << " | " + << (uint16_t)this->controlCommandFlagSet() << std::endl; + sif::debug << "SCID : " << this->getSpacecraftId() << std::endl; + sif::debug << "VCID : " << (uint16_t)this->getVirtualChannelId() + << std::endl; + sif::debug << "Frame length: " << std::dec << this->getFrameLength() + << std::endl; + sif::debug << "Sequence Number: " << (uint16_t)this->getSequenceNumber() + << std::endl; +#endif } diff --git a/datalinklayer/TcTransferFrameLocal.cpp b/datalinklayer/TcTransferFrameLocal.cpp index e8785c92..de8f568f 100644 --- a/datalinklayer/TcTransferFrameLocal.cpp +++ b/datalinklayer/TcTransferFrameLocal.cpp @@ -37,7 +37,9 @@ TcTransferFrameLocal::TcTransferFrameLocal(bool bypass, bool controlCommand, uin this->getFullFrame()[getFullSize()-2] = (crc & 0xFF00) >> 8; this->getFullFrame()[getFullSize()-1] = (crc & 0x00FF); } else { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::debug << "TcTransferFrameLocal: dataSize too large: " << dataSize << std::endl; +#endif } } else { //No data in frame diff --git a/datalinklayer/VirtualChannelReception.cpp b/datalinklayer/VirtualChannelReception.cpp index cde28de3..3a56fe1e 100644 --- a/datalinklayer/VirtualChannelReception.cpp +++ b/datalinklayer/VirtualChannelReception.cpp @@ -102,8 +102,10 @@ uint8_t VirtualChannelReception::getChannelId() const { ReturnValue_t VirtualChannelReception::initialize() { ReturnValue_t returnValue = RETURN_FAILED; if ((slidingWindowWidth > 254) || (slidingWindowWidth % 2 != 0)) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "VirtualChannelReception::initialize: Illegal sliding window width: " << (int) slidingWindowWidth << std::endl; +#endif return RETURN_FAILED; } for (mapChannelIterator iterator = mapChannels.begin(); iterator != mapChannels.end(); diff --git a/datapool/PoolDataSetBase.cpp b/datapool/PoolDataSetBase.cpp index cb2348f7..01069785 100644 --- a/datapool/PoolDataSetBase.cpp +++ b/datapool/PoolDataSetBase.cpp @@ -9,21 +9,28 @@ PoolDataSetBase::PoolDataSetBase(PoolVariableIF** registeredVariablesArray, PoolDataSetBase::~PoolDataSetBase() {} + ReturnValue_t PoolDataSetBase::registerVariable( PoolVariableIF *variable) { - if (state != States::DATA_SET_UNINITIALISED) { + if (state != States::STATE_SET_UNINITIALISED) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "DataSet::registerVariable: " "Call made in wrong position." << std::endl; +#endif return DataSetIF::DATA_SET_UNINITIALISED; } if (variable == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "DataSet::registerVariable: " "Pool variable is nullptr." << std::endl; +#endif return DataSetIF::POOL_VAR_NULL; } if (fillCount >= maxFillCount) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "DataSet::registerVariable: " "DataSet is full." << std::endl; +#endif return DataSetIF::DATA_SET_FULL; } registeredVariables[fillCount] = variable; @@ -31,25 +38,33 @@ ReturnValue_t PoolDataSetBase::registerVariable( 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; - if (state == States::DATA_SET_UNINITIALISED) { - lockDataPool(lockTimeout); + ReturnValue_t error = result; + if (state == States::STATE_SET_UNINITIALISED) { + lockDataPool(timeoutType, lockTimeout); for (uint16_t count = 0; count < fillCount; count++) { result = readVariable(count); if(result != RETURN_OK) { - break; + error = result; } } - state = States::DATA_SET_WAS_READ; + state = States::STATE_SET_WAS_READ; unlockDataPool(); } else { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "DataSet::read(): " "Call made in wrong position. Don't forget to commit" " member datasets!" << std::endl; +#endif result = SET_WAS_ALREADY_READ; } + + if(error != HasReturnvaluesIF::RETURN_OK) { + result = error; + } return result; } @@ -71,7 +86,15 @@ ReturnValue_t PoolDataSetBase::readVariable(uint16_t count) { registeredVariables[count]->getDataPoolId() != 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) { result = INVALID_PARAMETER_DEFINITION; } @@ -79,55 +102,76 @@ ReturnValue_t PoolDataSetBase::readVariable(uint16_t count) { return result; } -ReturnValue_t PoolDataSetBase::commit(uint32_t lockTimeout) { - if (state == States::DATA_SET_WAS_READ) { - handleAlreadyReadDatasetCommit(lockTimeout); +ReturnValue_t PoolDataSetBase::commit(MutexIF::TimeoutType timeoutType, + uint32_t lockTimeout) { + if (state == States::STATE_SET_WAS_READ) { + handleAlreadyReadDatasetCommit(timeoutType, lockTimeout); return HasReturnvaluesIF::RETURN_OK; } else { - return handleUnreadDatasetCommit(lockTimeout); + return handleUnreadDatasetCommit(timeoutType, lockTimeout); } } -void PoolDataSetBase::handleAlreadyReadDatasetCommit(uint32_t lockTimeout) { - lockDataPool(lockTimeout); +void PoolDataSetBase::handleAlreadyReadDatasetCommit( + MutexIF::TimeoutType timeoutType, uint32_t lockTimeout) { + lockDataPool(timeoutType, lockTimeout); for (uint16_t count = 0; count < fillCount; count++) { if (registeredVariables[count]->getReadWriteMode() != PoolVariableIF::VAR_READ && registeredVariables[count]->getDataPoolId() != 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(); } -ReturnValue_t PoolDataSetBase::handleUnreadDatasetCommit(uint32_t lockTimeout) { +ReturnValue_t PoolDataSetBase::handleUnreadDatasetCommit( + MutexIF::TimeoutType timeoutType, uint32_t lockTimeout) { ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; - lockDataPool(lockTimeout); + lockDataPool(timeoutType, lockTimeout); for (uint16_t count = 0; count < fillCount; count++) { if (registeredVariables[count]->getReadWriteMode() == PoolVariableIF::VAR_WRITE && registeredVariables[count]->getDataPoolId() != PoolVariableIF::NO_PARAMETER) { - registeredVariables[count]->commitWithoutLock(); + if(protectEveryReadCommitCall) { + result = registeredVariables[count]->commit( + timeoutTypeForSingleVars, + mutexTimeoutForSingleVars); + } + else { + result = registeredVariables[count]->commitWithoutLock(); + } + } else if (registeredVariables[count]->getDataPoolId() != PoolVariableIF::NO_PARAMETER) { if (result != COMMITING_WITHOUT_READING) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "DataSet::commit(): commit-without-read call made " "with non write-only variable." << std::endl; +#endif result = COMMITING_WITHOUT_READING; } } } - state = States::DATA_SET_UNINITIALISED; + state = States::STATE_SET_UNINITIALISED; unlockDataPool(); return result; } -ReturnValue_t PoolDataSetBase::lockDataPool(uint32_t timeoutMs) { +ReturnValue_t PoolDataSetBase::lockDataPool(MutexIF::TimeoutType timeoutType, + uint32_t lockTimeout) { return HasReturnvaluesIF::RETURN_OK; } @@ -172,3 +216,15 @@ size_t PoolDataSetBase::getSerializedSize() const { void PoolDataSetBase::setContainer(PoolVariableIF **variablesContainer) { this->registeredVariables = variablesContainer; } + +PoolVariableIF** PoolDataSetBase::getContainer() const { + return registeredVariables; +} + +void PoolDataSetBase::setReadCommitProtectionBehaviour( + bool protectEveryReadCommit, MutexIF::TimeoutType timeoutType, + uint32_t mutexTimeout) { + this->protectEveryReadCommitCall = protectEveryReadCommit; + this->timeoutTypeForSingleVars = timeoutType; + this->mutexTimeoutForSingleVars = mutexTimeout; +} diff --git a/datapool/PoolDataSetBase.h b/datapool/PoolDataSetBase.h index a8931d62..75654146 100644 --- a/datapool/PoolDataSetBase.h +++ b/datapool/PoolDataSetBase.h @@ -3,6 +3,7 @@ #include "PoolDataSetIF.h" #include "PoolVariableIF.h" +#include "../serialize/SerializeIF.h" #include "../ipc/MutexIF.h" /** @@ -44,6 +45,7 @@ public: /** * @brief The read call initializes reading out all registered variables. + * It is mandatory to call commit after every read call! * @details * It iterates through the list of registered variables and calls all read() * functions of the registered pool variables (which read out their values @@ -52,16 +54,18 @@ public: * the operation is aborted and @c INVALID_PARAMETER_DEFINITION returned. * * The data pool is locked during the whole read operation and - * freed afterwards.The state changes to "was written" after this operation. + * freed afterwards. It is mandatory to call commit after a read call, + * even if the read operation is not successful! * @return * - @c RETURN_OK if all variables were read successfully. - * - @c INVALID_PARAMETER_DEFINITION if PID, size or type of the - * requested variable is invalid. + * - @c INVALID_PARAMETER_DEFINITION if a pool entry does not exist or there + * is a type conflict. * - @c SET_WAS_ALREADY_READ if read() is called twice without calling - * commit() in between + * commit() in between */ - virtual ReturnValue_t read(uint32_t lockTimeout = - MutexIF::BLOCKING) override; + virtual ReturnValue_t read( + MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING, + uint32_t lockTimeout = 20) override; /** * @brief The commit call initializes writing back the registered variables. * @details @@ -75,13 +79,14 @@ public: * If the set does contain at least one variable which is not write-only * commit() can only be called after read(). If the set only contains * variables which are write only, commit() can be called without a - * preceding read() call. + * preceding read() call. Every read call must be followed by a commit call! * @return - @c RETURN_OK if all variables were read successfully. * - @c COMMITING_WITHOUT_READING if set was not read yet and * contains non write-only variables */ - virtual ReturnValue_t commit(uint32_t lockTimeout = - MutexIF::BLOCKING) override; + virtual ReturnValue_t commit( + MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING, + uint32_t lockTimeout = 20) override; /** * Register the passed pool variable instance into the data set. @@ -89,13 +94,15 @@ public: * @return */ virtual ReturnValue_t registerVariable( PoolVariableIF* variable) override; + /** * Provides the means to lock the underlying data structure to ensure * thread-safety. Default implementation is empty * @return Always returns -@c RETURN_OK */ - virtual ReturnValue_t lockDataPool(uint32_t timeoutMs = - MutexIF::BLOCKING) override; + virtual ReturnValue_t lockDataPool( + MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING, + uint32_t timeoutMs = 20) override; /** * Provides the means to unlock the underlying data structure to ensure * thread-safety. Default implementation is empty @@ -113,7 +120,16 @@ public: virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, SerializeIF::Endianness streamEndianness) override; + /** + * Can be used to individually protect every read and commit call. + * @param protectEveryReadCommit + * @param mutexTimeout + */ + void setReadCommitProtectionBehaviour(bool protectEveryReadCommit, + MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING, + uint32_t mutexTimeout = 20); protected: + /** * @brief The fill_count attribute ensures that the variables * register in the correct array position and that the maximum @@ -124,14 +140,14 @@ protected: * States of the seet. */ enum class States { - DATA_SET_UNINITIALISED, //!< DATA_SET_UNINITIALISED - DATA_SET_WAS_READ //!< DATA_SET_WAS_READ + STATE_SET_UNINITIALISED, //!< DATA_SET_UNINITIALISED + STATE_SET_WAS_READ //!< DATA_SET_WAS_READ }; /** * @brief state manages the internal state of the data set, * which is important e.g. for the behavior on destruction. */ - States state = States::DATA_SET_UNINITIALISED; + States state = States::STATE_SET_UNINITIALISED; /** * @brief This array represents all pool variables registered in this set. @@ -142,11 +158,20 @@ protected: const size_t maxFillCount = 0; void setContainer(PoolVariableIF** variablesContainer); + PoolVariableIF** getContainer() const; private: + bool protectEveryReadCommitCall = false; + MutexIF::TimeoutType timeoutTypeForSingleVars = MutexIF::TimeoutType::WAITING; + uint32_t mutexTimeoutForSingleVars = 20; + ReturnValue_t readVariable(uint16_t count); - void handleAlreadyReadDatasetCommit(uint32_t lockTimeout); - ReturnValue_t handleUnreadDatasetCommit(uint32_t lockTimeout); + void handleAlreadyReadDatasetCommit( + MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING, + uint32_t timeoutMs = 20); + ReturnValue_t handleUnreadDatasetCommit( + MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING, + uint32_t timeoutMs = 20); }; #endif /* FSFW_DATAPOOL_POOLDATASETBASE_H_ */ diff --git a/datapool/PoolDataSetIF.h b/datapool/PoolDataSetIF.h index aa45fa54..1f52871d 100644 --- a/datapool/PoolDataSetIF.h +++ b/datapool/PoolDataSetIF.h @@ -1,26 +1,27 @@ #ifndef FSFW_DATAPOOL_POOLDATASETIF_H_ #define FSFW_DATAPOOL_POOLDATASETIF_H_ +#include "ReadCommitIF.h" #include "DataSetIF.h" /** * @brief Extendes the DataSetIF by adding abstract functions to lock * and unlock a data pool and read/commit semantics. */ -class PoolDataSetIF: public DataSetIF { +class PoolDataSetIF: public DataSetIF, public ReadCommitIF { public: 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 * and will require a lock and unlock mechanism to ensure * thread-safety * @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. * @return Unlock operation result diff --git a/datapool/PoolEntry.cpp b/datapool/PoolEntry.cpp index fb73328c..a5867222 100644 --- a/datapool/PoolEntry.cpp +++ b/datapool/PoolEntry.cpp @@ -1,29 +1,24 @@ #include "PoolEntry.h" -#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../serviceinterface/ServiceInterface.h" #include "../globalfunctions/arrayprinter.h" #include +#include template -PoolEntry::PoolEntry(std::initializer_list initValue, uint8_t setLength, - bool setValid ) : length(setLength), valid(setValid) { +PoolEntry::PoolEntry(std::initializer_list initValue, bool setValid ): + length(initValue.size()), valid(setValid) { this->address = new T[this->length]; if(initValue.size() == 0) { std::memset(this->address, 0, this->getByteSize()); } - else if (initValue.size() != setLength){ - sif::warning << "PoolEntry: setLength is not equal to initializer list" - "length! Performing zero initialization with given setLength" - << std::endl; - std::memset(this->address, 0, this->getByteSize()); - } else { std::copy(initValue.begin(), initValue.end(), this->address); } } template -PoolEntry::PoolEntry( T* initValue, uint8_t setLength, bool setValid ) : +PoolEntry::PoolEntry(T* initValue, uint8_t setLength, bool setValid): length(setLength), valid(setValid) { this->address = new T[this->length]; if (initValue != nullptr) { @@ -67,10 +62,26 @@ bool PoolEntry::getValid() { template void PoolEntry::print() { - sif::debug << "Pool Entry Validity: " << - (this->valid? " (valid) " : " (invalid) ") << std::endl; - arrayprinter::print(reinterpret_cast(address), length); - sif::debug << std::dec << std::endl; + const char* validString = nullptr; + if(valid) { + validString = "Valid"; + } + else { + validString = "Invalid"; + } +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "PoolEntry information." << std::endl; + sif::info << "PoolEntry validity: " << validString << std::endl; +#else + sif::printInfo("PoolEntry information.\n"); + sif::printInfo("PoolEntry validity: %s\n", validString); +#endif + arrayprinter::print(reinterpret_cast(address), getByteSize()); +} + +template +inline T* PoolEntry::getDataPtr() { + return this->address; } template @@ -81,8 +92,10 @@ Type PoolEntry::getType() { template class PoolEntry; template class PoolEntry; template class PoolEntry; +template class PoolEntry; template class PoolEntry; template class PoolEntry; template class PoolEntry; +template class PoolEntry; template class PoolEntry; template class PoolEntry; diff --git a/datapool/PoolEntry.h b/datapool/PoolEntry.h index 033db40d..30940320 100644 --- a/datapool/PoolEntry.h +++ b/datapool/PoolEntry.h @@ -35,24 +35,22 @@ public: "uint8_t"); /** * @brief In the classe's constructor, space is allocated on the heap and - * potential init values are copied to that space. + * potential initialization values are copied to that space. * @details * Not passing any arguments will initialize an non-array pool entry - * (setLength = 1) with an initial invalid state. - * Please note that if an initializer list is passed, the correct - * corresponding length should be passed too, otherwise a zero - * initialization will be performed with the given setLength. + * with an initial invalid state and the value 0. + * Please note that if an initializer list is passed, the length of the + * initializer list needs to be correct for vector entries because + * required allocated space will be deduced from the initializer list length + * and the pool entry type. * @param initValue - * Initializer list with values to initialize with, for example {0,0} to - * initialize the two entries to zero. - * @param setLength - * Defines the array length of this entry. Should be equal to the - * intializer list length. + * Initializer list with values to initialize with, for example {0, 0} to + * initialize the a pool entry of a vector with two entries to 0. * @param setValid * Sets the initialization flag. It is invalid by default. */ - PoolEntry(std::initializer_list initValue = {}, uint8_t setLength = 1, - bool setValid = false); + PoolEntry(std::initializer_list initValue = {0}, bool setValid = false); + /** * @brief In the classe's constructor, space is allocated on the heap and * potential init values are copied to that space. @@ -66,9 +64,9 @@ public: */ PoolEntry(T* initValue, uint8_t setLength = 1, bool setValid = false); - //! Explicitely deleted copy ctor, copying is not allowed! + //! Explicitely deleted copy ctor, copying is not allowed. PoolEntry(const PoolEntry&) = delete; - //! Explicitely deleted copy assignment, copying is not allowed! + //! Explicitely deleted copy assignment, copying is not allowed. PoolEntry& operator=(const PoolEntry&) = delete; /** @@ -82,21 +80,16 @@ public: ~PoolEntry(); /** - * @brief This is the address pointing to the allocated memory. + * Return typed pointer to start of data. + * @return */ - T* address; - /** - * @brief This attribute stores the length information. - */ - uint8_t length; - /** - * @brief Here, the validity information for a variable is stored. - * Every entry (single variable or vector) has one valid flag. - */ - uint8_t valid; + T* getDataPtr(); + /** * @brief getSize returns the array size of the entry. - * @details A single parameter has size 1. + * @details + * For non-array pool entries return type size, for vector entries + * return type size times the number of entries. */ uint8_t getSize(); /** @@ -123,8 +116,22 @@ public: * information to the screen. It prints all array entries in a row. */ void print(); - Type getType(); + +private: + /** + * @brief This attribute stores the length information. + */ + uint8_t length; + /** + * @brief Here, the validity information for a variable is stored. + * Every entry (single variable or vector) has one valid flag. + */ + uint8_t valid; + /** + * @brief This is the address pointing to the allocated memory. + */ + T* address; }; #endif /* FSFW_DATAPOOL_POOLENTRY_H_ */ diff --git a/datapool/PoolReadHelper.h b/datapool/PoolReadHelper.h new file mode 100644 index 00000000..5c3153bb --- /dev/null +++ b/datapool/PoolReadHelper.h @@ -0,0 +1,51 @@ +#ifndef FSFW_DATAPOOL_POOLREADHELPER_H_ +#define FSFW_DATAPOOL_POOLREADHELPER_H_ + +#include "ReadCommitIF.h" +#include "../serviceinterface/ServiceInterface.h" +#include + +/** + * @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_ */ diff --git a/datapool/PoolVariableIF.h b/datapool/PoolVariableIF.h index cd15f744..444e19d0 100644 --- a/datapool/PoolVariableIF.h +++ b/datapool/PoolVariableIF.h @@ -3,6 +3,7 @@ #include "../returnvalues/HasReturnvaluesIF.h" #include "../serialize/SerializeIF.h" +#include "ReadCommitIF.h" /** * @brief This interface is used to control data pool @@ -17,13 +18,14 @@ * @author Bastian Baetz * @ingroup data_pool */ -class PoolVariableIF : public SerializeIF { +class PoolVariableIF : public SerializeIF, + public ReadCommitIF { friend class PoolDataSetBase; - friend class GlobDataSet; friend class LocalPoolDataSetBase; public: static constexpr uint8_t INTERFACE_ID = CLASS_ID::POOL_VARIABLE_IF; static constexpr ReturnValue_t INVALID_READ_WRITE_MODE = MAKE_RETURN_CODE(0xA0); + static constexpr ReturnValue_t INVALID_POOL_ENTRY = MAKE_RETURN_CODE(0xA1); static constexpr bool VALID = 1; static constexpr bool INVALID = 0; @@ -57,41 +59,6 @@ public: */ 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; diff --git a/datapool/ReadCommitIF.h b/datapool/ReadCommitIF.h new file mode 100644 index 00000000..e6355e82 --- /dev/null +++ b/datapool/ReadCommitIF.h @@ -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_ */ diff --git a/datapoollocal/AccessLocalPoolF.h b/datapoollocal/AccessLocalPoolF.h new file mode 100644 index 00000000..f68189f6 --- /dev/null +++ b/datapoollocal/AccessLocalPoolF.h @@ -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_ */ diff --git a/datapoollocal/CMakeLists.txt b/datapoollocal/CMakeLists.txt index c6b187cd..e2db39eb 100644 --- a/datapoollocal/CMakeLists.txt +++ b/datapoollocal/CMakeLists.txt @@ -5,4 +5,6 @@ target_sources(${LIB_FSFW_NAME} LocalPoolDataSetBase.cpp LocalPoolObjectBase.cpp SharedLocalDataSet.cpp -) \ No newline at end of file +) + +add_subdirectory(internal) \ No newline at end of file diff --git a/datapoollocal/HasLocalDataPoolIF.h b/datapoollocal/HasLocalDataPoolIF.h index 7f1f202e..1d87d47c 100644 --- a/datapoollocal/HasLocalDataPoolIF.h +++ b/datapoollocal/HasLocalDataPoolIF.h @@ -1,100 +1,66 @@ #ifndef FSFW_DATAPOOLLOCAL_HASLOCALDATAPOOLIF_H_ #define FSFW_DATAPOOLLOCAL_HASLOCALDATAPOOLIF_H_ -#include "locPoolDefinitions.h" +#include "localPoolDefinitions.h" +#include "LocalDataPoolManager.h" #include "../datapool/PoolEntryIF.h" +#include "../serviceinterface/ServiceInterface.h" #include "../ipc/MessageQueueSenderIF.h" #include "../housekeeping/HousekeepingMessage.h" #include -class LocalDataPoolManager; +class AccessPoolManagerIF; +class ProvidesDataPoolSubscriptionIF; class LocalPoolDataSetBase; class LocalPoolObjectBase; -using LocalDataPool = std::map; -using LocalDataPoolMapIter = LocalDataPool::iterator; - /** - * @brief This interface is implemented by classes which posses a local - * data pool (not the managing class). It defines the relationship - * between the local data pool owner and the LocalDataPoolManager. + * @brief This interface is implemented by classes which posses a local data pool (not the + * managing class). It defines the relationship between the local data pool owner + * and the LocalDataPoolManager. * @details - * Any class implementing this interface shall also have a LocalDataPoolManager - * member class which contains the actual pool data structure - * and exposes the public interface for it. - * This is required because the pool entries are templates, which makes - * specifying an interface rather difficult. The local data pool can be - * accessed by using the LocalPoolVariable, LocalPoolVector or LocalDataSet - * classes. + * Any class implementing this interface shall also have a LocalDataPoolManager member class which + * contains the actual pool data structure and exposes the public interface for it. + * The local data pool can be accessed using helper classes by using the + * LocalPoolVariable, LocalPoolVector or LocalDataSet classes. Every local pool variable can + * be uniquely identified by a global pool ID (gp_id_t) and every dataset tied + * to a pool manager can be uniqely identified by a global structure ID (sid_t). * - * 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 { + friend class HasLocalDpIFManagerAttorney; + friend class HasLocalDpIFUserAttorney; 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 - * 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( - 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; - } + /** + * 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; /** * @brief This function will be called by the manager if an update * notification is received. - * @details + * @details HasLocalDataPoolIF * Can be overriden by the child class to handle changed datasets. * @param sid * @param storeId If a snapshot was requested, data will be located inside @@ -119,18 +85,81 @@ public: return; } - /* These function can be implemented by pool owner, as they are required - * by the housekeeping message interface */ - virtual ReturnValue_t addDataSet(sid_t sid) { - return HasReturnvaluesIF::RETURN_FAILED; - }; - virtual ReturnValue_t removeDataSet(sid_t sid) { - return HasReturnvaluesIF::RETURN_FAILED; - }; - virtual ReturnValue_t changeCollectionInterval(sid_t sid, - float newIntervalSeconds) { - return HasReturnvaluesIF::RETURN_FAILED; - }; + /** + * These function can be implemented by pool owner, if they are required + * and used by the housekeeping message interface. + * */ + virtual ReturnValue_t addDataSet(sid_t sid) { + return HasReturnvaluesIF::RETURN_FAILED; + }; + virtual ReturnValue_t removeDataSet(sid_t sid) { + return HasReturnvaluesIF::RETURN_FAILED; + }; + virtual ReturnValue_t changeCollectionInterval(sid_t sid, float newIntervalSeconds) { + return HasReturnvaluesIF::RETURN_FAILED; + }; + + /** + * This function can be used by data pool consumers to retrieve a handle + * which allows subscriptions to dataset and variable updates in form of messages. + * The consumers can then read the most recent variable value by calling read with + * an own pool variable or set instance or using the deserialized snapshot data. + * Returns the HK manager casted to the required interface by default. + * @return + */ + virtual ProvidesDataPoolSubscriptionIF* getSubscriptionInterface() { + return getHkManagerHandle(); + } + +protected: + + /** + * Every class implementing this interface should have a local data pool manager. This + * function will return a reference to the manager. + * @return + */ + virtual LocalDataPoolManager* getHkManagerHandle() = 0; + + /** + * Accessor handle required for internal handling. Not intended for users and therefore + * declared protected. Users should instead use pool variables, sets or the subscription + * interface to access pool entries. Returns the HK manager casted to a different interface + * by default. + * @return + */ + virtual AccessPoolManagerIF* getAccessorHandle() { + return getHkManagerHandle(); + } + + /** + * This function is used by the pool manager to get a valid dataset + * from a SID. This function is protected to prevent users from + * using raw data set pointers which could not be thread-safe. Users + * should use the #ProvidesDataPoolSubscriptionIF. + * @param sid Corresponding structure ID + * @return + */ + virtual LocalPoolDataSetBase* getDataSetHandle(sid_t sid) = 0; + + /** + * Similar to the function above, but used to get a local pool variable + * handle. This is only needed for update notifications, so it is not + * defined as abstract. This function is protected to prevent users from + * using raw pool variable pointers which could not be thread-safe. + * Users should use the #ProvidesDataPoolSubscriptionIF. + * @param localPoolId + * @return + */ + virtual LocalPoolObjectBase* getPoolObjectHandle(lp_id_t localPoolId) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "HasLocalDataPoolIF::getPoolObjectHandle: Not overriden" + << ". Returning nullptr!" << std::endl; +#else + sif::printWarning("HasLocalDataPoolIF::getPoolObjectHandle: " + "Not overriden. Returning nullptr!\n"); +#endif + return nullptr; + } }; #endif /* FSFW_DATAPOOLLOCAL_HASLOCALDATAPOOLIF_H_ */ diff --git a/datapoollocal/LocalDataPoolManager.cpp b/datapoollocal/LocalDataPoolManager.cpp index f649a362..462ef17f 100644 --- a/datapoollocal/LocalDataPoolManager.cpp +++ b/datapoollocal/LocalDataPoolManager.cpp @@ -1,11 +1,13 @@ +#include "HasLocalDataPoolIF.h" #include "LocalDataPoolManager.h" #include "LocalPoolObjectBase.h" #include "LocalPoolDataSetBase.h" +#include "internal/LocalPoolDataSetAttorney.h" +#include "internal/HasLocalDpIFManagerAttorney.h" #include "../housekeeping/HousekeepingPacketUpdate.h" #include "../housekeeping/HousekeepingSetPacket.h" #include "../housekeeping/AcceptsHkPacketsIF.h" - #include "../timemanager/CCSDSTime.h" #include "../ipc/MutexFactory.h" #include "../ipc/MutexHelper.h" @@ -14,769 +16,896 @@ #include #include -object_id_t LocalDataPoolManager::defaultHkDestination = - objects::PUS_SERVICE_3_HOUSEKEEPING; +object_id_t LocalDataPoolManager::defaultHkDestination = objects::PUS_SERVICE_3_HOUSEKEEPING; -LocalDataPoolManager::LocalDataPoolManager(HasLocalDataPoolIF* owner, - MessageQueueIF* queueToUse, bool appendValidityBuffer): - appendValidityBuffer(appendValidityBuffer) { - if(owner == nullptr) { - sif::error << "LocalDataPoolManager::LocalDataPoolManager: " - << "Invalid supplied owner!" << std::endl; - return; - } - this->owner = owner; - mutex = MutexFactory::instance()->createMutex(); - if(mutex == nullptr) { - sif::error << "LocalDataPoolManager::LocalDataPoolManager: " - << "Could not create mutex." << std::endl; - } +LocalDataPoolManager::LocalDataPoolManager(HasLocalDataPoolIF* owner, MessageQueueIF* queueToUse, + bool appendValidityBuffer): + appendValidityBuffer(appendValidityBuffer) { + if(owner == nullptr) { + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "LocalDataPoolManager", HasReturnvaluesIF::RETURN_FAILED, + "Invalid supplied owner"); + return; + } + this->owner = owner; + mutex = MutexFactory::instance()->createMutex(); + if(mutex == nullptr) { + printWarningOrError(sif::OutputTypes::OUT_ERROR, + "LocalDataPoolManager", HasReturnvaluesIF::RETURN_FAILED, + "Could not create mutex"); + } - hkQueue = queueToUse; + hkQueue = queueToUse; } LocalDataPoolManager::~LocalDataPoolManager() {} ReturnValue_t LocalDataPoolManager::initialize(MessageQueueIF* queueToUse) { - if(queueToUse == nullptr) { - sif::error << "LocalDataPoolManager::initialize: " - << std::hex << "0x" << owner->getObjectId() << ". Supplied " - << "queue invalid!" << std::dec << std::endl; - } - hkQueue = queueToUse; + if(queueToUse == nullptr) { + // error, all destinations invalid + printWarningOrError(sif::OutputTypes::OUT_ERROR, + "initialize", QUEUE_OR_DESTINATION_INVALID); + } + hkQueue = queueToUse; - ipcStore = objectManager->get(objects::IPC_STORE); - if(ipcStore == nullptr) { - sif::error << "LocalDataPoolManager::initialize: " - << std::hex << "0x" << owner->getObjectId() << ": Could not " - << "set IPC store." <get(objects::IPC_STORE); + if(ipcStore == nullptr) { + // error, all destinations invalid + printWarningOrError(sif::OutputTypes::OUT_ERROR, + "initialize", HasReturnvaluesIF::RETURN_FAILED, + "Could not set IPC store."); + return HasReturnvaluesIF::RETURN_FAILED; + } - if(defaultHkDestination != objects::NO_OBJECT) { - AcceptsHkPacketsIF* hkPacketReceiver = - objectManager->get(defaultHkDestination); - if(hkPacketReceiver != nullptr) { - hkDestinationId = hkPacketReceiver->getHkQueue(); - } - else { - sif::error << "LocalDataPoolManager::LocalDataPoolManager: " - << "Default HK destination object is invalid!" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - } + if(defaultHkDestination != objects::NO_OBJECT) { + AcceptsHkPacketsIF* hkPacketReceiver = + objectManager->get(defaultHkDestination); + if(hkPacketReceiver != nullptr) { + hkDestinationId = hkPacketReceiver->getHkQueue(); + } + else { + printWarningOrError(sif::OutputTypes::OUT_ERROR, + "initialize", QUEUE_OR_DESTINATION_INVALID); + return QUEUE_OR_DESTINATION_INVALID; + } + } - return HasReturnvaluesIF::RETURN_OK; + return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t LocalDataPoolManager::initializeAfterTaskCreation( - uint8_t nonDiagInvlFactor) { - setNonDiagnosticIntervalFactor(nonDiagInvlFactor); - return initializeHousekeepingPoolEntriesOnce(); + uint8_t nonDiagInvlFactor) { + setNonDiagnosticIntervalFactor(nonDiagInvlFactor); + return initializeHousekeepingPoolEntriesOnce(); } ReturnValue_t LocalDataPoolManager::initializeHousekeepingPoolEntriesOnce() { - if(not mapInitialized) { - ReturnValue_t result = owner->initializeLocalDataPool(localPoolMap, - *this); - if(result == HasReturnvaluesIF::RETURN_OK) { - mapInitialized = true; - } - return result; - } - sif::warning << "HousekeepingManager: The map should only be initialized " - << "once!" << std::endl; - return HasReturnvaluesIF::RETURN_OK; + if(not mapInitialized) { + ReturnValue_t result = owner->initializeLocalDataPool(localPoolMap, + *this); + if(result == HasReturnvaluesIF::RETURN_OK) { + mapInitialized = true; + } + return result; + } + + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "initialize", HasReturnvaluesIF::RETURN_FAILED, + "The map should only be initialized once"); + return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t LocalDataPoolManager::performHkOperation() { - ReturnValue_t status = HasReturnvaluesIF::RETURN_OK; - for(auto& receiver: hkReceiversMap) { - switch(receiver.reportingType) { - case(ReportingType::PERIODIC): { - if(receiver.dataType == DataType::LOCAL_POOL_VARIABLE) { - // Periodic packets shall only be generated from datasets. - continue; - } - performPeriodicHkGeneration(receiver); - break; - } - case(ReportingType::UPDATE_HK): { - handleHkUpdate(receiver, status); - break; - } - case(ReportingType::UPDATE_NOTIFICATION): { - handleNotificationUpdate(receiver, status); - break; - } - case(ReportingType::UPDATE_SNAPSHOT): { - handleNotificationSnapshot(receiver, status); - break; - } - default: - // This should never happen. - return HasReturnvaluesIF::RETURN_FAILED; - } - } - resetHkUpdateResetHelper(); - return status; + ReturnValue_t status = HasReturnvaluesIF::RETURN_OK; + for(auto& receiver: hkReceiversMap) { + switch(receiver.reportingType) { + case(ReportingType::PERIODIC): { + if(receiver.dataType == DataType::LOCAL_POOL_VARIABLE) { + // Periodic packets shall only be generated from datasets. + continue; + } + performPeriodicHkGeneration(receiver); + break; + } + case(ReportingType::UPDATE_HK): { + handleHkUpdate(receiver, status); + break; + } + case(ReportingType::UPDATE_NOTIFICATION): { + handleNotificationUpdate(receiver, status); + break; + } + case(ReportingType::UPDATE_SNAPSHOT): { + handleNotificationSnapshot(receiver, status); + break; + } + default: + // This should never happen. + return HasReturnvaluesIF::RETURN_FAILED; + } + } + resetHkUpdateResetHelper(); + return status; } ReturnValue_t LocalDataPoolManager::handleHkUpdate(HkReceiver& receiver, - ReturnValue_t& status) { - if(receiver.dataType == DataType::LOCAL_POOL_VARIABLE) { - // Update packets shall only be generated from datasets. - return HasReturnvaluesIF::RETURN_FAILED; - } - LocalPoolDataSetBase* dataSet = owner->getDataSetHandle( - receiver.dataId.sid); - if(dataSet->hasChanged()) { - // prepare and send update notification - ReturnValue_t result = generateHousekeepingPacket( - receiver.dataId.sid, dataSet, true); - if(result != HasReturnvaluesIF::RETURN_OK) { - status = result; - } - } - handleChangeResetLogic(receiver.dataType, receiver.dataId, - dataSet); - return HasReturnvaluesIF::RETURN_OK; + ReturnValue_t& status) { + if(receiver.dataType == DataType::LOCAL_POOL_VARIABLE) { + // Update packets shall only be generated from datasets. + return HasReturnvaluesIF::RETURN_FAILED; + } + LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, + receiver.dataId.sid); + if(dataSet->hasChanged()) { + // prepare and send update notification + ReturnValue_t result = generateHousekeepingPacket( + receiver.dataId.sid, dataSet, true); + if(result != HasReturnvaluesIF::RETURN_OK) { + status = result; + } + } + handleChangeResetLogic(receiver.dataType, receiver.dataId, + dataSet); + return HasReturnvaluesIF::RETURN_OK; } -ReturnValue_t LocalDataPoolManager::handleNotificationUpdate( - HkReceiver& receiver, ReturnValue_t& status) { - MarkChangedIF* toReset = nullptr; - if(receiver.dataType == DataType::LOCAL_POOL_VARIABLE) { - LocalPoolObjectBase* poolObj = owner->getPoolObjectHandle( - receiver.dataId.localPoolId); - if(poolObj == nullptr) { - return HasReturnvaluesIF::RETURN_FAILED; - } - if(poolObj->hasChanged()) { - // prepare and send update notification. - CommandMessage notification; - HousekeepingMessage::setUpdateNotificationVariableCommand( - ¬ification, receiver.dataId.localPoolId); - ReturnValue_t result = hkQueue->sendMessage( - receiver.destinationQueue, ¬ification); - if(result != HasReturnvaluesIF::RETURN_OK) { - status = result; - } - toReset = poolObj; - } +ReturnValue_t LocalDataPoolManager::handleNotificationUpdate(HkReceiver& receiver, + ReturnValue_t& status) { + MarkChangedIF* toReset = nullptr; + if(receiver.dataType == DataType::LOCAL_POOL_VARIABLE) { + LocalPoolObjectBase* poolObj = HasLocalDpIFManagerAttorney::getPoolObjectHandle(owner, + receiver.dataId.localPoolId); + //LocalPoolObjectBase* poolObj = owner->getPoolObjectHandle(receiver.dataId.localPoolId); + if(poolObj == nullptr) { + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "handleNotificationUpdate", POOLOBJECT_NOT_FOUND); + return POOLOBJECT_NOT_FOUND; + } + if(poolObj->hasChanged()) { + // prepare and send update notification. + CommandMessage notification; + HousekeepingMessage::setUpdateNotificationVariableCommand(¬ification, + receiver.dataId.localPoolId); + ReturnValue_t result = hkQueue->sendMessage( + receiver.destinationQueue, ¬ification); + if(result != HasReturnvaluesIF::RETURN_OK) { + status = result; + } + toReset = poolObj; + } - } - else { - LocalPoolDataSetBase* dataSet = owner->getDataSetHandle( - receiver.dataId.sid); - if(dataSet == nullptr) { - return HasReturnvaluesIF::RETURN_FAILED; - } - if(dataSet->hasChanged()) { - // prepare and send update notification - CommandMessage notification; - HousekeepingMessage::setUpdateNotificationSetCommand( - ¬ification, receiver.dataId.sid); - ReturnValue_t result = hkQueue->sendMessage( - receiver.destinationQueue, ¬ification); - if(result != HasReturnvaluesIF::RETURN_OK) { - status = result; - } - toReset = dataSet; - } - } - if(toReset != nullptr) { - handleChangeResetLogic(receiver.dataType, - receiver.dataId, toReset); - } - return HasReturnvaluesIF::RETURN_OK; + } + else { + LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, + receiver.dataId.sid); + if(dataSet == nullptr) { + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "handleNotificationUpdate", DATASET_NOT_FOUND); + return DATASET_NOT_FOUND; + } + if(dataSet->hasChanged()) { + // prepare and send update notification + CommandMessage notification; + HousekeepingMessage::setUpdateNotificationSetCommand( + ¬ification, receiver.dataId.sid); + ReturnValue_t result = hkQueue->sendMessage( + receiver.destinationQueue, ¬ification); + if(result != HasReturnvaluesIF::RETURN_OK) { + status = result; + } + toReset = dataSet; + } + } + if(toReset != nullptr) { + handleChangeResetLogic(receiver.dataType, + receiver.dataId, toReset); + } + return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t LocalDataPoolManager::handleNotificationSnapshot( - HkReceiver& receiver, ReturnValue_t& status) { - MarkChangedIF* toReset = nullptr; - // check whether data has changed and send messages in case it has. - if(receiver.dataType == DataType::LOCAL_POOL_VARIABLE) { - LocalPoolObjectBase* poolObj = owner->getPoolObjectHandle( - receiver.dataId.localPoolId); - if(poolObj == nullptr) { - return HasReturnvaluesIF::RETURN_FAILED; - } + HkReceiver& receiver, ReturnValue_t& status) { + MarkChangedIF* toReset = nullptr; + // check whether data has changed and send messages in case it has. + if(receiver.dataType == DataType::LOCAL_POOL_VARIABLE) { + LocalPoolObjectBase* poolObj = HasLocalDpIFManagerAttorney::getPoolObjectHandle(owner, + receiver.dataId.localPoolId); + if(poolObj == nullptr) { + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "handleNotificationSnapshot", POOLOBJECT_NOT_FOUND); + return POOLOBJECT_NOT_FOUND; + } - if (not poolObj->hasChanged()) { - return HasReturnvaluesIF::RETURN_OK; - } + if (not poolObj->hasChanged()) { + return HasReturnvaluesIF::RETURN_OK; + } - // prepare and send update snapshot. - timeval now; - Clock::getClock_timeval(&now); - CCSDSTime::CDS_short cds; - CCSDSTime::convertToCcsds(&cds, &now); - HousekeepingPacketUpdate updatePacket(reinterpret_cast(&cds), - sizeof(cds), owner->getPoolObjectHandle( - receiver.dataId.localPoolId)); + // prepare and send update snapshot. + timeval now; + Clock::getClock_timeval(&now); + CCSDSTime::CDS_short cds; + CCSDSTime::convertToCcsds(&cds, &now); + HousekeepingPacketUpdate updatePacket(reinterpret_cast(&cds), + sizeof(cds), HasLocalDpIFManagerAttorney::getPoolObjectHandle(owner, + receiver.dataId.localPoolId)); - store_address_t storeId; - ReturnValue_t result = addUpdateToStore(updatePacket, storeId); - if(result != HasReturnvaluesIF::RETURN_OK) { - return result; - } + store_address_t storeId; + ReturnValue_t result = addUpdateToStore(updatePacket, storeId); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } - CommandMessage notification; - HousekeepingMessage::setUpdateSnapshotVariableCommand(¬ification, - receiver.dataId.localPoolId, storeId); - result = hkQueue->sendMessage(receiver.destinationQueue, - ¬ification); - if (result != HasReturnvaluesIF::RETURN_OK) { - status = result; - } - toReset = poolObj; - } - else { - LocalPoolDataSetBase* dataSet = owner->getDataSetHandle( - receiver.dataId.sid); - if(dataSet == nullptr) { - return HasReturnvaluesIF::RETURN_FAILED; - } + CommandMessage notification; + HousekeepingMessage::setUpdateSnapshotVariableCommand(¬ification, + receiver.dataId.localPoolId, storeId); + result = hkQueue->sendMessage(receiver.destinationQueue, + ¬ification); + if (result != HasReturnvaluesIF::RETURN_OK) { + status = result; + } + toReset = poolObj; + } + else { + LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, + receiver.dataId.sid); + if(dataSet == nullptr) { + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "handleNotificationSnapshot", DATASET_NOT_FOUND); + return DATASET_NOT_FOUND; + } - if(not dataSet->hasChanged()) { - return HasReturnvaluesIF::RETURN_OK; - } + if(not dataSet->hasChanged()) { + return HasReturnvaluesIF::RETURN_OK; + } - // prepare and send update snapshot. - timeval now; - Clock::getClock_timeval(&now); - CCSDSTime::CDS_short cds; - CCSDSTime::convertToCcsds(&cds, &now); - HousekeepingPacketUpdate updatePacket(reinterpret_cast(&cds), - sizeof(cds), owner->getDataSetHandle(receiver.dataId.sid)); + // prepare and send update snapshot. + timeval now; + Clock::getClock_timeval(&now); + CCSDSTime::CDS_short cds; + CCSDSTime::convertToCcsds(&cds, &now); + HousekeepingPacketUpdate updatePacket(reinterpret_cast(&cds), + sizeof(cds), HasLocalDpIFManagerAttorney::getDataSetHandle(owner, + receiver.dataId.sid)); - store_address_t storeId; - ReturnValue_t result = addUpdateToStore(updatePacket, storeId); - if(result != HasReturnvaluesIF::RETURN_OK) { - return result; - } + store_address_t storeId; + ReturnValue_t result = addUpdateToStore(updatePacket, storeId); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } - CommandMessage notification; - HousekeepingMessage::setUpdateSnapshotSetCommand( - ¬ification, receiver.dataId.sid, storeId); - result = hkQueue->sendMessage(receiver.destinationQueue, ¬ification); - if(result != HasReturnvaluesIF::RETURN_OK) { - status = result; - } - toReset = dataSet; + CommandMessage notification; + HousekeepingMessage::setUpdateSnapshotSetCommand( + ¬ification, receiver.dataId.sid, storeId); + result = hkQueue->sendMessage(receiver.destinationQueue, ¬ification); + if(result != HasReturnvaluesIF::RETURN_OK) { + status = result; + } + toReset = dataSet; - } - if(toReset != nullptr) { - handleChangeResetLogic(receiver.dataType, - receiver.dataId, toReset); - } - return HasReturnvaluesIF::RETURN_OK; + } + if(toReset != nullptr) { + handleChangeResetLogic(receiver.dataType, + receiver.dataId, toReset); + } + return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t LocalDataPoolManager::addUpdateToStore( - HousekeepingPacketUpdate& updatePacket, store_address_t& storeId) { - size_t updatePacketSize = updatePacket.getSerializedSize(); - uint8_t *storePtr = nullptr; - ReturnValue_t result = ipcStore->getFreeElement(&storeId, - updatePacket.getSerializedSize(), &storePtr); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - size_t serializedSize = 0; - result = updatePacket.serialize(&storePtr, &serializedSize, - updatePacketSize, SerializeIF::Endianness::MACHINE); - return result;; + HousekeepingPacketUpdate& updatePacket, store_address_t& storeId) { + size_t updatePacketSize = updatePacket.getSerializedSize(); + uint8_t *storePtr = nullptr; + ReturnValue_t result = ipcStore->getFreeElement(&storeId, + updatePacket.getSerializedSize(), &storePtr); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + size_t serializedSize = 0; + result = updatePacket.serialize(&storePtr, &serializedSize, + updatePacketSize, SerializeIF::Endianness::MACHINE); + return result;; } void LocalDataPoolManager::handleChangeResetLogic( - DataType type, DataId dataId, MarkChangedIF* toReset) { - if(hkUpdateResetList == nullptr) { - // config error! - return; - } + DataType type, DataId dataId, MarkChangedIF* toReset) { + if(hkUpdateResetList == nullptr) { + // config error! + return; + } + HkUpdateResetList& listRef = *hkUpdateResetList; + for(auto& changeInfo: listRef) { + if(changeInfo.dataType != type) { + continue; + } + if((changeInfo.dataType == DataType::DATA_SET) and + (changeInfo.dataId.sid != dataId.sid)) { + continue; + } + if((changeInfo.dataType == DataType::LOCAL_POOL_VARIABLE) and + (changeInfo.dataId.localPoolId != dataId.localPoolId)) { + continue; + } - for(auto& changeInfo: *hkUpdateResetList) { - if(changeInfo.dataType != type) { - continue; - } - if((changeInfo.dataType == DataType::DATA_SET) and - (changeInfo.dataId.sid != dataId.sid)) { - continue; - } - if((changeInfo.dataType == DataType::LOCAL_POOL_VARIABLE) and - (changeInfo.dataId.localPoolId != dataId.localPoolId)) { - continue; - } - - if(changeInfo.updateCounter <= 1) { - toReset->setChanged(false); - } - if(changeInfo.currentUpdateCounter == 0) { - toReset->setChanged(false); - } - else { - changeInfo.currentUpdateCounter--; - } - return; - } + // only one update recipient, we can reset changes status immediately. + if(changeInfo.updateCounter <= 1) { + toReset->setChanged(false); + } + // All recipients have been notified, reset the changed flag. + if(changeInfo.currentUpdateCounter <= 1) { + toReset->setChanged(false); + changeInfo.currentUpdateCounter = 0; + } + // Not all recipiens have been notified yet, decrement. + else { + changeInfo.currentUpdateCounter--; + } + return; + } } void LocalDataPoolManager::resetHkUpdateResetHelper() { - if(hkUpdateResetList == nullptr) { - return; - } + if(hkUpdateResetList == nullptr) { + return; + } - for(auto& changeInfo: *hkUpdateResetList) { - changeInfo.currentUpdateCounter = changeInfo.updateCounter; - } + for(auto& changeInfo: *hkUpdateResetList) { + changeInfo.currentUpdateCounter = changeInfo.updateCounter; + } } ReturnValue_t LocalDataPoolManager::subscribeForPeriodicPacket(sid_t sid, - bool enableReporting, float collectionInterval, bool isDiagnostics, - object_id_t packetDestination) { - AcceptsHkPacketsIF* hkReceiverObject = - objectManager->get(packetDestination); - if(hkReceiverObject == nullptr) { - sif::error << "LocalDataPoolManager::subscribeForPeriodicPacket:" - << " Invalid receiver!"<< std::endl; - return HasReturnvaluesIF::RETURN_OK; - } + bool enableReporting, float collectionInterval, bool isDiagnostics, + object_id_t packetDestination) { + AcceptsHkPacketsIF* hkReceiverObject = + objectManager->get(packetDestination); + if(hkReceiverObject == nullptr) { + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "subscribeForPeriodicPacket", QUEUE_OR_DESTINATION_INVALID); + return QUEUE_OR_DESTINATION_INVALID; + } - struct HkReceiver hkReceiver; - hkReceiver.dataId.sid = sid; - hkReceiver.reportingType = ReportingType::PERIODIC; - hkReceiver.dataType = DataType::DATA_SET; - hkReceiver.destinationQueue = hkReceiverObject->getHkQueue(); + struct HkReceiver hkReceiver; + hkReceiver.dataId.sid = sid; + hkReceiver.reportingType = ReportingType::PERIODIC; + hkReceiver.dataType = DataType::DATA_SET; + hkReceiver.destinationQueue = hkReceiverObject->getHkQueue(); - LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid); - if(dataSet != nullptr) { - dataSet->setReportingEnabled(enableReporting); - dataSet->setDiagnostic(isDiagnostics); - dataSet->initializePeriodicHelper(collectionInterval, - owner->getPeriodicOperationFrequency(), isDiagnostics); - } + LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid); + //LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid); + if(dataSet != nullptr) { + LocalPoolDataSetAttorney::setReportingEnabled(*dataSet, enableReporting); + LocalPoolDataSetAttorney::setDiagnostic(*dataSet, isDiagnostics); + LocalPoolDataSetAttorney::initializePeriodicHelper(*dataSet, collectionInterval, + owner->getPeriodicOperationFrequency(), isDiagnostics); + } - hkReceiversMap.push_back(hkReceiver); - return HasReturnvaluesIF::RETURN_OK; + hkReceiversMap.push_back(hkReceiver); + return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t LocalDataPoolManager::subscribeForUpdatePackets(sid_t sid, - bool isDiagnostics, bool reportingEnabled, - object_id_t packetDestination) { - AcceptsHkPacketsIF* hkReceiverObject = - objectManager->get(packetDestination); - if(hkReceiverObject == nullptr) { - sif::error << "LocalDataPoolManager::subscribeForPeriodicPacket:" - << " Invalid receiver!"<< std::endl; - return HasReturnvaluesIF::RETURN_OK; - } + bool isDiagnostics, bool reportingEnabled, + object_id_t packetDestination) { + AcceptsHkPacketsIF* hkReceiverObject = + objectManager->get(packetDestination); + if(hkReceiverObject == nullptr) { + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "subscribeForPeriodicPacket", QUEUE_OR_DESTINATION_INVALID); + return QUEUE_OR_DESTINATION_INVALID; + } - struct HkReceiver hkReceiver; - hkReceiver.dataId.sid = sid; - hkReceiver.reportingType = ReportingType::UPDATE_HK; - hkReceiver.dataType = DataType::DATA_SET; - hkReceiver.destinationQueue = hkReceiverObject->getHkQueue(); + struct HkReceiver hkReceiver; + hkReceiver.dataId.sid = sid; + hkReceiver.reportingType = ReportingType::UPDATE_HK; + hkReceiver.dataType = DataType::DATA_SET; + hkReceiver.destinationQueue = hkReceiverObject->getHkQueue(); - LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid); - if(dataSet != nullptr) { - dataSet->setReportingEnabled(true); - dataSet->setDiagnostic(isDiagnostics); - } + LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid); + //LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid); + if(dataSet != nullptr) { + LocalPoolDataSetAttorney::setReportingEnabled(*dataSet, true); + LocalPoolDataSetAttorney::setDiagnostic(*dataSet, isDiagnostics); + } - hkReceiversMap.push_back(hkReceiver); + hkReceiversMap.push_back(hkReceiver); - handleHkUpdateResetListInsertion(hkReceiver.dataType, hkReceiver.dataId); - return HasReturnvaluesIF::RETURN_OK; + handleHkUpdateResetListInsertion(hkReceiver.dataType, hkReceiver.dataId); + return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t LocalDataPoolManager::subscribeForSetUpdateMessages( - const uint32_t setId, object_id_t destinationObject, - MessageQueueId_t targetQueueId, bool generateSnapshot) { - struct HkReceiver hkReceiver; - hkReceiver.dataType = DataType::DATA_SET; - hkReceiver.dataId.sid = sid_t(this->getOwner()->getObjectId(), setId); - hkReceiver.destinationQueue = targetQueueId; - hkReceiver.objectId = destinationObject; - if(generateSnapshot) { - hkReceiver.reportingType = ReportingType::UPDATE_SNAPSHOT; - } - else { - hkReceiver.reportingType = ReportingType::UPDATE_NOTIFICATION; - } + const uint32_t setId, object_id_t destinationObject, + MessageQueueId_t targetQueueId, bool generateSnapshot) { + struct HkReceiver hkReceiver; + hkReceiver.dataType = DataType::DATA_SET; + hkReceiver.dataId.sid = sid_t(owner->getObjectId(), setId); + hkReceiver.destinationQueue = targetQueueId; + hkReceiver.objectId = destinationObject; + if(generateSnapshot) { + hkReceiver.reportingType = ReportingType::UPDATE_SNAPSHOT; + } + else { + hkReceiver.reportingType = ReportingType::UPDATE_NOTIFICATION; + } - hkReceiversMap.push_back(hkReceiver); + hkReceiversMap.push_back(hkReceiver); - handleHkUpdateResetListInsertion(hkReceiver.dataType, hkReceiver.dataId); - return HasReturnvaluesIF::RETURN_OK; + handleHkUpdateResetListInsertion(hkReceiver.dataType, hkReceiver.dataId); + return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t LocalDataPoolManager::subscribeForVariableUpdateMessages( - const lp_id_t localPoolId, object_id_t destinationObject, - MessageQueueId_t targetQueueId, bool generateSnapshot) { - struct HkReceiver hkReceiver; - hkReceiver.dataType = DataType::LOCAL_POOL_VARIABLE; - hkReceiver.dataId.localPoolId = localPoolId; - hkReceiver.destinationQueue = targetQueueId; - hkReceiver.objectId = destinationObject; - if(generateSnapshot) { - hkReceiver.reportingType = ReportingType::UPDATE_SNAPSHOT; - } - else { - hkReceiver.reportingType = ReportingType::UPDATE_NOTIFICATION; - } + const lp_id_t localPoolId, object_id_t destinationObject, + MessageQueueId_t targetQueueId, bool generateSnapshot) { + struct HkReceiver hkReceiver; + hkReceiver.dataType = DataType::LOCAL_POOL_VARIABLE; + hkReceiver.dataId.localPoolId = localPoolId; + hkReceiver.destinationQueue = targetQueueId; + hkReceiver.objectId = destinationObject; + if(generateSnapshot) { + hkReceiver.reportingType = ReportingType::UPDATE_SNAPSHOT; + } + else { + hkReceiver.reportingType = ReportingType::UPDATE_NOTIFICATION; + } - hkReceiversMap.push_back(hkReceiver); + hkReceiversMap.push_back(hkReceiver); - handleHkUpdateResetListInsertion(hkReceiver.dataType, hkReceiver.dataId); - return HasReturnvaluesIF::RETURN_OK; + handleHkUpdateResetListInsertion(hkReceiver.dataType, hkReceiver.dataId); + return HasReturnvaluesIF::RETURN_OK; } void LocalDataPoolManager::handleHkUpdateResetListInsertion(DataType dataType, - DataId dataId) { - if(hkUpdateResetList == nullptr) { - hkUpdateResetList = new std::vector(); - } + DataId dataId) { + if(hkUpdateResetList == nullptr) { + hkUpdateResetList = new std::vector(); + } - for(auto& updateResetStruct: *hkUpdateResetList) { - if(dataType == DataType::DATA_SET) { - if(updateResetStruct.dataId.sid == dataId.sid) { - updateResetStruct.updateCounter++; - updateResetStruct.currentUpdateCounter++; - return; - } - } - else { - if(updateResetStruct.dataId.localPoolId == dataId.localPoolId) { - updateResetStruct.updateCounter++; - updateResetStruct.currentUpdateCounter++; - return; - } - } + for(auto& updateResetStruct: *hkUpdateResetList) { + if(dataType == DataType::DATA_SET) { + if(updateResetStruct.dataId.sid == dataId.sid) { + updateResetStruct.updateCounter++; + updateResetStruct.currentUpdateCounter++; + return; + } + } + else { + if(updateResetStruct.dataId.localPoolId == dataId.localPoolId) { + updateResetStruct.updateCounter++; + updateResetStruct.currentUpdateCounter++; + return; + } + } - } - HkUpdateResetHelper hkUpdateResetHelper; - hkUpdateResetHelper.currentUpdateCounter = 1; - hkUpdateResetHelper.updateCounter = 1; - hkUpdateResetHelper.dataType = dataType; - if(dataType == DataType::DATA_SET) { - hkUpdateResetHelper.dataId.sid = dataId.sid; - } - else { - hkUpdateResetHelper.dataId.localPoolId = dataId.localPoolId; - } - hkUpdateResetList->push_back(hkUpdateResetHelper); + } + HkUpdateResetHelper hkUpdateResetHelper; + hkUpdateResetHelper.currentUpdateCounter = 1; + hkUpdateResetHelper.updateCounter = 1; + hkUpdateResetHelper.dataType = dataType; + if(dataType == DataType::DATA_SET) { + hkUpdateResetHelper.dataId.sid = dataId.sid; + } + else { + hkUpdateResetHelper.dataId.localPoolId = dataId.localPoolId; + } + hkUpdateResetList->push_back(hkUpdateResetHelper); } ReturnValue_t LocalDataPoolManager::handleHousekeepingMessage( - CommandMessage* message) { - Command_t command = message->getCommand(); - sid_t sid = HousekeepingMessage::getSid(message); - ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; - switch(command) { - // Houskeeping interface handling. - case(HousekeepingMessage::ENABLE_PERIODIC_DIAGNOSTICS_GENERATION): { - result = togglePeriodicGeneration(sid, true, true); - break; - } + CommandMessage* message) { + Command_t command = message->getCommand(); + sid_t sid = HousekeepingMessage::getSid(message); + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + switch(command) { + // Houskeeping interface handling. + case(HousekeepingMessage::ENABLE_PERIODIC_DIAGNOSTICS_GENERATION): { + result = togglePeriodicGeneration(sid, true, true); + break; + } - case(HousekeepingMessage::DISABLE_PERIODIC_DIAGNOSTICS_GENERATION): { - result = togglePeriodicGeneration(sid, false, true); - break; - } + case(HousekeepingMessage::DISABLE_PERIODIC_DIAGNOSTICS_GENERATION): { + result = togglePeriodicGeneration(sid, false, true); + break; + } - case(HousekeepingMessage::ENABLE_PERIODIC_HK_REPORT_GENERATION): { - result = togglePeriodicGeneration(sid, true, false); - break; - } + case(HousekeepingMessage::ENABLE_PERIODIC_HK_REPORT_GENERATION): { + result = togglePeriodicGeneration(sid, true, false); + break; + } - case(HousekeepingMessage::DISABLE_PERIODIC_HK_REPORT_GENERATION): { - result = togglePeriodicGeneration(sid, false, false); - break; - } + case(HousekeepingMessage::DISABLE_PERIODIC_HK_REPORT_GENERATION): { + result = togglePeriodicGeneration(sid, false, false); + break; + } - case(HousekeepingMessage::REPORT_DIAGNOSTICS_REPORT_STRUCTURES): - return generateSetStructurePacket(sid, true); - case(HousekeepingMessage::REPORT_HK_REPORT_STRUCTURES): - return generateSetStructurePacket(sid, false); - case(HousekeepingMessage::MODIFY_DIAGNOSTICS_REPORT_COLLECTION_INTERVAL): - case(HousekeepingMessage::MODIFY_PARAMETER_REPORT_COLLECTION_INTERVAL): { - float newCollIntvl = 0; - HousekeepingMessage::getCollectionIntervalModificationCommand(message, - &newCollIntvl); - if(command == HousekeepingMessage:: - MODIFY_DIAGNOSTICS_REPORT_COLLECTION_INTERVAL) { - result = changeCollectionInterval(sid, newCollIntvl, true); - } - else { - result = changeCollectionInterval(sid, newCollIntvl, false); - } - break; - } + case(HousekeepingMessage::REPORT_DIAGNOSTICS_REPORT_STRUCTURES): { + return generateSetStructurePacket(sid, true); + } - case(HousekeepingMessage::GENERATE_ONE_PARAMETER_REPORT): - case(HousekeepingMessage::GENERATE_ONE_DIAGNOSTICS_REPORT): { - LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid); - if(command == HousekeepingMessage::GENERATE_ONE_PARAMETER_REPORT - and dataSet->isDiagnostics()) { - return WRONG_HK_PACKET_TYPE; - } - else if(command == HousekeepingMessage::GENERATE_ONE_DIAGNOSTICS_REPORT - and not dataSet->isDiagnostics()) { - return WRONG_HK_PACKET_TYPE; - } - return generateHousekeepingPacket(HousekeepingMessage::getSid(message), - dataSet, true); - } + case(HousekeepingMessage::REPORT_HK_REPORT_STRUCTURES): { + return generateSetStructurePacket(sid, false); + } + case(HousekeepingMessage::MODIFY_DIAGNOSTICS_REPORT_COLLECTION_INTERVAL): + case(HousekeepingMessage::MODIFY_PARAMETER_REPORT_COLLECTION_INTERVAL): { + float newCollIntvl = 0; + HousekeepingMessage::getCollectionIntervalModificationCommand(message, + &newCollIntvl); + if(command == HousekeepingMessage:: + MODIFY_DIAGNOSTICS_REPORT_COLLECTION_INTERVAL) { + result = changeCollectionInterval(sid, newCollIntvl, true); + } + else { + result = changeCollectionInterval(sid, newCollIntvl, false); + } + break; + } - // Notification handling. - case(HousekeepingMessage::UPDATE_NOTIFICATION_SET): { - owner->handleChangedDataset(sid); - return HasReturnvaluesIF::RETURN_OK; - } - case(HousekeepingMessage::UPDATE_NOTIFICATION_VARIABLE): { - lp_id_t locPoolId = HousekeepingMessage:: - getUpdateNotificationVariableCommand(message); - owner->handleChangedPoolVariable(locPoolId); - return HasReturnvaluesIF::RETURN_OK; - } - case(HousekeepingMessage::UPDATE_SNAPSHOT_SET): { - store_address_t storeId; - HousekeepingMessage::getUpdateSnapshotSetCommand(message, &storeId); - owner->handleChangedDataset(sid, storeId); - return HasReturnvaluesIF::RETURN_OK; - } - case(HousekeepingMessage::UPDATE_SNAPSHOT_VARIABLE): { - store_address_t storeId; - lp_id_t localPoolId = HousekeepingMessage:: - getUpdateSnapshotVariableCommand(message, &storeId); - owner->handleChangedPoolVariable(localPoolId, storeId); - return HasReturnvaluesIF::RETURN_OK; - } + case(HousekeepingMessage::GENERATE_ONE_PARAMETER_REPORT): + case(HousekeepingMessage::GENERATE_ONE_DIAGNOSTICS_REPORT): { + LocalPoolDataSetBase* dataSet =HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid); + //LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid); + if(command == HousekeepingMessage::GENERATE_ONE_PARAMETER_REPORT + and LocalPoolDataSetAttorney::isDiagnostics(*dataSet)) { + return WRONG_HK_PACKET_TYPE; + } + else if(command == HousekeepingMessage::GENERATE_ONE_DIAGNOSTICS_REPORT + and not LocalPoolDataSetAttorney::isDiagnostics(*dataSet)) { + return WRONG_HK_PACKET_TYPE; + } + return generateHousekeepingPacket(HousekeepingMessage::getSid(message), + dataSet, true); + } - default: - return CommandMessageIF::UNKNOWN_COMMAND; - } + // Notification handling. + case(HousekeepingMessage::UPDATE_NOTIFICATION_SET): { + owner->handleChangedDataset(sid); + return HasReturnvaluesIF::RETURN_OK; + } + case(HousekeepingMessage::UPDATE_NOTIFICATION_VARIABLE): { + lp_id_t locPoolId = HousekeepingMessage:: + getUpdateNotificationVariableCommand(message); + owner->handleChangedPoolVariable(locPoolId); + return HasReturnvaluesIF::RETURN_OK; + } + case(HousekeepingMessage::UPDATE_SNAPSHOT_SET): { + store_address_t storeId; + HousekeepingMessage::getUpdateSnapshotSetCommand(message, &storeId); + owner->handleChangedDataset(sid, storeId); + return HasReturnvaluesIF::RETURN_OK; + } + case(HousekeepingMessage::UPDATE_SNAPSHOT_VARIABLE): { + store_address_t storeId; + lp_id_t localPoolId = HousekeepingMessage:: + getUpdateSnapshotVariableCommand(message, &storeId); + owner->handleChangedPoolVariable(localPoolId, storeId); + return HasReturnvaluesIF::RETURN_OK; + } - CommandMessage reply; - if(result != HasReturnvaluesIF::RETURN_OK) { - HousekeepingMessage::setHkRequestFailureReply(&reply, sid, result); - } - else { - HousekeepingMessage::setHkRequestSuccessReply(&reply, sid); - } - hkQueue->sendMessage(hkDestinationId, &reply); - return result; + default: + return CommandMessageIF::UNKNOWN_COMMAND; + } + + CommandMessage reply; + if(result != HasReturnvaluesIF::RETURN_OK) { + HousekeepingMessage::setHkRequestFailureReply(&reply, sid, result); + } + else { + HousekeepingMessage::setHkRequestSuccessReply(&reply, sid); + } + hkQueue->sendMessage(hkDestinationId, &reply); + return result; } ReturnValue_t LocalDataPoolManager::printPoolEntry( - lp_id_t localPoolId) { - auto poolIter = localPoolMap.find(localPoolId); - if (poolIter == localPoolMap.end()) { - sif::debug << "HousekeepingManager::fechPoolEntry:" - << " Pool entry not found." << std::endl; - return POOL_ENTRY_NOT_FOUND; - } - poolIter->second->print(); - return HasReturnvaluesIF::RETURN_OK; + lp_id_t localPoolId) { + auto poolIter = localPoolMap.find(localPoolId); + if (poolIter == localPoolMap.end()) { + printWarningOrError(sif::OutputTypes::OUT_WARNING, "printPoolEntry", + localpool::POOL_ENTRY_NOT_FOUND); + return localpool::POOL_ENTRY_NOT_FOUND; + } + poolIter->second->print(); + return HasReturnvaluesIF::RETURN_OK; } MutexIF* LocalDataPoolManager::getMutexHandle() { - return mutex; + return mutex; } HasLocalDataPoolIF* LocalDataPoolManager::getOwner() { - return owner; + return owner; } ReturnValue_t LocalDataPoolManager::generateHousekeepingPacket(sid_t sid, - LocalPoolDataSetBase* dataSet, bool forDownlink, - MessageQueueId_t destination) { - if(dataSet == nullptr) { - // Configuration error. - sif::warning << "HousekeepingManager::generateHousekeepingPacket:" - << " Set ID not found or dataset not assigned!" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } + LocalPoolDataSetBase* dataSet, bool forDownlink, + MessageQueueId_t destination) { + if(dataSet == nullptr) { + // Configuration error. + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "generateHousekeepingPacket", + DATASET_NOT_FOUND); + return DATASET_NOT_FOUND; + } - store_address_t storeId; - HousekeepingPacketDownlink hkPacket(sid, dataSet); - size_t serializedSize = 0; - ReturnValue_t result = serializeHkPacketIntoStore(hkPacket, storeId, - forDownlink, &serializedSize); - if(result != HasReturnvaluesIF::RETURN_OK or serializedSize == 0) { - return result; - } + store_address_t storeId; + HousekeepingPacketDownlink hkPacket(sid, dataSet); + size_t serializedSize = 0; + ReturnValue_t result = serializeHkPacketIntoStore(hkPacket, storeId, + forDownlink, &serializedSize); + if(result != HasReturnvaluesIF::RETURN_OK or serializedSize == 0) { + return result; + } - // and now we set a HK message and send it the HK packet destination. - CommandMessage hkMessage; - if(dataSet->isDiagnostics()) { - HousekeepingMessage::setHkDiagnosticsReply(&hkMessage, sid, storeId); - } - else { - HousekeepingMessage::setHkReportReply(&hkMessage, sid, storeId); - } + // and now we set a HK message and send it the HK packet destination. + CommandMessage hkMessage; + if(LocalPoolDataSetAttorney::isDiagnostics(*dataSet)) { + HousekeepingMessage::setHkDiagnosticsReply(&hkMessage, sid, storeId); + } + else { + HousekeepingMessage::setHkReportReply(&hkMessage, sid, storeId); + } - if(hkQueue == nullptr) { - return QUEUE_OR_DESTINATION_NOT_SET; - } - if(destination == MessageQueueIF::NO_QUEUE) { - if(hkDestinationId == MessageQueueIF::NO_QUEUE) { - // error, all destinations invalid - return HasReturnvaluesIF::RETURN_FAILED; - } - destination = hkDestinationId; - } + if(hkQueue == nullptr) { + // error, no queue available to send packet with. + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "generateHousekeepingPacket", + QUEUE_OR_DESTINATION_INVALID); + return QUEUE_OR_DESTINATION_INVALID; + } + if(destination == MessageQueueIF::NO_QUEUE) { + if(hkDestinationId == MessageQueueIF::NO_QUEUE) { + // error, all destinations invalid + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "generateHousekeepingPacket", + QUEUE_OR_DESTINATION_INVALID); + } + destination = hkDestinationId; + } - return hkQueue->sendMessage(destination, &hkMessage); + return hkQueue->sendMessage(destination, &hkMessage); } ReturnValue_t LocalDataPoolManager::serializeHkPacketIntoStore( - HousekeepingPacketDownlink& hkPacket, - store_address_t& storeId, bool forDownlink, - size_t* serializedSize) { - uint8_t* dataPtr = nullptr; - const size_t maxSize = hkPacket.getSerializedSize(); - ReturnValue_t result = ipcStore->getFreeElement(&storeId, - maxSize, &dataPtr); - if(result != HasReturnvaluesIF::RETURN_OK) { - return result; - } + HousekeepingPacketDownlink& hkPacket, + store_address_t& storeId, bool forDownlink, + size_t* serializedSize) { + uint8_t* dataPtr = nullptr; + const size_t maxSize = hkPacket.getSerializedSize(); + ReturnValue_t result = ipcStore->getFreeElement(&storeId, + maxSize, &dataPtr); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } - if(forDownlink) { - return hkPacket.serialize(&dataPtr, serializedSize, maxSize, - SerializeIF::Endianness::BIG); - } - return hkPacket.serialize(&dataPtr, serializedSize, maxSize, - SerializeIF::Endianness::MACHINE); + if(forDownlink) { + return hkPacket.serialize(&dataPtr, serializedSize, maxSize, + SerializeIF::Endianness::BIG); + } + return hkPacket.serialize(&dataPtr, serializedSize, maxSize, + SerializeIF::Endianness::MACHINE); } void LocalDataPoolManager::setNonDiagnosticIntervalFactor( - uint8_t nonDiagInvlFactor) { - this->nonDiagnosticIntervalFactor = nonDiagInvlFactor; + uint8_t nonDiagInvlFactor) { + this->nonDiagnosticIntervalFactor = nonDiagInvlFactor; } void LocalDataPoolManager::performPeriodicHkGeneration(HkReceiver& receiver) { - sid_t sid = receiver.dataId.sid; - LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid); - if(not dataSet->getReportingEnabled()) { - return; - } + sid_t sid = receiver.dataId.sid; + //LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid); + LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid); + if(dataSet == nullptr) { + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "performPeriodicHkGeneration", + DATASET_NOT_FOUND); + return; + } - if(dataSet->periodicHelper == nullptr) { - // Configuration error. - return; - } + if(not LocalPoolDataSetAttorney::getReportingEnabled(*dataSet)) { + return; + } - if(not dataSet->periodicHelper->checkOpNecessary()) { - return; - } + PeriodicHousekeepingHelper* periodicHelper = + LocalPoolDataSetAttorney::getPeriodicHelper(*dataSet); - ReturnValue_t result = generateHousekeepingPacket( - sid, dataSet, true); - if(result != HasReturnvaluesIF::RETURN_OK) { - // configuration error - sif::debug << "LocalDataPoolManager::performHkOperation:" - << "0x" << std::hex << std::setfill('0') << std::setw(8) - << owner->getObjectId() << " Error generating " - << "HK packet" << std::setfill(' ') << std::dec << std::endl; - } + if(periodicHelper == nullptr) { + // Configuration error. + return; + } + + if(periodicHelper->checkOpNecessary()) { + return; + } + + ReturnValue_t result = generateHousekeepingPacket( + sid, dataSet, true); + if(result != HasReturnvaluesIF::RETURN_OK) { + // configuration error +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "LocalDataPoolManager::performHkOperation: " + << "HK generation failed." << std::endl; +#else + sif::printWarning("LocalDataPoolManager::performHkOperation: " + "HK generation failed.\n"); +#endif + } } ReturnValue_t LocalDataPoolManager::togglePeriodicGeneration(sid_t sid, - bool enable, bool isDiagnostics) { - LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid); - if((dataSet->isDiagnostics() and not isDiagnostics) or - (not dataSet->isDiagnostics() and isDiagnostics)) { - return WRONG_HK_PACKET_TYPE; - } + bool enable, bool isDiagnostics) { + //LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid); + LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid); + if((LocalPoolDataSetAttorney::isDiagnostics(*dataSet) and not isDiagnostics) or + (not LocalPoolDataSetAttorney::isDiagnostics(*dataSet) and isDiagnostics)) { + return WRONG_HK_PACKET_TYPE; + } - if((dataSet->getReportingEnabled() and enable) or - (not dataSet->getReportingEnabled() and not enable)) { - return REPORTING_STATUS_UNCHANGED; - } + if((LocalPoolDataSetAttorney::getReportingEnabled(*dataSet) and enable) or + (not LocalPoolDataSetAttorney::getReportingEnabled(*dataSet) and not enable)) { + return REPORTING_STATUS_UNCHANGED; + } - dataSet->setReportingEnabled(enable); - return HasReturnvaluesIF::RETURN_OK; + LocalPoolDataSetAttorney::setReportingEnabled(*dataSet, enable); + return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t LocalDataPoolManager::changeCollectionInterval(sid_t sid, - float newCollectionInterval, bool isDiagnostics) { - LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid); - bool targetIsDiagnostics = dataSet->isDiagnostics(); - if((targetIsDiagnostics and not isDiagnostics) or - (not targetIsDiagnostics and isDiagnostics)) { - return WRONG_HK_PACKET_TYPE; - } + float newCollectionInterval, bool isDiagnostics) { + //LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid); + LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid); + bool targetIsDiagnostics = LocalPoolDataSetAttorney::isDiagnostics(*dataSet); + if((targetIsDiagnostics and not isDiagnostics) or + (not targetIsDiagnostics and isDiagnostics)) { + return WRONG_HK_PACKET_TYPE; + } - if(dataSet->periodicHelper == nullptr) { - // config error - return PERIODIC_HELPER_INVALID; - } + PeriodicHousekeepingHelper* periodicHelper = + LocalPoolDataSetAttorney::getPeriodicHelper(*dataSet); - dataSet->periodicHelper->changeCollectionInterval(newCollectionInterval); - return HasReturnvaluesIF::RETURN_OK; + if(periodicHelper == nullptr) { + // config error + return PERIODIC_HELPER_INVALID; + } + + periodicHelper->changeCollectionInterval(newCollectionInterval); + return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t LocalDataPoolManager::generateSetStructurePacket(sid_t sid, - bool isDiagnostics) { - // Get and check dataset first. - LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid); - if(dataSet == nullptr) { - sif::warning << "HousekeepingManager::generateHousekeepingPacket:" - << " Set ID not found" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } + bool isDiagnostics) { + // Get and check dataset first. + //LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid); + LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid); + if(dataSet == nullptr) { + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "performPeriodicHkGeneration", + DATASET_NOT_FOUND); + return DATASET_NOT_FOUND; + } - bool targetIsDiagnostics = dataSet->isDiagnostics(); - if((targetIsDiagnostics and not isDiagnostics) or - (not targetIsDiagnostics and isDiagnostics)) { - return WRONG_HK_PACKET_TYPE; - } + bool targetIsDiagnostics = LocalPoolDataSetAttorney::isDiagnostics(*dataSet); + if((targetIsDiagnostics and not isDiagnostics) or + (not targetIsDiagnostics and isDiagnostics)) { + return WRONG_HK_PACKET_TYPE; + } - bool valid = dataSet->isValid(); - bool reportingEnabled = dataSet->getReportingEnabled(); - float collectionInterval = - dataSet->periodicHelper->getCollectionIntervalInSeconds(); + bool valid = dataSet->isValid(); + bool reportingEnabled = LocalPoolDataSetAttorney::getReportingEnabled(*dataSet); + float collectionInterval = LocalPoolDataSetAttorney::getPeriodicHelper(*dataSet)-> + getCollectionIntervalInSeconds(); - // Generate set packet which can be serialized. - HousekeepingSetPacket setPacket(sid, - reportingEnabled, valid, collectionInterval, dataSet); - size_t expectedSize = setPacket.getSerializedSize(); - uint8_t* storePtr = nullptr; - store_address_t storeId; - ReturnValue_t result = ipcStore->getFreeElement(&storeId, - expectedSize,&storePtr); - if(result != HasReturnvaluesIF::RETURN_OK) { - sif::error << "HousekeepingManager::generateHousekeepingPacket: " - << "Could not get free element from IPC store." << std::endl; - return result; - } + // Generate set packet which can be serialized. + HousekeepingSetPacket setPacket(sid, + reportingEnabled, valid, collectionInterval, dataSet); + size_t expectedSize = setPacket.getSerializedSize(); + uint8_t* storePtr = nullptr; + store_address_t storeId; + ReturnValue_t result = ipcStore->getFreeElement(&storeId, + expectedSize,&storePtr); + if(result != HasReturnvaluesIF::RETURN_OK) { + printWarningOrError(sif::OutputTypes::OUT_ERROR, + "generateSetStructurePacket", HasReturnvaluesIF::RETURN_FAILED, + "Could not get free element from IPC store."); + return result; + } - // Serialize set packet into store. - size_t size = 0; - result = setPacket.serialize(&storePtr, &size, expectedSize, - SerializeIF::Endianness::BIG); - if(expectedSize != size) { - sif::error << "HousekeepingManager::generateSetStructurePacket: " - << "Expected size is not equal to serialized size" << std::endl; - } + // Serialize set packet into store. + size_t size = 0; + result = setPacket.serialize(&storePtr, &size, expectedSize, + SerializeIF::Endianness::BIG); + if(expectedSize != size) { + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "generateSetStructurePacket", HasReturnvaluesIF::RETURN_FAILED, + "Expected size is not equal to serialized size"); + } - // Send structure reporting reply. - CommandMessage reply; - if(isDiagnostics) { - HousekeepingMessage::setDiagnosticsStuctureReportReply(&reply, - sid, storeId); - } - else { - HousekeepingMessage::setHkStuctureReportReply(&reply, - sid, storeId); - } + // Send structure reporting reply. + CommandMessage reply; + if(isDiagnostics) { + HousekeepingMessage::setDiagnosticsStuctureReportReply(&reply, + sid, storeId); + } + else { + HousekeepingMessage::setHkStuctureReportReply(&reply, + sid, storeId); + } - hkQueue->reply(&reply); - return result; + hkQueue->reply(&reply); + return result; +} + +void LocalDataPoolManager::clearReceiversList() { + // clear the vector completely and releases allocated memory. + HkReceivers().swap(hkReceiversMap); +} + +MutexIF* LocalDataPoolManager::getLocalPoolMutex() { + return this->mutex; +} + +object_id_t LocalDataPoolManager::getCreatorObjectId() const { + return owner->getObjectId(); + //return owner->getObjectId(); +} + +void LocalDataPoolManager::printWarningOrError(sif::OutputTypes outputType, + const char* functionName, ReturnValue_t error, const char* errorPrint) { + if(errorPrint == nullptr) { + if(error == DATASET_NOT_FOUND) { + errorPrint = "Dataset not found"; + } + else if(error == POOLOBJECT_NOT_FOUND) { + errorPrint = "Pool Object not found"; + } + else if(error == HasReturnvaluesIF::RETURN_FAILED) { + if(outputType == sif::OutputTypes::OUT_WARNING) { + errorPrint = "Generic Warning"; + } + else { + errorPrint = "Generic error"; + } + } + else if(error == QUEUE_OR_DESTINATION_INVALID) { + errorPrint = "Queue or destination not set"; + } + else if(error == localpool::POOL_ENTRY_TYPE_CONFLICT) { + errorPrint = "Pool entry type conflict"; + } + else if(error == localpool::POOL_ENTRY_NOT_FOUND) { + errorPrint = "Pool entry not found"; + } + else { + errorPrint = "Unknown error"; + } + } + + if(outputType == sif::OutputTypes::OUT_WARNING) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "LocalDataPoolManager::" << functionName + << ": Object ID " << std::setw(8) << std::setfill('0') + << std::hex << owner->getObjectId() << " | " << errorPrint + << std::dec << std::setfill(' ') << std::endl; +#else + sif::printWarning("LocalDataPoolManager::%s: Object ID 0x%08x | %s\n", + owner->getObjectId(), errorPrint); +#endif + } + else if(outputType == sif::OutputTypes::OUT_ERROR) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "LocalDataPoolManager::" << functionName + << ": Object ID " << std::setw(8) << std::setfill('0') + << std::hex << owner->getObjectId() << " | " << errorPrint + << std::dec << std::setfill(' ') << std::endl; +#else + sif::printError("LocalDataPoolManager::%s: Object ID 0x%08x | %s\n", + owner->getObjectId(), errorPrint); +#endif + } +} + +LocalDataPoolManager* LocalDataPoolManager::getHkManagerHandle() { + return this; } diff --git a/datapoollocal/LocalDataPoolManager.h b/datapoollocal/LocalDataPoolManager.h index c4024cf9..580ac8b9 100644 --- a/datapoollocal/LocalDataPoolManager.h +++ b/datapoollocal/LocalDataPoolManager.h @@ -1,8 +1,10 @@ #ifndef 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/HousekeepingMessage.h" #include "../housekeeping/PeriodicHousekeepingHelper.h" @@ -15,6 +17,7 @@ #include "../ipc/MutexHelper.h" #include +#include namespace Factory { void setStaticFrameworkObjectIds(); @@ -22,6 +25,8 @@ void setStaticFrameworkObjectIds(); class LocalPoolDataSetBase; class HousekeepingPacketUpdate; +class HasLocalDataPoolIF; +class LocalDataPool; /** * @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. * @author R. Mueller */ -class LocalDataPoolManager { - template friend class LocalPoolVariable; - template friend class LocalPoolVector; - friend class LocalPoolDataSetBase; +class LocalDataPoolManager: public ProvidesDataPoolSubscriptionIF, + public AccessPoolManagerIF { friend void (Factory::setStaticFrameworkObjectIds)(); + //! Some classes using the pool manager directly need to access class internals of the + //! manager. The attorney provides granular control of access to these internals. + friend class LocalDpManagerAttorney; public: static constexpr uint8_t INTERFACE_ID = CLASS_ID::HOUSEKEEPING_MANAGER; - static constexpr ReturnValue_t POOL_ENTRY_NOT_FOUND = MAKE_RETURN_CODE(0x00); - static constexpr ReturnValue_t POOL_ENTRY_TYPE_CONFLICT = MAKE_RETURN_CODE(0x01); + static constexpr ReturnValue_t QUEUE_OR_DESTINATION_INVALID = MAKE_RETURN_CODE(0); - 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 @@ -119,7 +125,7 @@ public: */ ReturnValue_t subscribeForPeriodicPacket(sid_t sid, bool enableReporting, 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 @@ -133,7 +139,7 @@ public: */ ReturnValue_t subscribeForUpdatePackets(sid_t sid, bool reportingEnabled, bool isDiagnostics, - object_id_t packetDestination = defaultHkDestination); + object_id_t packetDestination = defaultHkDestination) override; /** * @brief Subscribe for a notification message which will be sent @@ -152,7 +158,7 @@ public: ReturnValue_t subscribeForSetUpdateMessages(const uint32_t setId, object_id_t destinationObject, MessageQueueId_t targetQueueId, - bool generateSnapshot); + bool generateSnapshot) override; /** * @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, object_id_t destinationObject, MessageQueueId_t targetQueueId, - bool generateSnapshot); + bool generateSnapshot) override; + + MutexIF* getLocalPoolMutex() override; /** * Non-Diagnostics packets usually have a lower minimum sampling frequency @@ -250,8 +258,18 @@ public: LocalDataPoolManager(const LocalDataPoolManager &) = delete; LocalDataPoolManager operator=(const LocalDataPoolManager&) = delete; + /** + * This function can be used to clear the receivers list. This is + * intended for test functions and not for regular operations, because + * the insertion operations allocate dynamically. + */ + void clearReceiversList(); + + object_id_t getCreatorObjectId() const; + + virtual LocalDataPoolManager* getHkManagerHandle() override; private: - LocalDataPool localPoolMap; + localpool::DataPool localPoolMap; //! Every housekeeping data manager has a mutex to protect access //! to it's data pool. MutexIF* mutex = nullptr; @@ -370,6 +388,11 @@ private: ReturnValue_t& status); ReturnValue_t addUpdateToStore(HousekeepingPacketUpdate& updatePacket, 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 **poolEntry) { auto poolIter = localPoolMap.find(localPoolId); if (poolIter == localPoolMap.end()) { - sif::warning << "HousekeepingManager::fechPoolEntry: Pool entry " - "not found." << std::endl; - return POOL_ENTRY_NOT_FOUND; + printWarningOrError(sif::OutputTypes::OUT_ERROR, "fetchPoolEntry", + localpool::POOL_ENTRY_NOT_FOUND); + return localpool::POOL_ENTRY_NOT_FOUND; } *poolEntry = dynamic_cast< PoolEntry* >(poolIter->second); if(*poolEntry == nullptr) { - sif::debug << "HousekeepingManager::fetchPoolEntry:" - " Pool entry not found." << std::endl; - return POOL_ENTRY_TYPE_CONFLICT; + printWarningOrError(sif::OutputTypes::OUT_ERROR, "fetchPoolEntry", + localpool::POOL_ENTRY_TYPE_CONFLICT); + return localpool::POOL_ENTRY_TYPE_CONFLICT; } return HasReturnvaluesIF::RETURN_OK; } diff --git a/datapoollocal/LocalDataSet.cpp b/datapoollocal/LocalDataSet.cpp index 394a9abe..aeb5c6b3 100644 --- a/datapoollocal/LocalDataSet.cpp +++ b/datapoollocal/LocalDataSet.cpp @@ -9,13 +9,13 @@ LocalDataSet::LocalDataSet(HasLocalDataPoolIF *hkOwner, uint32_t setId, const size_t maxNumberOfVariables): LocalPoolDataSetBase(hkOwner, setId, nullptr, maxNumberOfVariables), poolVarList(maxNumberOfVariables) { - this->setContainer(poolVarList.data()); + this->setContainer(poolVarList.data()); } LocalDataSet::LocalDataSet(sid_t sid, const size_t maxNumberOfVariables): LocalPoolDataSetBase(sid, nullptr, maxNumberOfVariables), - poolVarList(maxNumberOfVariables) { - this->setContainer(poolVarList.data()); + poolVarList(maxNumberOfVariables) { + this->setContainer(poolVarList.data()); } LocalDataSet::~LocalDataSet() {} diff --git a/datapoollocal/LocalDataSet.h b/datapoollocal/LocalDataSet.h index 0368f26d..b7f8f90f 100644 --- a/datapoollocal/LocalDataSet.h +++ b/datapoollocal/LocalDataSet.h @@ -7,7 +7,7 @@ class LocalDataSet: public LocalPoolDataSetBase { public: LocalDataSet(HasLocalDataPoolIF* hkOwner, uint32_t setId, - const size_t maxSize); + const size_t maxSize); LocalDataSet(sid_t sid, const size_t maxSize); virtual~ LocalDataSet(); diff --git a/datapoollocal/LocalPoolDataSetBase.cpp b/datapoollocal/LocalPoolDataSetBase.cpp index 640956db..4dae757e 100644 --- a/datapoollocal/LocalPoolDataSetBase.cpp +++ b/datapoollocal/LocalPoolDataSetBase.cpp @@ -1,4 +1,8 @@ #include "LocalPoolDataSetBase.h" +#include "HasLocalDataPoolIF.h" +#include "internal/HasLocalDpIFUserAttorney.h" + +#include "../serviceinterface/ServiceInterface.h" #include "../datapoollocal/LocalDataPoolManager.h" #include "../housekeeping/PeriodicHousekeepingHelper.h" #include "../serialize/SerializeAdapter.h" @@ -8,22 +12,31 @@ LocalPoolDataSetBase::LocalPoolDataSetBase(HasLocalDataPoolIF *hkOwner, uint32_t setId, PoolVariableIF** registeredVariablesArray, - const size_t maxNumberOfVariables, bool noPeriodicHandling): + const size_t maxNumberOfVariables, bool periodicHandling): PoolDataSetBase(registeredVariablesArray, maxNumberOfVariables) { if(hkOwner == nullptr) { // Configuration error. +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "LocalPoolDataSetBase::LocalPoolDataSetBase: Owner " << "invalid!" << std::endl; +#else + sif::printError("LocalPoolDataSetBase::LocalPoolDataSetBase: Owner " + "invalid!\n\r"); +#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ return; } - hkManager = hkOwner->getHkManagerHandle(); + AccessPoolManagerIF* accessor = HasLocalDpIFUserAttorney::getAccessorHandle(hkOwner); + + if(accessor != nullptr) { + poolManager = accessor->getHkManagerHandle(); + mutexIfSingleDataCreator = accessor->getLocalPoolMutex(); + } + this->sid.objectId = hkOwner->getObjectId(); this->sid.ownerSetId = setId; - mutex = MutexFactory::instance()->createMutex(); - // Data creators get a periodic helper for periodic HK data generation. - if(not noPeriodicHandling) { + if(periodicHandling) { periodicHelper = new PeriodicHousekeepingHelper(this); } } @@ -31,27 +44,40 @@ LocalPoolDataSetBase::LocalPoolDataSetBase(HasLocalDataPoolIF *hkOwner, LocalPoolDataSetBase::LocalPoolDataSetBase(sid_t sid, PoolVariableIF** registeredVariablesArray, const size_t maxNumberOfVariables): - PoolDataSetBase(registeredVariablesArray, maxNumberOfVariables) { + PoolDataSetBase(registeredVariablesArray, maxNumberOfVariables) { HasLocalDataPoolIF* hkOwner = objectManager->get( sid.objectId); - if(hkOwner == nullptr) { - // Configuration error. - sif::error << "LocalPoolDataSetBase::LocalPoolDataSetBase: Owner " - << "invalid!" << std::endl; - return; + if(hkOwner != nullptr) { + AccessPoolManagerIF* accessor = HasLocalDpIFUserAttorney::getAccessorHandle(hkOwner); + if(accessor != nullptr) { + mutexIfSingleDataCreator = accessor->getLocalPoolMutex(); + } } - 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() { + if(periodicHelper != nullptr) { + delete periodicHelper; + } } -ReturnValue_t LocalPoolDataSetBase::lockDataPool(uint32_t timeoutMs) { - MutexIF* mutex = hkManager->getMutexHandle(); - return mutex->lockMutex(MutexIF::TimeoutType::WAITING, timeoutMs); +ReturnValue_t LocalPoolDataSetBase::lockDataPool( + MutexIF::TimeoutType timeoutType, + uint32_t timeoutMs) { + if(mutexIfSingleDataCreator != nullptr) { + return mutexIfSingleDataCreator->lockMutex(timeoutType, timeoutMs); + } + return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t LocalPoolDataSetBase::serializeWithValidityBuffer(uint8_t **buffer, @@ -127,8 +153,10 @@ ReturnValue_t LocalPoolDataSetBase::deSerializeWithValidityBuffer( } ReturnValue_t LocalPoolDataSetBase::unlockDataPool() { - MutexIF* mutex = hkManager->getMutexHandle(); - return mutex->unlockMutex(); + if(mutexIfSingleDataCreator != nullptr) { + return mutexIfSingleDataCreator->unlockMutex(); + } + return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t LocalPoolDataSetBase::serializeLocalPoolIds(uint8_t** buffer, @@ -145,8 +173,13 @@ ReturnValue_t LocalPoolDataSetBase::serializeLocalPoolIds(uint8_t** buffer, auto result = SerializeAdapter::serialize(¤tPoolId, buffer, size, maxSize, streamEndianness); if(result != HasReturnvaluesIF::RETURN_OK) { - sif::warning << "LocalDataSet::serializeLocalPoolIds: Serialization" - " error!" << std::endl; +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "LocalPoolDataSetBase::serializeLocalPoolIds: " + << "Serialization error!" << std::endl; +#else + sif::printWarning("LocalPoolDataSetBase::serializeLocalPoolIds: " + "Serialization error!\n\r"); +#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ return result; } } @@ -204,8 +237,13 @@ ReturnValue_t LocalPoolDataSetBase::serialize(uint8_t **buffer, size_t *size, void LocalPoolDataSetBase::bitSetter(uint8_t* byte, uint8_t position) const { 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; +#else + sif::printWarning("LocalPoolDataSetBase::bitSetter: " + "Invalid position!\n\r"); +#endif return; } uint8_t shiftNumber = position + (7 - 2 * position); @@ -236,14 +274,10 @@ void LocalPoolDataSetBase::initializePeriodicHelper( } void LocalPoolDataSetBase::setChanged(bool changed) { - // TODO: Make this configurable? - MutexHelper(mutex, MutexIF::TimeoutType::WAITING, 20); this->changed = changed; } bool LocalPoolDataSetBase::hasChanged() const { - // TODO: Make this configurable? - MutexHelper(mutex, MutexIF::TimeoutType::WAITING, 20); return changed; } @@ -254,8 +288,10 @@ sid_t LocalPoolDataSetBase::getSid() const { bool LocalPoolDataSetBase::bitGetter(const uint8_t* byte, uint8_t position) const { if(position > 7) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::debug << "Pool Raw Access: Bit setting invalid position" << std::endl; +#endif return false; } uint8_t shiftNumber = position + (7 - 2 * position); @@ -263,12 +299,10 @@ bool LocalPoolDataSetBase::bitGetter(const uint8_t* byte, } bool LocalPoolDataSetBase::isValid() const { - MutexHelper(mutex, MutexIF::TimeoutType::WAITING, 5); return this->valid; } void LocalPoolDataSetBase::setValidity(bool valid, bool setEntriesRecursively) { - MutexHelper(mutex, MutexIF::TimeoutType::WAITING, 5); if(setEntriesRecursively) { for(size_t idx = 0; idx < this->getFillCount(); idx++) { registeredVariables[idx] -> setValid(valid); @@ -276,3 +310,10 @@ void LocalPoolDataSetBase::setValidity(bool valid, bool setEntriesRecursively) { } this->valid = valid; } + +object_id_t LocalPoolDataSetBase::getCreatorObjectId() { + if(poolManager != nullptr) { + return poolManager->getCreatorObjectId(); + } + return objects::NO_OBJECT; +} diff --git a/datapoollocal/LocalPoolDataSetBase.h b/datapoollocal/LocalPoolDataSetBase.h index aa155bf1..cc41b0eb 100644 --- a/datapoollocal/LocalPoolDataSetBase.h +++ b/datapoollocal/LocalPoolDataSetBase.h @@ -1,16 +1,16 @@ #ifndef FSFW_DATAPOOLLOCAL_LOCALPOOLDATASETBASE_H_ #define FSFW_DATAPOOLLOCAL_LOCALPOOLDATASETBASE_H_ -#include "HasLocalDataPoolIF.h" #include "MarkChangedIF.h" +#include "localPoolDefinitions.h" #include "../datapool/DataSetIF.h" #include "../datapool/PoolDataSetBase.h" -#include "../serialize/SerializeIF.h" #include class LocalDataPoolManager; +class HasLocalDataPoolIF; class PeriodicHousekeepingHelper; /** @@ -41,156 +41,185 @@ class PeriodicHousekeepingHelper; * * @ingroup data_pool */ -class LocalPoolDataSetBase: public PoolDataSetBase, +class LocalPoolDataSetBase: + public PoolDataSetBase, public MarkChangedIF { - friend class LocalDataPoolManager; - friend class PeriodicHousekeepingHelper; + friend class LocalPoolDataSetAttorney; + friend class PeriodicHousekeepingHelper; public: - /** - * @brief Constructor for the creator of local pool data. - * @details - * This constructor also initializes the components required for - * periodic handling. - */ - LocalPoolDataSetBase(HasLocalDataPoolIF *hkOwner, - uint32_t setId, PoolVariableIF** registeredVariablesArray, - const size_t maxNumberOfVariables, bool noPeriodicHandling = false); + /** + * @brief Constructor for the creator of local pool data. + * @details + * This constructor also initializes the components required for + * periodic handling. + */ + LocalPoolDataSetBase(HasLocalDataPoolIF *hkOwner, + uint32_t setId, PoolVariableIF** registeredVariablesArray, + const size_t maxNumberOfVariables, bool periodicHandling = true); - /** - * @brief Constructor for users of local pool data. - * @details - * @param sid Unique identifier of dataset consisting of object ID and - * set ID. - * @param registeredVariablesArray - * @param maxNumberOfVariables - */ - LocalPoolDataSetBase(sid_t sid, PoolVariableIF** registeredVariablesArray, - const size_t maxNumberOfVariables); + /** + * @brief Constructor for users of the local pool data, which need + * to access data created by one (!) HK manager. + * @details + * Unlike the first constructor, no component for periodic handling + * will be initiated. + * @param sid Unique identifier of dataset consisting of object ID and + * set ID. + * @param registeredVariablesArray + * @param maxNumberOfVariables + */ + LocalPoolDataSetBase(sid_t sid, PoolVariableIF** registeredVariablesArray, + const size_t maxNumberOfVariables); - /** - * @brief 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(); + /** + * @brief Simple constructor, if the dataset is not the owner by + * a class with a HK manager. + * @details + * This constructor won't create components required for periodic handling + * and it also won't try to deduce the HK manager because no SID is + * supplied. This function should therefore be called by classes which need + * to access pool variables from different creators. + * + * If the class is intended to access pool variables from different + * creators, the third argument should be set to true. The mutex + * properties can be set with #setReadCommitProtectionBehaviour . + * @param registeredVariablesArray + * @param maxNumberOfVariables + * @param protectEveryReadCommitCall If the pool variables are created by + * multiple creators, this flag can be set to protect all read and + * commit calls separately. + */ + LocalPoolDataSetBase(PoolVariableIF** registeredVariablesArray, + const size_t maxNumberOfVariables, + bool protectEveryReadCommitCall = true); - 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 */ - 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; + sid_t getSid() const; - /** - * Special version of the serilization function which appends a - * validity buffer at the end. Each bit of this validity buffer - * denotes whether the container data set entries are valid from left - * to right, MSB first. (length = ceil(N/8), N = number of pool variables) - * @param buffer - * @param size - * @param maxSize - * @param bigEndian - * @param withValidityBuffer - * @return - */ - ReturnValue_t serializeWithValidityBuffer(uint8_t** buffer, - size_t* size, size_t maxSize, - SerializeIF::Endianness streamEndianness) const; - ReturnValue_t deSerializeWithValidityBuffer(const uint8_t** buffer, - size_t *size, SerializeIF::Endianness streamEndianness); - ReturnValue_t serializeLocalPoolIds(uint8_t** buffer, - size_t* size, size_t maxSize, - SerializeIF::Endianness streamEndianness, - bool serializeFillCount = true) const; - uint8_t getLocalPoolIdsSerializedSize(bool serializeFillCount = true) const; + /** SerializeIF overrides */ + ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, + SerializeIF::Endianness streamEndianness) const override; + ReturnValue_t deSerialize(const uint8_t** buffer, size_t *size, + SerializeIF::Endianness streamEndianness) override; + size_t getSerializedSize() const override; - /** - * Set the dataset valid or invalid. These calls are mutex protected. - * @param setEntriesRecursively - * If this is true, all contained datasets will also be set recursively. - */ - void setValidity(bool valid, bool setEntriesRecursively); - bool isValid() const override; + /** + * Special version of the serilization function which appends a + * validity buffer at the end. Each bit of this validity buffer + * denotes whether the container data set entries are valid from left + * to right, MSB first. (length = ceil(N/8), N = number of pool variables) + * @param buffer + * @param size + * @param maxSize + * @param bigEndian + * @param withValidityBuffer + * @return + */ + ReturnValue_t serializeWithValidityBuffer(uint8_t** buffer, + size_t* size, size_t maxSize, + SerializeIF::Endianness streamEndianness) const; + ReturnValue_t deSerializeWithValidityBuffer(const uint8_t** buffer, + size_t *size, SerializeIF::Endianness streamEndianness); + ReturnValue_t serializeLocalPoolIds(uint8_t** buffer, + size_t* size, size_t maxSize, + SerializeIF::Endianness streamEndianness, + bool serializeFillCount = true) const; + uint8_t getLocalPoolIdsSerializedSize(bool serializeFillCount = true) const; - /** - * These calls are mutex protected. - * @param changed - */ - void setChanged(bool changed) override; - bool hasChanged() const override; + /** + * Set the dataset valid or invalid. These calls are mutex protected. + * @param setEntriesRecursively + * If this is true, all contained datasets will also be set recursively. + */ + void setValidity(bool valid, bool setEntriesRecursively); + bool isValid() const override; + /** + * These calls are mutex protected. + * @param changed + */ + void setChanged(bool changed) override; + bool hasChanged() const override; + + object_id_t getCreatorObjectId(); protected: - sid_t sid; - MutexIF* mutex = nullptr; + sid_t sid; + //! This mutex is used if the data is created by one object only. + MutexIF* mutexIfSingleDataCreator = nullptr; - bool diagnostic = false; - void setDiagnostic(bool diagnostics); - bool isDiagnostics() const; + bool diagnostic = false; + void setDiagnostic(bool diagnostics); + bool isDiagnostics() const; - /** - * Used for periodic generation. - */ - bool reportingEnabled = false; - void setReportingEnabled(bool enabled); - bool getReportingEnabled() const; + /** + * Used for periodic generation. + */ + bool reportingEnabled = false; + void setReportingEnabled(bool enabled); + bool getReportingEnabled() const; - void initializePeriodicHelper(float collectionInterval, - dur_millis_t minimumPeriodicInterval, - bool isDiagnostics, uint8_t nonDiagIntervalFactor = 5); + void initializePeriodicHelper(float collectionInterval, + dur_millis_t minimumPeriodicInterval, + bool isDiagnostics, uint8_t nonDiagIntervalFactor = 5); - /** - * If the valid state of a dataset is always relevant to the whole - * data set we can use this flag. - */ - bool valid = false; + /** + * If the valid state of a dataset is always relevant to the whole + * data set we can use this flag. + */ + bool valid = false; - /** - * Can be used to mark the dataset as changed, which is used - * by the LocalDataPoolManager to send out update messages. - */ - bool changed = false; + /** + * Can be used to mark the dataset as changed, which is used + * by the LocalDataPoolManager to send out update messages. + */ + bool changed = false; - /** - * Specify whether the validity buffer is serialized too when serializing - * or deserializing the packet. Each bit of the validity buffer will - * contain the validity state of the pool variables from left to right. - * The size of validity buffer thus will be ceil(N / 8) with N = number of - * pool variables. - */ - bool withValidityBuffer = true; + /** + * Specify whether the validity buffer is serialized too when serializing + * or deserializing the packet. Each bit of the validity buffer will + * contain the validity state of the pool variables from left to right. + * The size of validity buffer thus will be ceil(N / 8) with N = number of + * pool variables. + */ + bool withValidityBuffer = true; - /** - * @brief This is a small helper function to facilitate locking - * the global data pool. - * @details - * It makes use of the lockDataPool method offered by the DataPool class. - */ - ReturnValue_t lockDataPool(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; + /** + * @brief This is a small helper function to facilitate locking + * the global data pool. + * @details + * It makes use of the lockDataPool method offered by the DataPool class. + */ + ReturnValue_t lockDataPool(MutexIF::TimeoutType timeoutType, + uint32_t timeoutMs) override; - 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 - * (most significant bit) to 7 (least significant bit) - */ - void bitSetter(uint8_t* byte, uint8_t position) const; - bool bitGetter(const uint8_t* byte, uint8_t position) const; + /** + * Set n-th bit of a byte, with n being the position from 0 + * (most significant bit) to 7 (least significant bit) + */ + void bitSetter(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; }; diff --git a/datapoollocal/LocalPoolObjectBase.cpp b/datapoollocal/LocalPoolObjectBase.cpp index b4d0e306..a0bf5708 100644 --- a/datapoollocal/LocalPoolObjectBase.cpp +++ b/datapoollocal/LocalPoolObjectBase.cpp @@ -1,40 +1,58 @@ #include "LocalPoolObjectBase.h" +#include "LocalDataPoolManager.h" +#include "internal/HasLocalDpIFUserAttorney.h" +#include "HasLocalDataPoolIF.h" -LocalPoolObjectBase::LocalPoolObjectBase(lp_id_t poolId, - HasLocalDataPoolIF* hkOwner, DataSetIF* dataSet, - pool_rwm_t setReadWriteMode): localPoolId(poolId), - readWriteMode(setReadWriteMode) { +#include "../objectmanager/ObjectManagerIF.h" + +LocalPoolObjectBase::LocalPoolObjectBase(lp_id_t poolId, HasLocalDataPoolIF* hkOwner, + DataSetIF* dataSet, pool_rwm_t setReadWriteMode): + localPoolId(poolId), readWriteMode(setReadWriteMode) { if(poolId == PoolVariableIF::NO_PARAMETER) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "LocalPoolVar::LocalPoolVar: 0 passed as pool ID, " << "which is the NO_PARAMETER value!" << std::endl; +#endif } if(hkOwner == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "LocalPoolVar::LocalPoolVar: The supplied pool " << "owner is a invalid!" << std::endl; +#endif return; } - hkManager = hkOwner->getHkManagerHandle(); + AccessPoolManagerIF* poolManAccessor = HasLocalDpIFUserAttorney::getAccessorHandle(hkOwner); + hkManager = poolManAccessor->getHkManagerHandle(); + if (dataSet != nullptr) { dataSet->registerVariable(this); } } -LocalPoolObjectBase::LocalPoolObjectBase(object_id_t poolOwner, lp_id_t poolId, - DataSetIF *dataSet, pool_rwm_t setReadWriteMode): localPoolId(poolId), - readWriteMode(setReadWriteMode) { +LocalPoolObjectBase::LocalPoolObjectBase(object_id_t poolOwner, lp_id_t poolId, DataSetIF *dataSet, + pool_rwm_t setReadWriteMode): + localPoolId(poolId), readWriteMode(setReadWriteMode) { if(poolId == PoolVariableIF::NO_PARAMETER) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "LocalPoolVar::LocalPoolVar: 0 passed as pool ID, " << "which is the NO_PARAMETER value!" << std::endl; +#endif } - HasLocalDataPoolIF* hkOwner = - objectManager->get(poolOwner); + HasLocalDataPoolIF* hkOwner = objectManager->get(poolOwner); if(hkOwner == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "LocalPoolVariable: The supplied pool owner did not " << "implement the correct interface" << " HasLocalDataPoolIF!" << std::endl; +#endif return; } - hkManager = hkOwner->getHkManagerHandle(); + + AccessPoolManagerIF* accessor = HasLocalDpIFUserAttorney::getAccessorHandle(hkOwner); + if(accessor != nullptr) { + hkManager = accessor->getHkManagerHandle(); + } + if(dataSet != nullptr) { dataSet->registerVariable(this); } @@ -69,5 +87,44 @@ bool LocalPoolObjectBase::hasChanged() const { } 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 */ } diff --git a/datapoollocal/LocalPoolObjectBase.h b/datapoollocal/LocalPoolObjectBase.h index 7165fc24..797cf8b5 100644 --- a/datapoollocal/LocalPoolObjectBase.h +++ b/datapoollocal/LocalPoolObjectBase.h @@ -2,10 +2,20 @@ #define FSFW_DATAPOOLLOCAL_LOCALPOOLOBJECTBASE_H_ #include "MarkChangedIF.h" -#include "../datapoollocal/LocalDataPoolManager.h" +#include "localPoolDefinitions.h" + +#include "../objectmanager/SystemObjectIF.h" #include "../datapool/PoolVariableIF.h" +#include "../returnvalues/HasReturnvaluesIF.h" +class LocalDataPoolManager; +class DataSetIF; +class HasLocalDataPoolIF; +/** + * @brief This class serves as a non-template base for pool objects like pool variables + * or pool vectors. + */ class LocalPoolObjectBase: public PoolVariableIF, public HasReturnvaluesIF, public MarkChangedIF { @@ -54,10 +64,10 @@ protected: ReadWriteMode_t readWriteMode = pool_rwm_t::VAR_READ_WRITE; //! @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_ */ diff --git a/datapoollocal/LocalPoolVariable.h b/datapoollocal/LocalPoolVariable.h index 7b7e443e..76629489 100644 --- a/datapoollocal/LocalPoolVariable.h +++ b/datapoollocal/LocalPoolVariable.h @@ -4,9 +4,12 @@ #include "LocalPoolObjectBase.h" #include "HasLocalDataPoolIF.h" #include "LocalDataPoolManager.h" +#include "AccessLocalPoolF.h" +#include "internal/LocalDpManagerAttorney.h" #include "../datapool/PoolVariableIF.h" #include "../datapool/DataSetIF.h" +#include "../serviceinterface/ServiceInterface.h" #include "../objectmanager/ObjectManagerIF.h" #include "../serialize/SerializeAdapter.h" @@ -24,145 +27,160 @@ template class LocalPoolVariable: public LocalPoolObjectBase { public: - //! Default ctor is forbidden. - LocalPoolVariable() = delete; + //! Default ctor is forbidden. + LocalPoolVariable() = delete; - /** - * This constructor is used by the data creators to have pool variable - * instances which can also be stored in datasets. - * - * It does not fetch the current value from the data pool, which - * has to be done by calling the read() operation. - * Datasets can be used to access multiple local pool entries in an - * efficient way. A pointer to a dataset can be passed to register - * the pool variable in that dataset directly. - * @param poolId ID of the local pool entry. - * @param hkOwner Pointer of the owner. This will generally be the calling - * class itself which passes "this". - * @param dataSet The data set in which the variable shall register itself. - * If nullptr, the variable is not registered. - * @param setReadWriteMode Specify the read-write mode of the pool variable. - */ - LocalPoolVariable(HasLocalDataPoolIF* hkOwner, lp_id_t poolId, - DataSetIF* dataSet = nullptr, - pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE); + /** + * This constructor is used by the data creators to have pool variable + * instances which can also be stored in datasets. + * + * It does not fetch the current value from the data pool, which + * has to be done by calling the read() operation. + * Datasets can be used to access multiple local pool entries in an + * efficient way. A pointer to a dataset can be passed to register + * the pool variable in that dataset directly. + * @param poolId ID of the local pool entry. + * @param hkOwner Pointer of the owner. This will generally be the calling + * class itself which passes "this". + * @param dataSet The data set in which the variable shall register itself. + * If nullptr, the variable is not registered. + * @param setReadWriteMode Specify the read-write mode of the pool variable. + */ + LocalPoolVariable(HasLocalDataPoolIF* hkOwner, lp_id_t poolId, + DataSetIF* dataSet = nullptr, + pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE); - /** - * This constructor is used by data users like controllers to have - * access to the local pool variables of data creators by supplying - * the respective creator object ID. - * - * It does not fetch the current value from the data pool, which - * has to be done by calling the read() operation. - * Datasets can be used to access multiple local pool entries in an - * efficient way. A pointer to a dataset can be passed to register - * the pool variable in that dataset directly. - * @param poolId ID of the local pool entry. - * @param hkOwner object ID of the pool owner. - * @param dataSet The data set in which the variable shall register itself. - * If nullptr, the variable is not registered. - * @param setReadWriteMode Specify the read-write mode of the pool variable. - * - */ - LocalPoolVariable(object_id_t poolOwner, lp_id_t poolId, - DataSetIF* dataSet = nullptr, - pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE); - /** - * Variation which takes the global unique identifier of a pool variable. - * @param globalPoolId - * @param dataSet - * @param setReadWriteMode - */ - LocalPoolVariable(gp_id_t globalPoolId, DataSetIF* dataSet = nullptr, - pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE); + /** + * This constructor is used by data users like controllers to have + * access to the local pool variables of data creators by supplying + * the respective creator object ID. + * + * It does not fetch the current value from the data pool, which + * has to be done by calling the read() operation. + * Datasets can be used to access multiple local pool entries in an + * efficient way. A pointer to a dataset can be passed to register + * the pool variable in that dataset directly. + * @param poolId ID of the local pool entry. + * @param hkOwner object ID of the pool owner. + * @param dataSet The data set in which the variable shall register itself. + * If nullptr, the variable is not registered. + * @param setReadWriteMode Specify the read-write mode of the pool variable. + * + */ + LocalPoolVariable(object_id_t poolOwner, lp_id_t poolId, + DataSetIF* dataSet = nullptr, + pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE); + /** + * Variation which takes the global unique identifier of a pool variable. + * @param globalPoolId + * @param dataSet + * @param setReadWriteMode + */ + LocalPoolVariable(gp_id_t globalPoolId, DataSetIF* dataSet = nullptr, + pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE); - virtual~ LocalPoolVariable() {}; + virtual~ LocalPoolVariable() {}; - /** - * @brief This is the local copy of the data pool entry. - * @details The user can work on this attribute - * just like he would on a simple local variable. - */ - T value = 0; + /** + * @brief This is the local copy of the data pool entry. + * @details The user can work on this attribute + * just like he would on a simple local variable. + */ + T value = 0; - ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, - SerializeIF::Endianness streamEndianness) const override; - virtual size_t getSerializedSize() const override; - virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - SerializeIF::Endianness streamEndianness) override; + ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, + SerializeIF::Endianness streamEndianness) const override; + virtual size_t getSerializedSize() const override; + virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + SerializeIF::Endianness streamEndianness) override; - /** - * @brief This is a call to read the array's values - * from the global data pool. - * @details - * When executed, this operation tries to fetch the pool entry with matching - * data pool id from the data pool and copies all array values and the valid - * information to its local attributes. - * In case of a failure (wrong type, size or pool id not found), the - * variable is set to zero and invalid. - * The read call is protected with a lock. - * It is recommended to use DataSets to read and commit multiple variables - * at once to avoid the overhead of unnecessary lock und unlock operations. - * - */ - ReturnValue_t read(dur_millis_t lockTimeout = MutexIF::BLOCKING) override; - /** - * @brief The commit call copies the array values back to the data pool. - * @details - * It checks type and size, as well as if the variable is writable. If so, - * the value is copied and the local valid flag is written back as well. - * The read call is protected with a lock. - * It is recommended to use DataSets to read and commit multiple variables - * at once to avoid the overhead of unnecessary lock und unlock operations. - */ - ReturnValue_t commit(dur_millis_t lockTimeout = MutexIF::BLOCKING) override; + /** + * @brief This is a call to read the array's values + * from the global data pool. + * @details + * When executed, this operation tries to fetch the pool entry with matching + * data pool id from the data pool and copies all array values and the valid + * information to its local attributes. + * In case of a failure (wrong type, size or pool id not found), the + * variable is set to zero and invalid. + * The read call is protected with a lock. + * It is recommended to use DataSets to read and commit multiple variables + * at once to avoid the overhead of unnecessary lock und unlock operations. + * + */ + ReturnValue_t read(MutexIF::TimeoutType timeoutType = + MutexIF::TimeoutType::WAITING, + uint32_t timeoutMs = 20) override; + /** + * @brief The commit call copies the array values back to the data pool. + * @details + * It checks type and size, as well as if the variable is writable. If so, + * the value is copied and the local valid flag is written back as well. + * The read call is protected with a lock. + * It is recommended to use DataSets to read and commit multiple variables + * at once to avoid the overhead of unnecessary lock und unlock operations. + */ + ReturnValue_t commit(MutexIF::TimeoutType timeoutType = + MutexIF::TimeoutType::WAITING, + uint32_t timeoutMs = 20) override; + /** + * @brief This commit function can be used to set the pool variable valid + * as well. + * @param setValid + * @param timeoutType + * @param timeoutMs + * @return + */ + ReturnValue_t commit(bool setValid, MutexIF::TimeoutType timeoutType = + MutexIF::TimeoutType::WAITING, + uint32_t timeoutMs = 20); - LocalPoolVariable &operator=(const T& newValue); - LocalPoolVariable &operator=(const LocalPoolVariable& newPoolVariable); + LocalPoolVariable &operator=(const T& newValue); + LocalPoolVariable &operator=(const LocalPoolVariable& newPoolVariable); - //! Explicit type conversion operator. Allows casting the class to - //! its template type to perform operations on value. - explicit operator T() const; + //! Explicit type conversion operator. Allows casting the class to + //! its template type to perform operations on value. + explicit operator T() const; - bool operator==(const LocalPoolVariable& other) const; - bool operator==(const T& other) const; + bool operator==(const LocalPoolVariable& other) const; + bool operator==(const T& other) const; - bool operator!=(const LocalPoolVariable& other) const; - bool operator!=(const T& other) const; + bool operator!=(const LocalPoolVariable& other) const; + bool operator!=(const T& other) const; - bool operator<(const LocalPoolVariable& other) const; - bool operator<(const T& other) const; + bool operator<(const LocalPoolVariable& other) const; + bool operator<(const T& other) const; - bool operator>(const LocalPoolVariable& other) const; - bool operator>(const T& other) const; + bool operator>(const LocalPoolVariable& other) const; + bool operator>(const T& other) const; protected: - /** - * @brief Like #read, but without a lock protection of the global pool. - * @details - * The operation does NOT provide any mutual exclusive protection by itself. - * This can be used if the lock is handled externally to avoid the overhead - * of consecutive lock und unlock operations. - * Declared protected to discourage free public usage. - */ - ReturnValue_t readWithoutLock() override; - /** - * @brief Like #commit, but without a lock protection of the global pool. - * @details - * The operation does NOT provide any mutual exclusive protection by itself. - * This can be used if the lock is handled externally to avoid the overhead - * of consecutive lock und unlock operations. - * Declared protected to discourage free public usage. - */ - ReturnValue_t commitWithoutLock() override; + /** + * @brief Like #read, but without a lock protection of the global pool. + * @details + * The operation does NOT provide any mutual exclusive protection by itself. + * This can be used if the lock is handled externally to avoid the overhead + * of consecutive lock und unlock operations. + * Declared protected to discourage free public usage. + */ + ReturnValue_t readWithoutLock() override; + /** + * @brief Like #commit, but without a lock protection of the global pool. + * @details + * The operation does NOT provide any mutual exclusive protection by itself. + * This can be used if the lock is handled externally to avoid the overhead + * of consecutive lock und unlock operations. + * Declared protected to discourage free public usage. + */ + ReturnValue_t commitWithoutLock() override; - // std::ostream is the type for object std::cout - template - friend std::ostream& operator<< (std::ostream &out, - const LocalPoolVariable &var); - -private: +#if FSFW_CPP_OSTREAM_ENABLED == 1 + // std::ostream is the type for object std::cout + template + friend std::ostream& operator<< (std::ostream &out, + const LocalPoolVariable &var); +#endif }; #include "LocalPoolVariable.tpp" diff --git a/datapoollocal/LocalPoolVariable.tpp b/datapoollocal/LocalPoolVariable.tpp index 48649ad5..35de4ebd 100644 --- a/datapoollocal/LocalPoolVariable.tpp +++ b/datapoollocal/LocalPoolVariable.tpp @@ -7,163 +7,196 @@ template inline LocalPoolVariable::LocalPoolVariable(HasLocalDataPoolIF* hkOwner, - lp_id_t poolId, DataSetIF* dataSet, pool_rwm_t setReadWriteMode): - LocalPoolObjectBase(poolId, hkOwner, dataSet, setReadWriteMode) {} + lp_id_t poolId, DataSetIF* dataSet, pool_rwm_t setReadWriteMode): + LocalPoolObjectBase(poolId, hkOwner, dataSet, setReadWriteMode) {} template -inline LocalPoolVariable::LocalPoolVariable(object_id_t poolOwner, lp_id_t poolId, - DataSetIF *dataSet, pool_rwm_t setReadWriteMode): +inline LocalPoolVariable::LocalPoolVariable(object_id_t poolOwner, + lp_id_t poolId, DataSetIF *dataSet, pool_rwm_t setReadWriteMode): LocalPoolObjectBase(poolOwner, poolId, dataSet, setReadWriteMode) {} template -inline LocalPoolVariable::LocalPoolVariable(gp_id_t globalPoolId, DataSetIF *dataSet, - pool_rwm_t setReadWriteMode): - LocalPoolObjectBase(globalPoolId.objectId, globalPoolId.localPoolId, - dataSet, setReadWriteMode){} +inline LocalPoolVariable::LocalPoolVariable(gp_id_t globalPoolId, + DataSetIF *dataSet, pool_rwm_t setReadWriteMode): + LocalPoolObjectBase(globalPoolId.objectId, globalPoolId.localPoolId, + dataSet, setReadWriteMode){} template -inline ReturnValue_t LocalPoolVariable::read(dur_millis_t lockTimeout) { - MutexHelper(hkManager->getMutexHandle(), MutexIF::TimeoutType::WAITING, - lockTimeout); - return readWithoutLock(); +inline ReturnValue_t LocalPoolVariable::read( + MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) { + MutexHelper(LocalDpManagerAttorney::getMutexHandle(*hkManager), timeoutType, timeoutMs); + return readWithoutLock(); } template inline ReturnValue_t LocalPoolVariable::readWithoutLock() { - if(readWriteMode == pool_rwm_t::VAR_WRITE) { - sif::debug << "LocalPoolVar: Invalid read write " - "mode for read() call." << std::endl; - return PoolVariableIF::INVALID_READ_WRITE_MODE; - } + if(readWriteMode == pool_rwm_t::VAR_WRITE) { + object_id_t targetObjectId = hkManager->getCreatorObjectId(); + reportReadCommitError("LocalPoolVector", + PoolVariableIF::INVALID_READ_WRITE_MODE, true, targetObjectId, + localPoolId); + return PoolVariableIF::INVALID_READ_WRITE_MODE; + } - PoolEntry* poolEntry = nullptr; - ReturnValue_t result = hkManager->fetchPoolEntry(localPoolId, &poolEntry); - if(result != RETURN_OK and poolEntry != nullptr) { - sif::error << "PoolVector: Read of local pool variable of object " - "0x" << std::hex << std::setw(8) << std::setfill('0') << - hkManager->getOwner() << " and lp ID 0x" << localPoolId << - std::dec << " failed.\n" << std::flush; - return result; - } - this->value = *(poolEntry->address); - this->valid = poolEntry->valid; - return RETURN_OK; + PoolEntry* poolEntry = nullptr; + ReturnValue_t result = LocalDpManagerAttorney::fetchPoolEntry(*hkManager, localPoolId, + &poolEntry); + //ReturnValue_t result = hkManager->fetchPoolEntry(localPoolId, &poolEntry); + if(result != RETURN_OK) { + object_id_t ownerObjectId = hkManager->getCreatorObjectId(); + reportReadCommitError("LocalPoolVariable", result, + false, ownerObjectId, localPoolId); + return result; + } + + // 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 -inline ReturnValue_t LocalPoolVariable::commit(dur_millis_t lockTimeout) { - MutexHelper(hkManager->getMutexHandle(), MutexIF::TimeoutType::WAITING, - lockTimeout); - return commitWithoutLock(); +inline ReturnValue_t LocalPoolVariable::commit(bool setValid, + MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) { + this->setValid(setValid); + return commit(timeoutType, timeoutMs); +} + +template +inline ReturnValue_t LocalPoolVariable::commit( + MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) { + MutexHelper(LocalDpManagerAttorney::getMutexHandle(*hkManager), timeoutType, timeoutMs); + return commitWithoutLock(); } template inline ReturnValue_t LocalPoolVariable::commitWithoutLock() { - if(readWriteMode == pool_rwm_t::VAR_READ) { - sif::debug << "LocalPoolVar: Invalid read write " - "mode for commit() call." << std::endl; - return PoolVariableIF::INVALID_READ_WRITE_MODE; - } - PoolEntry* poolEntry = nullptr; - ReturnValue_t result = hkManager->fetchPoolEntry(localPoolId, &poolEntry); - if(result != RETURN_OK) { - sif::error << "PoolVector: Read of local pool variable of object " - "0x" << std::hex << std::setw(8) << std::setfill('0') << - hkManager->getOwner() << " and lp ID 0x" << localPoolId << - std::dec << " failed.\n" << std::flush; - return result; - } - *(poolEntry->address) = this->value; - poolEntry->valid = this->valid; - return RETURN_OK; + if(readWriteMode == pool_rwm_t::VAR_READ) { + object_id_t targetObjectId = hkManager->getCreatorObjectId(); + reportReadCommitError("LocalPoolVector", + PoolVariableIF::INVALID_READ_WRITE_MODE, false, targetObjectId, + localPoolId); + return PoolVariableIF::INVALID_READ_WRITE_MODE; + } + + PoolEntry* poolEntry = nullptr; + //ReturnValue_t result = hkManager->fetchPoolEntry(localPoolId, &poolEntry); + ReturnValue_t result = LocalDpManagerAttorney::fetchPoolEntry(*hkManager, localPoolId, + &poolEntry); + if(result != RETURN_OK) { + object_id_t ownerObjectId = hkManager->getCreatorObjectId(); + reportReadCommitError("LocalPoolVariable", result, + false, ownerObjectId, localPoolId); + return result; + } + + *(poolEntry->getDataPtr()) = this->value; + poolEntry->setValid(this->valid); + return RETURN_OK; } template -inline ReturnValue_t LocalPoolVariable::serialize(uint8_t** buffer, size_t* size, - const size_t max_size, SerializeIF::Endianness streamEndianness) const { - return SerializeAdapter::serialize(&value, - buffer, size ,max_size, streamEndianness); +inline ReturnValue_t LocalPoolVariable::serialize(uint8_t** buffer, + size_t* size, const size_t max_size, + SerializeIF::Endianness streamEndianness) const { + return SerializeAdapter::serialize(&value, + buffer, size ,max_size, streamEndianness); } template inline size_t LocalPoolVariable::getSerializedSize() const { - return SerializeAdapter::getSerializedSize(&value); + return SerializeAdapter::getSerializedSize(&value); } template inline ReturnValue_t LocalPoolVariable::deSerialize(const uint8_t** buffer, - size_t* size, SerializeIF::Endianness streamEndianness) { - return SerializeAdapter::deSerialize(&value, buffer, size, streamEndianness); + size_t* size, SerializeIF::Endianness streamEndianness) { + return SerializeAdapter::deSerialize(&value, buffer, size, streamEndianness); } +#if FSFW_CPP_OSTREAM_ENABLED == 1 template inline std::ostream& operator<< (std::ostream &out, - const LocalPoolVariable &var) { + const LocalPoolVariable &var) { out << var.value; return out; } +#endif template inline LocalPoolVariable::operator T() const { - return value; + return value; } template -inline LocalPoolVariable & LocalPoolVariable::operator=(const T& newValue) { +inline LocalPoolVariable & LocalPoolVariable::operator=( + const T& newValue) { value = newValue; return *this; } template inline LocalPoolVariable& LocalPoolVariable::operator =( - const LocalPoolVariable& newPoolVariable) { - value = newPoolVariable.value; - return *this; + const LocalPoolVariable& newPoolVariable) { + value = newPoolVariable.value; + return *this; } template -inline bool LocalPoolVariable::operator ==(const LocalPoolVariable &other) const { - return this->value == other.value; +inline bool LocalPoolVariable::operator ==( + const LocalPoolVariable &other) const { + return this->value == other.value; } template inline bool LocalPoolVariable::operator ==(const T &other) const { - return this->value == other; + return this->value == other; } template -inline bool LocalPoolVariable::operator !=(const LocalPoolVariable &other) const { - return not (*this == other); +inline bool LocalPoolVariable::operator !=( + const LocalPoolVariable &other) const { + return not (*this == other); } template inline bool LocalPoolVariable::operator !=(const T &other) const { - return not (*this == other); + return not (*this == other); } template -inline bool LocalPoolVariable::operator <(const LocalPoolVariable &other) const { - return this->value < other.value; +inline bool LocalPoolVariable::operator <( + const LocalPoolVariable &other) const { + return this->value < other.value; } template inline bool LocalPoolVariable::operator <(const T &other) const { - return this->value < other; + return this->value < other; } template -inline bool LocalPoolVariable::operator >(const LocalPoolVariable &other) const { - return not (*this < other); +inline bool LocalPoolVariable::operator >( + const LocalPoolVariable &other) const { + return not (*this < other); } template inline bool LocalPoolVariable::operator >(const T &other) const { - return not (*this < other); + return not (*this < other); } #endif /* FSFW_DATAPOOLLOCAL_LOCALPOOLVARIABLE_TPP_ */ diff --git a/datapoollocal/LocalPoolVector.h b/datapoollocal/LocalPoolVector.h index 58face3c..593d26ab 100644 --- a/datapoollocal/LocalPoolVector.h +++ b/datapoollocal/LocalPoolVector.h @@ -2,12 +2,14 @@ #define FSFW_DATAPOOLLOCAL_LOCALPOOLVECTOR_H_ #include "LocalPoolObjectBase.h" +#include "internal/LocalDpManagerAttorney.h" + #include "../datapool/DataSetIF.h" #include "../datapool/PoolEntry.h" #include "../datapool/PoolVariableIF.h" #include "../datapoollocal/LocalDataPoolManager.h" #include "../serialize/SerializeAdapter.h" -#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../serviceinterface/ServiceInterface.h" /** @@ -33,136 +35,149 @@ template class LocalPoolVector: public LocalPoolObjectBase { public: - LocalPoolVector() = delete; - /** - * This constructor is used by the data creators to have pool variable - * instances which can also be stored in datasets. - * It does not fetch the current value from the data pool. This is performed - * by the read() operation (which is not thread-safe). - * Datasets can be used to access local pool entires in a thread-safe way. - * @param poolId ID of the local pool entry. - * @param hkOwner Pointer of the owner. This will generally be the calling - * class itself which passes "this". - * @param setReadWriteMode Specify the read-write mode of the pool variable. - * @param dataSet The data set in which the variable shall register itself. - * If nullptr, the variable is not registered. - */ - LocalPoolVector(HasLocalDataPoolIF* hkOwner, lp_id_t poolId, - DataSetIF* dataSet = nullptr, - pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE); + LocalPoolVector() = delete; + /** + * This constructor is used by the data creators to have pool variable + * instances which can also be stored in datasets. + * It does not fetch the current value from the data pool. This is performed + * by the read() operation (which is not thread-safe). + * Datasets can be used to access local pool entires in a thread-safe way. + * @param poolId ID of the local pool entry. + * @param hkOwner Pointer of the owner. This will generally be the calling + * class itself which passes "this". + * @param setReadWriteMode Specify the read-write mode of the pool variable. + * @param dataSet The data set in which the variable shall register itself. + * If nullptr, the variable is not registered. + */ + LocalPoolVector(HasLocalDataPoolIF* hkOwner, lp_id_t poolId, + DataSetIF* dataSet = nullptr, + pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE); - /** - * This constructor is used by data users like controllers to have - * access to the local pool variables of data creators by supplying - * the respective creator object ID. - * It does not fetch the current value from the data pool. This is performed - * by the read() operation (which is not thread-safe). - * Datasets can be used to access local pool entires in a thread-safe way. - * @param poolId ID of the local pool entry. - * @param hkOwner Pointer of the owner. This will generally be the calling - * class itself which passes "this". - * @param setReadWriteMode Specify the read-write mode of the pool variable. - * @param dataSet The data set in which the variable shall register itself. - * If nullptr, the variable is not registered. - */ - LocalPoolVector(object_id_t poolOwner, lp_id_t poolId, - DataSetIF* dataSet = nullptr, - pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE); - /** - * Variation which takes the unique global identifier of a local pool - * vector. - * @param globalPoolId - * @param dataSet - * @param setReadWriteMode - */ - LocalPoolVector(gp_id_t globalPoolId, - DataSetIF* dataSet = nullptr, - pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE); + /** + * This constructor is used by data users like controllers to have + * access to the local pool variables of data creators by supplying + * the respective creator object ID. + * It does not fetch the current value from the data pool. This is performed + * by the read() operation (which is not thread-safe). + * Datasets can be used to access local pool entires in a thread-safe way. + * @param poolId ID of the local pool entry. + * @param hkOwner Pointer of the owner. This will generally be the calling + * class itself which passes "this". + * @param setReadWriteMode Specify the read-write mode of the pool variable. + * @param dataSet The data set in which the variable shall register itself. + * If nullptr, the variable is not registered. + */ + LocalPoolVector(object_id_t poolOwner, lp_id_t poolId, + DataSetIF* dataSet = nullptr, + pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE); + /** + * Variation which takes the unique global identifier of a local pool + * vector. + * @param globalPoolId + * @param dataSet + * @param setReadWriteMode + */ + LocalPoolVector(gp_id_t globalPoolId, + DataSetIF* dataSet = nullptr, + pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE); - /** - * @brief This is the local copy of the data pool entry. - * @details - * The user can work on this attribute just like he would on a local - * array of this type. - */ - T value[vectorSize]; - /** - * @brief The classes destructor is empty. - * @details If commit() was not called, the local value is - * discarded and not written back to the data pool. - */ - ~LocalPoolVector() {}; - /** - * @brief The operation returns the number of array entries - * in this variable. - */ - uint8_t getSize() { - return vectorSize; - } + /** + * @brief This is the local copy of the data pool entry. + * @details + * The user can work on this attribute just like he would on a local + * array of this type. + */ + T value[vectorSize]; + /** + * @brief The classes destructor is empty. + * @details If commit() was not called, the local value is + * discarded and not written back to the data pool. + */ + ~LocalPoolVector() {}; + /** + * @brief The operation returns the number of array entries + * in this variable. + */ + uint8_t getSize() { + return vectorSize; + } - T& operator [](int i); - const T &operator [](int i) const; + T& operator [](size_t i); + const T &operator [](size_t i) const; - virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, - const size_t maxSize, - SerializeIF::Endianness streamEndiannes) const override; - virtual size_t getSerializedSize() const override; - virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - SerializeIF::Endianness streamEndianness) override; + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t maxSize, + SerializeIF::Endianness streamEndiannes) const override; + virtual size_t getSerializedSize() const override; + virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + SerializeIF::Endianness streamEndianness) override; - /** - * @brief This is a call to read the array's values - * from the global data pool. - * @details - * When executed, this operation tries to fetch the pool entry with matching - * data pool id from the data pool and copies all array values and the valid - * information to its local attributes. - * In case of a failure (wrong type, size or pool id not found), the - * variable is set to zero and invalid. - * The read call is protected with a lock. - * It is recommended to use DataSets to read and commit multiple variables - * at once to avoid the overhead of unnecessary lock und unlock operations. - */ - ReturnValue_t read(uint32_t lockTimeout = MutexIF::BLOCKING) override; - /** - * @brief The commit call copies the array values back to the data pool. - * @details - * It checks type and size, as well as if the variable is writable. If so, - * the value is copied and the local valid flag is written back as well. - * The read call is protected with a lock. - * It is recommended to use DataSets to read and commit multiple variables - * at once to avoid the overhead of unnecessary lock und unlock operations. - */ - ReturnValue_t commit(uint32_t lockTimeout = MutexIF::BLOCKING) override; + /** + * @brief This is a call to read the array's values + * from the global data pool. + * @details + * When executed, this operation tries to fetch the pool entry with matching + * data pool id from the data pool and copies all array values and the valid + * information to its local attributes. + * In case of a failure (wrong type, size or pool id not found), the + * variable is set to zero and invalid. + * The read call is protected with a lock. + * It is recommended to use DataSets to read and commit multiple variables + * at once to avoid the overhead of unnecessary lock und unlock operations. + */ + ReturnValue_t read(MutexIF::TimeoutType timeoutType = + MutexIF::TimeoutType::WAITING, + uint32_t timeoutMs = 20) override; + + /** + * @brief The commit call copies the array values back to the data pool. + * @details + * It checks type and size, as well as if the variable is writable. If so, + * the value is copied and the local valid flag is written back as well. + * The read call is protected with a lock. + * It is recommended to use DataSets to read and commit multiple variables + * at once to avoid the overhead of unnecessary lock und unlock operations. + */ + ReturnValue_t commit(MutexIF::TimeoutType timeoutType = + MutexIF::TimeoutType::WAITING, + uint32_t timeoutMs = 20) override; + + /** + * @brief This commit call also sets the validity of the pool entry. + * @details + */ + ReturnValue_t commit(bool valid, MutexIF::TimeoutType timeoutType = + MutexIF::TimeoutType::WAITING, + uint32_t timeoutMs = 20); protected: - /** - * @brief Like #read, but without a lock protection of the global pool. - * @details - * The operation does NOT provide any mutual exclusive protection by itself. - * This can be used if the lock is handled externally to avoid the overhead - * of consecutive lock und unlock operations. - * Declared protected to discourage free public usage. - */ - ReturnValue_t readWithoutLock() override; - /** - * @brief Like #commit, but without a lock protection of the global pool. - * @details - * The operation does NOT provide any mutual exclusive protection by itself. - * This can be used if the lock is handled externally to avoid the overhead - * of consecutive lock und unlock operations. - * Declared protected to discourage free public usage. - */ - ReturnValue_t commitWithoutLock() override; + /** + * @brief Like #read, but without a lock protection of the global pool. + * @details + * The operation does NOT provide any mutual exclusive protection by itself. + * This can be used if the lock is handled externally to avoid the overhead + * of consecutive lock und unlock operations. + * Declared protected to discourage free public usage. + */ + ReturnValue_t readWithoutLock() override; + /** + * @brief Like #commit, but without a lock protection of the global pool. + * @details + * The operation does NOT provide any mutual exclusive protection by itself. + * This can be used if the lock is handled externally to avoid the overhead + * of consecutive lock und unlock operations. + * Declared protected to discourage free public usage. + */ + ReturnValue_t commitWithoutLock() override; private: - - // std::ostream is the type for object std::cout - template - friend std::ostream& operator<< (std::ostream &out, - const LocalPoolVector &var); - +#if FSFW_CPP_OSTREAM_ENABLED == 1 + // std::ostream is the type for object std::cout + template + friend std::ostream& operator<< (std::ostream &out, + const LocalPoolVector &var); +#endif }; diff --git a/datapoollocal/LocalPoolVector.tpp b/datapoollocal/LocalPoolVector.tpp index 46123ccc..98eb27f9 100644 --- a/datapoollocal/LocalPoolVector.tpp +++ b/datapoollocal/LocalPoolVector.tpp @@ -7,140 +7,161 @@ template inline LocalPoolVector::LocalPoolVector( - HasLocalDataPoolIF* hkOwner, lp_id_t poolId, DataSetIF* dataSet, - pool_rwm_t setReadWriteMode): - LocalPoolObjectBase(poolId, hkOwner, dataSet, setReadWriteMode) {} + HasLocalDataPoolIF* hkOwner, lp_id_t poolId, DataSetIF* dataSet, + pool_rwm_t setReadWriteMode): + LocalPoolObjectBase(poolId, hkOwner, dataSet, setReadWriteMode) {} template inline LocalPoolVector::LocalPoolVector(object_id_t poolOwner, - lp_id_t poolId, DataSetIF *dataSet, pool_rwm_t setReadWriteMode): - LocalPoolObjectBase(poolOwner, poolId, dataSet, setReadWriteMode) {} + lp_id_t poolId, DataSetIF *dataSet, pool_rwm_t setReadWriteMode): + LocalPoolObjectBase(poolOwner, poolId, dataSet, setReadWriteMode) {} template inline LocalPoolVector::LocalPoolVector(gp_id_t globalPoolId, - DataSetIF *dataSet, pool_rwm_t setReadWriteMode): - LocalPoolObjectBase(globalPoolId.objectId, globalPoolId.localPoolId, - dataSet, setReadWriteMode) {} + DataSetIF *dataSet, pool_rwm_t setReadWriteMode): + LocalPoolObjectBase(globalPoolId.objectId, globalPoolId.localPoolId, + dataSet, setReadWriteMode) {} template -inline ReturnValue_t LocalPoolVector::read(uint32_t lockTimeout) { - MutexHelper(hkManager->getMutexHandle(), MutexIF::TimeoutType::WAITING, - lockTimeout); - return readWithoutLock(); +inline ReturnValue_t LocalPoolVector::read( + MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) { + MutexHelper(LocalDpManagerAttorney::getMutexHandle(*hkManager), timeoutType, timeoutMs); + return readWithoutLock(); } template inline ReturnValue_t LocalPoolVector::readWithoutLock() { - if(readWriteMode == pool_rwm_t::VAR_WRITE) { - sif::debug << "LocalPoolVar: Invalid read write " - "mode for read() call." << std::endl; - return PoolVariableIF::INVALID_READ_WRITE_MODE; - } + if(readWriteMode == pool_rwm_t::VAR_WRITE) { + object_id_t targetObjectId = hkManager->getCreatorObjectId(); + reportReadCommitError("LocalPoolVector", + PoolVariableIF::INVALID_READ_WRITE_MODE, true, targetObjectId, + localPoolId); + return PoolVariableIF::INVALID_READ_WRITE_MODE; + } - PoolEntry* poolEntry = nullptr; - ReturnValue_t result = hkManager->fetchPoolEntry(localPoolId, &poolEntry); - memset(this->value, 0, vectorSize * sizeof(T)); + PoolEntry* poolEntry = nullptr; + ReturnValue_t result = LocalDpManagerAttorney::fetchPoolEntry(*hkManager, localPoolId, + &poolEntry); + memset(this->value, 0, vectorSize * sizeof(T)); - if(result != RETURN_OK) { - sif::error << "PoolVector: Read of local pool variable of object " - "0x" << std::hex << std::setw(8) << std::setfill('0') << - hkManager->getOwner() << "and lp ID 0x" << localPoolId << - std::dec << " failed." << std::endl; - return result; - } - std::memcpy(this->value, poolEntry->address, poolEntry->getByteSize()); - this->valid = poolEntry->valid; - return RETURN_OK; + if(result != RETURN_OK) { + object_id_t targetObjectId = hkManager->getCreatorObjectId(); + reportReadCommitError("LocalPoolVector", result, true, targetObjectId, + localPoolId); + return result; + } + std::memcpy(this->value, poolEntry->getDataPtr(), poolEntry->getByteSize()); + this->valid = poolEntry->getValid(); + return RETURN_OK; +} + +template +inline ReturnValue_t LocalPoolVector::commit(bool valid, + MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) { + this->setValid(valid); + return commit(timeoutType, timeoutMs); } template inline ReturnValue_t LocalPoolVector::commit( - uint32_t lockTimeout) { - MutexHelper(hkManager->getMutexHandle(), MutexIF::TimeoutType::WAITING, - lockTimeout); - return commitWithoutLock(); + MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) { + MutexHelper(LocalDpManagerAttorney::getMutexHandle(*hkManager), timeoutType, timeoutMs); + return commitWithoutLock(); } template inline ReturnValue_t LocalPoolVector::commitWithoutLock() { - if(readWriteMode == pool_rwm_t::VAR_READ) { - sif::debug << "LocalPoolVar: Invalid read write " - "mode for commit() call." << std::endl; - return PoolVariableIF::INVALID_READ_WRITE_MODE; - } - PoolEntry* poolEntry = nullptr; - ReturnValue_t result = hkManager->fetchPoolEntry(localPoolId, &poolEntry); - if(result != RETURN_OK) { - sif::error << "PoolVector: Read of local pool variable of object " - "0x" << std::hex << std::setw(8) << std::setfill('0') << - hkManager->getOwner() << " and lp ID 0x" << localPoolId << - std::dec << " failed.\n" << std::flush; - return result; - } - std::memcpy(poolEntry->address, this->value, poolEntry->getByteSize()); - poolEntry->valid = this->valid; - return RETURN_OK; + if(readWriteMode == pool_rwm_t::VAR_READ) { + object_id_t targetObjectId = hkManager->getCreatorObjectId(); + reportReadCommitError("LocalPoolVector", + PoolVariableIF::INVALID_READ_WRITE_MODE, false, targetObjectId, + localPoolId); + return PoolVariableIF::INVALID_READ_WRITE_MODE; + } + PoolEntry* poolEntry = nullptr; + ReturnValue_t result = LocalDpManagerAttorney::fetchPoolEntry(*hkManager, localPoolId, + &poolEntry); + if(result != RETURN_OK) { + object_id_t targetObjectId = hkManager->getCreatorObjectId(); + reportReadCommitError("LocalPoolVector", result, false, targetObjectId, + localPoolId); + return result; + } + std::memcpy(poolEntry->getDataPtr(), this->value, poolEntry->getByteSize()); + poolEntry->setValid(this->valid); + return RETURN_OK; } template -inline T& LocalPoolVector::operator [](int i) { - if(i <= vectorSize) { - return value[i]; - } - // If this happens, I have to set some value. I consider this - // a configuration error, but I wont exit here. - sif::error << "LocalPoolVector: Invalid index. Setting or returning" - " last value!" << std::endl; - return value[i]; +inline T& LocalPoolVector::operator [](size_t i) { + if(i < vectorSize) { + return value[i]; + } + // If this happens, I have to set some value. I consider this + // a configuration error, but I wont exit here. +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "LocalPoolVector: Invalid index. Setting or returning" + " last value!" << std::endl; +#else + sif::printWarning("LocalPoolVector: Invalid index. Setting or returning" + " last value!\n"); +#endif + return value[vectorSize - 1]; } template -inline const T& LocalPoolVector::operator [](int i) const { - if(i <= vectorSize) { - return value[i]; - } - // If this happens, I have to set some value. I consider this - // a configuration error, but I wont exit here. - sif::error << "LocalPoolVector: Invalid index. Setting or returning" - " last value!" << std::endl; - return value[i]; +inline const T& LocalPoolVector::operator [](size_t i) const { + if(i < vectorSize) { + return value[i]; + } + // If this happens, I have to set some value. I consider this + // a configuration error, but I wont exit here. +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "LocalPoolVector: Invalid index. Setting or returning" + " last value!" << std::endl; +#else + sif::printWarning("LocalPoolVector: Invalid index. Setting or returning" + " last value!\n"); +#endif + return value[vectorSize - 1]; } template inline ReturnValue_t LocalPoolVector::serialize(uint8_t** buffer, - size_t* size, size_t maxSize, - SerializeIF::Endianness streamEndianness) const { - ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; - for (uint16_t i = 0; i < vectorSize; i++) { - result = SerializeAdapter::serialize(&(value[i]), buffer, size, - maxSize, streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - break; - } - } - return result; + size_t* size, size_t maxSize, + SerializeIF::Endianness streamEndianness) const { + ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; + for (uint16_t i = 0; i < vectorSize; i++) { + result = SerializeAdapter::serialize(&(value[i]), buffer, size, + maxSize, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + break; + } + } + return result; } template inline size_t LocalPoolVector::getSerializedSize() const { - return vectorSize * SerializeAdapter::getSerializedSize(value); + return vectorSize * SerializeAdapter::getSerializedSize(value); } template inline ReturnValue_t LocalPoolVector::deSerialize( - const uint8_t** buffer, size_t* size, - SerializeIF::Endianness streamEndianness) { - ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; - for (uint16_t i = 0; i < vectorSize; i++) { - result = SerializeAdapter::deSerialize(&(value[i]), buffer, size, - streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - break; - } - } - return result; + const uint8_t** buffer, size_t* size, + SerializeIF::Endianness streamEndianness) { + ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; + for (uint16_t i = 0; i < vectorSize; i++) { + result = SerializeAdapter::deSerialize(&(value[i]), buffer, size, + streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + break; + } + } + return result; } +#if FSFW_CPP_OSTREAM_ENABLED == 1 template inline std::ostream& operator<< (std::ostream &out, const LocalPoolVector &var) { @@ -154,5 +175,6 @@ inline std::ostream& operator<< (std::ostream &out, out << "]"; return out; } +#endif #endif /* FSFW_DATAPOOLLOCAL_LOCALPOOLVECTOR_TPP_ */ diff --git a/datapoollocal/ProvidesDataPoolSubscriptionIF.h b/datapoollocal/ProvidesDataPoolSubscriptionIF.h new file mode 100644 index 00000000..a0d73b93 --- /dev/null +++ b/datapoollocal/ProvidesDataPoolSubscriptionIF.h @@ -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_ */ diff --git a/datapoollocal/SharedLocalDataSet.h b/datapoollocal/SharedLocalDataSet.h index 2e5a76fa..83f2a72f 100644 --- a/datapoollocal/SharedLocalDataSet.h +++ b/datapoollocal/SharedLocalDataSet.h @@ -6,7 +6,15 @@ #include "../objectmanager/SystemObject.h" #include -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 SharedDataSetIF { public: diff --git a/datapoollocal/StaticLocalDataSet.h b/datapoollocal/StaticLocalDataSet.h index a637e360..0e51fb5b 100644 --- a/datapoollocal/StaticLocalDataSet.h +++ b/datapoollocal/StaticLocalDataSet.h @@ -20,26 +20,24 @@ template class StaticLocalDataSet: public LocalPoolDataSetBase { public: - /** - * Constructor used by data owner and creator like device handlers. - * This constructor also initialized the components required for - * periodic handling. - * @param hkOwner - * @param setId - */ - StaticLocalDataSet(HasLocalDataPoolIF* hkOwner, - uint32_t setId): LocalPoolDataSetBase(hkOwner, setId, nullptr, - NUM_VARIABLES) { + /** + * Constructor used by data owner and creator like device handlers. + * This constructor also initialized the components required for + * periodic handling. + * @param hkOwner + * @param setId + */ + StaticLocalDataSet(HasLocalDataPoolIF* hkOwner, uint32_t setId): + LocalPoolDataSetBase(hkOwner, setId, nullptr, NUM_VARIABLES) { this->setContainer(poolVarList.data()); } - /** - * Constructor used by data users like controllers. - * @param hkOwner - * @param setId - */ - StaticLocalDataSet(sid_t sid): LocalPoolDataSetBase(sid, nullptr, - NUM_VARIABLES) { + /** + * Constructor used by data users like controllers. + * @param hkOwner + * @param setId + */ + StaticLocalDataSet(sid_t sid): LocalPoolDataSetBase(sid, nullptr, NUM_VARIABLES) { this->setContainer(poolVarList.data()); } diff --git a/datapoollocal/internal/CMakeLists.txt b/datapoollocal/internal/CMakeLists.txt new file mode 100644 index 00000000..554f3b88 --- /dev/null +++ b/datapoollocal/internal/CMakeLists.txt @@ -0,0 +1,5 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + HasLocalDpIFUserAttorney.cpp + HasLocalDpIFManagerAttorney.cpp +) diff --git a/datapoollocal/internal/HasLocalDpIFManagerAttorney.cpp b/datapoollocal/internal/HasLocalDpIFManagerAttorney.cpp new file mode 100644 index 00000000..65feda75 --- /dev/null +++ b/datapoollocal/internal/HasLocalDpIFManagerAttorney.cpp @@ -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(); +} diff --git a/datapoollocal/internal/HasLocalDpIFManagerAttorney.h b/datapoollocal/internal/HasLocalDpIFManagerAttorney.h new file mode 100644 index 00000000..dfe333a6 --- /dev/null +++ b/datapoollocal/internal/HasLocalDpIFManagerAttorney.h @@ -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_ */ diff --git a/datapoollocal/internal/HasLocalDpIFUserAttorney.cpp b/datapoollocal/internal/HasLocalDpIFUserAttorney.cpp new file mode 100644 index 00000000..838204a7 --- /dev/null +++ b/datapoollocal/internal/HasLocalDpIFUserAttorney.cpp @@ -0,0 +1,7 @@ +#include "HasLocalDpIFUserAttorney.h" +#include "../AccessLocalPoolF.h" +#include "../HasLocalDataPoolIF.h" + +AccessPoolManagerIF* HasLocalDpIFUserAttorney::getAccessorHandle(HasLocalDataPoolIF *clientIF) { + return clientIF->getAccessorHandle(); +} diff --git a/datapoollocal/internal/HasLocalDpIFUserAttorney.h b/datapoollocal/internal/HasLocalDpIFUserAttorney.h new file mode 100644 index 00000000..77eaa8bd --- /dev/null +++ b/datapoollocal/internal/HasLocalDpIFUserAttorney.h @@ -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_ */ diff --git a/datapoollocal/internal/LocalDpManagerAttorney.h b/datapoollocal/internal/LocalDpManagerAttorney.h new file mode 100644 index 00000000..bb64fb42 --- /dev/null +++ b/datapoollocal/internal/LocalDpManagerAttorney.h @@ -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 static ReturnValue_t fetchPoolEntry(LocalDataPoolManager& manager, + lp_id_t localPoolId, PoolEntry **poolEntry) { + return manager.fetchPoolEntry(localPoolId, poolEntry); + } + + static MutexIF* getMutexHandle(LocalDataPoolManager& manager) { + return manager.getMutexHandle(); + } + + + template friend class LocalPoolVariable; + template friend class LocalPoolVector; +}; + +#endif /* FSFW_DATAPOOLLOCAL_LOCALDPMANAGERATTORNEY_H_ */ diff --git a/datapoollocal/internal/LocalPoolDataSetAttorney.h b/datapoollocal/internal/LocalPoolDataSetAttorney.h new file mode 100644 index 00000000..7a34e9c8 --- /dev/null +++ b/datapoollocal/internal/LocalPoolDataSetAttorney.h @@ -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_ */ diff --git a/datapoollocal/locPoolDefinitions.h b/datapoollocal/localPoolDefinitions.h similarity index 51% rename from datapoollocal/locPoolDefinitions.h rename to datapoollocal/localPoolDefinitions.h index 6e74d349..ff44fb8e 100644 --- a/datapoollocal/locPoolDefinitions.h +++ b/datapoollocal/localPoolDefinitions.h @@ -1,10 +1,13 @@ -#ifndef FSFW_DATAPOOLLOCAL_LOCPOOLDEFINITIONS_H_ -#define FSFW_DATAPOOLLOCAL_LOCPOOLDEFINITIONS_H_ +#ifndef FSFW_DATAPOOLLOCAL_LOCALPOOLDEFINITIONS_H_ +#define FSFW_DATAPOOLLOCAL_LOCALPOOLDEFINITIONS_H_ -#include +#include "../datapool/PoolEntryIF.h" #include "../objectmanager/SystemObjectIF.h" #include "../objectmanager/frameworkObjects.h" +#include +#include + /** * @brief Type definition for local pool entries. */ @@ -12,10 +15,21 @@ using lp_id_t = uint32_t; namespace localpool { 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; +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 { static constexpr uint64_t INVALID_SID = -1; @@ -26,8 +40,8 @@ union sid_t { sid_t(): raw(INVALID_SID) {} sid_t(object_id_t objectId, uint32_t setId): - objectId(objectId), - ownerSetId(setId) {} + objectId(objectId), + ownerSetId(setId) {} struct { 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 { - 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_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): - objectId(objectId), - localPoolId(localPoolId) {} + gp_id_t(object_id_t objectId, lp_id_t localPoolId): + objectId(objectId), + localPoolId(localPoolId) {} - struct { - object_id_t objectId; - lp_id_t localPoolId; - }; + struct { + object_id_t objectId; + lp_id_t localPoolId; + }; - uint64_t raw; + uint64_t raw; - bool notSet() const { - return raw == INVALID_GPID; - } + bool notSet() const { + return raw == INVALID_GPID; + } bool operator==(const sid_t& other) const { return raw == other.raw; @@ -90,4 +105,4 @@ union gp_id_t { } }; -#endif /* FSFW_DATAPOOLLOCAL_LOCPOOLDEFINITIONS_H_ */ +#endif /* FSFW_DATAPOOLLOCAL_LOCALPOOLDEFINITIONS_H_ */ diff --git a/defaultcfg/fsfwconfig/CMakeLists.txt b/defaultcfg/fsfwconfig/CMakeLists.txt index b8b41c93..cbd4ecde 100644 --- a/defaultcfg/fsfwconfig/CMakeLists.txt +++ b/defaultcfg/fsfwconfig/CMakeLists.txt @@ -1,15 +1,15 @@ -target_sources(${TARGET_NAME} - PRIVATE +target_sources(${LIB_FSFW_NAME} PRIVATE + ipc/missionMessageTypes.cpp + objects/FsfwFactory.cpp + pollingsequence/PollingSequenceFactory.cpp ) -# Add include paths for the executable -target_include_directories(${TARGET_NAME} - PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR} +# Should be added to include path +target_include_directories(${TARGET_NAME} PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} ) -# Add include paths for the FSFW library -target_include_directories(${LIB_FSFW_NAME} - PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR} -) \ No newline at end of file +if(NOT FSFW_CONFIG_PATH) + set(FSFW_CONFIG_PATH ${CMAKE_CURRENT_SOURCE_DIR}) +endif() + diff --git a/defaultcfg/fsfwconfig/FSFWConfig.h b/defaultcfg/fsfwconfig/FSFWConfig.h index e1815d05..ed86e6e1 100644 --- a/defaultcfg/fsfwconfig/FSFWConfig.h +++ b/defaultcfg/fsfwconfig/FSFWConfig.h @@ -4,16 +4,21 @@ #include #include -//! Used to determine whether C++ ostreams are used -//! Those can lead to code bloat. +//! Used to determine whether C++ ostreams are used which can increase +//! the binary size significantly. If this is disabled, +//! the C stdio functions can be used alternatively #define FSFW_CPP_OSTREAM_ENABLED 1 -//! Reduced printout to further decrease code size -//! Be careful, this also turns off most diagnostic prinouts! -#define FSFW_ENHANCED_PRINTOUT 0 +//! More FSFW related printouts depending on level. Useful for development. +#define FSFW_VERBOSE_LEVEL 1 -//! Can be used to enable additional debugging printouts for developing the FSFW -#define FSFW_PRINT_VERBOSITY_LEVEL 0 +//! Can be used to completely disable printouts, even the C stdio ones. +#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, //! 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 //! each CSB service ! static constexpr uint8_t FSFW_CSB_FIFO_DEPTH = 6; + +static constexpr size_t FSFW_PRINT_BUFFER_SIZE = 124; } #endif /* CONFIG_FSFWCONFIG_H_ */ diff --git a/defaultcfg/fsfwconfig/OBSWConfig.h b/defaultcfg/fsfwconfig/OBSWConfig.h index 8ad2cb67..6ed8ea2c 100644 --- a/defaultcfg/fsfwconfig/OBSWConfig.h +++ b/defaultcfg/fsfwconfig/OBSWConfig.h @@ -3,11 +3,12 @@ #include "OBSWVersion.h" +#ifdef __cplusplus + #include "objects/systemObjectList.h" #include "events/subsystemIdRanges.h" #include "returnvalues/classIds.h" -#ifdef __cplusplus namespace config { #endif diff --git a/defaultcfg/fsfwconfig/devices/logicalAddresses.h b/defaultcfg/fsfwconfig/devices/logicalAddresses.h index e0827ba3..53edcd54 100644 --- a/defaultcfg/fsfwconfig/devices/logicalAddresses.h +++ b/defaultcfg/fsfwconfig/devices/logicalAddresses.h @@ -2,7 +2,7 @@ #define CONFIG_DEVICES_LOGICALADDRESSES_H_ #include -#include "../objects/systemObjectList.h" +#include #include /** diff --git a/defaultcfg/fsfwconfig/objects/Factory.cpp b/defaultcfg/fsfwconfig/objects/FsfwFactory.cpp similarity index 60% rename from defaultcfg/fsfwconfig/objects/Factory.cpp rename to defaultcfg/fsfwconfig/objects/FsfwFactory.cpp index 41333b1c..428adf1d 100644 --- a/defaultcfg/fsfwconfig/objects/Factory.cpp +++ b/defaultcfg/fsfwconfig/objects/FsfwFactory.cpp @@ -1,9 +1,5 @@ -#include "Factory.h" -#include "../tmtc/apid.h" -#include "../tmtc/pusIds.h" -#include "../objects/systemObjectList.h" -#include "../devices/logicalAddresses.h" -#include "../devices/powerSwitcherList.h" +#include "FsfwFactory.h" +#include #include #include @@ -11,24 +7,27 @@ #include #include #include -#include +#include #include /** - * This class should be used to create all system objects required for - * the on-board software, using the object ID list from the configuration - * folder. + * This function builds all system objects required for using + * the FSFW. It is recommended to build all other required objects + * 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. - * This is used later to add objects to tasks. + * All system objects are registered in the internal object manager + * 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 */ -void Factory::produce(void) { +void Factory::produceFsfwObjects(void) { setStaticFrameworkObjectIds(); new EventManager(objects::EVENT_MANAGER); new HealthTable(objects::HEALTH_TABLE); diff --git a/defaultcfg/fsfwconfig/objects/Factory.h b/defaultcfg/fsfwconfig/objects/FsfwFactory.h similarity index 61% rename from defaultcfg/fsfwconfig/objects/Factory.h rename to defaultcfg/fsfwconfig/objects/FsfwFactory.h index fe55deff..198b22f2 100644 --- a/defaultcfg/fsfwconfig/objects/Factory.h +++ b/defaultcfg/fsfwconfig/objects/FsfwFactory.h @@ -1,5 +1,5 @@ -#ifndef FACTORY_H_ -#define FACTORY_H_ +#ifndef FSFWCONFIG_OBJECTS_FACTORY_H_ +#define FSFWCONFIG_OBJECTS_FACTORY_H_ #include #include @@ -9,9 +9,9 @@ namespace Factory { * @brief Creates all SystemObject elements which are persistent * during execution. */ - void produce(); + void produceFsfwObjects(); void setStaticFrameworkObjectIds(); } -#endif /* FACTORY_H_ */ +#endif /* FSFWCONFIG_OBJECTS_FACTORY_H_ */ diff --git a/defaultcfg/fsfwconfig/pollingsequence/PollingSequenceFactory.cpp b/defaultcfg/fsfwconfig/pollingsequence/PollingSequenceFactory.cpp index f836a746..b7f1fb3e 100644 --- a/defaultcfg/fsfwconfig/pollingsequence/PollingSequenceFactory.cpp +++ b/defaultcfg/fsfwconfig/pollingsequence/PollingSequenceFactory.cpp @@ -15,8 +15,10 @@ ReturnValue_t pst::pollingSequenceInitDefault( return HasReturnvaluesIF::RETURN_OK; } else { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "pst::pollingSequenceInitDefault: Sequence invalid!" << std::endl; +#endif return HasReturnvaluesIF::RETURN_FAILED; } } diff --git a/devicehandlers/DeviceHandlerBase.cpp b/devicehandlers/DeviceHandlerBase.cpp index d0630854..6092a89f 100644 --- a/devicehandlers/DeviceHandlerBase.cpp +++ b/devicehandlers/DeviceHandlerBase.cpp @@ -2,7 +2,7 @@ #include "AcceptsDeviceResponsesIF.h" #include "DeviceTmReportingWrapper.h" -#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../serviceinterface/ServiceInterface.h" #include "../objectmanager/ObjectManager.h" #include "../storagemanager/StorageManagerIF.h" #include "../thermal/ThermalComponentIF.h" @@ -13,9 +13,6 @@ #include "../subsystem/SubsystemBase.h" #include "../datapoollocal/LocalPoolVariable.h" -#include - - object_id_t DeviceHandlerBase::powerSwitcherId = objects::NO_OBJECT; object_id_t DeviceHandlerBase::rawDataReceiverId = 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), deviceCommunicationId(deviceCommunication), comCookie(comCookie), healthHelper(this,setObjectId), modeHelper(this), parameterHelper(this), - actionHelper(this, nullptr), hkManager(this, nullptr), + actionHelper(this, nullptr), poolManager(this, nullptr), childTransitionFailure(RETURN_OK), fdirInstance(fdirInstance), hkSwitcher(this), defaultFDIRUsed(fdirInstance == nullptr), switchOffWasReported(false), childTransitionDelay(5000), @@ -39,11 +36,8 @@ DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, cookieInfo.state = COOKIE_UNUSED; cookieInfo.pendingCommand = deviceCommandMap.end(); if (comCookie == nullptr) { - sif::error << "DeviceHandlerBase: ObjectID 0x" << std::hex - << std::setw(8) << std::setfill('0') << this->getObjectId() - << std::dec << ": Do not pass nullptr as a cookie, consider " - << std::setfill(' ') << "passing a dummy cookie instead!" - << std::endl; + printWarningOrError(sif::OutputTypes::OUT_ERROR, "DeviceHandlerBase", + HasReturnvaluesIF::RETURN_FAILED, "Invalid cookie"); } if (this->fdirInstance == nullptr) { this->fdirInstance = new DeviceHandlerFailureIsolation(setObjectId, @@ -113,7 +107,7 @@ ReturnValue_t DeviceHandlerBase::performOperation(uint8_t counter) { doGetRead(); // This will be performed after datasets have been updated by the // custom device implementation. - hkManager.performHkOperation(); + poolManager.performHkOperation(); break; default: break; @@ -130,24 +124,24 @@ ReturnValue_t DeviceHandlerBase::initialize() { communicationInterface = objectManager->get( deviceCommunicationId); if (communicationInterface == nullptr) { - sif::error << "DeviceHandlerBase::initialize: Communication interface " - "invalid." << std::endl; - sif::error << "Make sure it is set up properly and implements" - " DeviceCommunicationIF" << std::endl; + printWarningOrError(sif::OutputTypes::OUT_ERROR, "initialize", + ObjectManagerIF::CHILD_INIT_FAILED, + "Passed communication IF invalid"); return ObjectManagerIF::CHILD_INIT_FAILED; } result = communicationInterface->initializeInterface(comCookie); if (result != RETURN_OK) { - sif::error << "DeviceHandlerBase::initialize: Initializing " - "communication interface failed!" << std::endl; + printWarningOrError(sif::OutputTypes::OUT_ERROR, "initialize", + ObjectManagerIF::CHILD_INIT_FAILED, + "ComIF initialization failed"); return result; } IPCStore = objectManager->get(objects::IPC_STORE); if (IPCStore == nullptr) { - sif::error << "DeviceHandlerBase::initialize: IPC store not set up in " - "factory." << std::endl; + printWarningOrError(sif::OutputTypes::OUT_ERROR, "initialize", + ObjectManagerIF::CHILD_INIT_FAILED, "IPC Store not set up"); return ObjectManagerIF::CHILD_INIT_FAILED; } @@ -156,10 +150,16 @@ ReturnValue_t DeviceHandlerBase::initialize() { AcceptsDeviceResponsesIF>(rawDataReceiverId); if (rawReceiver == nullptr) { - sif::error << "DeviceHandlerBase::initialize: Raw receiver object " - "ID set but no valid object found." << std::endl; + printWarningOrError(sif::OutputTypes::OUT_ERROR, + "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" " 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; } defaultRawReceiver = rawReceiver->getDeviceQueue(); @@ -168,10 +168,16 @@ ReturnValue_t DeviceHandlerBase::initialize() { if(powerSwitcherId != objects::NO_OBJECT) { powerSwitcher = objectManager->get(powerSwitcherId); if (powerSwitcher == nullptr) { - sif::error << "DeviceHandlerBase::initialize: Power switcher " - << "object ID set but no valid object found." << std::endl; - sif::error << "Make sure the raw receiver object is set up properly" - << " and implements PowerSwitchIF" << std::endl; + printWarningOrError(sif::OutputTypes::OUT_ERROR, + "initialize", ObjectManagerIF::CHILD_INIT_FAILED, + "Power switcher set but no valid object found."); +#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; } } @@ -204,7 +210,7 @@ ReturnValue_t DeviceHandlerBase::initialize() { return result; } - result = hkManager.initialize(commandQueue); + result = poolManager.initialize(commandQueue); if (result != HasReturnvaluesIF::RETURN_OK) { return result; } @@ -217,7 +223,8 @@ ReturnValue_t DeviceHandlerBase::initialize() { if(result == HasReturnvaluesIF::RETURN_OK) { thermalSet->heaterRequest.value = ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL; - thermalSet->commit(PoolVariableIF::VALID); + thermalSet->heaterRequest.setValid(true); + thermalSet->commit(); } } @@ -273,7 +280,7 @@ void DeviceHandlerBase::readCommandQueue() { return; } - result = hkManager.handleHousekeepingMessage(&command); + result = poolManager.handleHousekeepingMessage(&command); if (result == RETURN_OK) { return; } @@ -543,17 +550,17 @@ void DeviceHandlerBase::replyReturnvalueToCommand(ReturnValue_t status, void DeviceHandlerBase::replyToCommand(ReturnValue_t status, 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 (status == NO_REPLY_EXPECTED) { status = RETURN_OK; } replyReturnvalueToCommand(status, parameter); - //Always delete data from a raw command. + // Always delete data from a raw command. IPCStore->deleteData(storedRawData); return; } -//Check if we were externally commanded. + // Check if we were externally commanded. if (cookieInfo.pendingCommand->second.sendReplyTo != NO_COMMANDER) { MessageQueueId_t queueId = cookieInfo.pendingCommand->second.sendReplyTo; if (status == NO_REPLY_EXPECTED) { @@ -568,15 +575,17 @@ void DeviceHandlerBase::replyToCommand(ReturnValue_t status, void DeviceHandlerBase::replyToReply(DeviceReplyMap::iterator iter, 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()) { //Is most likely periodic reply. Silent 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); 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) { actionHelper.finish(info->sendReplyTo, iter->first, status); } @@ -593,7 +602,7 @@ void DeviceHandlerBase::doSendWrite() { if (result == RETURN_OK) { cookieInfo.state = COOKIE_WRITE_SENT; } 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, cookieInfo.pendingCommand->first); replyToCommand(result); @@ -682,8 +691,10 @@ void DeviceHandlerBase::doGetRead() { replyRawData(receivedData, receivedDataLen, requestedRawTraffic); } - if (mode == MODE_RAW and defaultRawReceiver != MessageQueueIF::NO_QUEUE) { - replyRawReplyIfnotWiretapped(receivedData, receivedDataLen); + if (mode == MODE_RAW) { + if (defaultRawReceiver != MessageQueueIF::NO_QUEUE) { + replyRawReplyIfnotWiretapped(receivedData, receivedDataLen); + } } else { parseReply(receivedData, receivedDataLen); @@ -706,8 +717,9 @@ void DeviceHandlerBase::parseReply(const uint8_t* receivedData, case RETURN_OK: handleReply(receivedData, foundId, foundLen); if(foundLen == 0) { - sif::warning << "DeviceHandlerBase::parseReply: foundLen is 0!" - " Packet parsing will be stuck." << std::endl; + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "parseReply", ObjectManagerIF::CHILD_INIT_FAILED, + "Found length is one, parsing might be stuck"); } break; case APERIODIC_REPLY: { @@ -718,8 +730,13 @@ void DeviceHandlerBase::parseReply(const uint8_t* receivedData, foundId); } 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!" " Packet parsing will be stuck." << std::endl; +#endif } break; } @@ -728,7 +745,8 @@ void DeviceHandlerBase::parseReply(const uint8_t* receivedData, case IGNORE_FULL_PACKET: return; 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); triggerEvent(DEVICE_READING_REPLY_FAILED, result, foundLen); break; @@ -949,7 +967,8 @@ ReturnValue_t DeviceHandlerBase::getStateOfSwitches(void) { } 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) { return _MODE_TO_ON; } @@ -1272,10 +1291,11 @@ void DeviceHandlerBase::buildInternalCommand(void) { if (mode == MODE_NORMAL) { result = buildNormalDeviceCommand(&deviceCommandId); if (result == BUSY) { - //so we can track misconfigurations - sif::debug << std::hex << getObjectId() - << ": DHB::buildInternalCommand: Busy" << std::dec - << std::endl; + // so we can track misconfigurations + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "buildInternalCommand", + HasReturnvaluesIF::RETURN_FAILED, + "Busy."); result = NOTHING_TO_SEND; //no need to report this } } @@ -1299,11 +1319,16 @@ void DeviceHandlerBase::buildInternalCommand(void) { if (iter == deviceCommandMap.end()) { result = COMMAND_NOT_SUPPORTED; } else if (iter->second.isExecuting) { - //so we can track misconfigurations - sif::debug << std::hex << getObjectId() - << ": DHB::buildInternalCommand: Command " - << deviceCommandId << " isExecuting" << std::dec - << std::endl; +#if FSFW_DISABLE_PRINTOUT == 0 + char output[36]; + sprintf(output, "Command 0x%08x is executing", + static_cast(deviceCommandId)); + // 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, // missed reply will track if a reply is too late, otherwise, it's ok return; @@ -1396,7 +1421,7 @@ void DeviceHandlerBase::performOperationHook() { } ReturnValue_t DeviceHandlerBase::initializeLocalDataPool( - LocalDataPool &localDataPoolMap, + localpool::DataPool &localDataPoolMap, LocalDataPoolManager& poolManager) { if(thermalSet != nullptr) { localDataPoolMap.emplace(thermalSet->thermalStatePoolId, @@ -1407,18 +1432,13 @@ ReturnValue_t DeviceHandlerBase::initializeLocalDataPool( return RETURN_OK; } -LocalDataPoolManager* DeviceHandlerBase::getHkManagerHandle() { - return &hkManager; -} - - ReturnValue_t DeviceHandlerBase::initializeAfterTaskCreation() { // In this function, the task handle should be valid if the task // was implemented correctly. We still check to be 1000 % sure :-) if(executingTask != nullptr) { pstIntervalMs = executingTask->getPeriodMs(); } - this->hkManager.initializeAfterTaskCreation(); + this->poolManager.initializeAfterTaskCreation(); if(setStartupImmediately) { 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; +} diff --git a/devicehandlers/DeviceHandlerBase.h b/devicehandlers/DeviceHandlerBase.h index 24ba0372..3a993aff 100644 --- a/devicehandlers/DeviceHandlerBase.h +++ b/devicehandlers/DeviceHandlerBase.h @@ -6,6 +6,8 @@ #include "DeviceHandlerFailureIsolation.h" #include "DeviceHandlerThermalSet.h" +#include "../serviceinterface/ServiceInterface.h" +#include "../serviceinterface/serviceInterfaceDefintions.h" #include "../objectmanager/SystemObject.h" #include "../tasks/ExecutableObjectIF.h" #include "../returnvalues/HasReturnvaluesIF.h" @@ -512,11 +514,14 @@ protected: * @param localDataPoolMap * @return */ - virtual ReturnValue_t initializeLocalDataPool(LocalDataPool& localDataPoolMap, + virtual ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap, 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 @@ -646,7 +651,7 @@ protected: /** Action helper for HasActionsIF */ ActionHelper actionHelper; /** Housekeeping Manager */ - LocalDataPoolManager hkManager; + LocalDataPoolManager poolManager; /** * @brief Information about commands @@ -1111,7 +1116,7 @@ private: /** * @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!! * (it is _MODE_POWER_DOWN during this modes) @@ -1190,7 +1195,8 @@ private: * Check if the RMAP sendWrite action was successful. * * 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 */ void doGetWrite(void); @@ -1206,9 +1212,9 @@ private: /** * Check the getRead reply and the contained data. * - * If data was received scanForReply() and, if successful, handleReply() are called. - * If the current mode is @c MODE_RAW, the received packet is sent to the commanding object - * via commandQueue. + * If data was received scanForReply() and, if successful, handleReply() + * are called. If the current mode is @c MODE_RAW, the received packet + * is sent to the commanding object via commandQueue. */ void doGetRead(void); @@ -1227,7 +1233,7 @@ private: 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); @@ -1247,6 +1253,11 @@ private: void handleTransitionToOnMode(Mode_t commandedMode, 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_ */ diff --git a/devicehandlers/DeviceHandlerFailureIsolation.cpp b/devicehandlers/DeviceHandlerFailureIsolation.cpp index 9d0535bf..5f7ab89f 100644 --- a/devicehandlers/DeviceHandlerFailureIsolation.cpp +++ b/devicehandlers/DeviceHandlerFailureIsolation.cpp @@ -169,8 +169,10 @@ void DeviceHandlerFailureIsolation::clearFaultCounters() { ReturnValue_t DeviceHandlerFailureIsolation::initialize() { ReturnValue_t result = FailureIsolationBase::initialize(); if (result != HasReturnvaluesIF::RETURN_OK) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "DeviceHandlerFailureIsolation::initialize: Could not" " initialize FailureIsolationBase." << std::endl; +#endif return result; } ConfirmsFailuresIF* power = objectManager->get( @@ -250,8 +252,10 @@ bool DeviceHandlerFailureIsolation::isFdirInActionOrAreWeFaulty( if (owner == nullptr) { // Configuration error. +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "DeviceHandlerFailureIsolation::" << "isFdirInActionOrAreWeFaulty: Owner not set!" << std::endl; +#endif return false; } diff --git a/devicehandlers/DeviceHandlerIF.h b/devicehandlers/DeviceHandlerIF.h index 865b38b3..fc31cce0 100644 --- a/devicehandlers/DeviceHandlerIF.h +++ b/devicehandlers/DeviceHandlerIF.h @@ -3,8 +3,8 @@ #include "DeviceHandlerMessage.h" +#include "../datapoollocal/localPoolDefinitions.h" #include "../action/HasActionsIF.h" -#include "../datapoollocal/locPoolDefinitions.h" #include "../events/Event.h" #include "../modes/HasModesIF.h" #include "../ipc/MessageQueueSenderIF.h" diff --git a/doc/README-controllers.md b/doc/README-controllers.md new file mode 100644 index 00000000..7af0652d --- /dev/null +++ b/doc/README-controllers.md @@ -0,0 +1 @@ +## Controllers diff --git a/doc/README-core.md b/doc/README-core.md index c47ae0f2..6431b831 100644 --- a/doc/README-core.md +++ b/doc/README-core.md @@ -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 nullptr check of the returning Pointer must be done. This function is based on Run-time type information. -``` c++ - template T* ObjectManagerIF::get( object_id_t id ) - +```cpp +template T* ObjectManagerIF::get( object_id_t id ) ``` * A typical way to create all objects on startup is a handing a static produce function to the ObjectManager on creation. By calling objectManager->initialize() the produce function will be called and all SystemObjects will be initialized afterwards. diff --git a/doc/README-devicehandlers.md b/doc/README-devicehandlers.md index 6e737cc5..8b6551aa 100644 --- a/doc/README-devicehandlers.md +++ b/doc/README-devicehandlers.md @@ -1 +1 @@ -## FSFW DeviceHandlers \ No newline at end of file +## Device Handlers diff --git a/doc/README-highlevel.md b/doc/README-highlevel.md new file mode 100644 index 00000000..fac89c53 --- /dev/null +++ b/doc/README-highlevel.md @@ -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) diff --git a/doc/README-localpools.md b/doc/README-localpools.md new file mode 100644 index 00000000..8dd83385 --- /dev/null +++ b/doc/README-localpools.md @@ -0,0 +1,3 @@ +## Local Data Pools + + diff --git a/doc/README-osal.md b/doc/README-osal.md new file mode 100644 index 00000000..6f8ce60f --- /dev/null +++ b/doc/README-osal.md @@ -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. + + diff --git a/doc/README-pus.md b/doc/README-pus.md new file mode 100644 index 00000000..928d2eda --- /dev/null +++ b/doc/README-pus.md @@ -0,0 +1 @@ +## PUS Services diff --git a/events/EventManager.cpp b/events/EventManager.cpp index 6cc97eb6..e25e574f 100644 --- a/events/EventManager.cpp +++ b/events/EventManager.cpp @@ -122,6 +122,7 @@ void EventManager::printEvent(EventMessage* message) { case severity::INFO: #if DEBUG_INFO_EVENT == 1 string = translateObject(message->getReporter()); +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::info << "EVENT: "; if (string != 0) { sif::info << string; @@ -132,10 +133,12 @@ void EventManager::printEvent(EventMessage* message) { << std::dec << message->getEventId() << std::hex << ") P1: 0x" << message->getParameter1() << " P2: 0x" << message->getParameter2() << std::dec << std::endl; -#endif +#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ +#endif /* DEBUG_INFO_EVENT == 1 */ break; default: string = translateObject(message->getReporter()); +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::debug << "EventManager: "; if (string != 0) { sif::debug << string; @@ -146,22 +149,28 @@ void EventManager::printEvent(EventMessage* message) { sif::debug << " reported " << translateEvents(message->getEvent()) << " (" << std::dec << message->getEventId() << ") " << std::endl; - sif::debug << std::hex << "P1 Hex: 0x" << message->getParameter1() << ", P1 Dec: " << std::dec << message->getParameter1() << std::endl; sif::debug << std::hex << "P2 Hex: 0x" << message->getParameter2() << ", P2 Dec: " << std::dec << message->getParameter2() << std::endl; +#endif break; } } #endif void EventManager::lockMutex() { - mutex->lockMutex(MutexIF::BLOCKING); + mutex->lockMutex(timeoutType, timeoutMs); } void EventManager::unlockMutex() { mutex->unlockMutex(); } + +void EventManager::setMutexTimeout(MutexIF::TimeoutType timeoutType, + uint32_t timeoutMs) { + this->timeoutType = timeoutType; + this->timeoutMs = timeoutMs; +} diff --git a/events/EventManager.h b/events/EventManager.h index c6bd07be..abce9b8b 100644 --- a/events/EventManager.h +++ b/events/EventManager.h @@ -29,6 +29,8 @@ public: EventManager(object_id_t setObjectId); virtual ~EventManager(); + void setMutexTimeout(MutexIF::TimeoutType timeoutType, uint32_t timeoutMs); + MessageQueueId_t getEventReportQueue(); ReturnValue_t registerListener(MessageQueueId_t listener, bool forwardAllButSelected = false); @@ -51,6 +53,8 @@ protected: std::map listenerList; MutexIF* mutex = nullptr; + MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING; + uint32_t timeoutMs = 20; static const uint8_t N_POOLS = 3; LocalPool factoryBackend; diff --git a/fdir/FailureIsolationBase.cpp b/fdir/FailureIsolationBase.cpp index a04a0313..69cb0f01 100644 --- a/fdir/FailureIsolationBase.cpp +++ b/fdir/FailureIsolationBase.cpp @@ -21,8 +21,10 @@ ReturnValue_t FailureIsolationBase::initialize() { EventManagerIF* manager = objectManager->get( objects::EVENT_MANAGER); if (manager == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "FailureIsolationBase::initialize: Event Manager has not" " been initialized!" << std::endl; +#endif return RETURN_FAILED; } ReturnValue_t result = manager->registerListener(eventQueue->getId()); @@ -36,8 +38,10 @@ ReturnValue_t FailureIsolationBase::initialize() { } owner = objectManager->get(ownerId); if (owner == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "FailureIsolationBase::intialize: Owner object " "invalid. Make sure it implements HasHealthIF" << std::endl; +#endif return ObjectManagerIF::CHILD_INIT_FAILED; } } @@ -45,10 +49,14 @@ ReturnValue_t FailureIsolationBase::initialize() { ConfirmsFailuresIF* parentIF = objectManager->get( faultTreeParent); if (parentIF == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "FailureIsolationBase::intialize: Parent object" << "invalid." << std::endl; +#endif +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "Make sure it implements ConfirmsFailuresIF." << std::endl; +#endif return ObjectManagerIF::CHILD_INIT_FAILED; return RETURN_FAILED; } diff --git a/fsfw.mk b/fsfw.mk index 3df63060..0d72fae1 100644 --- a/fsfw.mk +++ b/fsfw.mk @@ -10,6 +10,7 @@ CXXSRC += $(wildcard $(FRAMEWORK_PATH)/coordinates/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/datalinklayer/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/datapool/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/datapoollocal/*.cpp) +CXXSRC += $(wildcard $(FRAMEWORK_PATH)/datapoollocal/internal/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/housekeeping/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/devicehandlers/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/events/*.cpp) diff --git a/globalfunctions/arrayprinter.cpp b/globalfunctions/arrayprinter.cpp index b1e888c5..25d6fcf4 100644 --- a/globalfunctions/arrayprinter.cpp +++ b/globalfunctions/arrayprinter.cpp @@ -1,13 +1,17 @@ #include "arrayprinter.h" -#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../serviceinterface/ServiceInterface.h" #include void arrayprinter::print(const uint8_t *data, size_t size, OutputType type, bool printInfo, size_t maxCharPerLine) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 if(printInfo) { sif::info << "Printing data with size " << size << ": "; } sif::info << "["; +#else + sif::printInfo("Printing data with size %zu: [", size); +#endif if(type == OutputType::HEX) { 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, size_t maxCharPerLine) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::info << std::hex; for(size_t i = 0; i < size; i++) { sif::info << "0x" << static_cast(data[i]); @@ -28,16 +33,20 @@ void arrayprinter::printHex(const uint8_t *data, size_t size, sif::info << " , "; if(i > 0 and i % maxCharPerLine == 0) { sif::info << std::endl; + } } - } sif::info << std::dec; sif::info << "]" << std::endl; +#else + // how much memory to reserve for printout? +#endif } void arrayprinter::printDec(const uint8_t *data, size_t size, size_t maxCharPerLine) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::info << std::dec; for(size_t i = 0; i < size; i++) { sif::info << static_cast(data[i]); @@ -49,13 +58,20 @@ void arrayprinter::printDec(const uint8_t *data, size_t size, } } sif::info << "]" << std::endl; +#else + // how much memory to reserve for printout? +#endif } void arrayprinter::printBin(const uint8_t *data, size_t size) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::info << "\n" << std::flush; for(size_t i = 0; i < size; i++) { sif::info << "Byte " << i + 1 << ": 0b"<< std::bitset<8>(data[i]) << ",\n" << std::flush; } sif::info << "]" << std::endl; +#else + // how much memory to reserve for printout? +#endif } diff --git a/health/HealthHelper.cpp b/health/HealthHelper.cpp index d574634d..231d616e 100644 --- a/health/HealthHelper.cpp +++ b/health/HealthHelper.cpp @@ -41,14 +41,18 @@ ReturnValue_t HealthHelper::initialize() { eventSender = objectManager->get(objectId); if (healthTable == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "HealthHelper::initialize: Health table object needs" "to be created in factory." << std::endl; +#endif return ObjectManagerIF::CHILD_INIT_FAILED; } if(eventSender == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "HealthHelper::initialize: Owner has to implement " "ReportingProxyIF." << std::endl; +#endif return ObjectManagerIF::CHILD_INIT_FAILED; } @@ -79,8 +83,10 @@ void HealthHelper::informParent(HasHealthIF::HealthState health, health, oldHealth); if (MessageQueueSenderIF::sendMessage(parentQueue, &information, owner->getCommandQueue()) != HasReturnvaluesIF::RETURN_OK) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::debug << "HealthHelper::informParent: sending health reply failed." << std::endl; +#endif } } @@ -98,8 +104,10 @@ void HealthHelper::handleSetHealthCommand(CommandMessage* command) { } if (MessageQueueSenderIF::sendMessage(command->getSender(), &reply, owner->getCommandQueue()) != HasReturnvaluesIF::RETURN_OK) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::debug << "HealthHelper::handleHealthCommand: sending health " "reply failed." << std::endl; +#endif } } diff --git a/health/HealthTableIF.h b/health/HealthTableIF.h index d61e6761..727c4496 100644 --- a/health/HealthTableIF.h +++ b/health/HealthTableIF.h @@ -5,6 +5,8 @@ #include "../objectmanager/ObjectManagerIF.h" #include "../returnvalues/HasReturnvaluesIF.h" +#include + class HealthTableIF: public ManagesHealthIF { public: virtual ~HealthTableIF() {} diff --git a/housekeeping/HousekeepingMessage.h b/housekeeping/HousekeepingMessage.h index 90bbe594..0c7680dc 100644 --- a/housekeeping/HousekeepingMessage.h +++ b/housekeeping/HousekeepingMessage.h @@ -1,7 +1,7 @@ #ifndef FSFW_HOUSEKEEPING_HOUSEKEEPINGMESSAGE_H_ #define FSFW_HOUSEKEEPING_HOUSEKEEPINGMESSAGE_H_ -#include "../datapoollocal/locPoolDefinitions.h" +#include "../datapoollocal/localPoolDefinitions.h" #include "../ipc/CommandMessage.h" #include "../ipc/FwMessageTypes.h" #include "../objectmanager/frameworkObjects.h" diff --git a/internalError/InternalErrorDataset.h b/internalError/InternalErrorDataset.h index fa91116d..bd9062ed 100644 --- a/internalError/InternalErrorDataset.h +++ b/internalError/InternalErrorDataset.h @@ -21,11 +21,11 @@ public: InternalErrorDataset(object_id_t objectId): StaticLocalDataSet(sid_t(objectId , ERROR_SET_ID)) {} - lp_var_t tmHits = lp_var_t(hkManager->getOwner(), + lp_var_t tmHits = lp_var_t(sid.objectId, TM_HITS, this); - lp_var_t queueHits = lp_var_t(hkManager->getOwner(), + lp_var_t queueHits = lp_var_t(sid.objectId, QUEUE_HITS, this); - lp_var_t storeHits = lp_var_t(hkManager->getOwner(), + lp_var_t storeHits = lp_var_t(sid.objectId, STORE_HITS, this); }; diff --git a/internalError/InternalErrorReporter.cpp b/internalError/InternalErrorReporter.cpp index bfb67289..7e5a316c 100644 --- a/internalError/InternalErrorReporter.cpp +++ b/internalError/InternalErrorReporter.cpp @@ -2,7 +2,7 @@ #include "../ipc/QueueFactory.h" #include "../ipc/MutexFactory.h" -#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../serviceinterface/ServiceInterface.h" InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId, uint32_t messageQueueDepth): SystemObject(setObjectId), @@ -23,20 +23,27 @@ void InternalErrorReporter::setDiagnosticPrintout(bool enable) { } ReturnValue_t InternalErrorReporter::performOperation(uint8_t opCode) { - internalErrorDataset.read(INTERNAL_ERROR_MUTEX_TIMEOUT); + internalErrorDataset.read(timeoutType, timeoutMs); uint32_t newQueueHits = getAndResetQueueHits(); uint32_t newTmHits = getAndResetTmHits(); uint32_t newStoreHits = getAndResetStoreHits(); -#ifdef DEBUG +#if FSFW_VERBOSE_LEVEL == 1 if(diagnosticPrintout) { if((newQueueHits > 0) or (newTmHits > 0) or (newStoreHits > 0)) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::debug << "InternalErrorReporter::performOperation: Errors " << "occured!" << std::endl; sif::debug << "Queue errors: " << newQueueHits << std::endl; sif::debug << "TM errors: " << newTmHits << std::endl; sif::debug << "Store errors: " << newStoreHits << std::endl; +#else + sif::printDebug("InternalErrorReporter::performOperation: Errors occured!\n"); + sif::printDebug("Queue errors: %lu\n", static_cast(newQueueHits)); + sif::printDebug("TM errors: %lu\n", static_cast(newTmHits)); + sif::printDebug("Store errors: %lu\n", static_cast(newStoreHits)); +#endif } } #endif @@ -44,8 +51,8 @@ ReturnValue_t InternalErrorReporter::performOperation(uint8_t opCode) { internalErrorDataset.queueHits.value += newQueueHits; internalErrorDataset.storeHits.value += newStoreHits; internalErrorDataset.tmHits.value += newTmHits; - - internalErrorDataset.commit(INTERNAL_ERROR_MUTEX_TIMEOUT); + internalErrorDataset.setValidity(true, true); + internalErrorDataset.commit(timeoutType, timeoutMs); poolManager.performHkOperation(); @@ -67,7 +74,7 @@ void InternalErrorReporter::lostTm() { uint32_t InternalErrorReporter::getAndResetQueueHits() { uint32_t value; - mutex->lockMutex(MutexIF::WAITING, INTERNAL_ERROR_MUTEX_TIMEOUT); + mutex->lockMutex(timeoutType, timeoutMs); value = queueHits; queueHits = 0; mutex->unlockMutex(); @@ -76,21 +83,21 @@ uint32_t InternalErrorReporter::getAndResetQueueHits() { uint32_t InternalErrorReporter::getQueueHits() { uint32_t value; - mutex->lockMutex(MutexIF::WAITING, INTERNAL_ERROR_MUTEX_TIMEOUT); + mutex->lockMutex(timeoutType, timeoutMs); value = queueHits; mutex->unlockMutex(); return value; } void InternalErrorReporter::incrementQueueHits() { - mutex->lockMutex(MutexIF::WAITING, INTERNAL_ERROR_MUTEX_TIMEOUT); + mutex->lockMutex(timeoutType, timeoutMs); queueHits++; mutex->unlockMutex(); } uint32_t InternalErrorReporter::getAndResetTmHits() { uint32_t value; - mutex->lockMutex(MutexIF::WAITING, INTERNAL_ERROR_MUTEX_TIMEOUT); + mutex->lockMutex(timeoutType, timeoutMs); value = tmHits; tmHits = 0; mutex->unlockMutex(); @@ -99,14 +106,14 @@ uint32_t InternalErrorReporter::getAndResetTmHits() { uint32_t InternalErrorReporter::getTmHits() { uint32_t value; - mutex->lockMutex(MutexIF::WAITING, INTERNAL_ERROR_MUTEX_TIMEOUT); + mutex->lockMutex(timeoutType, timeoutMs); value = tmHits; mutex->unlockMutex(); return value; } void InternalErrorReporter::incrementTmHits() { - mutex->lockMutex(MutexIF::WAITING, INTERNAL_ERROR_MUTEX_TIMEOUT); + mutex->lockMutex(timeoutType, timeoutMs); tmHits++; mutex->unlockMutex(); } @@ -117,7 +124,7 @@ void InternalErrorReporter::storeFull() { uint32_t InternalErrorReporter::getAndResetStoreHits() { uint32_t value; - mutex->lockMutex(MutexIF::WAITING, INTERNAL_ERROR_MUTEX_TIMEOUT); + mutex->lockMutex(timeoutType, timeoutMs); value = storeHits; storeHits = 0; mutex->unlockMutex(); @@ -126,14 +133,14 @@ uint32_t InternalErrorReporter::getAndResetStoreHits() { uint32_t InternalErrorReporter::getStoreHits() { uint32_t value; - mutex->lockMutex(MutexIF::WAITING, INTERNAL_ERROR_MUTEX_TIMEOUT); + mutex->lockMutex(timeoutType, timeoutMs); value = storeHits; mutex->unlockMutex(); return value; } void InternalErrorReporter::incrementStoreHits() { - mutex->lockMutex(MutexIF::WAITING, INTERNAL_ERROR_MUTEX_TIMEOUT); + mutex->lockMutex(timeoutType, timeoutMs); storeHits++; mutex->unlockMutex(); } @@ -147,7 +154,7 @@ MessageQueueId_t InternalErrorReporter::getCommandQueue() const { } ReturnValue_t InternalErrorReporter::initializeLocalDataPool( - LocalDataPool &localDataPoolMap, LocalDataPoolManager &poolManager) { + localpool::DataPool &localDataPoolMap, LocalDataPoolManager &poolManager) { localDataPoolMap.emplace(errorPoolIds::TM_HITS, new PoolEntry()); localDataPoolMap.emplace(errorPoolIds::QUEUE_HITS, @@ -160,10 +167,6 @@ ReturnValue_t InternalErrorReporter::initializeLocalDataPool( return HasReturnvaluesIF::RETURN_OK; } -LocalDataPoolManager* InternalErrorReporter::getHkManagerHandle() { - return &poolManager; -} - dur_millis_t InternalErrorReporter::getPeriodicOperationFrequency() const { return this->executingTask->getPeriodMs(); } @@ -188,3 +191,12 @@ ReturnValue_t InternalErrorReporter::initializeAfterTaskCreation() { return poolManager.initializeAfterTaskCreation(); } +void InternalErrorReporter::setMutexTimeout(MutexIF::TimeoutType timeoutType, + uint32_t timeoutMs) { + this->timeoutType = timeoutType; + this->timeoutMs = timeoutMs; +} + +LocalDataPoolManager* InternalErrorReporter::getHkManagerHandle() { + return &poolManager; +} diff --git a/internalError/InternalErrorReporter.h b/internalError/InternalErrorReporter.h index 8d33c06e..a237418e 100644 --- a/internalError/InternalErrorReporter.h +++ b/internalError/InternalErrorReporter.h @@ -22,7 +22,6 @@ class InternalErrorReporter: public SystemObject, public InternalErrorReporterIF, public HasLocalDataPoolIF { public: - static constexpr uint8_t INTERNAL_ERROR_MUTEX_TIMEOUT = 20; InternalErrorReporter(object_id_t setObjectId, uint32_t messageQueueDepth = 5); @@ -34,16 +33,19 @@ public: */ void setDiagnosticPrintout(bool enable); + void setMutexTimeout(MutexIF::TimeoutType timeoutType, + uint32_t timeoutMs); + virtual ~InternalErrorReporter(); virtual object_id_t getObjectId() const override; virtual MessageQueueId_t getCommandQueue() const override; virtual ReturnValue_t initializeLocalDataPool( - LocalDataPool& localDataPoolMap, + localpool::DataPool& localDataPoolMap, LocalDataPoolManager& poolManager) override; - virtual LocalDataPoolManager* getHkManagerHandle() override; virtual dur_millis_t getPeriodicOperationFrequency() const override; virtual LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override; + LocalDataPoolManager* getHkManagerHandle() override; virtual ReturnValue_t initialize() override; virtual ReturnValue_t initializeAfterTaskCreation() override; @@ -61,7 +63,11 @@ protected: LocalDataPoolManager poolManager; PeriodicTaskIF* executingTask = nullptr; + MutexIF* mutex = nullptr; + MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING; + uint32_t timeoutMs = 20; + sid_t internalErrorSid; InternalErrorDataset internalErrorDataset; diff --git a/ipc/MessageQueueMessage.cpp b/ipc/MessageQueueMessage.cpp index dcd4def3..e97778c3 100644 --- a/ipc/MessageQueueMessage.cpp +++ b/ipc/MessageQueueMessage.cpp @@ -15,8 +15,10 @@ MessageQueueMessage::MessageQueueMessage(uint8_t* data, size_t size) : this->messageSize = this->HEADER_SIZE + size; } else { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "MessageQueueMessage: Passed size larger than maximum" "allowed size! Setting content to 0" << std::endl; +#endif memset(this->internalBuffer, 0, sizeof(this->internalBuffer)); this->messageSize = this->HEADER_SIZE; } @@ -52,7 +54,9 @@ void MessageQueueMessage::setSender(MessageQueueId_t setId) { } void MessageQueueMessage::print(bool printWholeMessage) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::debug << "MessageQueueMessage content: " << std::endl; +#endif if(printWholeMessage) { arrayprinter::print(getData(), getMaximumMessageSize()); } diff --git a/ipc/MutexHelper.h b/ipc/MutexHelper.h index 97001ade..befa69bc 100644 --- a/ipc/MutexHelper.h +++ b/ipc/MutexHelper.h @@ -12,12 +12,16 @@ public: ReturnValue_t status = mutex->lockMutex(timeoutType, timeoutMs); if(status == MutexIF::MUTEX_TIMEOUT) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "MutexHelper: Lock of mutex failed with timeout of " << timeoutMs << " milliseconds!" << std::endl; +#endif } else if(status != HasReturnvaluesIF::RETURN_OK){ +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "MutexHelper: Lock of Mutex failed with code " << status << std::endl; +#endif } } diff --git a/ipc/MutexIF.h b/ipc/MutexIF.h index 5673e4d7..084b702b 100644 --- a/ipc/MutexIF.h +++ b/ipc/MutexIF.h @@ -14,7 +14,7 @@ public: /** * Different types of timeout for the mutex lock. */ - enum TimeoutType { + enum class TimeoutType { POLLING, //!< If mutex is not available, return immediately WAITING, //!< Wait a specified time for the mutex to become available BLOCKING //!< Block indefinitely until the mutex becomes available. diff --git a/memory/MemoryHelper.cpp b/memory/MemoryHelper.cpp index 6b11882f..42ac2654 100644 --- a/memory/MemoryHelper.cpp +++ b/memory/MemoryHelper.cpp @@ -16,7 +16,9 @@ ReturnValue_t MemoryHelper::handleMemoryCommand(CommandMessage* message) { lastSender = message->getSender(); lastCommand = message->getCommand(); if (busy) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::debug << "MemHelper: Busy!" << std::endl; +#endif } switch (lastCommand) { case MemoryMessage::CMD_MEMORY_DUMP: diff --git a/monitoring/MonitorReporter.h b/monitoring/MonitorReporter.h index 9028e7e4..7ce110e5 100644 --- a/monitoring/MonitorReporter.h +++ b/monitoring/MonitorReporter.h @@ -5,7 +5,7 @@ #include "MonitoringIF.h" #include "MonitoringMessageContent.h" -#include "../datapoollocal/locPoolDefinitions.h" +#include "../datapoollocal/localPoolDefinitions.h" #include "../events/EventManagerIF.h" #include "../parameters/HasParametersIF.h" diff --git a/monitoring/MonitoringMessageContent.h b/monitoring/MonitoringMessageContent.h index 44d32656..d830e313 100644 --- a/monitoring/MonitoringMessageContent.h +++ b/monitoring/MonitoringMessageContent.h @@ -1,9 +1,10 @@ -#ifndef MONITORINGMESSAGECONTENT_H_ -#define MONITORINGMESSAGECONTENT_H_ +#ifndef FSFW_MONITORING_MONITORINGMESSAGECONTENT_H_ +#define FSFW_MONITORING_MONITORINGMESSAGECONTENT_H_ #include "HasMonitorsIF.h" #include "MonitoringIF.h" -#include "../datapoollocal/locPoolDefinitions.h" + +#include "../datapoollocal/localPoolDefinitions.h" #include "../objectmanager/ObjectManagerIF.h" #include "../serialize/SerialBufferAdapter.h" #include "../serialize/SerialFixedArrayListAdapter.h" @@ -72,8 +73,10 @@ private: if (timeStamper == nullptr) { timeStamper = objectManager->get( timeStamperId ); if ( timeStamper == nullptr ) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "MonitoringReportContent::checkAndSetStamper: " "Stamper not found!" << std::endl; +#endif return false; } } @@ -83,4 +86,4 @@ private: template object_id_t MonitoringReportContent::timeStamperId = 0; -#endif /* MONITORINGMESSAGECONTENT_H_ */ +#endif /* FSFW_MONITORING_MONITORINGMESSAGECONTENT_H_ */ diff --git a/objectmanager/ObjectManager.cpp b/objectmanager/ObjectManager.cpp index 5871bfcd..882d2762 100644 --- a/objectmanager/ObjectManager.cpp +++ b/objectmanager/ObjectManager.cpp @@ -1,6 +1,9 @@ #include "ObjectManager.h" #include "../serviceinterface/ServiceInterfaceStream.h" + +#if FSFW_CPP_OSTREAM_ENABLED == 1 #include +#endif #include ObjectManager::ObjectManager( void (*setProducer)() ): @@ -18,13 +21,18 @@ ObjectManager::~ObjectManager() { ReturnValue_t ObjectManager::insert( object_id_t id, SystemObjectIF* object) { auto returnPair = objectList.emplace(id, object); if (returnPair.second) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 // sif::debug << "ObjectManager::insert: Object " << std::hex // << (int)id << std::dec << " inserted." << std::endl; +#endif return this->RETURN_OK; } else { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "ObjectManager::insert: Object id " << std::hex - << (int)id << std::dec << " is already in use!" << std::endl; + << static_cast(id) << std::dec + << " is already in use!" << std::endl; sif::error << "Terminating program." << std::endl; +#endif //This is very severe and difficult to handle in other places. 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 ) { if ( this->getSystemObject(id) != NULL ) { this->objectList.erase( id ); +#if FSFW_CPP_OSTREAM_ENABLED == 1 //sif::debug << "ObjectManager::removeObject: Object " << std::hex // << (int)id << std::dec << " removed." << std::endl; +#endif return RETURN_OK; } else { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "ObjectManager::removeObject: Requested object " << std::hex << (int)id << std::dec << " not found." << std::endl; +#endif return NOT_FOUND; } } @@ -60,8 +72,10 @@ ObjectManager::ObjectManager() : produceObjects(nullptr) { void ObjectManager::initialize() { if(produceObjects == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "ObjectManager::initialize: Passed produceObjects " "functions is nullptr!" << std::endl; +#endif return; } this->produceObjects(); @@ -70,38 +84,49 @@ void ObjectManager::initialize() { for (auto const& it : objectList) { result = it.second->initialize(); if ( result != RETURN_OK ) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 object_id_t var = it.first; sif::error << "ObjectManager::initialize: Object 0x" << std::hex << std::setw(8) << std::setfill('0')<< var << " failed to " "initialize with code 0x" << result << std::dec << std::setfill(' ') << std::endl; +#endif errorCount++; } } if (errorCount > 0) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "ObjectManager::ObjectManager: Counted " << errorCount << " failed initializations." << std::endl; +#endif } //Init was successful. Now check successful interconnections. errorCount = 0; for (auto const& it : objectList) { result = it.second->checkObjectConnections(); if ( result != RETURN_OK ) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "ObjectManager::ObjectManager: Object " << std::hex << (int) it.first << " connection check failed with code 0x" << result << std::dec << std::endl; +#endif errorCount++; } } if (errorCount > 0) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "ObjectManager::ObjectManager: Counted " << errorCount << " failed connection checks." << std::endl; +#endif } } void ObjectManager::printList() { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::debug << "ObjectManager: Object List contains:" << std::endl; for (auto const& it : objectList) { sif::debug << std::hex << it.first << " | " << it.second << std::endl; + } +#endif } diff --git a/objectmanager/ObjectManagerIF.h b/objectmanager/ObjectManagerIF.h index 4bd1d915..8bebb609 100644 --- a/objectmanager/ObjectManagerIF.h +++ b/objectmanager/ObjectManagerIF.h @@ -86,8 +86,10 @@ extern ObjectManagerIF *objectManager; template T* ObjectManagerIF::get( object_id_t id ) { if(objectManager == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "ObjectManagerIF: Global object manager has not " "been initialized yet!" << std::endl; +#endif } SystemObjectIF* temp = this->getSystemObject(id); return dynamic_cast(temp); diff --git a/osal/FreeRTOS/BinSemaphUsingTask.cpp b/osal/FreeRTOS/BinSemaphUsingTask.cpp index a420ec48..7d609aee 100644 --- a/osal/FreeRTOS/BinSemaphUsingTask.cpp +++ b/osal/FreeRTOS/BinSemaphUsingTask.cpp @@ -8,8 +8,10 @@ BinarySemaphoreUsingTask::BinarySemaphoreUsingTask() { handle = TaskManagement::getCurrentTaskHandle(); if(handle == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "Could not retrieve task handle. Please ensure the" "constructor was called inside a task." << std::endl; +#endif } xTaskNotifyGive(handle); } diff --git a/osal/FreeRTOS/BinarySemaphore.cpp b/osal/FreeRTOS/BinarySemaphore.cpp index 6fee5c35..c0349b7c 100644 --- a/osal/FreeRTOS/BinarySemaphore.cpp +++ b/osal/FreeRTOS/BinarySemaphore.cpp @@ -5,7 +5,9 @@ BinarySemaphore::BinarySemaphore() { handle = xSemaphoreCreateBinary(); if(handle == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "Semaphore: Binary semaph creation failure" << std::endl; +#endif } // Initiated semaphore must be given before it can be taken. xSemaphoreGive(handle); @@ -18,7 +20,9 @@ BinarySemaphore::~BinarySemaphore() { BinarySemaphore::BinarySemaphore(BinarySemaphore&& s) { handle = xSemaphoreCreateBinary(); if(handle == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "Binary semaphore creation failure" << std::endl; +#endif } xSemaphoreGive(handle); } @@ -28,7 +32,9 @@ BinarySemaphore& BinarySemaphore::operator =( if(&s != this) { handle = xSemaphoreCreateBinary(); if(handle == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "Binary semaphore creation failure" << std::endl; +#endif } xSemaphoreGive(handle); } diff --git a/osal/FreeRTOS/Clock.cpp b/osal/FreeRTOS/Clock.cpp index d3f4e68e..9c0a0267 100644 --- a/osal/FreeRTOS/Clock.cpp +++ b/osal/FreeRTOS/Clock.cpp @@ -163,7 +163,7 @@ ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) { if (checkOrCreateClockMutex() != HasReturnvaluesIF::RETURN_OK) { return HasReturnvaluesIF::RETURN_FAILED; } - ReturnValue_t result = timeMutex->lockMutex(MutexIF::BLOCKING); + ReturnValue_t result = timeMutex->lockMutex(MutexIF::TimeoutType::BLOCKING); if (result != HasReturnvaluesIF::RETURN_OK) { return result; } @@ -178,7 +178,7 @@ ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) { if (timeMutex == NULL) { return HasReturnvaluesIF::RETURN_FAILED; } - ReturnValue_t result = timeMutex->lockMutex(MutexIF::BLOCKING); + ReturnValue_t result = timeMutex->lockMutex(MutexIF::TimeoutType::BLOCKING); if (result != HasReturnvaluesIF::RETURN_OK) { return result; } diff --git a/osal/FreeRTOS/CountingSemaphUsingTask.cpp b/osal/FreeRTOS/CountingSemaphUsingTask.cpp index 9d309acc..750ea9d6 100644 --- a/osal/FreeRTOS/CountingSemaphUsingTask.cpp +++ b/osal/FreeRTOS/CountingSemaphUsingTask.cpp @@ -9,25 +9,31 @@ CountingSemaphoreUsingTask::CountingSemaphoreUsingTask(const uint8_t maxCount, uint8_t initCount): maxCount(maxCount) { if(initCount > maxCount) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "CountingSemaphoreUsingTask: Max count bigger than " "intial cout. Setting initial count to max count." << std::endl; +#endif initCount = maxCount; } handle = TaskManagement::getCurrentTaskHandle(); if(handle == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "CountingSemaphoreUsingTask: Could not retrieve task " "handle. Please ensure the constructor was called inside a " "task." << std::endl; +#endif } uint32_t oldNotificationValue; xTaskNotifyAndQuery(handle, 0, eSetValueWithOverwrite, &oldNotificationValue); if(oldNotificationValue != 0) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "CountinSemaphoreUsingTask: Semaphore initiated but " "current notification value is not 0. Please ensure the " "notification value is not used for other purposes!" << std::endl; +#endif } for(int i = 0; i < initCount; i++) { xTaskNotifyGive(handle); diff --git a/osal/FreeRTOS/CountingSemaphore.cpp b/osal/FreeRTOS/CountingSemaphore.cpp index a202e480..40884d27 100644 --- a/osal/FreeRTOS/CountingSemaphore.cpp +++ b/osal/FreeRTOS/CountingSemaphore.cpp @@ -10,14 +10,18 @@ CountingSemaphore::CountingSemaphore(const uint8_t maxCount, uint8_t initCount): maxCount(maxCount), initCount(initCount) { if(initCount > maxCount) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "CountingSemaphoreUsingTask: Max count bigger than " "intial cout. Setting initial count to max count." << std::endl; +#endif initCount = maxCount; } handle = xSemaphoreCreateCounting(maxCount, initCount); if(handle == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "CountingSemaphore: Creation failure" << std::endl; +#endif } } @@ -25,7 +29,9 @@ CountingSemaphore::CountingSemaphore(CountingSemaphore&& other): maxCount(other.maxCount), initCount(other.initCount) { handle = xSemaphoreCreateCounting(other.maxCount, other.initCount); if(handle == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "CountingSemaphore: Creation failure" << std::endl; +#endif } } @@ -33,7 +39,9 @@ CountingSemaphore& CountingSemaphore::operator =( CountingSemaphore&& other) { handle = xSemaphoreCreateCounting(other.maxCount, other.initCount); if(handle == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "CountingSemaphore: Creation failure" << std::endl; +#endif } return * this; } diff --git a/osal/FreeRTOS/FixedTimeslotTask.cpp b/osal/FreeRTOS/FixedTimeslotTask.cpp index fc5b89fe..aa7e6c59 100644 --- a/osal/FreeRTOS/FixedTimeslotTask.cpp +++ b/osal/FreeRTOS/FixedTimeslotTask.cpp @@ -37,15 +37,19 @@ void FixedTimeslotTask::taskEntryPoint(void* argument) { } originalTask->taskFunctionality(); +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::debug << "Polling task " << originalTask->handle << " returned from taskFunctionality." << std::endl; +#endif } void FixedTimeslotTask::missedDeadlineCounter() { FixedTimeslotTask::deadlineMissedCount++; if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "PST missed " << FixedTimeslotTask::deadlineMissedCount << " deadlines." << std::endl; +#endif } } @@ -69,8 +73,10 @@ ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, return HasReturnvaluesIF::RETURN_OK; } +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "Component " << std::hex << componentId << " not found, not adding it to pst" << std::endl; +#endif return HasReturnvaluesIF::RETURN_FAILED; } diff --git a/osal/FreeRTOS/MessageQueue.cpp b/osal/FreeRTOS/MessageQueue.cpp index fdadf8b7..c0c82cf1 100644 --- a/osal/FreeRTOS/MessageQueue.cpp +++ b/osal/FreeRTOS/MessageQueue.cpp @@ -10,6 +10,7 @@ MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize): maxMessageSize(maxMessageSize) { handle = xQueueCreate(messageDepth, maxMessageSize); +#if FSFW_CPP_OSTREAM_ENABLED == 1 if (handle == nullptr) { sif::error << "MessageQueue::MessageQueue:" << " Creation failed." << std::endl; @@ -17,7 +18,9 @@ MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize): << std::endl; sif::error << "Specified Maximum Message Size: " << maxMessageSize << std::endl; + } +#endif } MessageQueue::~MessageQueue() { diff --git a/osal/FreeRTOS/Mutex.cpp b/osal/FreeRTOS/Mutex.cpp index 9d9638b5..0b85ca13 100644 --- a/osal/FreeRTOS/Mutex.cpp +++ b/osal/FreeRTOS/Mutex.cpp @@ -5,7 +5,9 @@ Mutex::Mutex() { handle = xSemaphoreCreateMutex(); if(handle == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "Mutex::Mutex(FreeRTOS): Creation failure" << std::endl; +#endif } } diff --git a/osal/FreeRTOS/PeriodicTask.cpp b/osal/FreeRTOS/PeriodicTask.cpp index 2ee7bec0..3e830c7f 100644 --- a/osal/FreeRTOS/PeriodicTask.cpp +++ b/osal/FreeRTOS/PeriodicTask.cpp @@ -13,8 +13,10 @@ PeriodicTask::PeriodicTask(const char *name, TaskPriority setPriority, BaseType_t status = xTaskCreate(taskEntryPoint, name, stackSize, this, setPriority, &handle); if(status != pdPASS){ +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::debug << "PeriodicTask Insufficient heap memory remaining. " "Status: " << status << std::endl; +#endif } } @@ -41,8 +43,10 @@ void PeriodicTask::taskEntryPoint(void* argument) { } originalTask->taskFunctionality(); +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::debug << "Polling task " << originalTask->handle << " returned from taskFunctionality." << std::endl; +#endif } ReturnValue_t PeriodicTask::startTask() { @@ -99,8 +103,10 @@ ReturnValue_t PeriodicTask::addComponent(object_id_t object) { ExecutableObjectIF* newObject = objectManager->get( object); if (newObject == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "PeriodicTask::addComponent: Invalid object. Make sure" "it implement ExecutableObjectIF" << std::endl; +#endif return HasReturnvaluesIF::RETURN_FAILED; } objectList.push_back(newObject); diff --git a/osal/FreeRTOS/SemaphoreFactory.cpp b/osal/FreeRTOS/SemaphoreFactory.cpp index beb0d096..df005f6a 100644 --- a/osal/FreeRTOS/SemaphoreFactory.cpp +++ b/osal/FreeRTOS/SemaphoreFactory.cpp @@ -32,8 +32,10 @@ SemaphoreIF* SemaphoreFactory::createBinarySemaphore(uint32_t argument) { return new BinarySemaphoreUsingTask(); } else { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "SemaphoreFactory: Invalid argument, return regular" "binary semaphore" << std::endl; +#endif return new BinarySemaphore(); } } @@ -47,8 +49,10 @@ SemaphoreIF* SemaphoreFactory::createCountingSemaphore(uint8_t maxCount, return new CountingSemaphoreUsingTask(maxCount, initCount); } else { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "SemaphoreFactory: Invalid argument, return regular" "binary semaphore" << std::endl; +#endif return new CountingSemaphore(maxCount, initCount); } diff --git a/osal/host/CMakeLists.txt b/osal/host/CMakeLists.txt index aa32990b..367f721e 100644 --- a/osal/host/CMakeLists.txt +++ b/osal/host/CMakeLists.txt @@ -13,9 +13,11 @@ target_sources(${LIB_FSFW_NAME} ) if(UNIX) + find_package(Threads REQUIRED) + target_link_libraries(${LIB_FSFW_NAME} PRIVATE rt - pthread + ${CMAKE_THREAD_LIBS_INIT} ) endif() \ No newline at end of file diff --git a/osal/host/Clock.cpp b/osal/host/Clock.cpp index 41321eeb..88bf51d2 100644 --- a/osal/host/Clock.cpp +++ b/osal/host/Clock.cpp @@ -14,7 +14,9 @@ MutexIF* Clock::timeMutex = NULL; using SystemClock = std::chrono::system_clock; uint32_t Clock::getTicksPerSecond(void){ +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "Clock::getTicksPerSecond: not implemented yet" << std::endl; +#endif return 0; //return CLOCKS_PER_SEC; //uint32_t ticks = sysconf(_SC_CLK_TCK); @@ -23,7 +25,9 @@ uint32_t Clock::getTicksPerSecond(void){ ReturnValue_t Clock::setClock(const TimeOfDay_t* time) { // do some magic with chrono +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "Clock::setClock: not implemented yet" << std::endl; +#endif return HasReturnvaluesIF::RETURN_OK; } @@ -36,7 +40,9 @@ ReturnValue_t Clock::setClock(const timeval* time) { #else #endif +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "Clock::getUptime: Not implemented for found OS" << std::endl; +#endif return HasReturnvaluesIF::RETURN_FAILED; } @@ -60,7 +66,9 @@ ReturnValue_t Clock::getClock_timeval(timeval* time) { time->tv_usec = timeUnix.tv_nsec / 1000.0; return HasReturnvaluesIF::RETURN_OK; #else +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "Clock::getUptime: Not implemented for found OS" << std::endl; +#endif return HasReturnvaluesIF::RETURN_FAILED; #endif @@ -68,7 +76,9 @@ ReturnValue_t Clock::getClock_timeval(timeval* time) { ReturnValue_t Clock::getClock_usecs(uint64_t* time) { // do some magic with chrono +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "Clock::gerClock_usecs: not implemented yet" << std::endl; +#endif return HasReturnvaluesIF::RETURN_OK; } @@ -90,7 +100,9 @@ timeval Clock::getUptime() { timeval.tv_usec = uptimeSeconds *(double) 1e6 - (timeval.tv_sec *1e6); } #else +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "Clock::getUptime: Not implemented for found OS" << std::endl; +#endif #endif return timeval; } @@ -126,7 +138,9 @@ ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) { auto usecond = std::chrono::duration_cast(fraction); time->usecond = usecond.count(); +#if FSFW_CPP_OSTREAM_ENABLED == 1 //sif::warning << "Clock::getDateAndTime: not implemented yet" << std::endl; +#endif return HasReturnvaluesIF::RETURN_OK; } @@ -148,7 +162,9 @@ ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from, to->tv_usec = from->usecond; //Fails in 2038.. return HasReturnvaluesIF::RETURN_OK; +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "Clock::convertTimeBla: not implemented yet" << std::endl; +#endif return HasReturnvaluesIF::RETURN_OK; } @@ -186,7 +202,7 @@ ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) { if(checkOrCreateClockMutex()!=HasReturnvaluesIF::RETURN_OK){ return HasReturnvaluesIF::RETURN_FAILED; } - ReturnValue_t result = timeMutex->lockMutex(MutexIF::BLOCKING); + ReturnValue_t result = timeMutex->lockMutex(); if (result != HasReturnvaluesIF::RETURN_OK) { return result; } @@ -201,7 +217,7 @@ ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) { if(timeMutex == nullptr){ return HasReturnvaluesIF::RETURN_FAILED; } - ReturnValue_t result = timeMutex->lockMutex(MutexIF::BLOCKING); + ReturnValue_t result = timeMutex->lockMutex(); if (result != HasReturnvaluesIF::RETURN_OK) { return result; } diff --git a/osal/host/FixedTimeslotTask.cpp b/osal/host/FixedTimeslotTask.cpp index 9e892bb5..272d99b9 100644 --- a/osal/host/FixedTimeslotTask.cpp +++ b/osal/host/FixedTimeslotTask.cpp @@ -35,15 +35,19 @@ FixedTimeslotTask::FixedTimeslotTask(const char *name, TaskPriority setPriority, reinterpret_cast(mainThread.native_handle()), ABOVE_NORMAL_PRIORITY_CLASS); if(result != 0) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "FixedTimeslotTask: Windows SetPriorityClass failed with code " << GetLastError() << std::endl; +#endif } result = SetThreadPriority( reinterpret_cast(mainThread.native_handle()), THREAD_PRIORITY_NORMAL); if(result != 0) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "FixedTimeslotTask: Windows SetPriorityClass failed with code " << GetLastError() << std::endl; +#endif } #elif defined(LINUX) // 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(); +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::debug << "FixedTimeslotTask::taskEntryPoint: " "Returned from taskFunctionality." << std::endl; +#endif } ReturnValue_t FixedTimeslotTask::startTask() { @@ -134,8 +140,10 @@ ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, return HasReturnvaluesIF::RETURN_OK; } +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "Component " << std::hex << componentId << " not found, not adding it to pst" << std::endl; +#endif return HasReturnvaluesIF::RETURN_FAILED; } diff --git a/osal/host/MessageQueue.cpp b/osal/host/MessageQueue.cpp index d662d782..dfc045e8 100644 --- a/osal/host/MessageQueue.cpp +++ b/osal/host/MessageQueue.cpp @@ -10,8 +10,10 @@ MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize): queueLock = MutexFactory::instance()->createMutex(); auto result = QueueMapManager::instance()->addMessageQueue(this, &mqId); if(result != HasReturnvaluesIF::RETURN_OK) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "MessageQueue::MessageQueue:" << " Could not be created" << std::endl; +#endif } } @@ -137,8 +139,10 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, targetQueue->messageQueue.push(*mqmMessage); } else { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "MessageQueue::sendMessageFromMessageQueue: Message" "is not MessageQueueMessage!" << std::endl; +#endif } } diff --git a/osal/host/Mutex.cpp b/osal/host/Mutex.cpp index ad8873df..892028b2 100644 --- a/osal/host/Mutex.cpp +++ b/osal/host/Mutex.cpp @@ -4,16 +4,16 @@ Mutex::Mutex() {} ReturnValue_t Mutex::lockMutex(TimeoutType timeoutType, uint32_t timeoutMs) { - if(timeoutType == MutexIF::BLOCKING) { + if(timeoutType == TimeoutType::BLOCKING) { mutex.lock(); return HasReturnvaluesIF::RETURN_OK; } - else if(timeoutType == MutexIF::POLLING) { + else if(timeoutType == TimeoutType::POLLING) { if(mutex.try_lock()) { return HasReturnvaluesIF::RETURN_OK; } } - else if(timeoutMs > MutexIF::POLLING){ + else if(timeoutType == TimeoutType::WAITING){ auto chronoMs = std::chrono::milliseconds(timeoutMs); if(mutex.try_lock_for(chronoMs)) { return HasReturnvaluesIF::RETURN_OK; diff --git a/osal/host/Mutex.h b/osal/host/Mutex.h index c0fa19b7..0bd93c8a 100644 --- a/osal/host/Mutex.h +++ b/osal/host/Mutex.h @@ -22,7 +22,6 @@ public: std::timed_mutex* getMutexHandle(); private: - //bool locked = false; std::timed_mutex mutex; }; diff --git a/osal/host/PeriodicTask.cpp b/osal/host/PeriodicTask.cpp index bfa6c3fd..1f427546 100644 --- a/osal/host/PeriodicTask.cpp +++ b/osal/host/PeriodicTask.cpp @@ -33,15 +33,19 @@ PeriodicTask::PeriodicTask(const char *name, TaskPriority setPriority, reinterpret_cast(mainThread.native_handle()), ABOVE_NORMAL_PRIORITY_CLASS); if(result != 0) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "PeriodicTask: Windows SetPriorityClass failed with code " << GetLastError() << std::endl; +#endif } result = SetThreadPriority( reinterpret_cast(mainThread.native_handle()), THREAD_PRIORITY_NORMAL); if(result != 0) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "PeriodicTask: Windows SetPriorityClass failed with code " << GetLastError() << std::endl; +#endif } #elif defined(LINUX) // we can just copy and paste the code from linux here. @@ -69,8 +73,10 @@ void PeriodicTask::taskEntryPoint(void* argument) { } this->taskFunctionality(); +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::debug << "PeriodicTask::taskEntryPoint: " "Returned from taskFunctionality." << std::endl; +#endif } ReturnValue_t PeriodicTask::startTask() { diff --git a/osal/host/QueueMapManager.cpp b/osal/host/QueueMapManager.cpp index 621f46bc..7ffd4758 100644 --- a/osal/host/QueueMapManager.cpp +++ b/osal/host/QueueMapManager.cpp @@ -26,8 +26,10 @@ ReturnValue_t QueueMapManager::addMessageQueue( auto returnPair = queueMap.emplace(currentId, queueToInsert); if(not returnPair.second) { // this should never happen for the atomic variable. +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "QueueMapManager: This ID is already inside the map!" << std::endl; +#endif return HasReturnvaluesIF::RETURN_FAILED; } if (id != nullptr) { @@ -44,8 +46,10 @@ MessageQueueIF* QueueMapManager::getMessageQueue( return queueIter->second; } else { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "QueueMapManager::getQueueHandle: The ID " << messageQueueId << " does not exists in the map" << std::endl; +#endif return nullptr; } } diff --git a/osal/host/SemaphoreFactory.cpp b/osal/host/SemaphoreFactory.cpp index b19b2c75..3d3fe17f 100644 --- a/osal/host/SemaphoreFactory.cpp +++ b/osal/host/SemaphoreFactory.cpp @@ -21,16 +21,20 @@ SemaphoreFactory* SemaphoreFactory::instance() { SemaphoreIF* SemaphoreFactory::createBinarySemaphore(uint32_t arguments) { // Just gonna wait for full C++20 for now. +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "SemaphoreFactory: Binary Semaphore not implemented yet." " Returning nullptr!\n" << std::flush; +#endif return nullptr; } SemaphoreIF* SemaphoreFactory::createCountingSemaphore(const uint8_t maxCount, uint8_t initCount, uint32_t arguments) { // Just gonna wait for full C++20 for now. +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "SemaphoreFactory: Counting Semaphore not implemented yet." " Returning nullptr!\n" << std::flush; +#endif return nullptr; } diff --git a/osal/linux/BinarySemaphore.cpp b/osal/linux/BinarySemaphore.cpp index b81fa109..5716e560 100644 --- a/osal/linux/BinarySemaphore.cpp +++ b/osal/linux/BinarySemaphore.cpp @@ -1,10 +1,11 @@ #include "BinarySemaphore.h" +#include "../../serviceinterface/ServiceInterfacePrinter.h" #include "../../serviceinterface/ServiceInterfaceStream.h" -extern "C" { +#include #include #include -} + BinarySemaphore::BinarySemaphore() { // Using unnamed semaphores for now @@ -43,8 +44,10 @@ ReturnValue_t BinarySemaphore::acquire(TimeoutType timeoutType, timeOut.tv_nsec = nseconds - timeOut.tv_sec * 1000000000; result = sem_timedwait(&handle, &timeOut); if(result != 0 and errno == EINVAL) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::debug << "BinarySemaphore::acquire: Invalid time value possible" << std::endl; +#endif } } if(result == 0) { @@ -62,8 +65,10 @@ ReturnValue_t BinarySemaphore::acquire(TimeoutType timeoutType, return SemaphoreIF::SEMAPHORE_INVALID; case(EINTR): // Call was interrupted by signal handler +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::debug << "BinarySemaphore::acquire: Signal handler interrupted." "Code " << strerror(errno) << std::endl; +#endif /* No break */ default: return HasReturnvaluesIF::RETURN_FAILED; @@ -109,7 +114,8 @@ uint8_t BinarySemaphore::getSemaphoreCounter(sem_t *handle) { } else if(result != 0 and errno == EINVAL) { // Could be called from interrupt, use lightweight printf - printf("BinarySemaphore::getSemaphoreCounter: Invalid semaphore\n"); + sif::printError("BinarySemaphore::getSemaphoreCounter: " + "Invalid semaphore\n"); return 0; } else { @@ -124,10 +130,16 @@ void BinarySemaphore::initSemaphore(uint8_t initCount) { switch(errno) { case(EINVAL): // Value exceeds SEM_VALUE_MAX - case(ENOSYS): - // System does not support process-shared semaphores - sif::error << "BinarySemaphore: Init failed with" << strerror(errno) - << std::endl; + case(ENOSYS): { + // System does not support process-shared semaphores +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "BinarySemaphore: Init failed with " + << strerror(errno) << std::endl; +#else + sif::printError("BinarySemaphore: Init failed with %s\n", + strerror(errno)); +#endif + } } } } diff --git a/osal/linux/CMakeLists.txt b/osal/linux/CMakeLists.txt index c0096e42..474e548b 100644 --- a/osal/linux/CMakeLists.txt +++ b/osal/linux/CMakeLists.txt @@ -18,8 +18,14 @@ target_sources(${LIB_FSFW_NAME} Timer.cpp ) -target_link_libraries(${LIB_FSFW_NAME} - PRIVATE - rt - pthread +find_package(Threads REQUIRED) + +target_link_libraries(${LIB_FSFW_NAME} PRIVATE + ${CMAKE_THREAD_LIBS_INIT} + rt ) + +target_link_libraries(${LIB_FSFW_NAME} INTERFACE + ${CMAKE_THREAD_LIBS_INIT} +) + diff --git a/osal/linux/Clock.cpp b/osal/linux/Clock.cpp index 6cddda35..35cbfae0 100644 --- a/osal/linux/Clock.cpp +++ b/osal/linux/Clock.cpp @@ -69,7 +69,9 @@ timeval Clock::getUptime() { timeval uptime; auto result = getUptime(&uptime); if(result != HasReturnvaluesIF::RETURN_OK) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "Clock::getUptime: Error getting uptime" << std::endl; +#endif } return uptime; } @@ -180,7 +182,7 @@ ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) { if(checkOrCreateClockMutex()!=HasReturnvaluesIF::RETURN_OK){ return HasReturnvaluesIF::RETURN_FAILED; } - ReturnValue_t result = timeMutex->lockMutex(MutexIF::BLOCKING); + ReturnValue_t result = timeMutex->lockMutex(MutexIF::TimeoutType::BLOCKING); if (result != HasReturnvaluesIF::RETURN_OK) { return result; } @@ -195,7 +197,7 @@ ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) { if(timeMutex==NULL){ return HasReturnvaluesIF::RETURN_FAILED; } - ReturnValue_t result = timeMutex->lockMutex(MutexIF::BLOCKING); + ReturnValue_t result = timeMutex->lockMutex(MutexIF::TimeoutType::BLOCKING); if (result != HasReturnvaluesIF::RETURN_OK) { return result; } @@ -207,13 +209,13 @@ ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) { } ReturnValue_t Clock::checkOrCreateClockMutex(){ - if(timeMutex==NULL){ + if(timeMutex == nullptr){ MutexFactory* mutexFactory = MutexFactory::instance(); - if (mutexFactory == NULL) { + if (mutexFactory == nullptr) { return HasReturnvaluesIF::RETURN_FAILED; } timeMutex = mutexFactory->createMutex(); - if (timeMutex == NULL) { + if (timeMutex == nullptr) { return HasReturnvaluesIF::RETURN_FAILED; } } diff --git a/osal/linux/CountingSemaphore.cpp b/osal/linux/CountingSemaphore.cpp index 18339399..07c52212 100644 --- a/osal/linux/CountingSemaphore.cpp +++ b/osal/linux/CountingSemaphore.cpp @@ -1,11 +1,15 @@ #include "../../osal/linux/CountingSemaphore.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "../../serviceinterface/ServiceInterface.h" + +#include CountingSemaphore::CountingSemaphore(const uint8_t maxCount, uint8_t initCount): maxCount(maxCount), initCount(initCount) { if(initCount > maxCount) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "CountingSemaphoreUsingTask: Max count bigger than " "intial cout. Setting initial count to max count." << std::endl; +#endif initCount = maxCount; } diff --git a/osal/linux/FixedTimeslotTask.cpp b/osal/linux/FixedTimeslotTask.cpp index 247a34ed..a545eeb7 100644 --- a/osal/linux/FixedTimeslotTask.cpp +++ b/osal/linux/FixedTimeslotTask.cpp @@ -47,8 +47,10 @@ ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, return HasReturnvaluesIF::RETURN_OK; } +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "Component " << std::hex << componentId << " not found, not adding it to pst" << std::dec << std::endl; +#endif return HasReturnvaluesIF::RETURN_FAILED; } @@ -91,7 +93,9 @@ void FixedTimeslotTask::taskFunctionality() { void FixedTimeslotTask::missedDeadlineCounter() { FixedTimeslotTask::deadlineMissedCount++; if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "PST missed " << FixedTimeslotTask::deadlineMissedCount << " deadlines." << std::endl; +#endif } } diff --git a/osal/linux/MessageQueue.cpp b/osal/linux/MessageQueue.cpp index cfadb793..60d15dee 100644 --- a/osal/linux/MessageQueue.cpp +++ b/osal/linux/MessageQueue.cpp @@ -1,5 +1,5 @@ #include "MessageQueue.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "../../serviceinterface/ServiceInterface.h" #include "../../objectmanager/ObjectManagerIF.h" #include @@ -10,7 +10,6 @@ #include - MessageQueue::MessageQueue(uint32_t messageDepth, size_t maxMessageSize): id(MessageQueueIF::NO_QUEUE),lastPartner(MessageQueueIF::NO_QUEUE), defaultDestination(MessageQueueIF::NO_QUEUE), @@ -43,13 +42,17 @@ MessageQueue::MessageQueue(uint32_t messageDepth, size_t maxMessageSize): MessageQueue::~MessageQueue() { int status = mq_close(this->id); if(status != 0){ +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "MessageQueue::Destructor: mq_close Failed with status: " << strerror(errno) < Apply changes with: sudo sysctl -p */ +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "MessageQueue::MessageQueue: Default MQ size " << defaultMqMaxMsg << " is too small for requested size " << messageDepth << std::endl; sif::error << "This error can be fixed by setting the maximum " "allowed message size higher!" << std::endl; +#endif } break; @@ -95,8 +102,10 @@ ReturnValue_t MessageQueue::handleError(mq_attr* attributes, //We unlink the other queue int status = mq_unlink(name); if (status != 0) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "mq_unlink Failed with status: " << strerror(errno) << std::endl; +#endif } else { // Successful unlinking, try to open again @@ -112,12 +121,16 @@ ReturnValue_t MessageQueue::handleError(mq_attr* attributes, break; } - default: + default: { // Failed either the first time or the second time - sif::error << "MessageQueue::MessageQueue: Creating Queue " << std::hex - << name << std::dec << " failed with status: " - << strerror(errno) << std::endl; - +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "MessageQueue::MessageQueue: Creating Queue " << name + << " failed with status: " << strerror(errno) << std::endl; +#else + sif::printError("MessageQueue::MessageQueue: Creating Queue %s" + " failed with status: %s\n", name, strerror(errno)); +#endif + } } return HasReturnvaluesIF::RETURN_FAILED; @@ -151,15 +164,19 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message, ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) { if(message == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "MessageQueue::receiveMessage: Message is " "nullptr!" << std::endl; +#endif return HasReturnvaluesIF::RETURN_FAILED; } if(message->getMaximumMessageSize() < maxMessageSize) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "MessageQueue::receiveMessage: Message size " << message->getMaximumMessageSize() << " too small to receive data!" << std::endl; +#endif return HasReturnvaluesIF::RETURN_FAILED; } @@ -187,8 +204,10 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) { return MessageQueueIF::EMPTY; case EBADF: //mqdes doesn't represent a valid queue open for reading. +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "MessageQueue::receive: configuration error " << strerror(errno) << std::endl; +#endif /*NO BREAK*/ case EINVAL: /* @@ -200,8 +219,10 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) { * queue, and the QNX extended option MQ_READBUF_DYNAMIC hasn't * been set in the queue's mq_flags. */ +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "MessageQueue::receive: configuration error " << strerror(errno) << std::endl; +#endif /*NO BREAK*/ case EMSGSIZE: /* @@ -213,8 +234,10 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) { * given msg_len is too short for the message that would have * been received. */ +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "MessageQueue::receive: configuration error " << strerror(errno) << std::endl; +#endif /*NO BREAK*/ case EINTR: //The operation was interrupted by a signal. @@ -237,8 +260,10 @@ ReturnValue_t MessageQueue::flush(uint32_t* count) { switch(errno){ case EBADF: //mqdes doesn't represent a valid message queue. +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "MessageQueue::flush configuration error, " "called flush with an invalid queue ID" << std::endl; +#endif /*NO BREAK*/ case EINVAL: //mq_attr is NULL @@ -253,8 +278,10 @@ ReturnValue_t MessageQueue::flush(uint32_t* count) { switch(errno){ case EBADF: //mqdes doesn't represent a valid message queue. +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "MessageQueue::flush configuration error, " "called flush with an invalid queue ID" << std::endl; +#endif /*NO BREAK*/ case EINVAL: /* @@ -306,8 +333,10 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, MessageQueueMessageIF *message, MessageQueueId_t sentFrom, bool ignoreFault) { if(message == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "MessageQueue::sendMessageFromMessageQueue: Message is " "nullptr!" << std::endl; +#endif return HasReturnvaluesIF::RETURN_FAILED; } @@ -335,11 +364,13 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, case EBADF: { //mq_des doesn't represent a valid message queue descriptor, //or mq_des wasn't opened for writing. +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "MessageQueue::sendMessage: Configuration error, MQ" << " destination invalid." << std::endl; sif::error << strerror(errno) << " in " <<"mq_send to: " << sendTo << " sent from " << sentFrom << std::endl; +#endif return DESTINVATION_INVALID; } case EINTR: @@ -354,14 +385,18 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, * - MQ_PRIO_RESTRICT is set in the mq_attr of mq_des, and * msg_prio is greater than the priority of the calling process. */ +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "MessageQueue::sendMessage: Configuration error " << strerror(errno) << " in mq_send" << std::endl; +#endif /*NO BREAK*/ case EMSGSIZE: // The msg_len is greater than the msgsize associated with //the specified queue. +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "MessageQueue::sendMessage: Size error [" << strerror(errno) << "] in mq_send" << std::endl; +#endif /*NO BREAK*/ default: return HasReturnvaluesIF::RETURN_FAILED; diff --git a/osal/linux/Mutex.cpp b/osal/linux/Mutex.cpp index b27ff8c0..c642b132 100644 --- a/osal/linux/Mutex.cpp +++ b/osal/linux/Mutex.cpp @@ -12,24 +12,32 @@ Mutex::Mutex() { pthread_mutexattr_t mutexAttr; int status = pthread_mutexattr_init(&mutexAttr); if (status != 0) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "Mutex: Attribute init failed with: " << strerror(status) << std::endl; +#endif } status = pthread_mutexattr_setprotocol(&mutexAttr, PTHREAD_PRIO_INHERIT); if (status != 0) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "Mutex: Attribute set PRIO_INHERIT failed with: " << strerror(status) << std::endl; +#endif } status = pthread_mutex_init(&mutex, &mutexAttr); if (status != 0) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "Mutex: creation with name, id " << mutex.__data.__count << ", " << " failed with " << strerror(status) << std::endl; +#endif } // After a mutex attributes object has been used to initialize one or more // mutexes, any function affecting the attributes object // (including destruction) shall not affect any previously initialized mutexes. status = pthread_mutexattr_destroy(&mutexAttr); if (status != 0) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "Mutex: Attribute destroy failed with " << strerror(status) << std::endl; +#endif } } diff --git a/osal/linux/PeriodicPosixTask.cpp b/osal/linux/PeriodicPosixTask.cpp index 3c1df6bb..a8f2de60 100644 --- a/osal/linux/PeriodicPosixTask.cpp +++ b/osal/linux/PeriodicPosixTask.cpp @@ -25,8 +25,10 @@ ReturnValue_t PeriodicPosixTask::addComponent(object_id_t object) { ExecutableObjectIF* newObject = objectManager->get( object); if (newObject == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "PeriodicTask::addComponent: Invalid object. Make sure" << " it implements ExecutableObjectIF!" << std::endl; +#endif return HasReturnvaluesIF::RETURN_FAILED; } objectList.push_back(newObject); @@ -42,7 +44,9 @@ ReturnValue_t PeriodicPosixTask::sleepFor(uint32_t ms) { ReturnValue_t PeriodicPosixTask::startTask(void) { started = true; +#if FSFW_CPP_OSTREAM_ENABLED == 1 //sif::info << stackSize << std::endl; +#endif PosixThread::createTask(&taskEntryPoint,this); return HasReturnvaluesIF::RETURN_OK; } @@ -67,12 +71,16 @@ void PeriodicPosixTask::taskFunctionality(void) { char name[20] = {0}; int status = pthread_getname_np(pthread_self(), name, sizeof(name)); if(status == 0) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "PeriodicPosixTask " << name << ": Deadline " "missed." << std::endl; +#endif } else { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "PeriodicPosixTask X: Deadline missed. " << status << std::endl; +#endif } if (this->deadlineMissedFunc != nullptr) { this->deadlineMissedFunc(); diff --git a/osal/linux/PosixThread.cpp b/osal/linux/PosixThread.cpp index 55d74de3..2499b442 100644 --- a/osal/linux/PosixThread.cpp +++ b/osal/linux/PosixThread.cpp @@ -1,6 +1,6 @@ #include "PosixThread.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "../../serviceinterface/ServiceInterface.h" #include #include @@ -48,8 +48,10 @@ void PosixThread::suspend() { sigaddset(&waitSignal, SIGUSR1); sigwait(&waitSignal, &caughtSig); if (caughtSig != SIGUSR1) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "FixedTimeslotTask: Unknown Signal received: " << caughtSig << std::endl; +#endif } } @@ -118,7 +120,9 @@ uint64_t PosixThread::getCurrentMonotonicTimeMs(){ void PosixThread::createTask(void* (*fnc_)(void*), void* arg_) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 //sif::debug << "PosixThread::createTask" << std::endl; +#endif /* * The attr argument points to a pthread_attr_t structure whose contents are used at thread creation time to determine attributes for the new @@ -129,53 +133,75 @@ void PosixThread::createTask(void* (*fnc_)(void*), void* arg_) { pthread_attr_t attributes; int status = pthread_attr_init(&attributes); if(status != 0){ +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "Posix Thread attribute init failed with: " << strerror(status) << std::endl; +#endif } void* stackPointer; status = posix_memalign(&stackPointer, sysconf(_SC_PAGESIZE), stackSize); if(status != 0){ +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "PosixThread::createTask: Stack init failed with: " << strerror(status) << std::endl; +#endif if(errno == ENOMEM) { - uint64_t stackMb = stackSize/10e6; + size_t stackMb = stackSize/10e6; +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "PosixThread::createTask: Insufficient memory for" " the requested " << stackMb << " MB" << std::endl; +#else + sif::printError("PosixThread::createTask: Insufficient memory for " + "the requested %zu MB\n", stackMb); +#endif } else if(errno == EINVAL) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "PosixThread::createTask: Wrong alignment argument!" << std::endl; +#else + sif::printError("PosixThread::createTask: " + "Wrong alignment argument!\n"); +#endif } return; } status = pthread_attr_setstack(&attributes, stackPointer, stackSize); if(status != 0){ +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "PosixThread::createTask: pthread_attr_setstack " " failed with: " << strerror(status) << std::endl; sif::error << "Make sure the specified stack size is valid and is " "larger than the minimum allowed stack size." << std::endl; +#endif } status = pthread_attr_setinheritsched(&attributes, PTHREAD_EXPLICIT_SCHED); if(status != 0){ +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "Posix Thread attribute setinheritsched failed with: " << strerror(status) << std::endl; +#endif } // TODO FIFO -> This needs root privileges for the process status = pthread_attr_setschedpolicy(&attributes,SCHED_FIFO); if(status != 0){ +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "Posix Thread attribute schedule policy failed with: " << strerror(status) << std::endl; +#endif } sched_param scheduleParams; scheduleParams.__sched_priority = priority; status = pthread_attr_setschedparam(&attributes, &scheduleParams); if(status != 0){ +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "Posix Thread attribute schedule params failed with: " << strerror(status) << std::endl; +#endif } //Set Signal Mask for suspend until startTask is called @@ -184,36 +210,48 @@ void PosixThread::createTask(void* (*fnc_)(void*), void* arg_) { sigaddset(&waitSignal, SIGUSR1); status = pthread_sigmask(SIG_BLOCK, &waitSignal, NULL); if(status != 0){ +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "Posix Thread sigmask failed failed with: " << strerror(status) << " errno: " << strerror(errno) << std::endl; +#endif } status = pthread_create(&thread,&attributes,fnc_,arg_); if(status != 0){ +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "Posix Thread create failed with: " << strerror(status) << std::endl; +#endif } status = pthread_setname_np(thread,name); if(status != 0){ +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "PosixThread::createTask: setname failed with: " << strerror(status) << std::endl; +#endif if(status == ERANGE) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "PosixThread::createTask: Task name length longer" " than 16 chars. Truncating.." << std::endl; +#endif name[15] = '\0'; status = pthread_setname_np(thread,name); if(status != 0){ +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "PosixThread::createTask: Setting name" " did not work.." << std::endl; +#endif } } } status = pthread_attr_destroy(&attributes); if(status!=0){ +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "Posix Thread attribute destroy failed with: " << strerror(status) << std::endl; +#endif } } diff --git a/osal/linux/TcUnixUdpPollingTask.cpp b/osal/linux/TcUnixUdpPollingTask.cpp index af99ec91..11ed7fee 100644 --- a/osal/linux/TcUnixUdpPollingTask.cpp +++ b/osal/linux/TcUnixUdpPollingTask.cpp @@ -1,6 +1,8 @@ #include "TcUnixUdpPollingTask.h" #include "../../globalfunctions/arrayprinter.h" +#include + TcUnixUdpPollingTask::TcUnixUdpPollingTask(object_id_t objectId, object_id_t tmtcUnixUdpBridge, size_t frameSize, double timeoutSeconds): SystemObject(objectId), @@ -39,14 +41,18 @@ ReturnValue_t TcUnixUdpPollingTask::performOperation(uint8_t opCode) { reinterpret_cast(&senderAddress), &senderSockLen); if(bytesReceived < 0) { // handle error +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "TcSocketPollingTask::performOperation: Reception" "error." << std::endl; +#endif handleReadError(); continue; } +#if FSFW_CPP_OSTREAM_ENABLED == 1 // sif::debug << "TcSocketPollingTask::performOperation: " << bytesReceived // << " bytes received" << std::endl; +#endif ReturnValue_t result = handleSuccessfullTcRead(bytesReceived); if(result != HasReturnvaluesIF::RETURN_FAILED) { @@ -65,9 +71,11 @@ ReturnValue_t TcUnixUdpPollingTask::handleSuccessfullTcRead(size_t bytesRead) { receptionBuffer.data(), bytesRead); // arrayprinter::print(receptionBuffer.data(), bytesRead); if (result != HasReturnvaluesIF::RETURN_OK) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "TcSerialPollingTask::transferPusToSoftwareBus: Data " "storage failed" << std::endl; sif::error << "Packet size: " << bytesRead << std::endl; +#endif return HasReturnvaluesIF::RETURN_FAILED; } @@ -75,8 +83,10 @@ ReturnValue_t TcUnixUdpPollingTask::handleSuccessfullTcRead(size_t bytesRead) { result = MessageQueueSenderIF::sendMessage(targetTcDestination, &message); if (result != HasReturnvaluesIF::RETURN_OK) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "Serial Polling: Sending message to queue failed" << std::endl; +#endif tcStore->deleteData(storeId); } return result; @@ -85,15 +95,19 @@ ReturnValue_t TcUnixUdpPollingTask::handleSuccessfullTcRead(size_t bytesRead) { ReturnValue_t TcUnixUdpPollingTask::initialize() { tcStore = objectManager->get(objects::TC_STORE); if (tcStore == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "TcSerialPollingTask::initialize: TC Store uninitialized!" << std::endl; +#endif return ObjectManagerIF::CHILD_INIT_FAILED; } tmtcBridge = objectManager->get(tmtcBridgeId); if(tmtcBridge == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "TcSocketPollingTask::TcSocketPollingTask: Invalid" " TMTC bridge object!" << std::endl; +#endif return ObjectManagerIF::CHILD_INIT_FAILED; } @@ -115,8 +129,10 @@ void TcUnixUdpPollingTask::setTimeout(double timeoutSeconds) { int result = setsockopt(serverUdpSocket, SOL_SOCKET, SO_RCVTIMEO, &tval, sizeof(receptionTimeout)); if(result == -1) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "TcSocketPollingTask::TcSocketPollingTask: Setting " "receive timeout failed with " << strerror(errno) << std::endl; +#endif } } @@ -126,13 +142,17 @@ void TcUnixUdpPollingTask::handleReadError() { case(EAGAIN): { // todo: When working in timeout mode, this will occur more often // and is not an error. +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "TcUnixUdpPollingTask::handleReadError: Timeout." << std::endl; +#endif break; } default: { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "TcUnixUdpPollingTask::handleReadError: " << strerror(errno) << std::endl; +#endif } } } diff --git a/osal/linux/Timer.cpp b/osal/linux/Timer.cpp index bae631d7..fe0fbebb 100644 --- a/osal/linux/Timer.cpp +++ b/osal/linux/Timer.cpp @@ -10,8 +10,10 @@ Timer::Timer() { sigEvent.sigev_value.sival_ptr = &timerId; int status = timer_create(CLOCK_MONOTONIC, &sigEvent, &timerId); if(status!=0){ +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "Timer creation failed with: " << status << " errno: " << errno << std::endl; +#endif } } diff --git a/osal/linux/TmTcUnixUdpBridge.cpp b/osal/linux/TmTcUnixUdpBridge.cpp index ab28623e..0af1fc68 100644 --- a/osal/linux/TmTcUnixUdpBridge.cpp +++ b/osal/linux/TmTcUnixUdpBridge.cpp @@ -1,5 +1,5 @@ #include "TmTcUnixUdpBridge.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "../../serviceinterface/ServiceInterface.h" #include "../../ipc/MutexHelper.h" #include @@ -26,8 +26,10 @@ TmTcUnixUdpBridge::TmTcUnixUdpBridge(object_id_t objectId, //clientSocket = socket(AF_INET, SOCK_DGRAM, 0); serverSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if(serverSocket < 0) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "TmTcUnixUdpBridge::TmTcUnixUdpBridge: Could not open" " UDP socket!" << std::endl; +#endif handleSocketError(); return; } @@ -51,9 +53,11 @@ TmTcUnixUdpBridge::TmTcUnixUdpBridge(object_id_t objectId, reinterpret_cast(&serverAddress), serverAddressLen); if(result == -1) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "TmTcUnixUdpBridge::TmTcUnixUdpBridge: Could not bind " "local port " << setServerPort << " to server socket!" << std::endl; +#endif handleBindError(); return; } @@ -74,18 +78,24 @@ ReturnValue_t TmTcUnixUdpBridge::sendTm(const uint8_t *data, size_t dataLen) { } // char ipAddress [15]; +#if FSFW_CPP_OSTREAM_ENABLED == 1 // sif::debug << "IP Address Sender: "<< inet_ntop(AF_INET, // &clientAddress.sin_addr.s_addr, ipAddress, 15) << std::endl; +#endif ssize_t bytesSent = sendto(serverSocket, data, dataLen, flags, reinterpret_cast(&clientAddress), clientAddressLen); if(bytesSent < 0) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "TmTcUnixUdpBridge::sendTm: Send operation failed." << std::endl; +#endif handleSendError(); } +#if FSFW_CPP_OSTREAM_ENABLED == 1 // sif::debug << "TmTcUnixUdpBridge::sendTm: " << bytesSent << " bytes were" // " sent." << std::endl; +#endif return HasReturnvaluesIF::RETURN_OK; } @@ -93,10 +103,12 @@ void TmTcUnixUdpBridge::checkAndSetClientAddress(sockaddr_in& newAddress) { MutexHelper lock(mutex, MutexIF::TimeoutType::WAITING, 10); // char ipAddress [15]; +#if FSFW_CPP_OSTREAM_ENABLED == 1 // sif::debug << "IP Address Sender: "<< inet_ntop(AF_INET, // &newAddress.sin_addr.s_addr, ipAddress, 15) << std::endl; // sif::debug << "IP Address Old: " << inet_ntop(AF_INET, // &clientAddress.sin_addr.s_addr, ipAddress, 15) << std::endl; +#endif // Set new IP address if it has changed. if(clientAddress.sin_addr.s_addr != newAddress.sin_addr.s_addr) { @@ -117,12 +129,16 @@ void TmTcUnixUdpBridge::handleSocketError() { case(ENOBUFS): case(ENOMEM): case(EPROTONOSUPPORT): +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "TmTcUnixBridge::handleSocketError: Socket creation failed" << " with " << strerror(errno) << std::endl; +#endif break; default: +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "TmTcUnixBridge::handleSocketError: Unknown error" << std::endl; +#endif break; } } @@ -135,10 +151,12 @@ void TmTcUnixUdpBridge::handleBindError() { Ephermeral ports can be shown with following command: sysctl -A | grep ip_local_port_range */ +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "TmTcUnixBridge::handleBindError: Port access issue." "Ports 1-1024 are reserved on UNIX systems and require root " "rights while ephermeral ports should not be used as well." << std::endl; +#endif } break; case(EADDRINUSE): @@ -153,22 +171,32 @@ void TmTcUnixUdpBridge::handleBindError() { case(ENOMEM): case(ENOTDIR): case(EROFS): { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "TmTcUnixBridge::handleBindError: Socket creation failed" << " with " << strerror(errno) << std::endl; +#endif break; } default: +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "TmTcUnixBridge::handleBindError: Unknown error" << std::endl; +#endif break; } } void TmTcUnixUdpBridge::handleSendError() { switch(errno) { - default: + default: { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "TmTcUnixBridge::handleSendError: " << strerror(errno) << std::endl; +#else + sif::printError("TmTcUnixBridge::handleSendError: %s\n", + strerror(errno)); +#endif + } } } diff --git a/osal/rtems/CMakeLists.txt b/osal/rtems/CMakeLists.txt new file mode 100644 index 00000000..bff03184 --- /dev/null +++ b/osal/rtems/CMakeLists.txt @@ -0,0 +1,18 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + Clock.cpp + CpuUsage.cpp + InitTask.cpp + InternalErrorCodes.cpp + MessageQueue.cpp + MultiObjectTask.cpp + Mutex.cpp + MutexFactory.cpp + PollingTask.cpp + QueueFactory.cpp + RtemsBasic.cpp + TaskBase.cpp + TaskFactory.cpp +) + + diff --git a/osal/rtems/Clock.cpp b/osal/rtems/Clock.cpp index e5f37ec6..8bd7ac37 100644 --- a/osal/rtems/Clock.cpp +++ b/osal/rtems/Clock.cpp @@ -1,6 +1,10 @@ -#include "../../timemanager/Clock.h" #include "RtemsBasic.h" + +#include "../../timemanager/Clock.h" +#include "../../ipc/MutexHelper.h" + #include +#include uint16_t Clock::leapSeconds = 0; MutexIF* Clock::timeMutex = nullptr; @@ -33,15 +37,24 @@ ReturnValue_t Clock::setClock(const TimeOfDay_t* time) { } ReturnValue_t Clock::setClock(const timeval* time) { - //TODO This routine uses _TOD_Set which is not timespec newTime; newTime.tv_sec = time->tv_sec; + if(time->tv_usec < 0) { + // better returnvalue. + return HasReturnvaluesIF::RETURN_FAILED; + } newTime.tv_nsec = time->tv_usec * TOD_NANOSECONDS_PER_MICROSECOND; - //SHOULDDO: Not sure if we need to protect this call somehow (by thread lock or something). - //Uli: rtems docu says you can call this from an ISR, not sure if this means no protetion needed - //TODO Second parameter is ISR_lock_Context - _TOD_Set(&newTime,nullptr); - return HasReturnvaluesIF::RETURN_OK; + + ISR_lock_Context context; + _TOD_Lock(); + _TOD_Acquire(&context); + Status_Control status = _TOD_Set(&newTime, &context); + _TOD_Unlock(); + if(status == STATUS_SUCCESSFUL) { + return HasReturnvaluesIF::RETURN_OK; + } + // better returnvalue + return HasReturnvaluesIF::RETURN_FAILED; } ReturnValue_t Clock::getClock_timeval(timeval* time) { @@ -91,6 +104,7 @@ ReturnValue_t Clock::getClock_usecs(uint64_t* time) { } ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) { + // TIsn't this a bug? Are RTEMS ticks always microseconds? rtems_time_of_day* timeRtems = reinterpret_cast(time); rtems_status_code status = rtems_clock_get_tod(timeRtems); switch (status) { diff --git a/osal/rtems/InternalErrorCodes.cpp b/osal/rtems/InternalErrorCodes.cpp index ddf365d5..f4079814 100644 --- a/osal/rtems/InternalErrorCodes.cpp +++ b/osal/rtems/InternalErrorCodes.cpp @@ -34,8 +34,10 @@ ReturnValue_t InternalErrorCodes::translate(uint8_t code) { return OUT_OF_PROXIES; case INTERNAL_ERROR_INVALID_GLOBAL_ID: return INVALID_GLOBAL_ID; +#ifndef STM32H743ZI_NUCLEO case INTERNAL_ERROR_BAD_STACK_HOOK: return BAD_STACK_HOOK; +#endif // case INTERNAL_ERROR_BAD_ATTRIBUTES: // return BAD_ATTRIBUTES; // case INTERNAL_ERROR_IMPLEMENTATION_KEY_CREATE_INCONSISTENCY: diff --git a/osal/rtems/MessageQueue.cpp b/osal/rtems/MessageQueue.cpp index 839182a6..bfaf3569 100644 --- a/osal/rtems/MessageQueue.cpp +++ b/osal/rtems/MessageQueue.cpp @@ -9,9 +9,11 @@ MessageQueue::MessageQueue(size_t message_depth, size_t max_message_size) : rtems_status_code status = rtems_message_queue_create(name, message_depth, max_message_size, 0, &(this->id)); if (status != RTEMS_SUCCESSFUL) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "MessageQueue::MessageQueue: Creating Queue " << std::hex << name << std::dec << " failed with status:" << (uint32_t) status << std::endl; +#endif this->id = 0; } } diff --git a/osal/rtems/MultiObjectTask.cpp b/osal/rtems/MultiObjectTask.cpp index 970d01e1..b111f724 100644 --- a/osal/rtems/MultiObjectTask.cpp +++ b/osal/rtems/MultiObjectTask.cpp @@ -30,8 +30,10 @@ ReturnValue_t MultiObjectTask::startTask() { rtems_status_code status = rtems_task_start(id, MultiObjectTask::taskEntryPoint, rtems_task_argument((void *) this)); if (status != RTEMS_SUCCESSFUL) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "ObjectTask::startTask for " << std::hex << this->getId() << std::dec << " failed." << std::endl; +#endif } switch(status){ case RTEMS_SUCCESSFUL: @@ -63,7 +65,9 @@ void MultiObjectTask::taskFunctionality() { char nameSpace[8] = { 0 }; char* ptr = rtems_object_get_name(getId(), sizeof(nameSpace), nameSpace); +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "ObjectTask: " << ptr << " Deadline missed." << std::endl; +#endif if (this->deadlineMissedFunc != nullptr) { this->deadlineMissedFunc(); } diff --git a/osal/rtems/Mutex.cpp b/osal/rtems/Mutex.cpp index a5ec9635..7dd512fa 100644 --- a/osal/rtems/Mutex.cpp +++ b/osal/rtems/Mutex.cpp @@ -10,27 +10,31 @@ Mutex::Mutex() : RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_INHERIT_PRIORITY, 0, &mutexId); if (status != RTEMS_SUCCESSFUL) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "Mutex: creation with name, id " << mutexName << ", " << mutexId << " failed with " << status << std::endl; +#endif } } Mutex::~Mutex() { rtems_status_code status = rtems_semaphore_delete(mutexId); if (status != RTEMS_SUCCESSFUL) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "Mutex: deletion for id " << mutexId << " failed with " << status << std::endl; +#endif } } ReturnValue_t Mutex::lockMutex(TimeoutType timeoutType = TimeoutType::BLOCKING, uint32_t timeoutMs) { rtems_status_code status = RTEMS_INVALID_ID; - if(timeoutMs == MutexIF::TimeoutType::BLOCKING) { + if(timeoutType == MutexIF::TimeoutType::BLOCKING) { status = rtems_semaphore_obtain(mutexId, RTEMS_WAIT, RTEMS_NO_TIMEOUT); } - else if(timeoutMs == MutexIF::TimeoutType::POLLING) { + else if(timeoutType == MutexIF::TimeoutType::POLLING) { timeoutMs = RTEMS_NO_TIMEOUT; status = rtems_semaphore_obtain(mutexId, RTEMS_NO_WAIT, 0); diff --git a/osal/rtems/PollingTask.cpp b/osal/rtems/PollingTask.cpp index db7864fe..0ebf63e2 100644 --- a/osal/rtems/PollingTask.cpp +++ b/osal/rtems/PollingTask.cpp @@ -35,15 +35,19 @@ rtems_task PollingTask::taskEntryPoint(rtems_task_argument argument) { PollingTask *originalTask(reinterpret_cast(argument)); //The task's functionality is called. originalTask->taskFunctionality(); +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::debug << "Polling task " << originalTask->getId() << " returned from taskFunctionality." << std::endl; +#endif } void PollingTask::missedDeadlineCounter() { PollingTask::deadlineMissedCount++; if (PollingTask::deadlineMissedCount % 10 == 0) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "PST missed " << PollingTask::deadlineMissedCount << " deadlines." << std::endl; +#endif } } @@ -51,8 +55,10 @@ ReturnValue_t PollingTask::startTask() { rtems_status_code status = rtems_task_start(id, PollingTask::taskEntryPoint, rtems_task_argument((void *) this)); if (status != RTEMS_SUCCESSFUL) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "PollingTask::startTask for " << std::hex << this->getId() << std::dec << " failed." << std::endl; +#endif } switch(status){ case RTEMS_SUCCESSFUL: @@ -75,8 +81,10 @@ ReturnValue_t PollingTask::addSlot(object_id_t componentId, return HasReturnvaluesIF::RETURN_OK; } +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "Component " << std::hex << componentId << " not found, not adding it to pst" << std::endl; +#endif return HasReturnvaluesIF::RETURN_FAILED; } diff --git a/osal/rtems/TaskBase.cpp b/osal/rtems/TaskBase.cpp index 4e0c8f00..6abfcca8 100644 --- a/osal/rtems/TaskBase.cpp +++ b/osal/rtems/TaskBase.cpp @@ -22,9 +22,11 @@ TaskBase::TaskBase(rtems_task_priority set_priority, size_t stack_size, } ReturnValue_t result = convertReturnCode(status); if (result != HasReturnvaluesIF::RETURN_OK) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "TaskBase::TaskBase: createTask with name " << std::hex << osalName << std::dec << " failed with return code " << (uint32_t) status << std::endl; +#endif this->id = 0; } } diff --git a/osal/windows/TcWinUdpPollingTask.cpp b/osal/windows/TcWinUdpPollingTask.cpp index 06deafd1..4fd88c93 100644 --- a/osal/windows/TcWinUdpPollingTask.cpp +++ b/osal/windows/TcWinUdpPollingTask.cpp @@ -43,13 +43,17 @@ ReturnValue_t TcWinUdpPollingTask::performOperation(uint8_t opCode) { &senderAddressSize); if(bytesReceived == SOCKET_ERROR) { // handle error +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "TcWinUdpPollingTask::performOperation: Reception" " error." << std::endl; +#endif handleReadError(); continue; } +#if FSFW_CPP_OSTREAM_ENABLED == 1 //sif::debug << "TcWinUdpPollingTask::performOperation: " << bytesReceived // << " bytes received" << std::endl; +#endif ReturnValue_t result = handleSuccessfullTcRead(bytesReceived); if(result != HasReturnvaluesIF::RETURN_FAILED) { @@ -68,9 +72,11 @@ ReturnValue_t TcWinUdpPollingTask::handleSuccessfullTcRead(size_t bytesRead) { receptionBuffer.data(), bytesRead); // arrayprinter::print(receptionBuffer.data(), bytesRead); if (result != HasReturnvaluesIF::RETURN_OK) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "TcSerialPollingTask::transferPusToSoftwareBus: Data " "storage failed" << std::endl; sif::error << "Packet size: " << bytesRead << std::endl; +#endif return HasReturnvaluesIF::RETURN_FAILED; } @@ -78,8 +84,10 @@ ReturnValue_t TcWinUdpPollingTask::handleSuccessfullTcRead(size_t bytesRead) { result = MessageQueueSenderIF::sendMessage(targetTcDestination, &message); if (result != HasReturnvaluesIF::RETURN_OK) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "Serial Polling: Sending message to queue failed" << std::endl; +#endif tcStore->deleteData(storeId); } return result; @@ -88,21 +96,27 @@ ReturnValue_t TcWinUdpPollingTask::handleSuccessfullTcRead(size_t bytesRead) { ReturnValue_t TcWinUdpPollingTask::initialize() { tcStore = objectManager->get(objects::TC_STORE); if (tcStore == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "TcSerialPollingTask::initialize: TC Store uninitialized!" << std::endl; +#endif return ObjectManagerIF::CHILD_INIT_FAILED; } tmtcBridge = objectManager->get(tmtcBridgeId); if(tmtcBridge == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "TcSocketPollingTask::TcSocketPollingTask: Invalid" " TMTC bridge object!" << std::endl; +#endif return ObjectManagerIF::CHILD_INIT_FAILED; } serverUdpSocket = tmtcBridge->serverSocket; +#if FSFW_CPP_OSTREAM_ENABLED == 1 //sif::info << "TcWinUdpPollingTask::initialize: Server UDP socket " // << serverUdpSocket << std::endl; +#endif return HasReturnvaluesIF::RETURN_OK; } @@ -119,8 +133,10 @@ void TcWinUdpPollingTask::setTimeout(double timeoutSeconds) { int result = setsockopt(serverUdpSocket, SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast(&timeoutMs), sizeof(DWORD)); if(result == -1) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "TcWinUdpPollingTask::TcSocketPollingTask: Setting " "receive timeout failed with " << strerror(errno) << std::endl; +#endif } } @@ -128,23 +144,31 @@ void TcWinUdpPollingTask::handleReadError() { int error = WSAGetLastError(); switch(error) { case(WSANOTINITIALISED): { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::info << "TcWinUdpPollingTask::handleReadError: WSANOTINITIALISED: " << "WSAStartup(...) call " << "necessary" << std::endl; +#endif break; } case(WSAEFAULT): { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::info << "TcWinUdpPollingTask::handleReadError: WSADEFAULT: " << "Bad address " << std::endl; +#endif break; } case(WSAEINVAL): { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::info << "TcWinUdpPollingTask::handleReadError: WSAEINVAL: " << "Invalid input parameters. " << std::endl; +#endif break; } default: { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::info << "TcWinUdpPollingTask::handleReadError: Error code: " << error << std::endl; +#endif break; } } diff --git a/osal/windows/TmTcWinUdpBridge.cpp b/osal/windows/TmTcWinUdpBridge.cpp index e1ba132e..69a48f3e 100644 --- a/osal/windows/TmTcWinUdpBridge.cpp +++ b/osal/windows/TmTcWinUdpBridge.cpp @@ -15,8 +15,10 @@ TmTcWinUdpBridge::TmTcWinUdpBridge(object_id_t objectId, if (err != 0) { /* Tell the user that we could not find a usable */ /* Winsock DLL. */ +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "TmTcWinUdpBridge::TmTcWinUdpBridge:" "WSAStartup failed with error: " << err << std::endl; +#endif return; } @@ -34,8 +36,10 @@ TmTcWinUdpBridge::TmTcWinUdpBridge(object_id_t objectId, //clientSocket = socket(AF_INET, SOCK_DGRAM, 0); serverSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if(serverSocket == INVALID_SOCKET) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "TmTcWinUdpBridge::TmTcWinUdpBridge: Could not open" " UDP socket!" << std::endl; +#endif handleSocketError(); return; } @@ -59,9 +63,11 @@ TmTcWinUdpBridge::TmTcWinUdpBridge(object_id_t objectId, reinterpret_cast(&serverAddress), serverAddressLen); if(result != 0) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "TmTcWinUdpBridge::TmTcWinUdpBridge: Could not bind " "local port " << setServerPort << " to server socket!" << std::endl; +#endif handleBindError(); } } @@ -77,19 +83,25 @@ ReturnValue_t TmTcWinUdpBridge::sendTm(const uint8_t *data, size_t dataLen) { //clientAddressLen = sizeof(serverAddress); // char ipAddress [15]; +#if FSFW_CPP_OSTREAM_ENABLED == 1 // sif::debug << "IP Address Sender: "<< inet_ntop(AF_INET, // &clientAddress.sin_addr.s_addr, ipAddress, 15) << std::endl; +#endif ssize_t bytesSent = sendto(serverSocket, reinterpret_cast(data), dataLen, flags, reinterpret_cast(&clientAddress), clientAddressLen); if(bytesSent == SOCKET_ERROR) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "TmTcWinUdpBridge::sendTm: Send operation failed." << std::endl; +#endif handleSendError(); } +#if FSFW_CPP_OSTREAM_ENABLED == 1 // sif::debug << "TmTcUnixUdpBridge::sendTm: " << bytesSent << " bytes were" // " sent." << std::endl; +#endif return HasReturnvaluesIF::RETURN_OK; } @@ -97,10 +109,12 @@ void TmTcWinUdpBridge::checkAndSetClientAddress(sockaddr_in newAddress) { MutexHelper lock(mutex, MutexIF::TimeoutType::WAITING, 10); // char ipAddress [15]; +#if FSFW_CPP_OSTREAM_ENABLED == 1 // sif::debug << "IP Address Sender: "<< inet_ntop(AF_INET, // &newAddress.sin_addr.s_addr, ipAddress, 15) << std::endl; // sif::debug << "IP Address Old: " << inet_ntop(AF_INET, // &clientAddress.sin_addr.s_addr, ipAddress, 15) << std::endl; +#endif registerCommConnect(); // Set new IP address if it has changed. @@ -114,8 +128,10 @@ void TmTcWinUdpBridge::handleSocketError() { int errCode = WSAGetLastError(); switch(errCode) { case(WSANOTINITIALISED): { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::info << "TmTcWinUdpBridge::handleSocketError: WSANOTINITIALISED: " << "WSAStartup(...) call necessary" << std::endl; +#endif break; } default: { @@ -123,8 +139,10 @@ void TmTcWinUdpBridge::handleSocketError() { https://docs.microsoft.com/en-us/windows/win32/winsock/ windows-sockets-error-codes-2 */ +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::info << "TmTcWinUdpBridge::handleSocketError: Error code: " << errCode << std::endl; +#endif break; } } @@ -134,13 +152,17 @@ void TmTcWinUdpBridge::handleBindError() { int errCode = WSAGetLastError(); switch(errCode) { case(WSANOTINITIALISED): { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::info << "TmTcWinUdpBridge::handleBindError: WSANOTINITIALISED: " << "WSAStartup(...) call " << "necessary" << std::endl; +#endif break; } case(WSAEADDRINUSE): { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "TmTcWinUdpBridge::handleBindError: WSAEADDRINUSE: " << "Port is already in use!" << std::endl; +#endif break; } default: { @@ -148,8 +170,10 @@ void TmTcWinUdpBridge::handleBindError() { https://docs.microsoft.com/en-us/windows/win32/winsock/ windows-sockets-error-codes-2 */ +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::info << "TmTcWinUdpBridge::handleBindError: Error code: " << errCode << std::endl; +#endif break; } } @@ -159,13 +183,17 @@ void TmTcWinUdpBridge::handleSendError() { int errCode = WSAGetLastError(); switch(errCode) { case(WSANOTINITIALISED): { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::info << "TmTcWinUdpBridge::handleSendError: WSANOTINITIALISED: " << "WSAStartup(...) call necessary" << std::endl; +#endif break; } case(WSAEADDRNOTAVAIL): { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::info << "TmTcWinUdpBridge::handleSendError: WSAEADDRNOTAVAIL: " << "Check target address. " << std::endl; +#endif break; } default: { @@ -173,8 +201,10 @@ void TmTcWinUdpBridge::handleSendError() { https://docs.microsoft.com/en-us/windows/win32/winsock/ windows-sockets-error-codes-2 */ +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::info << "TmTcWinUdpBridge::handleSendError: Error code: " << errCode << std::endl; +#endif break; } } diff --git a/parameters/ParameterHelper.cpp b/parameters/ParameterHelper.cpp index 23d1a1f3..4ad5cdf2 100644 --- a/parameters/ParameterHelper.cpp +++ b/parameters/ParameterHelper.cpp @@ -48,8 +48,10 @@ ReturnValue_t ParameterHelper::handleParameterMessage(CommandMessage *message) { ConstStorageAccessor accessor(storeId); result = storage->getData(storeId, accessor); if (result != HasReturnvaluesIF::RETURN_OK) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "ParameterHelper::handleParameterMessage: Getting" << " store data failed for load command." << std::endl; +#endif break; } diff --git a/power/Fuse.cpp b/power/Fuse.cpp index 1c30d83f..b6e0a7f1 100644 --- a/power/Fuse.cpp +++ b/power/Fuse.cpp @@ -65,8 +65,8 @@ ReturnValue_t Fuse::check() { set.read(); if (!healthHelper.healthTable->isHealthy(getObjectId())) { setAllMonitorsToUnchecked(); - set.commit(PoolVariableIF::INVALID); - return RETURN_OK; + set.setValidity(false, true); + return set.commit(); } ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; checkFuseState(); @@ -206,7 +206,8 @@ float Fuse::getPower() { void Fuse::setDataPoolEntriesInvalid() { set.read(); - set.commit(PoolVariableIF::INVALID); + set.setValidity(false, true); + set.commit(); } ReturnValue_t Fuse::getParameter(uint8_t domainId, uint16_t parameterId, diff --git a/power/PowerSensor.cpp b/power/PowerSensor.cpp index 1ef041e3..fb181d9f 100644 --- a/power/PowerSensor.cpp +++ b/power/PowerSensor.cpp @@ -97,7 +97,8 @@ void PowerSensor::checkCommandQueue() { void PowerSensor::setDataPoolEntriesInvalid() { powerSensorSet.read(); - powerSensorSet.commit(PoolVariableIF::INVALID); + powerSensorSet.setValidity(false, true); + powerSensorSet.commit(); } float PowerSensor::getPower() { diff --git a/pus/CService201HealthCommanding.cpp b/pus/CService201HealthCommanding.cpp index edacd73a..ca761f14 100644 --- a/pus/CService201HealthCommanding.cpp +++ b/pus/CService201HealthCommanding.cpp @@ -22,7 +22,9 @@ ReturnValue_t CService201HealthCommanding::isValidSubservice(uint8_t subservice) case(Subservice::COMMAND_ANNOUNCE_HEALTH_ALL): return RETURN_OK; default: +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "Invalid Subservice" << std::endl; +#endif return AcceptsTelecommandsIF::INVALID_SUBSERVICE; } } diff --git a/pus/Service1TelecommandVerification.cpp b/pus/Service1TelecommandVerification.cpp index 86b0dcde..9e86c752 100644 --- a/pus/Service1TelecommandVerification.cpp +++ b/pus/Service1TelecommandVerification.cpp @@ -51,8 +51,10 @@ ReturnValue_t Service1TelecommandVerification::sendVerificationReport( result = generateSuccessReport(message); } if(result != HasReturnvaluesIF::RETURN_OK){ +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "Service1TelecommandVerification::sendVerificationReport: " "Sending verification packet failed !" << std::endl; +#endif } return result; } @@ -88,9 +90,11 @@ ReturnValue_t Service1TelecommandVerification::initialize() { AcceptsTelemetryIF* funnel = objectManager-> get(targetDestination); if(funnel == nullptr){ +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "Service1TelecommandVerification::initialize: Specified" " TM funnel invalid. Make sure it is set up and implements" " AcceptsTelemetryIF." << std::endl; +#endif return ObjectManagerIF::CHILD_INIT_FAILED; } tmQueue->setDefaultDestination(funnel->getReportReceptionQueue()); diff --git a/pus/Service2DeviceAccess.cpp b/pus/Service2DeviceAccess.cpp index 3648b7eb..72db82df 100644 --- a/pus/Service2DeviceAccess.cpp +++ b/pus/Service2DeviceAccess.cpp @@ -25,7 +25,9 @@ ReturnValue_t Service2DeviceAccess::isValidSubservice(uint8_t subservice) { case Subservice::COMMAND_TOGGLE_WIRETAPPING: return HasReturnvaluesIF::RETURN_OK; default: +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "Invalid Subservice" << std::endl; +#endif return AcceptsTelecommandsIF::INVALID_SUBSERVICE; } } @@ -125,9 +127,11 @@ void Service2DeviceAccess::handleUnrequestedReply(CommandMessage* reply) { static_cast(Subservice::REPLY_RAW)); break; default: +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "Unknown message in Service2DeviceAccess::" "handleUnrequestedReply with command ID " << reply->getCommand() << std::endl; +#endif break; } //Must be reached by all cases to clear message @@ -143,9 +147,11 @@ void Service2DeviceAccess::sendWiretappingTm(CommandMessage *reply, size_t size = 0; ReturnValue_t result = IPCStore->getData(storeAddress, &data, &size); if(result != HasReturnvaluesIF::RETURN_OK){ +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "Service2DeviceAccess::sendWiretappingTm: Data Lost in " "handleUnrequestedReply with failure ID "<< result << std::endl; +#endif return; } diff --git a/pus/Service3Housekeeping.cpp b/pus/Service3Housekeeping.cpp index 175af026..ba7ff6ee 100644 --- a/pus/Service3Housekeeping.cpp +++ b/pus/Service3Housekeeping.cpp @@ -222,8 +222,10 @@ ReturnValue_t Service3Housekeeping::handleReply(const CommandMessage* reply, } default: +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "Service3Housekeeping::handleReply: Invalid reply with " << "reply command " << command << "!" << std::endl; +#endif return CommandingServiceBase::INVALID_REPLY; } return HasReturnvaluesIF::RETURN_OK; @@ -249,16 +251,20 @@ void Service3Housekeeping::handleUnrequestedReply( } default: +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "Service3Housekeeping::handleUnrequestedReply: Invalid " << "reply with " << "reply command " << command << "!" << std::endl; +#endif return; } if(result != HasReturnvaluesIF::RETURN_OK) { // Configuration error +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::debug << "Service3Housekeeping::handleUnrequestedReply:" << "Could not generate reply!" << std::endl; +#endif } } diff --git a/pus/Service5EventReporting.cpp b/pus/Service5EventReporting.cpp index e0b34a5b..29eb7f20 100644 --- a/pus/Service5EventReporting.cpp +++ b/pus/Service5EventReporting.cpp @@ -37,8 +37,10 @@ ReturnValue_t Service5EventReporting::performService() { } } } +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::debug << "Service5EventReporting::generateEventReport:" " Too many events" << std::endl; +#endif return HasReturnvaluesIF::RETURN_OK; } @@ -53,8 +55,10 @@ ReturnValue_t Service5EventReporting::generateEventReport( ReturnValue_t result = tmPacket.sendPacket( requestQueue->getDefaultDestination(),requestQueue->getId()); if(result != HasReturnvaluesIF::RETURN_OK) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::debug << "Service5EventReporting::generateEventReport:" " Could not send TM packet" << std::endl; +#endif } return result; } diff --git a/pus/Service8FunctionManagement.cpp b/pus/Service8FunctionManagement.cpp index d710c56e..49fa6ebe 100644 --- a/pus/Service8FunctionManagement.cpp +++ b/pus/Service8FunctionManagement.cpp @@ -60,9 +60,11 @@ ReturnValue_t Service8FunctionManagement::prepareCommand( ReturnValue_t Service8FunctionManagement::prepareDirectCommand( CommandMessage *message, const uint8_t *tcData, size_t tcDataLen) { if(tcDataLen < sizeof(object_id_t) + sizeof(ActionId_t)) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::debug << "Service8FunctionManagement::prepareDirectCommand:" << " TC size smaller thant minimum size of direct command." << std::endl; +#endif return CommandingServiceBase::INVALID_TC; } @@ -125,8 +127,10 @@ ReturnValue_t Service8FunctionManagement::handleDataReply( const uint8_t * buffer = nullptr; ReturnValue_t result = IPCStore->getData(storeId, &buffer, &size); if(result != RETURN_OK) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "Service 8: Could not retrieve data for data reply" << std::endl; +#endif return result; } DataReply dataReply(objectId, actionId, buffer, size); @@ -135,8 +139,10 @@ ReturnValue_t Service8FunctionManagement::handleDataReply( auto deletionResult = IPCStore->deleteData(storeId); if(deletionResult != HasReturnvaluesIF::RETURN_OK) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "Service8FunctionManagement::handleReply: Deletion" << " of data in pool failed." << std::endl; +#endif } return result; } diff --git a/serialize/EndianConverter.h b/serialize/EndianConverter.h index c888a905..3b19832e 100644 --- a/serialize/EndianConverter.h +++ b/serialize/EndianConverter.h @@ -3,7 +3,7 @@ #include "../osal/Endiness.h" #include -#include +#include /** * Helper class to convert variables or bitstreams between machine diff --git a/serialize/SerialBufferAdapter.cpp b/serialize/SerialBufferAdapter.cpp index 1c11afd4..53b8c3d5 100644 --- a/serialize/SerialBufferAdapter.cpp +++ b/serialize/SerialBufferAdapter.cpp @@ -95,8 +95,10 @@ ReturnValue_t SerialBufferAdapter::deSerialize(const uint8_t** buffer, template uint8_t * SerialBufferAdapter::getBuffer() { if(buffer == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "Wrong access function for stored type !" " Use getConstBuffer()." << std::endl; +#endif return nullptr; } return buffer; @@ -105,8 +107,10 @@ uint8_t * SerialBufferAdapter::getBuffer() { template const uint8_t * SerialBufferAdapter::getConstBuffer() { if(constBuffer == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "SerialBufferAdapter::getConstBuffer:" " Buffers are unitialized!" << std::endl; +#endif return nullptr; } return constBuffer; diff --git a/serviceinterface/CMakeLists.txt b/serviceinterface/CMakeLists.txt index d84adbeb..84c79177 100644 --- a/serviceinterface/CMakeLists.txt +++ b/serviceinterface/CMakeLists.txt @@ -1,5 +1,5 @@ -target_sources(${LIB_FSFW_NAME} - PRIVATE - ServiceInterfaceStream.cpp - ServiceInterfaceBuffer.cpp +target_sources(${LIB_FSFW_NAME} PRIVATE + ServiceInterfaceStream.cpp + ServiceInterfaceBuffer.cpp + ServiceInterfacePrinter.cpp ) \ No newline at end of file diff --git a/serviceinterface/ServiceInterface.h b/serviceinterface/ServiceInterface.h new file mode 100644 index 00000000..1f7e5e84 --- /dev/null +++ b/serviceinterface/ServiceInterface.h @@ -0,0 +1,13 @@ +#ifndef FSFW_SERVICEINTERFACE_SERVICEINTERFACE_H_ +#define FSFW_SERVICEINTERFACE_SERVICEINTERFACE_H_ + +#include +#include "serviceInterfaceDefintions.h" + +#if FSFW_CPP_OSTREAM_ENABLED == 1 +#include +#else +#include +#endif + +#endif /* FSFW_SERVICEINTERFACE_SERVICEINTERFACE_H_ */ diff --git a/serviceinterface/ServiceInterfaceBuffer.cpp b/serviceinterface/ServiceInterfaceBuffer.cpp index 68fc4dec..1a02d6e9 100644 --- a/serviceinterface/ServiceInterfaceBuffer.cpp +++ b/serviceinterface/ServiceInterfaceBuffer.cpp @@ -1,8 +1,17 @@ -#include "../timemanager/Clock.h" #include "ServiceInterfaceBuffer.h" + +#if FSFW_CPP_OSTREAM_ENABLED == 1 + +#include "../timemanager/Clock.h" + +#include "serviceInterfaceDefintions.h" #include #include +#if defined(WIN32) && FSFW_COLORED_OUTPUT == 1 +#include "Windows.h" +#endif + // to be implemented by bsp extern "C" void printChar(const char*, bool errStream); @@ -17,6 +26,34 @@ ServiceInterfaceBuffer::ServiceInterfaceBuffer(std::string setMessage, // Set pointers if the stream is buffered. setp( buf, buf + BUF_SIZE ); } + +#if FSFW_COLORED_OUTPUT == 1 + if(setMessage.find("DEBUG") != std::string::npos) { + colorPrefix = sif::ANSI_COLOR_MAGENTA; + } + else if(setMessage.find("INFO") != std::string::npos) { + colorPrefix = sif::ANSI_COLOR_GREEN; + } + else if(setMessage.find("WARNING") != std::string::npos) { + colorPrefix = sif::ANSI_COLOR_YELLOW; + } + else if(setMessage.find("ERROR") != std::string::npos) { + colorPrefix = sif::ANSI_COLOR_RED; + } + else { + colorPrefix = sif::ANSI_COLOR_RESET; + } + +#ifdef WIN32 + HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); + DWORD dwMode = 0; + GetConsoleMode(hOut, &dwMode); + dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; + SetConsoleMode(hOut, dwMode); +#endif + +#endif + preamble.reserve(MAX_PREAMBLE_SIZE); preamble.resize(MAX_PREAMBLE_SIZE); } @@ -102,6 +139,12 @@ std::string* ServiceInterfaceBuffer::getPreamble(size_t * preambleSize) { currentSize += 1; parsePosition += 1; } + +#if FSFW_COLORED_OUTPUT == 1 + currentSize += sprintf(parsePosition, "%s", colorPrefix.c_str()); + parsePosition += colorPrefix.size(); +#endif + int32_t charCount = sprintf(parsePosition, "%s: | %02" SCNu32 ":%02" SCNu32 ":%02" SCNu32 ".%03" SCNu32 " | ", this->logMessage.c_str(), loggerTime.hour, @@ -215,3 +258,5 @@ void ServiceInterfaceBuffer::initSocket() { } #endif //ML505 + +#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ diff --git a/serviceinterface/ServiceInterfaceBuffer.h b/serviceinterface/ServiceInterfaceBuffer.h index c5d5b258..b1a50848 100644 --- a/serviceinterface/ServiceInterfaceBuffer.h +++ b/serviceinterface/ServiceInterfaceBuffer.h @@ -2,6 +2,10 @@ #define FRAMEWORK_SERVICEINTERFACE_SERVICEINTERFACEBUFFER_H_ #include "../returnvalues/HasReturnvaluesIF.h" +#include + +#if FSFW_CPP_OSTREAM_ENABLED == 1 + #include #include #include @@ -41,6 +45,11 @@ private: //! For additional message information std::string logMessage; std::string preamble; + +#if FSFW_COLORED_OUTPUT == 1 + std::string colorPrefix; +#endif + // For EOF detection typedef std::char_traits Traits; @@ -54,7 +63,7 @@ private: bool errStream; //! Needed for buffered mode. - static size_t const BUF_SIZE = 128; + static size_t const BUF_SIZE = fsfwconfig::FSFW_PRINT_BUFFER_SIZE; char buf[BUF_SIZE]; //! In this function, the characters are parsed. @@ -141,5 +150,6 @@ private: }; #endif //ML505 +#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ #endif /* FRAMEWORK_SERVICEINTERFACE_SERVICEINTERFACEBUFFER_H_ */ diff --git a/serviceinterface/ServiceInterfacePrinter.cpp b/serviceinterface/ServiceInterfacePrinter.cpp new file mode 100644 index 00000000..a12f49e3 --- /dev/null +++ b/serviceinterface/ServiceInterfacePrinter.cpp @@ -0,0 +1,140 @@ +#include +#include "ServiceInterfacePrinter.h" +#include "serviceInterfaceDefintions.h" +#include "../timemanager/Clock.h" + +#include +#include + +static sif::PrintLevel printLevel = sif::PrintLevel::DEBUG_LEVEL; +#if defined(WIN32) && FSFW_COLORED_OUTPUT == 1 +static bool consoleInitialized = false; +#endif /* defined(WIN32) && FSFW_COLORED_OUTPUT == 1 */ + +#if FSFW_DISABLE_PRINTOUT == 0 + +static bool addCrAtEnd = false; + +uint8_t printBuffer[fsfwconfig::FSFW_PRINT_BUFFER_SIZE]; + +void fsfwPrint(sif::PrintLevel printType, const char* fmt, va_list arg) { + +#if defined(WIN32) && FSFW_COLORED_OUTPUT == 1 + if(not consoleInitialized) { + HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); + DWORD dwMode = 0; + GetConsoleMode(hOut, &dwMode); + dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; + SetConsoleMode(hOut, dwMode); + } + consoleInitialized = true; +#endif + + size_t len = 0; + char* bufferPosition = reinterpret_cast(printBuffer); + + /* Check logger level */ + if(printType == sif::PrintLevel::NONE or printType > printLevel) { + return; + } + + /* Log message to terminal */ + +#if FSFW_COLORED_OUTPUT == 1 + if(printType == sif::PrintLevel::INFO_LEVEL) { + len += sprintf(bufferPosition, sif::ANSI_COLOR_GREEN); + } + else if(printType == sif::PrintLevel::DEBUG_LEVEL) { + len += sprintf(bufferPosition, sif::ANSI_COLOR_MAGENTA); + } + else if(printType == sif::PrintLevel::WARNING_LEVEL) { + len += sprintf(bufferPosition, sif::ANSI_COLOR_YELLOW); + } + else if(printType == sif::PrintLevel::ERROR_LEVEL) { + len += sprintf(bufferPosition, sif::ANSI_COLOR_RED); + } +#endif + + if (printType == sif::PrintLevel::INFO_LEVEL) { + len += sprintf(bufferPosition + len, "INFO: "); + } + if(printType == sif::PrintLevel::DEBUG_LEVEL) { + len += sprintf(bufferPosition + len, "DEBUG: "); + } + if(printType == sif::PrintLevel::WARNING_LEVEL) { + len += sprintf(bufferPosition + len, "WARNING: "); + } + + if(printType == sif::PrintLevel::ERROR_LEVEL) { + len += sprintf(bufferPosition + len, "ERROR: "); + } + + Clock::TimeOfDay_t now; + Clock::getDateAndTime(&now); + /* + * Log current time to terminal if desired. + */ + len += sprintf(bufferPosition + len, "| %lu:%02lu:%02lu.%03lu | ", + (unsigned long) now.hour, + (unsigned long) now.minute, + (unsigned long) now.second, + (unsigned long) now.usecond /1000); + + len += vsnprintf(bufferPosition + len, sizeof(printBuffer) - len, fmt, arg); + + if(addCrAtEnd) { + len += sprintf(bufferPosition + len, "\r"); + } + + printf("%s", printBuffer); +} + + +void sif::printInfo(const char *fmt, ...) { + va_list args; + va_start(args, fmt); + fsfwPrint(sif::PrintLevel::INFO_LEVEL, fmt, args); + va_end(args); +} + +void sif::printWarning(const char *fmt, ...) { + va_list args; + va_start(args, fmt); + fsfwPrint(sif::PrintLevel::WARNING_LEVEL, fmt, args); + va_end(args); +} + +void sif::printDebug(const char *fmt, ...) { + va_list args; + va_start(args, fmt); + fsfwPrint(sif::PrintLevel::DEBUG_LEVEL, fmt, args); + va_end(args); +} + +void sif::setToAddCrAtEnd(bool addCrAtEnd_) { + addCrAtEnd = addCrAtEnd_; +} + +void sif::printError(const char *fmt, ...) { + va_list args; + va_start(args, fmt); + fsfwPrint(sif::PrintLevel::ERROR_LEVEL, fmt, args); + va_end(args); +} + +#else + +void sif::printInfo(const char *fmt, ...) {} +void sif::printWarning(const char *fmt, ...) {} +void sif::printDebug(const char *fmt, ...) {} +void sif::printError(const char *fmt, ...) {} + +#endif /* FSFW_DISABLE_PRINTOUT == 0 */ + +void sif::setPrintLevel(PrintLevel printLevel_) { + printLevel = printLevel_; +} + +sif::PrintLevel sif::getPrintLevel() { + return printLevel; +} diff --git a/serviceinterface/ServiceInterfacePrinter.h b/serviceinterface/ServiceInterfacePrinter.h new file mode 100644 index 00000000..fbdccdd1 --- /dev/null +++ b/serviceinterface/ServiceInterfacePrinter.h @@ -0,0 +1,40 @@ +#if FSFW_DISABLE_PRINTOUT == 0 +#include +#endif + +namespace sif { + +enum PrintLevel { + NONE = 0, + //! Strange error when using just ERROR.. + ERROR_LEVEL = 1, + WARNING_LEVEL = 2, + INFO_LEVEL = 3, + DEBUG_LEVEL = 4 +}; + +/** + * Set the print level. All print types with a smaller level will be printed + * as well. For example, set to PrintLevel::WARNING to only enable error + * and warning output. + * @param printLevel + */ +void setPrintLevel(PrintLevel printLevel); +PrintLevel getPrintLevel(); + +void setToAddCrAtEnd(bool addCrAtEnd_); + +/** + * These functions can be used like the C stdio printf and forward the + * supplied formatted string arguments to a printf function. + * They prepend the string with a color (if enabled), a log preamble and + * a timestamp. + * @param fmt Formatted string + */ +void printInfo(const char *fmt, ...); +void printWarning(const char* fmt, ...); +void printDebug(const char* fmt, ...); +void printError(const char* fmt, ...); + +} + diff --git a/serviceinterface/ServiceInterfaceStream.cpp b/serviceinterface/ServiceInterfaceStream.cpp index 5b7b9f00..59526536 100644 --- a/serviceinterface/ServiceInterfaceStream.cpp +++ b/serviceinterface/ServiceInterfaceStream.cpp @@ -1,5 +1,7 @@ #include "ServiceInterfaceStream.h" +#if FSFW_CPP_OSTREAM_ENABLED == 1 + ServiceInterfaceStream::ServiceInterfaceStream(std::string setMessage, bool addCrToPreamble, bool buffered, bool errStream, uint16_t port) : std::ostream(&streambuf), @@ -13,20 +15,5 @@ std::string* ServiceInterfaceStream::getPreamble() { return streambuf.getPreamble(); } -void ServiceInterfaceStream::print(std::string error, - bool withPreamble, bool withNewline, bool flush) { - if(not streambuf.isBuffered() and withPreamble) { - *this << getPreamble() << error; - } - else { - *this << error; - } +#endif - if(withNewline) { - *this << "\n"; - } - // if mode is non-buffered, no need to flush. - if(flush and streambuf.isBuffered()) { - this->flush(); - } -} diff --git a/serviceinterface/ServiceInterfaceStream.h b/serviceinterface/ServiceInterfaceStream.h index 76fa1bf2..f3cb2cd0 100644 --- a/serviceinterface/ServiceInterfaceStream.h +++ b/serviceinterface/ServiceInterfaceStream.h @@ -2,6 +2,10 @@ #define FRAMEWORK_SERVICEINTERFACE_SERVICEINTERFACESTREAM_H_ #include "ServiceInterfaceBuffer.h" +#include + +#if FSFW_CPP_OSTREAM_ENABLED == 1 + #include #include @@ -35,13 +39,6 @@ public: */ std::string* getPreamble(); - /** - * This prints an error with a preamble. Useful if using the unbuffered - * mode. Flushes in default mode (prints immediately). - */ - void print(std::string error, bool withPreamble = true, - bool withNewline = true, bool flush = true); - protected: ServiceInterfaceBuffer streambuf; }; @@ -55,4 +52,6 @@ extern ServiceInterfaceStream warning; extern ServiceInterfaceStream error; } +#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ + #endif /* FRAMEWORK_SERVICEINTERFACE_SERVICEINTERFACESTREAM_H_ */ diff --git a/serviceinterface/serviceInterfaceDefintions.h b/serviceinterface/serviceInterfaceDefintions.h new file mode 100644 index 00000000..eb36a84b --- /dev/null +++ b/serviceinterface/serviceInterfaceDefintions.h @@ -0,0 +1,23 @@ +#ifndef FSFW_SERVICEINTERFACE_SERVICEINTERFACEDEFINTIONS_H_ +#define FSFW_SERVICEINTERFACE_SERVICEINTERFACEDEFINTIONS_H_ + +namespace sif { + +enum class OutputTypes { + OUT_INFO, + OUT_DEBUG, + OUT_WARNING, + OUT_ERROR +}; + +static const char* const ANSI_COLOR_RED = "\x1b[31m"; +static const char* const ANSI_COLOR_GREEN = "\x1b[32m"; +static const char* const ANSI_COLOR_YELLOW = "\x1b[33m"; +static const char* const ANSI_COLOR_BLUE = "\x1b[34m"; +static const char* const ANSI_COLOR_MAGENTA = "\x1b[35m"; +static const char* const ANSI_COLOR_CYAN = "\x1b[36m"; +static const char* const ANSI_COLOR_RESET = "\x1b[0m"; + +} + +#endif /* FSFW_SERVICEINTERFACE_SERVICEINTERFACEDEFINTIONS_H_ */ diff --git a/storagemanager/ConstStorageAccessor.cpp b/storagemanager/ConstStorageAccessor.cpp index 842f1ce8..aab84862 100644 --- a/storagemanager/ConstStorageAccessor.cpp +++ b/storagemanager/ConstStorageAccessor.cpp @@ -4,6 +4,8 @@ #include "../serviceinterface/ServiceInterfaceStream.h" #include "../globalfunctions/arrayprinter.h" +#include + ConstStorageAccessor::ConstStorageAccessor(store_address_t storeId): storeId(storeId) {} @@ -46,7 +48,9 @@ const uint8_t* ConstStorageAccessor::data() const { size_t ConstStorageAccessor::size() const { if(internalState == AccessState::UNINIT) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "StorageAccessor: Not initialized!" << std::endl; +#endif } return size_; } @@ -54,12 +58,16 @@ size_t ConstStorageAccessor::size() const { ReturnValue_t ConstStorageAccessor::getDataCopy(uint8_t *pointer, size_t maxSize) { if(internalState == AccessState::UNINIT) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "StorageAccessor: Not initialized!" << std::endl; +#endif return HasReturnvaluesIF::RETURN_FAILED; } if(size_ > maxSize) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "StorageAccessor: Supplied buffer not large enough" << std::endl; +#endif return HasReturnvaluesIF::RETURN_FAILED; } std::copy(constDataPointer, constDataPointer + size_, pointer); @@ -76,7 +84,9 @@ store_address_t ConstStorageAccessor::getId() const { void ConstStorageAccessor::print() const { if(internalState == AccessState::UNINIT or constDataPointer == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "StorageAccessor: Not initialized!" << std::endl; +#endif return; } arrayprinter::print(constDataPointer, size_); diff --git a/storagemanager/LocalPool.cpp b/storagemanager/LocalPool.cpp index 74e362d4..cc7c9266 100644 --- a/storagemanager/LocalPool.cpp +++ b/storagemanager/LocalPool.cpp @@ -8,8 +8,10 @@ LocalPool::LocalPool(object_id_t setObjectId, const LocalPoolConfig& poolConfig, NUMBER_OF_POOLS(poolConfig.size()), spillsToHigherPools(spillsToHigherPools) { if(NUMBER_OF_POOLS == 0) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "LocalPool::LocalPool: Passed pool configuration is " << " invalid!" << std::endl; +#endif } max_pools_t index = 0; for (const auto& currentPoolConfig: poolConfig) { @@ -118,8 +120,10 @@ ReturnValue_t LocalPool::modifyData(store_address_t storeId, ReturnValue_t LocalPool::deleteData(store_address_t storeId) { #if FSFW_VERBOSE_PRINTOUT == 2 +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::debug << "Delete: Pool: " << std::dec << storeId.poolIndex << " Index: " << storeId.packetIndex << std::endl; +#endif #endif ReturnValue_t status = RETURN_OK; @@ -134,8 +138,10 @@ ReturnValue_t LocalPool::deleteData(store_address_t storeId) { } else { //pool_index or packet_index is too large +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "LocalPool::deleteData: Illegal store ID, no deletion!" << std::endl; +#endif status = ILLEGAL_STORAGE_ID; } return status; @@ -158,8 +164,10 @@ ReturnValue_t LocalPool::deleteData(uint8_t *ptr, size_t size, result = deleteData(localId); #if FSFW_VERBOSE_PRINTOUT == 2 if (deltaAddress % elementSizes[n] != 0) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "LocalPool::deleteData: Address not aligned!" << std::endl; +#endif } #endif break; @@ -186,8 +194,10 @@ ReturnValue_t LocalPool::initialize() { //Check if any pool size is large than the maximum allowed. for (uint8_t count = 0; count < NUMBER_OF_POOLS; count++) { if (elementSizes[count] >= STORAGE_FREE) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "LocalPool::initialize: Pool is too large! " "Max. allowed size is: " << (STORAGE_FREE - 1) << std::endl; +#endif return StorageManagerIF::POOL_TOO_LARGE; } } @@ -209,8 +219,10 @@ ReturnValue_t LocalPool::reserveSpace(const size_t size, store_address_t *storeId, bool ignoreFault) { ReturnValue_t status = getPoolIndex(size, &storeId->poolIndex); if (status != RETURN_OK) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "LocalPool( " << std::hex << getObjectId() << std::dec << " )::reserveSpace: Packet too large." << std::endl; +#endif return status; } status = findEmpty(storeId->poolIndex, &storeId->packetIndex); @@ -224,9 +236,11 @@ ReturnValue_t LocalPool::reserveSpace(const size_t size, } if (status == RETURN_OK) { #if FSFW_VERBOSE_PRINTOUT == 2 +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::debug << "Reserve: Pool: " << std::dec << storeId->poolIndex << " Index: " << storeId->packetIndex << std::endl; +#endif #endif sizeLists[storeId->poolIndex][storeId->packetIndex] = size; } @@ -266,8 +280,10 @@ ReturnValue_t LocalPool::getPoolIndex(size_t packetSize, uint16_t *poolIndex, uint16_t startAtIndex) { for (uint16_t n = startAtIndex; n < NUMBER_OF_POOLS; n++) { #if FSFW_VERBOSE_PRINTOUT == 2 +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::debug << "LocalPool " << getObjectId() << "::getPoolIndex: Pool: " << n << ", Element Size: " << elementSizes[n] << std::endl; +#endif #endif if (elementSizes[n] >= packetSize) { *poolIndex = n; diff --git a/storagemanager/PoolManager.cpp b/storagemanager/PoolManager.cpp index 3b7b549b..4e8014fd 100644 --- a/storagemanager/PoolManager.cpp +++ b/storagemanager/PoolManager.cpp @@ -26,9 +26,11 @@ ReturnValue_t PoolManager::reserveSpace(const size_t size, ReturnValue_t PoolManager::deleteData( store_address_t storeId) { #if FSFW_VERBOSE_PRINTOUT == 2 +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::debug << "PoolManager( " << translateObject(getObjectId()) << " )::deleteData from store " << storeId.poolIndex << ". id is "<< storeId.packetIndex << std::endl; +#endif #endif MutexHelper mutexHelper(mutex, MutexIF::TimeoutType::WAITING, mutexTimeoutMs); diff --git a/storagemanager/StorageAccessor.cpp b/storagemanager/StorageAccessor.cpp index 9c2f936a..a7b4fae4 100644 --- a/storagemanager/StorageAccessor.cpp +++ b/storagemanager/StorageAccessor.cpp @@ -2,6 +2,8 @@ #include "StorageManagerIF.h" #include "../serviceinterface/ServiceInterfaceStream.h" +#include + StorageAccessor::StorageAccessor(store_address_t storeId): ConstStorageAccessor(storeId) { } @@ -26,12 +28,16 @@ StorageAccessor::StorageAccessor(StorageAccessor&& other): ReturnValue_t StorageAccessor::getDataCopy(uint8_t *pointer, size_t maxSize) { if(internalState == AccessState::UNINIT) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "StorageAccessor: Not initialized!" << std::endl; +#endif return HasReturnvaluesIF::RETURN_FAILED; } if(size_ > maxSize) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "StorageAccessor: Supplied buffer not large " "enough" << std::endl; +#endif return HasReturnvaluesIF::RETURN_FAILED; } std::copy(dataPointer, dataPointer + size_, pointer); @@ -40,7 +46,9 @@ ReturnValue_t StorageAccessor::getDataCopy(uint8_t *pointer, size_t maxSize) { uint8_t* StorageAccessor::data() { if(internalState == AccessState::UNINIT) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "StorageAccessor: Not initialized!" << std::endl; +#endif } return dataPointer; } @@ -48,12 +56,16 @@ uint8_t* StorageAccessor::data() { ReturnValue_t StorageAccessor::write(uint8_t *data, size_t size, uint16_t offset) { if(internalState == AccessState::UNINIT) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "StorageAccessor: Not initialized!" << std::endl; +#endif return HasReturnvaluesIF::RETURN_FAILED; } if(offset + size > size_) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "StorageAccessor: Data too large for pool " "entry!" << std::endl; +#endif return HasReturnvaluesIF::RETURN_FAILED; } std::copy(data, data + size, dataPointer + offset); diff --git a/subsystem/SubsystemBase.cpp b/subsystem/SubsystemBase.cpp index f60c8847..bcfa4b0e 100644 --- a/subsystem/SubsystemBase.cpp +++ b/subsystem/SubsystemBase.cpp @@ -86,8 +86,10 @@ void SubsystemBase::executeTable(HybridIterator tableIter, object_id_t object = tableIter.value->getObject(); if ((iter = childrenMap.find(object)) == childrenMap.end()) { //illegal table entry, should only happen due to misconfigured mode table +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::debug << std::hex << getObjectId() << ": invalid mode table entry" << std::endl; +#endif continue; } diff --git a/tasks/FixedSlotSequence.cpp b/tasks/FixedSlotSequence.cpp index e5db4301..54b6ae6d 100644 --- a/tasks/FixedSlotSequence.cpp +++ b/tasks/FixedSlotSequence.cpp @@ -91,8 +91,10 @@ void FixedSlotSequence::addSlot(object_id_t componentId, uint32_t slotTimeMs, ReturnValue_t FixedSlotSequence::checkSequence() const { if(slotList.empty()) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "FixedSlotSequence::checkSequence:" << " Slot list is empty!" << std::endl; +#endif return HasReturnvaluesIF::RETURN_FAILED; } @@ -100,8 +102,10 @@ ReturnValue_t FixedSlotSequence::checkSequence() const { ReturnValue_t result = customCheckFunction(slotList); if(result != HasReturnvaluesIF::RETURN_OK) { // Continue for now but print error output. +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "FixedSlotSequence::checkSequence:" << " Custom check failed!" << std::endl; +#endif } } @@ -112,21 +116,27 @@ ReturnValue_t FixedSlotSequence::checkSequence() const { errorCount++; } else if (slot.pollingTimeMs < time) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "FixedSlotSequence::checkSequence: Time: " << slot.pollingTimeMs << " is smaller than previous with " << time << std::endl; +#endif errorCount++; } else { // All ok, print slot. +#if FSFW_CPP_OSTREAM_ENABLED == 1 //sif::info << "Current slot polling time: " << std::endl; //sif::info << std::dec << slotIt->pollingTimeMs << std::endl; +#endif } time = slot.pollingTimeMs; } +#if FSFW_CPP_OSTREAM_ENABLED == 1 //sif::info << "Number of elements in slot list: " // << slotList.size() << std::endl; +#endif if (errorCount > 0) { return HasReturnvaluesIF::RETURN_FAILED; } @@ -149,8 +159,10 @@ ReturnValue_t FixedSlotSequence::intializeSequenceAfterTaskCreation() const { } } if (count > 0) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "FixedSlotSequence::intializeSequenceAfterTaskCreation:" "Counted " << count << " failed initializations!" << std::endl; +#endif return HasReturnvaluesIF::RETURN_FAILED; } return HasReturnvaluesIF::RETURN_OK; diff --git a/tcdistribution/CCSDSDistributor.cpp b/tcdistribution/CCSDSDistributor.cpp index ddd63308..b795854f 100644 --- a/tcdistribution/CCSDSDistributor.cpp +++ b/tcdistribution/CCSDSDistributor.cpp @@ -11,21 +11,27 @@ CCSDSDistributor::CCSDSDistributor(uint16_t setDefaultApid, CCSDSDistributor::~CCSDSDistributor() {} TcDistributor::TcMqMapIter CCSDSDistributor::selectDestination() { +#if FSFW_CPP_OSTREAM_ENABLED == 1 // sif::debug << "CCSDSDistributor::selectDestination received: " << // this->currentMessage.getStorageId().pool_index << ", " << // this->currentMessage.getStorageId().packet_index << std::endl; +#endif const uint8_t* packet = nullptr; size_t size = 0; ReturnValue_t result = this->tcStore->getData(currentMessage.getStorageId(), &packet, &size ); if(result != HasReturnvaluesIF::RETURN_OK) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "CCSDSDistributor::selectDestination: Getting data from" " store failed!" << std::endl; +#endif } SpacePacketBase currentPacket(packet); +#if FSFW_CPP_OSTREAM_ENABLED == 1 // sif:: info << "CCSDSDistributor::selectDestination has packet with APID " // << std::hex << currentPacket.getAPID() << std::dec << std::endl; +#endif TcMqMapIter position = this->queueMap.find(currentPacket.getAPID()); if ( position != this->queueMap.end() ) { return position; @@ -70,8 +76,10 @@ ReturnValue_t CCSDSDistributor::initialize() { ReturnValue_t status = this->TcDistributor::initialize(); this->tcStore = objectManager->get( objects::TC_STORE ); if (this->tcStore == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "CCSDSDistributor::initialize: Could not initialize" " TC store!" << std::endl; +#endif status = RETURN_FAILED; } return status; diff --git a/tcdistribution/PUSDistributor.cpp b/tcdistribution/PUSDistributor.cpp index 8e5b94cc..00fd9029 100644 --- a/tcdistribution/PUSDistributor.cpp +++ b/tcdistribution/PUSDistributor.cpp @@ -13,9 +13,11 @@ PUSDistributor::PUSDistributor(uint16_t setApid, object_id_t setObjectId, PUSDistributor::~PUSDistributor() {} PUSDistributor::TcMqMapIter PUSDistributor::selectDestination() { +#if FSFW_CPP_OSTREAM_ENABLED == 1 // sif:: debug << "PUSDistributor::handlePacket received: " // << this->current_packet_id.store_index << ", " // << this->current_packet_id.packet_index << std::endl; +#endif TcMqMapIter queueMapIt = this->queueMap.end(); if(this->currentPacket == nullptr) { return queueMapIt; @@ -25,9 +27,11 @@ PUSDistributor::TcMqMapIter PUSDistributor::selectDestination() { tcStatus = checker.checkPacket(currentPacket); #ifdef DEBUG if(tcStatus != HasReturnvaluesIF::RETURN_OK) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::debug << "PUSDistributor::handlePacket: Packet format " << "invalid, code "<< static_cast(tcStatus) << std::endl; +#endif } #endif uint32_t queue_id = currentPacket->getService(); @@ -40,8 +44,10 @@ PUSDistributor::TcMqMapIter PUSDistributor::selectDestination() { if (queueMapIt == this->queueMap.end()) { tcStatus = DESTINATION_NOT_FOUND; #ifdef DEBUG +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::debug << "PUSDistributor::handlePacket: Destination not found, " << "code "<< static_cast(tcStatus) << std::endl; +#endif #endif } @@ -57,12 +63,16 @@ PUSDistributor::TcMqMapIter PUSDistributor::selectDestination() { ReturnValue_t PUSDistributor::registerService(AcceptsTelecommandsIF* service) { uint16_t serviceId = service->getIdentifier(); +#if FSFW_CPP_OSTREAM_ENABLED == 1 // sif::info << "Service ID: " << (int)serviceId << std::endl; +#endif MessageQueueId_t queue = service->getRequestQueue(); auto returnPair = queueMap.emplace(serviceId, queue); if (not returnPair.second) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "PUSDistributor::registerService: Service ID already" " exists in map." << std::endl; +#endif return SERVICE_ID_ALREADY_EXISTS; } return HasReturnvaluesIF::RETURN_OK; @@ -104,9 +114,11 @@ ReturnValue_t PUSDistributor::initialize() { CCSDSDistributorIF* ccsdsDistributor = objectManager->get(packetSource); if (ccsdsDistributor == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "PUSDistributor::initialize: Packet source invalid." << " Make sure it exists and implements CCSDSDistributorIF!" << std::endl; +#endif return RETURN_FAILED; } return ccsdsDistributor->registerApplication(this); diff --git a/tcdistribution/TcDistributor.cpp b/tcdistribution/TcDistributor.cpp index 06e1817f..df069556 100644 --- a/tcdistribution/TcDistributor.cpp +++ b/tcdistribution/TcDistributor.cpp @@ -39,6 +39,7 @@ ReturnValue_t TcDistributor::handlePacket() { } void TcDistributor::print() { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::debug << "Distributor content is: " << std::endl << "ID\t| Message Queue ID" << std::endl; sif::debug << std::setfill('0') << std::setw(8) << std::hex; @@ -47,7 +48,7 @@ void TcDistributor::print() { << std::endl; } sif::debug << std::setfill(' ') << std::dec; - +#endif } ReturnValue_t TcDistributor::callbackAfterSending(ReturnValue_t queueStatus) { diff --git a/timemanager/Stopwatch.cpp b/timemanager/Stopwatch.cpp index 302e2ac0..f79d2eeb 100644 --- a/timemanager/Stopwatch.cpp +++ b/timemanager/Stopwatch.cpp @@ -28,13 +28,17 @@ double Stopwatch::stopSeconds() { void Stopwatch::display() { if(displayMode == StopwatchDisplayMode::MILLIS) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::info << "Stopwatch: Operation took " << (elapsedTime.tv_sec * 1000 + elapsedTime.tv_usec / 1000) << " milliseconds" << std::endl; +#endif } else if(displayMode == StopwatchDisplayMode::SECONDS) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::info <<"Stopwatch: Operation took " << std::setprecision(3) << std::fixed << timevalOperations::toDouble(elapsedTime) << " seconds" << std::endl; +#endif } } diff --git a/tmstorage/TmStoreBackendIF.h b/tmstorage/TmStoreBackendIF.h index 4b2a8836..4ae77609 100644 --- a/tmstorage/TmStoreBackendIF.h +++ b/tmstorage/TmStoreBackendIF.h @@ -1,5 +1,5 @@ -#ifndef PLATFORM_TMTCSERVICES_TMSTOREBACKENDIF_H_ -#define PLATFORM_TMTCSERVICES_TMSTOREBACKENDIF_H_ +#ifndef FSFW_TMTCSERVICES_TMSTOREBACKENDIF_H_ +#define FSFW_TMTCSERVICES_TMSTOREBACKENDIF_H_ #include "../returnvalues/HasReturnvaluesIF.h" #include "../objectmanager/SystemObjectIF.h" @@ -49,14 +49,33 @@ public: static const Event AUTO_CATALOGS_SENDING_FAILED = MAKE_EVENT(15, severity::INFO);//!< Info that the a auto catalog report failed virtual ~TmStoreBackendIF() {} + + /** + * SHOULDDO: Specification on what has to be implemented here + * @param opCode + * @return + */ virtual ReturnValue_t performOperation(uint8_t opCode) = 0; virtual ReturnValue_t initialize() = 0; + + /** + * Implement the storage of TM packets to mass memory + * @param tmPacket + * @return + */ virtual ReturnValue_t storePacket(TmPacketMinimal* tmPacket) = 0; virtual ReturnValue_t setFetchLimitTime(const timeval* loverLimit, const timeval* upperLimit) = 0; virtual ReturnValue_t setFetchLimitBlocks(uint32_t startAddress, uint32_t endAddress) = 0; virtual ReturnValue_t fetchPackets(bool fromBegin = false) = 0; virtual ReturnValue_t initializeStore(object_id_t dumpTarget) = 0; virtual ReturnValue_t dumpIndex(store_address_t* storeId) = 0; + + /** + * SHOULDDO: Adapt for file management system? + * @param startAddress + * @param endAddress + * @return + */ virtual ReturnValue_t deleteBlocks(uint32_t startAddress, uint32_t endAddress) = 0; virtual ReturnValue_t deleteTime(const timeval* timeUntil, uint32_t* deletedPackets) = 0; @@ -73,4 +92,4 @@ public: -#endif /* PLATFORM_TMTCSERVICES_TMSTOREBACKENDIF_H_ */ +#endif /* FSFW_TMTCSERVICES_TMSTOREBACKENDIF_H_ */ diff --git a/tmstorage/TmStoreFrontendIF.h b/tmstorage/TmStoreFrontendIF.h index e1bc3a14..beee7ede 100644 --- a/tmstorage/TmStoreFrontendIF.h +++ b/tmstorage/TmStoreFrontendIF.h @@ -1,9 +1,10 @@ -#ifndef PLATFORM_TMTCSERVICES_TMSTOREFRONTENDIF_H_ -#define PLATFORM_TMTCSERVICES_TMSTOREFRONTENDIF_H_ +#ifndef FSFW_TMTCSERVICES_TMSTOREFRONTENDIF_H_ +#define FSFW_TMTCSERVICES_TMSTOREFRONTENDIF_H_ -#include "../returnvalues/HasReturnvaluesIF.h" #include "TmStorePackets.h" +#include "../returnvalues/HasReturnvaluesIF.h" #include "../ipc/MessageQueueSenderIF.h" + class TmPacketMinimal; class SpacePacketBase; class TmStoreBackendIF; @@ -11,6 +12,14 @@ class TmStoreBackendIF; class TmStoreFrontendIF { public: virtual TmStoreBackendIF* getBackend() const = 0; + + /** + * What do I need to implement here? + * This is propably used by PUS Service 15 so we should propably check for messages.. + * Provide base implementation? + * @param opCode + * @return + */ virtual ReturnValue_t performOperation(uint8_t opCode) = 0; /** * Callback from the back-end to indicate a certain packet was received. @@ -52,4 +61,4 @@ public: -#endif /* PLATFORM_TMTCSERVICES_TMSTOREFRONTENDIF_H_ */ +#endif /* FSFW_TMTCSERVICES_TMSTOREFRONTENDIF_H_ */ diff --git a/tmstorage/TmStoreMessage.cpp b/tmstorage/TmStoreMessage.cpp index d2efd403..033cbb1d 100644 --- a/tmstorage/TmStoreMessage.cpp +++ b/tmstorage/TmStoreMessage.cpp @@ -1,5 +1,5 @@ -#include "../objectmanager/ObjectManagerIF.h" #include "TmStoreMessage.h" +#include "../objectmanager/ObjectManagerIF.h" TmStoreMessage::~TmStoreMessage() { @@ -74,7 +74,7 @@ void TmStoreMessage::clear(CommandMessage* cmd) { case DELETE_STORE_CONTENT_BLOCKS: case DOWNLINK_STORE_CONTENT_BLOCKS: case REPORT_INDEX_REQUEST: - cmd->setCommand(UNKNOWN_COMMAND); + cmd->setCommand(CommandMessage::UNKNOWN_COMMAND); cmd->setParameter(0); cmd->setParameter2(0); break; diff --git a/tmstorage/TmStoreMessage.h b/tmstorage/TmStoreMessage.h index 5b928569..d0178920 100644 --- a/tmstorage/TmStoreMessage.h +++ b/tmstorage/TmStoreMessage.h @@ -1,11 +1,12 @@ -#ifndef FRAMEWORK_TMSTORAGE_TMSTOREMESSAGE_H_ -#define FRAMEWORK_TMSTORAGE_TMSTOREMESSAGE_H_ +#ifndef FSFW_TMSTORAGE_TMSTOREMESSAGE_H_ +#define FSFW_TMSTORAGE_TMSTOREMESSAGE_H_ +#include "TmStorePackets.h" #include "../ipc/CommandMessage.h" #include "../storagemanager/StorageManagerIF.h" -#include "TmStorePackets.h" #include "../objectmanager/SystemObjectIF.h" -class TmStoreMessage: public CommandMessage { + +class TmStoreMessage { public: static ReturnValue_t setEnableStoringMessage(CommandMessage* cmd, bool setEnabled); @@ -25,8 +26,10 @@ public: static void setDownlinkContentTimeMessage(CommandMessage* cmd, store_address_t storeId); static void setIndexReportMessage(CommandMessage* cmd, store_address_t storeId); - static ReturnValue_t setDeleteBlocksMessage(CommandMessage* cmd, uint32_t addressLow, uint32_t addressHigh); - static ReturnValue_t setDownlinkBlocksMessage(CommandMessage* cmd, uint32_t addressLow, uint32_t addressHigh); + static ReturnValue_t setDeleteBlocksMessage(CommandMessage* cmd, + uint32_t addressLow, uint32_t addressHigh); + static ReturnValue_t setDownlinkBlocksMessage(CommandMessage* cmd, + uint32_t addressLow, uint32_t addressHigh); static ReturnValue_t setIndexRequestMessage(CommandMessage* cmd); static void setDeleteContentTimeMessage(CommandMessage* cmd, store_address_t storeId); @@ -60,4 +63,4 @@ private: TmStoreMessage(); }; -#endif /* FRAMEWORK_TMSTORAGE_TMSTOREMESSAGE_H_ */ +#endif /* FSFW_TMSTORAGE_TMSTOREMESSAGE_H_ */ diff --git a/tmstorage/TmStorePackets.h b/tmstorage/TmStorePackets.h index b46ae6f6..3abd0c1c 100644 --- a/tmstorage/TmStorePackets.h +++ b/tmstorage/TmStorePackets.h @@ -1,5 +1,5 @@ -#ifndef FRAMEWORK_TMSTORAGE_TMSTOREPACKETS_H_ -#define FRAMEWORK_TMSTORAGE_TMSTOREPACKETS_H_ +#ifndef FSFW_TMSTORAGE_TMSTOREPACKETS_H_ +#define FSFW_TMSTORAGE_TMSTOREPACKETS_H_ #include "../serialize/SerialFixedArrayListAdapter.h" #include "../serialize/SerializeElement.h" @@ -140,8 +140,8 @@ public: if(packet->isValid()){ timeval packetTime = {0,0}; size_t foundlen = 0; - CCSDSTime::convertFromCcsds(&packetTime, - &packet->rawTimestamp[0],&foundlen,sizeof(rawTimestamp)); + CCSDSTime::convertFromCcsds(&packetTime,&packet->rawTimestamp[0], + &foundlen,sizeof(rawTimestamp)); if(packetTime <= *cmpTime){ return true; } @@ -154,7 +154,7 @@ public: timeval packetTime = {0,0}; size_t foundlen = 0; CCSDSTime::convertFromCcsds(&packetTime,&packet->rawTimestamp[0], - &foundlen,sizeof(rawTimestamp)); + &foundlen,sizeof(rawTimestamp)); if(packetTime >= *cmpTime){ return true; } @@ -208,7 +208,7 @@ public: timeval packetTime = {0,0}; size_t foundlen = 0; CCSDSTime::convertFromCcsds(&packetTime, &this->rawTimestamp[0], - &foundlen,sizeof(rawTimestamp)); + &foundlen, sizeof(rawTimestamp)); return packetTime; } @@ -300,4 +300,4 @@ private: uint8_t rawTimestamp[TimeStamperIF::MISSION_TIMESTAMP_SIZE]; }; -#endif /* FRAMEWORK_TMSTORAGE_TMSTOREPACKETS_H_ */ +#endif /* FSFW_TMSTORAGE_TMSTOREPACKETS_H_ */ diff --git a/tmtcpacket/pus/TcPacketBase.cpp b/tmtcpacket/pus/TcPacketBase.cpp index eaa8416a..ca3e2a99 100644 --- a/tmtcpacket/pus/TcPacketBase.cpp +++ b/tmtcpacket/pus/TcPacketBase.cpp @@ -63,7 +63,9 @@ uint8_t TcPacketBase::getPusVersionNumber() { } void TcPacketBase::print() { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::debug << "TcPacketBase::print: " << std::endl; +#endif arrayprinter::print(getWholeData(), getFullSize()); } diff --git a/tmtcpacket/pus/TcPacketStored.cpp b/tmtcpacket/pus/TcPacketStored.cpp index fffc86ae..f320386c 100644 --- a/tmtcpacket/pus/TcPacketStored.cpp +++ b/tmtcpacket/pus/TcPacketStored.cpp @@ -23,8 +23,10 @@ TcPacketStored::TcPacketStored(uint16_t apid, uint8_t service, ReturnValue_t returnValue = this->store->getFreeElement(&this->storeAddress, (TC_PACKET_MIN_SIZE + size), &pData); if (returnValue != this->store->RETURN_OK) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "TcPacketStored: Could not get free element from store!" << std::endl; +#endif return; } this->setData(pData); @@ -39,7 +41,9 @@ ReturnValue_t TcPacketStored::getData(const uint8_t ** dataPtr, size_t* dataSize) { auto result = this->store->getData(storeAddress, dataPtr, dataSize); if(result != HasReturnvaluesIF::RETURN_OK) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "TcPacketStored: Could not get data!" << std::endl; +#endif } return result; } @@ -61,8 +65,10 @@ bool TcPacketStored::checkAndSetStore() { if (this->store == nullptr) { this->store = objectManager->get(objects::TC_STORE); if (this->store == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "TcPacketStored::TcPacketStored: TC Store not found!" << std::endl; +#endif return false; } } diff --git a/tmtcpacket/pus/TmPacketBase.cpp b/tmtcpacket/pus/TmPacketBase.cpp index 2c8bfd63..c8e4b430 100644 --- a/tmtcpacket/pus/TmPacketBase.cpp +++ b/tmtcpacket/pus/TmPacketBase.cpp @@ -57,7 +57,9 @@ void TmPacketBase::setData(const uint8_t* p_Data) { } void TmPacketBase::print() { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::debug << "TmPacketBase::print: " << std::endl; +#endif arrayprinter::print(getWholeData(), getFullSize()); } @@ -65,8 +67,10 @@ bool TmPacketBase::checkAndSetStamper() { if (timeStamper == NULL) { timeStamper = objectManager->get(timeStamperId); if (timeStamper == NULL) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "TmPacketBase::checkAndSetStamper: Stamper not found!" << std::endl; +#endif return false; } } diff --git a/tmtcpacket/pus/TmPacketStored.cpp b/tmtcpacket/pus/TmPacketStored.cpp index 0fb789aa..0fd2a4a0 100644 --- a/tmtcpacket/pus/TmPacketStored.cpp +++ b/tmtcpacket/pus/TmPacketStored.cpp @@ -105,8 +105,10 @@ bool TmPacketStored::checkAndSetStore() { if (store == nullptr) { store = objectManager->get(objects::TM_STORE); if (store == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "TmPacketStored::TmPacketStored: TM Store not found!" << std::endl; +#endif return false; } } diff --git a/tmtcservices/CommandingServiceBase.cpp b/tmtcservices/CommandingServiceBase.cpp index ed765ecc..259f2ccb 100644 --- a/tmtcservices/CommandingServiceBase.cpp +++ b/tmtcservices/CommandingServiceBase.cpp @@ -75,8 +75,10 @@ ReturnValue_t CommandingServiceBase::initialize() { packetSource); if (packetForwarding == nullptr or distributor == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "CommandingServiceBase::intialize: Packet source or " "packet destination invalid!" << std::endl; +#endif return ObjectManagerIF::CHILD_INIT_FAILED; } @@ -88,8 +90,10 @@ ReturnValue_t CommandingServiceBase::initialize() { TCStore = objectManager->get(objects::TC_STORE); if (IPCStore == nullptr or TCStore == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "CommandingServiceBase::intialize: IPC store or TC store " "not initialized yet!" << std::endl; +#endif return ObjectManagerIF::CHILD_INIT_FAILED; } diff --git a/tmtcservices/PusServiceBase.cpp b/tmtcservices/PusServiceBase.cpp index cb5a1247..0a5cb202 100644 --- a/tmtcservices/PusServiceBase.cpp +++ b/tmtcservices/PusServiceBase.cpp @@ -25,9 +25,11 @@ ReturnValue_t PusServiceBase::performOperation(uint8_t opCode) { handleRequestQueue(); ReturnValue_t result = this->performService(); if (result != RETURN_OK) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "PusService " << (uint16_t) this->serviceId << ": performService returned with " << (int16_t) result << std::endl; +#endif return RETURN_FAILED; } return RETURN_OK; @@ -43,11 +45,13 @@ void PusServiceBase::handleRequestQueue() { for (uint8_t count = 0; count < PUS_SERVICE_MAX_RECEPTION; count++) { ReturnValue_t status = this->requestQueue->receiveMessage(&message); // if(status != MessageQueueIF::EMPTY) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 // sif::debug << "PusServiceBase::performOperation: Receiving from " // << "MQ ID: " << std::hex << "0x" << std::setw(8) // << std::setfill('0') << this->requestQueue->getId() // << std::dec << " returned: " << status << std::setfill(' ') // << std::endl; +#endif // } if (status == RETURN_OK) { @@ -79,9 +83,11 @@ void PusServiceBase::handleRequestQueue() { break; } else { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "PusServiceBase::performOperation: Service " << this->serviceId << ": Error receiving packet. Code: " << std::hex << status << std::dec << std::endl; +#endif } } } @@ -104,10 +110,12 @@ ReturnValue_t PusServiceBase::initialize() { PUSDistributorIF* distributor = objectManager->get( packetSource); if (destService == nullptr or distributor == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "PusServiceBase::PusServiceBase: Service " << this->serviceId << ": Configuration error. Make sure " << "packetSource and packetDestination are defined correctly" << std::endl; +#endif return ObjectManagerIF::CHILD_INIT_FAILED; } this->requestQueue->setDefaultDestination( diff --git a/tmtcservices/TmTcBridge.cpp b/tmtcservices/TmTcBridge.cpp index b4e9967b..2513071a 100644 --- a/tmtcservices/TmTcBridge.cpp +++ b/tmtcservices/TmTcBridge.cpp @@ -23,9 +23,11 @@ ReturnValue_t TmTcBridge::setNumberOfSentPacketsPerCycle( return RETURN_OK; } else { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "TmTcBridge::setNumberOfSentPacketsPerCycle: Number of " << "packets sent per cycle exceeds limits. " << "Keeping default value." << std::endl; +#endif return RETURN_FAILED; } } @@ -37,9 +39,11 @@ ReturnValue_t TmTcBridge::setMaxNumberOfPacketsStored( return RETURN_OK; } else { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "TmTcBridge::setMaxNumberOfPacketsStored: Number of " << "packets stored exceeds limits. " << "Keeping default value." << std::endl; +#endif return RETURN_FAILED; } } @@ -47,21 +51,27 @@ ReturnValue_t TmTcBridge::setMaxNumberOfPacketsStored( ReturnValue_t TmTcBridge::initialize() { tcStore = objectManager->get(tcStoreId); if (tcStore == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "TmTcBridge::initialize: TC store invalid. Make sure" "it is created and set up properly." << std::endl; +#endif return ObjectManagerIF::CHILD_INIT_FAILED; } tmStore = objectManager->get(tmStoreId); if (tmStore == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "TmTcBridge::initialize: TM store invalid. Make sure" "it is created and set up properly." << std::endl; +#endif return ObjectManagerIF::CHILD_INIT_FAILED; } AcceptsTelecommandsIF* tcDistributor = objectManager->get(tcDestination); if (tcDistributor == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "TmTcBridge::initialize: TC Distributor invalid" << std::endl; +#endif return ObjectManagerIF::CHILD_INIT_FAILED; } @@ -75,13 +85,17 @@ ReturnValue_t TmTcBridge::performOperation(uint8_t operationCode) { ReturnValue_t result; result = handleTc(); if(result != RETURN_OK) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::debug << "TmTcBridge::performOperation: " << "Error handling TCs" << std::endl; +#endif } result = handleTm(); if (result != RETURN_OK) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::debug << "TmTcBridge::performOperation: " << "Error handling TMs" << std::endl; +#endif } return result; } @@ -94,9 +108,11 @@ ReturnValue_t TmTcBridge::handleTm() { ReturnValue_t status = HasReturnvaluesIF::RETURN_OK; ReturnValue_t result = handleTmQueue(); if(result != RETURN_OK) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "TmTcBridge::handleTm: Error handling TM queue with " << "error code 0x" << std::hex << result << std::dec << "!" << std::endl; +#endif status = result; } @@ -104,8 +120,10 @@ ReturnValue_t TmTcBridge::handleTm() { (packetSentCounter < sentPacketsPerCycle)) { result = handleStoredTm(); if(result != RETURN_OK) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "TmTcBridge::handleTm: Error handling stored TMs!" << std::endl; +#endif status = result; } } @@ -122,7 +140,9 @@ ReturnValue_t TmTcBridge::handleTmQueue() { result == HasReturnvaluesIF::RETURN_OK; result = tmTcReceptionQueue->receiveMessage(&message)) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 //sif::info << (int) packetSentCounter << std::endl; +#endif if(communicationLinkUp == false or packetSentCounter >= sentPacketsPerCycle) { storeDownlinkData(&message); @@ -151,8 +171,10 @@ ReturnValue_t TmTcBridge::storeDownlinkData(TmTcMessage *message) { store_address_t storeId = 0; if(tmFifo->full()) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::debug << "TmTcBridge::storeDownlinkData: TM downlink max. number " << "of stored packet IDs reached! " << std::endl; +#endif if(overwriteOld) { tmFifo->retrieve(&storeId); tmStore->deleteData(storeId); @@ -171,8 +193,10 @@ ReturnValue_t TmTcBridge::storeDownlinkData(TmTcMessage *message) { ReturnValue_t TmTcBridge::handleStoredTm() { ReturnValue_t status = RETURN_OK; while(not tmFifo->empty() and packetSentCounter < sentPacketsPerCycle) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 //sif::info << "TMTC Bridge: Sending stored TM data. There are " // << (int) tmFifo->size() << " left to send\r\n" << std::flush; +#endif store_address_t storeId; const uint8_t* data = nullptr; @@ -185,8 +209,10 @@ ReturnValue_t TmTcBridge::handleStoredTm() { result = sendTm(data,size); if(result != RETURN_OK) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "TMTC Bridge: Could not send stored downlink data" << std::endl; +#endif status = result; } packetSentCounter ++; @@ -201,13 +227,17 @@ ReturnValue_t TmTcBridge::handleStoredTm() { void TmTcBridge::registerCommConnect() { if(not communicationLinkUp) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 //sif::info << "TMTC Bridge: Registered Comm Link Connect" << std::endl; +#endif communicationLinkUp = true; } } void TmTcBridge::registerCommDisconnect() { +#if FSFW_CPP_OSTREAM_ENABLED == 1 //sif::info << "TMTC Bridge: Registered Comm Link Disconnect" << std::endl; +#endif if(communicationLinkUp) { communicationLinkUp = false; } diff --git a/tmtcservices/VerificationReporter.cpp b/tmtcservices/VerificationReporter.cpp index 7e40bd27..ff6f54f9 100644 --- a/tmtcservices/VerificationReporter.cpp +++ b/tmtcservices/VerificationReporter.cpp @@ -27,9 +27,11 @@ void VerificationReporter::sendSuccessReport(uint8_t set_report_id, ReturnValue_t status = MessageQueueSenderIF::sendMessage(acknowledgeQueue, &message); if (status != HasReturnvaluesIF::RETURN_OK) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "VerificationReporter::sendSuccessReport: Error writing " << "to queue. Code: " << std::hex << status << std::dec << std::endl; +#endif } } @@ -44,9 +46,11 @@ void VerificationReporter::sendSuccessReport(uint8_t set_report_id, ReturnValue_t status = MessageQueueSenderIF::sendMessage(acknowledgeQueue, &message); if (status != HasReturnvaluesIF::RETURN_OK) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "VerificationReporter::sendSuccessReport: Error writing " << "to queue. Code: " << std::hex << status << std::dec << std::endl; +#endif } } @@ -64,9 +68,11 @@ void VerificationReporter::sendFailureReport(uint8_t report_id, ReturnValue_t status = MessageQueueSenderIF::sendMessage(acknowledgeQueue, &message); if (status != HasReturnvaluesIF::RETURN_OK) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "VerificationReporter::sendFailureReport: Error writing " << "to queue. Code: " << std::hex << "0x" << status << std::dec << std::endl; +#endif } } @@ -82,24 +88,30 @@ void VerificationReporter::sendFailureReport(uint8_t report_id, ReturnValue_t status = MessageQueueSenderIF::sendMessage(acknowledgeQueue, &message); if (status != HasReturnvaluesIF::RETURN_OK) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "VerificationReporter::sendFailureReport: Error writing " << "to queue. Code: " << std::hex << "0x" << status << std::dec << std::endl; +#endif } } void VerificationReporter::initialize() { if(messageReceiver == objects::NO_OBJECT) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "VerificationReporter::initialize: Verification message" " receiver object ID not set yet in Factory!" << std::endl; +#endif return; } AcceptsVerifyMessageIF* temp = objectManager->get( messageReceiver); if (temp == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "VerificationReporter::initialize: Message " << "receiver invalid. Make sure it is set up properly and " << "implementsAcceptsVerifyMessageIF" << std::endl; +#endif return; } this->acknowledgeQueue = temp->getVerificationQueue(); diff --git a/unittest/CMakeLists.txt b/unittest/CMakeLists.txt new file mode 100644 index 00000000..119ef243 --- /dev/null +++ b/unittest/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(internal) +add_subdirectory(tests) \ No newline at end of file diff --git a/unittest/README.md b/unittest/README.md index 8a787c07..d6a4bb85 100644 --- a/unittest/README.md +++ b/unittest/README.md @@ -1,59 +1,19 @@ ## FSFW Testing -This repository contains testing and unit testing components. -[Catch2](https://github.com/catchorg/Catch2) has been used as a framework, -and these unit tests can only be run on a linux host machine. -The makefile with default settings creates the unit test binary which can be -run in the terminal or in eclipse. +This folder contains testing and unit testing components. ### Instructions -To run the fsfw unittests in the project, perform following steps: +The easiest way to run the unittest contained in this folder is to follow +the steps in the [test repository](https://egit.irs.uni-stuttgart.de/fsfw/fsfw_tests). +This is recommended even if the goal is to set up a custom test repository to have +a starting point. -1. Copy the testcfg folder the project root (folder containing the FSFW). -2. There is a makefile inside the testcfg folder which can be used to have - a starting point to compile the unit tests. Copy that Makefile to the project - root -3. Create a folder named catch2 (can have other name which requires Makefile - adaption) and copy the Catch2 header files there (NOTE: CMake support - not enabled yet!) +To set up a custom test repository or project, following steps can be performed: + +1. Copy the user folder content into the project root. +2. Clone [Catch2](https://github.com/catchorg/Catch2) in the project root. +3. Use the `CMakeLists.txt` as a starting point to add tests and build the test + executable. -### Eclipse CDT settings - -The default eclipse terminal has issues displaying the colors used -when running the unit test binary by catch2. To fix this issue, -install the ANSI Escape In Console package from the eclipse marketplace. - -### GCOV integration - -GCOV has been integrated as a code coverage tool. -It can be enabled by adding `GCOV=1` to the build process as an additional argument. -Coverage data will be provided in form of .gcno and .gcda files. -These can be displayed in eclipse by looking -for a .gcno or .gcda file in the \_obj folder, double-clicking it -and picking the right source-binary. This will generate -information about which lines of a file have run, provided it is open in -eclipse. - -### LCOV integration - -The files generated by GCOV can also be processed by the tool LCOV. -On ubuntu, the tool can be installed with the following command: - -```sh -sudo apt-get install lcov -```` - -After that, the tool can be run by building the unit tests with `GCOV=1`, -running them at least one time and then executing the `lcov.sh` script. - -### Adding unit tests - -The catch unit tests are located in unittest/testfw. To add new unit tests, -add them to the UnitTestCatch.cpp file or add a new source file which -includes catch.hpp. - -For writing basics tests, the [assertion documentation](https://github.com/catchorg/Catch2/blob/master/docs/assertions.md#top) -or the existing examples are a good guideliens. -For more advanced tests, refer to the [catch2 documentation](https://github.com/catchorg/Catch2/blob/master/docs/Readme.md#top). diff --git a/unittest/internal/CMakeLists.txt b/unittest/internal/CMakeLists.txt new file mode 100644 index 00000000..9c24317f --- /dev/null +++ b/unittest/internal/CMakeLists.txt @@ -0,0 +1,7 @@ +target_sources(${TARGET_NAME} PRIVATE + InternalUnitTester.cpp + UnittDefinitions.cpp +) + +add_subdirectory(osal) +add_subdirectory(serialize) \ No newline at end of file diff --git a/unittest/internal/InternalUnitTester.cpp b/unittest/internal/InternalUnitTester.cpp index 503a71ec..bd41969c 100644 --- a/unittest/internal/InternalUnitTester.cpp +++ b/unittest/internal/InternalUnitTester.cpp @@ -13,13 +13,17 @@ InternalUnitTester::InternalUnitTester() {} InternalUnitTester::~InternalUnitTester() {} ReturnValue_t InternalUnitTester::performTests() { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::info << "Running internal unit tests.." << std::endl; +#endif testserialize::test_serialization(); testmq::testMq(); testsemaph::testBinSemaph(); testsemaph::testCountingSemaph(); testmutex::testMutex(); +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::info << "Internal unit tests finished." << std::endl; +#endif return RETURN_OK; } diff --git a/unittest/internal/UnittDefinitions.cpp b/unittest/internal/UnittDefinitions.cpp index 6265e9fd..517f561a 100644 --- a/unittest/internal/UnittDefinitions.cpp +++ b/unittest/internal/UnittDefinitions.cpp @@ -1,7 +1,11 @@ #include "UnittDefinitions.h" ReturnValue_t unitt::put_error(std::string errorId) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "Unit Tester error: Failed at test ID " - << errorId << "\n" << std::flush; + << errorId << std::endl; +#else + sif::printError("Unit Tester error: Failed at test ID 0x%08x", errorId); +#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ return HasReturnvaluesIF::RETURN_FAILED; } diff --git a/unittest/internal/UnittDefinitions.h b/unittest/internal/UnittDefinitions.h index ea36fea4..3e14fec5 100644 --- a/unittest/internal/UnittDefinitions.h +++ b/unittest/internal/UnittDefinitions.h @@ -2,9 +2,10 @@ #define UNITTEST_INTERNAL_UNITTDEFINITIONS_H_ #include "../../returnvalues/HasReturnvaluesIF.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "../../serviceinterface/ServiceInterface.h" #include #include +#include namespace tv { // POD test values diff --git a/unittest/internal/osal/CMakeLists.txt b/unittest/internal/osal/CMakeLists.txt new file mode 100644 index 00000000..c6f1eb95 --- /dev/null +++ b/unittest/internal/osal/CMakeLists.txt @@ -0,0 +1,5 @@ +target_sources(${TARGET_NAME} PRIVATE + IntTestMq.cpp + IntTestMutex.cpp + IntTestSemaphore.cpp +) diff --git a/unittest/internal/osal/IntTestMq.cpp b/unittest/internal/osal/IntTestMq.cpp index 9917285f..fc8e963e 100644 --- a/unittest/internal/osal/IntTestMq.cpp +++ b/unittest/internal/osal/IntTestMq.cpp @@ -1,8 +1,8 @@ #include "IntTestMq.h" -#include "../UnittDefinitions.h" +#include -#include "../../../ipc/MessageQueueIF.h" -#include "../../../ipc/QueueFactory.h" +#include +#include #include diff --git a/unittest/internal/osal/IntTestMutex.cpp b/unittest/internal/osal/IntTestMutex.cpp index d2f8b962..2a1584b8 100644 --- a/unittest/internal/osal/IntTestMutex.cpp +++ b/unittest/internal/osal/IntTestMutex.cpp @@ -1,10 +1,10 @@ #include "IntTestMutex.h" -#include "../../../ipc/MutexFactory.h" -#include "../UnittDefinitions.h" +#include +#include #if defined(hosted) -#include "../../osal/hosted/Mutex.h" +#include #include #include #endif @@ -13,7 +13,7 @@ void testmutex::testMutex() { std::string id = "[testMutex]"; MutexIF* mutex = MutexFactory::instance()->createMutex(); - auto result = mutex->lockMutex(MutexIF::POLLING); + auto result = mutex->lockMutex(MutexIF::TimeoutType::POLLING); if(result != HasReturnvaluesIF::RETURN_OK) { unitt::put_error(id); } diff --git a/unittest/internal/osal/IntTestSemaphore.cpp b/unittest/internal/osal/IntTestSemaphore.cpp index 6d2719d5..43990c2c 100644 --- a/unittest/internal/osal/IntTestSemaphore.cpp +++ b/unittest/internal/osal/IntTestSemaphore.cpp @@ -1,10 +1,11 @@ #include "IntTestSemaphore.h" -#include "../UnittDefinitions.h" +#include -#include "../../../tasks/SemaphoreFactory.h" -#include "../../../serviceinterface/ServiceInterfaceStream.h" -#include "../../../timemanager/Stopwatch.h" +#include +#include +#include +#include void testsemaph::testBinSemaph() { std::string id = "[BinSemaphore]"; @@ -93,8 +94,10 @@ void testsemaph::testBinSemaphoreImplementation(SemaphoreIF* binSemaph, result = binSemaph->acquire(SemaphoreIF::TimeoutType::WAITING, 10); //dur_millis_t time = stopwatch.stop(); // if(abs(time - 10) > 2) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 // sif::error << "UnitTester: Semaphore timeout measured incorrect." // << std::endl; +#endif // unitt::put_error(id); // } } @@ -138,7 +141,7 @@ void testsemaph::testCountingSemaphImplementation(SemaphoreIF* countingSemaph, // attempt to take when count is 0, measure time result = countingSemaph->acquire(SemaphoreIF::TimeoutType::WAITING, 10); dur_millis_t time = stopwatch.stop(); - if(abs(time - 10) > 1) { + if(std::abs(static_cast(time - 10)) > 1) { unitt::put_error(id); } } diff --git a/unittest/internal/serialize/CMakeLists.txt b/unittest/internal/serialize/CMakeLists.txt new file mode 100644 index 00000000..e8dc5717 --- /dev/null +++ b/unittest/internal/serialize/CMakeLists.txt @@ -0,0 +1,3 @@ +target_sources(${TARGET_NAME} PRIVATE + IntTestSerialization.cpp +) diff --git a/unittest/internal/serialize/IntTestSerialization.cpp b/unittest/internal/serialize/IntTestSerialization.cpp index 793661c5..69d82942 100644 --- a/unittest/internal/serialize/IntTestSerialization.cpp +++ b/unittest/internal/serialize/IntTestSerialization.cpp @@ -1,9 +1,9 @@ #include "IntTestSerialization.h" -#include "../UnittDefinitions.h" +#include -#include "../../../serialize/SerializeElement.h" -#include "../../../serialize/SerialBufferAdapter.h" -#include "../../../serialize/SerializeIF.h" +#include +#include +#include #include diff --git a/unittest/testcfg/devices/logicalAddresses.cpp b/unittest/testcfg/devices/logicalAddresses.cpp deleted file mode 100644 index c7ce314d..00000000 --- a/unittest/testcfg/devices/logicalAddresses.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "logicalAddresses.h" - - - - diff --git a/unittest/testcfg/devices/powerSwitcherList.cpp b/unittest/testcfg/devices/powerSwitcherList.cpp deleted file mode 100644 index 343f78d0..00000000 --- a/unittest/testcfg/devices/powerSwitcherList.cpp +++ /dev/null @@ -1,4 +0,0 @@ -#include "powerSwitcherList.h" - - - diff --git a/unittest/tests/CMakeLists.txt b/unittest/tests/CMakeLists.txt new file mode 100644 index 00000000..180e1a51 --- /dev/null +++ b/unittest/tests/CMakeLists.txt @@ -0,0 +1,7 @@ +add_subdirectory(action) +add_subdirectory(container) +add_subdirectory(osal) +add_subdirectory(serialize) +add_subdirectory(datapoollocal) +add_subdirectory(storagemanager) + diff --git a/unittest/tests/action/CMakeLists.txt b/unittest/tests/action/CMakeLists.txt new file mode 100644 index 00000000..0339000f --- /dev/null +++ b/unittest/tests/action/CMakeLists.txt @@ -0,0 +1,3 @@ +target_sources(${TARGET_NAME} PRIVATE + TestActionHelper.cpp +) diff --git a/unittest/tests/action/TestActionHelper.cpp b/unittest/tests/action/TestActionHelper.cpp index 944ad705..2493a6b8 100644 --- a/unittest/tests/action/TestActionHelper.cpp +++ b/unittest/tests/action/TestActionHelper.cpp @@ -1,8 +1,14 @@ #include "TestActionHelper.h" + +#include + #include #include -#include -#include "../../core/CatchDefinitions.h" +#include + +#include + +#include TEST_CASE( "Action Helper" , "[ActionHelper]") { diff --git a/unittest/tests/action/TestActionHelper.h b/unittest/tests/action/TestActionHelper.h index 4ba417eb..641ea2c6 100644 --- a/unittest/tests/action/TestActionHelper.h +++ b/unittest/tests/action/TestActionHelper.h @@ -3,7 +3,7 @@ #include #include -#include +#include #include @@ -48,85 +48,4 @@ public: }; -class MessageQueueMockBase: public MessageQueueIF { -public: - MessageQueueId_t myQueueId = 0; - bool defaultDestSet = false; - bool messageSent = false; - - - - bool wasMessageSent() { - bool tempMessageSent = messageSent; - messageSent = false; - return tempMessageSent; - } - - virtual ReturnValue_t reply( MessageQueueMessageIF* message ) { - messageSent = true; - lastMessage = *(dynamic_cast(message)); - return HasReturnvaluesIF::RETURN_OK; - }; - virtual ReturnValue_t receiveMessage(MessageQueueMessageIF* message, - MessageQueueId_t *receivedFrom) { - (*message) = lastMessage; - lastMessage.clear(); - return HasReturnvaluesIF::RETURN_OK; - } - virtual ReturnValue_t receiveMessage(MessageQueueMessageIF* message) { - memcpy(message->getBuffer(), lastMessage.getBuffer(), - message->getMessageSize()); - lastMessage.clear(); - return HasReturnvaluesIF::RETURN_OK; - } - virtual ReturnValue_t flush(uint32_t* count) { - return HasReturnvaluesIF::RETURN_OK; - } - virtual MessageQueueId_t getLastPartner() const { - return tconst::testQueueId; - } - virtual MessageQueueId_t getId() const { - return tconst::testQueueId; - } - virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo, - MessageQueueMessageIF* message, MessageQueueId_t sentFrom, - bool ignoreFault = false ) { - messageSent = true; - lastMessage = *(dynamic_cast(message)); - return HasReturnvaluesIF::RETURN_OK; - } - virtual ReturnValue_t sendMessage( MessageQueueId_t sendTo, - MessageQueueMessageIF* message, bool ignoreFault = false ) override { - messageSent = true; - lastMessage = *(dynamic_cast(message)); - return HasReturnvaluesIF::RETURN_OK; - } - virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessageIF* message, - MessageQueueId_t sentFrom, bool ignoreFault = false ) { - messageSent = true; - lastMessage = *(dynamic_cast(message)); - return HasReturnvaluesIF::RETURN_OK; - } - virtual ReturnValue_t sendToDefault( MessageQueueMessageIF* message ) { - messageSent = true; - lastMessage = *(dynamic_cast(message)); - return HasReturnvaluesIF::RETURN_OK; - } - virtual void setDefaultDestination(MessageQueueId_t defaultDestination) { - myQueueId = defaultDestination; - defaultDestSet = true; - } - - virtual MessageQueueId_t getDefaultDestination() const { - return myQueueId; - } - virtual bool isDefaultDestinationSet() const { - return defaultDestSet; - } -private: - MessageQueueMessage lastMessage; - -}; - - #endif /* UNITTEST_TESTFW_NEWTESTS_TESTACTIONHELPER_H_ */ diff --git a/unittest/tests/container/CMakeLists.txt b/unittest/tests/container/CMakeLists.txt new file mode 100644 index 00000000..966c5834 --- /dev/null +++ b/unittest/tests/container/CMakeLists.txt @@ -0,0 +1,10 @@ +target_sources(${TARGET_NAME} PRIVATE + RingBufferTest.cpp + TestArrayList.cpp + TestDynamicFifo.cpp + TestFifo.cpp + TestFixedArrayList.cpp + TestFixedMap.cpp + TestFixedOrderedMultimap.cpp + TestPlacementFactory.cpp +) diff --git a/unittest/tests/container/RingBufferTest.cpp b/unittest/tests/container/RingBufferTest.cpp index 9c1c8a23..32a2502d 100644 --- a/unittest/tests/container/RingBufferTest.cpp +++ b/unittest/tests/container/RingBufferTest.cpp @@ -1,7 +1,7 @@ -#include "../../core/CatchDefinitions.h" -#include "../../container/SimpleRingBuffer.h" +#include +#include -#include +#include #include TEST_CASE("Ring Buffer Test" , "[RingBufferTest]") { diff --git a/unittest/tests/container/TestArrayList.cpp b/unittest/tests/container/TestArrayList.cpp index 2f884276..1fd330b6 100644 --- a/unittest/tests/container/TestArrayList.cpp +++ b/unittest/tests/container/TestArrayList.cpp @@ -1,8 +1,8 @@ -#include "../../container/ArrayList.h" -#include "../../returnvalues/HasReturnvaluesIF.h" +#include +#include -#include -#include "../../core/CatchDefinitions.h" +#include +#include /** * @brief Array List test diff --git a/unittest/tests/container/TestDynamicFifo.cpp b/unittest/tests/container/TestDynamicFifo.cpp index bb19131e..2b572d52 100644 --- a/unittest/tests/container/TestDynamicFifo.cpp +++ b/unittest/tests/container/TestDynamicFifo.cpp @@ -1,10 +1,9 @@ +#include +#include +#include -#include "../../container/DynamicFIFO.h" -#include "../../container/FIFO.h" -#include "../../returnvalues/HasReturnvaluesIF.h" - -#include -#include +#include +#include TEST_CASE( "Dynamic Fifo Tests", "[TestDynamicFifo]") { INFO("Dynamic Fifo Tests"); diff --git a/unittest/tests/container/TestFifo.cpp b/unittest/tests/container/TestFifo.cpp index bd727e00..fbcd40cc 100644 --- a/unittest/tests/container/TestFifo.cpp +++ b/unittest/tests/container/TestFifo.cpp @@ -1,10 +1,9 @@ +#include +#include +#include -#include "../../container/DynamicFIFO.h" -#include "../../container/FIFO.h" -#include "../../returnvalues/HasReturnvaluesIF.h" - -#include -#include "../../core/CatchDefinitions.h" +#include +#include TEST_CASE( "Static Fifo Tests", "[TestFifo]") { INFO("Fifo Tests"); diff --git a/unittest/tests/container/TestFixedArrayList.cpp b/unittest/tests/container/TestFixedArrayList.cpp index 5a1bd280..1a85f30d 100644 --- a/unittest/tests/container/TestFixedArrayList.cpp +++ b/unittest/tests/container/TestFixedArrayList.cpp @@ -1,9 +1,8 @@ -#include "../../core/CatchDefinitions.h" +#include +#include -#include "../../container/FixedArrayList.h" -#include "../../returnvalues/HasReturnvaluesIF.h" - -#include +#include +#include TEST_CASE( "FixedArrayList Tests", "[TestFixedArrayList]") { diff --git a/unittest/tests/container/TestFixedMap.cpp b/unittest/tests/container/TestFixedMap.cpp index da0c84e3..297171ca 100644 --- a/unittest/tests/container/TestFixedMap.cpp +++ b/unittest/tests/container/TestFixedMap.cpp @@ -1,8 +1,8 @@ -#include "../../container/FixedMap.h" -#include "../../returnvalues/HasReturnvaluesIF.h" +#include +#include -#include -#include "../../core/CatchDefinitions.h" +#include +#include template class FixedMap; diff --git a/unittest/tests/container/TestFixedOrderedMultimap.cpp b/unittest/tests/container/TestFixedOrderedMultimap.cpp index e625b559..a47d6efb 100644 --- a/unittest/tests/container/TestFixedOrderedMultimap.cpp +++ b/unittest/tests/container/TestFixedOrderedMultimap.cpp @@ -1,8 +1,8 @@ -#include "../../container/FixedOrderedMultimap.h" -#include "../../returnvalues/HasReturnvaluesIF.h" +#include +#include -#include -#include "../../core/CatchDefinitions.h" +#include +#include TEST_CASE( "FixedOrderedMultimap Tests", "[TestFixedOrderedMultimap]") { INFO("FixedOrderedMultimap Tests"); diff --git a/unittest/tests/container/TestPlacementFactory.cpp b/unittest/tests/container/TestPlacementFactory.cpp index 5edbb9d2..14cf8eb4 100644 --- a/unittest/tests/container/TestPlacementFactory.cpp +++ b/unittest/tests/container/TestPlacementFactory.cpp @@ -1,45 +1,48 @@ -//#include -//#include -//#include -//#include -// -//#include -//#include "../../core/CatchDefinitions.h" -// -//TEST_CASE( "PlacementFactory Tests", "[TestPlacementFactory]") { -// INFO("PlacementFactory Tests"); -// -// const uint16_t element_sizes[3] = {sizeof(uint16_t), sizeof(uint32_t), sizeof(uint64_t)}; -// const uint16_t n_elements[3] = {1, 1, 1}; -// LocalPool<3> storagePool(0x1, element_sizes, n_elements, false, true); -// PlacementFactory factory(&storagePool); -// -// SECTION("Pool overload"){ -// store_address_t address; -// uint8_t* ptr = nullptr; -// REQUIRE(storagePool.getFreeElement(&address, sizeof(ArrayList), &ptr) -// == static_cast(StorageManagerIF::DATA_TOO_LARGE)); -// ArrayList* list2 = factory.generate >(80); -// REQUIRE(list2 == nullptr); -// } -// -// SECTION("Test generate and destroy"){ -// uint64_t* number = factory.generate(32000); -// REQUIRE(number != nullptr); -// REQUIRE(*number == 32000); -// store_address_t address; -// uint8_t* ptr = nullptr; -// REQUIRE(storagePool.getFreeElement(&address, sizeof(uint64_t), &ptr) -// == static_cast(StorageManagerIF::DATA_TOO_LARGE)); -// uint64_t* number2 = factory.generate(12345); -// REQUIRE(number2 == nullptr); -// REQUIRE(factory.destroy(number) == static_cast(HasReturnvaluesIF::RETURN_OK)); -// REQUIRE(storagePool.getFreeElement(&address, sizeof(uint64_t), &ptr) -// == static_cast(HasReturnvaluesIF::RETURN_OK)); -// REQUIRE(storagePool.deleteData(address) == static_cast(HasReturnvaluesIF::RETURN_OK)); -// -// //Check that PlacementFactory checks for nullptr -// ptr = nullptr; -// REQUIRE(factory.destroy(ptr) == static_cast(HasReturnvaluesIF::RETURN_FAILED)); -// } -//} +#include +#include +#include +#include + +#include +#include + +TEST_CASE( "PlacementFactory Tests", "[TestPlacementFactory]") { + INFO("PlacementFactory Tests"); + + LocalPool::LocalPoolConfig poolCfg= {{1, sizeof(uint16_t)}, + {1, sizeof(uint32_t)}, {1, sizeof(uint64_t)} + }; + //const uint16_t element_sizes[3] = {sizeof(uint16_t), sizeof(uint32_t), sizeof(uint64_t)}; + //const uint16_t n_elements[3] = {1, 1, 1}; + LocalPool storagePool(0x1, poolCfg, false, true); + PlacementFactory factory(&storagePool); + + SECTION("Pool overload"){ + store_address_t address; + uint8_t* ptr = nullptr; + REQUIRE(storagePool.getFreeElement(&address, sizeof(ArrayList), &ptr) + == static_cast(StorageManagerIF::DATA_TOO_LARGE)); + ArrayList* list2 = factory.generate >(80); + REQUIRE(list2 == nullptr); + } + + SECTION("Test generate and destroy"){ + uint64_t* number = factory.generate(32000); + REQUIRE(number != nullptr); + REQUIRE(*number == 32000); + store_address_t address; + uint8_t* ptr = nullptr; + REQUIRE(storagePool.getFreeElement(&address, sizeof(uint64_t), &ptr) + == static_cast(StorageManagerIF::DATA_TOO_LARGE)); + uint64_t* number2 = factory.generate(12345); + REQUIRE(number2 == nullptr); + REQUIRE(factory.destroy(number) == static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(storagePool.getFreeElement(&address, sizeof(uint64_t), &ptr) + == static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(storagePool.deleteData(address) == static_cast(HasReturnvaluesIF::RETURN_OK)); + + //Check that PlacementFactory checks for nullptr + ptr = nullptr; + REQUIRE(factory.destroy(ptr) == static_cast(HasReturnvaluesIF::RETURN_FAILED)); + } +} diff --git a/unittest/tests/datapoollocal/CMakeLists.txt b/unittest/tests/datapoollocal/CMakeLists.txt new file mode 100644 index 00000000..f196a080 --- /dev/null +++ b/unittest/tests/datapoollocal/CMakeLists.txt @@ -0,0 +1,6 @@ +target_sources(${TARGET_NAME} PRIVATE + LocalPoolVariableTest.cpp + LocalPoolVectorTest.cpp + DataSetTest.cpp + LocalPoolManagerTest.cpp +) diff --git a/unittest/tests/datapoollocal/DataSetTest.cpp b/unittest/tests/datapoollocal/DataSetTest.cpp new file mode 100644 index 00000000..968a0b3d --- /dev/null +++ b/unittest/tests/datapoollocal/DataSetTest.cpp @@ -0,0 +1,23 @@ +#include "LocalPoolOwnerBase.h" + +#include +#include +#include +#include + +TEST_CASE("LocalDataSet" , "[LocDataSetTest]") { + LocalPoolOwnerBase* poolOwner = objectManager-> + get(objects::TEST_LOCAL_POOL_OWNER_BASE); + REQUIRE(poolOwner != nullptr); + REQUIRE(poolOwner->initializeHkManager() == retval::CATCH_OK); + REQUIRE(poolOwner->initializeHkManagerAfterTaskCreation() + == retval::CATCH_OK); + const uint32_t setId = 0; + SECTION("BasicTest") { + StaticLocalDataSet<3> localSet = StaticLocalDataSet<3>( + sid_t(objects::TEST_LOCAL_POOL_OWNER_BASE, setId)); + } +} + + + diff --git a/unittest/tests/datapoollocal/LocalPoolManagerTest.cpp b/unittest/tests/datapoollocal/LocalPoolManagerTest.cpp new file mode 100644 index 00000000..f550582e --- /dev/null +++ b/unittest/tests/datapoollocal/LocalPoolManagerTest.cpp @@ -0,0 +1,122 @@ +#include "LocalPoolOwnerBase.h" + +#include +#include +#include +#include +#include + + +TEST_CASE("LocalPoolManagerTest" , "[LocManTest]") { + LocalPoolOwnerBase* poolOwner = objectManager-> + get(objects::TEST_LOCAL_POOL_OWNER_BASE); + REQUIRE(poolOwner != nullptr); + REQUIRE(poolOwner->initializeHkManager() == retval::CATCH_OK); + REQUIRE(poolOwner->initializeHkManagerAfterTaskCreation() + == retval::CATCH_OK); + REQUIRE(poolOwner->dataset.assignPointers() == retval::CATCH_OK); + MessageQueueMockBase* mqMock = poolOwner->getMockQueueHandle(); + REQUIRE(mqMock != nullptr); + CommandMessage messageSent; + uint8_t messagesSent = 0; + + + SECTION("BasicTest") { + // Subscribe for message generation on update. + REQUIRE(poolOwner->subscribeWrapperSetUpdate() == retval::CATCH_OK); + // Subscribe for an update message. + poolOwner->dataset.setChanged(true); + // Now the update message should be generated. + REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK); + REQUIRE(mqMock->wasMessageSent() == true); + + REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK); + CHECK(messageSent.getCommand() == static_cast( + HousekeepingMessage::UPDATE_NOTIFICATION_SET)); + + // Should have been reset. + CHECK(poolOwner->dataset.hasChanged() == false); + // Set changed again, result should be the same. + poolOwner->dataset.setChanged(true); + REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK); + + REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + CHECK(messagesSent == 1); + REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK); + CHECK(messageSent.getCommand() == static_cast( + HousekeepingMessage::UPDATE_NOTIFICATION_SET)); + + // now subscribe for set update HK as well. + REQUIRE(poolOwner->subscribeWrapperSetUpdateHk() == retval::CATCH_OK); + poolOwner->dataset.setChanged(true); + REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK); + REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + CHECK(messagesSent == 2); + // first message sent should be the update notification, considering + // the internal list is a vector checked in insertion order. + REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK); + CHECK(messageSent.getCommand() == static_cast( + HousekeepingMessage::UPDATE_NOTIFICATION_SET)); + + REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK); + CHECK(messageSent.getCommand() == static_cast( + HousekeepingMessage::HK_REPORT)); + // clear message to avoid memory leak, our mock won't do it for us (yet) + CommandMessageCleaner::clearCommandMessage(&messageSent); + } + + SECTION("AdvancedTests") { + // we need to reset the subscription list because the pool owner + // is a global object. + poolOwner->resetSubscriptionList(); + // Subscribe for variable update as well + REQUIRE(not poolOwner->dataset.hasChanged()); + REQUIRE(poolOwner->subscribeWrapperVariableUpdate(lpool::uint8VarId) == + retval::CATCH_OK); + lp_var_t* poolVar = dynamic_cast*>( + poolOwner->getPoolObjectHandle(lpool::uint8VarId)); + REQUIRE(poolVar != nullptr); + poolVar->setChanged(true); + REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK); + + // Check update notification was sent. + REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + CHECK(messagesSent == 1); + // Should have been reset. + CHECK(poolVar->hasChanged() == false); + REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK); + CHECK(messageSent.getCommand() == static_cast( + HousekeepingMessage::UPDATE_NOTIFICATION_VARIABLE)); + + // now subscribe for the dataset update (HK and update) again + REQUIRE(poolOwner->subscribeWrapperSetUpdate() == retval::CATCH_OK); + REQUIRE(poolOwner->subscribeWrapperSetUpdateHk() == retval::CATCH_OK); + + poolOwner->dataset.setChanged(true); + REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK); + // now two messages should be sent. + REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + CHECK(messagesSent == 2); + mqMock->clearMessages(true); + + poolOwner->dataset.setChanged(true); + poolVar->setChanged(true); + REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK); + // now three messages should be sent. + REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + CHECK(messagesSent == 3); + REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK); + CHECK(messageSent.getCommand() == static_cast( + HousekeepingMessage::UPDATE_NOTIFICATION_VARIABLE)); + REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK); + CHECK(messageSent.getCommand() == static_cast( + HousekeepingMessage::UPDATE_NOTIFICATION_SET)); + REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK); + CHECK(messageSent.getCommand() == static_cast( + HousekeepingMessage::HK_REPORT)); + CommandMessageCleaner::clearCommandMessage(&messageSent); + REQUIRE(mqMock->receiveMessage(&messageSent) == + static_cast(MessageQueueIF::EMPTY)); + } +} + diff --git a/unittest/tests/datapoollocal/LocalPoolOwnerBase.h b/unittest/tests/datapoollocal/LocalPoolOwnerBase.h new file mode 100644 index 00000000..916b3e45 --- /dev/null +++ b/unittest/tests/datapoollocal/LocalPoolOwnerBase.h @@ -0,0 +1,197 @@ +#ifndef FSFW_UNITTEST_TESTS_DATAPOOLLOCAL_LOCALPOOLOWNERBASE_H_ +#define FSFW_UNITTEST_TESTS_DATAPOOLLOCAL_LOCALPOOLOWNERBASE_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace lpool { +static constexpr lp_id_t uint8VarId = 0; +static constexpr lp_id_t floatVarId = 1; +static constexpr lp_id_t uint32VarId = 2; +static constexpr lp_id_t uint16Vec3Id = 3; +static constexpr lp_id_t int64Vec2Id = 4; + +static constexpr uint32_t testSetId = 0; +static constexpr uint8_t dataSetMaxVariables = 10; +static const sid_t testSid = sid_t(objects::TEST_LOCAL_POOL_OWNER_BASE, + testSetId); +} + + +class LocalPoolTestDataSet: public LocalDataSet { +public: + LocalPoolTestDataSet(HasLocalDataPoolIF* owner, uint32_t setId): + LocalDataSet(owner, setId, lpool::dataSetMaxVariables) { + } + + ReturnValue_t assignPointers() { + PoolVariableIF** rawVarArray = getContainer(); + localPoolVarUint8 = dynamic_cast*>(rawVarArray[0]); + localPoolVarFloat = dynamic_cast*>(rawVarArray[1]); + localPoolUint16Vec = dynamic_cast*>( + rawVarArray[2]); + if(localPoolVarUint8 == nullptr or localPoolVarFloat == nullptr or + localPoolUint16Vec == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + return HasReturnvaluesIF::RETURN_OK; + } + + lp_var_t* localPoolVarUint8 = nullptr; + lp_var_t* localPoolVarFloat = nullptr; + lp_vec_t* localPoolUint16Vec = nullptr; + +private: +}; + + +class LocalPoolOwnerBase: public SystemObject, public HasLocalDataPoolIF { +public: + LocalPoolOwnerBase( + object_id_t objectId = objects::TEST_LOCAL_POOL_OWNER_BASE): + SystemObject(objectId), poolManager(this, messageQueue), + dataset(this, lpool::testSetId) { + messageQueue = new MessageQueueMockBase(); + } + + ~LocalPoolOwnerBase() { + QueueFactory::instance()->deleteMessageQueue(messageQueue); + } + + object_id_t getObjectId() const override { + return SystemObject::getObjectId(); + } + + ReturnValue_t initializeHkManager() { + if(not initialized) { + initialized = true; + return poolManager.initialize(messageQueue); + } + return HasReturnvaluesIF::RETURN_OK; + } + + ReturnValue_t initializeHkManagerAfterTaskCreation() { + if(not initializedAfterTaskCreation) { + initializedAfterTaskCreation = true; + return poolManager.initializeAfterTaskCreation(); + } + return HasReturnvaluesIF::RETURN_OK; + } + + /** Command queue for housekeeping messages. */ + MessageQueueId_t getCommandQueue() const override { + return messageQueue->getId(); + } + + // This is called by initializeAfterTaskCreation of the HK manager. + virtual ReturnValue_t initializeLocalDataPool( + localpool::DataPool& localDataPoolMap, + LocalDataPoolManager& poolManager) { + // Default initialization empty for now. + localDataPoolMap.emplace(lpool::uint8VarId, + new PoolEntry({0})); + localDataPoolMap.emplace(lpool::floatVarId, + new PoolEntry({0})); + localDataPoolMap.emplace(lpool::uint32VarId, + new PoolEntry({0})); + + localDataPoolMap.emplace(lpool::uint16Vec3Id, + new PoolEntry({0, 0, 0})); + localDataPoolMap.emplace(lpool::int64Vec2Id, + new PoolEntry({0, 0})); + return HasReturnvaluesIF::RETURN_OK; + } + + LocalDataPoolManager* getHkManagerHandle() override { + return &poolManager; + } + + uint32_t getPeriodicOperationFrequency() const override { + return 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) override { + return &dataset; + } + + virtual LocalPoolObjectBase* getPoolObjectHandle( + lp_id_t localPoolId) override { + if(localPoolId == lpool::uint8VarId) { + return &testUint8; + } + else if(localPoolId == lpool::uint16Vec3Id) { + return &testUint16Vec; + } + else if(localPoolId == lpool::floatVarId) { + return &testFloat; + } + else if(localPoolId == lpool::int64Vec2Id) { + return &testInt64Vec; + } + else if(localPoolId == lpool::uint32VarId) { + return &testUint32; + } + else { + return &testUint8; + } + } + + MessageQueueMockBase* getMockQueueHandle() const { + return dynamic_cast(messageQueue); + } + + ReturnValue_t subscribeWrapperSetUpdate() { + return poolManager.subscribeForSetUpdateMessages(lpool::testSetId, + objects::NO_OBJECT, MessageQueueIF::NO_QUEUE, false); + } + + ReturnValue_t subscribeWrapperSetUpdateHk(bool diagnostics = false) { + return poolManager.subscribeForUpdatePackets(lpool::testSid, diagnostics, + false, objects::HK_RECEIVER_MOCK); + } + + ReturnValue_t subscribeWrapperVariableUpdate(lp_id_t localPoolId) { + return poolManager.subscribeForVariableUpdateMessages(localPoolId, + MessageQueueIF::NO_QUEUE, objects::NO_OBJECT, false); + } + + void resetSubscriptionList() { + poolManager.clearReceiversList(); + } + + LocalDataPoolManager poolManager; + LocalPoolTestDataSet dataset; +private: + + lp_var_t testUint8 = lp_var_t(this, lpool::uint8VarId, + &dataset); + lp_var_t testFloat = lp_var_t(this, lpool::floatVarId, + &dataset); + lp_var_t testUint32 = lp_var_t(this, lpool::uint32VarId); + + lp_vec_t testUint16Vec = lp_vec_t(this, + lpool::uint16Vec3Id, &dataset); + lp_vec_t testInt64Vec = lp_vec_t(this, + lpool::int64Vec2Id); + + MessageQueueIF* messageQueue = nullptr; + + bool initialized = false; + bool initializedAfterTaskCreation = false; + +}; + +#endif /* FSFW_UNITTEST_TESTS_DATAPOOLLOCAL_LOCALPOOLOWNERBASE_H_ */ diff --git a/unittest/tests/datapoollocal/LocalPoolVariableTest.cpp b/unittest/tests/datapoollocal/LocalPoolVariableTest.cpp new file mode 100644 index 00000000..2e4cb7ec --- /dev/null +++ b/unittest/tests/datapoollocal/LocalPoolVariableTest.cpp @@ -0,0 +1,123 @@ +#include "LocalPoolOwnerBase.h" + +#include +#include +#include + + +TEST_CASE("LocalPoolVariable" , "[LocPoolVarTest]") { + LocalPoolOwnerBase* poolOwner = objectManager-> + get(objects::TEST_LOCAL_POOL_OWNER_BASE); + REQUIRE(poolOwner != nullptr); + REQUIRE(poolOwner->initializeHkManager() == retval::CATCH_OK); + REQUIRE(poolOwner->initializeHkManagerAfterTaskCreation() + == retval::CATCH_OK); + + SECTION("Basic Tests") { + // very basic test. + lp_var_t testVariable = lp_var_t( + objects::TEST_LOCAL_POOL_OWNER_BASE, lpool::uint8VarId); + REQUIRE(testVariable.read() == retval::CATCH_OK); + CHECK(testVariable.value == 0); + testVariable.value = 5; + REQUIRE(testVariable.commit() == retval::CATCH_OK); + REQUIRE(testVariable.read() == retval::CATCH_OK); + REQUIRE(testVariable.value == 5); + CHECK(not testVariable.isValid()); + testVariable.setValid(true); + CHECK(testVariable.isValid()); + CHECK(testVariable.commit(true) == retval::CATCH_OK); + + testVariable.setReadWriteMode(pool_rwm_t::VAR_READ); + CHECK(testVariable.getReadWriteMode() == pool_rwm_t::VAR_READ); + testVariable.setReadWriteMode(pool_rwm_t::VAR_READ_WRITE); + + testVariable.setDataPoolId(22); + CHECK(testVariable.getDataPoolId() == 22); + testVariable.setDataPoolId(lpool::uint8VarId); + + testVariable.setChanged(true); + CHECK(testVariable.hasChanged()); + testVariable.setChanged(false); + + gp_id_t globPoolId(objects::TEST_LOCAL_POOL_OWNER_BASE, + lpool::uint8VarId); + lp_var_t testVariable2 = lp_var_t(globPoolId); + REQUIRE(testVariable2.read() == retval::CATCH_OK); + CHECK(testVariable2 == 5); + CHECK(testVariable == testVariable2); + testVariable = 10; + CHECK(testVariable != 5); + //CHECK(not testVariable != testVariable2); + uint8_t variableRaw = 0; + uint8_t* varPtr = &variableRaw; + size_t maxSize = testVariable.getSerializedSize(); + CHECK(maxSize == 1); + size_t serSize = 0; + CHECK(testVariable.serialize(&varPtr, &serSize, maxSize, + SerializeIF::Endianness::MACHINE) == retval::CATCH_OK); + CHECK(variableRaw == 10); + const uint8_t* varConstPtr = &variableRaw; + testVariable = 5; + CHECK(testVariable.deSerialize(&varConstPtr, &serSize, + SerializeIF::Endianness::MACHINE) == retval::CATCH_OK); + CHECK(testVariable == 10); + CHECK(testVariable != testVariable2); + CHECK(testVariable2 < testVariable); + CHECK(testVariable2 < 10); + CHECK(testVariable > 5); + CHECK(testVariable > testVariable2); + variableRaw = static_cast(testVariable2); + CHECK(variableRaw == 5); + + CHECK(testVariable == 10); + testVariable = testVariable2; + CHECK(testVariable == 5); + } + + SECTION("ErrorHandling") { + + // not try to use a local pool variable which does not exist + lp_var_t invalidVariable = lp_var_t( + objects::TEST_LOCAL_POOL_OWNER_BASE, 0xffffffff); + REQUIRE(invalidVariable.read() == + static_cast(localpool::POOL_ENTRY_NOT_FOUND)); + + REQUIRE(invalidVariable.commit() == + static_cast(localpool::POOL_ENTRY_NOT_FOUND)); + // now try to access with wrong type + lp_var_t invalidVariable2 = lp_var_t( + objects::TEST_LOCAL_POOL_OWNER_BASE, lpool::uint8VarId); + REQUIRE(invalidVariable2.read() == + static_cast(localpool::POOL_ENTRY_TYPE_CONFLICT)); + + lp_var_t readOnlyVar = lp_var_t( + objects::TEST_LOCAL_POOL_OWNER_BASE, lpool::uint8VarId, + nullptr, pool_rwm_t::VAR_READ); + REQUIRE(readOnlyVar.commit() == + static_cast(PoolVariableIF::INVALID_READ_WRITE_MODE)); + lp_var_t writeOnlyVar = lp_var_t( + objects::TEST_LOCAL_POOL_OWNER_BASE, lpool::uint8VarId, + nullptr, pool_rwm_t::VAR_WRITE); + REQUIRE(writeOnlyVar.read() == static_cast( + PoolVariableIF::INVALID_READ_WRITE_MODE)); + + lp_var_t uint32tVar = lp_var_t( + objects::TEST_LOCAL_POOL_OWNER_BASE, lpool::uint32VarId); +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "LocalPoolVariable printout: " < OK + lp_var_t invalidObjectVar = lp_var_t( + 0xffffffff, lpool::uint8VarId); + gp_id_t globPoolId(0xffffffff, + lpool::uint8VarId); + lp_var_t invalidObjectVar2 = lp_var_t(globPoolId); + lp_var_t invalidObjectVar3 = lp_var_t(nullptr, + lpool::uint8VarId); + } + +} + + diff --git a/unittest/tests/datapoollocal/LocalPoolVectorTest.cpp b/unittest/tests/datapoollocal/LocalPoolVectorTest.cpp new file mode 100644 index 00000000..7c309bbb --- /dev/null +++ b/unittest/tests/datapoollocal/LocalPoolVectorTest.cpp @@ -0,0 +1,120 @@ +#include "LocalPoolOwnerBase.h" + +#include +#include +#include + +TEST_CASE("LocalPoolVector" , "[LocPoolVecTest]") { + LocalPoolOwnerBase* poolOwner = objectManager-> + get(objects::TEST_LOCAL_POOL_OWNER_BASE); + REQUIRE(poolOwner != nullptr); + REQUIRE(poolOwner->initializeHkManager() == retval::CATCH_OK); + REQUIRE(poolOwner->initializeHkManagerAfterTaskCreation() + == retval::CATCH_OK); + + SECTION("BasicTest") { + // very basic test. + lp_vec_t testVector = lp_vec_t( + objects::TEST_LOCAL_POOL_OWNER_BASE, lpool::uint16Vec3Id); + REQUIRE(testVector.read() == retval::CATCH_OK); + testVector.value[0] = 5; + testVector.value[1] = 232; + testVector.value[2] = 32023; + + REQUIRE(testVector.commit(true) == retval::CATCH_OK); + CHECK(testVector.isValid()); + + testVector.value[0] = 0; + testVector.value[1] = 0; + testVector.value[2] = 0; + + CHECK(testVector.read() == retval::CATCH_OK); + CHECK(testVector.value[0] == 5); + CHECK(testVector.value[1] == 232); + CHECK(testVector.value[2] == 32023); + + CHECK(testVector[0] == 5); + + // This is invalid access, so the last value will be set instead. + // (we can't throw exceptions) + testVector[4] = 12; + CHECK(testVector[2] == 12); + CHECK(testVector.commit() == retval::CATCH_OK); + + // Use read-only reference. + const lp_vec_t& roTestVec = testVector; + uint16_t valueOne = roTestVec[0]; + CHECK(valueOne == 5); + + uint16_t lastVal = roTestVec[25]; + CHECK(lastVal == 12); + + size_t maxSize = testVector.getSerializedSize(); + CHECK(maxSize == 6); + + uint16_t serializedVector[3]; + uint8_t* vecPtr = reinterpret_cast(serializedVector); + size_t serSize = 0; + REQUIRE(testVector.serialize(&vecPtr, &serSize, + maxSize, SerializeIF::Endianness::MACHINE) == retval::CATCH_OK); + + CHECK(serSize == 6); + CHECK(serializedVector[0] == 5); + CHECK(serializedVector[1] == 232); + CHECK(serializedVector[2] == 12); + + maxSize = 1; + REQUIRE(testVector.serialize(&vecPtr, &serSize, + maxSize, SerializeIF::Endianness::MACHINE) == + static_cast(SerializeIF::BUFFER_TOO_SHORT)); + + serializedVector[0] = 16; + serializedVector[1] = 7832; + serializedVector[2] = 39232; + + const uint8_t* constVecPtr = reinterpret_cast( + serializedVector); + REQUIRE(testVector.deSerialize(&constVecPtr, &serSize, + SerializeIF::Endianness::MACHINE) == retval::CATCH_OK); + CHECK(testVector[0] == 16); + CHECK(testVector[1] == 7832); + CHECK(testVector[2] == 39232); + + serSize = 1; + REQUIRE(testVector.deSerialize(&constVecPtr, &serSize, + SerializeIF::Endianness::MACHINE) == + static_cast(SerializeIF::STREAM_TOO_SHORT)); + } + + SECTION("ErrorHandling") { + // not try to use a local pool variable which does not exist + lp_vec_t invalidVector = lp_vec_t( + objects::TEST_LOCAL_POOL_OWNER_BASE, 0xffffffff); + REQUIRE(invalidVector.read() == + static_cast(localpool::POOL_ENTRY_NOT_FOUND)); + REQUIRE(invalidVector.commit() == + static_cast(localpool::POOL_ENTRY_NOT_FOUND)); + + // now try to access with wrong type + lp_vec_t invalidVector2 = lp_vec_t( + objects::TEST_LOCAL_POOL_OWNER_BASE, lpool::uint16Vec3Id); + REQUIRE(invalidVector2.read() == + static_cast(localpool::POOL_ENTRY_TYPE_CONFLICT)); + REQUIRE(invalidVector2.commit() == + static_cast(localpool::POOL_ENTRY_TYPE_CONFLICT)); + + lp_vec_t writeOnlyVec = lp_vec_t( + objects::TEST_LOCAL_POOL_OWNER_BASE, lpool::uint16Vec3Id, + nullptr, pool_rwm_t::VAR_WRITE); + REQUIRE(writeOnlyVec.read() == + static_cast(PoolVariableIF::INVALID_READ_WRITE_MODE)); + + lp_vec_t readOnlyVec = lp_vec_t( + objects::TEST_LOCAL_POOL_OWNER_BASE, lpool::uint16Vec3Id, + nullptr, pool_rwm_t::VAR_READ); + REQUIRE(readOnlyVec.commit() == + static_cast(PoolVariableIF::INVALID_READ_WRITE_MODE)); + } +} + + diff --git a/unittest/tests/mocks/HkReceiverMock.h b/unittest/tests/mocks/HkReceiverMock.h new file mode 100644 index 00000000..e7509c59 --- /dev/null +++ b/unittest/tests/mocks/HkReceiverMock.h @@ -0,0 +1,20 @@ +#ifndef FSFW_UNITTEST_TESTS_MOCKS_HKRECEIVERMOCK_H_ +#define FSFW_UNITTEST_TESTS_MOCKS_HKRECEIVERMOCK_H_ + +#include +#include + +class HkReceiverMock: public SystemObject, public AcceptsHkPacketsIF { +public: + HkReceiverMock(object_id_t objectId): SystemObject(objectId) { + + } + + MessageQueueId_t getHkQueue() const { + return MessageQueueIF::NO_QUEUE; + } +}; + + + +#endif /* FSFW_UNITTEST_TESTS_MOCKS_HKRECEIVERMOCK_H_ */ diff --git a/unittest/tests/mocks/MessageQueueMockBase.h b/unittest/tests/mocks/MessageQueueMockBase.h new file mode 100644 index 00000000..7b810b41 --- /dev/null +++ b/unittest/tests/mocks/MessageQueueMockBase.h @@ -0,0 +1,121 @@ +#ifndef FSFW_UNITTEST_TESTS_MOCKS_MESSAGEQUEUEMOCKBASE_H_ +#define FSFW_UNITTEST_TESTS_MOCKS_MESSAGEQUEUEMOCKBASE_H_ + +#include +#include +#include +#include + +#include + +class MessageQueueMockBase: public MessageQueueIF { +public: + MessageQueueId_t myQueueId = tconst::testQueueId; + uint8_t messageSentCounter = 0; + bool defaultDestSet = false; + bool messageSent = false; + + + bool wasMessageSent(uint8_t* messageSentCounter = nullptr, + bool resetCounter = true) { + bool tempMessageSent = messageSent; + messageSent = false; + if(messageSentCounter != nullptr) { + *messageSentCounter = this->messageSentCounter; + } + if(resetCounter) { + this->messageSentCounter = 0; + } + return tempMessageSent; + } + + virtual ReturnValue_t reply( MessageQueueMessageIF* message ) { + //messageSent = true; + //lastMessage = *(dynamic_cast(message)); + return sendMessage(myQueueId, message); + return HasReturnvaluesIF::RETURN_OK; + }; + virtual ReturnValue_t receiveMessage(MessageQueueMessageIF* message, + MessageQueueId_t *receivedFrom) { + return receiveMessage(message); + } + virtual ReturnValue_t receiveMessage(MessageQueueMessageIF* message) { + if(messagesSentQueue.empty()) { + return MessageQueueIF::EMPTY; + } + + std::memcpy(message->getBuffer(), messagesSentQueue.front().getBuffer(), + message->getMessageSize()); + messagesSentQueue.pop(); + return HasReturnvaluesIF::RETURN_OK; + } + virtual ReturnValue_t flush(uint32_t* count) { + return HasReturnvaluesIF::RETURN_OK; + } + virtual MessageQueueId_t getLastPartner() const { + return myQueueId; + } + virtual MessageQueueId_t getId() const { + return myQueueId; + } + virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo, + MessageQueueMessageIF* message, MessageQueueId_t sentFrom, + bool ignoreFault = false ) { + //messageSent = true; + //lastMessage = *(dynamic_cast(message)); + //return HasReturnvaluesIF::RETURN_OK; + return sendMessage(sendTo, message); + } + virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessageIF* message, + MessageQueueId_t sentFrom, bool ignoreFault = false ) { + //messageSent = true; + //lastMessage = *(dynamic_cast(message)); + //return HasReturnvaluesIF::RETURN_OK; + return sendMessage(myQueueId, message); + } + virtual ReturnValue_t sendToDefault( MessageQueueMessageIF* message ) { + //messageSent = true; + //lastMessage = *(dynamic_cast(message)); + return sendMessage(myQueueId, message); + } + virtual ReturnValue_t sendMessage( MessageQueueId_t sendTo, + MessageQueueMessageIF* message, bool ignoreFault = false ) override { + messageSent = true; + messageSentCounter++; + MessageQueueMessage& messageRef = *( + dynamic_cast(message)); + messagesSentQueue.push(messageRef); + return HasReturnvaluesIF::RETURN_OK; + } + virtual void setDefaultDestination(MessageQueueId_t defaultDestination) { + myQueueId = defaultDestination; + defaultDestSet = true; + } + + virtual MessageQueueId_t getDefaultDestination() const { + return myQueueId; + } + virtual bool isDefaultDestinationSet() const { + return defaultDestSet; + } + + void clearMessages(bool clearCommandMessages = true) { + while(not messagesSentQueue.empty()) { + if(clearCommandMessages) { + CommandMessage message; + std::memcpy(message.getBuffer(), + messagesSentQueue.front().getBuffer(), + message.getMessageSize()); + message.clear(); + } + messagesSentQueue.pop(); + } + } + +private: + std::queue messagesSentQueue; + //MessageQueueMessage lastMessage; +}; + + +#endif /* FSFW_UNITTEST_TESTS_MOCKS_MESSAGEQUEUEMOCKBASE_H_ */ diff --git a/unittest/tests/osal/CMakeLists.txt b/unittest/tests/osal/CMakeLists.txt new file mode 100644 index 00000000..5ca5e400 --- /dev/null +++ b/unittest/tests/osal/CMakeLists.txt @@ -0,0 +1,4 @@ +target_sources(${TARGET_NAME} PRIVATE + TestMessageQueue.cpp + TestSemaphore.cpp +) diff --git a/unittest/tests/osal/TestMessageQueue.cpp b/unittest/tests/osal/TestMessageQueue.cpp index 441d32e7..e33b7240 100644 --- a/unittest/tests/osal/TestMessageQueue.cpp +++ b/unittest/tests/osal/TestMessageQueue.cpp @@ -1,8 +1,10 @@ -#include "../../ipc/MessageQueueIF.h" -#include "../../ipc/QueueFactory.h" -#include +#include +#include + +#include +#include + #include -#include "../../core/CatchDefinitions.h" TEST_CASE("MessageQueue Basic Test","[TestMq]") { MessageQueueIF* testSenderMq = diff --git a/unittest/tests/serialize/CMakeLists.txt b/unittest/tests/serialize/CMakeLists.txt new file mode 100644 index 00000000..5a9d9a0f --- /dev/null +++ b/unittest/tests/serialize/CMakeLists.txt @@ -0,0 +1,5 @@ +target_sources(${TARGET_NAME} PRIVATE + TestSerialBufferAdapter.cpp + TestSerialization.cpp + TestSerialLinkedPacket.cpp +) diff --git a/unittest/tests/serialize/TestSerialBufferAdapter.cpp b/unittest/tests/serialize/TestSerialBufferAdapter.cpp index 07cd3f9c..1938746d 100644 --- a/unittest/tests/serialize/TestSerialBufferAdapter.cpp +++ b/unittest/tests/serialize/TestSerialBufferAdapter.cpp @@ -1,7 +1,9 @@ -#include "../../serialize/SerialBufferAdapter.h" +#include -#include -#include "../../core/CatchDefinitions.h" +#include +#include + +#include static bool test_value_bool = true; diff --git a/unittest/tests/serialize/TestSerialLinkedPacket.cpp b/unittest/tests/serialize/TestSerialLinkedPacket.cpp index fbe48894..b90ae9f8 100644 --- a/unittest/tests/serialize/TestSerialLinkedPacket.cpp +++ b/unittest/tests/serialize/TestSerialLinkedPacket.cpp @@ -1,9 +1,12 @@ #include "TestSerialLinkedPacket.h" -#include "../../core/CatchDefinitions.h" +#include -#include "../../globalfunctions/arrayprinter.h" +#include -#include +#include +#include + +#include TEST_CASE("Serial Linked Packet" , "[SerLinkPacket]") { diff --git a/unittest/tests/serialize/TestSerialLinkedPacket.h b/unittest/tests/serialize/TestSerialLinkedPacket.h index 6c720577..71f258f9 100644 --- a/unittest/tests/serialize/TestSerialLinkedPacket.h +++ b/unittest/tests/serialize/TestSerialLinkedPacket.h @@ -37,7 +37,7 @@ public: return buffer.entry.getConstBuffer(); } - const size_t getBufferLength() { + size_t getBufferLength() { return buffer.getSerializedSize(); } diff --git a/unittest/tests/serialize/TestSerialization.cpp b/unittest/tests/serialize/TestSerialization.cpp index 6e31170a..3de581ec 100644 --- a/unittest/tests/serialize/TestSerialization.cpp +++ b/unittest/tests/serialize/TestSerialization.cpp @@ -1,8 +1,10 @@ -#include "../../serialize/SerializeAdapter.h" +#include + +#include +#include +#include -#include "catch.hpp" #include -#include "../../core/CatchDefinitions.h" static bool test_value_bool = true; static uint8_t tv_uint8 {5}; @@ -119,10 +121,10 @@ TEST_CASE("Auto Serialize Adapter testing", "[single-file]") { REQUIRE(tv_int16 == -829); REQUIRE(tv_int32 == -2312); - REQUIRE(tv_float == Approx(8.214921)); - REQUIRE(tv_double == Approx(9.2132142141e8)); - REQUIRE(tv_sfloat == Approx(-922.2321321)); - REQUIRE(tv_sdouble == Approx(-2.2421e19)); + REQUIRE(tv_float == Catch::Approx(8.214921)); + REQUIRE(tv_double == Catch::Approx(9.2132142141e8)); + REQUIRE(tv_sfloat == Catch::Approx(-922.2321321)); + REQUIRE(tv_sdouble == Catch::Approx(-2.2421e19)); } } diff --git a/unittest/tests/storagemanager/CMakeLists.txt b/unittest/tests/storagemanager/CMakeLists.txt new file mode 100644 index 00000000..ed7be7d5 --- /dev/null +++ b/unittest/tests/storagemanager/CMakeLists.txt @@ -0,0 +1,4 @@ +target_sources(${TARGET_NAME} PRIVATE + TestNewAccessor.cpp + TestPool.cpp +) diff --git a/unittest/tests/storagemanager/TestNewAccessor.cpp b/unittest/tests/storagemanager/TestNewAccessor.cpp index 7bd0dee2..10d05c6b 100644 --- a/unittest/tests/storagemanager/TestNewAccessor.cpp +++ b/unittest/tests/storagemanager/TestNewAccessor.cpp @@ -1,161 +1,161 @@ -//#include -//#include -//#include "../../core/CatchDefinitions.h" -//#include -// -//TEST_CASE( "New Accessor" , "[NewAccessor]") { -// uint16_t numberOfElements[1] = {1}; -// uint16_t sizeofElements[1] = {10}; -// LocalPool<1> SimplePool = LocalPool<1>(0, sizeofElements, numberOfElements); -// std::array testDataArray; -// std::array receptionArray; -// store_address_t testStoreId; -// ReturnValue_t result = retval::CATCH_FAILED; -// -// for(size_t i = 0; i < testDataArray.size(); i++) { -// testDataArray[i] = i; -// } -// size_t size = 10; -// -// SECTION ("Simple tests getter functions") { -// result = SimplePool.addData(&testStoreId, testDataArray.data(), size); -// REQUIRE(result == retval::CATCH_OK); -// auto resultPair = SimplePool.getData(testStoreId); -// REQUIRE(resultPair.first == retval::CATCH_OK); -// resultPair.second.getDataCopy(receptionArray.data(), 20); -// CHECK(resultPair.second.getId() == testStoreId); -// CHECK(resultPair.second.size() == 10); -// for(size_t i = 0; i < size; i++) { -// CHECK(receptionArray[i] == i ); -// } -// -// std::copy(resultPair.second.data(), resultPair.second.data() + -// resultPair.second.size(), receptionArray.data()); -// for(size_t i = 0; i < size; i++) { -// CHECK(receptionArray[i] == i ); -// } -// -// { -// auto resultPairLoc = SimplePool.getData(testStoreId); -// REQUIRE(resultPairLoc.first == retval::CATCH_OK); -// // data should be deleted when accessor goes out of scope. -// } -// resultPair = SimplePool.getData(testStoreId); -// REQUIRE(resultPair.first == (int) StorageManagerIF::DATA_DOES_NOT_EXIST); -// -// result = SimplePool.addData(&testStoreId, testDataArray.data(), size); -// REQUIRE(result == retval::CATCH_OK); -// { -// ConstStorageAccessor constAccessor(testStoreId); -// result = SimplePool.getData(testStoreId, constAccessor); -// REQUIRE(result == retval::CATCH_OK); -// constAccessor.getDataCopy(receptionArray.data(), 20); -// for(size_t i = 0; i < size; i++) { -// CHECK(receptionArray[i] == i ); -// } -// // likewise, data should be deleted when accessor gets out of scope. -// } -// resultPair = SimplePool.getData(testStoreId); -// REQUIRE(resultPair.first == (int) StorageManagerIF::DATA_DOES_NOT_EXIST); -// -// result = SimplePool.addData(&testStoreId, testDataArray.data(), size); -// { -// resultPair = SimplePool.getData(testStoreId); -// REQUIRE(resultPair.first == retval::CATCH_OK); -// resultPair.second.release(); -// // now data should not be deleted anymore -// } -// resultPair = SimplePool.getData(testStoreId); -// REQUIRE(resultPair.first == retval::CATCH_OK); -// resultPair.second.getDataCopy(receptionArray.data(), 20); -// for(size_t i = 0; i < size; i++) { -// CHECK(receptionArray[i] == i ); -// } -// } -// -// -// SECTION("Simple tests modify functions") { -// result = SimplePool.addData(&testStoreId, testDataArray.data(), size); -// REQUIRE(result == retval::CATCH_OK); -// { -// StorageAccessor accessor(testStoreId); -// result = SimplePool.modifyData(testStoreId, accessor); -// REQUIRE(result == retval::CATCH_OK); -// CHECK(accessor.getId() == testStoreId); -// CHECK(accessor.size() == 10); -// accessor.getDataCopy(receptionArray.data(), 20); -// for(size_t i = 0; i < size; i++) { -// CHECK(receptionArray[i] == i ); -// } -// std::copy(accessor.data(), accessor.data() + -// accessor.size(), receptionArray.data()); -// for(size_t i = 0; i < size; i++) { -// CHECK(receptionArray[i] == i ); -// } -// // data should be deleted when accessor goes out of scope -// } -// auto resultPair = SimplePool.getData(testStoreId); -// REQUIRE(resultPair.first == (int) StorageManagerIF::DATA_DOES_NOT_EXIST); -// -// result = SimplePool.addData(&testStoreId, testDataArray.data(), size); -// REQUIRE(result == retval::CATCH_OK); -// { -// auto resultPairLoc = SimplePool.modifyData(testStoreId); -// REQUIRE(resultPairLoc.first == retval::CATCH_OK); -// CHECK(resultPairLoc.second.getId() == testStoreId); -// CHECK(resultPairLoc.second.size() == 10); -// resultPairLoc.second.getDataCopy(receptionArray.data(), 20); -// for(size_t i = 0; i < size; i++) { -// CHECK(receptionArray[i] == i ); -// } -// std::copy(resultPairLoc.second.data(), resultPairLoc.second.data() + -// resultPairLoc.second.size(), receptionArray.data()); -// for(size_t i = 0; i < size; i++) { -// CHECK(receptionArray[i] == i ); -// } -// resultPairLoc.second.release(); -// // data should not be deleted when accessor goes out of scope -// } -// resultPair = SimplePool.getData(testStoreId); -// REQUIRE(resultPair.first == retval::CATCH_OK); -// } -// -// -// SECTION("Write tests") { -// result = SimplePool.addData(&testStoreId, testDataArray.data(), size); -// REQUIRE(result == retval::CATCH_OK); -// { -// auto resultPair = SimplePool.modifyData(testStoreId); -// REQUIRE(resultPair.first == retval::CATCH_OK); -// testDataArray[9] = 42; -// resultPair.second.write(testDataArray.data(), 10, 0); -// // now data should not be deleted -// resultPair.second.release(); -// } -// auto resultConstPair = SimplePool.getData(testStoreId); -// REQUIRE(resultConstPair.first == retval::CATCH_OK); -// -// resultConstPair.second.getDataCopy(receptionArray.data(), 10); -// for(size_t i = 0; i < size-1; i++) { -// CHECK(receptionArray[i] == i ); -// } -// CHECK(receptionArray[9] == 42 ); -// -// auto resultPair = SimplePool.modifyData(testStoreId); -// REQUIRE(resultPair.first == retval::CATCH_OK); -// result = resultPair.second.write(testDataArray.data(), 20, 0); -// REQUIRE(result == retval::CATCH_FAILED); -// result = resultPair.second.write(testDataArray.data(), 10, 5); -// REQUIRE(result == retval::CATCH_FAILED); -// -// memset(testDataArray.data(), 42, 5); -// result = resultPair.second.write(testDataArray.data(), 5, 5); -// REQUIRE(result == retval::CATCH_OK); -// resultConstPair = SimplePool.getData(testStoreId); -// resultPair.second.getDataCopy(receptionArray.data(), 20); -// for(size_t i = 5; i < 10; i++) { -// CHECK(receptionArray[i] == 42 ); -// } -// -// } -//} +#include +#include +#include +#include +#include + +TEST_CASE( "New Accessor" , "[NewAccessor]") { + LocalPool::LocalPoolConfig poolCfg = {{1, 10}}; + LocalPool SimplePool = LocalPool(0, poolCfg); + std::array testDataArray; + std::array receptionArray; + store_address_t testStoreId; + ReturnValue_t result = retval::CATCH_FAILED; + + for(size_t i = 0; i < testDataArray.size(); i++) { + testDataArray[i] = i; + } + size_t size = 10; + + SECTION ("Simple tests getter functions") { + result = SimplePool.addData(&testStoreId, testDataArray.data(), size); + REQUIRE(result == retval::CATCH_OK); + auto resultPair = SimplePool.getData(testStoreId); + REQUIRE(resultPair.first == retval::CATCH_OK); + resultPair.second.getDataCopy(receptionArray.data(), 20); + CHECK(resultPair.second.getId() == testStoreId); + CHECK(resultPair.second.size() == 10); + for(size_t i = 0; i < size; i++) { + CHECK(receptionArray[i] == i ); + } + + std::copy(resultPair.second.data(), resultPair.second.data() + + resultPair.second.size(), receptionArray.data()); + for(size_t i = 0; i < size; i++) { + CHECK(receptionArray[i] == i ); + } + + { + auto resultPairLoc = SimplePool.getData(testStoreId); + REQUIRE(resultPairLoc.first == retval::CATCH_OK); + // data should be deleted when accessor goes out of scope. + } + resultPair = SimplePool.getData(testStoreId); + REQUIRE(resultPair.first == (int) StorageManagerIF::DATA_DOES_NOT_EXIST); + + result = SimplePool.addData(&testStoreId, testDataArray.data(), size); + REQUIRE(result == retval::CATCH_OK); + { + ConstStorageAccessor constAccessor(testStoreId); + result = SimplePool.getData(testStoreId, constAccessor); + REQUIRE(result == retval::CATCH_OK); + constAccessor.getDataCopy(receptionArray.data(), 20); + for(size_t i = 0; i < size; i++) { + CHECK(receptionArray[i] == i ); + } + // likewise, data should be deleted when accessor gets out of scope. + } + resultPair = SimplePool.getData(testStoreId); + REQUIRE(resultPair.first == (int) StorageManagerIF::DATA_DOES_NOT_EXIST); + + result = SimplePool.addData(&testStoreId, testDataArray.data(), size); + { + resultPair = SimplePool.getData(testStoreId); + REQUIRE(resultPair.first == retval::CATCH_OK); + resultPair.second.release(); + // now data should not be deleted anymore + } + resultPair = SimplePool.getData(testStoreId); + REQUIRE(resultPair.first == retval::CATCH_OK); + resultPair.second.getDataCopy(receptionArray.data(), 20); + for(size_t i = 0; i < size; i++) { + CHECK(receptionArray[i] == i ); + } + } + + + SECTION("Simple tests modify functions") { + result = SimplePool.addData(&testStoreId, testDataArray.data(), size); + REQUIRE(result == retval::CATCH_OK); + { + StorageAccessor accessor(testStoreId); + result = SimplePool.modifyData(testStoreId, accessor); + REQUIRE(result == retval::CATCH_OK); + CHECK(accessor.getId() == testStoreId); + CHECK(accessor.size() == 10); + accessor.getDataCopy(receptionArray.data(), 20); + for(size_t i = 0; i < size; i++) { + CHECK(receptionArray[i] == i ); + } + std::copy(accessor.data(), accessor.data() + + accessor.size(), receptionArray.data()); + for(size_t i = 0; i < size; i++) { + CHECK(receptionArray[i] == i ); + } + // data should be deleted when accessor goes out of scope + } + auto resultPair = SimplePool.getData(testStoreId); + REQUIRE(resultPair.first == (int) StorageManagerIF::DATA_DOES_NOT_EXIST); + + result = SimplePool.addData(&testStoreId, testDataArray.data(), size); + REQUIRE(result == retval::CATCH_OK); + { + auto resultPairLoc = SimplePool.modifyData(testStoreId); + REQUIRE(resultPairLoc.first == retval::CATCH_OK); + CHECK(resultPairLoc.second.getId() == testStoreId); + CHECK(resultPairLoc.second.size() == 10); + resultPairLoc.second.getDataCopy(receptionArray.data(), 20); + for(size_t i = 0; i < size; i++) { + CHECK(receptionArray[i] == i ); + } + std::copy(resultPairLoc.second.data(), resultPairLoc.second.data() + + resultPairLoc.second.size(), receptionArray.data()); + for(size_t i = 0; i < size; i++) { + CHECK(receptionArray[i] == i ); + } + resultPairLoc.second.release(); + // data should not be deleted when accessor goes out of scope + } + resultPair = SimplePool.getData(testStoreId); + REQUIRE(resultPair.first == retval::CATCH_OK); + } + + + SECTION("Write tests") { + result = SimplePool.addData(&testStoreId, testDataArray.data(), size); + REQUIRE(result == retval::CATCH_OK); + { + auto resultPair = SimplePool.modifyData(testStoreId); + REQUIRE(resultPair.first == retval::CATCH_OK); + testDataArray[9] = 42; + resultPair.second.write(testDataArray.data(), 10, 0); + // now data should not be deleted + resultPair.second.release(); + } + auto resultConstPair = SimplePool.getData(testStoreId); + REQUIRE(resultConstPair.first == retval::CATCH_OK); + + resultConstPair.second.getDataCopy(receptionArray.data(), 10); + for(size_t i = 0; i < size-1; i++) { + CHECK(receptionArray[i] == i ); + } + CHECK(receptionArray[9] == 42 ); + + auto resultPair = SimplePool.modifyData(testStoreId); + REQUIRE(resultPair.first == retval::CATCH_OK); + result = resultPair.second.write(testDataArray.data(), 20, 0); + REQUIRE(result == retval::CATCH_FAILED); + result = resultPair.second.write(testDataArray.data(), 10, 5); + REQUIRE(result == retval::CATCH_FAILED); + + std::memset(testDataArray.data(), 42, 5); + result = resultPair.second.write(testDataArray.data(), 5, 5); + REQUIRE(result == retval::CATCH_OK); + resultConstPair = SimplePool.getData(testStoreId); + resultPair.second.getDataCopy(receptionArray.data(), 20); + for(size_t i = 5; i < 10; i++) { + CHECK(receptionArray[i] == 42 ); + } + + } +} diff --git a/unittest/tests/storagemanager/TestPool.cpp b/unittest/tests/storagemanager/TestPool.cpp index daeb6bb5..50bde01a 100644 --- a/unittest/tests/storagemanager/TestPool.cpp +++ b/unittest/tests/storagemanager/TestPool.cpp @@ -1,17 +1,13 @@ -#include "CatchDefinitions.h" - #include #include -#include -#include +#include +#include #include TEST_CASE( "Local Pool Simple Tests [1 Pool]" , "[TestPool]") { -// uint16_t numberOfElements[1] = {1}; -// uint16_t sizeofElements[1] = {10}; LocalPool::LocalPoolConfig config = {{1, 10}}; LocalPool simplePool(0, config); std::array testDataArray; diff --git a/unittest/user/CMakeLists.txt b/unittest/user/CMakeLists.txt new file mode 100644 index 00000000..722cc424 --- /dev/null +++ b/unittest/user/CMakeLists.txt @@ -0,0 +1,257 @@ +################################################################################ +# CMake support for the Flight Software Framework Tests +# +# Developed in an effort to replace Make with a modern build system. +# +# Author: R. Mueller +################################################################################ + +################################################################################ +# Pre-Project preparation +################################################################################ +cmake_minimum_required(VERSION 3.13) + +# set(CMAKE_VERBOSE TRUE) + +set(CMAKE_SCRIPT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + +option(TMTC_TEST "Build binary for manual or automatic TMTC tests" FALSE) +option(GENERATE_COVERAGE + "Specify whether coverage data is generated with GCOV" + TRUE +) + +if(TMTC_TEST) + set(LINK_CATCH2 FALSE) +else() + set(LINK_CATCH2 TRUE) +endif() + +# Tests can be built with the Host OSAL or with the Linux OSAL. +if(NOT OS_FSFW) + set(OS_FSFW host CACHE STRING "OS for the FSFW.") +endif() + +option(CUSTOM_UNITTEST_RUNNER + "Specify whether custom main or Catch2 main is used" TRUE +) + +# Perform steps like loading toolchain files where applicable. +#include(${CMAKE_SCRIPT_PATH}/PreProjectConfig.cmake) +#pre_project_config() + +# Project Name +project(fsfw_tests C CXX) + +################################################################################ +# Pre-Sources preparation +################################################################################ + +# Specify the C++ standard +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED True) + +# Set names and variables +set(TARGET_NAME ${CMAKE_PROJECT_NAME}) +if(CUSTOM_UNITTEST_RUNNER) + set(CATCH2_TARGET Catch2) +else() + set(CATCH2_TARGET Catch2WithMain) +endif() +set(LIB_FSFW_NAME fsfw) + +# Set path names +set(FSFW_PATH fsfw) +set(CATCH2_PATH Catch2) +set(FSFW_TESTS_PATH fsfw/unittest) +set(TEST_SETUP_PATH unittest) +set(TMTC_TEST_PATH tests) + +# Analyse different OS and architecture/target options and +# determine BSP_PATH + +# FreeRTOS +if(${OS_FSFW} STREQUAL linux) + add_definitions(-DUNIX -DLINUX) + find_package(Threads REQUIRED) +# Hosted +else() + if(WIN32) + add_definitions(-DWIN32) + elseif(UNIX) + find_package(Threads REQUIRED) + add_definitions(-DUNIX -DLINUX) + endif() +endif() + +if(GENERATE_COVERAGE) + list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/cmake-modules) + if(CMAKE_COMPILER_IS_GNUCXX) + include(CodeCoverage) + # Add compile options on target base, we don't want coverage for Catch2 + # append_coverage_compiler_flags() + endif() +endif() + +set(FSFW_CONFIG_PATH testcfg) + +################################################################################ +# Executable and Sources +################################################################################ + +# Add executable +add_executable(${TARGET_NAME}) + +# Add subdirectories +add_subdirectory(${FSFW_PATH}) +add_subdirectory(${FSFW_CONFIG_PATH}) + +if(LINK_CATCH2) + add_subdirectory(${CATCH2_PATH}) + add_subdirectory(${FSFW_TESTS_PATH}) + add_subdirectory(${TEST_SETUP_PATH}) +else() + add_subdirectory(${TMTC_TEST_PATH}) +endif() + + +################################################################################ +# Post-Sources preparation +################################################################################ + +# Add libraries for all sources. +target_link_libraries(${TARGET_NAME} PRIVATE + ${LIB_FSFW_NAME} +) + +if(LINK_CATCH2) + target_link_libraries(${TARGET_NAME} PRIVATE + ${CATCH2_TARGET} + ) +endif() + +if(GENERATE_COVERAGE) + if(CMAKE_COMPILER_IS_GNUCXX) + set(CODE_COVERAGE_VERBOSE TRUE) + include(CodeCoverage) + + # Remove quotes. + separate_arguments(COVERAGE_COMPILER_FLAGS + NATIVE_COMMAND "${COVERAGE_COMPILER_FLAGS}" + ) + + # Add compile options manually, we don't want coverage for Catch2 + target_compile_options(${TARGET_NAME} PRIVATE + "${COVERAGE_COMPILER_FLAGS}" + ) + target_compile_options(${LIB_FSFW_NAME} PRIVATE + "${COVERAGE_COMPILER_FLAGS}" + ) + + # Exclude internal unittest from coverage for now. + if(WIN32) + set(GCOVR_ADDITIONAL_ARGS + "--exclude-throw-branches" + "--exclude-unreachable-branches" + ) + set(COVERAGE_EXCLUDES + "/c/msys64/mingw64/*" "Catch2" + "${CMAKE_CURRENT_SOURCE_DIR}/fsfw/unittest/internal" + ) + elseif(UNIX) + set(COVERAGE_EXCLUDES + "/usr/include/*" "/usr/bin/*" "Catch2/*" + "fsfw/unittest/internal/*" + ) + endif() + + target_link_options(${TARGET_NAME} PRIVATE + -fprofile-arcs + -ftest-coverage + ) + target_link_options(${LIB_FSFW_NAME} PRIVATE + -fprofile-arcs + -ftest-coverage + ) + + if(WIN32) + setup_target_for_coverage_gcovr_html( + NAME ${TARGET_NAME}_coverage + EXECUTABLE ${TARGET_NAME} + DEPENDENCIES ${TARGET_NAME} + ) + else() + setup_target_for_coverage_lcov( + NAME ${TARGET_NAME}_coverage + EXECUTABLE ${TARGET_NAME} + DEPENDENCIES ${TARGET_NAME} + ) + endif() + endif() +endif() + +# Add include paths for all sources. +target_include_directories(${TARGET_NAME} PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ${FSFW_CONFIG_PATH} +) + +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + set(WARNING_FLAGS + -Wall + -Wextra + -Wshadow=local + -Wimplicit-fallthrough=1 + -Wno-unused-parameter + -Wno-psabi + ) + + # Remove unused sections. + target_compile_options(${TARGET_NAME} PRIVATE + "-ffunction-sections" + "-fdata-sections" + ) + + # Removed unused sections. + target_link_options(${TARGET_NAME} PRIVATE + "-Wl,--gc-sections" + ) + +elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + set(COMPILER_FLAGS "/permissive-") +endif() + +if(CMAKE_VERBOSE) + message(STATUS "Warning flags: ${WARNING_FLAGS}") +endif() + + +# Compile options for all sources. +target_compile_options(${TARGET_NAME} PRIVATE + $<$:${WARNING_FLAGS} ${COMPILER_FLAGS}> + $<$:${WARNING_FLAGS} ${COMPILER_FLAGS}> + ${ABI_FLAGS} +) + +if(NOT CMAKE_SIZE) + set(CMAKE_SIZE size) + if(WIN32) + set(FILE_SUFFIX ".exe") + endif() +endif() + +add_custom_command(TARGET ${TARGET_NAME} + POST_BUILD + COMMAND echo "Build directory: ${CMAKE_BINARY_DIR}" + COMMAND echo "Target OSAL: ${OS_FSFW}" + COMMAND echo "Target Build Type: ${CMAKE_BUILD_TYPE}" + COMMAND ${CMAKE_SIZE} ${TARGET_NAME}${FILE_SUFFIX} +) + +include (${CMAKE_SCRIPT_PATH}/BuildType.cmake) +set_build_type() + + + + + diff --git a/unittest/user/testcfg/CMakeLists.txt b/unittest/user/testcfg/CMakeLists.txt new file mode 100644 index 00000000..dbf0256f --- /dev/null +++ b/unittest/user/testcfg/CMakeLists.txt @@ -0,0 +1,11 @@ +target_sources(${TARGET_NAME} + PRIVATE + ipc/MissionMessageTypes.cpp + pollingsequence/PollingSequenceFactory.cpp +) + +# Add include paths for the executable +target_include_directories(${TARGET_NAME} + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) diff --git a/unittest/testcfg/FSFWConfig.h b/unittest/user/testcfg/FSFWConfig.h similarity index 70% rename from unittest/testcfg/FSFWConfig.h rename to unittest/user/testcfg/FSFWConfig.h index 6b0def90..ed86e6e1 100644 --- a/unittest/testcfg/FSFWConfig.h +++ b/unittest/user/testcfg/FSFWConfig.h @@ -4,16 +4,21 @@ #include #include -//! Used to determine whether C++ ostreams are used -//! Those can lead to code bloat. +//! Used to determine whether C++ ostreams are used which can increase +//! the binary size significantly. If this is disabled, +//! the C stdio functions can be used alternatively #define FSFW_CPP_OSTREAM_ENABLED 1 -//! Reduced printout to further decrease code size -//! Be careful, this also turns off most diagnostic prinouts! -#define FSFW_ENHANCED_PRINTOUT 0 +//! More FSFW related printouts depending on level. Useful for development. +#define FSFW_VERBOSE_LEVEL 1 -//! Can be used to enable additional debugging printouts for developing the FSFW -#define FSFW_PRINT_VERBOSITY_LEVEL 0 +//! Can be used to completely disable printouts, even the C stdio ones. +#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, //! additional output which requires the translation files translateObjects @@ -49,7 +54,9 @@ static constexpr size_t FSFW_EVENTMGMR_RANGEMATCHERS = 120; //! also determines how many commands a CSB service can handle in one cycle //! simulataneously. This will increase the required RAM for //! each CSB service ! -static constexpr uint8_t FSFW_CSB_FIFO_DEPTH = 3; +static constexpr uint8_t FSFW_CSB_FIFO_DEPTH = 6; + +static constexpr size_t FSFW_PRINT_BUFFER_SIZE = 124; } #endif /* CONFIG_FSFWCONFIG_H_ */ diff --git a/unittest/testcfg/Makefile-FSFW-Tests b/unittest/user/testcfg/Makefile-FSFW-Tests similarity index 100% rename from unittest/testcfg/Makefile-FSFW-Tests rename to unittest/user/testcfg/Makefile-FSFW-Tests diff --git a/unittest/testcfg/TestsConfig.h b/unittest/user/testcfg/TestsConfig.h similarity index 100% rename from unittest/testcfg/TestsConfig.h rename to unittest/user/testcfg/TestsConfig.h diff --git a/unittest/testcfg/cdatapool/dataPoolInit.cpp b/unittest/user/testcfg/cdatapool/dataPoolInit.cpp similarity index 100% rename from unittest/testcfg/cdatapool/dataPoolInit.cpp rename to unittest/user/testcfg/cdatapool/dataPoolInit.cpp diff --git a/unittest/testcfg/cdatapool/dataPoolInit.h b/unittest/user/testcfg/cdatapool/dataPoolInit.h similarity index 100% rename from unittest/testcfg/cdatapool/dataPoolInit.h rename to unittest/user/testcfg/cdatapool/dataPoolInit.h diff --git a/defaultcfg/fsfwconfig/devices/logicalAddresses.cpp b/unittest/user/testcfg/devices/logicalAddresses.cpp similarity index 100% rename from defaultcfg/fsfwconfig/devices/logicalAddresses.cpp rename to unittest/user/testcfg/devices/logicalAddresses.cpp diff --git a/unittest/testcfg/devices/logicalAddresses.h b/unittest/user/testcfg/devices/logicalAddresses.h similarity index 100% rename from unittest/testcfg/devices/logicalAddresses.h rename to unittest/user/testcfg/devices/logicalAddresses.h diff --git a/defaultcfg/fsfwconfig/devices/powerSwitcherList.cpp b/unittest/user/testcfg/devices/powerSwitcherList.cpp similarity index 100% rename from defaultcfg/fsfwconfig/devices/powerSwitcherList.cpp rename to unittest/user/testcfg/devices/powerSwitcherList.cpp diff --git a/unittest/testcfg/devices/powerSwitcherList.h b/unittest/user/testcfg/devices/powerSwitcherList.h similarity index 100% rename from unittest/testcfg/devices/powerSwitcherList.h rename to unittest/user/testcfg/devices/powerSwitcherList.h diff --git a/unittest/testcfg/events/subsystemIdRanges.h b/unittest/user/testcfg/events/subsystemIdRanges.h similarity index 100% rename from unittest/testcfg/events/subsystemIdRanges.h rename to unittest/user/testcfg/events/subsystemIdRanges.h diff --git a/unittest/testcfg/ipc/MissionMessageTypes.cpp b/unittest/user/testcfg/ipc/MissionMessageTypes.cpp similarity index 100% rename from unittest/testcfg/ipc/MissionMessageTypes.cpp rename to unittest/user/testcfg/ipc/MissionMessageTypes.cpp diff --git a/unittest/testcfg/ipc/MissionMessageTypes.h b/unittest/user/testcfg/ipc/MissionMessageTypes.h similarity index 100% rename from unittest/testcfg/ipc/MissionMessageTypes.h rename to unittest/user/testcfg/ipc/MissionMessageTypes.h diff --git a/unittest/testcfg/objects/systemObjectList.h b/unittest/user/testcfg/objects/systemObjectList.h similarity index 64% rename from unittest/testcfg/objects/systemObjectList.h rename to unittest/user/testcfg/objects/systemObjectList.h index 0e034aff..88b92131 100644 --- a/unittest/testcfg/objects/systemObjectList.h +++ b/unittest/user/testcfg/objects/systemObjectList.h @@ -9,7 +9,20 @@ namespace objects { enum sourceObjects: uint32_t { /* All addresses between start and end are reserved for the FSFW */ FSFW_CONFIG_RESERVED_START = PUS_SERVICE_1_VERIFICATION, - FSFW_CONFIG_RESERVED_END = TM_STORE + FSFW_CONFIG_RESERVED_END = TM_STORE, + + CCSDS_DISTRIBUTOR = 10, + PUS_DISTRIBUTOR = 11, + TM_FUNNEL = 12, + + UDP_BRIDGE = 15, + UDP_POLLING_TASK = 16, + + TEST_ECHO_COM_IF = 20, + TEST_DEVICE = 21, + + HK_RECEIVER_MOCK = 22, + TEST_LOCAL_POOL_OWNER_BASE = 25 }; } diff --git a/unittest/testcfg/pollingsequence/PollingSequenceFactory.cpp b/unittest/user/testcfg/pollingsequence/PollingSequenceFactory.cpp similarity index 94% rename from unittest/testcfg/pollingsequence/PollingSequenceFactory.cpp rename to unittest/user/testcfg/pollingsequence/PollingSequenceFactory.cpp index f836a746..b7f1fb3e 100644 --- a/unittest/testcfg/pollingsequence/PollingSequenceFactory.cpp +++ b/unittest/user/testcfg/pollingsequence/PollingSequenceFactory.cpp @@ -15,8 +15,10 @@ ReturnValue_t pst::pollingSequenceInitDefault( return HasReturnvaluesIF::RETURN_OK; } else { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "pst::pollingSequenceInitDefault: Sequence invalid!" << std::endl; +#endif return HasReturnvaluesIF::RETURN_FAILED; } } diff --git a/unittest/testcfg/pollingsequence/PollingSequenceFactory.h b/unittest/user/testcfg/pollingsequence/PollingSequenceFactory.h similarity index 100% rename from unittest/testcfg/pollingsequence/PollingSequenceFactory.h rename to unittest/user/testcfg/pollingsequence/PollingSequenceFactory.h diff --git a/unittest/testcfg/returnvalues/classIds.h b/unittest/user/testcfg/returnvalues/classIds.h similarity index 100% rename from unittest/testcfg/returnvalues/classIds.h rename to unittest/user/testcfg/returnvalues/classIds.h diff --git a/unittest/testcfg/testcfg.mk b/unittest/user/testcfg/testcfg.mk similarity index 100% rename from unittest/testcfg/testcfg.mk rename to unittest/user/testcfg/testcfg.mk diff --git a/unittest/testcfg/tmtc/apid.h b/unittest/user/testcfg/tmtc/apid.h similarity index 100% rename from unittest/testcfg/tmtc/apid.h rename to unittest/user/testcfg/tmtc/apid.h diff --git a/unittest/testcfg/tmtc/pusIds.h b/unittest/user/testcfg/tmtc/pusIds.h similarity index 100% rename from unittest/testcfg/tmtc/pusIds.h rename to unittest/user/testcfg/tmtc/pusIds.h diff --git a/unittest/testtemplate/TestTemplate.cpp b/unittest/user/testtemplate/TestTemplate.cpp similarity index 100% rename from unittest/testtemplate/TestTemplate.cpp rename to unittest/user/testtemplate/TestTemplate.cpp diff --git a/unittest/user/unittest/CMakeLists.txt b/unittest/user/unittest/CMakeLists.txt new file mode 100644 index 00000000..ad6d4787 --- /dev/null +++ b/unittest/user/unittest/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(core) diff --git a/unittest/user/unittest/core/CMakeLists.txt b/unittest/user/unittest/core/CMakeLists.txt new file mode 100644 index 00000000..0989926c --- /dev/null +++ b/unittest/user/unittest/core/CMakeLists.txt @@ -0,0 +1,13 @@ +target_sources(${TARGET_NAME} PRIVATE + CatchDefinitions.cpp + CatchFactory.cpp + CatchRunner.cpp + CatchSetup.cpp + printChar.cpp +) + +if(CUSTOM_UNITTEST_RUNNER) + target_sources(${TARGET_NAME} PRIVATE + CatchRunner.cpp + ) +endif() \ No newline at end of file diff --git a/unittest/core/CatchDefinitions.cpp b/unittest/user/unittest/core/CatchDefinitions.cpp similarity index 62% rename from unittest/core/CatchDefinitions.cpp rename to unittest/user/unittest/core/CatchDefinitions.cpp index 0b66558a..bae02875 100644 --- a/unittest/core/CatchDefinitions.cpp +++ b/unittest/user/unittest/core/CatchDefinitions.cpp @@ -1,11 +1,16 @@ #include "CatchDefinitions.h" +#include #include StorageManagerIF* tglob::getIpcStoreHandle() { if(objectManager != nullptr) { return objectManager->get(objects::IPC_STORE); } else { +#if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "Global object manager uninitialized" << std::endl; +#else + sif::printError("Global object manager uninitialized\n\r"); +#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ return nullptr; } } diff --git a/unittest/core/CatchDefinitions.h b/unittest/user/unittest/core/CatchDefinitions.h similarity index 100% rename from unittest/core/CatchDefinitions.h rename to unittest/user/unittest/core/CatchDefinitions.h diff --git a/unittest/core/CatchFactory.cpp b/unittest/user/unittest/core/CatchFactory.cpp similarity index 56% rename from unittest/core/CatchFactory.cpp rename to unittest/user/unittest/core/CatchFactory.cpp index 3177212f..eabaa21d 100644 --- a/unittest/core/CatchFactory.cpp +++ b/unittest/user/unittest/core/CatchFactory.cpp @@ -1,11 +1,17 @@ +#include +#include #include "CatchFactory.h" #include #include - #include #include #include +#include +#include +#include +#include +#include /** * @brief Produces system objects. @@ -26,6 +32,9 @@ void Factory::produce(void) { new HealthTable(objects::HEALTH_TABLE); new InternalErrorReporter(objects::INTERNAL_ERROR_REPORTER); + new LocalPoolOwnerBase (objects::TEST_LOCAL_POOL_OWNER_BASE); + new HkReceiverMock(objects::HK_RECEIVER_MOCK); + { PoolManager::LocalPoolConfig poolCfg = { {100, 16}, {50, 32}, {25, 64} , {15, 128}, {5, 1024} @@ -50,7 +59,23 @@ void Factory::produce(void) { } void Factory::setStaticFrameworkObjectIds() { + PusServiceBase::packetSource = objects::NO_OBJECT; + PusServiceBase::packetDestination = objects::NO_OBJECT; + CommandingServiceBase::defaultPacketSource = objects::NO_OBJECT; + CommandingServiceBase::defaultPacketDestination = objects::NO_OBJECT; + + VerificationReporter::messageReceiver = objects::PUS_SERVICE_1_VERIFICATION; + + DeviceHandlerBase::powerSwitcherId = objects::NO_OBJECT; + DeviceHandlerBase::rawDataReceiverId = objects::PUS_SERVICE_2_DEVICE_ACCESS; + + LocalDataPoolManager::defaultHkDestination = objects::HK_RECEIVER_MOCK; + + DeviceHandlerFailureIsolation::powerConfirmationId = objects::NO_OBJECT; + + TmPacketStored::timeStamperId = objects::NO_OBJECT; } + diff --git a/unittest/core/CatchFactory.h b/unittest/user/unittest/core/CatchFactory.h similarity index 100% rename from unittest/core/CatchFactory.h rename to unittest/user/unittest/core/CatchFactory.h diff --git a/unittest/core/CatchRunner.cpp b/unittest/user/unittest/core/CatchRunner.cpp similarity index 74% rename from unittest/core/CatchRunner.cpp rename to unittest/user/unittest/core/CatchRunner.cpp index 35c53cd4..886d641f 100644 --- a/unittest/core/CatchRunner.cpp +++ b/unittest/user/unittest/core/CatchRunner.cpp @@ -1,17 +1,16 @@ /** - * @file CatchSource.cpp + * @file CatchRunner.cpp * @brief Source file to compile catch framework. * @details All tests should be written in other files. * For eclipse console output, install ANSI Escape in Console * from the eclipse market place to get colored characters. */ -#ifndef NO_UNIT_TEST_FRAMEWORK +#include -#define CATCH_CONFIG_RUNNER -#include +#define CATCH_CONFIG_COLOUR_WINDOWS -#if CUSTOM_UNITTEST_RUNNER == 0 +#include extern int customSetup(); @@ -25,7 +24,3 @@ int main( int argc, char* argv[] ) { return result; } -#endif - - -#endif diff --git a/unittest/core/CatchSetup.cpp b/unittest/user/unittest/core/CatchSetup.cpp similarity index 65% rename from unittest/core/CatchSetup.cpp rename to unittest/user/unittest/core/CatchSetup.cpp index c93cf032..bda31400 100644 --- a/unittest/core/CatchSetup.cpp +++ b/unittest/user/unittest/core/CatchSetup.cpp @@ -1,21 +1,20 @@ -#include +#include "CatchFactory.h" #include "CatchDefinitions.h" -#include #ifdef GCOV #include #endif -#include "../../objectmanager/ObjectManager.h" -#include "../../objectmanager/ObjectManagerIF.h" -#include "../../storagemanager/StorageManagerIF.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" +#include +#include +#include +#include /* Global instantiations normally done in main.cpp */ /* Initialize Data Pool */ - +#if FSFW_CPP_OSTREAM_ENABLED == 1 namespace sif { /* Set up output streams */ ServiceInterfaceStream debug("DEBUG"); @@ -23,6 +22,7 @@ ServiceInterfaceStream info("INFO"); ServiceInterfaceStream error("ERROR"); ServiceInterfaceStream warning("WARNING"); } +#endif /* Global object manager */ ObjectManagerIF *objectManager; diff --git a/unittest/core/core.mk b/unittest/user/unittest/core/core.mk similarity index 100% rename from unittest/core/core.mk rename to unittest/user/unittest/core/core.mk diff --git a/unittest/core/printChar.cpp b/unittest/user/unittest/core/printChar.cpp similarity index 80% rename from unittest/core/printChar.cpp rename to unittest/user/unittest/core/printChar.cpp index 755a13b2..5d4f1b17 100644 --- a/unittest/core/printChar.cpp +++ b/unittest/user/unittest/core/printChar.cpp @@ -1,4 +1,4 @@ -#include +#include "printChar.h" #include void printChar(const char* character, bool errStream) { diff --git a/unittest/core/printChar.h b/unittest/user/unittest/core/printChar.h similarity index 100% rename from unittest/core/printChar.h rename to unittest/user/unittest/core/printChar.h diff --git a/unittest/unlockRealtime.sh b/unittest/user/unlockRealtime.sh similarity index 100% rename from unittest/unlockRealtime.sh rename to unittest/user/unlockRealtime.sh